After spending way too much time (ETA: yesterday and today, after not touching this since Friday) adding/tweaking minor demo features far beyond what I had intended to post on Friday, here it is at last:
Code:
// ==UserScript==
// @name SWA Ad Carousel Zapper With Expert Mode
// @author wnProTips
// @namespace http://www.flyertalk.com/forum/members/ftnoob.html
// @description Removes the Ad Carousel from flight search page on southwest.com. A future version will enable the expert mode search feature.
// @license Creative Commons Attribution License
// @version Beta 0.1
// @released 2011-05-25
// @updated
// @include http://www.southwest.com/flight/
// @include http://www.southwest.com/flight/?int=*
// @include http://www.southwest.com/flight/search-flight.html*
// @include http://www.southwest.com/flight/select-flight.html?disc=*
// ==/UserScript==
window.addEventListener('load',
function(e) {var pn=document.location.pathname;
function fixFlightsPage() {
window.setTimeout(function() {
var $ = unsafeWindow.jQuery, sEl=document.createElement('script') ;
$('#modifyDatesForm [id*="port_"]').hide();
$('#modifyDatesForm [id$="port"]').show();
sEl.setAttribute("type", "text/javascript");
sEl.setAttribute("id", "disUp");
sEl.appendChild(document.createTextNode("document.addEventListener('click', function(){disableUpsellDrawers = true;},false);\n"));
document.body.appendChild(sEl);
}
,250);
}
function fixSearchPage(){
var $ = unsafeWindow.jQuery, scriptNode=document.createElement("script");
$('#sw_footer, .swa_content_module').html('');
$("#outboundTimeOfDay").hide();
$('#center-content').fadeOut(250);
$('#returnBookingSelects, div.passenger-selects, #sw_header_primary_nav').slideToggle(500);
$('#promoCode').parent().parent().slideToggle(500);
$(".product-icon").parent().slideToggle(500);
var sEmbed="var displayFilteredStationList=function(i,v,G,k,K,t,g,f){try{if(typeof f==\"undefined\"){f=\"ALL\" }$(\"#tab_container .country_tabs\").css(\"display\",\"none\"); var h=$(i).siblings(\"select.stationInput\").attr(\"id\"); if($(i).siblings(\"label\").size()>0){h=$(i).siblings(\"label\").attr(\"for\") }var D=$(\"#destination_flyout\"); D.html(\"\"); var C=[\"US\",\"MX\",\"ALL\"]; var J=[\"USA\",\"Mexico\",\"All\"]; var m=\"<div id=\\\"tab_container\\\"><ul style=\\\"width:100%;position:relative;z-index:1000\\\" class=\\\"country_tabs\\\">\"; for(var u=0; u<C.length; u++){var F=(f==C[u])?\"country_tab_selected\":\"country_tab\"; if(f==\"ALL\"&&u==0){F=\"country_tab_selected\" }if(C[u]!=\"ALL\"){m+=\"<li id=\\\"tab_\"+C[u]+\"\\\" class=\\\"\"+F+\"\\\">\"+J[u]+\"</li>\" }}var A=\"-12px\"; if($(\"option.MX\").length==0){A=\"0px\" }m+=\"</ul></div>\"; m+=\"<div style=\\\"padding-left:0px;width:100%;border-bottom:solid 1px #F0F0F0;height:1px;position:relative;top:\"+A+\";_top:-18px;z-index:900\\\"></div>\"; D.append(m); for(var u=0; u<1; u++){var c=\"<div style=\\\"clear:both;display:none;width:100%;padding-top:0px;_margin-top:-5px\\\" class=\\\"destination_container\\\" id=\\\"destination_container_\"+C[u]+\"\\\">\"; if(K){c+=\"<div class=\\\"noMatch\\\">\"+noMatchOnFilterErrorMessage+\"</div><br style=\\\"clear:both\\\" />\" }c+=\"</div>\"; D.append(c) }var N=t?$(i).val().toUpperCase():null; populateDestinationFlyout(D,v,G,N,g,f); D.wrapInner(\"<div class=\\\"station_list\\\" id=\\\"\"+h+\"_station_list\\\"></div>\"); var j=\"\"; j+=\"<div class=\\\"close_button_container\\\">\"; j+=\"<div style=\\\"float:left;padding-top:3px;padding-left:10px\\\" id=\\\"destination_footer_content\\\"></div>\"; j+=\"<div style=\\\"float:right\\\"><a class=\\\"close_button\\\" onclick=\\\"return(false)\\\" href=\\\"#\\\"><span class=\\\"closeImg\\\"></span><span style=\\\"float:right\\\">Close</span></a></div>\"; j+=\"</div>\"; D.children(\".station_list\").after(j); if(k){var L=D.children(\".station_list\").children(\"div.innerDiv:first-child\").children(\"a\"); $(L[0]).addClass(\"highlighted\") }if(g==true){$(\"#tab_container .country_tabs\").hide(); $(\"#destination_container_US\").show() }else{$(\"#destination_container_\"+C[0]).show() }i.value.trim().length>3&&D.show(); var B=\"#destination_container_\"+C[0]+\" div\"; var x=$(B).length; if(x>4){x=4 }var a=x*240; D.css(\"width\",a); var d=$(\"#\"+h+\"_displayed\").offset(); var w=$(\"#\"+h+\"_displayed\").outerHeight(); var p=$(\"#\"+h+\"_displayed\").outerWidth(); var z; if($(\"#\"+h+\"_displayed\").hasClass(\"destFlyoutRightAlign\")){z=d.left+p-D.outerWidth() }else{z=d.left }D.css({left:z,top:d.top+w}); var b=$(flyoutHider); if(b.size()>0){$(b[0]).css({left:$(D[0]).offset().left,top:$(D[0]).offset().top,width:a,height:$(D[0]).innerHeight(),position:\"absolute\",zIndex:1}); $(b[0]).show() }var r=D.offset(); var q=r.left; var M=D.width(); var H=$(window).width(); if(H-(q+M)<0){var l=q-(Math.abs(H-(q+M))); $(flyoutHider).css(\"left\",q) }if($(\".innerDiv:last\").length>0){var o=$(\".innerDiv:last\"); var n=o.offset(); var s=n.left; var y=n.left+o.width(); var E=(q+M)-y; if(E>0){D.css(\"width\",((a-E)+12)+\"px\"); $(flyoutHider).css(\"width\",((a-E)+12)+\"px\") }}$(\"#tab_container .country_tabs li\").bind(\"click\",function(){if($(i).attr(\"id\").indexOf(\"returnAirport\")>=0){setTimeout(function(){var P=\"\"; if($(\"input#oneWay\").length==0){P+=\"<a class=\\\"US\\\" title=\\\"\\\" style=\\\"display:block;\\\">None</a>\" }P+=\"<a class=\\\"US\\\" title=\\\"RoundTrip\\\" style=\\\"display:block;\\\">Depart City/Round Trip</a>\"; $(\".destination_container .innerDiv:first\").prepend(P) },100) }selectTab(this); D.html(\"\"); var O=$(this).attr(\"id\"); var e=O.substring(O.indexOf(\"_\")+1); displayFilteredStationList(i,v,G,k,K,t,g,e); addEventsToDestinationFlyout(i,D); if(e.toLowerCase()==\"mx\"){if($(\".destination_flyout\").css(\"width\")==\"223px\"||$(\".destination_flyout\").css(\"width\")==\"213px\"){$(\".destination_flyout\").css(\"width\",\"375px\") }$(\"#destination_footer_content\").css(\"text-align\",\"left\"); $(\"#destination_footer_content\").text(\"Flights into and out of Mexico operated by Volaris\"); if(SWA.dollarToggle.pointsSelected){$(\"#destination_container_US\").hide() }}}) }catch(I){}return D };".quote();
unsafeWindow.String.prototype.trim = function (){return $.trim(this.toString())}
unsafeWindow.isStationCodeOrNameMatching = function (b, a) {b=b.trim(); return a.stationCode.indexOf(b) == 0 || a.stationName.toUpperCase().indexOf(b) == 0;}
scriptNode.setAttribute("type", "text/javascript");
scriptNode.appendChild(document.createTextNode("eval(" + sEmbed +");"));
document.body.appendChild(scriptNode);
$('#oneWay').click();
$('#returnAirport_displayed').attr('disabled', false);
$('label[for="oneWay"]').attr('accessKey', 'o');
$('label[for="roundTrip"]').attr('accessKey', 'a');
$('label[for="roundTrip"]').html('<span style="text-decoration: underline;">A</span>-B-C');
$('label[for="oneWay"]').html('<span style="text-decoration: underline;">O</span>ne Way');
$('#buildItineraryForm *').filter(':input').attr('tabindex',999);
$('#buildItineraryForm a[href*="routemap"]').attr('tabindex',0);
window.setTimeout(function() {
var $ = unsafeWindow.jQuery,cc=$('#center-content'),oA=$('#originAirport_displayed'),oD=$('#outboundDate'),ccHtml;
ccHtml = '<div id="divExpert"><h2 style="text-align: center;">Expert Mode</h2>' +
'<h3 style="text-align: center;">Coming soon!</h3>' +
'<form id="expInp" style="margin-left: 4ex; ">' +
' <label for="expInp">Search: </label>' +
' <input id="expSearch" type="text" style="width: 80%; border: 1px solid black;">' +
' <p style="margin: .3em 0; font-weight: 600;">Examples of valid searches:</p>' +
' <p style="margin: 0 2ex; padding-bottom: 2em;">' +
' LAX,SFO,0704<br />' +
' LAX.SFO.0704<br />' +
' LAX/SFO/0704<br />' +
' LAX SFO 0704<br />' +
' LAXSFO07.04<br />' +
' LAX (SFO OAK) 07/04<br />' +
' (LAX SNA)(SFO OAK) 0704<br /></span></P>' +
'<p id=dlm></p>' +
'<p id=cookies> </p>' +
'</form>' +
'</div>' ;
cc.html(ccHtml);
$('#dlm').html(document.lastModified) ;
cc.fadeIn(700);
$.datepicker._disableDatepicker(oD[0]) ;
oD.attr('disabled', '') ;
oA.focus();
oA.select();
}, 600);
}
(pn.indexOf('select-')<0)?fixSearchPage():fixFlightsPage();
}
,false);
If you have already tried the script above you obviously know that it vastly decrapifies the flight search page. For now, much of the decrapifiying relies on jQuery animation effects a) for amusement; and b) as a reminder that an installed script is modifying the page (as opposed to the page being broken). Remember that you can always use the GreaseMonkey menu to disable a script if you need to see the unmodfied version of the page.
The ultra-long line of unintelligible code is a tweak of an existing (minified) JS function related to the airport flyouts. It simply adds one tiny condition that makes the existence of the flyouts vastly more tolerable. The conditional does one simple thing: until the point that you have typed at least four characters in the input field, it causes the flyout script to assume that you probably know what you are doing and don't need any help. (That is similar to the way kayak.com implements their smart input fields, though their help might show up after the third character.)
This GreaseMonkey script also implements
my 2009-Oct proposed fix for the
typing a space after the airport code / city name problem that SWA is (presumably) still "working on."
These two tiny changes do not add up to a perfect solution, as at least one area of potential confusion remains: if you don't know that the code for Fort Myers is RSW, and you don't know whether SWA lists Fort Myers as
- Fort Myers;
- Ft Myers; or
- Ft. Myers
you are going to have to resort to either trial-and-error or clicking the flyout trigger button.

