canvas.js 73 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788
  1. /* Contains all the Javascript logic of the canvas and its main features: save, export and share */
  2. $(document).ready(function() {
  3. /* ================================================
  4. Miscellaneous
  5. ================================================= */
  6. // Declare the currently loaded tags belonging to the user
  7. var tags;
  8. // Show tooltip for every category
  9. $("[data-toggle='tooltip']").tooltip({container: "body"});
  10. // Fix to make the "X" in the Close button in dialogs show up
  11. $.fn.bootstrapBtn = $.fn.button.noConflict();
  12. // This piece of code is for making the column-count and column-gap CSS to work in Firefox
  13. document.getElementById("7-5-col-layout").style.MozColumnCount = "5";
  14. document.getElementById("4-col-layout").style.MozColumnCount = "4";
  15. // Prevent pressing ENTER on Project Title from submitting the form
  16. $('.proj_title').keydown(function(event){
  17. if(event.keyCode == 13) {
  18. event.preventDefault();
  19. return false;
  20. }
  21. });
  22. /* ================================================
  23. Rearrange fields numerically if 1 column is displayed
  24. ================================================= */
  25. // Declarations
  26. var groupOneLayout = $("#7-5-col-layout");
  27. var groupTwoLayout = $("#4-col-layout");
  28. var field01 = $("#panel_01");
  29. var field03 = $("#panel_03");
  30. var field04 = $("#panel_04");
  31. var field09 = $("#panel_09");
  32. var field05 = $("#panel_05");
  33. var field06 = $("#panel_06");
  34. var field02 = $("#panel_02");
  35. var field07 = $("#panel_07");
  36. var field08 = $("#panel_08");
  37. var isRearranged = false;
  38. // Rearrange the fields to suit mobile
  39. function rearrangeFields() {
  40. field01.detach();
  41. field03.detach();
  42. field04.detach();
  43. field09.detach();
  44. field05.detach();
  45. field06.detach();
  46. field02.detach();
  47. field07.detach();
  48. field08.detach();
  49. groupOneLayout.append(field01);
  50. groupOneLayout.append(field02);
  51. groupOneLayout.append(field03);
  52. groupOneLayout.append(field04);
  53. groupOneLayout.append(field05);
  54. groupOneLayout.append(field06);
  55. groupOneLayout.append(field07);
  56. groupOneLayout.append(field08);
  57. groupOneLayout.append(field09);
  58. }
  59. // Rearrange the fields according to their original order
  60. function rearrangeFieldsOriginal() {
  61. field01.detach();
  62. field02.detach();
  63. field03.detach();
  64. field04.detach();
  65. field05.detach();
  66. field06.detach();
  67. field07.detach();
  68. field08.detach();
  69. field09.detach();
  70. groupOneLayout.append(field01);
  71. groupOneLayout.append(field03);
  72. groupOneLayout.append(field04);
  73. groupOneLayout.append(field09);
  74. groupOneLayout.append(field05);
  75. groupOneLayout.append(field06);
  76. groupOneLayout.append(field02);
  77. groupTwoLayout.append(field07);
  78. groupTwoLayout.append(field08);
  79. }
  80. // If the webpage is opened on a mobile
  81. if ($(window).width() <= 499) {
  82. rearrangeFields();
  83. }
  84. // When resizing the window
  85. $(window).on("resize", function() {
  86. if (isRearranged === false && $(window).width() <= 499) {
  87. rearrangeFields();
  88. isRearranged = true;
  89. }
  90. else if(isRearranged === true && $(window).width() >= 500) {
  91. rearrangeFieldsOriginal();
  92. isRearranged = false;
  93. }
  94. });
  95. /* ================================================
  96. "Jump to" functions
  97. ================================================= */
  98. // When the user scrolls down, change "position" to "fixed"
  99. $(window).scroll(function() {
  100. var scrollPosition = $(window).scrollTop();
  101. // var firstFieldPosition = $("div.field_01").offset().top;
  102. var firstFieldPosition = $("div.saved-tags").offset().top;
  103. // If the user has scrolled down to the first field
  104. if(scrollPosition >= firstFieldPosition) {
  105. $("div.jump-to").css("display", "block");
  106. }
  107. else {
  108. $("div.jump-to").css("display", "none");
  109. }
  110. });
  111. // When the user clicks on "Jump to", show menu
  112. $("div.jump-to > div > a").on("click", function() {
  113. // Toggle the menu
  114. $("div.jump-to ul").slideToggle(300);
  115. // Rotate arrow
  116. // $("div.jump-to span.jump-to-arrow").toggleClass("rotate-arrow-180");
  117. // $("div.jump-to span.jump-to-arrow").toggleClass("rotate-arrow-0");
  118. $(".arrow-img").toggleClass("rotate1");
  119. $(".arrow-img").toggleClass("rotate2");
  120. return false;
  121. });
  122. // When the user clicks on a menu item
  123. $("div.jump-to ul a").on("click", function() {
  124. // Declarations
  125. var chosenLiIndex = $(this).parent().index();
  126. var chosenFieldPosition;
  127. var scrollPositionNew;
  128. // Toggle the menu
  129. $("div.jump-to ul").slideToggle(300);
  130. // Rotate arrow
  131. // $("div.jump-to span.jump-to-arrow").toggleClass("rotate-arrow-180");
  132. // $("div.jump-to span.jump-to-arrow").toggleClass("rotate-arrow-0");
  133. $(".arrow-img").toggleClass("rotate1");
  134. $(".arrow-img").toggleClass("rotate2");
  135. // If the user has chosen the list item 0
  136. if(chosenLiIndex === 0) {
  137. chosenFieldPosition = $("div.saved-tags").offset().top;
  138. }
  139. // If the user has chosen the list item 1-9
  140. else if(chosenLiIndex >= 1 && chosenLiIndex <= 9) {
  141. chosenFieldPosition = $("div.field_0" + chosenLiIndex).offset().top;
  142. }
  143. // If the user has chosen the list item 10 or higher
  144. else {
  145. chosenFieldPosition = $("div.field_" + chosenLiIndex).offset().top;
  146. }
  147. // If the user has chosen to jump to "Saved Tags"
  148. if(chosenLiIndex === 0) {
  149. scrollPositionNew = chosenFieldPosition - 14; // 14 // - $("div.jump-to").height() + 38;
  150. }
  151. // If the user has chosen to jump to a category
  152. else {
  153. scrollPositionNew = chosenFieldPosition - 57; // 77 // - $("div.jump-to").height() - 20;
  154. }
  155. $(window).scrollTop(scrollPositionNew);
  156. return false;
  157. });
  158. /* ================================================
  159. Remove all tags from all fields
  160. ================================================= */
  161. // Remove all tags from all fields
  162. function removeTags() {
  163. // AJAX
  164. $.ajax({
  165. type: "POST",
  166. url: "php/get-tags.php",
  167. dataType: "JSON",
  168. data: {
  169. "username": username
  170. },
  171. timeout: 5000,
  172. success: function(returnData) {
  173. // Declarations
  174. var loopCounter = 0;
  175. tags = returnData;
  176. // For every added item
  177. $("li.added_item div").each(function() {
  178. var thisDiv = $(this); // Delete the declaration (because it's ugly!)
  179. // For every tag in the database that belongs to the active user
  180. for(t in tags) {
  181. // If the current tag exists in the textarea
  182. if(thisDiv.html().indexOf("</a>") != -1) {
  183. // Delete the tag
  184. var text = thisDiv.html();
  185. text = thisDiv.text().replace("<a class='tag'>" + tags[loopCounter] + "</a>", tags[loopCounter]);
  186. thisDiv.html(text);
  187. }
  188. loopCounter++;
  189. }
  190. });
  191. if(tags.length === 0) {
  192. $("div.saved-tags p").html("You haven't added any tags yet.");
  193. }
  194. },
  195. error: function(xhr) {
  196. console.log(xhr.statusText);
  197. }
  198. });
  199. /*
  200. // The code below is much better than the code above, because no database connection is being called, but the "You haven't added any tags yet" text is not being reset
  201. // Declarations
  202. var loopCounter = 0;
  203. // For every added item
  204. $("li.added_item div").each(function() {
  205. var thisDiv = $(this); // Delete the declaration (because it's ugly)
  206. // For every tag that belongs to the active user
  207. for(t in tags) {
  208. // If the current tag exists in the textarea
  209. if(thisDiv.html().indexOf("</a>") != -1) {
  210. // Delete the tag
  211. var text = thisDiv.html();
  212. text = thisDiv.text().replace("<a class='tag'>" + tags[loopCounter] + "</a>", tags[loopCounter]);
  213. thisDiv.html(text);
  214. }
  215. loopCounter++;
  216. }
  217. });
  218. console.log(tags);
  219. console.log(tags.length);
  220. if(tags.length === 0) {
  221. $("div.saved-tags p").html("You haven't added any tags yet.");
  222. }
  223. */
  224. }
  225. /* ================================================
  226. Get the user's tags from the database and apply them on the canvas
  227. ================================================= */
  228. // Apply tags (Incoming parameter is an array with every tag from the database belonging to the active user)
  229. function applyTags() {
  230. var loopCounter = 0;
  231. // For every added item
  232. // $("li.added_item textarea").each(function() {
  233. $("li.added_item div").each(function() {
  234. // Here the selector is retrieving the objects it is supposed to...
  235. // For every tag in the database that belongs to the active user
  236. for(t in tags) {
  237. // console.log("tags.length: " + tags.length);
  238. // console.log("tag: " + tags[loopCounter]);
  239. // console.log($(this));
  240. // console.log("Now working with " + tags[loopCounter]);
  241. // console.log($(this).html());
  242. // console.log("The tag " + tags[loopCounter] + " has index '" + tags[loopCounter].indexOf("&nbsp;") + "' for '&nbsp;'");
  243. var text = $(this).html();
  244. // If the current tag exists in the textarea
  245. if(text.indexOf(tags[loopCounter]) != -1) {
  246. // console.log($(this).html());
  247. // ... But here the selector only seems to retrieve the first instance
  248. // console.log("Inside if!");
  249. // Apply the tag
  250. text = text.replace(tags[loopCounter], "<a class='tag' contenteditable='false'>" + tags[loopCounter] + "</a>");
  251. $(this).html(text);
  252. }
  253. loopCounter++;
  254. }
  255. });
  256. // Populate "Saved Tags"
  257. loopCounter = 0;
  258. var savedTags = $("div.saved-tags p");
  259. savedTags.html("");
  260. for(t in tags) {
  261. if(savedTags.html() === "You haven't added any tags yet.") {
  262. savedTags.html("");
  263. }
  264. savedTags.append("<a href='#' class='tag'>" + tags[loopCounter] + "</a>").append("&nbsp;&nbsp; ");
  265. loopCounter++;
  266. }
  267. }
  268. // Get the tags from the database
  269. function getTags() {
  270. // Declarations
  271. var username = $("input[name='username']").val();
  272. // AJAX
  273. $.ajax({
  274. type: "POST",
  275. url: "php/get-tags.php",
  276. dataType: "JSON",
  277. data: {
  278. "username": username
  279. },
  280. timeout: 5000,
  281. success: function(returnData) {
  282. if(returnData.length > 0) {
  283. // Assign returnData to the tags variable
  284. tags = returnData;
  285. // Sort the tags
  286. returnData.sort(function (a, b) {
  287. return a.toLowerCase().localeCompare(b.toLowerCase())
  288. });
  289. // Apply the tags on the canvas
  290. applyTags();
  291. showTagWindowOnTagClick();
  292. }
  293. },
  294. error: function(xhr) {
  295. console.log(xhr.statusText);
  296. }
  297. });
  298. }
  299. /* ================================================
  300. Load tags if the user is logged in
  301. ================================================= */
  302. if($("input[name='name']").val() != "") {
  303. getTags();
  304. }
  305. /* ================================================
  306. Tag window functions
  307. ================================================= */
  308. // Declarations
  309. // var textarea = $("div#tag-window textarea#tag-description");
  310. var textareaHasBeenChanged = false;
  311. var tag;
  312. var tagIsNew = false;
  313. var username = $("input[name='username']").val();
  314. // Check if the tag is new
  315. function checkIfTagIsNew() {
  316. // Declarations
  317. var tagToAJAX = tag;
  318. // AJAX
  319. $.ajax({
  320. type: "POST",
  321. url: "php/check-if-tag-exists.php",
  322. dataType: "text",
  323. data: {
  324. "tag": tagToAJAX,
  325. "username": username
  326. },
  327. timeout: 5000,
  328. success: function(returnData) {
  329. // If the current tag does not exist in the database
  330. if(returnData === "") {
  331. // Hide "Delete tag" button
  332. $("div#tag-window button#delete-tag").css("display", "none");
  333. // Hide "Similar tags"
  334. $("div#tag-window h2.similar-tags").css("display", "none");
  335. // The tag is new
  336. tagIsNew = true;
  337. }
  338. // If the current tag exists in the database
  339. else {
  340. // Show "Delete tag" button
  341. $("div#tag-window button#delete-tag").css("display", "inline");
  342. // Show "Similar tags"
  343. $("div#tag-window h2.similar-tags").css("display", "block");
  344. }
  345. },
  346. error: function(xhr) {
  347. console.log(xhr.statusText);
  348. }
  349. });
  350. }
  351. // Updating the remaining characters information
  352. function updateRemainingCharacters() {
  353. // Declarations
  354. var length = $("div#tag-window textarea#tag-description").val().length; // Retrieving from "Please enter a description..."
  355. var maxLength = 200;
  356. /*
  357. var length;
  358. if(description != "") {
  359. length = description;
  360. }
  361. else {
  362. length = $("div#tag-window textarea#tag-description").val().length;
  363. }
  364. */
  365. // Update length
  366. length = maxLength - length;
  367. // Show the remaining characters
  368. $("div#tag-window span.chars").text(length);
  369. }
  370. // Get the description for the selected tag
  371. function getDescriptionForSelectedTag() {
  372. // Declarations
  373. var tagToAJAX = tag;
  374. // AJAX
  375. $.ajax({
  376. type: "POST",
  377. url: "php/get-description-for-selected-tag.php",
  378. dataType: "text",
  379. data: {
  380. "tag": tagToAJAX,
  381. "username": username
  382. },
  383. timeout: 5000,
  384. success: function(returnData) {
  385. if(returnData != "") {
  386. // Update description field with the description for the selected tag
  387. $("div#tag-window textarea#tag-description").val(returnData);
  388. // Update remaining characters
  389. updateRemainingCharacters();
  390. }
  391. textareaHasBeenChanged = true;
  392. },
  393. error: function(xhr) {
  394. console.log(xhr.statusText);
  395. }
  396. });
  397. }
  398. // Get similar tags by other users
  399. function getSimilarTags() {
  400. // Declarations
  401. var tagToAJAX = tag;
  402. // AJAX
  403. $.ajax({
  404. type: "POST",
  405. url: "php/get-similar-tags.php",
  406. dataType: "JSON",
  407. data: {
  408. "tag": tagToAJAX,
  409. "username": username
  410. },
  411. timeout: 5000,
  412. success: function(returnData) {
  413. // Reset similar tags if similar tags are to be showed again
  414. $("p.similar-tags-tag").remove();
  415. $("p.similar-tags-description").remove();
  416. $("p.similar-tags-username").remove();
  417. // Declarations
  418. var htmlToAppend = "";
  419. // If similar tags exist
  420. if(returnData.length > 0) {
  421. // Declarations
  422. var index = 0;
  423. // While there still are tags to append
  424. while(index < returnData.length) {
  425. htmlToAppend += "<p class='similar-tags-tag'><a class='tag'>" + returnData[index]["tag"] + "</a></p>"
  426. + "<p class='similar-tags-description'>" + returnData[index]["description"] + "</p>"
  427. + "<p class='similar-tags-username'>by <a href='#'>" + returnData[index]["username"] + "</a></p>";
  428. index++;
  429. }
  430. // Append tags
  431. $("div#tag-window h2.similar-tags").after(htmlToAppend);
  432. $("p.similar-tags-description-none").css("display", "none");
  433. // Apply the tags on the canvas
  434. // applyTags();
  435. // showTagWindowOnTagClick();
  436. }
  437. else {
  438. // If the tag isn't a new tag
  439. if(tagIsNew === false) {
  440. // Show the message saying that there are no similar tags to show
  441. $("p.similar-tags-description-none").css("display", "block");
  442. }
  443. }
  444. },
  445. error: function(xhr) {
  446. console.log(xhr.statusText);
  447. }
  448. });
  449. }
  450. // Close the tag window
  451. function closeTagWindow() {
  452. $("div#shadow").css("display", "none");
  453. $("div#tag-window").css("display", "none");
  454. }
  455. // Show the tag window
  456. function showTagWindow() {
  457. // Show the tag window
  458. $("div#shadow").css("display", "block");
  459. $("div#tag-window").css("display", "block");
  460. // Move the window to the centre of the screen
  461. /*
  462. The code below should be working, but the height of the second selector seems completely wrong!
  463. var middle = (document.body.clientHeight / 2) - ($("div#tag-window").height() / 2);
  464. $("div#tag-window").css("top", middle);
  465. */
  466. // Check if the tag is new
  467. checkIfTagIsNew();
  468. // Get the description for the selected tag
  469. getDescriptionForSelectedTag();
  470. // Get tags by other users from the database
  471. getSimilarTags();
  472. // Update remaining characters in case description is loaded
  473. updateRemainingCharacters();
  474. // If a description hasn't been entered
  475. if($("div#tag-window textarea#tag-description") !== "Please enter a description..." && textareaHasBeenChanged !== true) {
  476. // Reset the remaining characters information
  477. $("div#tag-window span.chars").text("200");
  478. }
  479. }
  480. // When the user presses a key in the description textarea
  481. $("div#tag-window textarea#tag-description").on("keyup", function() {
  482. // Update remaining characters
  483. updateRemainingCharacters();
  484. });
  485. // When the user clicks on the "Save tag" button
  486. $("div#tag-window #save-tag").on("click", function() {
  487. // Declarations
  488. var description = $("div#tag-window textarea#tag-description").val();
  489. var tagToAJAX = tag;
  490. // If a description has been entered
  491. if(description != "" && description != "Please enter a description...") {
  492. // AJAX
  493. $.ajax({
  494. timeout: 5000,
  495. dataType: "text",
  496. type: "post",
  497. data: {
  498. "tag": tagToAJAX,
  499. "description": description,
  500. "username": username
  501. },
  502. url: "php/save-tag.php",
  503. success: function() {
  504. textareaHasBeenChanged = true;
  505. // Get the user's tags from the database and apply them on the canvas
  506. getTags();
  507. },
  508. error: function(xhr) {
  509. console.log(xhr.statusText);
  510. }
  511. });
  512. // Close the tag window
  513. closeTagWindow();
  514. }
  515. tagIsNew = false;
  516. });
  517. // When the user clicks on the "Close" button
  518. $("div#tag-window button.close").on("click", function() {
  519. // Close the tag window
  520. closeTagWindow();
  521. });
  522. // When the user clicks on the "Delete tag" button
  523. $("div#tag-window #delete-tag").on("click", function() {
  524. // Declarations
  525. var tagToAJAX = tag;
  526. // AJAX
  527. $.ajax({
  528. timeout: 5000,
  529. dataType: "text",
  530. type: "post",
  531. data: {
  532. "tag": tagToAJAX,
  533. "username": username
  534. },
  535. url: "php/delete-tag.php",
  536. success: function() {
  537. // Remove all tags from all fields
  538. removeTags();
  539. // Get the user's tags from the database and apply them on the canvas
  540. getTags();
  541. },
  542. error: function(xhr) {
  543. console.log(xhr.statusText);
  544. }
  545. });
  546. // Close the tag window
  547. closeTagWindow();
  548. });
  549. // When the user focuses in the textarea
  550. $("div#tag-window textarea#tag-description").on("focusin", function() {
  551. // Declarations
  552. var description = $("div#tag-window textarea#tag-description").val();
  553. // If a description hasn't been entered
  554. // if(textareaHasBeenChanged === false) {
  555. if(description === "Please enter a description...") {
  556. // Empty the description textarea
  557. $("div#tag-window textarea#tag-description").val("");
  558. }
  559. });
  560. // When the user focuses out the textarea
  561. $("div#tag-window textarea#tag-description").on("focusout", function() {
  562. // Declarations
  563. var description = $("div#tag-window textarea#tag-description").val();
  564. // If a description hasn't been entered
  565. // if(textareaHasBeenChanged === false) {
  566. if(description === "") {
  567. // Reset the description textarea
  568. $("div#tag-window textarea#tag-description").val("Please enter a description...");
  569. }
  570. });
  571. /* ================================================
  572. When the user types a new character in the added idea field, add tag if a term could be found
  573. ================================================= */
  574. // 8an33j24
  575. function applyTagOnTypeMatch() {
  576. $("li.added_item div").on("focusin", function() {
  577. // When the user presses a key in the description textarea
  578. $("li.added_item div").on("keyup", function() {
  579. if(event.which !== 9 && // Tab
  580. event.which !== 16 && // Shift
  581. event.which !== 37 && // Left
  582. event.which !== 38 && // Up
  583. event.which !== 39 && // Right
  584. event.which !== 40) { // Down
  585. // Declarations
  586. var bugCounter = 0;
  587. var loopCounter = 0;
  588. var tagLinkToSearch;
  589. var tagLinkHits;
  590. var tagTextToSearch;
  591. var tagTextHits;
  592. var text = $(this).html();
  593. // Fix the bug that triggers the event twice
  594. if(!bugCounter > 0) {
  595. /*
  596. console.log("tagTextHits: " + tagTextHits);
  597. console.log("tagLinkHits: " + tagLinkHits);
  598. */
  599. // For every tag that belongs to the active user
  600. for(t in tags) {
  601. if($(this).html().indexOf(tags[loopCounter]) != -1) {
  602. // Search for the tag inside the added idea as a link
  603. tagLinkToSearch = text.match(tags[loopCounter] + "</a>"); // match() can only count to one instance (67hi9nt3)
  604. // Search for the tag inside the added idea as plain text
  605. tagTextToSearch = text.match(tags[loopCounter]); // match() can only count to one instance (67hi9nt3)
  606. // If the tag exists inside the added idea as a link
  607. if(tagLinkToSearch !== null) {
  608. // tagLinkHits = 1
  609. tagLinkHits = tagLinkToSearch.length;
  610. }
  611. else {
  612. // tagLinkHits = 0
  613. tagLinkHits = 0;
  614. }
  615. // If the tag exists inside the added idea as plain text
  616. if(tagTextToSearch !== null) {
  617. // tagTextHits = 1
  618. tagTextHits = tagTextToSearch.length;
  619. }
  620. else {
  621. // tagTextHits = 0
  622. tagTextHits = 0;
  623. }
  624. // If there are more instances of the tag as plain text than the tag as links, and there is a maximum of 1 instances of the tag as plain text
  625. // Change "tagTextHits <= 1" to "tagLinkHits === 0"
  626. if(tagTextHits > tagLinkHits && tagLinkHits === 0) {
  627. // Apply the tag
  628. text = text.replace(tags[loopCounter], "<a class='tag' contenteditable='false'>" + tags[loopCounter] + "</a>");
  629. $(this).html(text);
  630. }
  631. }
  632. loopCounter++;
  633. }
  634. }
  635. bugCounter++;
  636. }
  637. });
  638. });
  639. };
  640. /* ----------------------------------------------
  641. Limiting the number of characters the user is able to type
  642. ----------------------------------------------- */
  643. var maxLength = 100;
  644. $('.card').on('keyup', '.new_item', function() {
  645. var length = $(this).val().length;
  646. length = maxLength - length;
  647. // show the characters remaining only on this field
  648. $(this).closest('.user-input').find('.chars').text(length);
  649. });
  650. function limitLengthOnInput() {
  651. // Limit text on key press
  652. $("li.added_item div").on("keypress", function(event) {
  653. // Declarations
  654. var numberOfTags = $(this).children().filter("a").length;
  655. var textLength = $(this).html().length;
  656. // Subtract 43 from textLength per tag (the tag HTML is 43 characters)
  657. $(this).each(function() {
  658. textLength -= 43 * numberOfTags;
  659. });
  660. if(textLength === 100) { // Windows menu/Right cmd
  661. event.preventDefault();
  662. }
  663. });
  664. // 28jek79t
  665. // Limit text on paste
  666. /*
  667. $("li.added_item div").on("paste", function(event) {
  668. var pastedText;
  669. $("li.added_item div").bind("paste", function(e) {
  670. pastedText = e.originalEvent.clipboardData.getData("Text");
  671. console.log(pastedText);
  672. if($(this).html().length + pastedText >= 100) {
  673. event.preventDefault();
  674. }
  675. });
  676. // var text = $(this).html()
  677. // var length = text.length;
  678. // var newText = text.substring(0, maxLength);
  679. // if(length >= maxLength) {
  680. // $(this).html(newText);
  681. // Move the text cursor to the very end
  682. }
  683. });
  684. */
  685. }
  686. /* ================================================
  687. The user clicks on the "Tag selected term" link
  688. ================================================= */
  689. // Declaration
  690. var selection = "";
  691. // var newRange = "";
  692. // Initiate tag
  693. tag = "";
  694. // Update the tag variable
  695. document.onselectionchange = function() {
  696. // if($("textarea").is(":focus")) {
  697. if($("li.added_item div").is(":focus")) { // This is nicer: $("li.added_item div").on("focusin", function() {
  698. selection = window.getSelection().toString();
  699. tag = selection.trim();
  700. }
  701. }
  702. // When the user clicks on the "Tag selected term" link
  703. $("p.tag-selected-term a").on("click", function() {
  704. // If the tag isn't empty
  705. if(tag != "") {
  706. // Show the tag window
  707. showTagWindow();
  708. }
  709. else {
  710. // Show a dialog
  711. $("div#shadow").css("display", "block");
  712. $("#dialog-select-term").dialog({draggable: false, resizable: false});
  713. // Style the close button inside the dialog
  714. $(".ui-button-icon-only").html("<button type='button' class='close' aria-label='Close'><span aria-hidden='true'>&times;</span></button>");
  715. }
  716. // Prevent the current view to jump to the top of the screen
  717. return false;
  718. });
  719. // Hide the shadow when closing a dialog
  720. $(".dialog").on("dialogclose", function() {
  721. $("div#shadow").css("display", "none");
  722. });
  723. // When the user moves the focus from the added idea, reset variables
  724. // $("li.added_item textarea").on("focusout", function() {
  725. $("li.added_item div").on("focusout", function() {
  726. selection = "";
  727. tag = "";
  728. });
  729. /* ================================================
  730. When the user clicks on a tag, show the tag window
  731. ================================================= */
  732. // When the user clicks on a tag
  733. function showTagWindowOnTagClick() {
  734. $("a.tag").on("click", function() { // Event not triggered...
  735. // Declarations
  736. tag = $(this).text();
  737. // If the user is logged in
  738. if($("input[name='username']").val() != "") {
  739. // Show the tag window
  740. showTagWindow();
  741. }
  742. else {
  743. // Show a dialog
  744. $("div#shadow").css("display", "block");
  745. $("#dialog-log-in").dialog({draggable: false, resizable: false});
  746. // Style the close button inside the dialog
  747. $(".ui-button-icon-only").html("<button type='button' class='close' aria-label='Close'><span aria-hidden='true'>&times;</span></button>");
  748. }
  749. });
  750. }
  751. /*
  752. // Mouse-enabled devices
  753. $("tag").mouseenter(function() {
  754. timer = setTimeout(function() {
  755. showTagWindow(); // showTagWindow needs a parameter!
  756. }, 400);
  757. }).mouseleave(function() {
  758. clearTimeout(timer);
  759. });
  760. // Touch devices
  761. try {
  762. document.createEvent("TouchEvent");
  763. $("a.tag").on("click", showTagWindow()); // showTagWindow needs a parameter!
  764. return true;
  765. }
  766. catch(e) {
  767. return false;
  768. }
  769. */
  770. /* ================================================
  771. Serialize Form to JSON
  772. ================================================= */
  773. $.fn.serializeObject = function() {
  774. var o = {};
  775. var a = this.serializeArray();
  776. $.each(a, function() {
  777. if (o[this.name]) {
  778. if (!o[this.name].push) {
  779. o[this.name] = [o[this.name]];
  780. }
  781. o[this.name].push(this.value || '');
  782. } else {
  783. o[this.name] = this.value || '';
  784. }
  785. });
  786. return o;
  787. };
  788. /* ================================================
  789. Getting the current date
  790. ================================================= */
  791. var fullDate = new Date();
  792. var twoDigitMonth = fullDate.getMonth() + "";
  793. if (twoDigitMonth.length == 1) twoDigitMonth = "0" + twoDigitMonth;
  794. var twoDigitDate = fullDate.getDate() + "";
  795. if (twoDigitDate.length == 1) twoDigitDate = "0" + twoDigitDate;
  796. var currentDate = fullDate.getFullYear() + "-" + twoDigitMonth + "-" + twoDigitDate;
  797. // set the currebt date in the date input field
  798. $('.proj_date').val(currentDate);
  799. /* ================================================
  800. USER LOGS OUT (dropdown menu)
  801. ================================================= */
  802. $('.user-profile').on('click', '#logout', function() {
  803. var url = 'php/logout.php';
  804. $.post(url, function(data, status) {
  805. if (data == 200) {
  806. $('.user-profile').hide();
  807. window.location.href="https://www.ethicscanvas.org";
  808. }
  809. });
  810. });
  811. /* ================================================
  812. When the page loads, Import the chosen canvas if the user has picked one from the dashbord,
  813. otherwise load an empty canvas
  814. ================================================= */
  815. // if a canvas is chosen by the user to be loaded
  816. if (current_canvas_id !== '') {
  817. var url = 'json/' + current_canvas_id + '.json';
  818. // var url= 'json/test_canvas.json';
  819. // get the saved ISON object in the sendJSON.text file
  820. $.getJSON(url, function(returnedObj) {
  821. // Display the json data in the html
  822. var itemListHTML = '';
  823. // iterate through the object
  824. $.each(returnedObj, function(key, value) {
  825. // project name and tem field
  826. if (key === 'field_00[]') {
  827. $('.form-header').find('input.proj_title').val(value[
  828. 0]);
  829. $('.form-header').find('input.proj_date').val(value[1]);
  830. }
  831. else if (key !== 'new_item') {
  832. if ($.type(value) === "array") {
  833. $.each(value, function(i, itm) {
  834. /** FIX DUPLICATIONs in the canvas when importing
  835. /* Importing will override the canvas content
  836. clear the canvas by giving en emty content to the ul list (remove previous list items) */
  837. $('.canvas-form').find('.card').filter('.' + key.substr(0, 8)).find('ul.item_list').html('');
  838. /* Create a list item with each value item
  839. and give it text area with the name attribute as the "key" (right field name) */
  840. itemListHTML +=
  841. // '<li class="added_item"><span class="handle glyphicon glyphicon-move"></span><textarea maxlength="100" class="expandable" rows="3" data-limit-rows="true" data-autoresize name="' + key + '">' + itm + '</textarea><span class="remove glyphicon glyphicon-remove-circle"></span></li>';
  842. '<li class="added_item"><div class="expandable" name="' + key + '" contenteditable="true">' + itm + '</div><span class="handle glyphicon glyphicon-list"></span><span class="move-up glyphicon glyphicon-chevron-up"></span><span class="move-down glyphicon glyphicon-chevron-down"></span><span class="remove glyphicon glyphicon-remove-circle"></span></li>';
  843. });
  844. }
  845. else { // a single value string
  846. itemListHTML +=
  847. // '<li class="added_item"><span class="handle glyphicon glyphicon-move"></span><textarea maxlength="100" class="expandable" rows="3" data-limit-rows="true" data-autoresize name="' + key + '">' + value + '</textarea><span class="remove glyphicon glyphicon-remove-circle"></span></li>';
  848. '<li class="added_item"><div class="expandable" name="' + key + '" contenteditable="true">' + value + '</div><span class="handle glyphicon glyphicon-list"></span><span class="move-up glyphicon glyphicon-chevron-up"></span><span class="move-down glyphicon glyphicon-chevron-down"></span><span class="remove glyphicon glyphicon-remove-circle"></span></li>';
  849. }
  850. /* Append the created list items/textatreas to the right field based on the "key"*/
  851. /* the str.substr(start,length)
  852. is used to remove the [] from the end of the "key"name (for each field. also the name attributes accociated with each fiels) so that we can select the right class (right field) and append the created lists to the right field
  853. so field names/key/name attribute will tuen into class names: ex: field_1[] becomes field_1
  854. */
  855. // find the field by its class names besed on the current key name
  856. // append the created list of item values to that right field
  857. $('.canvas-form').find('.card').filter('.' + key.substr(0, 8)).find('ul.item_list').append(itemListHTML);
  858. /*$('form').find('.card').filter('.field_1').find('ul.item_list').append(itemListHTML); */
  859. /* !! Empty the item list after each count of "key" so that the previous item lists from the other fields (associated with the previous key) don't get added up to the item list of other fields */
  860. itemListHTML = '';
  861. }
  862. });
  863. });
  864. // Get the user's tags from the database and apply them on the canvas
  865. getTags();
  866. // Show "Tag selected term" link
  867. if($(this).parent().parent().parent().prev().prev().children().length > 0) {
  868. $(this).parent().parent().parent().prev().css("display", "block");
  869. }
  870. // Fix the heights after importing
  871. // fixHeights();
  872. }
  873. /* ================================================
  874. Toggle the introduction text in fields
  875. ================================================= */
  876. //$(selector).toggle(speed,easing,callback)
  877. $('.card').on('click', '.intro-toggle', function() {
  878. var $TogglingText = $($(this).closest('.card').find('.intro'));
  879. var $Toggler = $($(this).closest('.card').find('.intro-toggle'));
  880. $TogglingText.toggle('slow', function() {
  881. // Do this when toggling:
  882. // the boolean .is(':visible') of the current toggle state
  883. if ($TogglingText.is(':visible')) {
  884. // change the text of the toggle
  885. $Toggler.find('.intro-toggle-text').text('Hide description');
  886. // change the icon of the toggle
  887. $Toggler.find('.intro-toggle-icon').switchClass("glyphicon-plus-sign", "glyphicon-minus-sign", 1000, "easeInOutQuad");
  888. }
  889. else {
  890. $Toggler.find('.intro-toggle-text').text('Show description');
  891. $Toggler.find('.intro-toggle-icon').switchClass("glyphicon-minus-sign", "glyphicon-plus-sign", 1000, "easeInOutQuad");
  892. }
  893. });
  894. });
  895. /* ================================================
  896. Auto expand user input textareas
  897. ================================================= */
  898. /* Works for textareas already exsting in the html when the page loads -> User input
  899. $.each($('textarea[data-autoresize]'), function() {
  900. var offset = this.offsetHeight - this.clientHeight;
  901. var resizeTextarea = function(el) {
  902. $(el).css('height', 'auto').css('height', el.scrollHeight + offset);
  903. };
  904. $(this).on('keyup input', function() {
  905. resizeTextarea(this);
  906. }).removeAttr('data-autoresize');
  907. });
  908. /* ================================================
  909. Limiting the number of lines in textareas
  910. ================================================= */
  911. // <textarea data-limit-rows="true" cols="60" rows="8"></textarea>
  912. /*
  913. $('.card').on('keypress', 'textarea[data-limit-rows=true]', function(event) {
  914. var textarea = $(this),
  915. text = textarea.val(),
  916. // match() -> Searches a string for a match against a regular expression, and returns the matches, as an Array object.
  917. numberOfLines = (text.match(/\n/g) || []).length + 1,
  918. maxRows = parseInt(textarea.attr('rows'));
  919. // if the number of lines have reached the max rows
  920. if (numberOfLines === maxRows) {
  921. return false;
  922. }
  923. });
  924. */
  925. /* ================================================
  926. Handling user input, ADD items
  927. A. Add button
  928. B. Clicking enter
  929. ================================================= */
  930. /* ----------------------------------------------
  931. add new idea slide effect
  932. ----------------------------------------------- */
  933. // When clicking on "add a new idea", Slide down and show the input field for adding a new item (from the begining, it is set to display:hidden with CSS). If clicked again, slide it up. After that, set the textarea in automatic focus
  934. $('.card').on('click', 'a.add-idea', function(event) {
  935. // stop the default behavior of the link (jumping back to the start of the page)
  936. event.preventDefault();
  937. // set the textarea automatically in focus
  938. $(this).closest('.card').find('.user-input').slideToggle("slow", function() {
  939. // When the toggle animation is complete:
  940. // set the text area in focus
  941. $(this).closest('.card').find('.new_item').val('');
  942. $(this).closest('.card').find('.chars').text(maxLength);
  943. $(this).closest('.card').find('.new_item').focus();
  944. });
  945. });
  946. /* ----------------------------------------------
  947. A. When we click the add btn to
  948. add the item to the list
  949. ----------------------------------------------- */
  950. // event deligation to handle the present and future elements that are dynamically added
  951. $('.card').on('click', '.add_btn', function() {
  952. var new_item = $(this).closest('.card').find('.new_item').val();
  953. var new_item_height = $(this).closest('.card').find('.new_item').height();
  954. // number of items are in the list
  955. var fieldItemCount = $(this).closest('.card').find('ul.item_list').find('li').length;
  956. // new item added, increment the number of items
  957. fieldItemCount++;
  958. // add the input value as a textarea item
  959. /* create a name attribute in the "field_nr[]" format to be able to tag each new item with the right field attr name (based on the field they are added to). This is to format the json file for each group of dynamically added items. We get the name attribute directly from the id attribute of the ul list in each card (the one we pressed the add button in) */
  960. // if the new item input exist (is not empty), add the item
  961. if (new_item) {
  962. var field_attr = $(this).closest('.card').find('ul.item_list').attr('id') + '[]';
  963. // The height of the newly added item = the height of the add new idea textarea
  964. $(this).closest('.card').find('ul.item_list').append(
  965. // '<li class="added_item"><span class="handle glyphicon glyphicon-move"></span><textarea maxlength="100" class="expandable" rows="3" data-limit-rows="true" data-autoresize name="' + field_attr + '">' + new_item + '</textarea><span class="remove glyphicon glyphicon-remove-circle"></span></li>'
  966. '<li class="added_item"><div class="expandable" name="' + field_attr + '" contenteditable="true">' + new_item + '</div><span class="handle glyphicon glyphicon-list"></span><span class="move-up glyphicon glyphicon-chevron-up"></span><span class="move-down glyphicon glyphicon-chevron-down"></span><span class="remove glyphicon glyphicon-remove-circle"></span></li>'
  967. );
  968. // Fix the heights only after a new item is added
  969. // fixHeights();
  970. }
  971. // clear the new item the text area value
  972. $(this).closest('.card').find('.new_item').val('');
  973. /* When clicking on "add idea", hide the input field for adding a new item (slideUp() doesn't work nicely here)*/
  974. $(this).closest('.card').find('.user-input').hide("fast", function() {
  975. // Animation complete.
  976. });
  977. // Limit the text in the idea field if it reaches the max length
  978. limitLengthOnInput();
  979. // Apply event listener to the added idea handling the application of tags should the user writes one of the terms in it
  980. applyTagOnTypeMatch();
  981. // Remove all tags from all fields
  982. removeTags();
  983. // Get the user's tags from the database and apply them on the canvas
  984. getTags(); // Really necessary?
  985. // Show "Tag selected term" link
  986. if($(this).parent().parent().prev().prev().children().length > 0) {
  987. $(this).parent().parent().prev().css("display", "block");
  988. }
  989. });
  990. /* ----------------------------------------------
  991. B. Clicking enter in the add idea textarea,
  992. will add the new item to the card
  993. ----------------------------------------------- */
  994. $('.card').on('keypress', 'textarea[data-limit-rows=true]', function(event) {
  995. var textarea = $(this);
  996. var text = textarea.val();
  997. /* The jQuery event.which -->
  998. Returns which keyboard key was pressed: */
  999. // if the enter is pressed, event.which === 13
  1000. if (event.which === 13) {
  1001. var new_item = $(this).closest('.card').find('.new_item').val();
  1002. var new_item_height = $(this).closest('.card').find('.new_item').height();
  1003. // number of items are in the list
  1004. var fieldItemCount = $(this).closest('.card').find('ul.item_list')
  1005. .find('li').length;
  1006. // new item added, increment the number of items
  1007. fieldItemCount++;
  1008. // add the input value as a textarea item
  1009. /* create a name attribute in the "field_nr[]" format to be able to tag each new item with the right field attr name (based on the field they are added to). This is to format the json file for each group of dynamically added items. We get the name attribute directly from the id attribute of the ul list in each card (the one we pressed the add button in) */
  1010. // if the new item input exist (is not empty), add the item
  1011. if (new_item) {
  1012. var field_attr = $(this).closest('.card').find('ul.item_list').attr(
  1013. 'id') + '[]';
  1014. // The height of the newly added item = the height of the add new idea textarea
  1015. $(this).closest('.card').find('ul.item_list').append(
  1016. // '<li class="added_item"><span class="handle glyphicon glyphicon-move"></span><textarea maxlength="100" class="expandable" rows="3" data-limit-rows="true" data-autoresize name="' + field_attr + '">' + new_item + '</textarea><span class="remove glyphicon glyphicon-remove-circle"></span></li>');
  1017. '<li class="added_item"><div class="expandable" name="' + field_attr + '" contenteditable="true">' + new_item + '</div><span class="handle glyphicon glyphicon-list"></span><span class="move-up glyphicon glyphicon-chevron-up"></span><span class="move-down glyphicon glyphicon-chevron-down"></span><span class="remove glyphicon glyphicon-remove-circle"></span></li>'
  1018. );
  1019. // Fix the heights only after a new item is added
  1020. // fixHeights();
  1021. }
  1022. // clear the new item the text area value
  1023. $(this).closest('.card').find('.new_item').val('');
  1024. /* When clicking on "add idea", hide the input field for adding a new item (slideUp() doesn't work nicely here)*/
  1025. $(this).closest('.card').find('.user-input').hide("fast", function() {
  1026. // Animation complete.
  1027. });
  1028. // Limit the text in the idea field if it reaches the max length
  1029. limitLengthOnInput();
  1030. // Apply event listener to the added idea handling the application of tags should the user writes one of the terms in it
  1031. applyTagOnTypeMatch();
  1032. // Remove all tags from all fields
  1033. removeTags();
  1034. // Get the user's tags from the database and apply them on the canvas
  1035. getTags(); // Really necessary?
  1036. // Show "Tag selected term" link
  1037. if($(this).parent().parent().parent().prev().prev().children().length > 0) {
  1038. $(this).parent().parent().parent().prev().css("display", "block");
  1039. }
  1040. }
  1041. });
  1042. /* ================================================
  1043. Moving ideas to a different category
  1044. ================================================= */
  1045. // Declarations
  1046. // var categoryUl = $("div#move-window ul");
  1047. var categoryDestination;
  1048. var categoryLis = $("div#move-window ul").html();
  1049. var categoryOrigin;
  1050. var ideaLi;
  1051. var linkLi;
  1052. var linkText;
  1053. // Remove the link to the current category, as the idea cannot be moved to its own category where it already is
  1054. function removeLinkToOriginCategory(text) {
  1055. // If the number of the category is between 10-99
  1056. if(text.substring(6, 7) != "0") {
  1057. categoryOrigin = text.substring(6, 9) - 1;
  1058. }
  1059. // If the number of the category is between 0-9
  1060. else {
  1061. categoryOrigin = text.substring(7, 9) - 1;
  1062. }
  1063. // Remove "a" tag
  1064. linkLi = $("div#move-window ul li").get(categoryOrigin);
  1065. linkText = $("div#move-window ul a").get(categoryOrigin).innerHTML;
  1066. linkLi.innerHTML = linkText;
  1067. }
  1068. // When the user clicks on the "Move" icon, show the move window
  1069. $('.card').on('click', 'span.handle', function() {
  1070. // Show the move window
  1071. $("div#shadow").css("display", "block");
  1072. $("div#move-window").css("display", "block");
  1073. // Assign the idea that is going to be moved
  1074. ideaLi = $(this).parent();
  1075. // Remove the link to the current category, as the idea cannot be moved to its own category where it already is
  1076. removeLinkToOriginCategory($(this).parent().parent().attr("id"));
  1077. });
  1078. // Close the move window
  1079. function closeMoveWindow() {
  1080. // Close the move window
  1081. $("div#shadow").css("display", "none");
  1082. $("div#move-window").css("display", "none");
  1083. }
  1084. // When the user clicks on the "Close" button
  1085. $("div#move-window button.close").on("click", function() {
  1086. // Close the move window
  1087. closeMoveWindow();
  1088. });
  1089. // When the user clicks on a category, move the idea
  1090. function moveIdeaOnClick() {
  1091. $("div#move-window ul a").on("click", function() {
  1092. // If the number of the category is between 10-99
  1093. if($(this).parent().text().trim().substring(1, 2) != ".") {
  1094. categoryDestination = $(this).parent().text().trim().substring(0, 2);
  1095. }
  1096. // If the number of the category is between 0-9
  1097. else {
  1098. categoryDestination = $(this).parent().text().trim().substring(0, 1);
  1099. }
  1100. // Move the idea
  1101. // If the number of the category is between 10-99
  1102. if(categoryDestination > 9) {
  1103. $("ul#field_" + categoryDestination).append(ideaLi);
  1104. // $("ul#field_0" + (categoryOrigin + 1)).parent().find("p.tag-selected-term").css("display", "none");
  1105. }
  1106. // If the number of the category is between 0-9
  1107. else {
  1108. $("ul#field_0" + categoryDestination).append(ideaLi);
  1109. // $("ul#field_0" + (categoryOrigin + 1)).parent().find("p.tag-selected-term").css("display", "none");
  1110. }
  1111. // Close the move window
  1112. closeMoveWindow();
  1113. // Restore links in the move window
  1114. if($("div#move-window li").length > $("div#move-window a").length) {
  1115. $("div#move-window ul").children().remove()
  1116. $("div#move-window ul").append(categoryLis);
  1117. moveIdeaOnClick();
  1118. }
  1119. // Hide "Tag selected term" link in the origin category if there are no ideas left
  1120. if($("ul#field_0" + (categoryOrigin + 1)).children().length === 0) {
  1121. // If the number of the category is between 10-99
  1122. if((categoryOrigin + 1) > 9) {
  1123. $("ul#field_" + (categoryOrigin + 1)).parent().find("p.tag-selected-term").css("display", "none");
  1124. }
  1125. // If the number of the category is between 0-9
  1126. else {
  1127. $("ul#field_0" + (categoryOrigin + 1)).parent().find("p.tag-selected-term").css("display", "none");
  1128. }
  1129. }
  1130. // Show "Tag selected term" link in the destination category
  1131. // If the number of the category is between 10-99
  1132. if((categoryOrigin + 1) > 9) {
  1133. $("ul#field_" + categoryDestination).parent().find("p.tag-selected-term").css("display", "block");
  1134. }
  1135. // If the number of the category is between 0-9
  1136. else {
  1137. $("ul#field_0" + categoryDestination).parent().find("p.tag-selected-term").css("display", "block");
  1138. }
  1139. });
  1140. }
  1141. moveIdeaOnClick();
  1142. /* ================================================
  1143. Moving ideas up
  1144. ================================================= */
  1145. // When the user clicks on the "Up" button
  1146. $('.card').on('click', 'span.move-up', function() {
  1147. // Declarations
  1148. var ideaLiCurrent = $(this).parent();
  1149. var ideaLiPrevious = $(this).parent().prev();
  1150. // Move the idea
  1151. if(ideaLiPrevious.is("li")) {
  1152. ideaLiCurrent.detach();
  1153. ideaLiPrevious.before(ideaLiCurrent);
  1154. }
  1155. });
  1156. /* ================================================
  1157. Moving ideas down
  1158. ================================================= */
  1159. // When the user clicks on the "Down" button
  1160. $('.card').on('click', 'span.move-down', function() {
  1161. // Declarations
  1162. var ideaLiCurrent = $(this).parent();
  1163. var ideaLiNext = $(this).parent().next();
  1164. // Move the idea
  1165. if(ideaLiNext.is("li")) {
  1166. ideaLiCurrent.detach();
  1167. ideaLiNext.after(ideaLiCurrent);
  1168. }
  1169. });
  1170. /* ================================================
  1171. Deleting ideas
  1172. ================================================= */
  1173. // when the cross beside the textarea is clicked (span.remove)
  1174. // remove that list item
  1175. $('.card').on('click', 'span.remove', function() {
  1176. // If there are no ideas left, hide "Tag selected term" link
  1177. if($(this).prev().parent().parent().children().length === 1) {
  1178. $(this).prev().parent().parent().next().css("display", "none");
  1179. }
  1180. // Remove the list item
  1181. $(this).closest('li').remove();
  1182. });
  1183. /* ================================================
  1184. Sortable field ideas
  1185. ================================================= */
  1186. // make items sortable in their fields and between fields
  1187. /*
  1188. $('.sortable').sortable({
  1189. connectWith: '.connectedList',
  1190. placeholder: "sort-placeholder",
  1191. // revert: true
  1192. zIndex: 300 // Or greater than any other relative/absolute/fixed elements and droppables
  1193. });
  1194. */
  1195. /* ================================================
  1196. Sorting and Dragging events
  1197. ================================================= */
  1198. /* sortstart
  1199. sortover
  1200. sortstop */
  1201. // Every textarea in a item needs to get the right name attribute once they have been dropped in another field (so it ends up in the right place in the json file)
  1202. /*
  1203. // Dragging starts
  1204. $(".sortable").on("sortstart", function(event, ui) {
  1205. // WHEN WE SORT CARDS, $(this) ---> the "begining" ul with the class of .sortable
  1206. });
  1207. // Dragging ends: item dropped
  1208. $(".sortable").on("sortstop", function(event, ui) {
  1209. // get the id of the field ul (to set the name attribute of textareas)
  1210. // # mouseleave is the right event for when we release and leave a card mouseup doesn't work properly in this case
  1211. $('.card').on('mouseleave', 'li', function() {
  1212. //$(selector).attr(attribute,value)
  1213. var fieldAttr = $(this).closest('ul.item_list').attr('id');
  1214. // $(this).find('textarea').attr('name', fieldAttr + '[]');
  1215. $(this).find('li.added_item div').attr('name', fieldAttr + '[]');
  1216. });
  1217. });
  1218. */
  1219. /* ================================================
  1220. SAVING THE CANVAS:
  1221. CLICK ON #EXPORT JSON# form button
  1222. ================================================= */
  1223. /* ----------------------------------------------
  1224. When the user clicks on the SAVE CANVAS button
  1225. ----------------------------------------------- */
  1226. $('.canvas-form').on('click', '.json_exp', function() {
  1227. /* ----------------------------------------------
  1228. A: saving the canvas
  1229. as a registered user
  1230. ----------------------------------------------- */
  1231. // php variables are retieved in the header of the canvas index.php as js variables -->
  1232. var name_save_canvas = $('.form-header').find('.proj_title').val();
  1233. var date_save_canvas = $('.form-header').find('.proj_date').val();
  1234. var save_canvas_obj = {
  1235. 'email_save_canvas': email_save_canvas,
  1236. 'name_save_canvas': name_save_canvas,
  1237. 'date_save_canvas': date_save_canvas
  1238. };
  1239. var save_canvas = $.param(save_canvas_obj);
  1240. /* Post the JSON stringified object to the php file
  1241. (the php script will save it in a .json file )*/
  1242. var save_reg_url = "php/save-canvas.php";
  1243. $.post(save_reg_url, { save_canvas: save_canvas }, function(data, status) {
  1244. //the returned data is successful, is the $canvas_id
  1245. var canvas_id = data;
  1246. // send this canvas_id with the next ajax requestedto the php/canvas.php file and use it as the name of the json file to be saved
  1247. // Give the user feedback that the canvas is saved
  1248. if (data !== 400 || data !== 401) {
  1249. if ($('.imp-exp-btn ').find(".save-canvas-feedback") !== null) {
  1250. $('.imp-exp-btn ').find(".save-canvas-feedback").remove();
  1251. }
  1252. $('.canvas-form').find('.imp-exp-btn ').append('<div class="save-canvas-feedback"><p><span class="glyphicon glyphicon-ok" aria-hidden="true"></span>Your canvas is saved in your dashbord</p></div>');
  1253. // remove the canvas is saves message as soon as user changes the canvas
  1254. // $('.canvas-form').on("change keyup", 'textarea', function() {
  1255. $('.canvas-form').on("change keyup", '.expandable', function() {
  1256. $('.imp-exp-btn ').find(".save-canvas-feedback").remove();
  1257. });
  1258. } else {
  1259. $('.canvas-form').find('.imp-exp-btn ').append('<div class="save-canvas-feedback-fail"><p>Oh! We could not save your canvas. Please try again or contact us at hello@ethicscanvas.org</p></div>');
  1260. }
  1261. // For the second AJAX request:
  1262. /* ----------------------------------------------
  1263. B: Exporing the form data json to a file
  1264. and save it on the server
  1265. ----------------------------------------------- */
  1266. // $('#result').text(JSON.stringify($('.canvas-form').serializeObject()));
  1267. // Make the JSON object into a JSON string
  1268. var JSONstrObj = JSON.stringify($('.canvas-form').serializeObject());
  1269. var url = "php/canvas.php";
  1270. /* Post the JSON stringified object to the php file
  1271. (the php script will save it in a .json file )*/
  1272. // also, send the canvas_id and use it for naming the file
  1273. $.post(url, {
  1274. JSONstrObj: JSONstrObj,
  1275. canvas_id: canvas_id
  1276. }, function(data, status) {
  1277. console.log(
  1278. 'Response from php when sending the form json object: \n' +
  1279. 'data:' + data + '\n status: ' + status);
  1280. }).fail(function(jqXHR) {
  1281. console.log("Error " + jqXHR.status + ' ' + jqXHR.statustext);
  1282. });
  1283. }).fail(function(jqXHR) {
  1284. console.log("Error " + jqXHR.status + ' ' + jqXHR.statustext);
  1285. });
  1286. // Prevent the card item list from reseting itself after clicking on the export button (submission). Because the type of the button is submit
  1287. return false;
  1288. });
  1289. /* ================================================
  1290. HANDLING CLICK ON : Share This Canvas BUTTON
  1291. ================================================= */
  1292. $('.canvas-form').on('click', '.share_canvas', function() {
  1293. $('.share_canvas_email').slideDown(1000, function() {
  1294. // SAVE THE PDF AS file
  1295. $.post('mpdf/canvas-pdf-save.php', function(data, status) { }); // save pdf as file
  1296. });
  1297. });
  1298. $('.canvas-form').on('click', '.share_canvas_send', function() {
  1299. var share_email = $('.share_canvas_email').find('input').serialize();
  1300. // This sends a serialized array share_email to the php file. Example: the value of this array will be: share-canvas-email=eternalflame.f%40gmail.com
  1301. $.post('php/share-canvas.php', {
  1302. share_email: share_email
  1303. }, function(data, status) {
  1304. if (data == 200) { // canvas successfully shared
  1305. $('.canvas-form').find('.imp-exp-btn ').append('<div class="save-canvas-feedback"><p><span class="glyphicon glyphicon-ok" aria-hidden="true"></span>Your canvas has been shared by email</p></div>')
  1306. }
  1307. else {
  1308. $('.canvas-form').find('.imp-exp-btn ').append('<div class="save-canvas-feedback"><p><span class="glyphicon glyphicon-ok" aria-hidden="true"></span>Your canvas could not be shared by email</p></div>')
  1309. }
  1310. });
  1311. // slide up the .share_canvas_email area
  1312. $('.share_canvas_email').slideUp();
  1313. });
  1314. /* ================================================
  1315. Controlling the height of divs dynamically
  1316. ================================================= */
  1317. // Call this function after adding a new item and importing
  1318. // $( window ).width(); ->Returns width of browser viewport
  1319. /*
  1320. function fixHeights() {
  1321. // Returns width of browser viewport
  1322. var screenSize = $(window).width();
  1323. //the longest card of the group 1 .masonry-layout7-5
  1324. var longest_1 = $('.masonry-layout7-5').height();
  1325. //the longest card of the group 2 .masonry-layout7-5
  1326. var longest_2 = $('.masonry-layout4').height();
  1327. // --- 5 COL Range ----
  1328. if (screenSize >= 1139) {
  1329. // inforcing a fixed height ".height(longest_1/2)" will create some layout issues when we try to add new items the add item area will go outside the box and the heights don't increase naturally
  1330. // card group 1:
  1331. // $('.field_05,.field_11, .field_07').css('min-height', longest_1 - longest_1 * 5 / 100);
  1332. // $('.field_06,.field_08, .field_12').css('min-height', longest_1 + longest_1 * 5 / 100);
  1333. // $('.field_01, .field_02').css('min-height', longest_1 * 2 + longest_1 * 1 / 100);
  1334. // card group 2:
  1335. // $('.field_03, .field_09, .field_10, .field_04').css('min-height', longest_2 * 2 - longest_2 * 20 / 100);
  1336. $('.field_05,.field_11, .field_07').css('min-height', longest_1 - longest_1 * 20 / 100);
  1337. $('.field_06,.field_08, .field_12').css('min-height', longest_1 - longest_1 * 20 / 100);
  1338. $('.field_01, .field_02').css('min-height', longest_1 + longest_1 * 40 / 100);
  1339. // card group 2:
  1340. $('.field_03, .field_09, .field_10, .field_04').css('min-height', longest_2 - longest_2 * 10 / 100);
  1341. }
  1342. // 4 COL Range //
  1343. else if (screenSize >= 977 && screenSize <= 1138) {
  1344. // card group 1:
  1345. // row 1
  1346. $('.field_01,.field_06, .field_12,.field_08 ').css('min-height', longest_1 + longest_2 * 20 / 100);
  1347. // row 2
  1348. $('.field_05,.field_11, .field_07,.field_02 ').css('min-height', longest_1 + longest_2 * 20 / 100);
  1349. // card group 2:
  1350. // row 3
  1351. $('.field_03, .field_09, .field_10, .field_04').css('min-height', longest_2 * 2 - longest_2 * 20 / 100);
  1352. } else if (screenSize >= 920 && screenSize <= 976) {
  1353. // card group 1:
  1354. // row 1
  1355. $('.field_01,.field_06, .field_12,.field_08 ').css('min-height', longest_1 + longest_2 * 20 / 100);
  1356. // row 2
  1357. $('.field_05,.field_11, .field_07,.field_02 ').css('min-height', longest_1 + longest_2 * 20 / 100);
  1358. // card group 2:
  1359. // row 3
  1360. $('.field_03, .field_09, .field_10, .field_04').css('min-height', longest_2 * 2 - longest_2 * 20 / 100);
  1361. } else if (screenSize >= 485 && screenSize <= 919) {
  1362. // else if (500 <= screenSize < 920) {
  1363. // card group 1:
  1364. $('.field_01,.field_06, .field_12,.field_08 ').css('min-height', longest_1 * 80 / 100);
  1365. $('.field_05,.field_11, .field_07,.field_02 ').css('min-height', longest_1 * 80 / 100);
  1366. // card group 2:
  1367. $('.field_03, .field_09, .field_10, .field_04').css('min-height', longest_2 * 80 / 100);
  1368. // --- 1 COL Range ----
  1369. } else {
  1370. // card group 1:
  1371. $('.field_01,.field_06, .field_12,.field_08 ').css('min-height', longest_1 * 20 / 100);
  1372. $('.field_05,.field_11, .field_07,.field_02 ').css('min-height', longest_1 * 20 / 100);
  1373. // card group 2:
  1374. $('.field_03, .field_09, .field_10, .field_04').css('min-height', longest_2 * 20 / 100);
  1375. }
  1376. }
  1377. function fixHeights() {
  1378. // Returns width of browser viewport
  1379. var screenSize = $(window).width();
  1380. var field01 = $("div.field_01");
  1381. var field02 = $("div.field_02");
  1382. var field03 = $("div.field_03");
  1383. var field04 = $("div.field_04");
  1384. var field05 = $("div.field_05");
  1385. var field06 = $("div.field_06");
  1386. var field07 = $("div.field_07");
  1387. var field08 = $("div.field_08");
  1388. var field09 = $("div.field_09");
  1389. // Set the height of every field
  1390. var heightOfField01 = field01.height();
  1391. var heightOfField03 = field03.height();
  1392. var heightOfField04 = field04.height();
  1393. var heightOfField03And04 = field03.height() + field04.height();
  1394. var heightOfField09 = field09.height();
  1395. var heightOfField05 = field05.height();
  1396. var heightOfField06 = field06.height();
  1397. var heightOfField05And06 = field05.height() + field06.height();
  1398. var heightOfField02 = field02.height();
  1399. // --- 5 COL Range ---
  1400. if (screenSize >= 935) {
  1401. var longestInGroup1 = Math.max(heightOfField01, heightOfField03, heightOfField04, heightOfField03And04, heightOfField09, heightOfField05, heightOfField06, heightOfField05And06, heightOfField02);
  1402. console.log(longestInGroup1);
  1403. // Field group 1
  1404. switch(longestInGroup1) {
  1405. case heightOfField01:
  1406. $(".field_04").css("min-height", longestInGroup1 + 10);
  1407. $(".field_09").css("min-height", longestInGroup1 + 448);
  1408. $(".field_06").css("min-height", longestInGroup1 + 10);
  1409. $(".field_02").css("min-height", longestInGroup1 + 448);
  1410. break;
  1411. case heightOfField03:
  1412. // Code goes here
  1413. break;
  1414. case heightOfField04:
  1415. // Code goes here
  1416. break;
  1417. case heightOfField03And04:
  1418. // Code goes here
  1419. break;
  1420. case heightOfField09:
  1421. // Code goes here
  1422. break;
  1423. case heightOfField05:
  1424. // Code goes here
  1425. break;
  1426. case heightOfField06:
  1427. // Code goes here
  1428. break;
  1429. case heightOfField05And06:
  1430. // Code goes here
  1431. break;
  1432. case heightOfField02:
  1433. // Code goes here
  1434. break;
  1435. default:
  1436. break;
  1437. }
  1438. }
  1439. // --- 4 COL Range ---
  1440. else if (screenSize >= 935 && screenSize <= 991) {
  1441. // Field group 1
  1442. // Code goes here
  1443. // Field group 2
  1444. // Code goes here
  1445. }
  1446. else if (screenSize >= 992 && screenSize <= 1153) {
  1447. // Field group 1
  1448. // Code goes here
  1449. // Field group 2
  1450. // Code goes here
  1451. }
  1452. // --- 2 COL Range ---
  1453. else if (screenSize >= 500 && screenSize <= 934) {
  1454. // Field group 1
  1455. // Code goes here
  1456. // Field group 2
  1457. // Code goes here
  1458. }
  1459. // --- 2-5 COL Range ---
  1460. if (screenSize >= 500) {
  1461. var longestInGroup2;
  1462. // Field group 2
  1463. // Determine the longest Field in group 2
  1464. if(field07.height() < field08.height()) {
  1465. longestInGroup2 = field08;
  1466. }
  1467. else {
  1468. longestInGroup2 = field07;
  1469. }
  1470. if(longestInGroup2 === field07) {
  1471. $(".field_08").css("min-height", longestInGroup2.height() + 10);
  1472. }
  1473. else {
  1474. $(".field_07").css("min-height", longestInGroup2.height() + 10);
  1475. }
  1476. }
  1477. // --- 1 COL Range ---
  1478. // Field group 1
  1479. // Code goes here
  1480. // Field group 2
  1481. // Code goes here
  1482. }
  1483. */
  1484. /*
  1485. new ResizeSensor($(".field_01, .field_02, .field_03, .field_04, .field_05, .field_06, .field_07, .field_08, .field_09"), function() {
  1486. // fixHeights();
  1487. });
  1488. */
  1489. });