PageSourceSearch

https://highschool.herffjones.com/secom/scripts/hjRingWall.js

js herffjones.com collected 2026-10-01 10:30:08 UTC 20,620 bytes, 611 lines download raw bytes

1
2HJCONTAINER.components.ringWallPage = function(con) {		
3	con.init = function() {
4	
5/*
6	 	Filter Flow:
7	 	1. Using jquery against the $allSavedRings DOMFragment - Grab each of the allSavedRings and clone it
8		2. By default give the clone, css class of hide
9		3. Run clone through filter tests, if a match remove css class hide 
10		4. If theres not a class of hide add it to a array of jquery objects (If this wasn't running against a domFragment then I would be hesitant, but since there's no browser repaint/refow it seemed as good an indicator as any.)
11			>>>>>> 5. Filtered results get passed to sorter flow
12			
13		Sorter Flow:
14		1. Either the filter or a menu change invokes the sorter function
15		2. The sorter cares not about appearance, it is fed the array of jquery objects for the rings that should be visible
16		3. Sorter makes a temp array that features just the comparison points and array index for the jq obj representing ring elem
17		4. After making the order correct, $currentRings gets overwritten with the same jq objs - just in expected order
18			>>>>>> 5. showUpdatedResults called, this removes old results, appends new stuff and then invokes pagination
19*/
20		
21		// width of pagination 'panes', longer than you would expect to accomodate margins without tracking 1st and last in row
22		con.galleryContentWidth = 1000;
23
24		// Use this to know first time a ring is liked (first time, login modal presented if not logged in)
25		con.likeCounter = 0;
26		
27		con.ringGalleryLoginModalInit();
28		
29		// For filter&sorter, following 2 crucial - $allSavedRings is domFragment, $currentRings array of JQobjs for each ring elem
30		var $allSavedRings = $();
31		$allSavedRings = $("#ringGalleryRingsHolder").clone();
32		con.$allSavedRings = $allSavedRings;
33
34		con.$currentRings = $();
35		(con.$allSavedRings).find('[data-control="savedRing"]').each(function() {
36			(con.$currentRings).push($(this));
37		});
38		
39		/* 
40			Grab one of these design yours callouts and then let 
41			showUpdated at the end worry about where and how often it goes in with results
42		*/		
43		con.$designYoursCalloutEl = $();
44		con.$designYoursCalloutEl = $("#container").find(".designYourOwnCalloutTemplate").first().clone();
45		
46		con.ringGalleryLikeControlActiveSrc = $("#container").find('[data-control="savedRing"]').first().attr("data-likeControlImgActiveSrc");
47		con.ringGalleryLikeControlSrc = $("#container").find('[data-control="savedRing"]').first().attr("data-likeControlImgSrc");
48		
49		// Grab initial like status from the cookie
50		con.setLikeStatusForAllRings();
51
52		/* Event Handlers */
53				
54		$("#ringGalleryPage").on("click", '[data-control="ringFilter"]', function(e) {
55			var cat = $(this).attr("data-category");
56			con.filterRings($(this), cat);
57		}); 
58		
59		$("#ringGalleryRings").on("click", '[data-control="like"]', function(e) {
60			console.log('page like handler triggered');
61			con.toggleLike($(this));
62		});
63
64		$('[data-control="modalLike"]').click(function(e) {
65			// second param true makes the toggle code update modal and parent page like indicator
66			console.log('modal like handler triggered');
67			con.toggleLike($(this), true);
68		});
69						
70		$("#ringGallerySortBy").on("change", function() {
71			con.sortRings(con.$currentRings);
72		});		
73		
74		$('.ringImg').on('click', function() {
75			var el = $(this);
76			con.showRingModal( el );
77		});
78		
79		$("#designThisRing").on("click", con.designYourRingMakeGradCallback());
80
81		//ringLandingPage
82		$('#savedRingLogin').click(function(e) {
83			e.preventDefault();
84			con.viewSavedRing();
85		});
86		
87		con.promoId = null;
88		con.genderOnLeft = false;
89
90		$(".designYourRing").on("click", con.designYourRingMakeGenderCallback(false));
91		$(".promoArea .imageWithSubtitles").on("click", con.designYourRingMakeGenderCallback(true));
92        //ringLandingPage
93        
94		$(".gradPop button").on("click", function (e) {
95			con.designYourRingGender = "Male";
96			con.designYourRingMaybeGo();
97		});
98				
99		// simulate click to perform initial sort
100		$('#ringGalleryPage #filterRingByAll').trigger('click');
101		
102		con.postFacebookLoginRingSpecifics();
103
104        con.showPassedIn();
105	};
106
107    con.showPassedIn = function() {
108        var rid = con.getURLParameter("ringid");
109        if(!rid || !rid.length)
110            return;
111
112        var toFind = $("#galleryRing" + rid);
113        if(!toFind.length)
114            return;
115
116        var page = toFind.closest(".paginationPage");
117        var pageIdx = page.index();
118
119        selectPaginationPage(pageIdx);
120
121        toFind.find(".ringImg").trigger("click");
122    };
123
124    con.getURLParameter = function(name) {
125        return decodeURI((new RegExp(name + '=' + '(.+?)(&|$)').exec(window.location.search)||[,null])[1]);
126    };
127
128	con.toggleLike = function($likeEl, withinModal) {		
129		// if the like is toggled within the modal we update indicator in parent page AND via a wee function in the modal
130		//		and we do some modal open and closing if its the first like
131		var withinModal = (withinModal) ? withinModal : false;
132		var $parent;
133		
134		if (!withinModal) {
135			// we are liking within the parent page so can just grab the closest savedRing
136			$parent = $likeEl.closest('[data-control="savedRing"]');
137		} else {
138			// find the parent page savedRing that matches what we are 'liking' in the detail modal
139			var $modalParent = $likeEl.closest('[data-control="savedRing"]');
140			var modalRingData = $.parseJSON($modalParent.attr("data-info"));
141			
142			$("#ringGalleryRings").find('[data-control="savedRing"]').each(function(){
143				var data = $.parseJSON($(this).attr("data-info"));
144				if (data.id === modalRingData.id) {
145					$parent = $(this);
146				}	
147			});
148			// NOTE - we have a wee standalone functon later that specifically updates the modal after we take care of same
149			//		savedRing on the parent page
150		}
151		
152		var data = $.parseJSON($parent.attr("data-info"));
153		var likes = $parent.find('.likeCount').text();
154		var ringId = data.id;
155		var idstr = ringId + "-";				
156		var updated = "";
157				
158		if (! $.cookie("herffJones-myLikedRings")) {
159			var likedRingIds = "";
160		} else {
161			var likedRingIds = $.cookie("herffJones-myLikedRings");	
162		}
163		
164		// Toggle liked value
165		if ($parent.attr("data-liked") === "false") {
166			var likeStatus = "true";			
167			$parent.attr("data-liked", likeStatus);
168			updated = likedRingIds + idstr;
169
170			var newLikes = parseInt(likes) + 1;
171			if (newLikes < 0) { 
172				newLikes = 0; 
173			}
174			
175			$parent.find('.likeCount').text(newLikes);
176			updateLikeStatusInAllRings(newLikes, likeStatus);						
177			con.likeCounter++;
178			
179			if (withinModal) {
180				updateLikeStatusInDetailModal(newLikes, likeStatus);
181			}
182
183		} else {
184			var likeStatus = "false";
185			$parent.attr("data-liked", likeStatus);
186			updated = likedRingIds.replace(idstr, "");			
187
188			var newLikes = parseInt(likes) - 1;
189			if (newLikes < 0) { 
190				newLikes = 0; 
191			}
192			
193			$parent.find('.likeCount').text(newLikes);
194			updateLikeStatusInAllRings(newLikes, likeStatus);
195			
196			if (withinModal) {
197				updateLikeStatusInDetailModal(newLikes, likeStatus);
198			}															
199		}
200					
201		// Reset cookie
202		// providing path param as otherwise cookie won't be deleted
203		$.cookie("herffJones-myLikedRings", null, { path: '/'});
204		
205		if (updated.length) {
206			$.cookie("herffJones-myLikedRings", updated, { expires: 999, path: '/' });				
207		}
208		
209		// Since we have a wee function to update the image in the modal (if applicable), 
210		//		here explicitly change on parent page
211		con.toggleLikeImage($parent.find('[data-control="like"]').first(), likeStatus);	
212		
213		console.log('like status is ' + likeStatus);
214		
215		if (con.likeCounter == 1 && ($("#container").attr("loggedIn")) !== 'true' ) {
216			con.afterLoginRingIdToSave = data.id;
217            con.afterLoginRingIdToSaveLiked = likeStatus == "true";
218            // see if they cancel instead, this whole flow needs to be reworked
219
220            var handleClose = function() {
221                con.saveRingLikeToBackend(data.id, likeStatus == "true");
222                $("#login-to-save-liked-rings-modal .closeBtn").off("click", handleClose);
223            };
224
225            $("#login-to-save-liked-rings-modal .closeBtn").on("click", handleClose);
226            
227			window.launchModal($("#login-to-save-liked-rings-modal"), "show", "rings/changeSchool");
228			
229			// increase like counter so if login is dismissed we don't hassle the customer with it again
230			con.likeCounter++;	
231			return false;				
232		} else {
233			con.saveRingLikeToBackend(data.id, likeStatus == "true");
234		}
235		
236		function updateLikeStatusInAllRings(newLikes, likeStatus) {			
237			(con.$allSavedRings).find('[data-control="savedRing"]').each(function() {
238				var data = $.parseJSON($(this).attr("data-info"));
239				if(data.id === ringId) {
240					$(this).attr("data-liked", likeStatus);
241					$(this).find('.likeCount').text(newLikes);			
242				}
243			});
244		}
245		
246		function updateLikeStatusInDetailModal(newLikes, likeStatus) {
247			var $detailRing = $("#ring-wall-view-ring-modal").find('[data-control="savedRing"]').first();
248			$detailRing.attr("data-liked", likeStatus);
249			$detailRing.find('.likeCount').first().text(newLikes);	
250			var $likeEl = $detailRing.find('[data-control="modalLike"]').first();
251			con.toggleLikeImage($likeEl, likeStatus);
252		} 	
253		
254	};
255	con.toggleLikeImage = function($likeEl, likeStatus) {
256		if (likeStatus === "true") {
257			$likeEl.attr("src", con.ringGalleryLikeControlActiveSrc);				
258		} else {
259			$likeEl.attr("src", con.ringGalleryLikeControlSrc);
260		}	
261	};
262	con.saveRingLikeToBackend = function(ringId, like) {
263		var req = con.relativePath + "/rings/" + (like ? "like" : "unlike")+ "/" + ringId;
264		$.ajax({
265			method: 'GET',
266			url: req,
267			success: function(data){
268				console.log('con.saveRingLikeToBackend success for ring ' + ringId + '. data is ' + data);
269			},
270			error: function() {
271				console.log('con.saveRingLikeToBackend FAILURE for ring ' + ringId);
272			}
273		});		
274	};
275	con.setLikeStatusForAllRings = function() {
276		// Grab likes from cookie
277		if ($.cookie("herffJones-myLikedRings")) {
278			var likedRingIds = $.cookie("herffJones-myLikedRings");	
279		} else {
280			return;
281		}
282
283		$("#ringGalleryRingsHolder").find('[data-control="savedRing"]').each(function() {		
284			var data = $.parseJSON($(this).attr("data-info"));		
285			var likeStatus;
286			
287			if (likedRingIds.match(data.id)) {
288				likeStatus = "true";	
289			} else {
290				likeStatus = "false";				
291			}	
292			
293			$(this).attr("data-liked", likeStatus);
294			con.toggleLikeImage($(this).find('[data-control="like"]').first(), likeStatus);	
295		});
296	};
297	con.filterRings = function($el, cat) {
298		var showCount = 0;
299		var $possibleMatch = $();
300		var $filteredRings = [];
301				
302		$("#ringFilters").find('[data-control="ringFilter"]').each(function() {
303			if ($(this).attr("data-category") === cat) {
304				if (! $(this).hasClass("btn-silver-active")) {
305					$(this).removeClass("btn-silver");
306					$(this).addClass("btn-silver-active");
307				}
308			} else {
309				if ($(this).hasClass("btn-silver-active")) {
310					$(this).removeClass("btn-silver-active");
311					$(this).addClass("btn-silver");
312				}
313			}	
314		});
315		
316		(con.$allSavedRings).find('[data-control="savedRing"]').each(function() {
317			var data = $.parseJSON($(this).attr("data-info"));
318			$possibleMatch = $(this).clone();
319			$possibleMatch.addClass("hide");	
320			
321			if (data.title !== 'designYours') {
322				switch (cat) {
323					case "m":
324						if (data.gender && data.gender === cat) {
325							$possibleMatch.removeClass("hide");
326						} 
327						break;
328					case "f":
329						if (data.gender && data.gender === cat) {
330							$possibleMatch.removeClass("hide");
331						}
332						break;
333					case "liked":
334						if ( $(this).attr("data-liked") === "true" ) {
335							$possibleMatch.removeClass("hide");
336						}	
337						break;
338					case "all":	
339						$possibleMatch.removeClass("hide");
340						break;				
341				}
342			
343			}
344			
345			if (! $possibleMatch.hasClass("hide") ) {
346				showCount++;
347				$filteredRings.push($possibleMatch);
348			}			
349		});
350		
351		con.sortRings($filteredRings);		
352	};
353	con.sortRings = function($currentRings) {
354		var sort = $("#ringGallerySortBy").val();
355		
356		// Build a array with just some criteria and the index of the jquery object
357		var tempArray = [];
358		for (i = 0, len = $currentRings.length; i < len; i++) {
359			var curr = $currentRings[i];
360			
361			// grab the json so we can have the sort criteria
362			var data = $.parseJSON(curr.attr("data-info"));
363			
364			// date object so we can compare newest to oldest
365			var slicedDate = (data.created).slice(0, 10);
366			var splitDate = slicedDate.split("-");
367			var slashDate = splitDate[0] + '/' + splitDate[1] + '/' + splitDate[2];
368			var date = new Date(slashDate);
369			
370			// Adding the 2 sort criteria and the original position in the array of jquery elements
371			tempArray.push([data.likeCount, date, i]);
372		}
373		
374		switch (sort) {
375			case "mostPopular":
376				tempArray.sort(function(a, b) {  
377					return b[0] - a[0];  
378				});	
379				
380				break;	
381			case "newestFirst":
382				tempArray.sort(function(a, b) {  
383					return b[1] - a[1];  
384				});					
385			
386				break;
387			case "oldestFirst":
388				tempArray.sort(function(a, b) { 			 
389					return a[1] - b[1];  
390				});				
391			
392				break;
393		}
394		
395		// Now the tempArray is in the correct order we rebuild the currentRings array of elements to match
396		var tempSortedArray = [];
397		for (i = 0, len = tempArray.length; i < len; i++) {
398			var elpos = tempArray[i][2]; 
399			var el = $currentRings[elpos]
400			tempSortedArray.push(el);
401		}
402		$currentRings = [];
403		$currentRings = tempSortedArray;
404		
405		// Export the current rings now they are in correct order per current sort option
406		con.$currentRings = $currentRings;
407		
408		con.showUpdatedRings($currentRings);		
409	};
410	con.showUpdatedRings = function($currentRings) {
411		$("#ringGalleryRingsHolder").remove();
412		$("#ringGalleryPage .pagination ul").empty();
413		var $ringGalleryRingsHolder = $('<div id="ringGalleryRingsHolder"></div>');
414		$("#ringGalleryRings").append($ringGalleryRingsHolder);
415		
416		var len = $currentRings.length;
417		for (i = 0; i < len; i++) {			
418			var $currentEl = $();
419			$currentEl = $currentRings[i];			
420			$("#ringGalleryRingsHolder").append($currentEl);
421			if ( i % 9 !== 0 ) {
422				// Insert the 'Design your own ring' callout (features text and button) here. Same dimensions as rings.
423				$("#ringGalleryRingsHolder").append(con.$designYoursCalloutEl);
424			} 
425		}
426								
427		con.setLikeStatusForAllRings();
428		con.paginate();
429
430		$('.ringImg').on('click', function() {
431			var el = $(this);
432			con.showRingModal( el );
433		});
434	};
435	con.paginate = function() {
436		//window.setupPagination($("#ringGalleryPage .pagination"), $("#ringGalleryRingsHolder"), 10, con.galleryContentWidth);				
437	};
438	con.showRingModal = function( el ) {
439		
440			var $saveRing = el.closest('[data-control="savedRing"]');
441		
442			if( !$saveRing.hasClass('designYours') ) {
443				var $ringWallModal = $('#ring-wall-view-ring-modal');
444				var ringImgSrc = el.attr('src');
445				
446				// add meta data to ring in modal so the likeToggle code can use it as on parent page
447				var $detailRing = $ringWallModal.find('[data-control="savedRing"]');
448				$detailRing.attr("data-info", $saveRing.attr('data-info'));
449													
450				// Ensure like image is correctly highlighted with most recent count 
451				var currentLikeImgSrc = $saveRing.find('[data-control="like"]').first().attr("src");
452				$detailRing.find('[data-control="modalLike"]').first().attr("src", currentLikeImgSrc);
453				$detailRing.attr("data-liked", $saveRing.attr("data-liked"));				
454				$detailRing.find('.likeCount').first().text($saveRing.find('.likeCount').first().text());
455				
456				var data = JSON.parse($saveRing.attr('data-info'));
457				
458				switch( data.gender ) {
459					case "m":
460                        con.designYourRingGender = "Male";
461						$ringWallModal.find('.gender').addClass('male');
462						break;
463					case "f":
464                        con.designYourRingGender = "Female";
465						$ringWallModal.find('.gender').addClass('female');
466						break;
467					default:
468						break;
469				}
470		
471				$ringWallModal.find('.ringName').html(data.title);
472				$ringWallModal.find('.date').html(data.created);
473				$ringWallModal.find('.ringImg').attr('src', ringImgSrc);
474
475				var $button = $ringWallModal.find("#designThisRing");
476                con.designYourRingRedirect = $button.attr("linkroot") + JSON.parse($saveRing.attr("data-info")).id; 
477		
478				launchModal($ringWallModal, {show: true}, "ringWall/" + data.id);
479		}
480	};
481	// This is very redundant but with a week to browse mode launch safe albeit very ugly
482	con.ringGalleryLoginModalInit = function() {
483		if (!con.$loginGallerySaveLikeModalHead) {
484			// to avoid making an ajax cal if we switch back to login, cloning the login view now
485			con.$loginGallerySaveLikeModalHead = $('#login-to-save-liked-rings-modal').find('.modal-header').first().clone();
486			con.$loginGallerySaveLikeModalBody = $('#login-to-save-liked-rings-modal').find('.modal-body').first().clone();
487		}
488		
489		$('#login-to-save-liked-rings-modal').on('click', '.loginBtn', function(e) {
490			e.preventDefault();
491			con.standaloneLogin($('.loginBtn'), 'ringGallery');
492		});
493		
494		$('#login-to-save-liked-rings-modal').on('click', '#modalRegister', function(e) {
495			e.preventDefault();			
496			con.ringGalleryModalRegRequest();
497		});	
498		
499		$('#login-to-save-liked-rings-modal').on('click', '#likeRingFacebookLoginButton', function(e) {
500			console.log('fb login clicked from showLoginSaveRing');	
501			$.cookie("herffJonesPostFacebookLoginAction", "ringGallery", { expires: 999, path: '/' });	
502			$.cookie("herffJonesPostFacebookLoginAction-ringIdToSave", con.afterLoginRingIdToSave, { expires: 999, path: '/' });	
503			var url = con.relativePath + '/social/facebook/signin?sRedirect=' + window.location.href;
504			window.location = url;	
505		});			
506					
507	};
508	con.ringGalleryModalLoginRequest = function() {
509		$('#login-to-save-liked-rings-modal').empty();
510		$('#login-to-save-liked-rings-modal').append( (con.$loginGallerySaveLikeModalHead).clone() );
511		$('#login-to-save-liked-rings-modal').append( (con.$loginGallerySaveLikeModalBody).clone() );						
512		con.ringGalleryLoginModalInit();		
513	};
514	con.ringGalleryModalRegRequest = function() {		
515		var url = $("#loginRegHolder").attr("regURL");
516					
517		$.ajax({
518			url : url,
519			type : "GET",
520			success : function(data) {
521				$('#login-to-save-liked-rings-modal').html(data);
522				$("#login-to-save-liked-rings-modal").on('click', '#modalLogin', function() {
523					con.ringGalleryModalLoginRequest();
524				});
525				$("#login-to-save-liked-rings-modal").on("click", '.registerBtn', function(e) {
526					con.ringGallerySubmitRegisterForm(e);
527				});
528				
529			},
530			error: function( data ) {			
531				// TO DO: redirect to standalone login page
532			}
533		});			
534				
535	};	
536	con.ringGallerySubmitRegisterForm = function( e ) {
537		e.preventDefault();
538		
539		var _this = $("#login-to-save-liked-rings-modal #registerForm");
540		var form = _this.closest('form');
541		var url = con.relativePath + "/register";
542		var lName = $('#lName');
543		var fName = $('#fName');
544		
545		var email = form.find('.emailAddress').val();
546		var errors = con.validateEmail( email );
547		
548		if( fName.val() == "") {
549			errors += "<br/>Please provide a valid first name.";
550			fName.addClass('inputError');
551		}
552		
553		if( lName.val() == "") {
554			errors += "<br/>Please provide a valid last name.";
555			lName.addClass('inputError');
556		}
557		
558		if( errors !== null ) {
559			form.find('.errors').html( errors ).show();
560			form.find('.emailAddress').addClass('inputError');
561		} else {
562			form.find('.errors').html('').hide();
563			form.find('.inputError').removeClass('inputError');
564				
565			var formData = form.serialize();
566			var registerErrors = "";
567	
568			$.ajax({
569				url: url,
570				type: 'POST',
571				data: formData,
572				success: function( data ) {
573	
574					console.log( data );
575	
576					if( data.success === false ) {
577						
578						if( data.messages.password ) {
579							if(typeof data.messages.password == 'string') {
580								registerErrors = "Password: " + data.messages.password;
581							} else {
582								for(var i = 0;i<data.messages.password.length;i++ ) {
583									registerErrors += 'Password: ' + data.messages.password[i] + '<br />';
584								}
585							}
586						} else if( data.messages.confirmPassword ) {
587							registerErrors += data.messages.confirmPassword;
588						} else {
589							registerErrors += data.messages.global;
590						}
591						
592						form.find('.errors').html( registerErrors ).show();
593					} else {
594						$('#login-to-save-liked-rings-modal').modal('hide');
595						con.saveRingLikeToBackend(con.afterLoginRingIdToSave, con.afterLoginRingIdToSaveLiked);
596						con.updateHeaderLinksOnLogin();
597						
598					}
599				},
600				error: function( data ) {
601					console.log( data );
602				}
603			});
604		}
605	};
606};
607
608
609
610
611

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.