1ae784e_TagPrompt_11.js 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. function TagPrompt(select_tag_callback, tag_prompt_connector)
  2. {
  3. // En plus je change une ligne !
  4. /* @var tags_selected array of Tag */
  5. var tags_selected = [];
  6. /* @var tags_proposed array of Tag */
  7. var tags_proposed = [];
  8. var _select_tag_callback = select_tag_callback;
  9. var _tag_prompt_connector = tag_prompt_connector;
  10. this.getProposedTagsForString = function(search_string, callback_success, callback_error)
  11. {
  12. tags_proposed = [];
  13. JQueryJson(url_search_tag, {'string_search': search_string}, function(response){
  14. if (response.status == 'error')
  15. {
  16. callback_error(response.error);
  17. }
  18. else if (response.status == 'success')
  19. {
  20. for (i in response.data)
  21. {
  22. var tag = new Tag(
  23. response.data[i].id,
  24. response.data[i].name
  25. );
  26. tags_proposed.push(tag);
  27. }
  28. callback_success(tags_proposed, search_string, response.message, response.same_found);
  29. }
  30. });
  31. }
  32. this.selectProposedTag = function (tag_id, tag_name)
  33. {
  34. if (!tag_id)
  35. {
  36. if (!visitor)
  37. {
  38. openTagSubmission(tag_name);
  39. }
  40. else
  41. {
  42. open_connection_or_subscription_window();
  43. }
  44. }
  45. else
  46. {
  47. addTagToSelectedTags(findTagInProposedList(tag_id));
  48. _select_tag_callback(tags_selected);
  49. }
  50. }
  51. var openTagSubmission = function (tag_name)
  52. {
  53. // TODO : Cette partie du code n'est pas encore refactorisé
  54. // Effet fade-in du fond opaque
  55. $('body').append($('<div>').attr('id', 'fade'));
  56. //Apparition du fond - .css({'filter' : 'alpha(opacity=80)'}) pour corriger les bogues de IE
  57. $('#fade').css({'filter' : 'alpha(opacity=80)'}).fadeIn();
  58. // En premier lieux on fait apparaître la fenêtre de confirmation
  59. var popup = $('<div>')
  60. .attr('id', 'add_tag')
  61. .addClass('popin_block')
  62. .css('width', '400px')
  63. //.append($('<h2>').append(string_tag_add_title))
  64. .append($('<form>')
  65. .attr('action', url_add_tag)
  66. .attr('method', 'post')
  67. .attr('name', 'add_tag')
  68. .ajaxForm(function(response) {
  69. window.ResponseController.execute(
  70. response,
  71. function(){},
  72. function(response){
  73. $('form[name="add_tag"]').find('ul.error_list').remove();
  74. var ul_errors = $('<ul>').addClass('error_list');
  75. for (i in response.errors)
  76. {
  77. ul_errors.append($('<li>').append(response.errors[i]));
  78. }
  79. $('form[name="add_tag"]').prepend(ul_errors);
  80. }
  81. );
  82. if (response.status === 'success')
  83. {
  84. var tag = new Tag(response.tag_id, response.tag_name);
  85. addTagToProposedTags(tag);
  86. addTagToSelectedTags(tag);
  87. _tag_prompt_connector.updateOutput(tags_selected);
  88. $('#fade').fadeOut(400, function(){$('#fade').remove();});
  89. $('#add_tag').remove();
  90. }
  91. return false;
  92. })
  93. .append($('<div>').addClass('tag')
  94. .append($('<ul>')
  95. .append($('<li>').addClass('button')
  96. .append(tag_name))))
  97. .append($('<p>').append(string_tag_add_text))
  98. .append($('<p>').append(string_tag_add_argument))
  99. .append($('<textarea>').attr('name', 'argument'))
  100. .append($('<div>').addClass('inputs')
  101. .append($('<input>')
  102. .attr('type', 'button')
  103. .attr('value', string_tag_add_inputs_cancel)
  104. .addClass('button')
  105. .click(function(){
  106. $('#fade').fadeOut(1000, function(){$('#fade').remove();});
  107. $('#add_tag').remove();
  108. return false;
  109. })
  110. )
  111. .append($('<input>')
  112. .attr('type', 'submit')
  113. .attr('value', string_tag_add_inputs_submit)
  114. .addClass('button')
  115. .click(function(){
  116. // TODO: loader gif
  117. })
  118. )
  119. .append($('<input>').attr('type', 'hidden').attr('name', 'tag_name').val(tag_name))
  120. ))
  121. ;
  122. // Il faut ajouter le popup au dom avant de le positionner en css
  123. // Sinon la valeur height n'est pas encore calculable
  124. $('body').prepend(popup);
  125. //Récupération du margin, qui permettra de centrer la fenêtre - on ajuste de 80px en conformité avec le CSS
  126. var popMargTop = (popup.height() + 50) / 2;
  127. var popMargLeft = (popup.width() + 50) / 2;
  128. //On affecte le margin
  129. $(popup).css({
  130. 'margin-top' : -popMargTop,
  131. 'margin-left' : -popMargLeft
  132. });
  133. return false;
  134. }
  135. this.openTagSubmission = function (tag_name)
  136. {
  137. // TODO : Cette partie du code n'est pas encore refactorisé
  138. // Effet fade-in du fond opaque
  139. $('body').append($('<div>').attr('id', 'fade'));
  140. //Apparition du fond - .css({'filter' : 'alpha(opacity=80)'}) pour corriger les bogues de IE
  141. $('#fade').css({'filter' : 'alpha(opacity=80)'}).fadeIn();
  142. // En premier lieux on fait apparaître la fenêtre de confirmation
  143. var popup = $('<div>')
  144. .attr('id', 'add_tag')
  145. .addClass('popin_block')
  146. .css('width', '400px')
  147. //.append($('<h2>').append(string_tag_add_title))
  148. .append($('<form>')
  149. .attr('action', url_add_tag)
  150. .attr('method', 'post')
  151. .attr('name', 'add_tag')
  152. .ajaxForm(function(response) {
  153. /*
  154. *
  155. */
  156. window.ResponseController.execute(
  157. response,
  158. function(){},
  159. function(){}
  160. );
  161. if (response.status == 'success')
  162. {
  163. var tag = new Tag(response.tag_id, response.tag_name);
  164. addTagToProposedTags(tag);
  165. addTagToSelectedTags(tag);
  166. _tag_prompt_connector.updateOutput(tags_selected);
  167. $('#fade').fadeOut(400, function(){$('#fade').remove();});
  168. $('#add_tag').remove();
  169. }
  170. if (response.status == 'error')
  171. {
  172. $('form[name="add_tag"]').find('ul.error_list').remove();
  173. var ul_errors = $('<ul>').addClass('error_list');
  174. for (i in response.errors)
  175. {
  176. ul_errors.append($('<li>').append(response.errors[i]));
  177. }
  178. $('form[name="add_tag"]').prepend(ul_errors);
  179. }
  180. return false;
  181. })
  182. .append($('<div>').addClass('tag')
  183. .append($('<ul>')
  184. .append($('<li>').addClass('button')
  185. .append(tag_name))))
  186. .append($('<p>').append(string_tag_add_text))
  187. .append($('<p>').append(string_tag_add_argument))
  188. .append($('<textarea>').attr('name', 'argument'))
  189. .append($('<div>').addClass('inputs')
  190. .append($('<input>')
  191. .attr('type', 'button')
  192. .attr('value', string_tag_add_inputs_cancel)
  193. .addClass('button')
  194. .click(function(){
  195. $('#fade').fadeOut(1000, function(){$('#fade').remove();});
  196. $('#add_tag').remove();
  197. return false;
  198. })
  199. )
  200. .append($('<input>')
  201. .attr('type', 'submit')
  202. .attr('value', string_tag_add_inputs_submit)
  203. .addClass('button')
  204. .click(function(){
  205. // TODO: loader gif
  206. })
  207. )
  208. .append($('<input>').attr('type', 'hidden').attr('name', 'tag_name').val(tag_name))
  209. ))
  210. ;
  211. // Il faut ajouter le popup au dom avant de le positionner en css
  212. // Sinon la valeur height n'est pas encore calculable
  213. $('body').prepend(popup);
  214. //Récupération du margin, qui permettra de centrer la fenêtre - on ajuste de 80px en conformité avec le CSS
  215. var popMargTop = (popup.height() + 50) / 2;
  216. var popMargLeft = (popup.width() + 50) / 2;
  217. //On affecte le margin
  218. $(popup).css({
  219. 'margin-top' : -popMargTop,
  220. 'margin-left' : -popMargLeft
  221. });
  222. return false;
  223. }
  224. var addTagToSelectedTags = function(tag)
  225. {
  226. var found = false;
  227. for (i in tags_selected)
  228. {
  229. if (tags_selected[i].id == tag.id)
  230. {
  231. found = true;
  232. }
  233. }
  234. if (!found)
  235. {
  236. tags_selected.push(tag);
  237. }
  238. }
  239. var addTagToProposedTags = function(tag)
  240. {
  241. var found = false;
  242. for (i in tags_proposed)
  243. {
  244. if (tags_proposed[i].id == tag.id)
  245. {
  246. found = true;
  247. }
  248. }
  249. if (!found)
  250. {
  251. tags_proposed.push(tag);
  252. }
  253. }
  254. this.addTag = function(tag)
  255. {
  256. addTagToSelectedTags(tag);
  257. addTagToProposedTags(tag);
  258. }
  259. var findTagInProposedList = function(tag_id)
  260. {
  261. for (i in tags_proposed)
  262. {
  263. if (tags_proposed[i].id == tag_id)
  264. {
  265. return tags_proposed[i];
  266. }
  267. }
  268. throw new Error("Unable to find the tag !")
  269. }
  270. this.removeSelectedTag = function(tag_id)
  271. {
  272. var new_tags_selected = [];
  273. for (i in tags_selected)
  274. {
  275. if (tags_selected[i].id != tag_id)
  276. {
  277. new_tags_selected.push(tags_selected[i]);
  278. }
  279. }
  280. tags_selected = new_tags_selected;
  281. }
  282. this.getSelectedTags = function()
  283. {
  284. return tags_selected;
  285. }
  286. this.setSelectedTags = function(tags)
  287. {
  288. tags_selected = tags;
  289. }
  290. }
  291. function TagPromptConnector(input, output, proposition_list, tag_box, prompt_loader)
  292. {
  293. var _input = input;
  294. var _output = output;
  295. var _tag_box_manager = new TagBoxManager(tag_box, this);
  296. var _prompt_loader = prompt_loader;
  297. var updateHelpDisplay = function()
  298. {
  299. if (_tag_prompt.getSelectedTags())
  300. {
  301. if (_tag_prompt.getSelectedTags().length)
  302. {
  303. $('#tags_prompt_search p.help_notags').hide();
  304. }
  305. else
  306. {
  307. $('#tags_prompt_search p.help_notags').show();
  308. }
  309. }
  310. }
  311. this.updateOutput = function(tags)
  312. {
  313. _output.val(array2json(tagsToArrayIds(tags)));
  314. _tag_proposition_list.hide();
  315. _tag_box_manager.update(tags);
  316. cleanInput();
  317. updateHelpDisplay();
  318. }
  319. var _tag_prompt = new TagPrompt(this.updateOutput, this);
  320. var _tag_proposition_list = new TagPromptPropositionList(proposition_list, _tag_prompt.selectProposedTag, this);
  321. var cleanInput = function()
  322. {
  323. // hack pour ie < 10 ne supportant pas le placeholder
  324. if ($.browser.version < 10 && $.browser.msie)
  325. {
  326. _input.addClass('placeholder');
  327. _input.val(_input.attr('placeholder'));
  328. }
  329. else
  330. {
  331. _input.val('');
  332. }
  333. }
  334. var showPromptLoader = function()
  335. {
  336. _prompt_loader.show();
  337. }
  338. this.hidePromptLoader = function()
  339. {
  340. _prompt_loader.hide();
  341. }
  342. var launchSearchTagsIdLastKeystroke = function(search_string)
  343. {
  344. if (search_string == _input.val())
  345. {
  346. displayTagsProposedSearchTags();
  347. }
  348. }
  349. var displayTagsProposedSearchTags = function()
  350. {
  351. var string_search = _input.val();
  352. _tag_prompt.getProposedTagsForString(
  353. string_search,
  354. _tag_proposition_list.displayTagsPropositions,
  355. _tag_proposition_list.displayError
  356. );
  357. }
  358. $(_input).bind('keyup', function() {
  359. if ($(this).val().length > 0)
  360. {
  361. showPromptLoader();
  362. var input_value = _input.val();
  363. window.setTimeout(function(){
  364. launchSearchTagsIdLastKeystroke(input_value);
  365. }, 1000);
  366. }
  367. });
  368. var tagsToArrayIds = function(tags)
  369. {
  370. var tags_ids = [];
  371. for (i in tags)
  372. {
  373. tags_ids.push(tags[i].id);
  374. }
  375. return tags_ids;
  376. }
  377. this.removeSelectedTag = function(tag_id)
  378. {
  379. _tag_prompt.removeSelectedTag(tag_id);
  380. this.updateOutput(_tag_prompt.getSelectedTags());
  381. }
  382. this.initializeTags = function(tags)
  383. {
  384. _tag_prompt.setSelectedTags(tags);
  385. this.updateOutput(_tag_prompt.getSelectedTags());
  386. }
  387. this.addTagToTagPrompt = function(tag)
  388. {
  389. _tag_prompt.addTag(tag);
  390. this.updateOutput(_tag_prompt.getSelectedTags());
  391. }
  392. this.openTagSubmission = function(tag_name)
  393. {
  394. _tag_prompt.openTagSubmission(tag_name);
  395. }
  396. }
  397. function TagBoxManager(tag_box, tag_prompt_connector)
  398. {
  399. var _tag_prompt_connector = tag_prompt_connector;
  400. var _tag_box = tag_box;
  401. this.update = function(tags)
  402. {
  403. _tag_box.find('li').remove();
  404. for (i in tags)
  405. {
  406. _tag_box.append(getTagLine(tags[i]));
  407. }
  408. }
  409. var getTagLine = function (tag)
  410. {
  411. var line = $('<li>');
  412. line.addClass('tag');
  413. line.text(tag.name);
  414. line.append(getCloseLink(tag));
  415. return line;
  416. }
  417. var getCloseLink = function(tag)
  418. {
  419. var close_link = $('<a>');
  420. close_link.addClass('close');
  421. close_link.attr('href', '#');
  422. close_link.data('tag_id', tag.id);
  423. close_link.data('tag_name', tag.name);
  424. close_link.text('close');
  425. close_link.bind('click', function(){
  426. _tag_prompt_connector.removeSelectedTag($(this).data('tag_id'));
  427. return false;
  428. });
  429. return close_link;
  430. }
  431. }
  432. function TagPromptPropositionList(proposition_list, click_tag_callback, tag_prompt_connector)
  433. {
  434. var _proposition_list = proposition_list;
  435. var _list;
  436. var _limit_display_tags = 30;
  437. var _click_tag_callback = click_tag_callback;
  438. var _tag_prompt_connector = tag_prompt_connector;
  439. this.displayError = function(error_string)
  440. {
  441. initializeList();
  442. var span_info = _proposition_list.find('span.info');
  443. span_info.text(error_string);
  444. }
  445. this.displayTagsPropositions = function(tags, search_string, message, same_found)
  446. {
  447. initializeList();
  448. displayMessage(message);
  449. for (i in tags)
  450. {
  451. addTagToList(tags[i], search_string);
  452. }
  453. if (!same_found)
  454. {
  455. addTagPropositionToList(new Tag(null, search_string));
  456. }
  457. }
  458. var initializeList = function()
  459. {
  460. _tag_prompt_connector.hidePromptLoader();
  461. $(_proposition_list).show();
  462. _list = _proposition_list.find('ul.search_tag_list');
  463. _list.find('li').remove();
  464. _proposition_list.find('a.more').hide();
  465. }
  466. var displayMessage = function(message)
  467. {
  468. var span_info = _proposition_list.find('span.info');
  469. span_info.text(message);
  470. }
  471. var addTagToList = function(tag, search_string)
  472. {
  473. var line = '';
  474. if (_list.find('li').length > _limit_display_tags)
  475. {
  476. line = getListLine(tag, true);
  477. _proposition_list.find('a.more').show();
  478. }
  479. else
  480. {
  481. line = getListLine(tag, false);
  482. }
  483. line = strongifySearchedLetters(line, search_string);
  484. _list.append(line);
  485. }
  486. var getListLine = function(tag, hide)
  487. {
  488. if (hide)
  489. {
  490. var line = $('<li style="display: none;">');
  491. }
  492. else
  493. {
  494. var line = $('<li>');
  495. }
  496. return line.append(getTagLink(tag));
  497. }
  498. var getTagLink = function(tag)
  499. {
  500. link = $('<a>');
  501. link.attr('href', '#');
  502. link.data('tag_id', tag.id);
  503. link.data('tag_name', tag.name);
  504. link.text(tag.name);
  505. link.bind('click', function(){
  506. _click_tag_callback($(this).data('tag_id'), $(this).data('tag_name'));
  507. return false;
  508. });
  509. return link;
  510. }
  511. var strongifySearchedLetters = function(line, search_string)
  512. {
  513. var name = line.find('a').text();
  514. line.find('a').html(name.replace(new RegExp(search_string, "i"), "<strong>" + search_string + "</strong>"));
  515. return line;
  516. }
  517. var addTagPropositionToList = function(tag)
  518. {
  519. var line = getListLine(tag);
  520. line.addClass('new');
  521. _list.append(line);
  522. }
  523. this.hide = function()
  524. {
  525. _proposition_list.hide();
  526. }
  527. }
  528. function Tag(id, name)
  529. {
  530. /* @var _id int */
  531. this.id = id;
  532. /* @var _name string */
  533. this.name = name;
  534. }
  535. Tag.prototype =
  536. {
  537. isKnew: function()
  538. {
  539. if (this.id)
  540. {
  541. return true;
  542. }
  543. return false;
  544. }
  545. }
  546. $(document).ready(function(){
  547. // Ce code permet la fermeture de la propositions de tags lors d'un click sur la page
  548. $('html').click(function() {
  549. if ($("div.search_tag_list").is(':visible'))
  550. {
  551. $("div.search_tag_list").hide();
  552. }
  553. });
  554. $("div.search_tag_list, div.search_tag_list a.more").live('click', function(event){
  555. event.stopPropagation();
  556. $("div.search_tag_list").show();
  557. });
  558. $('div.search_tag_list a.more').live('click', function(){
  559. $(this).parents('div.search_tag_list ').find('ul.search_tag_list li').show();
  560. $(this).hide();
  561. return false;
  562. });
  563. });
  564. // loaders