1function isNumber(n) { 2 return !isNaN(parseFloat(n)) && isFinite(n); 3} 4 5function debouncer(func, timeout) { 6 var timeoutID, 7 timeout = timeout || 200; 8 return function () { 9 var scope = this, 10 args = arguments; 11 clearTimeout(timeoutID); 12 timeoutID = setTimeout(function () { 13 func.apply(scope, Array.prototype.slice.call(args)); 14 }, timeout); 15 }; 16} 17 18var JSON;JSON||(JSON={}); 19(function(){function k(a){return a<10?"0"+a:a}function o(a){p.lastIndex=0;return p.test(a)?'"'+a.replace(p,function(a){var c=r[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function l(a,j){var c,d,h,m,g=e,f,b=j[a];b&&typeof b==="object"&&typeof b.toJSON==="function"&&(b=b.toJSON(a));typeof i==="function"&&(b=i.call(j,a,b));switch(typeof b){case "string":return o(b);case "number":return isFinite(b)?String(b):"null";case "boolean":case "null":return String(b);case "object":if(!b)return"null"; 20e+=n;f=[];if(Object.prototype.toString.apply(b)==="[object Array]"){m=b.length;for(c=0;c<m;c+=1)f[c]=l(c,b)||"null";h=f.length===0?"[]":e?"[\n"+e+f.join(",\n"+e)+"\n"+g+"]":"["+f.join(",")+"]";e=g;return h}if(i&&typeof i==="object"){m=i.length;for(c=0;c<m;c+=1)typeof i[c]==="string"&&(d=i[c],(h=l(d,b))&&f.push(o(d)+(e?": ":":")+h))}else for(d in b)Object.prototype.hasOwnProperty.call(b,d)&&(h=l(d,b))&&f.push(o(d)+(e?": ":":")+h);h=f.length===0?"{}":e?"{\n"+e+f.join(",\n"+e)+"\n"+g+"}":"{"+f.join(",")+ 21"}";e=g;return h}}if(typeof Date.prototype.toJSON!=="function")Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+k(this.getUTCMonth()+1)+"-"+k(this.getUTCDate())+"T"+k(this.getUTCHours())+":"+k(this.getUTCMinutes())+":"+k(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()};var q=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, 22p=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,e,n,r={"\u0008":"\\b","\t":"\\t","\n":"\\n","\u000c":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},i;if(typeof JSON.stringify!=="function")JSON.stringify=function(a,j,c){var d;n=e="";if(typeof c==="number")for(d=0;d<c;d+=1)n+=" ";
22else typeof c==="string"&&(n=c);if((i=j)&&typeof j!=="function"&&(typeof j!=="object"||typeof j.length!=="number"))throw Error("JSON.stringify");return l("", 23{"":a})};if(typeof JSON.parse!=="function")JSON.parse=function(a,e){function c(a,d){var g,f,b=a[d];if(b&&typeof b==="object")for(g in b)Object.prototype.hasOwnProperty.call(b,g)&&(f=c(b,g),f!==void 0?b[g]=f:delete b[g]);return e.call(a,d,b)}var d,a=String(a);q.lastIndex=0;q.test(a)&&(a=a.replace(q,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, 24"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return d=eval("("+a+")"),typeof e==="function"?c({"":d},""):d;throw new SyntaxError("JSON.parse");}})(); 25 26function loadModalManager() { 27 28 var modalManagerObjectOptions = { 29 "token": token, 30 "tokenDomain": tokenDomain, 31 "userSignedIn": userSignedIn, 32 "userSignInUrl": signInUrl, 33 "siteName": siteName, 34 "upsellMsgShown": function (featureId) { 35 if (typeof trackUpsellPageView !== "function") return; 36 37 trackUpsellPageView(featureId); 38 }, 39 "isMobile": isMobile() 40 }; 41 42 wfModalManager = new WFModalManager(modalManagerObjectOptions); 43 44 $("body").bind("profile_clicked", function (event, profileId) { 45 if (profileId != undefined && profileId > 0) { 46 window.location = "/profile/" + profileId; 47 } else { 48 window.location = "/profile"; 49 } 50 }); 51} 52 53function loadProfileManager() { 54 // Click event for add to profile 55 $(document).on("click", ".createProfileShow", function () { 56 if (wfModalManager.doesUserHaveAccessToFeature(WFProducts.ProfileFeature)) { 57 if (wfModalManager != null) { 58 wfModalManager.addProfile(); 59 } 60 } 61 62 return false; 63 }); 64 65 $("body").bind("profiles_loaded", function (event) { 66 // TODO: Update the profile list in the header 67 updateProfileMenuList(); 68 69 // Handle fav stars 70 switch (currentPage) { 71 case "Favorites": 72 if (wfProfileManager.isProfileFavorited(currentProfileID)) { 73 $("#profileFavButton").removeClass("favorite").addClass("favorite-yellow"); 74 } else { 75 $("#profileFavButton").removeClass("favorite-yellow").addClass("favorite"); 76 } 77 break; 78 case "ManageFavorites": 79 updateProfileManagerList(); 80 break; 81 } 82 83 }); 84 85 // Create the profile manager object. Singleton. One instance per page 86 wfProfileManager = new WFProfileManager({ "activeProfileId": defaultProfileId, "token": token, "cad": showAds, "baseURL": apiurl, "userSignedIn": userSignedIn, "tokenDomain": tokenDomain }); 87 wfProfileManager.init(); 88} 89 90function updateProfileMenuList() { 91 // UL element in the header 92 var profileList = $(".profileList-profiles"); 93 var profiles = wfProfileManager.getProfiles(); 94 var profileClass = "profile-item"; 95 96 // Clear the list 97 $(".profile-item", profileList).remove(); 98 99 for (var x = 0; x < profiles.length; x++) { 100 var liClass = profiles[x].master == "true" ? "immuteable rounded-corners " + profileClass : "rounded-corners " + profileClass; 101 var profileLink = "/profile"; 102 if (profiles[x].profile_id > 0) { 103 profileLink += "/" + profiles[x].profile_id; 104 } 105 profileList.append("<li class='" + liClass + "' id='" + profiles[x].profile_id + "'><a href='" + profileLink + "' class='name'>" + wfProfileManager.getProfileDisplayName(profiles[x].name) + "</a></li>"); 106 } 107 108 // Pro Forecasts 109 profileList.append("<li class='" + profileClass + "'><a href='/proforecasts'>Pro Forecasts</a></li>"); 110 profileList.append("<li class='" + profileClass + "'><a href='/storm'>StormTrack</a></li>"); 111 112 if (siteName == "iWindsurf") {
113 profileList.append("<li class='" + profileClass + "'><a href='http://www.iwindsurf.com/forums.iws'>iWindsurf Forums</a></li>"); 114 profileList.append("<li class='" + profileClass + "'><a href='http://www.iwindsurf.com/classifieds.iws'>iWindsurf Classifieds</a></li>"); 115 } 116 117 // Wind Meters 118 profileList.append("<li class='" + profileClass + "'><a href='http://weatherflow.com/windmeter/?utm_source=" + siteName + "&utm_medium=Web&utm_campaign=MyWeather-Menu' class='js-menu-link' target='_blank'>Shop: Wind Meters</a></li>"); 119 120 if (primaryActivity == "Kite" && (siteName == "iKitesurf" || siteName == "WindAlert")) { 121 profileList.append("<li class='" + profileClass + "'><a href='https://www.amazon.com/iKitesurf-Rash-Guard-Lycra-Medium/dp/B01JGRFHGE/' class='js-menu-link' target='_blank'>Shop: iKitesurf Rash Guard</a></li>"); 122 profileList.append("<li class='" + profileClass + "'><a href='http://www.zazzle.com/ikitesurf_merch/products' class='js-menu-link' target='_blank'>Shop: iKitesurf Apparel</a></li>"); 123 profileList.append("<li class='" + profileClass + "'><a href='http://c.ikitesurf.com/schools' class='js-menu-link'>iKitesurf Schools</a></li>"); 124 } 125 126 // Default items appended to the end of the sub menu 127 profileList.append("<li class='" + profileClass + "'><a href='#' class='js-menu-link' onclick='doAddProfile()'>Create Favorites Profile</a></li>"); 128 profileList.append("<li class='" + profileClass + "'><a href='/en-us/Favorites/ManageFavorites.aspx' class='js-menu-link'>Manage Favorites Profiles</a></li>"); 129 130} 131 132function showLearnMore() { 133 window.location = learnMoreUrl + "?ret=" + escape(location.pathname + location.search + location.hash); 134} 135 136function doAddProfile() { 137 if (wfModalManager.doesUserHaveAccessToFeature(WFProducts.ProfileFeature)) { 138 if (wfModalManager != null) { 139 wfModalManager.addProfile(); 140 } 141 } 142 143 return false; 144} 145// The "Map" event is load-only: it fires once per page load, on the first 146// view_changed that resolves to a valid product label (the initial map load). 147// Later view_changed fires (layer selections, fx model-run / param / animation 148// tweaks, custom-layer changes, hash changes) are intentionally not reported. 149let mapEventFired = false; 150 151function trackViewEvent(viewId, zoomLevel) { 152 if (mapEventFired) { 153 return; 154 } 155 156 const label = getViewAnalyticsId(viewId); 157 const zoom = zoomLevel || 'N/A'; 158 159 if (typeof label != 'undefined' && label != null && label != '') { 160 mapEventFired = true; 161 162 gtag('event', 'Map', { 163 Regional_Product: label, 164 Zoom: zoom, 165 }); 166 } 167} 168 169function trackSpotListClickEvent(eventName, spot, upgradeAvailable) { 170 const spotId = spot[0]; 171 const spotName = spot[1]; 172 let formattedSpotName = `${spotName}-${spotId}`; 173 174 if (!spotName || spotName === '') { 175 formattedSpotName = `${spot[5]},${spot[6]}-${spotId}`; 176 } 177 178 gtag("event", eventName, { 179 Spot_Name: `${formattedSpotName}`, 180 }); 181} 182 183function getViewAnalyticsId(viewId) { 184 var label = viewId; 185 186 switch (viewId) { 187 case "obs": 188 label = "custom-obs"; 189 break; 190 case "fx": 191 label = "custom-fx"; 192 break; 193 default: 194 for (var x = 0; x < WFProducts.regionalProducts.length; x++) { 195 var product = WFProducts.regionalProducts[x]; 196 197 if (product.regional_product_id == viewId) { 198 label = product.analytics_key; 199 break; 200 } else { 201 label = "Custom"; 202 } 203 } 204 break; 205 } 206 207 return label; 208} 209 210/* 211 * jQuery MultiSelect UI Widget 1.13 212 * Copyright (c) 2012 Eric Hynds 213 * 214 * http://www.erichynds.com/jquery/jquery-ui-multiselect-widget/ 215 * 216 * Depends: 217 * - jQuery 1.4.2+ 218 * - jQuery UI 1.8 widget factory 219 * 220 * Optional: 221 * - jQuery UI effects 222 * - jQuery UI position utility 223 * 224 * Dual licensed under the MIT and GPL licenses: 225 * http://www.opensource.org/licenses/mit-license.php 226 * http://www.gnu.org/licenses/gpl.html 227 * 228 */ 229(function(d){var k=0;d.widget("ech.multiselect",{options:{header:!0,height:175,minWidth:225,classes:"",checkAllText:"Check all",uncheckAllText:"Uncheck all",noneSelectedText:"Select options",selectedText:"# selected",selectedList:0,show:null,hide:null,autoOpen:!1,multiple:!0,position:{}},_create:function(){var a=this.element.hide(),b=this.options;this.speed=d.fx.speeds._default;this._isOpen=!1;a=(this.button=d('<button type="button"><span class="ui-icon ui-icon-triangle-2-n-s"></span></button>')).addClass("ui-multiselect ui-widget ui-state-default ui-corner-all").addClass(b.classes).attr({title:a.attr("title"),"aria-haspopup":!0,tabIndex:a.attr("tabIndex")}).insertAfter(a);
229(this.buttonlabel=d("<span />")).html(b.noneSelectedText).appendTo(a);var a=(this.menu=d("<div />")).addClass("ui-multiselect-menu ui-widget ui-widget-content ui-corner-all").addClass(b.classes).appendTo(document.body),c=(this.header=d("<div />")).addClass("ui-widget-header ui-corner-all ui-multiselect-header ui-helper-clearfix").appendTo(a);(this.headerLinkContainer=d("<ul />")).addClass("ui-helper-reset").html(function(){return!0===b.header?'<li><a class="ui-multiselect-all" href="#"><span class="ui-icon ui-icon-check"></span><span>'+b.checkAllText+'</span></a></li><li><a class="ui-multiselect-none" href="#"><span class="ui-icon ui-icon-closethick"></span><span>'+b.uncheckAllText+"</span></a></li>":"string"===typeof b.header?"<li>"+b.header+"</li>":""}).append('<li class="ui-multiselect-close"><a href="#" class="ui-multiselect-close"><span class="ui-icon ui-icon-circle-close"></span></a></li>').appendTo(c);(this.checkboxContainer=d("<ul />")).addClass("ui-multiselect-checkboxes ui-helper-reset").appendTo(a);this._bindEvents();this.refresh(!0);b.multiple||a.addClass("ui-multiselect-single")},_init:function(){!1===this.options.header&&this.header.hide();this.options.multiple||this.headerLinkContainer.find(".ui-multiselect-all, .ui-multiselect-none").hide();this.options.autoOpen&&this.open();this.element.is(":disabled")&&this.disable()},refresh:function(a){var b=this.element,c=this.options,f=this.menu,h=this.checkboxContainer,g=[],e="",i=b.attr("id")||k++;b.find("option").each(function(b){d(this);var a=this.parentNode,f=this.innerHTML,h=this.title,k=this.value,b="ui-multiselect-"+(this.id||i+"-option-"+b),l=this.disabled,n=this.selected,m=["ui-corner-all"],o=(l?"ui-multiselect-disabled ":" ")+this.className,j;"OPTGROUP"===a.tagName&&(j=a.getAttribute("label"),-1===d.inArray(j,g)&&(e+='<li class="ui-multiselect-optgroup-label '+a.className+'"><a href="#">'+j+"</a></li>",g.push(j)));l&&m.push("ui-state-disabled");n&&!c.multiple&&m.push("ui-state-active");e+='<li class="'+o+'">';e+='<label for="'+b+'" title="'+h+'" class="'+m.join(" ")+'">';e+='<input id="'+b+'" name="multiselect_'+i+'" type="'+(c.multiple?"checkbox":"radio")+'" value="'+k+'" title="'+f+'"';n&&(e+=' checked="checked"',e+=' aria-selected="true"');l&&(e+=' disabled="disabled"',e+=' aria-disabled="true"');e+=" /><span>"+f+"</span></label></li>"});h.html(e);this.labels=f.find("label");this.inputs=this.labels.children("input");this._setButtonWidth();this._setMenuWidth();this.button[0].defaultValue=this.update();a||this._trigger("refresh")},update:function(){var a=this.options,b=this.inputs,c=b.filter(":checked"),f=c.length,a=0===f?a.noneSelectedText:d.isFunction(a.selectedText)?a.selectedText.call(this,f,b.length,c.get()):/\d/.test(a.selectedList)&&0<a.selectedList&&f<=a.selectedList?c.map(function(){return d(this).next().html()}).get().join(", "):a.selectedText.replace("#",f).replace("#",b.length);this.buttonlabel.html(a);return a},_bindEvents:function(){function a(){b[b._isOpen? "close":"open"]();return!1}var b=this,c=this.button;c.find("span").bind("click.multiselect",a);c.bind({click:a,keypress:function(a){switch(a.which){case 27:case 38:case 37:b.close();break;case 39:case 40:b.open()}},mouseenter:function(){c.hasClass("ui-state-disabled")||d(this).addClass("ui-state-hover")},mouseleave:function(){d(this).removeClass("ui-state-hover")},focus:function(){c.hasClass("ui-state-disabled")||d(this).addClass("ui-state-focus")},blur:function(){d(this).removeClass("ui-state-focus")}});this.header.delegate("a","click.multiselect",function(a){if(d(this).hasClass("ui-multiselect-close"))b.close();else b[d(this).hasClass("ui-multiselect-all")?"checkAll":"uncheckAll"]();a.preventDefault()});this.menu.delegate("li.ui-multiselect-optgroup-label a","click.multiselect",function(a){a.preventDefault();var c=d(this),g=c.parent().nextUntil("li.ui-multiselect-optgroup-label").find("input:visible:not(:disabled)"),e=g.get(),c=c.parent().text();!1!==b._trigger("beforeoptgrouptoggle",a,{inputs:e,label:c})&&(b._toggleChecked(g.filter(":checked").length!==g.length,g),b._trigger("optgrouptoggle",a,{inputs:e,label:c,checked:e[0].checked}))}).delegate("label","mouseenter.multiselect",function(){d(this).hasClass("ui-state-disabled")||(b.labels.removeClass("ui-state-hover"),d(this).addClass("ui-state-hover").find("input").focus())}).delegate("label","keydown.multiselect",function(a){a.preventDefault();switch(a.which){case 9:case 27:b.close();break;case 38:case 40:case 37:case 39:b._traverse(a.which,this);break;case 13:d(this).find("input")[0].click()}}).delegate('input[type="checkbox"], input[type="radio"]',"click.multiselect",function(a){var c=d(this),g=this.value,e=this.checked,i=b.element.find("option");this.disabled||!1===b._trigger("click",a,{value:g,text:this.title,checked:e})?a.preventDefault():(c.focus(),c.attr("aria-selected",e),i.each(function(){this.value===g?this.selected=e:b.options.multiple||(this.selected=!1)}),b.options.multiple||(b.labels.removeClass("ui-state-active"),c.closest("label").toggleClass("ui-state-active",e),b.close()),b.element.trigger("change"),setTimeout(d.proxy(b.update,b),10))});d(document).bind("mousedown.multiselect",function(a){b._isOpen&&(!d.contains(b.menu[0],a.target)&&!d.contains(b.button[0],a.target)&&a.target!==b.button[0])&&b.close()});d(this.element[0].form).bind("reset.multiselect",function(){setTimeout(d.proxy(b.refresh,b),10)})},_setButtonWidth:function(){var a=this.element.outerWidth(),b=this.options;/\d/.test(b.minWidth)&&a<b.minWidth&&(a=b.minWidth);this.button.width(a)},_setMenuWidth:function(){var a=this.menu,b=this.button.outerWidth()-parseInt(a.css("padding-left"),10)-parseInt(a.css("padding-right"),10)-parseInt(a.css("border-right-width"),10)-parseInt(a.css("border-left-width"),10);a.width(b||this.button.outerWidth())},_traverse:function(a,b){var c=d(b),f=38===a||37===a,c=c.parent()[f?"prevAll":"nextAll"]("li:not(.ui-multiselect-disabled, .ui-multiselect-optgroup-label)")[f?"last":"first"]();c.length?c.find("label").trigger("mouseover"):(c=this.menu.find("ul").last(),this.menu.find("label")[f? "last":"first"]().trigger("mouseover"),c.scrollTop(f?c.height():0))},_toggleState:function(a,b){return function(){this.disabled||(this[a]=b);b?this.setAttribute("aria-selected",!0):this.removeAttribute("aria-selected")}},_toggleChecked:function(a,b){var c=b&&b.length?b:this.inputs,f=this;c.each(this._toggleState("checked",a));c.eq(0).focus();this.update();var h=c.map(function(){return this.value}).get();this.element.find("option").each(function(){!this.disabled&&-1<d.inArray(this.value,h)&&f._toggleState("selected",a).call(this)});c.length&&this.element.trigger("change")},_toggleDisabled:function(a){this.button.attr({disabled:a,"aria-disabled":a})[a?"addClass":"removeClass"]("ui-state-disabled");
229var b=this.menu.find("input"),b=a?b.filter(":enabled").data("ech-multiselect-disabled",!0):b.filter(function(){return!0===d.data(this,"ech-multiselect-disabled")}).removeData("ech-multiselect-disabled");b.attr({disabled:a,"arial-disabled":a}).parent()[a?"addClass":"removeClass"]("ui-state-disabled");this.element.attr({disabled:a,"aria-disabled":a})},open:function(){var a=this.button,b=this.menu,c=this.speed,f=this.options,h=[];if(!(!1===this._trigger("beforeopen")||a.hasClass("ui-state-disabled")||this._isOpen)){var g=b.find("ul").last(),e=f.show,i=a.offset();d.isArray(f.show)&&(e=f.show[0],c=f.show[1]||this.speed);e&&(h=[e,c]);g.scrollTop(0).height(f.height);d.ui.position&&!d.isEmptyObject(f.position)?(f.position.of=f.position.of||a,b.show().position(f.position).hide()):b.css({top:i.top+a.outerHeight(),left:i.left});d.fn.show.apply(b,h);this.labels.eq(0).trigger("mouseover").trigger("mouseenter").find("input").trigger("focus");a.addClass("ui-state-active");this._isOpen=!0;this._trigger("open")}},close:function(){if(!1!==this._trigger("beforeclose")){var a=this.options,b=a.hide,c=this.speed,f=[];d.isArray(a.hide)&&(b=a.hide[0],c=a.hide[1]||this.speed);b&&(f=[b,c]);d.fn.hide.apply(this.menu,f);this.button.removeClass("ui-state-active").trigger("blur").trigger("mouseleave");this._isOpen=!1;this._trigger("close")}},enable:function(){this._toggleDisabled(!1)},disable:function(){this._toggleDisabled(!0)},checkAll:function(){this._toggleChecked(!0);this._trigger("checkAll")},uncheckAll:function(){this._toggleChecked(!1);this._trigger("uncheckAll")},getChecked:function(){return this.menu.find("input").filter(":checked")},destroy:function(){d.Widget.prototype.destroy.call(this);this.button.remove();this.menu.remove();this.element.show();return this},isOpen:function(){return this._isOpen},widget:function(){return this.menu},getButton:function(){return this.button},_setOption:function(a,b){var c=this.menu;switch(a){case "header":c.find("div.ui-multiselect-header")[b?"show":"hide"]();break;case "checkAllText":c.find("a.ui-multiselect-all span").eq(-1).text(b);break;case "uncheckAllText":c.find("a.ui-multiselect-none span").eq(-1).text(b);break;case "height":c.find("ul").last().height(parseInt(b,10));break;case "minWidth":this.options[a]=parseInt(b,10);this._setButtonWidth();this._setMenuWidth();break;case "selectedText":case "selectedList":case "noneSelectedText":this.options[a]=b;this.update();break;case "classes":c.add(this.button).removeClass(this.options.classes).addClass(b);break;case "multiple":c.toggleClass("ui-multiselect-single",!b),this.options.multiple=b,this.element[0].multiple=b,this.refresh()}d.Widget.prototype._setOption.apply(this,arguments)}})})(jQuery); 230 231function WFMessage(targetDiv, messages, tokenDomain, settings) { 232 this.targetDiv = targetDiv; 233 this.messages = JSON.parse(messages); 234 this.cookiePrefix = "msg-"; 235 this.messageIdx = -1; 236 this.tokenDomain = tokenDomain; 237 this.defaultSettings = { 238 messageDismissed: null 239 }; 240 241 this.settings = $.extend(true, {}, this.default_settings, settings); 242 243 if (this.messages) { 244 // Show the message to the user 245 this.displayMessage(); 246 } 247} 248 249WFMessage.prototype.displayMessage = function () { 250 for (var i = 0; i < this.messages.length; i++) { 251 if (!this.messageDismissed(this.messages[i].Id)) { 252 // Display the message 253 this.messageIdx = i; 254 this.createMessageBox(this.messages[i].Message); 255 break; 256 } 257 } 258} 259 260WFMessage.prototype.messageDismissed = function (msgId) { 261 if ($.cookie(this.cookiePrefix + msgId) != null) { 262 return true; 263 } else { 264 return false; 265 } 266} 267 268WFMessage.prototype.dismissMessage = function () { 269 if (this.messageIdx > -1 && this.messageIdx < this.messages.length) { 270 var message = this.messages[this.messageIdx]; 271 var expiration = 9999; 272 273 if (message.Expire_Time != null) { 274 var dt = message.Expire_Time; 275 276 expiration = new Date( 277 parseInt(dt.slice(0, 4), 10), 278 parseInt(dt.slice(5, 7), 10) - 1, 279 parseInt(dt.slice(8, 10), 10), 280 parseInt(dt.slice(11, 13), 10), 281 parseInt(dt.slice(14, 16), 10), 282 parseInt(dt.slice(17, 19), 10), 283 0 284 ); 285 } 286 287 // Set the cookie 288 $.cookie(this.cookiePrefix + message.Id, new Date().toUTCString(), { expires: expiration, path: "/", domain: this.tokenDomain }); 289 290 // Hide the msg 291 $(this.targetDiv).hide(); 292 293 if (typeof this.settings.messageDismissed === "function") { 294 this.settings.messageDismissed(); 295 } 296 } 297} 298 299WFMessage.prototype.createMessageBox = function (message) { 300 var self = this; 301 302 $(this.targetDiv).append("<div class='wfMessage'><a href='#' class='wfMessage-close' title='Dismiss message'></a><p>" + message + "</p></div>"); 303 304 // Close event handler 305 $(document).on("click", ".wfMessage-close", function () { 306 self.dismissMessage(); 307 return false;
308 }); 309} 310function WFSpot() { 311 312} 313 314WFSpot.spot_id = 0; 315WFSpot.spot_name = 1; 316WFSpot.type = 2; 317WFSpot.spot_status = 3; 318WFSpot.distance = 4; 319WFSpot.lat = 5; 320WFSpot.lon = 6; 321WFSpot.provider = 7; 322WFSpot.region_id = 8; 323WFSpot.upgrade_available = 9; 324WFSpot.is_favorite = 10; 325WFSpot.fav_sort_order = 11; 326WFSpot.wind_alert_exists = 12; 327WFSpot.wind_alert_active = 13; 328WFSpot.spot_rank = 14; 329WFSpot.status_message = 15; 330WFSpot.spot_message = 16; 331WFSpot.source_message = 17; 332WFSpot.timestamp = 18; 333WFSpot.avg = 19; 334WFSpot.lull = 20; 335WFSpot.gust = 21; 336WFSpot.dir = 22; 337WFSpot.dir_text = 23; 338WFSpot.atemp = 24; 339WFSpot.wtemp = 25; 340WFSpot.forecast = 26; 341WFSpot.wave_height = 27; 342WFSpot.wave_period = 28; 343WFSpot.current_time_local = 29; 344WFSpot.pres = 30; 345WFSpot.fav_spot_id = 31; 346WFSpot.wind_desc = 32; 347 348WFSpot.station_is_down = 4; 349 350WFSpot.record_length = 33; 351 352/****************************************************************************** 353* Converts structure returned from getSpotDetailSetBy[x] to a the 354* format returned by getSpotSetBy[x] 355******************************************************************************/ 356WFSpot.prototype.convert = function (spotDetailSet, frameIdx) { 357 var station = spotDetailSet.stations[0]; 358 var frame = station.data_values[frameIdx]; 359 var spot = new Array(WFSpot.record_length); 360 361 spot[WFSpot.spot_id] = spotDetailSet.spot_id; 362 spot[WFSpot.spot_name] = spotDetailSet.name; 363 spot[WFSpot.type] = station.type; 364 spot[WFSpot.spot_status] = station.status_id; 365 spot[WFSpot.distance] = null; 366 spot[WFSpot.lat] = spotDetailSet.lat; 367 spot[WFSpot.lon] = spotDetailSet.lon; 368 spot[WFSpot.provider] = station.provider; 369 spot[WFSpot.region_id] = null; 370 spot[WFSpot.upgrade_available] = spotDetailSet.upgrade_available; 371 spot[WFSpot.is_favorite] = null; 372 spot[WFSpot.fav_sort_order] = null; 373 spot[WFSpot.wind_alert_exists] = null; 374 spot[WFSpot.wind_alert_active] = null; 375 spot[WFSpot.spot_rank] = null; 376 spot[WFSpot.status_message] = null; 377 spot[WFSpot.spot_message] = null; 378 spot[WFSpot.source_message] = null; 379 spot[WFSpot.timestamp] = frame[WFSpotDetail.timestamp]; 380 spot[WFSpot.avg] = frame[WFSpotDetail.avg]; 381 spot[WFSpot.lull] = frame[WFSpotDetail.lull]; 382 spot[WFSpot.gust] = frame[WFSpotDetail.gust]; 383 spot[WFSpot.dir] = frame[WFSpotDetail.dir]; 384 spot[WFSpot.dir_text] = frame[WFSpotDetail.dir_text]; 385 spot[WFSpot.atemp] = frame[WFSpotDetail.atemp]; 386 spot[WFSpot.wtemp] = frame[WFSpotDetail.wtemp]; 387 spot[WFSpot.forecast] = null; 388 spot[WFSpot.wave_height] = frame[WFSpotDetail.wave_height]; 389 spot[WFSpot.wave_period] = frame[WFSpotDetail.wave_period]; 390 spot[WFSpot.current_time_local] = spotDetailSet.current_time_local; 391 spot[WFSpot.pres] = frame[WFSpotDetail.pres]; 392 spot[WFSpot.fav_spot_id] = spotDetailSet.fav_spot_id; 393 spot[WFSpot.wind_desc] = frame[WFSpotDetail.wind_desc]; 394 395 return spot; 396 397} 398///////////////////////////////////////////////////////////////////////////////////////// 399///////////////////////////////////////////////////////////////////////////////////////// 400// WFModalManager 401// - Used to create single and multi-step modals 402// 403// functions Modals 404// ---------------------------------------------------------------------- --------------------------------------------- 405// addContainerToProfile(containerName, containerTypeId, containerOptions) nameModal,selectProfileModal,addProfileModal 406// addArbitrarySpotToProfile(lat, lon, spotName) nameModal,selectProfileModal,addProfileModal 407// addSpotToProfile(spotId, spotName) selectProfileModal,addProfileModal 408// removeContainerFromProfile(containerId, targetDivId) 409// 410// Modals 411// ----------------- 412// nameModal 413// selectProfileModal 414// addProfileModal 415// alertModal 416// membershipModal 417// manageSettingsModal 418// downloadDataModal 419// 420// - Uses WFProfileManager - must already be in scope and initialized. 421// - All default_args in the constructor can be set by the client and passed using options when creating 422// - Ability to forward to a signin page if user is not signed in and url is provided in constructor options
423///////////////////////////////////////////////////////////////////////////////////////// 424///////////////////////////////////////////////////////////////////////////////////////// 425 426///////////////////////////////////////////////////////////////////////////////////////// 427///////////////////////////////////////////////////////////////////////////////////////// 428// WFModalManager - Constructor 429///////////////////////////////////////////////////////////////////////////////////////// 430///////////////////////////////////////////////////////////////////////////////////////// 431function WFModalManager(options) { 432 this.default_args = { 433 "userSignInUrl": "", // redirect url for signin WindAlert=/en-us/MyAccount/SignIn.aspx 434 "learnMoreUrl": typeof learnMoreUrl !== "undefined" ? learnMoreUrl : "/en-us/Services/SignUp.aspx", 435 "userSignedIn": "false", // if userSignedIn == "false" and userSignInUrl.length > 0 --> redirect to so userSignInUrl 436 "token": "", 437 "tokenDomain": null, 438 "baseURL": "https://api.weatherflow.com/wxengine/rest", // Weather Engine baseurl - client might want to change to staging 439 "siteName": "WindAlert", 440 "upsellMsgShown": null, 441 "isMobile": false 442 }; 443 444 445 this.options = options; 446 this.nameField = ""; 447 this.containerId = ""; 448 this.containerTypeIdField = ""; 449 this.optionsField = ""; 450 this.profileNameField = ""; 451 this.currentActivity = ""; // addcontainertoprofile, addspottoprofile, addarbitraryspottoprofile 452 this.spotId; 453 this.spotType; // 1,100,101 454 this.spotLat; 455 this.spotLon; 456 this.favSpotId; 457 this.reloadPageOnClose = false; // calls location.reload() on modal close if true 458 this.profileId; 459 460 this.memberLevel = -1; 461 this.showAds = true; 462 this.showAdsToggle = false; 463 this.defaultAdsToggleState = 1; 464 this.canAdsToggle = false; 465 this.trialEndDate = ""; 466 467 // download data member vars 468 469 this.downloadDataUnitsWind = "mph"; 470 this.downloadDataUnitsTemp = "F"; 471 this.downloadDataStartDateStr = ""; 472 this.downloadDataEndDateStr = ""; 473 this.downloadDataSpotId = 0; 474 this.downloadDataFormat = "csv"; 475 476 477 // set options - use default_args if not passed in options var 478 for (var index in this.default_args) { 479 if (typeof this.options[index] == "undefined") { 480 this.options[index] = this.default_args[index]; 481 } 482 } 483 484 this.scrollTop = null; 485 this.openModalId = null; 486 this.nameModalId = "wfmodal-name-item"; 487 this.selectProfileModalId = "wfmodal-select-profile"; 488 this.alertModalId = "wfmodal-alert"; 489 this.addProfileModalId = "wfmodal-add-profile"; 490 this.toggleAdsModalId = "wfmodal-ad-toggle"; 491 this.loadingModalId = "wfmodal-loading"; 492 this.membershipModalId = "wfmodal-membership"; 493 this.downloadDataModalId = "wfmodal-download-data"; 494 this.replicateProfileModalId = "wfmodal-replicate-profile"; 495 this.renameProfileModalId = "wfmodal-rename-profile"; 496 497 /////////////////////////////////////////////////////////////////////// 498 // Add each container to the DOM and define as a modal 499 ////////////////////////////////////////////////////////////////////// 500 // Add Container to Profile - Step 1 - nameItem Modal 501 $("body").append(this.createNameItemModal()); 502 this.nameModal = $("#" + this.nameModalId); 503 504 // Add Container to Profile - Step 2 - Select Profiles 505 $("body").append(this.createSelectProfileModal()); 506 this.selectProfileModal = $("#" + this.selectProfileModalId); 507 508 // Add Profile 509 $("body").append(this.createAddProfileModal()); 510 this.addProfileModal = $("#" + this.addProfileModalId); 511 512 // Rename Profile 513 $("body").append(this.createRenameProfileModal()); 514 this.renameProfileModal = $("#" + this.renameProfileModalId); 515 516 // Alert Modal 517 $("body").append(this.createAlertModal()); 518 this.alertModal = $("#" + this.alertModalId); 519 520 // Membership Modal 521 $("body").append(this.createMembershipModal()); 522 this.membershipModal = $("#" + this.membershipModalId); 523 524 // Download Data Modal 525 $("body").append(this.createDownloadDataModal()); 526 this.downloadDataModal = $("#" + this.downloadDataModalId); 527 528 // Loading Modal 529 $("body").append(this.createLoadingModal()); 530 this.loadingModal = $("#" + this.loadingModalId); 531 532 // Replicate Profile 533 $("body").append(this.createReplicateProfileModal()); 534 this.replicateProfileModal = $("#" + this.replicateProfileModalId); 535 536 // Info Window 537 this.createInfoWindow(); 538 539 this._attachEventHandlers(); 540 541 // set user member vars 542 // default values 543 // ------------------------------ 544 // this.member_level = -1; 545 // this.show_ads = true; 546 // this.show_ads_toggle = false;
547 // this.can_ads_toggle = false; 548 // this.default_ads_toggle_state = 1; 549 // this.trial_end_date = ""; 550 551 552 // option 1 - check to see if already in scope (ie: set by server side) 553 if (typeof memberLevel != "undefined" && typeof showAdsToggle != "undefined" && typeof canToggleAds != "undefined" && typeof showAds != "undefined" && typeof defaultAdsToggleState != "undefined") { 554 this.memberLevel = memberLevel; 555 this.defaultAdsToggleState = defaultAdsToggleState; 556 557 if (showAds == "false") { 558 this.showAds = false; 559 } 560 if (showAdsToggle == "true") { 561 this.showAdsToggle = true; 562 } 563 if (canToggleAds == "true") { 564 this.canAdsToggle = true; 565 } 566 } 567 else { 568 // option 2 - use api checkToken 569 var url = this.options.baseURL + "/session/checkToken?callback=?"; 570 var urldata = new Object(); 571 urldata.wf_token = this.options.token;; 572 573 var myself = this; 574 this.jqRequest = $.getJSON(url, urldata, function (data, textStatus, jqXHR) { 575 if (data.status.status_code == 0) { 576 // success 577 myself.memberLevel = data.wf_user.member_level; 578 myself.defaultAdsToggleState = data.wf_user.default_ads_toggle_state; 579 myself.trialEndDate = data.wf_user.trial_end_date; 580 581 if (data.wf_user.show_ads == "false") { 582 myself.showAds = false; 583 } 584 if (data.wf_user.show_ads_toggle == "true") { 585 myself.showAdsToggle = true; 586 } 587 if (data.wf_user.can_ads_toggle == "true") { 588 myself.canAdsToggle = true; 589 } 590 } 591 else { 592 // fail 593 } 594 }, "json"); 595 } 596} 597 598 599////////////////////////////////////////////////////////////////////////////////////////////////////////// 600////////////////////////////////////////////////////////////////////////////////////////////////////////// 601////////////////////////////////////////////////////////////////////////////////////////////////////////// 602// Event Listeners 603////////////////////////////////////////////////////////////////////////////////////////////////////////// 604////////////////////////////////////////////////////////////////////////////////////////////////////////// 605////////////////////////////////////////////////////////////////////////////////////////////////////////// 606 607// listen for profiles loaded and change the profile list 608$("body").bind("profiles_loaded", function (event) { 609 $("#wfmodal-profile-list").empty(); 610 $("#wfmodal-profile-list").append(wfModalManager.createSelectProfileList()); 611}); 612 613$(document).on("click", "a.profileName", function () { 614 var profileId = $(this).attr("pid"); 615 616 $("body").trigger("profile_clicked", profileId); 617 618 return false; 619}); 620 621 622////////////////////////////////////////////////////////////////////////////////////////////////////////// 623////////////////////////////////////////////////////////////////////////////////////////////////////////// 624////////////////////////////////////////////////////////////////////////////////////////////////////////// 625// Controllers 626////////////////////////////////////////////////////////////////////////////////////////////////////////// 627////////////////////////////////////////////////////////////////////////////////////////////////////////// 628////////////////////////////////////////////////////////////////////////////////////////////////////////// 629 630////////////////////////////////////////////////////////////////////////////////////////////////////////// 631// General Entry Controller for a Spot 632// - spot is defined in WFSpot.js 633////////////////////////////////////////////////////////////////////////////////////////////////////////// 634WFModalManager.prototype.addRemoveSpot = function (spot) { 635 var spotId = spot[WFSpot.spot_id]; 636 var favSpotId = spot[WFSpot.fav_spot_id]; 637 var spotType = spot[WFSpot.type]; 638 if (spot[WFSpot.type] == 101) { 639 var spotName = "Nowcast Spot (" + spot[WFSpot.lat].toFixed(2) + ", " + spot[WFSpot.lon].toFixed(2) + ")"; 640 } else { 641 var spotName = spot[WFSpot.spot_name]; 642 } 643 var lat = spot[WFSpot.lat]; 644 var lon = spot[WFSpot.lon]; 645 646 if (typeof spotId != "undefined" && spotId > 0) { 647 // type 1 or 100 spot with a spot_id 648 this.addSpotToProfile(spotId, spotName, spotType); 649 } 650 else if (typeof lat != "undefined" && typeof lon != "undefined") { 651 // arbitrary spot, might have favSpotId and name but those will fall out later 652 this.addArbitrarySpotToProfile(lat, lon, spotName, favSpotId); 653 } 654} 655 656 657//////////////////////////////////////////////////////////////////////////////////////////////////////////
658// addContainerToProfile Controllers 659////////////////////////////////////////////////////////////////////////////////////////////////////////// 660// Add Container to Profile - Step 1 661WFModalManager.prototype.addContainerToProfile = function (containerName, containerTypeId, containerOptions) { 662 663 // display step 1 modal 664 this.currentActivity = "addcontainertoprofile"; 665 this.nameField = containerName; 666 this.containerTypeIdField = containerTypeId; 667 this.optionsField = containerOptions; 668 669 this.setModalTitle(this.getSaveContainerTitle(containerTypeId), this.nameModalId); 670 671 // set input to container name 672 $("#wfmodal-spot-name").val(containerName); 673 674 this.open(this.nameModalId); 675 676} 677 678WFModalManager.prototype.getSaveContainerTitle = function (containerTypeId) { 679 var title = "Save"; 680 var ctnName = null; 681 682 switch (containerTypeId) { 683 case "Bulletin": 684 ctnName = "bulletins"; 685 break; 686 case "Tides": 687 ctnName = "nearby-tides"; 688 break; 689 case "Archive": 690 ctnName = "data-archives" 691 break; 692 case "Current Conditions": 693 ctnName = "current-conditions"; 694 break; 695 case "Spot Stats": 696 ctnName = "wind-stats"; 697 break; 698 case "Onsite Report": 699 ctnName = "onsite-reports"; 700 break; 701 case "Operational Forecast": 702 ctnName = "daily-briefing"; 703 break; 704 case "Model Table": 705 ctnName = "forecast-table"; 706 break; 707 } 708 709 if (ctnName != null) { 710 var ctn = new ContainerInfo(ctnName); 711 title += " " + ctn.title(); 712 } 713 714 return title; 715} 716 717 718// Add Container to Profile - Step 2 719WFModalManager.prototype.addContainerToProfileStep2 = function () { 720 // set modal title 721 $(".wf-modal-title").empty(); 722 $(".wf-modal-title").append(this.nameField); 723 724 // update the profile list in the modal 725 $("#wfmodal-profile-list").empty(); 726 $("#wfmodal-profile-list").append(this.createSelectProfileList()); 727 728 if (wfProfileManager.profileCount == 1) { 729 var profiles = wfProfileManager.getProfiles(); 730 731 if (this.currentActivity == "addarbitraryspottoprofile") { 732 this.doAddArbitrarySpotToProfile(profiles[0].profile_id, profiles[0].name); 733 } else if (this.currentActivity == "addcontainertoprofile") { 734 this.doAddContainerToProfile(profiles[0].profile_id, profiles[0].name); 735 } 736 } 737 738 // display select profile modal 739 this.open(this.selectProfileModalId); 740} 741 742////////////////////////////////////////////////////////////////////////////////////////////////////////// 743// addSpotToProfile Controllers 744////////////////////////////////////////////////////////////////////////////////////////////////////////// 745// Add Container to Profile - Step 1 746WFModalManager.prototype.addSpotToProfile = function (spotId, spotName, spotType) { 747 this.currentActivity = "addspottoprofile"; 748 this.nameField = spotName; 749 this.spotId = spotId; 750 751 if (spotType != undefined && spotType > 0) { 752 this.spotType = spotType; 753 } 754 else { 755 this.spotType = 1; 756 } 757 758 // set modal title 759 $(".wf-modal-title").empty(); 760 $(".wf-modal-title").append(this.nameField); 761 762 // update the profile list in the modal 763 $("#wfmodal-profile-list").empty(); 764 $("#wfmodal-profile-list").append(this.createSelectProfileList()); 765 766 // If the user only has one profile, automatically add/remove the spot to/from their profile 767 if (wfProfileManager.profileCount == 1) { 768 var profiles = wfProfileManager.getProfiles(); 769 770 if (wfProfileManager.isSpotIdInAnyProfile(spotId)) { 771 //spotId, favSpotId, profileId, profileName 772 var favId = wfProfileManager.getFavSpotIdForSpotIdInProfile(spotId, profiles[0].profile_id); 773 this.doRemoveSpotFromProfile(spotId, favId, profiles[0].profile_id, profiles[0].name); 774 } else { 775 this.doAddSpotToProfile(spotId, profiles[0].profile_id, profiles[0].name); 776 } 777 } else { 778 $(".wfmodal-instructions").html("<br/>Click a favorite star to add or remove spot from your profile.").show();; 779 } 780 781 // display select profile modal 782 this.open(this.selectProfileModalId); 783} 784 785 786//////////////////////////////////////////////////////////////////////////////////////////////////////////
787// addArbitrarySpotToProfile Controllers 788////////////////////////////////////////////////////////////////////////////////////////////////////////// 789// Add Arbitrary Spot to Profile - Step 1 790WFModalManager.prototype.addArbitrarySpotToProfile = function (lat, lon, spotName, favSpotId) { 791 792 // display step 1 modal 793 this.currentActivity = "addarbitraryspottoprofile"; 794 this.nameField = spotName; 795 this.spotType = 101; 796 this.spotLat = lat; 797 this.spotLon = lon; 798 this.favSpotId = favSpotId; 799 800 if (this.favSpotId != null || wfProfileManager.isLatLonInAnyProfile(this.spotLat, this.spotLon)) { 801 // User is working with a arb spot that is already favorited 802 // set modal title 803 $(".wf-modal-title").empty(); 804 $(".wf-modal-title").append(this.nameField); 805 806 // update the profile list in the modal 807 $("#wfmodal-profile-list").empty(); 808 $("#wfmodal-profile-list").append(this.createSelectProfileList()); 809 810 if (wfProfileManager.profileCount == 1) { 811 profiles = wfProfileManager.getProfiles(); 812 813 // favSpotId, profileId, profileName 814 this.doRemoveArbitrarySpotFromProfile(favSpotId, profiles[0].profile_id, profiles[0].name); 815 } 816 817 // display select profile modal 818 this.open(this.selectProfileModalId); 819 } else { 820 if (typeof spotName == "undefined" || spotName.length < 1) { 821 this.nameField = "Location " + this.spotLat + "," + this.spotLon; 822 } 823 // set modal title 824 $(".wf-modal-title").empty(); 825 $(".wf-modal-title").append("Save Location"); 826 827 // set input to container name 828 $("#wfmodal-spot-name").val(this.nameField); 829 830 // display change name modal 831 this.open(this.nameModalId); 832 } 833} 834 835 836// Add Arbitrary Spot to Profile - Step 2 837WFModalManager.prototype.addArbitrarySpotToProfileStep2 = function () { 838 // set modal title 839 $(".wf-modal-title").empty(); 840 $(".wf-modal-title").append(this.nameField); 841 842 // update the profile list in the modal 843 $("#wfmodal-profile-list").empty(); 844 $("#wfmodal-profile-list").append(this.createSelectProfileList()); 845 846 // display select profile modal 847 this.open(this.selectProfileModalId); 848} 849 850 851////////////////////////////////////////////////////////////////////////////////////////////////////////// 852// addProfile Controllers 853////////////////////////////////////////////////////////////////////////////////////////////////////////// 854WFModalManager.prototype.addProfile = function () { 855 // set modal title 856 $(".wf-modal-title").empty(); 857 $(".wfmodal-instructions").hide(); 858 $(".wfmodal-message").hide(); 859 $(".wf-modal-title").append("Create Favorites Profile"); 860 $("#wfmodal-profile-name").val(""); 861 862 863 // display add profile 864 this.open(this.addProfileModalId); 865 866 // refresh profiles - leaving profile list display and the data could have changed 867 wfProfileManager.loadProfiles(); 868} 869 870WFModalManager.prototype.renameProfile = function (profileId, profileName) { 871 $(".wf-modal-title").html("Rename " + profileName); 872 $(this.renameProfileModal).attr("data-profile-id", profileId); 873 874 this.open(this.renameProfileModalId); 875} 876 877 878////////////////////////////////////////////////////////////////////////////////////////////////////////// 879// removeContainerFromProfile Controllers 880////////////////////////////////////////////////////////////////////////////////////////////////////////// 881WFModalManager.prototype.removeContainerFromProfile = function (containerId, targetDivId) { 882 // set modal alert message 883 $(".wfmodal-alert-message").empty(); 884 885 // set modal title 886 $(".wf-modal-title").empty(); 887 $(".wf-modal-title").append("Remove Container"); 888 889 if (this.options.userSignedIn == "false") { 890 // User not signed in. Remove container from their local profile 891 var profile = new WFLocalProfile(this.options.tokenDomain); 892 profile.removeContainer(containerId); 893 894 $(".wfmodal-alert-message").append("The container was successfully removed."); 895 896 // display add profile 897 this.open(this.alertModalId); 898 899 // remove container from DOM 900 $("#" + targetDivId).remove(); 901 } else { 902 903 // use API to remove container from profile 904 var url = this.options.baseURL + "/profile/removeContainerFromProfile?callback=?"; 905 var urldata = new Object(); 906 urldata.container_id = containerId; 907 urldata.wf_token = this.options.token;; 908 909 var myself = this; 910 this.jqRequest = $.getJSON(url, urldata, function (data, textStatus, jqXHR) { 911 if (data.status_code == 0) { 912 // success 913 $(".wfmodal-alert-message").append("The container was successfully removed."); 914 // remove container from DOM 915 $("#" + targetDivId).remove(); 916 } 917 else { 918 // fail 919 $(".wfmodal-alert-message").append("An error occurred while removing the container."); 920 } 921 // display add profile 922 myself.open(myself.alertModalId); 923 924 }, "json"); 925 } 926 927} 928 929WFModalManager.prototype.displayAlert = function (title, message) { 930 // set modal alert message 931 $(".wfmodal-alert-message").empty(); 932 933 // set modal title 934 $(".wf-modal-title").empty(); 935 $(".wf-modal-title").append(title); 936 937 // set the message 938 $(".wfmodal-alert-message").append(message); 939 940 // display add profile 941 this.open(this.alertModalId); 942} 943 944WFModalManager.prototype.showReplicateProfile = function (profileId, profilename) { 945 $("#replicateProfileName").val(unescape(profilename) + " copy").attr("data-profile-id", profileId); 946 $("#replicateProgress").html("Create a copy of " + unescape(profilename)).show(); 947 948 this.open(this.replicateProfileModalId); 949} 950 951WFModalManager.prototype.showToast = function (title, message) { 952 var self = this; 953 this.displayAlert(title, message); 954 955 var t = setTimeout(function () { self.close() }, 2000) 956} 957 958WFModalManager.prototype.displayInfoWindow = function (content, title, width) { 959 // Set the content 960 $("#info-window-content").empty().append(content); 961 $("#info-window").dialog("option", "title", title); 962 $("#info-window").dialog("option", "width", "100%"); 963 964 // Show the window 965 $("#info-window").dialog("open"); 966} 967 968WFModalManager.prototype.displayLoading = function (title) { 969 $(".wf-modal-title").html(title); 970 this.show(this.loadingModalId); 971} 972 973WFModalManager.prototype.hideLoading = function () { 974 this.close(); 975} 976
977////////////////////////////////////////////////////////////////////////////////////////////////////////// 978// displayMembershipModal Controllers 979////////////////////////////////////////////////////////////////////////////////////////////////////////// 980WFModalManager.prototype.doesUserHaveAccessToFeature = function (featureId, exceptionFailMemberIdsStr) { 981 var doesUserHaveAccessToFeature = WFProducts.doesUserHaveAccessToFeature(featureId, this.memberLevel, exceptionFailMemberIdsStr); 982 983 if (doesUserHaveAccessToFeature) { 984 // the user can use the feature, do not need to display a modal 985 return true; 986 } 987 else { 988 // hide sign in and upgrade buttons 989 $("#wfmodal-membership-upgrade").hide(); 990 $("#wfmodal-membership-signin").hide(); 991 992 // set modal title 993 $(".wf-modal-title").empty(); 994 if (this.memberLevel == -1) { 995 // Guest - need to sign in 996 $(".wf-modal-title").append("Sign in required for this feature"); 997 $("#wfmodal-membership-signin").show(); 998 } 999 else { 1000 $(".wf-modal-title").append("Upgrade required for this feature"); 1001 $("#wfmodal-membership-upgrade").show(); 1002 } 1003 1004 // set feature title 1005 $("#wfmodal-feature-title").empty(); 1006 $("#wfmodal-feature-title").append(WFProducts.getFeatureTitleById(featureId)); 1007 1008 // set feature membership string 1009 $("#wfmodal-feature-membershipstr").empty(); 1010 $("#wfmodal-feature-membershipstr").append(WFProducts.getFeatureMembershipStringById(featureId)); 1011 1012 // set current membership level 1013 $("#wfmodal-current-member-level").empty(); 1014 $("#wfmodal-current-member-level").append(WFProducts.getMembershipLevelNameById(this.memberLevel)); 1015 1016 this.open(this.membershipModalId); 1017 1018 if (typeof this.options.upsellMsgShown === "function") { 1019 this.options.upsellMsgShown(featureId); 1020 } 1021 1022 return false; 1023 } 1024} 1025 1026WFModalManager.prototype.showSignInRequired = function (feature, msg) { 1027 $("#wfmodal-membership-upgrade").hide(); 1028 1029 $(".wf-modal-title").text("Sign in required for this feature"); 1030 $("#wfmodal-membership-signin").show(); 1031 1032 // set feature title 1033 $("#wfmodal-feature-title").text(feature); 1034 1035 // set feature membership string 1036 $("#wfmodal-feature-membershipstr").html(msg); 1037 1038 // set membership level 1039 $("#wfmodal-current-member-level").append(WFProducts.getMembershipLevelNameById(this.memberLevel)); 1040 1041 this.open(this.membershipModalId); 1042 1043 return false; 1044} 1045 1046 1047WFModalManager.prototype.showMembershipRequired = function (feature) { 1048 var featureId = feature.feature_id; 1049 1050 // overriding getProducts.js membership_str to allow for dynamically changing the string based on memberLevel 1051 var membershipString = "This feature is available to PLUS, PRO, and GOLD Members. Upgrade today." 1052 1053 // hide sign in and learn more buttons 1054 $("#wfmodal-learnmore").hide(); 1055 $("#wfmodal-membership-signin").hide(); 1056 1057 // set modal title 1058 $(".wf-modal-title").empty(); 1059 if (this.memberLevel == -1) { 1060 // Guest - need to sign in 1061 membershipString = "This feature is available to PLUS, PRO, and GOLD Members. Sign In or Upgrade today." 1062 1063 $(".wf-modal-title").append("Sign In or Upgrade required for this feature"); 1064 $("#wfmodal-membership-signin").show(); 1065 } else { 1066 $(".wf-modal-title").append("Upgrade required for this feature"); 1067 } 1068 1069 // set feature title 1070 $("#wfmodal-feature-title").empty(); 1071 $("#wfmodal-feature-title").append(WFProducts.getFeatureTitleById(featureId)); 1072 1073 // set feature membership string 1074 $("#wfmodal-feature-membershipstr").empty(); 1075 $("#wfmodal-feature-membershipstr").append(membershipString); 1076 1077 // set current membership level 1078 $("#wfmodal-current-member-level").empty(); 1079 $("#wfmodal-current-member-level").append(WFProducts.getMembershipLevelNameById(this.memberLevel)); 1080 1081 1082 this.open(this.membershipModalId); 1083 return false; 1084} 1085 1086////////////////////////////////////////////////////////////////////////////////////////////////////////// 1087// downloadDataModal Controllers 1088////////////////////////////////////////////////////////////////////////////////////////////////////////// 1089WFModalManager.prototype.downloadData = function (startDateStr, endDateStr, spotId, unitsWind, unitsTemp, format) { 1090 // set member vars so they are available to the download click event 1091 if (typeof startDateStr == "undefined") { 1092 this.downloadDataStartDateStr = ""; 1093 } 1094 else { 1095 this.downloadDataStartDateStr = startDateStr; 1096 } 1097 1098 if (typeof endDateStr == "undefined") { 1099 this.downloadDataEndDateStr = ""; 1100 } 1101 else { 1102 this.downloadDataEndDateStr = endDateStr; 1103 } 1104 1105 if (typeof spotId == "undefined") { 1106 this.downloadDataSpotId = 0; 1107 } 1108 else { 1109 this.downloadDataSpotId = spotId; 1110 } 1111 1112 if (typeof unitsWind == "undefined") { 1113 this.downloadDataUnitsWind = "mph"; 1114 } 1115 else { 1116 this.downloadDataUnitsWind = unitsWind; 1117 } 1118 1119 if (typeof unitsTemp == "undefined") { 1120 this.downloadDataUnitsTemp = "F"; 1121 } 1122 else { 1123 this.downloadDataUnitsTemp = unitsTemp; 1124 } 1125 1126 if (typeof format == "undefined") { 1127 this.downloadDataFormat = "csv"; 1128 } 1129 else { 1130 this.downloadDataFormat = format; 1131 } 1132 1133 1134 // set modal alert message 1135 $(".wfmodal-alert-message").empty(); 1136 1137 // set modal title 1138 $(".wf-modal-title").empty(); 1139 $(".wf-modal-title").append("Archive Data Download"); 1140 1141 // set start date 1142 $("#wfmodal-download-data-start-date").empty(); 1143 $("#wfmodal-download-data-start-date").append(this.downloadDataStartDateStr); 1144 1145 // set end date 1146 $("#wfmodal-download-data-end-date").empty(); 1147 $("#wfmodal-download-data-end-date").append(this.downloadDataEndDateStr); 1148 1149 this.open(this.downloadDataModalId); 1150} 1151 1152WFModalManager.prototype.doDownloadData = function () { 1153 this.close(); 1154 1155 // use API to updateContainer 1156 var downloadUrl = "https://api.weatherflow.com/wxengine/rest/spot/getSpotDetail?" + 1157 "wf_token=" + this.options.token + 1158 "&units_wind=" + this.downloadDataUnitsWind + 1159 "&units_temp=" + this.downloadDataUnitsTemp + 1160 "&format=" + this.downloadDataFormat + 1161 "&time_start=" + this.downloadDataStartDateStr + 1162 "&time_end=" + this.downloadDataEndDateStr + 1163 "&spot_id=" + this.downloadDataSpotId; 1164 1165 window.location = downloadUrl; 1166} 1167
1168////////////////////////////////////////////////////////////////////////////////////// 1169// HTML Generation Controllers 1170////////////////////////////////////////////////////////////////////////////////////// 1171// Name Item Modal 1172WFModalManager.prototype.createNameItemModal = function () { 1173 var myself = this; 1174 var buttons = []; 1175 var nextButton = this.createButton("wfmodal-do-add-to-container-step-2", "", "#", "Next"); 1176 var str = "<div class='field-wrap'>"; 1177 str += "<label for='wfmodal-spot-name'>Name:</label>"; 1178 str += "<input type='text' id='wfmodal-spot-name' />"; 1179 str += "</div>"; 1180 1181 buttons.push(nextButton); 1182 buttons.push(this.createButton("wf-modal-close-btn", "wf-modal-close", "#", "Cancel")); 1183 1184 $(nextButton).on("touchend click", function () { 1185 var newName = $("#wfmodal-spot-name").val(); 1186 if (newName.length > 0) { 1187 document.activeElement.blur(); 1188 myself.nameField = $("#wfmodal-spot-name").val() 1189 myself.close(); 1190 myself.addContainerToProfileStep2(); 1191 } 1192 return false; 1193 }); 1194 1195 var settings = { 1196 id: this.nameModalId, 1197 title: "", 1198 body: str, 1199 buttons: buttons 1200 }; 1201 1202 return this.createModal(settings); 1203} 1204 1205// Select Profile Modal 1206WFModalManager.prototype.createSelectProfileModal = function () { 1207 var str = "<div id='wfmodal-profile-list'></div>"; 1208 var settings = { 1209 id: this.selectProfileModalId, 1210 title: "", 1211 body: str, 1212 buttons: [this.createButton("cancelSaveFavorite", "wf-modal-close", "#", "Done")], 1213 extras: this.getSelectProfileLinks() 1214 }; 1215 1216 return this.createModal(settings); 1217} 1218// Add Profile Modal 1219WFModalManager.prototype.createAddProfileModal = function () { 1220 var myself = this; 1221 var buttons = []; 1222 var saveButton = this.createButton("wfmodal-add-profile", "", "#", "Save"); 1223 var str = "<div class='wfmodal-message'>Invalid input parameter value - name required</div>" + 1224 "<div id='saveFx1'>" + 1225 " <div class='wfmodal-input-field-container'>" + 1226 " <div class='wfmodal-input-field-label'><span>Name:</span></div>" + 1227 " <div class='wfmodal-textfield'><input type='text' id='wfmodal-profile-name'/></div>" + 1228 " </div>" + 1229 "</div>"; 1230 1231 buttons.push(saveButton); 1232 buttons.push(this.createButton("wf-add-profile-close", "wf-modal-close", "#", "Cancel")); 1233 1234 $(saveButton).on("touchend click", function () { 1235 var newName = $("#wfmodal-profile-name").val(); 1236 if (newName.length > 0) { 1237 myself.doAddProfileAction(); 1238 } 1239 else { 1240 $(".wfmodal-message").show(); 1241 } 1242 return false; 1243 }); 1244 1245 var settings = { 1246 id: this.addProfileModalId, 1247 title: "", 1248 body: str, 1249 buttons: buttons 1250 }; 1251 1252 return this.createModal(settings); 1253} 1254 1255// Rename Profile Modal 1256WFModalManager.prototype.createRenameProfileModal = function () { 1257 var myself = this; 1258 var buttons = []; 1259 var saveButton = this.createButton("wfmodal-rename-profile", "", "#", "Rename"); 1260 var str = "<div class='wfmodal-message'>Invalid input parameter value - name required</div>" + 1261 "<div id='saveFx1'>" + 1262 " <div class='wfmodal-input-field-container'>" + 1263 " <div class='wfmodal-input-field-label'><span>New Name:</span></div>" + 1264 " <div class='wfmodal-textfield'><input type='text' id='wfmodal-profile-new-name'/></div>" + 1265 " </div>" + 1266 "</div>"; 1267 1268 buttons.push(saveButton); 1269 buttons.push(this.createButton("wf-rename-profile-close", "wf-modal-close", "#", "Cancel")); 1270 1271 $(saveButton).on("touchend click", function () { 1272 var newName = $("#wfmodal-profile-new-name").val(); 1273 if (newName.length > 0) { 1274 myself.doRenameProfileAction(); 1275 } 1276 else { 1277 $(".wfmodal-message").show(); 1278 } 1279 return false; 1280 }); 1281 1282 var settings = { 1283 id: this.renameProfileModalId, 1284 title: "", 1285 body: str, 1286 buttons: buttons 1287 }; 1288 1289 return this.createModal(settings); 1290} 1291 1292// Alert Modal 1293WFModalManager.prototype.createAlertModal = function () { 1294 var settings = { 1295 id: this.alertModalId, 1296 title: "", 1297 body: "<div class='wfmodal-alert-message'></div>", 1298 buttons: [this.createButton("wf-alert-modal-close", "wf-modal-close", "#", "Close")] 1299 }; 1300 return this.createModal(settings); 1301} 1302 1303// Loading Modal 1304WFModalManager.prototype.createLoadingModal = function () { 1305 var settings = { 1306 id: this.loadingModalId, 1307 title: "", 1308 body: "<div class='loading3B3B3B'></div>" 1309 }; 1310 1311 return this.createModal(settings); 1312} 1313 1314// Replicate Profile Modal 1315WFModalManager.prototype.createReplicateProfileModal = function () { 1316 var myself = this; 1317 var saveBtn = this.createButton("wf-replicate-save", "", "#", "Save"); 1318 var str = "<p id='replicateProgress'></p>" 1319 str += "<div class='wfmodal-input-field-container'>"; 1320 str += "<div class='wfmodal-input-field-label'><span>Name:</span></div>"; 1321 str += "<div class='wfmodal-textfield'><input type='text' data-profile-id='' id='replicateProfileName'/></div>"; 1322 str += "</div>"; 1323 1324 $(saveBtn).on("touchend click", function () { 1325 if ($("#replicateProfileName").val() != "") { 1326 wfProfileManager.replicateProfile($("#replicateProfileName").attr("data-profile-id"), $("#replicateProfileName").val(), primaryActivity, function (status) { 1327 if (status.status_code > 0) { 1328 $("#replicateProgress").html(data.status_message); 1329 } else { 1330 wfModalManager.close(); 1331 } 1332 }); 1333 } else { 1334 $("#replicateProgress").html("Invalid profile name").show(); 1335 } 1336 1337 return false;
1338 }); 1339 1340 var settings = { 1341 id: this.replicateProfileModalId, 1342 title: "Save Profile As", 1343 body: str, 1344 buttons: [saveBtn, this.createButton("wf-replicate-modal-close", "wf-modal-close", "#", "Close")] 1345 }; 1346 1347 return this.createModal(settings); 1348} 1349 1350// Membership Modal 1351WFModalManager.prototype.createMembershipModal = function () { 1352 var myself = this; 1353 var str = "<div class='wfmodal-row'>Feature: <span class='wfmodal-value' id='wfmodal-feature-title'></span></div>" + 1354 "<div class='wfmodal-row' id='wfmodal-feature-membershipstr'></div>" + 1355 "<div class='wfmodal-row'>Your Current Membership Level: <span class='wfmodal-value' id='wfmodal-current-member-level'></span></div>"; 1356 1357 var signInButton = this.createButton("wfmodal-membership-signin", "", "#", "Sign In"); 1358 $(signInButton).on("touchend click", function () { 1359 window.location = myself.options.userSignInUrl; 1360 return false; 1361 }); 1362 1363 var upgradeButton = this.createButton("wfmodal-membership-upgrade", "", "#", "Upgrade"); 1364 $(upgradeButton).on("touchend click", function () { 1365 window.location = myself.options.learnMoreUrl; 1366 return false; 1367 }); 1368 1369 var learnMoreButton = this.createButton("wfmodal-learnmore", "", "#", "Learn More"); 1370 $(learnMoreButton).on("touchend click", function () { 1371 window.location = myself.options.learnMoreUrl; 1372 return false; 1373 }); 1374 1375 var cancelButton = this.createButton("membership-close", "wf-modal-close", "#", "Cancel"); 1376 1377 var settings = { 1378 id: this.membershipModalId, 1379 title: "", 1380 body: str, 1381 buttons: [signInButton, upgradeButton, learnMoreButton, cancelButton] 1382 }; 1383 1384 return this.createModal(settings); 1385} 1386 1387// Membership Modal 1388WFModalManager.prototype.createDownloadDataModal = function () { 1389 var myself = this; 1390 var str = "<div class='wfmodal-row'>Download all archived observation records for the period of time listed below.</div>" + 1391 "<div class='wfmodal-row'><span class='wfmodal-label'>Start:</span><span class='wfmodal-value-text' id='wfmodal-download-data-start-date'></span></div>" + 1392 "<div class='wfmodal-row'><span class='wfmodal-label'>End:</span><span class='wfmodal-value-text' id='wfmodal-download-data-end-date'></span></div>" + 1393 "<div class='wfmodal-row'><span class='wfmodal-label'>Format:</span><span class='wfmodal-value-text' id='wfmodal-download-data-format'>csv (header row included)</span></div>" + 1394 "<div class='wfmodal-row'><span class='wfmodal-label'>Fields:</span><span class='wfmodal-value-text' id='wfmodal-download-data-fields'>All available fields. Can include the following: station meta data, wind(avg,gust,lull,dir), air temperature, pressure, precipitation, water temperature, wave height, wave period</span></div>" 1395 1396 var downloadButton = this.createButton("wfmodal-download", "", "#", "Download"); 1397 $(downloadButton).on("touchend click", function () { 1398 myself.doDownloadData(); 1399 return false; 1400 }); 1401 1402 var closeButton = this.createButton("wfmodal-cancel", "wf-modal-close", "#", "Cancel"); 1403 1404 var settings = { 1405 id: this.downloadDataModalId, 1406 title: "", 1407 body: str, 1408 buttons: [downloadButton, closeButton] 1409 }; 1410 1411 return this.createModal(settings); 1412} 1413 1414// Info Window 1415WFModalManager.prototype.createInfoWindow = function () { 1416 var str = "<div id='info-window' title='More Information' style='display:none;'>"; 1417 str += "<div id='info-window-content'></div>"; 1418 str += "</div>"; 1419 1420 $("body").append(str); 1421 1422 $("#info-window").dialog({ 1423 autoOpen: false, 1424 draggable: false, 1425 modal: true, 1426 resizable: false, 1427 width: "auto" 1428 }); 1429} 1430 1431 1432////////////////////////////////////////////////////////////////////////////////////// 1433// Common HTML Parts 1434////////////////////////////////////////////////////////////////////////////////////// 1435// Header 1436WFModalManager.prototype.createModalHeader = function (title) { 1437 var hdr = document.createElement("div"); 1438 hdr.className = "wf-modal-title"; 1439 hdr.innerHTML = "<h2 class='wf-modal-title jw-h1'>" + title + "</h2><p class='wfmodal-instructions' style='display: none;'></p>"; 1440 1441 return hdr; 1442} 1443 1444// Footer 1445WFModalManager.prototype.createModalFooter = function () { 1446 var foot = document.createElement("div"); 1447 foot.className = "wfmodal-footer"; 1448 foot.innerHTML = "<span class='wfmodal-status-good'></span><span class='wfmodal-status-bad'></span>"; 1449 1450 return foot; 1451} 1452 1453WFModalManager.prototype.getSelectProfileLinks = function () { 1454 var str = ""; 1455 if (this.options.userSignedIn == "true") { 1456 str += "<ul class='wfmodal-links-ul'>"; 1457 str += "<li><a onclick='javascript:wfModalManager.addProfile();return false;' href='#' class='createProfileShow' id='createProfileShow'>Create Profile</a></li>"; 1458 str += "<li><a href='/en-us/Favorites/ManageFavorites.aspx'>Manage Favorites Profiles</a></li>"; 1459 str += "</ul>"; 1460 } else { 1461 // Working with a local profile 1462 str += "<p>You are using a local profile. To save your profile <a href='#' class='clkSignIn underline'>Sign In</a> or <a href='#' class='clkLearnMore underline'>Create An Account</a>.</p>"; 1463 } 1464 1465 return str; 1466} 1467 1468// Body - Profile List 1469WFModalManager.prototype.createSelectProfileList = function () { 1470 var sb = ""; 1471 1472 sb += "<div class='wfmodal-body wfmodal-profile-scroller' style='height: auto;'>"; 1473 sb += "<table width='95%' class='wfmodal-table' id='profileListTable'>"; 1474 sb += "<thead><tr><th>
1474Your Profiles</th><th class='starColumn'>Add / Remove</th></tr></thead>"; 1475 1476 var profiles = wfProfileManager.getProfiles(); 1477 var myself = this; 1478 var rowClass = "alt"; 1479 1480 $.each(profiles, function (i, profile) { 1481 if (profile.my_profile == "true") { 1482 var onClickStr = ""; 1483 var starButtonClass = ""; 1484 var hoverTitleStr = ""; 1485 1486 if (myself.currentActivity == "addspottoprofile") { 1487 if (userSignedIn == "true") { 1488 var favSpotIdInProfile = wfProfileManager.getFavSpotIdForSpotIdInProfile(myself.spotId, profile.profile_id); // returns -1 if spot not in profile 1489 if (favSpotIdInProfile > 0) { 1490 // spot already in this profile 1491 onClickStr = "javascript:wfModalManager.doRemoveSpotFromProfile(\"" + myself.spotId + "\",\"" + favSpotIdInProfile + "\",\"" + profile.profile_id + "\",\"" + escape(profile.name) + "\")"; 1492 starButtonClass = "wfmodal-favorite-yellow"; 1493 hoverTitleStr = "Remove from " + profile.name; 1494 } 1495 else { 1496 // spot not in this profile 1497 onClickStr = "javascript:wfModalManager.doAddSpotToProfile(\"" + myself.spotId + "\",\"" + profile.profile_id + "\",\"" + escape(profile.name) + "\")"; 1498 starButtonClass = "wfmodal-favorite"; 1499 hoverTitleStr = "Add to " + profile.name; 1500 } 1501 } else { 1502 // Working with local profile 1503 if (wfProfileManager.isSpotIdInProfile(myself.spotId, profile.profile_id)) { 1504 // spot already in this profile 1505 onClickStr = "javascript:wfModalManager.doRemoveSpotFromProfile(\"" + myself.spotId + "\",null,\"" + profile.profile_id + "\",\"" + escape(profile.name) + "\")"; 1506 starButtonClass = "wfmodal-favorite-yellow"; 1507 hoverTitleStr = "Remove from " + profile.name; 1508 } else { 1509 // spot not in this profile 1510 onClickStr = "javascript:wfModalManager.doAddSpotToProfile(\"" + myself.spotId + "\",\"" + profile.profile_id + "\",\"" + escape(profile.name) + "\")"; 1511 starButtonClass = "wfmodal-favorite"; 1512 hoverTitleStr = "Add to " + profile.name; 1513 } 1514 } 1515 } 1516 if (myself.currentActivity == "addarbitraryspottoprofile") { 1517 if (userSignedIn == "true") { 1518 // do lookup by lat lon incase this arb spot is in multiple profiles (same lat lon with different fav spot ids) 1519 var favSpotIdInProfile = wfProfileManager.getFavSpotIdForLatLonInProfile(myself.spotLat, myself.spotLon, profile.profile_id); 1520 1521 if (favSpotIdInProfile > 0) { 1522 // spot already in this profile 1523 onClickStr = "javascript:wfModalManager.doRemoveArbitrarySpotFromProfile(\"" + favSpotIdInProfile + "\",\"" + profile.profile_id + "\",\"" + escape(profile.name) + "\")"; 1524 starButtonClass = "wfmodal-favorite-yellow"; 1525 hoverTitleStr = "Remove from " + profile.name; 1526 myself.favSpotId = ""; 1527 } 1528 else { 1529 // spot not in this profile 1530 onClickStr = "javascript:wfModalManager.doAddArbitrarySpotToProfile(\"" + profile.profile_id + "\",\"" + escape(profile.name) + "\")"; 1531 starButtonClass = "wfmodal-favorite"; 1532 hoverTitleStr = "Add to " + profile.name; 1533 } 1534 } else { 1535 // Local profile. We don't have fav spot id's 1536 if (wfProfileManager.isLatLonInProfile(myself.lat, myself.lon, profile.profile_id)) { 1537 // spot already in this profile 1538 onClickStr = "javascript:wfModalManager.doRemoveArbitrarySpotFromProfile(null,\"" + profile.profile_id + "\",\"" + escape(profile.name) + "\")"; 1539 starButtonClass = "wfmodal-favorite-yellow"; 1540 hoverTitleStr = "Remove from " + profile.name; 1541 myself.favSpotId = ""; 1542 } else { 1543 // spot not in this profile 1544 onClickStr = "javascript:wfModalManager.doAddArbitrarySpotToProfile(\"" + profile.profile_id + "\",\"" + escape(profile.name) + "\")"; 1545 starButtonClass = "wfmodal-favorite"; 1546 hoverTitleStr = "Add to " + profile.name; 1547 } 1548 } 1549 1550 } 1551 else if (myself.currentActivity == "addcontainertoprofile") { 1552 onClickStr = "javascript:wfModalManager.doAddContainerToProfile(\"" + profile.profile_id + "\",\"" + escape(profile.name) + "\")"; 1553 starButtonClass = "wfmodal-favorite"; 1554 hoverTitleStr = "Add to " + profile.name; 1555 } 1556 1557 sb += "<tr class='" + rowClass + "'><td>" + profile.name + "</td><td class='wfcontainer-center starColumn' id='wfmodal-td-" + profile.profile_id + "'><div onclick='" + onClickStr + "' class='" + starButtonClass + "' id='" + profile.profile_id + "' title='" + hoverTitleStr + "'></div></td></tr>"; 1558 } 1559 else { 1560 sb += "<tr class='" + rowClass + "'><td>" + profile.name + "</td><td class='notyours'>Owner: " + profile.created_by + " - <a href='/en-us/Favorites/ViewFavorites.aspx?pid=" + profile.profile_id + "'>View Profile</a></td></tr>"; 1561 } 1562 1563 // Switch the row class 1564 rowClass = rowClass == "alt" ? "" : "alt"; 1565 }); 1566 1567 sb += "</table>"; 1568 sb += "</div>"; 1569 1570 return sb; 1571} 1572
1573//////////////////////////////////////////////////////////////////////////////// 1574//////////////////////////////////////////////////////////////////////////////// 1575//////////////////////////////////////////////////////////////////////////////// 1576// Click Event Handlers 1577//////////////////////////////////////////////////////////////////////////////// 1578//////////////////////////////////////////////////////////////////////////////// 1579//////////////////////////////////////////////////////////////////////////////// 1580 1581//////////////////////////////////////////////////////////////////////////////// 1582// Add/Remove Container - Click Event Handlers 1583//////////////////////////////////////////////////////////////////////////////// 1584// Add Container to Profile 1585WFModalManager.prototype.doAddContainerToProfile = function (profileId, profileName) { 1586 profileName = unescape(profileName); 1587 1588 if (this.options.userSignedIn == "false") { 1589 // User not signed in. Add spot to the local profile 1590 var profile = new WFLocalProfile(this.options.tokenDomain); 1591 1592 //containerId, containerTypeId, containerName, flowviewOptions, options 1593 var newContainerId = profile.newContainerId(); 1594 var favCtn = new WFFavoriteContainer(newContainerId, this.containerTypeIdField, this.nameField, null, this.optionsField); 1595 profile.addContainer(favCtn); 1596 1597 $("#wfmodal-td-" + profileId).empty(); 1598 $("#wfmodal-td-" + profileId).append("<div onclick='javascript:wfModalManager.doRemoveContainerFromProfile(\"" + newContainerId + "\",\"" + profileId + "\",\"" + escape(profileName) + "\")' class='wfmodal-favorite-yellow' id='" + profileId + "' title='Remove from " + profileName + "'></div>"); 1599 1600 // Update the page title 1601 $(".wf-modal-title").html(this.nameField + " added to " + profileName); 1602 1603 } else { 1604 var myself = this; 1605 var ps = new WFProfileService({ "baseURL": this.options.baseURL, "token": this.options.token }); 1606 1607 profileName = unescape(profileName); 1608 1609 var urlData = { 1610 "container_type_id": this.containerTypeIdField, 1611 "name": this.nameField, 1612 "options": this.optionsField, 1613 "profile_id": profileId 1614 }; 1615 1616 ps.addContainerToProfile(urlData, function (data) { 1617 if (data.status_code == 0) { 1618 var newContainerId = data.status_message; 1619 $("#wfmodal-td-" + profileId).empty(); 1620 $("#wfmodal-td-" + profileId).append("<div onclick='javascript:wfModalManager.doRemoveContainerFromProfile(\"" + newContainerId + "\",\"" + profileId + "\",\"" + escape(profileName) + "\")' class='wfmodal-favorite-yellow' id='" + profileId + "' title='Remove from " + profileName + "'></div>"); 1621 1622 // Update the page title 1623 $(".wf-modal-title").html(myself.nameField + " added to " + profileName); 1624 } 1625 }); 1626 1627 } 1628} 1629 1630// Remove Container From Profile 1631WFModalManager.prototype.doRemoveContainerFromProfile = function (containerId, profileId, profileName) { 1632 profileName = unescape(profileName); 1633 var url = this.options.baseURL + "/profile/removeContainerFromProfile?callback=?"; 1634 var urldata = new Object(); 1635 var self = this; 1636 urldata.wf_token = this.options.token;; 1637 urldata.container_id = containerId;; 1638 1639 this.jqRequest = $.getJSON(url, urldata, function (data, textStatus, jqXHR) { 1640 if (data.status_code == 0) { 1641 $("#wfmodal-td-" + profileId).empty(); 1642 $("#wfmodal-td-" + profileId).append("<div onclick='javascript:wfModalManager.doAddContainerToProfile(\"" + profileId + "\",\"" + escape(profileName) + "\")' class='wfmodal-favorite' id='" + profileId + "' title='Add to " + profileName + "'></div>"); 1643 // Update the page title 1644 $(".wf-modal-title").html(self.nameField + " removed from " + profileName); 1645 } 1646 }, "json"); 1647} 1648 1649//////////////////////////////////////////////////////////////////////////////// 1650// Add/Remove Arbitrary Spot - Click Event Handlers 1651//////////////////////////////////////////////////////////////////////////////// 1652// Add Arbitrary Spot to Profile 1653WFModalManager.prototype.doAddArbitrarySpotToProfile = function (profileId, profileName) { 1654 if (this.options.userSignedIn == "false") { 1655 // User not signed in. Add spot to the local profile 1656 var profile = new WFLocalProfile(this.options.tokenDomain); 1657 1658 //typeId, favSpotId, spotId, lat, lon 1659 var favSpot = new WFFavoriteSpot("101", null, null, this.spotLat, this.spotLon); 1660 newFavSpotId = profile.addFavSpot(favSpot); 1661
1662 this.reloadPageOnClose = true; 1663 1664 $("#wfmodal-td-" + profileId).empty(); 1665 $("#wfmodal-td-" + profileId).append("<div onclick='javascript:wfModalManager.doRemoveArbitrarySpotFromProfile(\"" + newFavSpotId + "\",\"" + profileId + "\",\"" + escape(profileName) + "\")' class='wfmodal-favorite-yellow' id='" + profileId + "' title='Remove from " + profileName + "'></div>"); 1666 1667 // Update the page title 1668 $(".wf-modal-title").html(this.nameField + " added to " + profileName); 1669 } else { 1670 var myself = this; 1671 var ps = new WFProfileService({ "baseURL": this.options.baseURL, "token": this.options.token }); 1672 1673 profileName = unescape(profileName); 1674 1675 var urlData = { 1676 "lat": this.spotLat, 1677 "lon": this.spotLon, 1678 "name": this.nameField, 1679 "profile_id": profileId, 1680 "spot_types": this.spotType 1681 }; 1682 1683 ps.addSpotToProfile(urlData, function (data) { 1684 if (data.status_code == 0) { 1685 var newFavSpotId = data.status_message; 1686 1687 myself.reloadPageOnClose = true; 1688 1689 $("#wfmodal-td-" + profileId).empty(); 1690 $("#wfmodal-td-" + profileId).append("<div onclick='javascript:wfModalManager.doRemoveArbitrarySpotFromProfile(\"" + newFavSpotId + "\",\"" + profileId + "\",\"" + escape(profileName) + "\")' class='wfmodal-favorite-yellow' id='" + profileId + "' title='Remove from " + profileName + "'></div>"); 1691 1692 // Update the page title 1693 $(".wf-modal-title").html(myself.nameField + " added to " + profileName); 1694 } 1695 }); 1696 1697 } 1698} 1699 1700// Remove Arbitrary Spot From Profile 1701WFModalManager.prototype.doRemoveArbitrarySpotFromProfile = function (favSpotId, profileId, profileName) { 1702 1703 if (this.options.userSignedIn == "false") { 1704 var profile = new WFLocalProfile(this.options.tokenDomain); 1705 var favSpot = profile.getSpotByLatLon(this.spotLat, this.spotLon); 1706 1707 if (profile.removeFavSpot(favSpot)) { 1708 this.reloadPageOnClose = true; 1709 $("#wfmodal-td-" + profileId).empty(); 1710 $("#wfmodal-td-" + profileId).append("<div onclick='javascript:wfModalManager.doAddArbitrarySpotToProfile(\"" + profileId + "\",\"" + escape(profileName) + "\")' class='wfmodal-favorite' id='" + profileId + "' title='Add to " + profileName + "'></div>"); 1711 // Update the page title 1712 $(".wf-modal-title").html(this.nameField + " removed from " + profileName); 1713 } 1714 } else { 1715 profileName = unescape(profileName); 1716 var url = this.options.baseURL + "/profile/removeSpotFromProfile?callback=?"; 1717 var urldata = new Object(); 1718 urldata.wf_token = this.options.token;; 1719 urldata.fav_spot_id = favSpotId; 1720 1721 var myself = this; 1722 this.jqRequest = $.getJSON(url, urldata, function (data, textStatus, jqXHR) { 1723 if (data.status_code == 0) { 1724 myself.reloadPageOnClose = true; 1725 $("#wfmodal-td-" + profileId).empty(); 1726 $("#wfmodal-td-" + profileId).append("<div onclick='javascript:wfModalManager.doAddArbitrarySpotToProfile(\"" + profileId + "\",\"" + escape(profileName) + "\")' class='wfmodal-favorite' id='" + profileId + "' title='Add to " + profileName + "'></div>"); 1727 // Update the page title 1728 $(".wf-modal-title").html(myself.nameField + " removed from " + profileName); 1729 } 1730 }, "json"); 1731 } 1732} 1733 1734 1735//////////////////////////////////////////////////////////////////////////////// 1736// Add/Remove Spot - Click Event Handlers 1737//////////////////////////////////////////////////////////////////////////////// 1738// Add Spot to Profile 1739WFModalManager.prototype.doAddSpotToProfile = function (spotId, profileId, profileName) { 1740 1741 if (this.options.userSignedIn == "false") { 1742 // User not signed in. Add spot to the local profile 1743 var profile = new WFLocalProfile(this.options.tokenDomain); 1744 1745 //typeId, favSpotId, spotId, lat, lon 1746 var favSpot = new WFFavoriteSpot(this.spotType, null, spotId, null, null); 1747 profile.addFavSpot(favSpot); 1748
1749 this.reloadPageOnClose = true; 1750 1751 $("#wfmodal-td-" + profileId).empty(); 1752 $("#wfmodal-td-" + profileId).append("<div onclick='javascript:wfModalManager.doRemoveSpotFromProfile(\"" + spotId + "\",null,\"" + profileId + "\",\"" + escape(profileName) + "\")' class='wfmodal-favorite-yellow' id='" + profileId + "' title='Remove from " + profileName + "'></div>"); 1753 1754 // Update the page title 1755 $(".wf-modal-title").html(this.nameField + " added to " + profileName); 1756 1757 } else { 1758 var myself = this; 1759 var ps = new WFProfileService({ "baseURL": this.options.baseURL, "token": this.options.token }); 1760 1761 profileName = unescape(profileName); 1762 1763 var urlData = { 1764 "profile_id": profileId, 1765 "spot_id": spotId, 1766 "spot_types": this.spotType 1767 }; 1768 1769 ps.addSpotToProfile(urlData, function (data) { 1770 if (data.status_code == 0) { 1771 var newFavSpotId = data.status_message; 1772 1773 myself.reloadPageOnClose = true; 1774 1775 $("#wfmodal-td-" + profileId).empty(); 1776 $("#wfmodal-td-" + profileId).append("<div onclick='javascript:wfModalManager.doRemoveSpotFromProfile(\"" + spotId + "\",\"" + newFavSpotId + "\",\"" + profileId + "\",\"" + escape(profileName) + "\")' class='wfmodal-favorite-yellow' id='" + profileId + "' title='Remove from " + profileName + "'></div>"); 1777 1778 // Update the page title 1779 $(".wf-modal-title").html(myself.nameField + " added to " + profileName); 1780 1781 _gaq.push(['_trackEvent', 'Favorite', 'Add', myself.nameField + " " + spotId]); 1782 } 1783 }); 1784 } 1785 1786} 1787 1788// Remove Spot From Profile 1789WFModalManager.prototype.doRemoveSpotFromProfile = function (spotId, favSpotId, profileId, profileName) { 1790 profileName = unescape(profileName); 1791 1792 1793 if (this.options.userSignedIn == "false") { 1794 // User not signed in. Removespot from the local profile 1795 var profile = new WFLocalProfile(this.options.tokenDomain); 1796 1797 //typeId, favSpotId, spotId, lat, lon 1798 //var favSpot = new WFFavoriteSpot(null, null, spotId, null, null); 1799 var favSpot = profile.getSpotById(spotId); 1800 1801 if (profile.removeFavSpot(favSpot)) { 1802 this.reloadPageOnClose = true; 1803 $("#wfmodal-td-" + profileId).empty(); 1804 $("#wfmodal-td-" + profileId).append("<div onclick='javascript:wfModalManager.doAddSpotToProfile(\"" + spotId + "\",\"" + profileId + "\",\"" + escape(profileName) + "\")' class='wfmodal-favorite' id='" + profileId + "' title='Add to " + profileName + "'></div>"); 1805 // Update the page title 1806 $(".wf-modal-title").html(this.nameField + " removed from " + profileName); 1807 } 1808 } else { 1809 var url = this.options.baseURL + "/profile/removeSpotFromProfile?callback=?"; 1810 var urldata = new Object(); 1811 urldata.wf_token = this.options.token; 1812 urldata.fav_spot_id = favSpotId; 1813 urldata.profile_id = profileId; 1814 1815 var myself = this; 1816 this.jqRequest = $.getJSON(url, urldata, function (data, textStatus, jqXHR) { 1817 if (data.status_code == 0) { 1818 myself.reloadPageOnClose = true; 1819 $("#wfmodal-td-" + profileId).empty(); 1820 $("#wfmodal-td-" + profileId).append("<div onclick='javascript:wfModalManager.doAddSpotToProfile(\"" + spotId + "\",\"" + profileId + "\",\"" + escape(profileName) + "\")' class='wfmodal-favorite' id='" + profileId + "' title='Add to " + profileName + "'></div>"); 1821 _gaq.push(['_trackEvent', 'Favorite', 'Remove', myself.nameField + " " + spotId]); 1822 1823 // Update the page title 1824 $(".wf-modal-title").html(myself.nameField + " removed from " + profileName); 1825 } 1826 }, "json"); 1827 } 1828} 1829 1830 1831//////////////////////////////////////////////////////////////////////////////// 1832// Add Profile - Click Event Handlers 1833//////////////////////////////////////////////////////////////////////////////// 1834// Add Profile 1835WFModalManager.prototype.doAddProfileAction = function () { 1836 var newProfileName = $("#wfmodal-profile-name").val(); 1837 1838 var myself = this; 1839 wfProfileManager.createNewProfile(newProfileName, function callback(createNewProfileStatusCode) { 1840 // Send to next step 1841 if (myself.currentActivity == "addcontainertoprofile") { 1842 myself.addContainerToProfileStep2(); 1843 } 1844 else if (myself.currentActivity == "addspottoprofile") { 1845 myself.addSpotToProfile(myself.spotId, myself.nameField, myself.spotType); 1846 } 1847 else if (myself.currentActivity == "addarbitraryspottoprofile") { 1848 myself.addArbitrarySpotToProfileStep2(); 1849 } 1850 else { 1851 if (createNewProfileStatusCode == 0) { 1852 myself.displayAlert("Create Profile", "The profile was created."); 1853 } 1854 else { 1855 myself.displayAlert("Create Profile", "There was an error while creating the profile."); 1856 } 1857 } 1858 }); 1859} 1860 1861WFModalManager.prototype.doRenameProfileAction = function () { 1862 var profileId = $(this.renameProfileModal).attr("data-profile-id"); 1863 var newProfileName = $("#wfmodal-profile-new-name").val(); 1864 var myself = this; 1865 1866 wfProfileManager.renameProfile(profileId, newProfileName, function callback(createNewProfileStatusCode) { 1867 if (createNewProfileStatusCode == 0) { 1868 myself.displayAlert("Rename Profile", "The profile was renamed."); 1869 } 1870 else { 1871 myself.displayAlert("Rename Profile", "There was an error while renaming the profile."); 1872 } 1873 }); 1874} 1875 1876// Cancel Add Profile 1877WFModalManager.prototype.doCancelAddProfileAction = function () { 1878 if (this.currentActivity == "addcontainertoprofile") { 1879 this.addContainerToProfileStep2(); 1880 } 1881 else if (this.currentActivity == "addspottoprofile") { 1882 this.addSpotToProfile(this.spotId, this.nameField, this.spotType); 1883 } 1884 else if (this.currentActivity == "addarbitraryspottoprofile") { 1885 this.addArbitrarySpotToProfileStep2(); 1886 } 1887} 1888 1889// saveContainerToNewProfile 1890WFModalManager.prototype.doSaveContainerToNewProfile = function () { 1891 this.addContainerToProfile(this.nameField, this.containerTypeIdField, this.optionsField); 1892} 1893
1894////////////////////////////////////////////////////////////////////////////// 1895// Other 1896////////////////////////////////////////////////////////////////////////////// 1897WFModalManager.prototype.createModal = function (settings) { 1898 var div = document.createElement("div"); 1899 var wrapper = document.createElement("div"); 1900 var body = document.createElement("div"); 1901 var buttons = document.createElement("div"); 1902 var header = this.createModalHeader(settings.title); 1903 1904 div.className = "wf-modal"; 1905 div.setAttribute("id", settings.id); 1906 1907 buttons.className = "wf-modal-buttons clearfix"; 1908 if (settings.hasOwnProperty("buttons") && settings.buttons) { 1909 for (var x = 0; x < settings.buttons.length; x++) { 1910 buttons.appendChild(settings.buttons[x]); 1911 } 1912 } 1913 1914 body.className = "wf-modal-body clearfix"; 1915 body.innerHTML = settings.body; 1916 1917 wrapper.className = "wf-modal-content"; 1918 wrapper.appendChild(header); 1919 wrapper.appendChild(body); 1920 wrapper.appendChild(buttons); 1921 1922 if (settings.hasOwnProperty("extras") && settings.extras) { 1923 var extras = document.createElement("div"); 1924 extras.className = "wf-modal-extras"; 1925 extras.innerHTML = settings.extras; 1926 1927 wrapper.appendChild(extras); 1928 } 1929 1930 if (settings.hasOwnProperty("footer") && settings.footer) { 1931 var footer = document.createElement("div"); 1932 footer.className = "wf-modal-footer"; 1933 footer.innerHTML = settings.footer; 1934 1935 wrapper.appendChild(footer); 1936 } 1937 1938 div.appendChild(wrapper); 1939 1940 return div; 1941} 1942 1943WFModalManager.prototype.createButton = function (id, classId, href, label) { 1944 var btn = document.createElement("button"); 1945 if (id) { 1946 btn.id = id; 1947 } 1948 btn.className = classId; 1949 btn.innerHTML = label; 1950 1951 return btn; 1952} 1953 1954WFModalManager.prototype.setModalTitle = function (title, modalId) { 1955 $("#" + modalId + " .wf-modal-title").empty().append(title); 1956} 1957 1958WFModalManager.prototype._attachEventHandlers = function () { 1959 var self = this; 1960 1961 $(".wf-modal-content").on("touchend click", function (e) { 1962 e.stopPropagation(); 1963 1964 return false; 1965 }); 1966 1967 $(".wf-modal-body a, .wf-modal-extras a, .wf-modal-body input, .wf-modal #wfmodal-profile-list").on("touchend click", function (e) { 1968 e.stopPropagation(); 1969 }); 1970 1971 $(".wf-modal-close").on("touchend click", function (e) { 1972 self.close(); 1973 }); 1974 1975 $(".wf-modal").on("touchend click", function (e) { 1976 var modalOpen = $("html").hasClass("modal-open"); 1977 1978 if (modalOpen) { 1979 self.close(); 1980 } 1981 }); 1982} 1983 1984WFModalManager.prototype.open = function (id) { 1985 this.scrollTop = $("body").scrollTop(); 1986 this.openModalId = id; 1987 1988 // Close any open modals 1989 $(".wf-modal").hide(); 1990 1991 $("html").addClass("modal-open"); 1992 $("#" + id).show(); 1993} 1994 1995WFModalManager.prototype.close = function () { 1996 if (this.openModalId) { 1997 $("html").removeClass("modal-open"); 1998 1999 if (this.options.isMobile && this.scrollTop) { 2000 $("body").scrollTop(this.scrollTop); 2001 } 2002 2003 $("#" + this.openModalId).hide(); 2004 2005 this.openModalId = null; 2006 this.scrollTop = null; 2007 2008 if (this.reloadPageOnClose) { 2009 location.reload(); 2010 } else { 2011 if (typeof wfProfileManager === "undefined") return; 2012 2013 wfProfileManager.loadProfiles(); 2014 } 2015 } 2016} 2017 2018// 2019WFModalManager.prototype.debug = function () { 2020 console.debug("this.member_level=" + this.memberLevel); 2021 console.debug("this.show_ads=" + this.showAds); 2022 console.debug("this.show_ads_toggle=" + this.showAdsToggle); 2023 console.debug("this.default_ads_toggle_state=" + this.defaultAdsToggleState); 2024 console.debug("this.trial_end_date=" + this.trialEndDate); 2025 2026 console.debug("this.nameField=" + this.nameField); 2027 console.debug("this.containerId=" + this.containerId); 2028 console.debug("this.containerTypeIdField=" + this.containerTypeIdField); 2029 console.debug("this.profileNameField=" + this.profileNameField); 2030 console.debug("this.currentActivity=" + this.currentActivity); 2031 // console.debug("spotId="+spotId); 2032 console.debug("spotType=" + this.spotType); 2033 console.debug("this.spotLat=" + this.spotLat); 2034 console.debug("this.spotLon=" + this.spotLon); 2035 console.debug("this.favSpotId=" + this.favSpotId);
2036 console.debug("this.reloadPageOnClose=" + this.reloadPageOnClose); 2037 console.debug("this.profileId=" + this.profileId); 2038} 2039 2040 2041///////////////////////////////////////////////////////////////////////////////////////// 2042///////////////////////////////////////////////////////////////////////////////////////// 2043///////////////////////////////////////////////////////////////////////////////////////// 2044// WFModalManager - END 2045///////////////////////////////////////////////////////////////////////////////////////// 2046///////////////////////////////////////////////////////////////////////////////////////// 2047///////////////////////////////////////////////////////////////////////////////////////// 2048 2049///////////////////////////////////////////////////////////////////////////////////////// 2050///////////////////////////////////////////////////////////////////////////////////////// 2051// WFProfileManager 2052// - Data store for getProfiles (profile set with containers and favorite spots) 2053// - Useful functions for getting profile data 2054// - Functions for adding things (spots, containers) to profiles 2055///////////////////////////////////////////////////////////////////////////////////////// 2056///////////////////////////////////////////////////////////////////////////////////////// 2057 2058///////////////////////////////////////////////////////////////////////////////////////// 2059///////////////////////////////////////////////////////////////////////////////////////// 2060// profiles definition 2061// 2062// profiles: [ 2063// { 2064// activity: "Kite" 2065// views: 2 2066// alerts_enabled: "true" 2067// created_by: "jforare" 2068// master: "false" 2069// my_profile: "true" 2070// name: "Vacation Spots" 2071// profile_id: 124097 2072// containers: [ 2073// { 2074// container_id: 20543 2075// container_type_id: "Favorite Spots" 2076// container_name: "Favorite Spots" 2077// options: "" 2078// } 2079// ] 2080// favorite_spots: [ 2081// { 2082// type_id: 1 2083// fav_spot_id: 287303 2084// spot_id: 53616 2085// } 2086// ] 2087// } 2088// ] 2089///////////////////////////////////////////////////////////////////////////////////////// 2090///////////////////////////////////////////////////////////////////////////////////////// 2091 2092 2093///////////////////////////////////////////////////////////////////////////////////////// 2094///////////////////////////////////////////////////////////////////////////////////////// 2095// WFModelDataSet - Constructor 2096// - Empty constructor so you can put into page scope early and initialize later 2097///////////////////////////////////////////////////////////////////////////////////////// 2098///////////////////////////////////////////////////////////////////////////////////////// 2099function WFProfileManager(options) { 2100 this.default_args = { 2101 "activeProfileId": 0, 2102 "baseURL": "https://api.weatherflow.com/wxengine/rest", // Weather Engine baseurl - client might want to change to staging 2103 "cad": null, 2104 "token": "", 2105 "tokenDomain": null, 2106 "userSignedIn": false 2107 }; 2108 2109 this.options = options; 2110 2111 this.profiles; // raw profiles array object from getProfiles(); 2112 this.relevantProfiles; // row profiles array object from getRelevantProfiles(); 2113 this.profilesLoaded = false; 2114 this.relevantProfilesLoaded = false; 2115 this.profileCount = -1; 2116 this.userLat = null; 2117 this.userLon = null; 2118 this.loadAllEventFired = false; 2119 2120 // set options - use default_args if not passed in options var 2121 for (var index in this.default_args) { 2122 if (typeof this.options[index] == "undefined") { 2123 this.options[index] = this.default_args[index]; 2124 } 2125 } 2126 2127} 2128 2129 2130///////////////////////////////////////////////////////////////////////////////////////// 2131// init 2132// - load profiles 2133///////////////////////////////////////////////////////////////////////////////////////// 2134WFProfileManager.prototype.init = function () { 2135 this.loadProfiles(); 2136} 2137 2138 2139// Allows client to ask if the profiles have loaded 2140WFProfileManager.prototype.profilesLoaded = function () { 2141 return this.profilesLoaded; 2142} 2143 2144 2145WFProfileManager.prototype.loadProfiles = function () { 2146 2147 if (this.options.userSignedIn == "true") { 2148 var url = this.options.baseURL + "/profile/getProfiles?callback=?"; 2149 var urldata = new Object(); 2150 urldata.wf_token = this.options.token; 2151 if (this.options.cad != null) { 2152 urldata.cad = this.options.cad; 2153 } 2154 2155 var myself = this; 2156 this.jqRequest = $.getJSON(url, urldata, function (data, textStatus, jqXHR) { 2157 if (data.status.status_code == 0) { 2158 myself.profiles = data.profiles; 2159 myself.profilesLoaded = true; 2160 2161 myself.profileCount = data.profiles.length; 2162 2163 // Profiles are loaded. Trigger the client event 2164 $("body").trigger("profiles_loaded"); 2165 2166 // Trigger the all_profiles_loaded event if the relevant profiles have already loaded 2167 if (myself.relevantProfilesLoaded && !myself.loadAllEventFired) { 2168 myself.loadAllEventFired = true; 2169 $("body").trigger("all_profiles_loaded"); 2170 } 2171 } 2172 2173 // Sync any local profiles 2174 myself.syncLocalProfile(); 2175 }, "json"); 2176 2177 } else { 2178 // User not signed in. Load or create their local profile 2179 //var data = undefined; 2180 2181 //data = this.getLocalProfile(); 2182 var localProfile = new WFLocalProfile(this.options.tokenDomain); 2183 2184 if (localProfile != undefined) { 2185 this.profiles = localProfile.profiles; 2186 this.profilesLoaded = true; 2187 this.profileCount = 1; 2188 2189 // Profiles are loaded. Trigger the client event 2190 $("body").trigger("profiles_loaded"); 2191 2192 // Trigger the all_profiles_loaded event if the relevant profiles have already loaded 2193 if (this.relevantProfilesLoaded && !this.loadAllEventFired) { 2194 this.loadAllEventFired = true; 2195 $("body").trigger("all_profiles_loaded"); 2196 } 2197 } 2198 } 2199} 2200 2201WFProfileManager.prototype.loadRelevantProfiles = function (bounds, primaryActivity) { 2202 var url = this.options.baseURL + "/profile/getRelevantProfiles?callback=?"; 2203 var urldata = new Object(); 2204 urldata.wf_token = this.options.token; 2205 urldata.num_per_page = 20; 2206 urldata.activity = primaryActivity; 2207 if (this.options.cad != null) { 2208 urldata.cad = this.options.cad; 2209 } 2210 2211 // TODO: Add geolocation hook if the bounds aren't set 2212 2213 // Add the bounds if provided by the client 2214 if (bounds) {
2215 urldata.lat_min = bounds.getSouthWest().lat(); 2216 urldata.lon_min = bounds.getSouthWest().lng(); 2217 urldata.lon_max = bounds.getNorthEast().lng(); 2218 urldata.lat_max = bounds.getNorthEast().lat(); 2219 } 2220 2221 var myself = this; 2222 this.jqRequest = $.getJSON(url, urldata, function (data, textStatus, jqXHR) { 2223 2224 myself.relevantProfiles = data.profiles; 2225 myself.relevantProfilesLoaded = true; 2226 2227 // Trigger the all_profiles_loaded event if the user's profiles have already loaded 2228 if (myself.profilesLoaded) { 2229 if (!myself.loadAllEventFired) { 2230 myself.loadAllEventFired = true; 2231 $("body").trigger("all_profiles_loaded"); 2232 } else { 2233 $("body").trigger("relevant_profiles_loaded"); 2234 } 2235 } 2236 }, "json"); 2237} 2238 2239///////////////////////////////////////////////////////////////////////////////////////// 2240// Setters/Getters 2241///////////////////////////////////////////////////////////////////////////////////////// 2242WFProfileManager.prototype.setProfiles = function (newProfilesObject) { 2243 this.profiles = newProfilesObject; 2244 this.profilesLoaded = true; 2245} 2246 2247WFProfileManager.prototype.getProfiles = function () { 2248 return this.profiles; 2249} 2250 2251 2252WFProfileManager.prototype.getRelevantProfiles = function () { 2253 return this.relevantProfiles; 2254} 2255 2256 2257WFProfileManager.prototype.getProfileCount = function () { 2258 if (this.profilesLoaded) { 2259 return this.profileCount; 2260 } 2261 else { 2262 return -1; 2263 } 2264} 2265 2266WFProfileManager.prototype.getProfileDisplayName = function (profileName) { 2267 if (profileName.length > 35) { 2268 return profileName.substring(0, 35) + "..."; 2269 } else { 2270 return profileName; 2271 } 2272} 2273 2274WFProfileManager.prototype.isSpotIdInAnyProfile = function (spotIdToFind) { 2275 var spotFound = false; 2276 2277 if (this.profilesLoaded) { 2278 $.each(this.profiles, function (i, profile) { 2279 $.each(profile.favorite_spots, function (j, favorite_spot) { 2280 if (favorite_spot.spot_id == spotIdToFind) { 2281 spotFound = true; 2282 } 2283 }); 2284 }); 2285 } 2286 return spotFound; 2287} 2288 2289 2290WFProfileManager.prototype.isSpotIdInProfile = function (spotIdToFind, profileIdToLookIn) { 2291 var spotFound = false; 2292 $.each(this.profiles, function (i, profile) { 2293 if (profile.profile_id == profileIdToLookIn) { 2294 $.each(profile.favorite_spots, function (j, favorite_spot) { 2295 if (favorite_spot.spot_id == spotIdToFind) { 2296 spotFound = true; 2297 } 2298 }); 2299 } 2300 }); 2301 return spotFound; 2302} 2303 2304 2305WFProfileManager.prototype.getFavSpotIdForSpotIdInProfile = function (spotIdToFind, profileIdToLookIn) { 2306 var returnFavSpotId = -1; 2307 $.each(this.profiles, function (i, profile) { 2308 if (profile.profile_id == profileIdToLookIn) { 2309 $.each(profile.favorite_spots, function (j, favorite_spot) { 2310 if (favorite_spot.spot_id == spotIdToFind) { 2311 returnFavSpotId = favorite_spot.fav_spot_id; 2312 } 2313 }); 2314 } 2315 }); 2316 return returnFavSpotId; 2317} 2318 2319WFProfileManager.prototype.getFavSpotIdForLatLonInProfile = function (lat, lon, profileIdToLookIn) { 2320 var returnFavSpotId = -1; 2321 2322 $.each(this.profiles, function (i, profile) { 2323 if (profile.profile_id == profileIdToLookIn) { 2324 $.each(profile.favorite_spots, function (j, favorite_spot) { 2325 if (favorite_spot.lat == lat && favorite_spot.lon == lon) { 2326 returnFavSpotId = favorite_spot.fav_spot_id; 2327 return false; // break the loop 2328 } 2329 }); 2330 } 2331 if (returnFavSpotId > -1) { 2332 return false; // break the loop 2333 } 2334 }); 2335 return returnFavSpotId; 2336} 2337 2338WFProfileManager.prototype.isFavSpotIdInAnyProfile = function (favSpotIdToFind) { 2339 var spotFound = false; 2340 $.each(this.profiles, function (i, profile) { 2341 $.each(profile.favorite_spots, function (j, favorite_spot) { 2342 if (favorite_spot.fav_spot_id == favSpotIdToFind) { 2343 spotFound = true; 2344 } 2345 }); 2346 }); 2347 return spotFound; 2348} 2349 2350 2351WFProfileManager.prototype.isFavSpotIdInProfile = function (favSpotIdToFind, profileIdToLookIn) { 2352 var spotFound = false;
2353 2354 $.each(this.profiles, function (i, profile) { 2355 if (profile.profile_id == profileIdToLookIn) { 2356 $.each(profile.favorite_spots, function (j, favorite_spot) { 2357 if (favorite_spot.fav_spot_id == favSpotIdToFind) { 2358 spotFound = true; 2359 } 2360 }); 2361 } 2362 }); 2363 return spotFound; 2364} 2365 2366WFProfileManager.prototype.isLatLonInAnyProfile = function (lat, lon) { 2367 var spotFound = false; 2368 2369 $.each(this.profiles, function (i, profile) { 2370 $.each(profile.favorite_spots, function (j, favorite_spot) { 2371 if (favorite_spot.lat == lat && favorite_spot.lon == lon) { 2372 spotFound = true; 2373 return false; // break the loop 2374 } 2375 }); 2376 if (spotFound) { 2377 return false; // break the loop 2378 } 2379 }); 2380 2381 return spotFound; 2382} 2383 2384WFProfileManager.prototype.isLatLonInProfile = function (lat, lon, profileIdToLookIn) { 2385 var spotFound = false; 2386 $.each(this.profiles, function (i, profile) { 2387 if (profile.profile_id == profileIdToLookIn) { 2388 $.each(profile.favorite_spots, function (j, favorite_spot) { 2389 if (favorite_spot.lat == lat && favorite_spot.lon == lon) { 2390 spotFound = true; 2391 return false; 2392 } 2393 }); 2394 } 2395 }); 2396 return spotFound; 2397} 2398 2399WFProfileManager.prototype.isProfileFavorited = function (profileIdToFind) { 2400 if (this.profilesLoaded) { 2401 var profileFound = false; 2402 $.each(this.profiles, function (i, profile) { 2403 if (profile.profile_id == profileIdToFind) { 2404 profileFound = true; 2405 return true; // break out of the loop 2406 } 2407 }); 2408 return profileFound; 2409 } else { 2410 // Profiles have not loaded yet 2411 return false; 2412 } 2413} 2414 2415 2416 2417WFProfileManager.prototype.createNewProfile = function (newProfileName, callback) { 2418 var url = this.options.baseURL + "/profile/addProfile?callback=?"; 2419 var urldata = new Object(); 2420 urldata.wf_token = this.options.token; 2421 urldata.name = newProfileName; 2422 if (this.options.cad != null) { 2423 urldata.cad = this.options.cad; 2424 } 2425 2426 var myself = this; 2427 this.jqRequest = $.getJSON(url, urldata, function (data, textStatus, jqXHR) { 2428 // Step 1 - addProfile 2429 if (data.status_code == 0) { 2430 myself.loadProfiles(); 2431 2432 if (callback) { 2433 callback(data.status_code); 2434 } 2435 } 2436 else { 2437 if (callback) { 2438 callback(data.status_code); 2439 }; 2440 } 2441 }, "json"); // end Step 1 - addProfile 2442} 2443 2444WFProfileManager.prototype.deleteProfile = function (profileId, callback) { 2445 if (profileId) { 2446 var url = this.options.baseURL + "/profile/deleteProfile?callback=?"; 2447 var urldata = new Object(); 2448 urldata.wf_token = this.options.token; 2449 urldata.profile_id = profileId; 2450 2451 var myself = this; 2452 this.jqRequest = $.getJSON(url, urldata, function (data, textStatus, jqXHR) { 2453 if (data.status_code == 0) { 2454 // Update the profile list 2455 myself.loadProfiles(); 2456 } 2457 if (callback) { 2458 callback(data.status_code); 2459 } 2460 }, "json"); 2461 } else { 2462 // Profile Id not passed 2463 if (callback) { 2464 callback(-1); 2465 } 2466 } 2467} 2468 2469WFProfileManager.prototype.addFavoriteProfile = function (profileId, primaryActivity, callback) { 2470 2471 if (profileId > 0) { 2472 var url = this.options.baseURL + "/profile/addFavoriteProfile?callback=?"; 2473 var urldata = new Object(); 2474 urldata.wf_token = this.options.token; 2475 urldata.profile_id = profileId; 2476 urldata.activity = primaryActivity; 2477 if (this.options.cad != null) { 2478 urldata.cad = this.options.cad; 2479 } 2480 2481 var myself = this; 2482 this.jqRequest = $.getJSON(url, urldata, function (data, textStatus, jqXHR) { 2483 if (callback) { 2484 if (data.status_code == 0) { 2485 // Update the profile list 2486 myself.loadProfiles(); 2487 } 2488 if (callback) { 2489 callback(data.status_code); 2490 } 2491 } 2492 }, "json"); 2493 } else { 2494 // Invalid profileId supplied 2495 if (callback) { 2496 callback(-1); 2497 } 2498 } 2499 2500} 2501 2502WFProfileManager.prototype.removeFavoriteProfile = function (profileId, primaryActivity, callback) { 2503 2504 if (profileId > 0) { 2505 var url = this.options.baseURL + "/profile/removeFavoriteProfile?callback=?"; 2506 var urldata = new Object(); 2507 urldata.wf_token = this.options.token; 2508 urldata.profile_id = profileId; 2509 urldata.activity = primaryActivity; 2510 if (this.options.cad != null) { 2511 urldata.cad = this.options.cad; 2512 } 2513 2514 var myself = this; 2515 this.jqRequest = $.getJSON(url, urldata, function (data, textStatus, jqXHR) { 2516 if (data.status_code == 0) { 2517 // Update the profile list 2518 myself.loadProfiles(); 2519 } 2520 if (callback) { 2521 callback(data.status_code); 2522 } 2523 }, "json"); 2524 } else { 2525 // Invalid profileId supplied 2526 if (callback) { 2527 callback(-1); 2528 } 2529 } 2530 2531} 2532 2533WFProfileManager.prototype.replicateProfile = function (profileId, newName, primaryActivity, callback) { 2534 if (profileId) { 2535 var url = this.options.baseURL + "/profile/copyProfile?callback=?"; 2536 var urldata = new Object(); 2537 urldata.wf_token = this.options.token; 2538 urldata.profile_id = profileId; 2539 urldata.name = newName; 2540 urldata.activity = primaryActivity; 2541 if (this.options.cad != null) { 2542 urldata.cad = this.options.cad; 2543 } 2544 2545 var myself = this; 2546 this.jqRequest = $.getJSON(url, urldata, function (data, textStatus, jqXHR) { 2547 if (data.status_code == 0) { 2548 // Update the profile list 2549 myself.loadProfiles(); 2550 } 2551 if (callback) { 2552 callback(data); 2553 } 2554 }, "json"); 2555 2556 } else { 2557 if (callback) { 2558 callback(-1); 2559 } 2560 } 2561} 2562 2563WFProfileManager.prototype.renameProfile = function (profileId, newName, callback) { 2564 if (profileId) { 2565 var url = this.options.baseURL + "/profile/updateProfile?callback=?"; 2566 var urldata = new Object(); 2567 urldata.wf_token = this.options.token; 2568 urldata.profile_id = profileId; 2569 urldata.name = newName; 2570 2571 if (this.options.cad != null) { 2572 urldata.cad = this.options.cad; 2573 } 2574 2575 var myself = this; 2576 this.jqRequest = $.getJSON(url, urldata, function (data, textStatus, jqXHR) { 2577 if (data.status_code == 0) { 2578 // Update the profile list 2579 myself.loadProfiles(); 2580 } 2581 if (callback) { 2582 callback(data.status_code); 2583 } 2584 }, "json"); 2585 } else { 2586 if (callback) { 2587 callback(-1); 2588 } 2589 } 2590} 2591 2592WFProfileManager.prototype.sortProfiles = function (profileIdList, callback) { 2593 if (profileIdList) { 2594 var url = this.options.baseURL + "/profile/sortProfiles?callback=?"; 2595 var urldata = new Object(); 2596 urldata.wf_token = this.options.token; 2597 urldata.profile_id_list = profileIdList.toString(); 2598 2599 var myself = this; 2600 this.jqRequest = $.getJSON(url, urldata, function (data, textStatus, jqXHR) { 2601 // Update the profile list 2602 myself.loadProfiles(); 2603 2604 if (callback) { 2605 callback(); 2606 } 2607 2608 }, "json"); 2609 2610 } else {
2611 // profileIdList is invalid 2612 if (callback) { 2613 callback(-1); 2614 } 2615 } 2616} 2617 2618WFProfileManager.prototype.syncLocalProfile = function () { 2619 var profile = new WFLocalProfile(this.options.tokenDomain); 2620 2621 if (this.options.activeProfileId != undefined && this.options.activeProfileId > 0) { 2622 this.syncLocalSpots(this.options.activeProfileId, profile); 2623 this.syncLocalContainers(this.options.activeProfileId, profile); 2624 } 2625} 2626 2627WFProfileManager.prototype.syncLocalContainers = function (activeProfileId, profile) { 2628 var localContainers = profile.profiles[0].containers; 2629 2630 for (var x = 0; x < localContainers.length; x++) { 2631 if (localContainers[x].container_type_id != "Favorite Spots") { 2632 this.addLocalContainerToProfile(localContainers[x], activeProfileId, function (data, ctn) { 2633 profile.removeContainer(ctn.container_id); 2634 }); 2635 } 2636 } 2637} 2638 2639WFProfileManager.prototype.syncLocalSpots = function (activeProfileId, profile) { 2640 var localSpots = profile.profiles[0].favorite_spots; 2641 2642 for (var x = 0; x < localSpots.length; x++) { 2643 this.addLocalSpotToProfile(localSpots[x], activeProfileId, function (data, spot) { 2644 profile.removeFavSpot(spot); 2645 }); 2646 } 2647} 2648 2649WFProfileManager.prototype.addLocalContainerToProfile = function (ctn, profileId, callback) { 2650 var url = this.options.baseURL + "/profile/addContainerToProfile?callback=?"; 2651 var urldata = new Object(); 2652 urldata.wf_token = this.options.token; 2653 urldata.options = ctn.options; 2654 urldata.name = ctn.container_name; 2655 urldata.profile_id = profileId; 2656 urldata.container_type_id = ctn.container_type_id; 2657 2658 var myself = this; 2659 var profile = new WFLocalProfile(this.options.tokenDomain); 2660 2661 this.jqRequest = $.getJSON(url, urldata, function (data, textStatus, jqXHR) { 2662 if (callback) { 2663 callback(data, ctn); 2664 } 2665 }, "json"); 2666 2667} 2668 2669WFProfileManager.prototype.addLocalSpotToProfile = function (spot, profileId, callback) { 2670 var url = this.options.baseURL + "/profile/addSpotToProfile?callback=?"; 2671 var urldata = new Object(); 2672 urldata.wf_token = this.options.token; 2673 urldata.profile_id = profileId; 2674 urldata.spot_types = spot.type_id; 2675 if (spot.type_id == 101) { 2676 urldata.lat = spot.lat; 2677 urldata.lon = spot.lon; 2678 urldata.name = "Virtual Station (" + spot.lat.toFixed(2) + ", " + spot.lon.toFixed(2) + ")"; 2679 } else { 2680 urldata.spot_id = spot.spot_id; 2681 } 2682 2683 var myself = this; 2684 this.jqRequest = $.getJSON(url, urldata, function (data, textStatus, jqXHR) { 2685 if (callback) { 2686 callback(data, spot); 2687 } 2688 }, "json"); 2689 2690} 2691 2692WFProfileManager.prototype.isLocalProfileEmpty = function () { 2693 var localProfile = new WFLocalProfile(this.options.tokenDomain); 2694 2695 return localProfile.isEmpty(); 2696} 2697 2698///////////////////////////////////////////////////////////////////////////////////////// 2699///////////////////////////////////////////////////////////////////////////////////////// 2700///////////////////////////////////////////////////////////////////////////////////////// 2701// WFProfileManager - END 2702///////////////////////////////////////////////////////////////////////////////////////// 2703///////////////////////////////////////////////////////////////////////////////////////// 2704///////////////////////////////////////////////////////////////////////////////////////// 2705 2706function WFProfileService(options) { 2707 2708 this.default_args = { 2709 "baseURL": "https://api.weatherflow.com/wxengine/rest", // Weather Engine baseurl - client might want to change to staging 2710 "primaryActivity": "", 2711 "token": "", 2712 "unitsWind": "mph", 2713 "unitsTemp": "f", 2714 "unitsHeight": "ft" 2715 }; 2716 2717 this.options = options; 2718 2719 // set options - use default_args if not passed in options var 2720 for (var index in this.default_args) { 2721 if (typeof this.options[index] == "undefined") { 2722 this.options[index] = this.default_args[index]; 2723 } 2724 } 2725} 2726 2727WFProfileService.prototype.addSpotToProfile = function (args, callback) { 2728 var url = this.options.baseURL + "/profile/addSpotToProfile?callback=?"; 2729 var urlData = this.setArgs(args); 2730 2731 urlData.wf_token = this.options.token; 2732 2733 $.getJSON(url, urlData, function (data) { 2734 if (callback) { 2735 callback(data); 2736 } 2737 }); 2738} 2739 2740WFProfileService.prototype.addContainerToProfile = function (args, callback) { 2741 var url = this.options.baseURL + "/profile/addContainerToProfile?callback=?"; 2742 var urlData = this.setArgs(args); 2743 2744 urlData.wf_token = this.options.token; 2745 2746 $.getJSON(url, urlData, function (data) { 2747 if (callback) { 2748 callback(data); 2749 } 2750 }); 2751} 2752 2753WFProfileService.prototype.setArgs = function (args) { 2754 var urlData = new Object(); 2755 2756 for (var index in args) { 2757 urlData[index] = args[index]; 2758 } 2759 2760 return urlData; 2761} 2762function WFLocalProfile(tokenDomain) { 2763 this.status = { "status_code": 0, "status_message": "Success" }; 2764 this.profiles = []; 2765 this.tokenDomain = tokenDomain; 2766 2767 this.getLocalProfile(); 2768} 2769 2770WFLocalProfile.prototype.addFavSpot = function (spot) { 2771 // Create a local fav spot id 2772 spot.fav_spot_id = this.profiles[0].favorite_spots.length + 1; 2773 2774 this.profiles[0].favorite_spots.push(spot); 2775 this.saveLocalProfile(); 2776 2777 return spot.fav_spot_id; 2778} 2779 2780WFLocalProfile.prototype.removeFavSpot = function (spot) { 2781 var profile = this.profiles[0]; 2782 var retVal = false;
2783 2784 if (spot.spot_id != null) { 2785 for (var x = 0; x < profile.favorite_spots.length; x++) { 2786 var item = profile.favorite_spots[x]; 2787 2788 if (spot.spot_id == item.spot_id) { 2789 profile.favorite_spots.splice(x, 1); 2790 retVal = true; 2791 } 2792 } 2793 } else { 2794 // Arb spot 2795 for (var x = 0; x < profile.favorite_spots.length; x++) { 2796 var item = profile.favorite_spots[x]; 2797 2798 if (spot.lat == item.lat && spot.lon == item.lon) { 2799 profile.favorite_spots.splice(x, 1); 2800 retVal = true; 2801 } 2802 } 2803 } 2804 this.saveLocalProfile(); 2805 2806 return retVal; 2807} 2808 2809WFLocalProfile.prototype.getSpotById = function (spotId) { 2810 var spot = null; 2811 2812 for (var x = 0; x < this.profiles[0].favorite_spots.length; x++) { 2813 if (this.profiles[0].favorite_spots[x].spot_id == spotId) { 2814 spot = this.profiles[0].favorite_spots[x]; 2815 break; 2816 } 2817 } 2818 2819 return spot; 2820} 2821 2822WFLocalProfile.prototype.getSpotByFavId = function (favId) { 2823 var spot = null; 2824 2825 for (var x = 0; x < this.profiles[0].favorite_spots.length; x++) { 2826 if (this.profiles[0].favorite_spots[x].fav_spot_id == favId) { 2827 spot = this.profiles[0].favorite_spots[x]; 2828 break; 2829 } 2830 } 2831 2832 return spot; 2833} 2834 2835WFLocalProfile.prototype.getSpotByLatLon = function (lat, lon) { 2836 var spot = null; 2837 2838 for (var x = 0; x < this.profiles[0].favorite_spots.length; x++) { 2839 if (this.profiles[0].favorite_spots[x].lat == lat && this.profiles[0].favorite_spots[x].lon == lon) { 2840 spot = this.profiles[0].favorite_spots[x]; 2841 break; 2842 } 2843 } 2844 2845 return spot; 2846} 2847 2848 2849WFLocalProfile.prototype.getContainer = function (ctnId) { 2850 var index = this.getContainerIndex(ctnId); 2851 var ctn = null; 2852 2853 if (index > -1) { 2854 ctn = this.profiles[0].containers[index]; 2855 } 2856 2857 return ctn; 2858} 2859 2860WFLocalProfile.prototype.addContainer = function (ctn) { 2861 this.profiles[0].containers.push(ctn); 2862 this.saveLocalProfile(); 2863} 2864 2865WFLocalProfile.prototype.removeContainer = function (ctnId) { 2866 var index = this.getContainerIndex(ctnId); 2867 var retVal = false; 2868 2869 if (index > -1) { 2870 this.profiles[0].containers.splice(index, 1); 2871 this.saveLocalProfile(); 2872 } 2873 2874 return retVal; 2875} 2876 2877WFLocalProfile.prototype.updateContainer = function (newCtn, ctnId) { 2878 var index = this.getContainerIndex(ctnId); 2879 var retVal = false; 2880 2881 if (index > -1) { 2882 this.profiles[0].containers[index] = newCtn; 2883 this.saveLocalProfile(); 2884 retVal = true 2885 } 2886 2887 return retVal; 2888} 2889 2890WFLocalProfile.prototype.profileId = function () { 2891 return this.profiles[0].profile_id; 2892} 2893 2894WFLocalProfile.prototype.profileName = function () { 2895 return this.profiles[0].name; 2896} 2897 2898WFLocalProfile.prototype.getLocalProfile = function () { 2899 2900 if ($.cookie("Profile") != null) { 2901 this.profiles = JSON.parse(unescape($.cookie("Profile"))); 2902 } else { 2903 // Create a local profile 2904 this.createLocalProfile(); 2905 } 2906} 2907 2908WFLocalProfile.prototype.createLocalProfile = function () { 2909 this.profiles.push(new WFDefaultLocalProfile()); 2910 2911 // Create the favorite spot list container 2912 this.profiles[0].containers.push(new WFFavoriteContainer(1, "Favorite Spots", "Favorite Spots", null, "")); 2913 2914 2915 this.saveLocalProfile(); 2916} 2917 2918WFLocalProfile.prototype.saveLocalProfile = function () { 2919 $.cookie('Profile', JSON.stringify(this.profiles), { expires: 9999, path: "/", domain: this.tokenDomain }); 2920 2921 if (this.isEmpty()) { 2922 $("body").trigger("local_profile_empty"); 2923 } 2924} 2925 2926WFLocalProfile.prototype.newContainerId = function () { 2927 return this.profiles[0].containers.length + 1; 2928} 2929 2930WFLocalProfile.prototype.getContainerIndex = function (ctnId) { 2931 var index = -1; 2932 2933 for (var x = 0; x < this.profiles[0].containers.length; x++) { 2934 if (this.profiles[0].containers[x].container_id == ctnId) { 2935 index = x; 2936 break; 2937 } 2938 } 2939 2940 return index; 2941} 2942 2943WFLocalProfile.prototype.isEmpty = function () { 2944 var retval = false; 2945 2946 if (this.profiles[0].containers.length == 1 && this.profiles[0].favorite_spots.length == 0) { 2947 retval = true; 2948 } 2949 2950 return retval; 2951} 2952 2953/****************************************************************************** 2954** WFDefaultLocalProfile ** 2955******************************************************************************/ 2956function WFDefaultLocalProfile() { 2957 this.name = "Favorites"; 2958 this.profile_id = 0; 2959 this.my_profile = "true"; 2960 this.created_by = "local"; 2961 this.favorite_spots = []; 2962 this.containers = []; 2963} 2964 2965/******************************************************************************
2966** WFFavoriteSpot ** 2967******************************************************************************/ 2968function WFFavoriteSpot(typeId, favSpotId, spotId, lat, lon) { 2969 this.type_id = typeId; 2970 this.fav_spot_id = favSpotId; 2971 this.spot_id = spotId; 2972 this.lat = lat; 2973 this.lon = lon; 2974} 2975 2976/****************************************************************************** 2977** WFFavoriteContainer ** 2978******************************************************************************/ 2979function WFFavoriteContainer(containerId, containerTypeId, containerName, flowviewOptions, options) { 2980 this.container_id = containerId; 2981 this.container_type_id = containerTypeId; 2982 this.container_name = containerName; 2983 this.flowview_options = flowviewOptions; 2984 this.options = options; 2985} 2986function WFProducts() {} 2987 2988// changes from api 2989// 1. made feature.exceptions and array 2990// 2. added guest member_levels to features 2991// 3. added guest member_level_kit 2992 2993////////////////////////////////////////////////////////////////////// 2994// Public Interface 2995///////////////////////////////////////////////////////////////////// 2996WFProducts.getFeatureTitleById = function (featureId) { 2997 for (i = 0; i < WFProducts.products.features.length; i++) { 2998 var feature = WFProducts.products.features[i]; 2999 if (feature.feature_id == featureId) { 3000 return feature.title; 3001 } 3002 } 3003} 3004 3005WFProducts.getFeatureMembershipStringById = function (featureId) { 3006 for (i = 0; i < WFProducts.products.features.length; i++) { 3007 var feature = WFProducts.products.features[i]; 3008 if (feature.feature_id == featureId) { 3009 return feature.memberships_str; 3010 } 3011 } 3012} 3013 3014WFProducts.getMembershipLevelNameById = function (memberLevel) { 3015 for (i = 0; i < WFProducts.products.member_level_kits.length; i++) { 3016 var memberLevelKit = WFProducts.products.member_level_kits[i]; 3017 if (memberLevelKit.member_level == memberLevel) { 3018 return memberLevelKit.name; 3019 } 3020 } 3021 return "Guest"; 3022} 3023 3024WFProducts.getAnalyticsKeyById = function (featureId) { 3025 var analyticsKey = null; 3026 3027 for (i = 0; i < WFProducts.products.features.length; i++) { 3028 var feature = WFProducts.products.features[i]; 3029 if (feature.feature_id == featureId) { 3030 analyticsKey = feature.analytics_key; 3031 } 3032 } 3033 3034 return analyticsKey; 3035} 3036 3037 3038/* 3039 doesUserHaveAccessToFeature 3040 3041 featureId int Required 3042 memberLevelId int Required 3043 exceptionFailMemberIdsStr str Optional "2,49" 3044 3045 returns true if a featureId is available for the given memberLevel 3046 3047 if exceptionFailMemberIdsStr is given it will also check the feature exceptions 3048 if an exception is found the matches the exceptionFailMemberLevelIds and memberLevel false is returned 3049*/ 3050WFProducts.doesUserHaveAccessToFeature = function (featureId, memberLevel, exceptionFailMemberLevelIdsStr) { 3051 for (i = 0; i < WFProducts.products.features.length; i++) { 3052 var feature = WFProducts.products.features[i]; 3053 if (feature.feature_id == featureId) { 3054 for (j = 0; j < feature.member_levels.length; j++) { 3055 if (feature.member_levels[j] == memberLevel) { 3056 // match found - the feature contains the user's memberLevel 3057 3058 // now look to see if there is an exception for a memberLevel in exceptionFailMemberIdsStr 3059 if (typeof exceptionFailMemberLevelIdsStr != "undefined" && exceptionFailMemberLevelIdsStr.length > 0) { 3060 // there is a list of memberIds to check for exceptions 3061 if (typeof feature.exceptions != "undefined") { 3062 // the feature does have exceptions 3063 // return false if we find a match 3064 var exceptionMemberLevelIds = exceptionFailMemberLevelIdsStr.split(","); 3065 for (k = 0; k < exceptionMemberLevelIds.length; k++) { 3066 exceptionMemberLevelId = exceptionMemberLevelIds[k]; 3067 for (l = 0; l < feature.exceptions.length; l++) { 3068 var exception = feature.exceptions[l]; 3069 if (exception.member_level == exceptionMemberLevelId && exceptionMemberLevelId == memberLevel) { 3070 // the feature does have an exception for a failMemberLevelId and user's memberLevel 3071 return false;
3072 } 3073 } 3074 } 3075 } 3076 } 3077 3078 // no exceptions found - return true 3079 return true; 3080 } 3081 } 3082 } 3083 } 3084 return false; 3085} 3086 3087WFProducts.getExcludedMapOverlays = function (memberLevel) { 3088 var excludedOverlays = []; 3089 3090 for (var x = 0; x < WFProducts.MapOverlays.length; x++) { 3091 if (!WFProducts.doesUserHaveAccessToFeature(WFProducts.MapOverlays[x].featureId, memberLevel)) { 3092 excludedOverlays.push(WFProducts.MapOverlays[x].overlayName); 3093 } 3094 } 3095 3096 return excludedOverlays; 3097} 3098 3099WFProducts.getExcludedMarkerData = function (memberLevel) { 3100 var excludedMarkerData = []; 3101 3102 if (!WFProducts.doesUserHaveAccessToFeature(7, memberLevel)) { 3103 excludedMarkerData.push(100); 3104 excludedMarkerData.push(101); 3105 } 3106 3107 return excludedMarkerData; 3108} 3109 3110WFProducts.test = function () { 3111 for (i = 0; i < WFProducts.products.features.length; i++) { 3112 var feature = WFProducts.products.features[i]; 3113 console.debug(i + " - " + feature.title); 3114 } 3115} 3116 3117WFProducts.MapOverlays = [{ featureId: 6, overlayName: "nautical" }, { featureId: 18, overlayName: "sst" }, { featureId: 25, overlayName: "currents" }, {featureId: 7, overlayName: "nowcast"}]; 3118WFProducts.ProfileFeature = 3; 3119WFProducts.AlertFeature = 4; 3120WFProducts.NauticalChartFeature = 6; 3121WFProducts.NoAdsFeature = 16; 3122 3123/* View Descriptions returned from api */ 3124WFProducts.regionalProducts = [ 3125 { 3126 "analytics_key": "Wind_Observations", 3127 "regional_product_id": 1, 3128 "title": "Wind Observations" 3129 }, 3130 { 3131 "analytics_key": "Wind_Forecast", 3132 "regional_product_id": 2, 3133 "title": "Wind Forecast" 3134 }, 3135 { 3136 "analytics_key": "Wind_Nowcast", 3137 "regional_product_id": 3, 3138 "title": "Wind Nowcast" 3139 }, 3140 { 3141 "analytics_key": "General_Weather", 3142 "regional_product_id": 4, 3143 "title": "General Weather" 3144 }, 3145 { 3146 "analytics_key": "Radar_Precipitation", 3147 "regional_product_id": 5, 3148 "title": "Radar / Precipitation" 3149 }, 3150 { 3151 "analytics_key": "Satellite_Clouds", 3152 "regional_product_id": 6, 3153 "title": "Satellite / Clouds" 3154 }, 3155 { 3156 "analytics_key": "Sea_Surface_Temperatures", 3157 "regional_product_id": 7, 3158 "title": "Sea Surface Temperatures" 3159 }, 3160 { 3161 "analytics_key": "Radar_Wind", 3162 "regional_product_id": 8, 3163 "title": "Radar + Wind" 3164 }, 3165 { 3166 "analytics_key": "Satellite_Wind", 3167 "regional_product_id": 9, 3168 "title": "Satellite + Wind" 3169 }, 3170 { 3171 "analytics_key": "NWS_Marine_Forecast_Zones", 3172 "regional_product_id": 10, 3173 "title": "NWS Marine Forecast Zones" 3174 }, 3175 { 3176 "analytics_key": "Daily_Briefings", 3177 "regional_product_id": 11, 3178 "title": "Daily Briefings" 3179 }, 3180 { 3181 "analytics_key": "OnSite_Reports", 3182 "regional_product_id": 12, 3183 "title": "OnSite Reports" 3184 }, 3185 { 3186 "analytics_key": "Sea_Surface_Current", 3187 "regional_product_id": 13, 3188 "title": "Sea Surface Current" 3189 }, 3190 { 3191 "analytics_key": "Flow", 3192 "regional_product_id": 18, 3193 "title": "Flow" 3194 }, 3195 { 3196 "analytics_key": "Wind_Gust", 3197 "regional_product_id": 19, 3198 "title": "Wind + Gust" 3199 }, 3200 { 3201 "analytics_key": "Live_Wind_Flow", 3202 "regional_product_id": 19, 3203 "title": "Live Wind - Flow" 3204 }, 3205 { 3206 "analytics_key": "Radar_Satellite", 3207 "regional_product_id": 23, 3208 "title": "Radar + Satellite" 3209 } 3210]; 3211function FVContainerOptions() { 3212 // Default values 3213 this.displayDuration = 15000; // Container display time 3214} 3215 3216function FVFavListOptions() { 3217 // Favorite spot options 3218 this.rotationSpeed = 8000; 3219 this.mapBackground = "High Contrast"; 3220 this.mapLayers = new Array(); 3221 this.showStationGraph = true; 3222 this.lockedStation = ""; 3223} 3224var size = window.getComputedStyle(document.body, ':after').getPropertyValue('content'); 3225console.log(size) 3226 3227$(document).ready(function () {
3228 loadModalManager(); 3229 cleanSavedSettings(); 3230 3231 // Load the profile manager for specific pages 3232 loadProfileManager(); 3233 loadProfiles(); 3234 3235 showWelcomeMsg(); 3236 3237 /*if (!(/(iPad|iPhone|iPod).*OS [6-7].*AppleWebKit.*Mobile.*Safari/.test(navigator.userAgent))) { 3238 $(function () { 3239 $.smartbanner() 3240 }); 3241 }*/ 3242}); 3243 3244function showWelcomeMsg() { 3245 // Welcome message is shown to users that have been to a legacy website, but have not been to new website. 3246 // CFTOKEN cookie exists: User has been to legacy website 3247 // uid cookie exists: User has been to new website 3248 3249 if ($.cookie("CFTOKEN") != null && firstTimeUser && siteName.toLowerCase() != "windalert") { 3250 var detailPage = getWelcomeDetailPage(); 3251 var tutorialPage = getWelcomeTutorialPage(); 3252 3253 var newUser = "<ul class='welcome-msg'>"; 3254 newUser += "<li>Welcome to the New " + siteName + "</li>"; 3255 newUser += "<li>The same Username and Password will work between Old and New " + siteName + "</li>"; 3256 newUser += "<li>Here is information on <a href='" + detailPage + "' target='_blank'>what's new</a>.</li>"; 3257 if (tutorialPage != "") { 3258 newUser += "<li>For help with the transition, <a href='" + tutorialPage + "'>please read this short tutorial</a>.</li>"; 3259 } 3260 newUser += "<li>We hope you enjoy all the new features!</li>"; 3261 newUser += "</ul>"; 3262 3263 // "Welcome to the New " + siteName 3264 wfModalManager.displayAlert("<div class='logo " + siteName.toLowerCase() + "'></div>", newUser); 3265 } 3266} 3267 3268function getWelcomeDetailPage() { 3269 switch (siteName.toLowerCase()) { 3270 case "sailflow": 3271 return "http://www.weatherflow.com/consumer-products/sailflow/"; 3272 break; 3273 case "fishweather": 3274 return "http://www.weatherflow.com/consumer-products/fishweather/"; 3275 break; 3276 default: 3277 return "http://www.weatherflow.com/consumer-products/"; 3278 break; 3279 } 3280} 3281 3282function getWelcomeTutorialPage() { 3283 switch (siteName.toLowerCase()) { 3284 case "sailflow": 3285 return "http://www.weatherflow.com/whats-different-on-new-sailflow/"; 3286 break; 3287 case "fishweather": 3288 return "http://www.weatherflow.com/whats-different-on-new-fishweather/"; 3289 break; 3290 default: 3291 return ""; 3292 break; 3293 } 3294} 3295 3296function isMobile() { 3297 var retval = false; 3298 3299 if (size.indexOf("mobile") > -1) { 3300 return true; 3301 } 3302 3303 return retval; 3304} 3305 3306function saveGraphModeSettings(mode) { 3307 mapSettings.gms = mode; 3308 saveMapSettings(); 3309 trackGraphModeEvent(mode); 3310 3311 if (mode == "Advanced") { 3312 $("html").addClass("advanced-graph"); 3313 } else { 3314 $("html").removeClass("advanced-graph"); 3315 } 3316} 3317 3318function delete_cookie(name) { 3319 document.cookie = name + '=; Path=/; Domain=' + tokenDomain + '; Expires=Thu, 01 Jan 1970 00:00:01 GMT;'; 3320} 3321 3322function cleanSavedSettings() { 3323 // Remove old Favorites sort order cookie 3324 delete_cookie('FavoritesSortOrder'); 3325 delete_cookie('wfEventToken'); 3326 3327 // Remove previous map graph mode 3328 if (mapSettings.hasOwnProperty("gm")) { 3329 delete mapSettings.gm; 3330 saveMapSettings(); 3331 console.log(mapSettings); 3332 } 3333} 3334MapHash = function (savedMapSettings) { 3335 this.mapSettings = savedMapSettings; 3336 this.hash = this._getHash(); 3337 this.params = this._split(); 3338} 3339 3340MapHash.LAT = 0; 3341MapHash.LON = 1; 3342MapHash.ZOOM = 2; 3343MapHash.VIEW = 3; 3344MapHash.SPOT_ID = 4; 3345MapHash.CTN_ID = 5; 3346MapHash.SEARCH = 0; 3347MapHash.VIEW_THRESHOLD = 1000; 3348 3349MapHash.LOCATION = {}; 3350MapHash.LOCATION.TYPE = {}; 3351MapHash.LOCATION.TYPE.HASH = "hash"; 3352MapHash.LOCATION.TYPE.SPOT = "spot" 3353MapHash.LOCATION.TYPE.PREVIOUS = "previous"; 3354MapHash.LOCATION.TYPE.API = "api"; 3355MapHash.LOCATION.TYPE.DEFAULT = "default"; 3356 3357MapHash.SPOT = {}; 3358MapHash.SPOT.TYPE = {}; 3359MapHash.SPOT.TYPE.SPOT = "spot"; 3360MapHash.SPOT.TYPE.ONSITE_REPORT = "onsite"; 3361MapHash.SPOT.TYPE.LATLNG = "latlng"; 3362 3363 3364MapHash.prototype._getHash = function () { 3365 var hash = null; 3366 var urlParts = location.href.split("#"); 3367 3368 if (urlParts.length > 1) { 3369 hash = urlParts[1].replace("#", ""); 3370 } 3371 3372 return hash; 3373} 3374 3375MapHash.prototype._split = function () { 3376 var params = []; 3377 3378 if (this.hash != null) { 3379 params = this.hash.split(","); 3380 } 3381 3382 return params; 3383} 3384 3385MapHash.prototype.coordinates = function (callback) { 3386 if (typeof callback === "function") { 3387 var previousLat = this._previousLat(); 3388 var previousLon = this._previousLon(); 3389 var lastLocation = getLastLocation(); 3390 var coords = { 3391 lat: null, 3392 lon: null, 3393 type: null, 3394 zoom: null 3395 }; 3396 3397 if (this.params.length > MapHash.ZOOM && this.params[MapHash.LAT] != "" && this.params[MapHash.LON] != "" && this.params[MapHash.ZOOM] != "") { 3398 coords.lat = this.params[MapHash.LAT]; 3399 coords.lon = this.params[MapHash.LON]; 3400 coords.zoom = this.params[MapHash.ZOOM]; 3401 coords.type = MapHash.LOCATION.TYPE.HASH; 3402 3403 callback(coords); 3404 } else if (this.params.length > MapHash.SPOT_ID && this.params[MapHash.LAT] == "" && this.params[MapHash.LON] == "" && this.params[MapHash.SPOT_ID] != "") { 3405 var self = this; 3406 var spotType = this.spotIdType(); 3407 var spotId = this.params[MapHash.SPOT_ID].replace(/!/g, ""); 3408 3409 // Set the zoom level and type 3410 coords.zoom = this.params[MapHash.ZOOM] == "" ? 9 : this.params[MapHash.ZOOM]; 3411 coords.type = MapHash.LOCATION.TYPE.SPOT; 3412 3413 switch (spotType) { 3414 case MapHash.SPOT.TYPE.SPOT: 3415 var spotService = new jweather.Data.SpotService({ include_obs: false, spot_types: "1,100" }); 3416 3417 spotService.getSpotDetailSetById(spotId, function (data) { 3418 if (data.status.status_code == 0 && data.spot_count >= 1) { 3419 var spot = data.spots[0]; 3420 3421 coords.lat = spot.lat; 3422 coords.lon = spot.lon; 3423 3424 callback(coords); 3425 } 3426 }); 3427 3428 break; 3429 case MapHash.SPOT.TYPE.ONSITE_REPORT: 3430 var onsiteReportId = spotId.replace(/o-/g, "") 3431 var onsiteReportService = new jweather.Data.OnsiteReportService(); 3432 3433 onsiteReportService.getOnsiteReportById(onsiteReportId, function (data) { 3434 if (data.status.status_code == 0 && data.count >= 1) { 3435 var report = data.onsite_reports[0]; 3436 3437 coords.lat = report.lat; 3438 coords.lon = report.lon; 3439 3440 callback(coords); 3441 } 3442 }); 3443 3444 break; 3445 case MapHash.SPOT.TYPE.LATLNG: 3446 var parts = spotId.split(":"); 3447 3448 if (parts.length >= 2) { 3449 coords.lat = parts[0]; 3450 coords.lon = parts[1]; 3451 3452 callback(coords); 3453 } 3454 3455 break; 3456 } 3457 } else if (lastLocation != null && lastLocation.lat != undefined && lastLocation.lat != null && lastLocation.lon != undefined && lastLocation.lon != null) { 3458 coords.lat = lastLocation.lat; 3459 coords.lon = lastLocation.lon; 3460 coords.zoom = lastLocation.zoom != null ? lastLocation.zoom : 9; 3461 3462 callback(coords); 3463 } else if (!this.isSearch() && previousLat != null && previousLon != null) { 3464 coords.lat = previousLat; 3465 coords.lon = previousLon; 3466 coords.zoom = previousMapZoom; 3467 coords.type = MapHash.LOCATION.TYPE.PREVIOUS; 3468 3469 saveLastMapLocation(previousMapCenter, previousMapZoom); 3470 3471 callback(coords); 3472 } else if (!this.isSearch() && userLati != "" && userLong != "") { 3473 coords.lat = userLati; 3474 coords.lon = userLong; 3475 coords.zoom = 9; 3476 coords.type = MapHash.LOCATION.TYPE.API; 3477 3478 callback(coords); 3479 } else if (!this.isSearch()) { 3480 coords.lat = 0; 3481 coords.lon = 0; 3482 coords.zoom = 2; 3483 coords.type = MapHash.LOCATION.TYPE.DEFAULT; 3484 3485 callback(coords); 3486 } 3487 } 3488} 3489 3490MapHash.prototype.viewId = function () { 3491 var viewId = null; 3492 3493 if (this.params.length > MapHash.VIEW) { 3494 viewId = this.params[MapHash.VIEW]; 3495 3496 if (viewId != "") { 3497 var localId = this.localCustomViewId(viewId); 3498 3499 if (localId != null) { 3500 viewId = localId 3501 } 3502 } else { 3503 // Set the default view based on the spot type 3504 var spotType = this.spotIdType(); 3505 3506 switch (spotType) { 3507 case MapHash.SPOT.TYPE.SPOT = "spot": 3508 viewId = "1"; 3509 break; 3510 case MapHash.SPOT.TYPE.ONSITE_REPORT = "onsite": 3511 viewId = "12"; 3512 break; 3513 case MapHash.SPOT.TYPE.LATLNG: 3514 viewId = "3"; 3515 break; 3516 } 3517 } 3518 } else { 3519 if (this.mapSettings.hasOwnProperty("v")) { 3520 viewId = this.mapSettings.v; 3521 } else { 3522 // default view 3523 viewId = "1"; 3524 } 3525 } 3526 3527 return viewId; 3528} 3529 3530MapHash.prototype.spotId = function () { 3531 var spotId = null; 3532 3533 if (this.params.length > MapHash.SPOT_ID && this.params[MapHash.SPOT_ID].indexOf(":") == -1) { 3534 spotId = this.params[MapHash.SPOT_ID].replace(/!/g, ""); 3535 } 3536 3537 return spotId; 3538} 3539 3540MapHash.prototype.spotIdType = function () { 3541 var spotType = null; 3542 3543 if (this.params.length > MapHash.SPOT_ID && this.params[MapHash.SPOT_ID] != "") { 3544 if (this.params[MapHash.SPOT_ID].indexOf("o-") > -1) { 3545 spotType = MapHash.SPOT.TYPE.ONSITE_REPORT; 3546 } else if (this.params[MapHash.SPOT_ID].indexOf(":") > -1) { 3547 spotType = MapHash.SPOT.TYPE.LATLNG; 3548 } else { 3549 spotType = MapHash.SPOT.TYPE.SPOT; 3550 } 3551 } 3552 3553 return spotType; 3554} 3555 3556MapHash.prototype.hasInfoWindow = function () { 3557 var hasInfoWindow = false;
3558 3559 if (this.params.length > MapHash.SPOT_ID) { 3560 if (this.params[MapHash.SPOT_ID].indexOf("!") > -1) { 3561 hasInfoWindow = true; 3562 } 3563 } 3564 3565 return hasInfoWindow; 3566} 3567 3568MapHash.prototype.spotLat = function () { 3569 var spotLat = null; 3570 3571 if (this.params.length > MapHash.SPOT_ID) { 3572 if (this.params[MapHash.SPOT_ID].indexOf(":") > -1) { 3573 var latLng = this.params[MapHash.SPOT_ID].split(":"); 3574 spotLat = latLng[0].replace(/!/g, ""); 3575 } 3576 } 3577 3578 return spotLat; 3579} 3580 3581MapHash.prototype.spotLon = function () { 3582 var spotLon = null; 3583 3584 if (this.params.length > MapHash.SPOT_ID) { 3585 if (this.params[MapHash.SPOT_ID].indexOf(":") > -1) { 3586 var latLng = this.params[MapHash.SPOT_ID].split(":"); 3587 spotLon = latLng[1].replace(/!/g, ""); 3588 } 3589 } 3590 3591 return spotLon; 3592} 3593 3594MapHash.prototype.ctnId = function () { 3595 var ctnId = null; 3596 3597 if (this.params.length > MapHash.CTN_ID) { 3598 if (!isNaN(this.params[MapHash.CTN_ID])) { 3599 ctnId = parseInt(this.params[MapHash.CTN_ID]); 3600 } 3601 } 3602 3603 return ctnId; 3604} 3605 3606MapHash.prototype.view = function (callback) { 3607 var id = this.viewId(); 3608 var view = null; 3609 3610 if (id != null) { 3611 // Lookup the view 3612 var ps = new jweather.Data.ProfileService({}); 3613 3614 ps.getContainer(id, function (data) { 3615 if (data.status.status_code == 0 && data.hasOwnProperty("options")) { 3616 view = jweather.Data.ProfileService.containerOptionsObject(data.options); 3617 3618 view.name = data.is_mine ? data.name : "Unsaved Map"; 3619 view.description = data.is_mine ? data.name : "A map that was shared with you."; 3620 } 3621 3622 if (typeof callback === "function") { 3623 callback(view, data); 3624 } 3625 }); 3626 } 3627 3628 return view; 3629} 3630 3631MapHash.prototype.searchString = function () { 3632 var searchString = null; 3633 3634 if (this.params.length > MapHash.SEARCH && this.params[MapHash.SEARCH] != "") { 3635 // Explicit search term in the hash 3636 searchString = decodeURIComponent(this.params[MapHash.SEARCH]); 3637 } else { 3638 // No search term in the hash (empty hash, or a view-only hash like 3639 // ",,,1"): fall back to the stored last location's search term. 3640 var lastLocation = getLastLocation(); 3641 3642 if (lastLocation != null && lastLocation.searchTerm != undefined && lastLocation.searchTerm != null) { 3643 searchString = decodeURIComponent(lastLocation.searchTerm); 3644 } 3645 } 3646 3647 return searchString; 3648} 3649 3650MapHash.prototype.isSearch = function () { 3651 // A hash that specifies an explicit location (lat/lon/zoom or a spot id) 3652 // centers the map directly and is never a stored-location search. 3653 if (this._hashHasLocation()) { 3654 return false; 3655 } 3656 3657 var lastLocation = getLastLocation(); 3658 3659 if (this.params.length == 1) { 3660 // A single hash param is an explicit search term. If we already have 3661 // coordinates stored for this exact term (e.g. saved by the wind list 3662 // before linking to the map), treat it as a restorable location instead 3663 // of a fresh search so coordinates() reuses those coords and 3664 // buildMapOptions doesn't clobber them via saveLastSearchLocation(). 3665 var searchTerm = decodeURIComponent(this.params[MapHash.SEARCH]); 3666 var hasCoordsForTerm = lastLocation != null 3667 && lastLocation.searchTerm != undefined && lastLocation.searchTerm != null 3668 && decodeURIComponent(lastLocation.searchTerm) == searchTerm 3669 && lastLocation.lat != undefined && lastLocation.lat != null 3670 && lastLocation.lon != undefined && lastLocation.lon != null; 3671 3672 return !hasCoordsForTerm; 3673 } 3674 3675 // The hash carries no location (empty, or a view-only hash like ",,,1"). 3676 // Defer to the stored last location: it is a search when that location is a 3677 // search term we still need to geocode (no coordinates saved for it). This 3678 // keeps a pending named search (e.g. from the wind list) from falling back 3679 // to the stale previous-map-center cookie in coordinates(). 3680 if (lastLocation != null && lastLocation.type != undefined && lastLocation.type == "search" 3681 && lastLocation.searchTerm != undefined && lastLocation.searchTerm != null && lastLocation.searchTerm != "" 3682 && (lastLocation.lat == undefined || lastLocation.lat == null || lastLocation.lon == undefined || lastLocation.lon == null)) { 3683 return true; 3684 } 3685 3686 return false;
3687} 3688 3689MapHash.prototype._hashHasLocation = function () { 3690 // Explicit lat/lon/zoom in the hash 3691 if (this.params.length > MapHash.ZOOM 3692 && this.params[MapHash.LAT] != "" && this.params[MapHash.LON] != "" && this.params[MapHash.ZOOM] != "") { 3693 return true; 3694 } 3695 3696 // A spot id (spot / onsite report / lat:lng) in the hash 3697 if (this.params.length > MapHash.SPOT_ID && this.params[MapHash.SPOT_ID] != "") { 3698 return true; 3699 } 3700 3701 return false; 3702} 3703 3704MapHash.prototype.localCustomViewId = function (urlViewId) { 3705 // Check to see if the view matches our local obs or fx settings 3706 var viewId = null; 3707 3708 if (this.mapSettings.hasOwnProperty("cv")) { 3709 if (this.mapSettings.cv.hasOwnProperty("obs")) { 3710 if (this.mapSettings.cv.obs.hasOwnProperty("ctnId") && this.mapSettings.cv.obs.ctnId == urlViewId) { 3711 viewId = "obs"; 3712 } 3713 } 3714 } 3715 3716 if (this.mapSettings.hasOwnProperty("cv")) { 3717 if (this.mapSettings.cv.hasOwnProperty("fx")) { 3718 if (this.mapSettings.cv.fx.hasOwnProperty("ctnId") && this.mapSettings.cv.fx.ctnId == urlViewId) { 3719 viewId = "fx"; 3720 } 3721 } 3722 } 3723 3724 return viewId; 3725} 3726 3727MapHash.prototype.set = function (center, zoom, bounds, viewId, view, spot) { 3728 var hashParts = []; 3729 var spotInfo = ""; 3730 var hashId = ""; 3731 3732 // Center 3733 hashParts.push(center); 3734 3735 // Zoom 3736 hashParts.push(zoom); 3737 3738 // View Id 3739 hashParts.push(this.buildViewId(viewId, view)); 3740 3741 if (this.spotInfoSet(spot)) { 3742 // Spot Id - Optional 3743 hashParts.push(this.buildSpotId(spot)); 3744 3745 // Ctn Id - Optional 3746 var ctnId = this.buildCtnId(spot) 3747 3748 if (ctnId != null) { 3749 hashParts.push(ctnId); 3750 } 3751 } 3752 3753 window.location.hash = hashParts.join(","); 3754} 3755 3756MapHash.prototype.buildViewId = function (viewId, view) { 3757 var hashId = viewId + ""; 3758 3759 // Cleanup the view id 3760 hashId = hashId.replace("c-", ""); 3761 3762 if (hashId == "obs" || hashId == "fx" || hashId == "unsaved" && view.hasOwnProperty("ctnId")) { 3763 hashId = view.ctnId; 3764 } 3765 3766 return hashId; 3767} 3768 3769MapHash.prototype.buildSpotId = function (spot) { 3770 var spotId = null; 3771 3772 if (this.spotInfoSet(spot)) { 3773 if (spot.id != null) { 3774 spotId = spot.id 3775 3776 if (spot.markerType == "OnsiteReportMarker") { 3777 spotId = "o-" + spotId; 3778 } 3779 } else { 3780 spot.lat = !isNaN(spot.lat) ? spot.lat.toFixed(4) : spot.lat; 3781 spot.lon = !isNaN(spot.lon) ? spot.lon.toFixed(4) : spot.lon; 3782 3783 spotId = spot.lat + ":" + spot.lon; 3784 } 3785 } 3786 3787 if (spot.infoWindow) { 3788 spotId = "!" + spotId; 3789 } 3790 3791 return spotId; 3792} 3793 3794MapHash.prototype.buildCtnId = function (spot) { 3795 var ctnId = null; 3796 3797 if (this.spotInfoSet(spot) && spot.hasOwnProperty("tab") && spot.tab != null) { 3798 ctnId = spot.tab; 3799 } 3800 3801 return ctnId; 3802} 3803 3804MapHash.prototype.spotInfoSet = function (spot) { 3805 var retval = false; 3806 3807 if (!spot) return retval; 3808 3809 if (spot.hasOwnProperty("id") && spot.id != null) { 3810 retval = true; 3811 } else if (spot.hasOwnProperty("lat") && spot.hasOwnProperty("lon") && spot.lat != null && spot.lon != null) { 3812 retval = true; 3813 } 3814 3815 return retval; 3816} 3817 3818MapHash.prototype._previousLat = function () { 3819 var previousLat = null; 3820 3821 if (previousMapCenter != "" && previousMapCenter.indexOf(",") > -1) { 3822 previousLat = previousMapCenter.split(",")[0]; 3823 } 3824 3825 return previousLat; 3826} 3827 3828MapHash.prototype._previousLon = function () { 3829 var previousLon = null; 3830 3831 if (previousMapCenter != "" && previousMapCenter.indexOf(",") > -1) { 3832 previousLon = previousMapCenter.split(",")[1]; 3833 } 3834 3835 return previousLon; 3836} 3837 3838MapHash.prototype.lat = function () { 3839 var lat = null; 3840 3841 if (this.params.length > MapHash.LAT) { 3842 lat = this.params[MapHash.LAT]; 3843 } 3844 3845 return lat; 3846} 3847 3848MapHash.prototype.lon = function () { 3849 var lon = null; 3850 3851 if (this.params.length > MapHash.LON) { 3852 lon = this.params[MapHash.LON]; 3853 } 3854 3855 return lon; 3856} 3857 3858MapHash.prototype.zoom = function () { 3859 var zoom = null; 3860 3861 if (this.params.length > MapHash.ZOOM) { 3862 zoom = this.params[MapHash.ZOOM]; 3863 } 3864 3865 return zoom; 3866} 3867 3868MapHash.prototype.urlViewId = function () { 3869 var viewId = null; 3870 3871 if (this.params.length > MapHash.VIEW) { 3872 viewId = this.params[MapHash.VIEW]; 3873 } 3874 3875 return viewId; 3876} 3877ContainerInfo = function (containerName) { 3878 this.containerName = containerName; 3879 this.container = null; 3880 this.info = { 3881 "bulletins": { 3882 title: "NWS Forecast", 3883 width: "600" 3884 }, 3885 "current-conditions": { 3886 title: "Current Conditions", 3887 width: "742" 3888 }, 3889 "data-archives": { 3890 title: "Data Archives", 3891 width: "600" 3892 }, 3893 "daily-briefing": { 3894 title: "Professional Meteorologist Forecast", 3895 width: "600" 3896 }, 3897 "forecast-table": { 3898 title: "Forecast Table", 3899 width: "600" 3900 }, 3901 "nearby-tides": { 3902 title: "Nearby Tides & Currents", 3903 width: "600" 3904 }, 3905 "nowcast": { 3906 title: "Nowcast", 3907 width: "600" 3908 }, 3909 "onsite-reports": { 3910 title: "Onsite Reports", 3911 width: "600" 3912 }, 3913 "station-info": { 3914 title: "Station Info", 3915 width: "600" 3916 }, 3917 "wind-stats": { 3918 title: "Wind Statistics", 3919 width: "600" 3920 } 3921 }; 3922 3923 this._init(); 3924}; 3925 3926ContainerInfo.prototype.width = function () { 3927 var width = "600"; 3928 3929 if (this.container != null) { 3930 width = this.container.width; 3931 } 3932 3933 return width; 3934} 3935 3936ContainerInfo.prototype.infoText = function () { 3937 var str = ""; 3938 3939 switch (this.containerName) { 3940 case "bulletins": 3941 str = this._bulletinInfo(); 3942 break; 3943 case "current-conditions": 3944 str = this._currentConditionsInfo(); 3945 break; 3946 case "data-archives": 3947 str = this._dataArchivesInfo(); 3948 break; 3949 case "forecast-table": 3950 str = this._forecastTableInfo(); 3951 break; 3952 case "nearby-tides": 3953 str = this._nearbyTidesInfo(); 3954 break; 3955 case "nowcast": 3956 str = this._nowcastInfo(); 3957 break; 3958 case "onsite-reports": 3959 str = this._onsiteReportsInfo(); 3960 break; 3961 case "daily-briefing": 3962 str = this._operationalForecastInfo(); 3963 break; 3964 case "station-info": 3965 str = this._stationInfo(); 3966 break; 3967 case "wind-stats": 3968 str = this._windStatsInfo(); 3969 break; 3970 } 3971 3972 return str; 3973} 3974 3975ContainerInfo.prototype.title = function () { 3976 var title = ""; 3977 3978 if (this.container != null) { 3979 title = this.container.title; 3980 } 3981 3982 return title; 3983} 3984 3985ContainerInfo.prototype._init = function () { 3986 if (this.info.hasOwnProperty(this.containerName)) { 3987 this.container = this.info[this.containerName]; 3988 } 3989} 3990 3991ContainerInfo.prototype._dataArchivesInfo = function () { 3992 var str = "<p>Our historical wind archives include a wealth of wind graphs & data, going back as far as 30 years in the case of some popular stations. Click the arrows to go backward or forward in time. You can also use the calendar button to select a specific date, or click View Month to see an entire month\'s worth of archived wind graphs all at once.</p>"; 3993 str += "<p>Raw, numerical data:<br/>If you\'re looking for raw numerical data, <a href='https://help.tempest.earth/hc/en-us/requests/new' target='_blank'>click here</a> to inquire about our data download packages.</p>"; 3994 str += "<p><img alt=\"Yesterday\'s Wind\" src=\"https://cdn-consumer.weatherflow.com/images/info/yesterdays_wind_info.jpg?v20171115\" width='572px'></p>"; 3995 3996 return str; 3997} 3998 3999ContainerInfo.prototype._currentConditionsInfo = function () { 4000 var mode = mapSettings.hasOwnProperty("gms") ? mapSettings.gms : "Basic"; 4001 var images = { 4002 "Advanced": { 4003 src: "/App_Themes/jWeather/images/current_conditions_info.png", 4004 width: "718px", 4005 height: "444px" 4006 }, 4007 "Basic": { 4008 src: "/App_Themes/jWeather/images/current_conditions_info_basic.png", 4009 width: "718px", 4010 height: "424px" 4011 } 4012 }; 4013 var img = images.hasOwnProperty(mode) ? images[mode] : null; 4014 4015 if (img != null) { 4016 var str = "<p>
4016<img src='" + img.src + "' height='" + img.height + "' width='" + img.width + "'></p>"; 4017 } 4018 4019 return str; 4020} 4021 4022ContainerInfo.prototype._nowcastInfo = function () { 4023 return "<p>There is no weather station here. Nowcast data at this spot is based on our Nowcast model, which is based on a formula that incorporates the best available observations and forecast data for this location. Nowcast is experimental.</p>"; 4024} 4025 4026ContainerInfo.prototype._nearbyTidesInfo = function () { 4027 var str = "<p>This is a list of all weather stations within " + searchRadius + " " + distanceUnits + " of this location. The search radius can be changed in your settings. The graph is for the current day.</p>"; 4028 str += "<p>We use Xtides program to generate our tidal graphs. </p>"; 4029 str += "<p>A very good summary of how Tides are calculated and a great general FAQ can be found here: </p>"; 4030 str += "<p><a class='extra-info-link' href='http://www.flaterco.com/xtide/faq.html#50' target=/'blank'>http://www.flaterco.com/xtide/faq.html#50</a></p>"; 4031 4032 return str; 4033} 4034 4035ContainerInfo.prototype._windStatsInfo = function () { 4036 var str = "<p> The left side shows the number of days per month a specific weather station reported average winds greater than 15, 20, and 25 miles per hour. The Right side shows the percentage of time that the weather station reported a specific wind direction for the highlighted month. The data has not been error checked. </p>"; 4037 str += "<h3>Options:</h3>"; 4038 str += "<ul>"; 4039 str += "<li><strong>All Time (default)</strong> - This data is the average over the years available in our database.</li>"; 4040 str += "<li><strong>Specific Years</strong> - These are specific statistics for a given year. Hovering your mouse over a month will tell you how many days and how many days that station reported.</li>"; 4041 str += "<li><strong>Gust vs. Average</strong> - WeatherFlow stations are positioned in very good spots to capture ambient wind conditions and averages often reflect actual winds experienced on the water. However, we also include stations from many other sources that may not be ideally placed and gusts can often be a better indicator of conditions.</li>"; 4042 str += "</ul>"; 4043 str += "<p><a class='extra-info-link' href='mailto:[email protected]' target='_blank'>For more detailed premium wind statistics click here</a></p>"; 4044 4045 return str; 4046} 4047 4048ContainerInfo.prototype._onsiteReportsInfo = function () { 4049 var str = infoContent = "This list displays the ten closest OnSite Reports within a 72 hour period. OnSite Reports are crowdsourced (user-generated) wind and weather reports, contributed by real people via different applications."; 4050 4051 return str; 4052} 4053 4054ContainerInfo.prototype._operationalForecastInfo = function () { 4055 var str = "<p>Professional Meteorologist Forecasts include a detailed wind forecast, or briefing, by a WeatherFlow meteorologist. Bullet points detail areas of interest or concerns that the meteorologist has that could impact the winds for the day. In contrast to the Computer Forecast Table, which was produced solely by a computer, the Pro Forecast forecast table was handcrafted by the meteorologist and reflects his or her expertise and local knowledge. The Pro Forecasts also include an Extended Discussion which provides a forecast for the upcoming conditions for the region over the next three days.</p><p><em>NOTE:</em> Pro Forecasts and Extended Discussions are both seasonal and local. Hence, they are not available for all regions.</p>"; 4056 4057 return str; 4058} 4059 4060ContainerInfo.prototype._bulletinInfo = function () { 4061 var str = "<p>The NWS Forecast includes Marine Forecasts as well as Watches & Warnings from the National Weather Service (NWS). These are produced by regional and national NWS offices.</p>"; 4062 4063 return str; 4064} 4065 4066ContainerInfo.prototype._stationInfo = function () { 4067 var str = "<p>Station information is provided to give additional metadata information, including facts about station ownership and operation.</p>"; 4068 4069 return str; 4070} 4071 4072ContainerInfo.prototype._forecastTableInfo = function () { 4073 var str = "<p>The forecast table shows you many parameters output by the forecast model going out up to 7 days ahead.</p>"; 4074 str += "<p>Clicking the star button saves the table that you have selected into your current profile.</p>"; 4075 str += "<p>Available Models: Select what forecast model you want to see. Available models will vary depending on the location that you have selected.</p>"; 4076 str += "<p>For more detailed information see our help topic <a class='extra-info-link' href='https://help.tempest.earth/hc/en-us/articles/207913138#h_01GV695ZJH0G8RNCD27B2HDJJW' target='_blank'>Reading Forecast Tables</a></p>"; 4077 4078 return str; 4079} 4080 4081(function ($, undefined) { 4082 var navData = null; 4083 4084 $(document).ready(function () { 4085 if (userLati && userLong) { 4086 setUIGeolocation(userLati, userLong); 4087 4088 $(".geolocation-btn").show(); 4089 4090 $(".geolocation-btn").click(function (e) { 4091 e.preventDefault(); 4092 4093 var page = "currentPage" in window ? currentPage : "Search"; 4094 4095 if (page == "SearchResults") { 4096 // Don't reload the page, just update the map 4097 if (ui) { 4098 var center = new google.maps.LatLng(userLati, userLong); 4099 4100 ui.loadCenterZoom(center, 10); 4101 refreshDFP(0); 4102 } 4103 closeMobileSearchMenu(); 4104 } else if (page == "WindList") { 4105 doWindListSearch(userLati + "," + userLong); 4106 refreshDFP(0); 4107 closeMobileSearchMenu(); 4108 } else if (page == "SearchResultsPlus") { 4109 doSearchResultsPlusSearch(userLati + "," + userLong); 4110 closeMobileSearchMenu(); 4111 } else { 4112 // Only track event if geolocate is used on the homepage 4113 if (page == "Search") {
4114 _gaq.push(['_trackEvent', 'Homepage Search', 'Geolocate', (userLati + ',' + userLong)]); 4115 } 4116 4117 window.location = "/windlist/" + userLati + "/" + userLong; 4118 } 4119 }); 4120 } else { 4121 $(".geolocation-btn").hide(); 4122 } 4123 4124 $("#main-menu-btn").click(function () { 4125 $("#main-menu").toggle(); 4126 mainMenuClosed(); 4127 closeMobileSearchMenu(); 4128 4129 return false; 4130 }); 4131 4132 $("#main-menu a.upgrade-available").on("click touchend", function () { 4133 var featureId = $(this).attr("data-feature-id"); 4134 var retval = wfModalManager.doesUserHaveAccessToFeature(featureId); 4135 4136 return retval; 4137 }); 4138 4139 $("body").on("click", ".parent-menu", function () { 4140 var menuId = $(this).attr("data-sub-menu"); 4141 4142 if (menuId != undefined && menuId != null && menuId != "") { 4143 $(this).toggleClass("sub-menu-show"); 4144 $("#" + menuId).toggleClass("sub-menu-show"); 4145 } 4146 4147 return false; 4148 }); 4149 4150 $("html").click(function () { 4151 $("#main-menu").hide(); 4152 $("#mobile-search-menu").hide(); 4153 mainMenuClosed(); 4154 }); 4155 4156 $("#mobile-search-btn").on("click touchend", function () { 4157 $("#mobile-search-menu").toggle(); 4158 $("#mobile-search-menu .mobile-searchInput").focus(); 4159 $("#main-menu").hide(); 4160 mainMenuClosed(); 4161 4162 return false; 4163 }); 4164 4165 $("#mobile-search-menu").click(function (e) { 4166 // Don't bubble up to html click handler 4167 e.stopPropagation(); 4168 }); 4169 4170 $("#cancel-mobile-search").on("click touchend", function () { 4171 closeMobileSearchMenu(); 4172 4173 return false; 4174 }); 4175 4176 4177 $(".mobile-searchInput").keypress(function (e) { 4178 if (e.which == 13) { 4179 searchInputHandler($(".mobile-searchInput").val()); 4180 closeMobileSearchMenu(); 4181 4182 return false; 4183 } 4184 }); 4185 4186 $("#do-mobile-search").on("click touchend", function () { 4187 searchInputHandler($(".mobile-searchInput").val()); 4188 closeMobileSearchMenu(); 4189 4190 return false; 4191 }); 4192 4193 loadRegionalNav(); 4194 }); 4195 4196 function closeMobileSearchMenu() { 4197 $("#mobile-search-menu .mobile-searchInput").val("").blur(); 4198 $("#mobile-search-menu").hide(); 4199 } 4200 4201 function setUIGeolocation(lat, lon) { 4202 var regions = [ 4203 { min_lat: 16.961, min_lon: -162.895, max_lat: 23.917, max_lon: -152.132 }, 4204 { min_lat: 9.788, min_lon: -71.525, max_lat: 19.538, max_lon: -58.313 }, 4205 { min_lat: 22.743, min_lon: -129.557, max_lat: 51.104, max_lon: -66.125 } 4206 ]; 4207 4208 for (var i = 0; i < regions.length; i++) { 4209 var r = regions[i]; 4210 4211 if (r.min_lat <= lat && r.min_lon <= lon && r.max_lat >= lat && r.max_lon >= lon) { 4212 return true; 4213 } 4214 } 4215 4216 return false; 4217 } 4218} (jQuery)); 4219 4220function mainMenuClosed() { 4221 if (isMobile()) { 4222 if ($("#main-menu").is(":visible")) { 4223 $("html").addClass("modal-open"); 4224 } else { 4225 $("html").removeClass("modal-open"); 4226 } 4227 } 4228} 4229 4230function lastLocationDefaultObj() { 4231 return { 4232 lat: null, 4233 lon: null, 4234 zoom: null, 4235 searchTerm: null, 4236 type: null 4237 }; 4238} 4239 4240function saveLastMapLocation(centerPoint, zoom) { 4241 var coords = centerPoint.split(","); 4242 var loc = lastLocationDefaultObj(); 4243 4244 if (coords.length > 1) { 4245 loc.lat = coords[0]; 4246 loc.lon = coords[1]; 4247 } 4248 4249 loc.searchTerm = centerPoint; 4250 loc.zoom = zoom; 4251 loc.type = "coords"; 4252 4253 saveLastLocation(loc); 4254} 4255 4256function saveLastSearchLocation(searchTerm) { 4257 var loc = lastLocationDefaultObj(); 4258 4259 loc.searchTerm = searchTerm; 4260 loc.type = "search"; 4261 4262 saveLastLocation(loc); 4263} 4264 4265function getLastLocation() { 4266 var str = getLocalSetting("lastLocation"); 4267 var obj = null; 4268 4269 if (str != undefined && str != null) { 4270 try { 4271 obj = JSON.parse(str); 4272 } catch (e) { 4273 // Invalid JSON 4274 obj = null; 4275 } 4276 } 4277 4278 return obj; 4279} 4280 4281function saveLastLocation(obj) { 4282 saveLocalSetting("lastLocation", JSON.stringify(obj)); 4283} 4284 4285function saveLocalSetting(key, value) { 4286 if (('localStorage' in window) && window.localStorage !== null) { 4287 localStorage[key] = value; 4288 } 4289} 4290 4291function getLocalSetting(key) { 4292 var retval = null; 4293 4294 if (('localStorage' in window) && window.localStorage !== null) { 4295 retval = localStorage[key]; 4296 } 4297 4298 return retval; 4299} 4300 4301function loadProfiles() { 4302 jweather.baseUrl = apiurl; 4303 jweather.token = token; 4304 4305 var ps = new jweather.Data.ProfileService(); 4306 4307 ps.getProfiles(function (data) { 4308 if (data.status.status_code == 0) { 4309 // UL element in the header 4310 var str = ""; 4311 var profileList = $(".profileList-profiles"); 4312 var profiles = data.profiles; 4313 var profileClass = "profile-item"; 4314 4315 // Clear the list 4316 $(".profile-item", profileList).remove(); 4317 4318 for (var x = 0; x < profiles.length; x++) { 4319 if (profiles[x].profile_id > 0) { 4320 var profileLink = "/profile/" + profiles[x].profile_id; 4321 4322 str += "<li id='" + profiles[x].profile_id + "' class='my-profile'><a href='" + profileLink + "'>" + profiles[x].name + "</a></li>"; 4323 } 4324 } 4325 4326 $("#main-menu #profile-list").prepend(str); 4327 } 4328 }); 4329} 4330 4331function loadRegionalNav() { 4332 var url = "/navigation.js"; 4333 var dataType = "json"; 4334 4335 var request = $.ajax({ 4336 async: true, 4337 url: url, 4338 dataType: dataType 4339 }); 4340 4341 request.done(function (data) { 4342 navData = data; 4343 regionalNavCallback(); 4344 }); 4345} 4346 4347function regionalNavCallback() { 4348 if (navData.hasOwnProperty("continents")) { 4349 for (var x = 0; x < navData.continents.length; x++) {
4350 var c = navData.continents[x]; 4351 var cname = c.name.replace("&", "").replace(".", "").replace(/ /g, ""); 4352 4353 loadCountries(cname, navData.continents[x]); 4354 } 4355 } 4356 4357 attachRegionalNavEventHandlers(); 4358} 4359 4360function loadCountries(continent, continentData) { 4361 var str = ""; 4362 4363 if (continentData.hasOwnProperty("countries")) { 4364 var countries = continentData.countries; 4365 4366 for (var i = 0; i < countries.length; i++) { 4367 var c = countries[i]; 4368 var idx = c.name.indexOf("--") == -1 ? i : ""; 4369 var hasRegions = c.regions != undefined ? true : false; 4370 var cssClass = hasRegions ? "class='parent-menu'" : ""; 4371 var locationInfo = c.c.split(","); 4372 var link = hasRegions || idx == "" ? "#" : "/windlist/" + locationInfo[0] + "/" + locationInfo[1]; 4373 4374 str += "<li><a href='" + link + "' " + cssClass + " data-country-idx='" + idx + "'>" + c.name + "</a></li>"; 4375 } 4376 } 4377 4378 $("#" + continent).empty().append(str); 4379} 4380 4381function attachRegionalNavEventHandlers() { 4382 // $(".Sub-Menu").click(function (e) { 4383 // e.preventDefault(); 4384 // return false; 4385 // }); 4386 4387 $("a[data-country-idx]").on("click", function () { 4388 var count = $(this).siblings(".sub-menu").length; 4389 4390 // Don't draw the menu if it already exists 4391 if (count == 0) { 4392 var subMenu = $(this).closest("ul"); 4393 var subMenuId = subMenu.attr("id"); 4394 var countryIdx = $(this).attr("data-country-idx"); 4395 var continentIdx = $("a[data-sub-menu='" + subMenuId + "']").attr("data-continent-idx"); 4396 4397 if (countryIdx != "" && continentIdx != "") { 4398 if (navData.continents[continentIdx].countries[countryIdx].regions) { 4399 var regions = navData.continents[continentIdx].countries[countryIdx].regions; 4400 var countryName = $(this).html(); 4401 var subMenuName = countryName.replace("&", "").replace(".", "").replace(/ /g, ""); 4402 4403 var str = "<ul id='" + subMenuName + "' class='sub-menu'>"; 4404 4405 for (var x = 0; x < regions.length; x++) { 4406 var hasSubRegions = regions[x].subregions != undefined ? true : false; 4407 var cssClass = hasSubRegions ? "class='parent-menu'" : ""; 4408 var locationInfo = regions[x].c.split(","); 4409 var link = hasSubRegions ? "#" : "/windlist/" + locationInfo[0] + "/" + locationInfo[1]; 4410 4411 str += "<li><a href='" + link + "' " + cssClass + " data-region-idx='" + x + "'>" + regions[x].name + "</a></li>"; 4412 } 4413 4414 str += "</ul>"; 4415 4416 $(this).attr("data-sub-menu", subMenuName); 4417 $(this).parent().append(str); 4418 } 4419 } else { 4420 return false; 4421 } 4422 } 4423 }); 4424 4425 $("body").on("click", "a[data-region-idx]", function () { 4426 var count = $(this).siblings(".sub-menu").length; 4427 4428 // Don't draw the menu if it already exists 4429 if (count == 0) { 4430 var countryMenu = $(this).closest("ul"); 4431 var countryMenuId = countryMenu.attr("id"); 4432 var continentMenu = $("a[data-sub-menu='" + countryMenuId + "']").closest("ul"); 4433 var continentMenuId = continentMenu.attr("id"); 4434 var regionIdx = $(this).attr("data-region-idx"); 4435 var countryIdx = $("a[data-sub-menu='" + countryMenuId + "']").attr("data-country-idx"); 4436 var continentIdx = $("a[data-sub-menu='" + continentMenuId + "']").attr("data-continent-idx"); 4437 4438 if (regionIdx != "") { 4439 if (navData.continents[continentIdx].countries[countryIdx].regions[regionIdx].subregions) { 4440 var regionName = $(this).html(); 4441 var subMenuName = regionName.replace("&", "").replace(".", "").replace(/ /g, ""); 4442 var subregions = navData.continents[continentIdx].countries[countryIdx].regions[regionIdx].subregions; 4443 var str = "<ul id='" + subMenuName + "' class='sub-menu sub-menu
4443-show'>"; 4444 4445 for (var x = 0; x < subregions.length; x++) { 4446 var locationInfo = subregions[x].c.split(","); 4447 4448 str += "<li><a href='windlist/" + locationInfo[0] + "/" + locationInfo[1] + "' data-sub-region-idx='" + x + "'>" + subregions[x].name + "</a></li>"; 4449 } 4450 4451 $(this).attr("data-sub-menu", subMenuName); 4452 $(this).parent().append(str); 4453 } 4454 } 4455 } 4456 }); 4457}
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.