canvas.js 97 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398
  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. // Declare canvas id
  9. var canvasId = $("input[name='canvas_id']").val();
  10. // Declare current user
  11. var username = $("input[name='username']").val();
  12. // Total number of collaborators
  13. var numberOfCollaborators = 0;
  14. // Fixes bug when added item field zooms on tag click
  15. var tagWindowIsOpen = false;
  16. // This piece of code is for making the column-count and column-gap CSS to work in Firefox
  17. /*
  18. document.getElementById("7-5-col-layout").style.MozColumnCount = "7";
  19. document.getElementById("2-col-layout").style.MozColumnCount = "2";
  20. */
  21. // Prevent pressing ENTER on Project Title from submitting the form
  22. $('.proj_title').keydown(function(event){
  23. if(event.keyCode == 13) {
  24. event.preventDefault();
  25. return false;
  26. }
  27. });
  28. /* ================================================
  29. Generate canvas id
  30. ================================================= */
  31. // Generate a random string of a specific length to be used as canvas_id
  32. if(canvasId === "") {
  33. var i = 0;
  34. var length = 10;
  35. var characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  36. var charactersLength = characters.length;
  37. var randomString = "";
  38. var minimum = 0;
  39. var maximum = charactersLength - 1;
  40. for (i = 0; i < length; i++) {
  41. randomString += characters[Math.floor(Math.random() * (maximum - minimum + 1)) + minimum];
  42. }
  43. // Save canvas ID
  44. canvasId = randomString;
  45. $("input[name='canvas_id']").val(randomString);
  46. }
  47. /* ================================================
  48. Rearrange fields numerically if 1 column is displayed
  49. ================================================= */
  50. // Declarations
  51. var groupOneLayout = $("#7-5-col-layout");
  52. var groupTwoLayout = $("#4-col-layout");
  53. var field01 = $("#panel_01");
  54. var field03 = $("#panel_03");
  55. var field04 = $("#panel_04");
  56. var field09 = $("#panel_09");
  57. var field05 = $("#panel_05");
  58. var field06 = $("#panel_06");
  59. var field02 = $("#panel_02");
  60. var field07 = $("#panel_07");
  61. var field08 = $("#panel_08");
  62. // var field10 = $("#panel_10");
  63. var isRearranged = false;
  64. // Rearrange the fields to suit mobile
  65. function rearrangeFields() {
  66. field01.detach();
  67. field03.detach();
  68. field04.detach();
  69. field09.detach();
  70. field05.detach();
  71. field06.detach();
  72. field02.detach();
  73. field07.detach();
  74. field08.detach();
  75. // field10.detach();
  76. groupOneLayout.append(field01);
  77. groupOneLayout.append(field02);
  78. groupOneLayout.append(field03);
  79. groupOneLayout.append(field04);
  80. groupOneLayout.append(field05);
  81. groupOneLayout.append(field06);
  82. groupOneLayout.append(field07);
  83. groupOneLayout.append(field08);
  84. groupOneLayout.append(field09);
  85. // groupOneLayout.append(field10);
  86. }
  87. // Rearrange the fields according to their original order
  88. function rearrangeFieldsOriginal() {
  89. field01.detach();
  90. field02.detach();
  91. field03.detach();
  92. field04.detach();
  93. field05.detach();
  94. field06.detach();
  95. field07.detach();
  96. field08.detach();
  97. field09.detach();
  98. // field10.detach();
  99. groupOneLayout.append(field01);
  100. groupOneLayout.append(field03);
  101. groupOneLayout.append(field04);
  102. groupOneLayout.append(field09);
  103. groupOneLayout.append(field05);
  104. groupOneLayout.append(field06);
  105. groupOneLayout.append(field02);
  106. groupTwoLayout.append(field07);
  107. groupTwoLayout.append(field08);
  108. // groupTwoLayout.append(field10);
  109. }
  110. // If the web page is opened on a mobile
  111. if ($(window).width() <= 499) {
  112. rearrangeFields();
  113. }
  114. // When resizing the window
  115. $(window).on("resize", function() {
  116. if (isRearranged === false && $(window).width() <= 499) {
  117. rearrangeFields();
  118. isRearranged = true;
  119. }
  120. else if(isRearranged === true && $(window).width() >= 500) {
  121. rearrangeFieldsOriginal();
  122. isRearranged = false;
  123. }
  124. });
  125. /* ================================================
  126. Collaborators window
  127. ================================================= */
  128. // If the user clicks on the "Collaborators" button, show the collaborators window
  129. $("div#collaborators button").on("click", function() {
  130. // Show the collaborators window
  131. $("div#shadow").css("display", "block");
  132. $("div#collaborators-window").css("display", "block");
  133. });
  134. // Close the collaborators window
  135. function closeCollaboratorsWindow() {
  136. // Close the collaborators window
  137. $("div#shadow").css("display", "none");
  138. $("div#collaborators-window").css("display", "none");
  139. }
  140. // If the user clicks on the "Close" button
  141. $("div#collaborators-window button.close").on("click", function() {
  142. // Close the collaborators window
  143. closeCollaboratorsWindow();
  144. $("div#collaborators-window input[type='email']").val("Please enter an email address...");
  145. $("div#username-already-exists").hide();
  146. $("div#enter-valid-email").hide();
  147. });
  148. // If the user clicks on the "Remove" button
  149. function removeCollaboratorOnClick() {
  150. // If the user clicks on the "Remove" button
  151. $("div#collaborators-window td:nth-child(4) span").on("click", function() {
  152. // Remove the collaborator
  153. var collaborator = $(this).parent().prev().text();
  154. var currentRow = $(this).parent().parent();
  155. // AJAX
  156. $.ajax({
  157. timeout: 5000,
  158. dataType: "text",
  159. type: "post",
  160. data: {
  161. "canvas_id": canvasId,
  162. "username": username,
  163. "collaborator": collaborator
  164. },
  165. url: "php/remove-collaborator.php",
  166. success: function() {
  167. currentRow.remove();
  168. numberOfCollaborators--;
  169. },
  170. error: function(xhr) {
  171. console.log(xhr.statusText);
  172. }
  173. });
  174. });
  175. }
  176. // Show only active collaborators or show all
  177. function updateCollaboratorsView() {
  178. // If the user only wants to see active collaborators
  179. if($("input[name='show-only-active']").is(":checked")) {
  180. // For every collaborator
  181. $("div#collaborators-window tr").each(function() {
  182. // If this collaborator is offline
  183. if($(this).find("td:nth-child(1)").html() === "") {
  184. // Hide this collaborator
  185. $(this).css("display", "none");
  186. }
  187. });
  188. /*
  189. // Show empty row if no collaborator is active
  190. if($("div#collaborators-window tr").not(":hidden").length === 1) {
  191. $("div#collaborators-window table").append("<tr id='empty-row'><td class='collaborators-active'>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>");
  192. }
  193. */
  194. }
  195. // If the user wants to see all active collaborators
  196. else {
  197. // For every collaborator
  198. $("div#collaborators-window tr").each(function() {
  199. // Show this collaborator
  200. $(this).css("display", "table-row");
  201. });
  202. }
  203. }
  204. // If the user checks the "Show only active collaborators" checkbox
  205. $("input[name='show-only-active']").on("change", function() {
  206. updateCollaboratorsView();
  207. });
  208. // If the user enters the text field
  209. $("div#collaborators-window input[type='email']").on("focusin", function() {
  210. if($(this).val() === "Please enter an email address...") {
  211. $(this).val("");
  212. $(this).css("color", "rgb(51, 51, 51)");
  213. }
  214. });
  215. // If the user leaves the text field
  216. $("div#collaborators-window input[type='email']").on("focusout", function() {
  217. if($(this).val() === "") {
  218. $(this).val("Please enter an email address...");
  219. $(this).css("color", "rgb(117, 117, 117)");
  220. }
  221. });
  222. // If the user clicks on "Add collaborator"
  223. $("div#collaborators-window button#add-collaborator").on("click", function() {
  224. // Declarations
  225. var collaborator = $("div#collaborators-window input[type='email']").val();
  226. // AJAX
  227. $.ajax({
  228. timeout: 5000,
  229. dataType: "text",
  230. type: "post",
  231. data: {
  232. "canvas_id": canvasId,
  233. "username": username,
  234. "collaborator": collaborator
  235. },
  236. url: "php/add-collaborator.php",
  237. success: function(returnData) {
  238. $("div#username-already-exists").hide();
  239. $("div#enter-valid-email").hide();
  240. if(returnData == 1) {
  241. $("div#collaborators-window input[type='email']").val("Please enter an email address...");
  242. $("div#collaborators-window input[type='email']").css("color", "rgb(117, 117, 117)");
  243. updateActiveCollaborators();
  244. }
  245. else if(returnData == 2) {
  246. $("div#username-already-exists").show();
  247. }
  248. else {
  249. $("div#enter-valid-email").show();
  250. }
  251. numberOfCollaborators++;
  252. },
  253. error: function(xhr) {
  254. console.log(xhr.statusText);
  255. }
  256. });
  257. });
  258. /* ================================================
  259. Collaborative features
  260. ================================================= */
  261. // Update active collaborators
  262. function updateActiveCollaborators() {
  263. // AJAX
  264. $.ajax({
  265. type: "POST",
  266. url: "php/update-active-collaborators.php",
  267. dataType: "JSON",
  268. data: {
  269. "canvas_id": canvasId,
  270. "username": username
  271. },
  272. timeout: 5000,
  273. success: function(returnData) {
  274. // Declarations
  275. var htmlToAppend = "<tr><th>Active</th><th>Name</th><th>Username</th><th>Remove</th></tr>";
  276. numberOfCollaborators = returnData.length;
  277. // If the total number of invited collaborators is greater than 0
  278. if(returnData.length > 0) {
  279. // Declarations
  280. var index = 0;
  281. // While there still are collaborators to append
  282. while(index < returnData.length) {
  283. htmlToAppend += "<tr><td class='collaborators-active'>";
  284. if(returnData[index]["active"] === 1) {
  285. htmlToAppend += "<span class='glyphicon glyphicon-ok-sign'></span>";
  286. }
  287. htmlToAppend += "</td><td>" + returnData[index]["name"] + "</td><td>" + returnData[index]["collaborator"] + "</td><td><span class='glyphicon glyphicon-remove-sign'></span></td></tr>";
  288. index++;
  289. }
  290. // console.log(returnData);
  291. // Append tags
  292. $("div#collaborators-window table").html(htmlToAppend);
  293. // Update the button to open the collaborators window
  294. $("div#collaborators button span").text("Collaborators (" + $("td.collaborators-active span").length + " active)");
  295. // Toggle the text explaining that the canvas is saved automatically
  296. $("p#save-canvas").hide();
  297. $("p#saved-automatically").show();
  298. // If the user clicks on the "Remove" button
  299. removeCollaboratorOnClick();
  300. // Show only active collaborators or show all
  301. updateCollaboratorsView();
  302. }
  303. else {
  304. // Toggle the text explaining that the canvas is saved automatically
  305. $("p#save-canvas").show();
  306. $("p#saved-automatically").hide();
  307. }
  308. },
  309. error: function(xhr) {
  310. console.log(xhr.statusText);
  311. }
  312. });
  313. }
  314. updateActiveCollaborators();
  315. window.setInterval(function() {
  316. updateActiveCollaborators();
  317. }, 7000);
  318. /* ================================================
  319. "Jump to" functions
  320. ================================================= */
  321. var hasScrolledDown = false;
  322. function showFixedJumpedTo() {
  323. // Add classes
  324. $("div.jump-to-click-area").addClass("jump-to-click-area-toggle");
  325. $("div.jump-to").addClass("jump-to-toggle");
  326. $("div.jump-to-list").addClass("jump-to-list-toggle");
  327. $("img.jump-to-img").addClass("jump-to-img-toggle");
  328. // If the user clicks on a link and scrolls up the page, hide list
  329. $("div.jump-to-list").hide();
  330. }
  331. function showInitialJumpedTo() {
  332. // Toggle classes
  333. $("div.jump-to-click-area").removeClass("jump-to-click-area-toggle");
  334. $("div.jump-to").removeClass("jump-to-toggle");
  335. $("div.jump-to-list").removeClass("jump-to-list-toggle");
  336. $("img.jump-to-img").removeClass("jump-to-img-toggle");
  337. // If the user clicks on a link and scrolls up the page, toggle list
  338. $("div.jump-to-list").show();
  339. hasScrolledDown = false;
  340. }
  341. // If the user scrolls down, change "position" to "fixed"
  342. $(window).scroll(function() {
  343. // If the web page is opened on a mobile
  344. if($(window).width() <= 499) {
  345. // Declarations
  346. var scrollPosition = $(window).scrollTop();
  347. var jumpToPosition = $("div.jump-to").offset().top;
  348. // If the user has scrolled down to "Jump To..."
  349. if(hasScrolledDown === false && scrollPosition >= jumpToPosition) {
  350. showFixedJumpedTo();
  351. // Update scroll position
  352. $(window).scrollTop($("div.saved-tags").offset().top - 300);
  353. hasScrolledDown = true;
  354. }
  355. // If the user has scrolled up to the top
  356. else if(hasScrolledDown === true && scrollPosition === 0) {
  357. showInitialJumpedTo();
  358. }
  359. }
  360. // If the web page is not open on a mobile
  361. else {
  362. showInitialJumpedTo();
  363. }
  364. });
  365. // If the user clicks on "Jump to", show menu
  366. $("div.jump-to-click-area").on("click", function() {
  367. // Toggle the menu
  368. $("div.jump-to div div").slideToggle(300);
  369. // Rotate arrow
  370. // $("div.jump-to span.jump-to-arrow").toggleClass("rotate-arrow-180");
  371. // $("div.jump-to span.jump-to-arrow").toggleClass("rotate-arrow-0");
  372. $("img.jump-to-img").toggleClass("jump-to-arrow-90");
  373. $("img.jump-to-img").toggleClass("jump-to-arrow-0");
  374. return false;
  375. });
  376. // If the user clicks on a menu item
  377. $("div.jump-to ul a").on("click", function() {
  378. // Declarations
  379. var chosenLiIndex = $(this).parent().index();
  380. var chosenFieldPosition;
  381. var scrollPositionNew;
  382. // Detect the scroll position of the chosen field
  383. // If the user has chosen the list item 0
  384. if(chosenLiIndex === 0) {
  385. chosenFieldPosition = $("div.saved-tags").offset().top;
  386. }
  387. // If the user has chosen the list item 1-9
  388. else if(chosenLiIndex >= 1 && chosenLiIndex <= 9) {
  389. chosenFieldPosition = $("div.field_0" + chosenLiIndex).offset().top;
  390. }
  391. // If the user has chosen the list item 10 or higher
  392. else {
  393. chosenFieldPosition = $("div.field_" + chosenLiIndex).offset().top;
  394. }
  395. // If the user hasn't scrolled down
  396. if(hasScrolledDown === false) {
  397. console.log(chosenLiIndex);
  398. // Set the new scroll position
  399. scrollPositionNew = chosenFieldPosition - $("div.jump-to").height() - 89;
  400. // Add classes
  401. showFixedJumpedTo();
  402. // Update scroll position
  403. hasScrolledDown = true;
  404. }
  405. // If the user has scrolled down to "Jump To..."
  406. else {
  407. // Set the new scroll position
  408. scrollPositionNew = chosenFieldPosition - 58;
  409. // Toggle the menu
  410. $("div.jump-to-list").slideToggle(300);
  411. // Rotate arrow
  412. // $("div.jump-to span.jump-to-arrow").toggleClass("rotate-arrow-90");
  413. // $("div.jump-to span.jump-to-arrow").toggleClass("rotate-arrow-0");
  414. $("img.jump-to-img").toggleClass("jump-to-arrow-90");
  415. $("img.jump-to-img").toggleClass("jump-to-arrow-0");
  416. }
  417. // Apply the new scroll position
  418. $(window).scrollTop(scrollPositionNew);
  419. return false;
  420. });
  421. /* ================================================
  422. Show tooltip for every category
  423. ================================================= */
  424. $("a[data-toggle='tooltip']").tooltip({container: "body"});
  425. $("a[data-toggle='tooltip']").on("click", function() {
  426. return false;
  427. });
  428. /* ================================================
  429. Remove all tags from all fields
  430. ================================================= */
  431. // Remove all tags from all fields
  432. function removeTags() {
  433. // AJAX
  434. $.ajax({
  435. type: "POST",
  436. url: "php/get-tags.php",
  437. dataType: "JSON",
  438. data: {
  439. "canvas_id": canvasId
  440. },
  441. timeout: 5000,
  442. success: function(returnData) {
  443. // Declarations
  444. var loopCounter = 0;
  445. tags = returnData;
  446. // For every added item
  447. $("li.added_item .expandable").each(function() {
  448. $(this).html($(this).text());
  449. /*
  450. var thisDiv = $(this); // Delete the declaration (because it's ugly!)
  451. // For every tag in the database that belongs to the active user
  452. for(t in tags) {
  453. // If the current tag exists in the textarea
  454. if(thisDiv.html().indexOf("</a>") != -1) { // Why not a while loop?
  455. // Delete the tag
  456. var text = thisDiv.html();
  457. text = thisDiv.text().replace("<a class='tag'>" + tags[loopCounter] + "</a>", tags[loopCounter]);
  458. thisDiv.html(text);
  459. }
  460. loopCounter++;
  461. }
  462. */
  463. });
  464. // If no tags have been added, reset text explaining so
  465. if(tags.length === 0) {
  466. $("div.saved-tags p").html("You haven't added any tags yet.");
  467. }
  468. },
  469. error: function(xhr) {
  470. console.log(xhr.statusText);
  471. }
  472. });
  473. /*
  474. // 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
  475. // Declarations
  476. var loopCounter = 0;
  477. // For every added item
  478. $("li.added_item .expandable").each(function() {
  479. var thisDiv = $(this); // Delete the declaration (because it's ugly)
  480. // For every tag that belongs to the active user
  481. for(t in tags) {
  482. // If the current tag exists in the textarea
  483. if(thisDiv.html().indexOf("</a>") != -1) {
  484. // Delete the tag
  485. var text = thisDiv.html();
  486. text = thisDiv.text().replace("<a class='tag'>" + tags[loopCounter] + "</a>", tags[loopCounter]);
  487. thisDiv.html(text);
  488. }
  489. loopCounter++;
  490. }
  491. });
  492. console.log(tags);
  493. console.log(tags.length);
  494. // If no tags have been added, reset text explaining so
  495. if(tags.length === 0) {
  496. $("div.saved-tags p").html("You haven't added any tags yet.");
  497. }
  498. */
  499. }
  500. /* ================================================
  501. Get the user's tags from the database and apply them on the canvas
  502. ================================================= */
  503. // Apply tags (Incoming parameter is an array with every tag from the database belonging to the active user)
  504. function updateTags() {
  505. // Apply tags on the canvas
  506. /*
  507. IMPORTANT! A timer was needed in order to solve several bugs related to tags not being applied on the canvas.
  508. Should this still become an issue later on, try increasing the amount of milliseconds.
  509. */
  510. window.setTimeout(function() {
  511. // For every added item
  512. $("li.added_item .expandable").each(function() {
  513. // Declarations
  514. // var instanceCounter;
  515. var loopCounter = 0;
  516. var text = $(this).text();
  517. // instanceCounter = $(text + ":contains('test')").length;
  518. // $('#parentDiv').find(":contains('No Records Found')").length
  519. // console.log(instanceCounter);
  520. // For every tag in the database that belongs to the active user
  521. for(t in tags) {
  522. // instanceCounter = ($(this).text().match(/aaa/g) || []).length;
  523. // Apply the tag for every instance of the current term
  524. // instanceCounter = text.indexOf(tags[loopCounter]);
  525. // while(instanceCounter > -1) {
  526. // text = text.replace(tags[loopCounter], "<a class='tag' contenteditable='false'>" + tags[loopCounter] + "</a>");
  527. text = text.replace(tags[loopCounter], "<a class='tag'>" + tags[loopCounter] + "</a>");
  528. // instanceCounter = text.indexOf(tags[loopCounter], instanceCounter + 1);
  529. // }
  530. loopCounter++;
  531. }
  532. $(this).html(text);
  533. });
  534. // Show the tag window on tag click
  535. showTagWindowOnTagClick();
  536. }, 100);
  537. // Populate "Saved Tags"
  538. var loopCounter = 0;
  539. var savedTags = $("div.saved-tags p");
  540. savedTags.html("");
  541. for(t in tags) {
  542. if(savedTags.html() === "You haven't added any tags yet.") {
  543. savedTags.html("");
  544. }
  545. savedTags.append("<a href='#' class='tag'>" + tags[loopCounter] + "</a>").append("&nbsp;&nbsp; ");
  546. loopCounter++;
  547. }
  548. }
  549. // Get the tags from the database
  550. function getTags() {
  551. // AJAX
  552. $.ajax({
  553. type: "POST",
  554. url: "php/get-tags.php",
  555. dataType: "JSON",
  556. data: {
  557. "canvas_id": canvasId
  558. },
  559. timeout: 5000,
  560. success: function(returnData) {
  561. if(returnData.length > 0) {
  562. // Assign returnData to the tags variable
  563. tags = returnData;
  564. // Update tags on the canvas
  565. updateTags();
  566. }
  567. },
  568. error: function(xhr) {
  569. console.log(xhr.statusText);
  570. }
  571. });
  572. }
  573. /* ================================================
  574. Load tags if the user is logged in
  575. ================================================= */
  576. if($("input[name='name']").val() != "") {
  577. getTags();
  578. }
  579. /* ================================================
  580. Tag window functions
  581. ================================================= */
  582. // Declarations
  583. // var textarea = $("div#tag-window textarea#tag-description");
  584. var textareaHasBeenChanged = false;
  585. var tag;
  586. // var tagIsNew = false;
  587. var username = $("input[name='username']").val();
  588. // Check if the tag is new
  589. function hideDeleteTagIfTagIsNew() {
  590. // Declarations
  591. var tagToAJAX = tag;
  592. // AJAX
  593. $.ajax({
  594. type: "POST",
  595. url: "php/check-if-tag-exists.php",
  596. dataType: "text",
  597. data: {
  598. "tag": tagToAJAX,
  599. "canvas_id": canvasId
  600. },
  601. timeout: 5000,
  602. success: function(returnData) {
  603. // If the current tag does not exist in the database
  604. if(returnData === "") {
  605. // Hide "Delete tag" button
  606. $("div#tag-window button#delete-tag").css("display", "none");
  607. // Hide "Similar tags"
  608. // $("div#tag-window h2.similar-tags").css("display", "none");
  609. // The tag is new
  610. // tagIsNew = true;
  611. }
  612. // If the current tag exists in the database
  613. else {
  614. // Show "Delete tag" button
  615. $("div#tag-window button#delete-tag").css("display", "inline");
  616. // Show "Similar tags"
  617. // $("div#tag-window h2.similar-tags").css("display", "block");
  618. }
  619. },
  620. error: function(xhr) {
  621. console.log(xhr.statusText);
  622. }
  623. });
  624. }
  625. // Updating the remaining characters information
  626. function updateRemainingCharacters() {
  627. // Declarations
  628. var length = $("div#tag-window textarea#tag-description").val().length; // Retrieving from "Please enter a description..."
  629. var maxLength = 200;
  630. /*
  631. var length;
  632. if(description != "") {
  633. length = description;
  634. }
  635. else {
  636. length = $("div#tag-window textarea#tag-description").val().length;
  637. }
  638. */
  639. // Update length
  640. length = maxLength - length;
  641. // Show the remaining characters
  642. $("div#tag-window span.chars").text(length);
  643. }
  644. // Get the description for the selected tag
  645. function getDescriptionForSelectedTag() {
  646. // Declarations
  647. var tagToAJAX = tag;
  648. // AJAX
  649. $.ajax({
  650. type: "POST",
  651. url: "php/get-description-for-selected-tag.php",
  652. dataType: "text",
  653. data: {
  654. "tag": tagToAJAX,
  655. "canvas_id": canvasId
  656. },
  657. timeout: 5000,
  658. success: function(returnData) {
  659. if(returnData != "") {
  660. // Update description field with the description for the selected tag
  661. $("div#tag-window textarea#tag-description").val(returnData);
  662. // Update remaining characters
  663. updateRemainingCharacters();
  664. }
  665. textareaHasBeenChanged = true;
  666. },
  667. error: function(xhr) {
  668. console.log(xhr.statusText);
  669. }
  670. });
  671. }
  672. // Get similar tags by other users
  673. function getSimilarTags() {
  674. // Declarations
  675. var tagToAJAX = tag;
  676. // AJAX
  677. $.ajax({
  678. type: "POST",
  679. url: "php/get-similar-tags.php",
  680. dataType: "JSON",
  681. data: {
  682. "tag": tagToAJAX,
  683. "canvas_id": canvasId
  684. },
  685. timeout: 5000,
  686. success: function(returnData) {
  687. // Reset similar tags if similar tags are to be showed again
  688. $("p.similar-tags-tag").remove();
  689. $("p.similar-tags-description").remove();
  690. $("p.similar-tags-canvas-name").remove();
  691. // Declarations
  692. var htmlToAppend = "";
  693. // If similar tags exist
  694. if(returnData.length > 0) {
  695. // Declarations
  696. var index = 0;
  697. // While there still are tags to append
  698. while(index < returnData.length) {
  699. htmlToAppend += "<p class='similar-tags-tag'><a class='tag'>" + returnData[index]["tag"] + "</a></p>"
  700. + "<p class='similar-tags-description'>" + returnData[index]["description"] + "</p>"
  701. + "<p class='similar-tags-canvas-name'>from <span class='canvas-name'>" + returnData[index]["canvas_name"] + "</span></p>";
  702. // "<p class='similar-tags-canvas-name'>from <a href='#'>" + returnData[index]["canvas_name"] + "</a></p>";
  703. index++;
  704. }
  705. // Append tags
  706. $("div#tag-window h2.similar-tags").after(htmlToAppend);
  707. $("p.similar-tags-description-none").css("display", "none");
  708. // Update tags on the canvas
  709. // updateTags();
  710. }
  711. else {
  712. // Show the message saying that there are no similar tags to show
  713. $("p.similar-tags-description-none").css("display", "block");
  714. }
  715. },
  716. error: function(xhr) {
  717. console.log(xhr.statusText);
  718. }
  719. });
  720. }
  721. // Close the tag window
  722. function closeTagWindow() {
  723. tagWindowIsOpen = false;
  724. $("div#shadow").css("display", "none");
  725. $("div#tag-window").css("display", "none");
  726. }
  727. // Show the tag window
  728. function showTagWindow() {
  729. // Show the tag window
  730. $("div#shadow").css("display", "block");
  731. $("div#tag-window").css("display", "block");
  732. // Update the header
  733. $("div#tag-window h1").html("<span class='glyphicon glyphicon-tag'></span> " + tag);
  734. // Move the window to the centre of the screen
  735. /*
  736. The code below should be working, but the height of the second selector seems completely wrong!
  737. var middle = (document.body.clientHeight / 2) - ($("div#tag-window").height() / 2);
  738. $("div#tag-window").css("top", middle);
  739. */
  740. // Check if the tag is new
  741. hideDeleteTagIfTagIsNew();
  742. // Get the description for the selected tag
  743. getDescriptionForSelectedTag();
  744. // Get tags by other users from the database
  745. // window.setTimeout(getSimilarTags(), 100);
  746. getSimilarTags();
  747. // Update remaining characters in case description is loaded
  748. updateRemainingCharacters();
  749. // If a description hasn't been entered
  750. if($("div#tag-window textarea#tag-description") !== "Please enter a description..." && textareaHasBeenChanged !== true) {
  751. // Reset the remaining characters information
  752. $("div#tag-window span.chars").text("200");
  753. }
  754. }
  755. // If the user presses a key in the description textarea
  756. $("div#tag-window textarea#tag-description").on("keyup", function() {
  757. // Update remaining characters
  758. updateRemainingCharacters();
  759. });
  760. // If the user clicks on the "Save tag" button
  761. $("div#tag-window #save-tag").on("click", function() {
  762. // Declarations
  763. var description = $("div#tag-window textarea#tag-description").val();
  764. var tagToAJAX = tag;
  765. // If a description has been entered
  766. if(description != "" && description != "Please enter a description...") {
  767. // AJAX
  768. $.ajax({
  769. timeout: 5000,
  770. dataType: "text",
  771. type: "post",
  772. data: {
  773. "tag": tagToAJAX,
  774. "description": description,
  775. "canvas_id": canvasId
  776. },
  777. url: "php/save-tag.php",
  778. success: function() {
  779. textareaHasBeenChanged = true;
  780. // Get the user's tags from the database and apply them on the canvas
  781. getTags();
  782. },
  783. error: function(xhr) {
  784. console.log(xhr.statusText);
  785. }
  786. });
  787. // Close the tag window
  788. closeTagWindow();
  789. }
  790. // tagIsNew = false;
  791. });
  792. // If the user clicks on the "Close" button
  793. $("div#tag-window button.close").on("click", function() {
  794. // Close the tag window
  795. closeTagWindow();
  796. });
  797. // If the user clicks on the "Delete tag" button
  798. $("div#tag-window #delete-tag").on("click", function() {
  799. // Declarations
  800. var tagToAJAX = tag;
  801. // AJAX
  802. $.ajax({
  803. timeout: 5000,
  804. dataType: "text",
  805. type: "post",
  806. data: {
  807. "tag": tagToAJAX,
  808. "canvas_id": canvasId
  809. },
  810. url: "php/delete-tag.php",
  811. success: function() {
  812. // Remove all tags from all fields
  813. removeTags();
  814. // Get the user's tags from the database and apply them on the canvas
  815. getTags();
  816. },
  817. error: function(xhr) {
  818. console.log(xhr.statusText);
  819. }
  820. });
  821. // Close the tag window
  822. closeTagWindow();
  823. });
  824. // If the user focuses in the textarea
  825. $("div#tag-window textarea#tag-description").on("focusin", function() {
  826. // Declarations
  827. var description = $("div#tag-window textarea#tag-description").val();
  828. // If a description hasn't been entered
  829. // if(textareaHasBeenChanged === false) {
  830. if(description === "Please enter a description...") {
  831. // Empty the description textarea
  832. $("div#tag-window textarea#tag-description").val("");
  833. }
  834. });
  835. // If the user focuses out the textarea
  836. $("div#tag-window textarea#tag-description").on("focusout", function() {
  837. // Declarations
  838. var description = $("div#tag-window textarea#tag-description").val();
  839. // If a description hasn't been entered
  840. // if(textareaHasBeenChanged === false) {
  841. if(description === "") {
  842. // Reset the description textarea
  843. $("div#tag-window textarea#tag-description").val("Please enter a description...");
  844. }
  845. });
  846. /* ================================================
  847. If the user clicks on a tag, show the tag window
  848. ================================================= */
  849. // If the user clicks on a tag
  850. function showTagWindowOnTagClick() {
  851. $("a.tag").on("click", function() {
  852. // Declarations
  853. tag = $(this).text();
  854. // If the user is logged in
  855. if($("input[name='username']").val() != "") {
  856. tagWindowIsOpen = true;
  857. // Show the tag window
  858. showTagWindow();
  859. }
  860. else {
  861. // Show a dialog
  862. $("div#shadow").css("display", "block");
  863. $("div#dialog-log-in").css("display", "block");
  864. }
  865. });
  866. }
  867. /*
  868. // Mouse-enabled devices
  869. $("tag").mouseenter(function() {
  870. timer = setTimeout(function() {
  871. showTagWindow(); // showTagWindow needs a parameter!
  872. }, 400);
  873. }).mouseleave(function() {
  874. clearTimeout(timer);
  875. });
  876. // Touch devices
  877. try {
  878. document.createEvent("TouchEvent");
  879. $("a.tag").on("click", showTagWindow()); // showTagWindow needs a parameter!
  880. return true;
  881. }
  882. catch(e) {
  883. return false;
  884. }
  885. */
  886. /* ================================================
  887. Save added idea on Enter press
  888. ================================================= */
  889. function saveAddedIdeaOnEnterPress(li) {
  890. $("li.added_item textarea.expandable").on("keydown", function(event) {
  891. if(event.which === 13) {
  892. event.preventDefault();
  893. // Declarations
  894. var li = $(this).parent();
  895. var textElement;
  896. var textElementWidth;
  897. // Replace textarea with a div
  898. $(this).replaceWith(
  899. "<div class='expandable' name='" + $(this).attr("name") + "'>" + $(this).val() + "</div>"
  900. );
  901. // Remember the text element
  902. textElement = li.find(".expandable");
  903. // Remember the width of the text element
  904. textElementWidth = textElement.width();
  905. // Update tags on the canvas
  906. // window.setTimeout(updateTags(), 100);
  907. updateTags();
  908. // Zoom out animation
  909. if(textElementWidth >= 0 && textElementWidth <= 250) {
  910. textElement.addClass("zoom-out-regular");
  911. }
  912. else if(textElementWidth >= 251 && textElementWidth <= 500) {
  913. textElement.addClass("zoom-out-less");
  914. }
  915. else if(textElementWidth >= 501) {
  916. textElement.addClass("zoom-out-least");
  917. }
  918. textElement.css("background-color", "rgba(255, 255, 255, 0.75)");
  919. textElement.css("-ms-transform", "scale(1)");
  920. textElement.css("-webkit-transform", "scale(1)");
  921. textElement.css("transform", "scale(1)");
  922. // If no tags have been added, reset text explaining so
  923. if(tags.length === 0) {
  924. $("div.saved-tags p").html("You haven't added any tags yet.");
  925. }
  926. toggleTextElementOnFocus();
  927. }
  928. });
  929. }
  930. /* ================================================
  931. Toggle textarea.expandable/div.expandable on edit
  932. ================================================= */
  933. function toggleTextElementOnFocus() {
  934. // If the user clicks on the added ideas
  935. $("li.added_item .expandable").on("click", function() {
  936. if(tagWindowIsOpen === false) {
  937. var li = $(this).parent();
  938. var textElement;
  939. // var textElementHTML;
  940. var textElementWidth;
  941. // Replace div with a textarea
  942. $(this).replaceWith(
  943. "<textarea maxlength='100' class='expandable' rows='3' data-limit-rows='true' data-autoresize name='" + $(this).attr("name") + "'>" + $(this).text() + "</textarea>"
  944. );
  945. // Remember the text element
  946. textElement = li.find(".expandable");
  947. /*
  948. // Fix the bug that tags still might appear
  949. textElementHTML = textElement.html();
  950. while(textElementHTML.indexOf("<a class='tag'>") != -1) {
  951. textElementHTML = textElementHTML.replace("<a class='tag'>", "");
  952. textElementHTML = textElementHTML.replace("</a>", "");
  953. }
  954. textElement.html(textElementHTML);
  955. */
  956. // Remember the width of the text element
  957. textElementWidth = textElement.width();
  958. // Focus immediately on click instead of having to click on the element a second time
  959. textElement.focus();
  960. // Zoom in animation
  961. if(textElementWidth >= 0 && textElementWidth <= 250) {
  962. textElement.addClass("zoom-in-regular");
  963. textElement.css("background-color", "rgba(255, 255, 255, 1)");
  964. textElement.css("-ms-transform", "scale(1.02)");
  965. textElement.css("-webkit-transform", "scale(1.02)");
  966. textElement.css("transform", "scale(1.02)");
  967. }
  968. else if(textElementWidth >= 251 && textElementWidth <= 600) {
  969. textElement.addClass("zoom-in-less");
  970. textElement.css("background-color", "rgba(255, 255, 255, 1)");
  971. textElement.css("-ms-transform", "scale(1.01)");
  972. textElement.css("-webkit-transform", "scale(1.01)");
  973. textElement.css("transform", "scale(1.01)");
  974. }
  975. else if(textElementWidth >= 601) {
  976. textElement.addClass("zoom-in-least");
  977. textElement.css("background-color", "rgba(255, 255, 255, 1)");
  978. textElement.css("-ms-transform", "scale(1.005)");
  979. textElement.css("-webkit-transform", "scale(1.005)");
  980. textElement.css("transform", "scale(1.005)");
  981. }
  982. // Save added idea on Enter press
  983. saveAddedIdeaOnEnterPress(li);
  984. // Replace textarea with a div
  985. $("li.added_item textarea.expandable").on("focusout", function() {
  986. // Declarations
  987. var li = $(this).parent();
  988. var textElement;
  989. var textElementWidth;
  990. // Replace textarea with a div
  991. $(this).replaceWith(
  992. "<div class='expandable' name='" + $(this).attr("name") + "'>" + $(this).val() + "</div>"
  993. );
  994. // Remember the text element
  995. textElement = li.find(".expandable");
  996. // Remember the width of the text element
  997. textElementWidth = textElement.width();
  998. // Update tags on the canvas
  999. // window.setTimeout(updateTags(), 100);
  1000. updateTags();
  1001. // Zoom out animation
  1002. if(textElementWidth >= 0 && textElementWidth <= 250) {
  1003. textElement.addClass("zoom-out-regular");
  1004. }
  1005. else if(textElementWidth >= 251 && textElementWidth <= 500) {
  1006. textElement.addClass("zoom-out-less");
  1007. }
  1008. else if(textElementWidth >= 501) {
  1009. textElement.addClass("zoom-out-least");
  1010. }
  1011. textElement.css("background-color", "rgba(255, 255, 255, 0.75)");
  1012. textElement.css("-ms-transform", "scale(1)");
  1013. textElement.css("-webkit-transform", "scale(1)");
  1014. textElement.css("transform", "scale(1)");
  1015. // If no tags have been added, reset text explaining so
  1016. if(tags.length === 0) {
  1017. $("div.saved-tags p").html("You haven't added any tags yet.");
  1018. }
  1019. toggleTextElementOnFocus();
  1020. });
  1021. }
  1022. });
  1023. }
  1024. /*
  1025. // ================================================
  1026. If the user types a new character in the added idea field, add tag if a term could be found
  1027. ================================================= //
  1028. // 8an33j24
  1029. function applyTagOnTypeMatch() {
  1030. $("li.added_item .expandable").on("focusin", function() {
  1031. // If the user presses a key in the description textarea
  1032. $("li.added_item .expandable").on("keyup", function() {
  1033. if(event.which !== 9 && // Tab
  1034. event.which !== 16 && // Shift
  1035. event.which !== 37 && // Left
  1036. event.which !== 38 && // Up
  1037. event.which !== 39 && // Right
  1038. event.which !== 40) { // Down
  1039. // Declarations
  1040. var bugCounter = 0;
  1041. var loopCounter = 0;
  1042. var tagLinkToSearch;
  1043. var tagLinkHits;
  1044. var tagTextToSearch;
  1045. var tagTextHits;
  1046. var text = $(this).html();
  1047. // Fix the bug that triggers the event twice
  1048. if(!bugCounter > 0) {
  1049. // console.log("tagTextHits: " + tagTextHits);
  1050. // console.log("tagLinkHits: " + tagLinkHits);
  1051. // For every tag that belongs to the active user
  1052. for(t in tags) {
  1053. if($(this).html().indexOf(tags[loopCounter]) != -1) {
  1054. // Search for the tag inside the added idea as a link
  1055. tagLinkToSearch = text.match(tags[loopCounter] + "</a>"); // match() can only count to one instance (67hi9nt3)
  1056. // Search for the tag inside the added idea as plain text
  1057. tagTextToSearch = text.match(tags[loopCounter]); // match() can only count to one instance (67hi9nt3)
  1058. // If the tag exists inside the added idea as a link
  1059. if(tagLinkToSearch !== null) {
  1060. // tagLinkHits = 1
  1061. tagLinkHits = tagLinkToSearch.length;
  1062. }
  1063. else {
  1064. // tagLinkHits = 0
  1065. tagLinkHits = 0;
  1066. }
  1067. // If the tag exists inside the added idea as plain text
  1068. if(tagTextToSearch !== null) {
  1069. // tagTextHits = 1
  1070. tagTextHits = tagTextToSearch.length;
  1071. }
  1072. else {
  1073. // tagTextHits = 0
  1074. tagTextHits = 0;
  1075. }
  1076. // 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
  1077. // Change "tagTextHits <= 1" to "tagLinkHits === 0"
  1078. if(tagTextHits > tagLinkHits && tagLinkHits === 0) {
  1079. // Apply the tag
  1080. text = text.replace(tags[loopCounter], "<a class='tag' contenteditable='false'>" + tags[loopCounter] + "</a>");
  1081. $(this).html(text);
  1082. // Restore caret position // u78krf3t
  1083. }
  1084. }
  1085. loopCounter++;
  1086. }
  1087. }
  1088. bugCounter++;
  1089. }
  1090. });
  1091. });
  1092. };
  1093. */
  1094. /* ----------------------------------------------
  1095. Limiting the number of characters the user is allowed to type
  1096. ----------------------------------------------- */
  1097. var maxLength = 100;
  1098. $('.card').on('keyup', '.new_item', function() {
  1099. var length = $(this).val().length;
  1100. length = maxLength - length;
  1101. // show the characters remaining only on this field
  1102. $(this).closest('.user-input').find('.chars').text(length);
  1103. });
  1104. function limitLengthOnInput() {
  1105. // Limit text on key press
  1106. $("li.added_item .expandable").on("keypress", function(event) {
  1107. // Declarations
  1108. var numberOfTags = $(this).children().filter("a").length;
  1109. var textLength = $(this).html().length;
  1110. // Subtract 43 from textLength per tag (the tag HTML is 43 characters)
  1111. $(this).each(function() {
  1112. textLength -= 43 * numberOfTags;
  1113. });
  1114. if(textLength === 100) { // Windows menu/Right cmd
  1115. event.preventDefault();
  1116. }
  1117. });
  1118. // 28jek79t
  1119. // Limit text on paste
  1120. /*
  1121. var pastedTextOriginal;
  1122. $("li.added_item .expandable").on("paste", function(event) {
  1123. pastedTextOriginal = event.originalEvent.clipboardData.getData("Text");
  1124. if($(this).html().length + pastedTextOriginal > 100) {
  1125. console.log("Too long!");
  1126. event.preventDefault();
  1127. // var caretPosition = the text position
  1128. // Insert the text after caretPosition
  1129. }
  1130. // return false;
  1131. });
  1132. */
  1133. }
  1134. /* ================================================
  1135. If the user closes a dialog
  1136. ================================================= */
  1137. $("div.dialog button").on("click", function() {
  1138. $("div#shadow").css("display", "none");
  1139. $("div.dialog").css("display", "none");
  1140. });
  1141. /* ================================================
  1142. If the user clicks on the "Tag selected term" link
  1143. ================================================= */
  1144. // Declaration
  1145. var selection = "";
  1146. // var newRange = "";
  1147. // Initiate tag
  1148. tag = "";
  1149. // Update the tag variable
  1150. document.onselectionchange = function() {
  1151. // if($("textarea").is(":focus")) {
  1152. if($("li.added_item .expandable").is(":focus")) {
  1153. selection = window.getSelection().toString();
  1154. tag = selection.trim();
  1155. }
  1156. }
  1157. // If the user clicks on the "Tag selected term" link
  1158. $("p.tag-selected-term a").on("click", function() {
  1159. // If the tag isn't empty
  1160. if(tag != "") {
  1161. // Show the tag window
  1162. showTagWindow();
  1163. }
  1164. else {
  1165. // Show a dialog
  1166. $("div#shadow").css("display", "block");
  1167. $("div#dialog-select-term").css("display", "block");
  1168. }
  1169. // Prevent the current view to jump to the top of the screen
  1170. return false;
  1171. });
  1172. // If the user moves the focus from the added idea, reset variables
  1173. $("li.added_item .expandable").on("focusout", function() {
  1174. selection = "";
  1175. tag = "";
  1176. });
  1177. /* ================================================
  1178. Serialize Form to JSON
  1179. ================================================= */
  1180. $.fn.serializeObject = function() {
  1181. // Declarations
  1182. var o = {};
  1183. var a = this.serializeArray();
  1184. var addedIdeaLists = $(".card ul");
  1185. $.each(a, function() {
  1186. if (o[this.name]) {
  1187. if (!o[this.name].push) {
  1188. o[this.name] = [o[this.name]];
  1189. }
  1190. o[this.name].push(this.value || '');
  1191. }
  1192. else {
  1193. o[this.name] = this.value || '';
  1194. }
  1195. });
  1196. // Add added ideas to the JSON object manually
  1197. $.each(addedIdeaLists, function() {
  1198. var field = $(this).attr("id");
  1199. var addedItemDivs = $(this).find($(".expandable"));
  1200. var addedItemArray = [];
  1201. var numberOfAddedItem = addedItemDivs.length;
  1202. if(numberOfAddedItem > 1) {
  1203. for(var i = 0; i < numberOfAddedItem; i++) {
  1204. addedItemArray[i] = addedItemDivs[i].textContent;
  1205. }
  1206. o[field + "[]"] = addedItemArray;
  1207. }
  1208. else if(numberOfAddedItem === 1) {
  1209. o[field + "[]"] = addedItemDivs[0].textContent;
  1210. }
  1211. });
  1212. return o;
  1213. };
  1214. /* ================================================
  1215. Getting the current date
  1216. ================================================= */
  1217. var fullDate = new Date();
  1218. var fourDigitYear = fullDate.getFullYear();
  1219. var twoDigitMonth = fullDate.getMonth() + 1 + "";
  1220. var twoDigitDate = fullDate.getDate() + "";
  1221. if(twoDigitMonth.length == 1) {
  1222. twoDigitMonth = "0" + twoDigitMonth;
  1223. }
  1224. if(twoDigitDate.length == 1) {
  1225. twoDigitDate = "0" + twoDigitDate;
  1226. }
  1227. var currentDate = fourDigitYear + "-" + twoDigitMonth + "-" + twoDigitDate;
  1228. // Set the current date in the date input field
  1229. // $('.proj_date').val(currentDate);
  1230. /* ================================================
  1231. USER LOGS OUT (dropdown menu)
  1232. ================================================= */
  1233. $('#user-profile').on('click', '#logout', function() {
  1234. var url = 'php/logout.php';
  1235. $.post(url, function(data, status) {
  1236. if (data == 200) {
  1237. $('#user-profile').hide();
  1238. $('.invited-members').hide();
  1239. window.location.href="https://www.ethicscanvas.org";
  1240. }
  1241. });
  1242. });
  1243. /* ================================================
  1244. When the page loads, Import the chosen canvas if the user has picked one from the dashboard,
  1245. otherwise load an empty canvas
  1246. ================================================= */
  1247. // if a canvas is chosen by the user to be loaded
  1248. if (current_canvas_id !== '') {
  1249. var url = 'json/' + current_canvas_id + '.json';
  1250. // var url= 'json/test_canvas.json';
  1251. // get the saved JSON object in the sendJSON.text file
  1252. $.getJSON(url, function(returnedObj) {
  1253. // Display the json data in the html
  1254. var itemListHTML = '';
  1255. // iterate through the object
  1256. $.each(returnedObj, function(key, value) {
  1257. // project name and tem field
  1258. if (key === 'field_00[]') {
  1259. $('.form-header').find('input.proj_title').val(value[
  1260. 0]);
  1261. $('.form-header').find('input.proj_date').val(value[1]);
  1262. }
  1263. else if (key !== 'new_item') {
  1264. if ($.type(value) === "array") {
  1265. $.each(value, function(i, itm) {
  1266. /** FIX DUPLICATIONs in the canvas when importing
  1267. /* Importing will override the canvas content
  1268. clear the canvas by giving en emty content to the ul list (remove previous list items) */
  1269. $('.canvas-form').find('.card').filter('.' + key.substr(0, 8)).find('ul.item_list').html('');
  1270. /* Create a list item with each value item
  1271. and give it text area with the name attribute as the "key" (right field name) */
  1272. itemListHTML +=
  1273. // '<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>';
  1274. '<li class="added_item"><div class="expandable" name="' + key + '">' + itm + '</div><br /><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>';
  1275. });
  1276. }
  1277. else { // a single value string
  1278. itemListHTML +=
  1279. // '<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>';
  1280. '<li class="added_item"><div class="expandable" name="' + key + '">' + value + '</div><br /><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>';
  1281. }
  1282. /* Append the created list items/textatreas to the right field based on the "key"*/
  1283. /* the str.substr(start,length)
  1284. 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
  1285. so field names/key/name attribute will tuen into class names: ex: field_1[] becomes field_1
  1286. */
  1287. // find the field by its class names besed on the current key name
  1288. // append the created list of item values to that right field
  1289. $('.canvas-form').find('.card').filter('.' + key.substr(0, 8)).find('ul.item_list').append(itemListHTML);
  1290. /*$('form').find('.card').filter('.field_1').find('ul.item_list').append(itemListHTML); */
  1291. /* !! 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 */
  1292. itemListHTML = '';
  1293. }
  1294. });
  1295. });
  1296. // Limit the text in the idea field if it reaches the max length
  1297. limitLengthOnInput();
  1298. // Apply event listener to the added idea handling the application of tags should the user writes one of the terms in it
  1299. // applyTagOnTypeMatch();
  1300. // Toggle textarea.expandable/div.expandable on focus
  1301. window.setTimeout(toggleTextElementOnFocus, 100);
  1302. // Show "Tag selected term" link in the destination category
  1303. window.setTimeout(function() {
  1304. $(".card .item_list").each(function() {
  1305. // console.log($(this).find("li"));
  1306. if($(this).find("li.added_item").length) {
  1307. $(this).next().show();
  1308. }
  1309. else {
  1310. // console.log("Nej!");
  1311. }
  1312. });
  1313. }, 100);
  1314. /*
  1315. $("div#move-window ul a").on("click", function() {
  1316. // If the number of the category is between 10-99
  1317. if($(this).parent().text().trim().substring(1, 2) != ".") {
  1318. categoryDestination = $(this).parent().text().trim().substring(0, 2);
  1319. }
  1320. // If the number of the category is between 0-9
  1321. else {
  1322. categoryDestination = $(this).parent().text().trim().substring(0, 1);
  1323. }
  1324. // Move the idea
  1325. // If the number of the category is between 10-99
  1326. if(categoryDestination > 9) {
  1327. $("ul#field_" + categoryDestination).append(ideaLi);
  1328. // $("ul#field_0" + (categoryOrigin + 1)).parent().find("p.tag-selected-term").css("display", "none");
  1329. }
  1330. // If the number of the category is between 0-9
  1331. else {
  1332. $("ul#field_0" + categoryDestination).append(ideaLi);
  1333. // $("ul#field_0" + (categoryOrigin + 1)).parent().find("p.tag-selected-term").css("display", "none");
  1334. }
  1335. // Close the move window
  1336. closeMoveWindow();
  1337. // Restore links in the move window
  1338. if($("div#move-window li").length > $("div#move-window a").length) {
  1339. $("div#move-window ul").children().remove()
  1340. $("div#move-window ul").append(categoryLis);
  1341. moveIdeaOnClick();
  1342. }
  1343. // Hide "Tag selected term" link in the origin category if there are no ideas left
  1344. if($("ul#field_0" + (categoryOrigin + 1)).children().length === 0) {
  1345. // If the number of the category is between 10-99
  1346. if((categoryOrigin + 1) > 9) {
  1347. $("ul#field_" + (categoryOrigin + 1)).parent().find("p.tag-selected-term").css("display", "none");
  1348. }
  1349. // If the number of the category is between 0-9
  1350. else {
  1351. $("ul#field_0" + (categoryOrigin + 1)).parent().find("p.tag-selected-term").css("display", "none");
  1352. }
  1353. }
  1354. // Show "Tag selected term" link in the destination category
  1355. // If the number of the category is between 10-99
  1356. if((categoryOrigin + 1) > 9) {
  1357. $("ul#field_" + categoryDestination).parent().find("p.tag-selected-term").css("display", "block");
  1358. }
  1359. // If the number of the category is between 0-9
  1360. else {
  1361. $("ul#field_0" + categoryDestination).parent().find("p.tag-selected-term").css("display", "block");
  1362. }
  1363. */
  1364. // Remove all tags from all fields
  1365. // removeTags();
  1366. // Get the user's tags from the database and apply them on the canvas
  1367. getTags();
  1368. // Show "Tag selected term" link
  1369. /*
  1370. if($(this).parent().parent().parent().prev().prev().children().length > 0) {
  1371. $(this).parent().parent().parent().prev().css("display", "block");
  1372. }
  1373. if($(this).parent().parent().prev().prev().children().length > 0) {
  1374. $(this).parent().parent().prev().css("display", "block");
  1375. }
  1376. */
  1377. // Fix the heights after importing
  1378. // fixHeights();
  1379. }
  1380. /* ================================================
  1381. Toggle the introduction text in fields
  1382. ================================================= */
  1383. //$(selector).toggle(speed,easing,callback)
  1384. $('.card').on('click', '.intro-toggle', function() {
  1385. var $TogglingText = $($(this).closest('.card').find('.intro'));
  1386. var $Toggler = $($(this).closest('.card').find('.intro-toggle'));
  1387. $TogglingText.toggle('slow', function() {
  1388. // Do this when toggling:
  1389. // the boolean .is(':visible') of the current toggle state
  1390. if ($TogglingText.is(':visible')) {
  1391. // change the text of the toggle
  1392. $Toggler.find('.intro-toggle-text').text('Hide description');
  1393. // change the icon of the toggle
  1394. $Toggler.find('.intro-toggle-icon').switchClass("glyphicon-plus-sign", "glyphicon-minus-sign", 1000, "easeInOutQuad");
  1395. }
  1396. else {
  1397. $Toggler.find('.intro-toggle-text').text('Show description');
  1398. $Toggler.find('.intro-toggle-icon').switchClass("glyphicon-minus-sign", "glyphicon-plus-sign", 1000, "easeInOutQuad");
  1399. }
  1400. });
  1401. });
  1402. /* ================================================
  1403. Auto expand user input textareas
  1404. ================================================= */
  1405. /* Works for textareas already exsting in the html when the page loads -> User input
  1406. $.each($('textarea[data-autoresize]'), function() {
  1407. var offset = this.offsetHeight - this.clientHeight;
  1408. var resizeTextarea = function(el) {
  1409. $(el).css('height', 'auto').css('height', el.scrollHeight + offset);
  1410. };
  1411. $(this).on('keyup input', function() {
  1412. resizeTextarea(this);
  1413. }).removeAttr('data-autoresize');
  1414. });
  1415. /* ================================================
  1416. Limiting the number of lines in textareas
  1417. ================================================= */
  1418. // <textarea data-limit-rows="true" cols="60" rows="8"></textarea>
  1419. /*
  1420. $('.card').on('keypress', 'textarea[data-limit-rows=true]', function(event) {
  1421. var textarea = $(this),
  1422. text = textarea.val(),
  1423. // match() -> Searches a string for a match against a regular expression, and returns the matches, as an Array object.
  1424. numberOfLines = (text.match(/\n/g) || []).length + 1,
  1425. maxRows = parseInt(textarea.attr('rows'));
  1426. // if the number of lines have reached the max rows
  1427. if (numberOfLines === maxRows) {
  1428. return false;
  1429. }
  1430. });
  1431. */
  1432. /* ================================================
  1433. Handling user input, ADD items
  1434. A. Add button
  1435. B. Clicking enter
  1436. ================================================= */
  1437. /* ----------------------------------------------
  1438. add new idea slide effect
  1439. ----------------------------------------------- */
  1440. // 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
  1441. $('.card').on('click', 'a.add-idea', function(event) {
  1442. // stop the default behavior of the link (jumping back to the start of the page)
  1443. event.preventDefault();
  1444. // set the textarea automatically in focus
  1445. $(this).closest('.card').find('.user-input').slideToggle("slow", function() {
  1446. // When the toggle animation is complete:
  1447. // set the text area in focus
  1448. $(this).closest('.card').find('.new_item').val('');
  1449. $(this).closest('.card').find('.chars').text(maxLength);
  1450. $(this).closest('.card').find('.new_item').focus();
  1451. });
  1452. });
  1453. /* ----------------------------------------------
  1454. A. When we click the add btn to
  1455. add the item to the list
  1456. ----------------------------------------------- */
  1457. // event deligation to handle the present and future elements that are dynamically added
  1458. $('.card').on('click', '.add_btn', function() {
  1459. var new_item = $(this).closest('.card').find('.new_item').val();
  1460. var new_item_height = $(this).closest('.card').find('.new_item').height();
  1461. // number of items are in the list
  1462. var fieldItemCount = $(this).closest('.card').find('ul.item_list').find('li').length;
  1463. // new item added, increment the number of items
  1464. fieldItemCount++;
  1465. // add the input value as a textarea item
  1466. /* 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) */
  1467. // if the new item input exist (is not empty), add the item
  1468. if (new_item) {
  1469. var field_attr = $(this).closest('.card').find('ul.item_list').attr('id') + '[]';
  1470. // The height of the newly added item = the height of the add new idea textarea
  1471. $(this).closest('.card').find('ul.item_list').append(
  1472. // '<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>'
  1473. '<li class="added_item"><div class="expandable" name="' + field_attr + '">' + new_item + '</div><br /><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>'
  1474. );
  1475. // Fix the heights only after a new item is added
  1476. // fixHeights();
  1477. }
  1478. // clear the new item the text area value
  1479. $(this).closest('.card').find('.new_item').val('');
  1480. /* When clicking on "add idea", hide the input field for adding a new item (slideUp() doesn't work nicely here)*/
  1481. $(this).closest('.card').find('.user-input').hide("fast", function() {
  1482. // Animation complete.
  1483. });
  1484. // Limit the text in the idea field if it reaches the max length
  1485. limitLengthOnInput();
  1486. // Apply event listener to the added idea handling the application of tags should the user writes one of the terms in it
  1487. // applyTagOnTypeMatch();
  1488. // Toggle textarea.expandable/div.expandable on edit
  1489. toggleTextElementOnFocus();
  1490. // Remove all tags from all fields
  1491. removeTags();
  1492. // Get the user's tags from the database and apply them on the canvas
  1493. getTags();
  1494. // Show "Tag selected term" link
  1495. if($(this).parent().parent().prev().prev().children().length > 0) {
  1496. $(this).parent().parent().prev().css("display", "block");
  1497. }
  1498. });
  1499. /* ----------------------------------------------
  1500. B. Clicking enter in the add idea textarea,
  1501. will add the new item to the card
  1502. ----------------------------------------------- */
  1503. $('.card').on('keypress', 'textarea[data-limit-rows=true]', function(event) {
  1504. var textarea = $(this);
  1505. var text = textarea.val();
  1506. /* The jQuery event.which -->
  1507. Returns which keyboard key was pressed: */
  1508. // if the enter is pressed, event.which === 13
  1509. if (event.which === 13 && !$("li.added_item .expandable").is(":focus")) {
  1510. var new_item = $(this).closest('.card').find('.new_item').val();
  1511. var new_item_height = $(this).closest('.card').find('.new_item').height();
  1512. // number of items are in the list
  1513. var fieldItemCount = $(this).closest('.card').find('ul.item_list')
  1514. .find('li').length;
  1515. // new item added, increment the number of items
  1516. fieldItemCount++;
  1517. // add the input value as a textarea item
  1518. /* 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) */
  1519. // if the new item input exist (is not empty), add the item
  1520. if (new_item) {
  1521. var field_attr = $(this).closest('.card').find('ul.item_list').attr(
  1522. 'id') + '[]';
  1523. // The height of the newly added item = the height of the add new idea textarea
  1524. $(this).closest('.card').find('ul.item_list').append(
  1525. // '<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>');
  1526. '<li class="added_item"><div class="expandable" name="' + field_attr + '">' + new_item + '</div><br /><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>'
  1527. );
  1528. // Fix the heights only after a new item is added
  1529. // fixHeights();
  1530. }
  1531. // clear the new item the text area value
  1532. $(this).closest('.card').find('.new_item').val('');
  1533. /* When clicking on "add idea", hide the input field for adding a new item (slideUp() doesn't work nicely here)*/
  1534. $(this).closest('.card').find('.user-input').hide("fast", function() {
  1535. // Animation complete.
  1536. });
  1537. // Limit the text in the idea field if it reaches the max length
  1538. limitLengthOnInput();
  1539. // Apply event listener to the added idea handling the application of tags should the user writes one of the terms in it
  1540. // applyTagOnTypeMatch();
  1541. // Toggle textarea.expandable/div.expandable on edit
  1542. toggleTextElementOnFocus();
  1543. // Remove all tags from all fields
  1544. removeTags();
  1545. // Get the user's tags from the database and apply them on the canvas
  1546. getTags();
  1547. // Show "Tag selected term" link
  1548. if($(this).parent().parent().parent().prev().prev().children().length > 0) {
  1549. $(this).parent().parent().parent().prev().css("display", "block");
  1550. }
  1551. }
  1552. });
  1553. /* ================================================
  1554. Moving ideas to a different category
  1555. ================================================= */
  1556. // Declarations
  1557. // var categoryUl = $("div#move-window ul");
  1558. var categoryDestination;
  1559. var categoryLis = $("div#move-window ul").html();
  1560. var categoryAs = $("div#move-window ul a");
  1561. var categoryOrigin;
  1562. var ideaLi;
  1563. var linkLi;
  1564. var linkText;
  1565. // Remove the link to the current category, as the idea cannot be moved to its own category where it already is
  1566. function removeLinkToOriginCategory(text) {
  1567. // If the number of the category is between 10-99
  1568. if(text.substring(6, 7) != "0") {
  1569. categoryOrigin = text.substring(6, 9) - 1;
  1570. }
  1571. // If the number of the category is between 0-9
  1572. else {
  1573. categoryOrigin = text.substring(7, 9) - 1;
  1574. }
  1575. // Remove "a" tag
  1576. linkLi = $("div#move-window ul li").get(categoryOrigin);
  1577. linkText = categoryAs.get(categoryOrigin).innerHTML;
  1578. linkLi.innerHTML = linkText;
  1579. }
  1580. // If the user clicks on the "Move" icon, show the move window
  1581. $(".card").on("click", "span.handle", function() {
  1582. // Show the move window
  1583. $("div#shadow").css("display", "block");
  1584. $("div#move-window").css("display", "block");
  1585. // Assign the idea that is going to be moved
  1586. ideaLi = $(this).parent();
  1587. // Remove the link to the current category, as the idea cannot be moved to its own category where it already is
  1588. removeLinkToOriginCategory($(this).parent().parent().attr("id"));
  1589. });
  1590. // Close the move window
  1591. function closeMoveWindow() {
  1592. // Close the move window
  1593. $("div#shadow").css("display", "none");
  1594. $("div#move-window").css("display", "none");
  1595. }
  1596. // If the user clicks on the "Close" button
  1597. $("div#move-window button.close").on("click", function() {
  1598. // Close the move window
  1599. closeMoveWindow();
  1600. });
  1601. // If the user clicks on a category, move the idea
  1602. function moveIdeaOnClick() {
  1603. $("div#move-window ul a").on("click", function() {
  1604. // If the number of the category is between 10-99
  1605. if($(this).parent().text().trim().substring(1, 2) != ".") {
  1606. categoryDestination = $(this).parent().text().trim().substring(0, 2);
  1607. }
  1608. // If the number of the category is between 0-9
  1609. else {
  1610. categoryDestination = $(this).parent().text().trim().substring(0, 1);
  1611. }
  1612. // Move the idea
  1613. // If the number of the category is between 10-99
  1614. if(categoryDestination > 9) {
  1615. $("ul#field_" + categoryDestination).append(ideaLi);
  1616. // $("ul#field_0" + (categoryOrigin + 1)).parent().find("p.tag-selected-term").css("display", "none");
  1617. }
  1618. // If the number of the category is between 0-9
  1619. else {
  1620. $("ul#field_0" + categoryDestination).append(ideaLi);
  1621. // $("ul#field_0" + (categoryOrigin + 1)).parent().find("p.tag-selected-term").css("display", "none");
  1622. }
  1623. // Close the move window
  1624. closeMoveWindow();
  1625. // Restore links in the move window
  1626. if($("div#move-window li").length > $("div#move-window a").length) {
  1627. $("div#move-window ul").children().remove()
  1628. $("div#move-window ul").append(categoryLis);
  1629. moveIdeaOnClick();
  1630. }
  1631. // Hide "Tag selected term" link in the origin category if there are no ideas left
  1632. if($("ul#field_0" + (categoryOrigin + 1)).children().length === 0) {
  1633. // If the number of the category is between 10-99
  1634. if((categoryOrigin + 1) > 9) {
  1635. $("ul#field_" + (categoryOrigin + 1)).parent().find("p.tag-selected-term").css("display", "none");
  1636. }
  1637. // If the number of the category is between 0-9
  1638. else {
  1639. $("ul#field_0" + (categoryOrigin + 1)).parent().find("p.tag-selected-term").css("display", "none");
  1640. }
  1641. }
  1642. // Show "Tag selected term" link in the destination category
  1643. // If the number of the category is between 10-99
  1644. if((categoryOrigin + 1) > 9) {
  1645. $("ul#field_" + categoryDestination).parent().find("p.tag-selected-term").css("display", "block");
  1646. }
  1647. // If the number of the category is between 0-9
  1648. else {
  1649. $("ul#field_0" + categoryDestination).parent().find("p.tag-selected-term").css("display", "block");
  1650. }
  1651. });
  1652. }
  1653. moveIdeaOnClick();
  1654. /* ================================================
  1655. Moving ideas up
  1656. ================================================= */
  1657. // If the user clicks on the "Up" button
  1658. $('.card').on('click', 'span.move-up', function() {
  1659. // Declarations
  1660. var ideaLiCurrent = $(this).parent();
  1661. var ideaLiPrevious = $(this).parent().prev();
  1662. // Move the idea
  1663. if(ideaLiPrevious.is("li")) {
  1664. ideaLiCurrent.detach();
  1665. ideaLiPrevious.before(ideaLiCurrent);
  1666. }
  1667. });
  1668. /* ================================================
  1669. Moving ideas down
  1670. ================================================= */
  1671. // If the user clicks on the "Down" button
  1672. $('.card').on('click', 'span.move-down', function() {
  1673. // Declarations
  1674. var ideaLiCurrent = $(this).parent();
  1675. var ideaLiNext = $(this).parent().next();
  1676. // Move the idea
  1677. if(ideaLiNext.is("li")) {
  1678. ideaLiCurrent.detach();
  1679. ideaLiNext.after(ideaLiCurrent);
  1680. }
  1681. });
  1682. /* ================================================
  1683. Deleting ideas
  1684. ================================================= */
  1685. // when the cross beside the textarea is clicked (span.remove)
  1686. // remove that list item
  1687. $('.card').on('click', 'span.remove', function() {
  1688. // If there are no ideas left, hide "Tag selected term" link
  1689. if($(this).prev().parent().parent().children().length === 1) {
  1690. $(this).prev().parent().parent().next().css("display", "none");
  1691. }
  1692. // Remove the list item
  1693. $(this).closest('li').remove();
  1694. });
  1695. /* ================================================
  1696. Sortable field ideas
  1697. ================================================= */
  1698. // make items sortable in their fields and between fields
  1699. /*
  1700. $('.sortable').sortable({
  1701. connectWith: '.connectedList',
  1702. placeholder: "sort-placeholder",
  1703. // revert: true
  1704. zIndex: 300 // Or greater than any other relative/absolute/fixed elements and droppables
  1705. });
  1706. */
  1707. /* ================================================
  1708. Sorting and Dragging events
  1709. ================================================= */
  1710. /* sortstart
  1711. sortover
  1712. sortstop */
  1713. // 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)
  1714. /*
  1715. // Dragging starts
  1716. $(".sortable").on("sortstart", function(event, ui) {
  1717. // WHEN WE SORT CARDS, $(this) ---> the "begining" ul with the class of .sortable
  1718. });
  1719. // Dragging ends: item dropped
  1720. $(".sortable").on("sortstop", function(event, ui) {
  1721. // get the id of the field ul (to set the name attribute of textareas)
  1722. // # mouseleave is the right event for when we release and leave a card mouseup doesn't work properly in this case
  1723. $('.card').on('mouseleave', 'li', function() {
  1724. //$(selector).attr(attribute,value)
  1725. var fieldAttr = $(this).closest('ul.item_list').attr('id');
  1726. // $(this).find('textarea').attr('name', fieldAttr + '[]');
  1727. $(this).find('li.added_item .expandable').attr('name', fieldAttr + '[]');
  1728. });
  1729. });
  1730. */
  1731. /* ================================================
  1732. SAVING THE CANVAS:
  1733. CLICK ON #EXPORT JSON# form button
  1734. ================================================= */
  1735. /* ----------------------------------------------
  1736. If the user clicks on the SAVE CANVAS button
  1737. ----------------------------------------------- */
  1738. $('.canvas-form').on('click', '.json_exp', function() {
  1739. /* ----------------------------------------------
  1740. A: Saving the canvas
  1741. as a registered user
  1742. ----------------------------------------------- */
  1743. // php variables are retieved in the header of the canvas index.php as js variables -->
  1744. var name_save_canvas = $('.form-header').find('.proj_title').val();
  1745. // var date_save_canvas = $('.form-header').find('.proj_date').val();
  1746. var date_save_canvas = currentDate;
  1747. var save_canvas_obj = {
  1748. 'email_save_canvas': email_save_canvas,
  1749. 'name_save_canvas': name_save_canvas,
  1750. 'date_save_canvas': date_save_canvas,
  1751. 'id_save_canvas': canvasId
  1752. };
  1753. var save_canvas = $.param(save_canvas_obj);
  1754. /* Post the JSON stringified object to the php file
  1755. (the php script will save it in a .json file ) */
  1756. var save_reg_url = "php/save-canvas.php";
  1757. $.post(save_reg_url, { save_canvas: save_canvas }, function(data, status) {
  1758. //the returned data is successful, is the $canvas_id
  1759. var canvas_id = data;
  1760. // 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
  1761. // Give the user feedback that the canvas has been saved
  1762. if (data !== 400 || data !== 401) {
  1763. if ($('.imp-exp-btn ').find(".save-canvas-feedback") !== null) {
  1764. $('.imp-exp-btn ').find(".save-canvas-feedback").remove();
  1765. }
  1766. $('.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 saved in your dashboard</p></div>');
  1767. // remove the canvas is saves message as soon as user changes the canvas
  1768. // $('.canvas-form').on("change keyup", 'textarea', function() {
  1769. $('.canvas-form').on("change keyup", '.expandable', function() {
  1770. $('.imp-exp-btn ').find(".save-canvas-feedback").remove();
  1771. });
  1772. } else {
  1773. $('.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>');
  1774. }
  1775. // For the second AJAX request:
  1776. /* ----------------------------------------------
  1777. B: Exporing the form data json to a file
  1778. and save it on the server
  1779. ----------------------------------------------- */
  1780. // $('#result').text(JSON.stringify($('.canvas-form').serializeObject()));
  1781. // Make the JSON object into a JSON string
  1782. // var JSONstrObj = JSON.stringify($('.canvas-form').serializeObject());
  1783. var JSONstrObj = JSON.stringify($('.canvas-form').serializeObject());
  1784. var url = "php/canvas.php";
  1785. // Post the JSON stringified object to the php file (the php script will save it in a .json file)
  1786. // Also, send the canvas_id and use it for naming the file
  1787. $.post(url, {
  1788. JSONstrObj: JSONstrObj,
  1789. canvas_id: canvas_id
  1790. }, function(data, status) {
  1791. console.log(
  1792. 'Response from php when sending the form json object: \n' +
  1793. 'data:' + data + '\n status: ' + status);
  1794. }).fail(function(jqXHR) {
  1795. console.log("Error " + jqXHR.status + ' ' + jqXHR.statustext);
  1796. });
  1797. }).fail(function(jqXHR) {
  1798. console.log("Error " + jqXHR.status + ' ' + jqXHR.statustext);
  1799. });
  1800. // Prevent the card item list from reseting itself after clicking on the export button (submission). Because the type of the button is submit
  1801. return false;
  1802. });
  1803. /* ================================================
  1804. HANDLING CLICK ON : Share This Canvas BUTTON
  1805. ================================================= */
  1806. $('.canvas-form').on('click', '.share_canvas', function() {
  1807. $('.share_canvas_email').slideDown(1000, function() {
  1808. // SAVE THE PDF AS file
  1809. $.post('mpdf/canvas-pdf-save.php', function(data, status) { }); // save pdf as file
  1810. });
  1811. });
  1812. $('.canvas-form').on('click', '.share_canvas_send', function() {
  1813. var share_email = $('.share_canvas_email').find('input').serialize();
  1814. // 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
  1815. $.post('php/share-canvas.php', {
  1816. share_email: share_email
  1817. }, function(data, status) {
  1818. if (data == 200) { // canvas successfully shared
  1819. $('.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>')
  1820. }
  1821. else {
  1822. $('.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>')
  1823. }
  1824. });
  1825. // slide up the .share_canvas_email area
  1826. $('.share_canvas_email').slideUp();
  1827. });
  1828. /* ================================================
  1829. Controlling the height of divs dynamically
  1830. ================================================= */
  1831. // Call this function after adding a new item and importing
  1832. // $( window ).width(); ->Returns width of browser viewport
  1833. /*
  1834. function fixHeights() {
  1835. // Returns width of browser viewport
  1836. var screenSize = $(window).width();
  1837. //the longest card of the group 1 .masonry-layout7-5
  1838. var longest_1 = $('.masonry-layout7-5').height();
  1839. //the longest card of the group 2 .masonry-layout7-5
  1840. var longest_2 = $('.masonry-layout4').height();
  1841. // --- 5 COL Range ----
  1842. if (screenSize >= 1139) {
  1843. // 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
  1844. // card group 1:
  1845. // $('.field_05,.field_11, .field_07').css('min-height', longest_1 - longest_1 * 5 / 100);
  1846. // $('.field_06,.field_08, .field_12').css('min-height', longest_1 + longest_1 * 5 / 100);
  1847. // $('.field_01, .field_02').css('min-height', longest_1 * 2 + longest_1 * 1 / 100);
  1848. // card group 2:
  1849. // $('.field_03, .field_09, .field_10, .field_04').css('min-height', longest_2 * 2 - longest_2 * 20 / 100);
  1850. $('.field_05,.field_11, .field_07').css('min-height', longest_1 - longest_1 * 20 / 100);
  1851. $('.field_06,.field_08, .field_12').css('min-height', longest_1 - longest_1 * 20 / 100);
  1852. $('.field_01, .field_02').css('min-height', longest_1 + longest_1 * 40 / 100);
  1853. // card group 2:
  1854. $('.field_03, .field_09, .field_10, .field_04').css('min-height', longest_2 - longest_2 * 10 / 100);
  1855. }
  1856. // 4 COL Range //
  1857. else if (screenSize >= 977 && screenSize <= 1138) {
  1858. // card group 1:
  1859. // row 1
  1860. $('.field_01,.field_06, .field_12,.field_08 ').css('min-height', longest_1 + longest_2 * 20 / 100);
  1861. // row 2
  1862. $('.field_05,.field_11, .field_07,.field_02 ').css('min-height', longest_1 + longest_2 * 20 / 100);
  1863. // card group 2:
  1864. // row 3
  1865. $('.field_03, .field_09, .field_10, .field_04').css('min-height', longest_2 * 2 - longest_2 * 20 / 100);
  1866. } else if (screenSize >= 920 && screenSize <= 976) {
  1867. // card group 1:
  1868. // row 1
  1869. $('.field_01,.field_06, .field_12,.field_08 ').css('min-height', longest_1 + longest_2 * 20 / 100);
  1870. // row 2
  1871. $('.field_05,.field_11, .field_07,.field_02 ').css('min-height', longest_1 + longest_2 * 20 / 100);
  1872. // card group 2:
  1873. // row 3
  1874. $('.field_03, .field_09, .field_10, .field_04').css('min-height', longest_2 * 2 - longest_2 * 20 / 100);
  1875. } else if (screenSize >= 485 && screenSize <= 919) {
  1876. // else if (500 <= screenSize < 920) {
  1877. // card group 1:
  1878. $('.field_01,.field_06, .field_12,.field_08 ').css('min-height', longest_1 * 80 / 100);
  1879. $('.field_05,.field_11, .field_07,.field_02 ').css('min-height', longest_1 * 80 / 100);
  1880. // card group 2:
  1881. $('.field_03, .field_09, .field_10, .field_04').css('min-height', longest_2 * 80 / 100);
  1882. // --- 1 COL Range ----
  1883. } else {
  1884. // card group 1:
  1885. $('.field_01,.field_06, .field_12,.field_08 ').css('min-height', longest_1 * 20 / 100);
  1886. $('.field_05,.field_11, .field_07,.field_02 ').css('min-height', longest_1 * 20 / 100);
  1887. // card group 2:
  1888. $('.field_03, .field_09, .field_10, .field_04').css('min-height', longest_2 * 20 / 100);
  1889. }
  1890. }
  1891. function fixHeights() {
  1892. // Returns width of browser viewport
  1893. var screenSize = $(window).width();
  1894. var field01 = $("div.field_01");
  1895. var field02 = $("div.field_02");
  1896. var field03 = $("div.field_03");
  1897. var field04 = $("div.field_04");
  1898. var field05 = $("div.field_05");
  1899. var field06 = $("div.field_06");
  1900. var field07 = $("div.field_07");
  1901. var field08 = $("div.field_08");
  1902. var field09 = $("div.field_09");
  1903. // Set the height of every field
  1904. var heightOfField01 = field01.height();
  1905. var heightOfField03 = field03.height();
  1906. var heightOfField04 = field04.height();
  1907. var heightOfField03And04 = field03.height() + field04.height();
  1908. var heightOfField09 = field09.height();
  1909. var heightOfField05 = field05.height();
  1910. var heightOfField06 = field06.height();
  1911. var heightOfField05And06 = field05.height() + field06.height();
  1912. var heightOfField02 = field02.height();
  1913. // --- 5 COL Range ---
  1914. if (screenSize >= 935) {
  1915. var longestInGroup1 = Math.max(heightOfField01, heightOfField03, heightOfField04, heightOfField03And04, heightOfField09, heightOfField05, heightOfField06, heightOfField05And06, heightOfField02);
  1916. console.log(longestInGroup1);
  1917. // Field group 1
  1918. switch(longestInGroup1) {
  1919. case heightOfField01:
  1920. $(".field_04").css("min-height", longestInGroup1 + 10);
  1921. $(".field_09").css("min-height", longestInGroup1 + 448);
  1922. $(".field_06").css("min-height", longestInGroup1 + 10);
  1923. $(".field_02").css("min-height", longestInGroup1 + 448);
  1924. break;
  1925. case heightOfField03:
  1926. // Code goes here
  1927. break;
  1928. case heightOfField04:
  1929. // Code goes here
  1930. break;
  1931. case heightOfField03And04:
  1932. // Code goes here
  1933. break;
  1934. case heightOfField09:
  1935. // Code goes here
  1936. break;
  1937. case heightOfField05:
  1938. // Code goes here
  1939. break;
  1940. case heightOfField06:
  1941. // Code goes here
  1942. break;
  1943. case heightOfField05And06:
  1944. // Code goes here
  1945. break;
  1946. case heightOfField02:
  1947. // Code goes here
  1948. break;
  1949. default:
  1950. break;
  1951. }
  1952. }
  1953. // --- 4 COL Range ---
  1954. else if (screenSize >= 935 && screenSize <= 991) {
  1955. // Field group 1
  1956. // Code goes here
  1957. // Field group 2
  1958. // Code goes here
  1959. }
  1960. else if (screenSize >= 992 && screenSize <= 1153) {
  1961. // Field group 1
  1962. // Code goes here
  1963. // Field group 2
  1964. // Code goes here
  1965. }
  1966. // --- 2 COL Range ---
  1967. else if (screenSize >= 500 && screenSize <= 934) {
  1968. // Field group 1
  1969. // Code goes here
  1970. // Field group 2
  1971. // Code goes here
  1972. }
  1973. // --- 2-5 COL Range ---
  1974. if (screenSize >= 500) {
  1975. var longestInGroup2;
  1976. // Field group 2
  1977. // Determine the longest Field in group 2
  1978. if(field07.height() < field08.height()) {
  1979. longestInGroup2 = field08;
  1980. }
  1981. else {
  1982. longestInGroup2 = field07;
  1983. }
  1984. if(longestInGroup2 === field07) {
  1985. $(".field_08").css("min-height", longestInGroup2.height() + 10);
  1986. }
  1987. else {
  1988. $(".field_07").css("min-height", longestInGroup2.height() + 10);
  1989. }
  1990. }
  1991. // --- 1 COL Range ---
  1992. // Field group 1
  1993. // Code goes here
  1994. // Field group 2
  1995. // Code goes here
  1996. }
  1997. */
  1998. /*
  1999. new ResizeSensor($(".field_01, .field_02, .field_03, .field_04, .field_05, .field_06, .field_07, .field_08, .field_09"), function() {
  2000. // fixHeights();
  2001. });
  2002. */
  2003. });