It wouldn't be difficult to fix that in the original source code, but it's too much trouble for Beta v0.1 of a GreaseMonkey
Extreme Makeover -- Web Site Edition! script!
This script also adds a rarely-used feature of HTML: access keys for form elements. For usability reasons I would never have implemented the OW/RT option the way SWA did. The (local storage) version of my Expert Mode flight search page used a select box with OW/RT/ABC options instead of (only two) radio buttons that lack access keys. Note that to use the (underlined) access keys in Firefox, you have to press Shift-Alt-[key] instead of just Alt-[Key] as you do in a stand alone Windows or Linux app (sorry, I don't know the Mac equivalents). That isn't super friendly, but it is a far sight better than having to take a hand off the keyboard to use the mouse. Experiment by alternately pressing Shift-Alt-A and Shift-Alt-O.
If you click "add another flight" and then repeat the above experiment, you might notice some weird stuff going on / not happening with the third city input box. That is due to a new bug introduced during SWA's rush to assault you with the offensive ad carousel on the flight search page. I might or might not again wait 19 months to see whether their crack programmers can figure that one out before distributing my own fix.
In conjunction with some other changes of varying visibility (lightly deploying the tab index feature, hiding input fields that usually shouldn't be used on an initial search, disabling the date picker calendar, and setting initial focus to the originAirport_displayed field), with this script installed it is now possible to pretty efficiently enter a fare search for travel "today:" nine key strokes, no mousing, and you are there. Example: sfo[tab]lax[tab][enter].

(I could of course change the default date in the script, but this version does not do that).
Once you do that, you'll see that the flight search results page has a few tweaks as well, although comparatively few. See the next post for that discussion.