diff --git a/.gitignore b/.gitignore index db0334d..a1c416c 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,5 @@ bower_components heroku heroku.pub +config.json test/spec/bundle.js diff --git a/app/bootstrap.js b/app/browser/bootstrap.jsx similarity index 57% rename from app/bootstrap.js rename to app/browser/bootstrap.jsx index 574ec86..807fa47 100644 --- a/app/bootstrap.js +++ b/app/browser/bootstrap.jsx @@ -1,10 +1,11 @@ /** @jsx React.DOM */ -var data = require("./data"); var React = require("react"); -var TubeTracker = require("./component/tube-tracker"); +var networkData = require("../common/data"); +var TubeTracker = require("../component/tube-tracker.jsx"); -window.app = (function(scope) { +window.app = (function() { var requiredFeatures = { + "JSON decoding": window.JSON, "the selectors API": document.querySelector, "ES5 array methods": Array.prototype.forEach, "DOM level 2 events": window.addEventListener, @@ -17,5 +18,6 @@ window.app = (function(scope) { } } - return React.renderComponent(, document.body); + var initialData = JSON.parse(document.getElementById("initial-data").innerHTML); + return React.renderComponent(, document.body); })(); diff --git a/app/common/data.js b/app/common/data.js new file mode 100644 index 0000000..0c35afa --- /dev/null +++ b/app/common/data.js @@ -0,0 +1,720 @@ +exports.lines = { + "bakerloo": "Bakerloo", + "central": "Central", + "circle": "Circle", + "district": "District", + "hammersmith-city": "Hammersmith & City", + "jubilee": "Jubilee", + "metropolitan": "Metropolitan", + "northern": "Northern", + "piccadilly": "Piccadilly", + "victoria": "Victoria", + "waterloo-city": "Waterloo & City" +}; + +exports.stations = { + "940GZZLUBST": "Baker Street", + "940GZZLUCHX": "Charing Cross", + "940GZZLUEAC": "Elephant & Castle", + "940GZZLUEMB": "Embankment", + "940GZZLUERB": "Edgware Road (Bakerloo)", + "940GZZLUHAW": "Harrow & Wealdstone", + "940GZZLUHSN": "Harlesden", + "940GZZLUKEN": "Kenton", + "940GZZLUKPK": "Kilburn Park", + "940GZZLUKSL": "Kensal Green", + "940GZZLULBN": "Lambeth North", + "940GZZLUMVL": "Maida Vale", + "940GZZLUMYB": "Marylebone", + "940GZZLUNWY": "North Wembley", + "940GZZLUOXC": "Oxford Circus", + "940GZZLUPAC": "Paddington", + "940GZZLUPCC": "Piccadilly Circus", + "940GZZLUQPS": "Queen's Park", + "940GZZLURGP": "Regent's Park", + "940GZZLUSGP": "Stonebridge Park", + "940GZZLUSKT": "South Kenton", + "940GZZLUWJN": "Willesden Junction", + "940GZZLUWKA": "Warwick Avenue", + "940GZZLUWLO": "Waterloo", + "940GZZLUWYC": "Wembley Central", + "940GZZLUADE": "Aldgate East", + "940GZZLUBBB": "Bromley-by-Bow", + "940GZZLUBBN": "Barbican", + "940GZZLUBKG": "Barking", + "940GZZLUBWR": "Bow Road", + "940GZZLUEHM": "East Ham", + "940GZZLUERC": "Edgware Road (Circle Line)", + "940GZZLUESQ": "Euston Square", + "940GZZLUFCN": "Farringdon", + "940GZZLUGHK": "Goldhawk Road", + "940GZZLUGPS": "Great Portland Street", + "940GZZLUHSC": "Hammersmith (H&C Line)", + "940GZZLUKSX": "King's Cross St. Pancras", + "940GZZLULAD": "Ladbroke Grove", + "940GZZLULRD": "Latimer Road", + "940GZZLULVT": "Liverpool Street", + "940GZZLUMED": "Mile End", + "940GZZLUMGT": "Moorgate", + "940GZZLUPAH": "Paddington (H&C Line)-Underground", + "940GZZLUPLW": "Plaistow", + "940GZZLURYO": "Royal Oak", + "940GZZLUSBM": "Shepherd's Bush Market", + "940GZZLUSGN": "Stepney Green", + "940GZZLUUPK": "Upton Park", + "940GZZLUWHM": "West Ham", + "940GZZLUWLA": "Wood Lane", + "940GZZLUWPL": "Whitechapel", + "940GZZLUWSP": "Westbourne Park", + "940GZZLUBMY": "Bermondsey", + "940GZZLUBND": "Bond Street", + "940GZZLUCGT": "Canning Town", + "940GZZLUCPK": "Canons Park", + "940GZZLUCWR": "Canada Water", + "940GZZLUCYF": "Canary Wharf", + "940GZZLUDOH": "Dollis Hill", + "940GZZLUFYR": "Finchley Road", + "940GZZLUGPK": "Green Park", + "940GZZLUKBN": "Kilburn", + "940GZZLUKBY": "Kingsbury", + "940GZZLULNB": "London Bridge", + "940GZZLUNDN": "Neasden", + "940GZZLUNGW": "North Greenwich", + "940GZZLUQBY": "Queensbury", + "940GZZLUSJW": "St. John's Wood", + "940GZZLUSTD": "Stratford", + "940GZZLUSTM": "Stanmore", + "940GZZLUSWC": "Swiss Cottage", + "940GZZLUSWK": "Southwark", + "940GZZLUWHP": "West Hampstead", + "940GZZLUWIG": "Willesden Green", + "940GZZLUWSM": "Westminster", + "940GZZLUWYP": "Wembley Park", + "940GZZLUBKE": "Barkingside", + "940GZZLUBKH": "Buckhurst Hill", + "940GZZLUBLG": "Bethnal Green", + "940GZZLUBNK": "Bank", + "940GZZLUCHL": "Chancery Lane", + "940GZZLUCWL": "Chigwell", + "940GZZLUDBN": "Debden", + "940GZZLUEAN": "East Acton", + "940GZZLUEBY": "Ealing Broadway", + "940GZZLUEPG": "Epping", + "940GZZLUFLP": "Fairlop", + "940GZZLUGFD": "Greenford", + "940GZZLUGGH": "Grange Hill", + "940GZZLUGTH": "Gants Hill", + "940GZZLUHBN": "Holborn", + "940GZZLUHGR": "Hanger Lane", + "940GZZLUHLT": "Hainault", + "940GZZLUHPK": "Holland Park", + "940GZZLULGN": "Loughton", + "940GZZLULGT": "Lancaster Gate", + "940GZZLULYN": "Leyton", + "940GZZLULYS": "Leytonstone", + "940GZZLUMBA": "Marble Arch", + "940GZZLUNAN": "North Acton", + "940GZZLUNBP": "Newbury Park", + "940GZZLUNHG": "Notting Hill Gate", + "940GZZLUNHT": "Northolt", + "940GZZLUPVL": "Perivale", + "940GZZLUQWY": "Queensway", + "940GZZLURBG": "Redbridge", + "940GZZLURSG": "Ruislip Gardens", + "940GZZLURVY": "Roding Valley", + "940GZZLUSBC": "Shepherd's Bush (Central)", + "940GZZLUSNB": "Snaresbrook", + "940GZZLUSPU": "St. Paul's", + "940GZZLUSRP": "South Ruislip", + "940GZZLUSWF": "South Woodford", + "940GZZLUTCR": "Tottenham Court Road", + "940GZZLUTHB": "Theydon Bois", + "940GZZLUWCY": "White City", + "940GZZLUWOF": "Woodford", + "940GZZLUWRP": "West Ruislip", + "940GZZLUWSD": "Wanstead", + "940GZZLUWTA": "West Acton", + "940GZZLUALD": "Aldgate", + "940GZZLUBKF": "Blackfriars", + "940GZZLUBWT": "Bayswater", + "940GZZLUCST": "Cannon Street", + "940GZZLUECT": "Earl's Court", + "940GZZLUGTR": "Gloucester Road", + "940GZZLUHSK": "High Street Kensington", + "940GZZLUMMT": "Monument", + "940GZZLUMSH": "Mansion House", + "940GZZLUSJP": "St. James's Park", + "940GZZLUSKS": "South Kensington", + "940GZZLUSSQ": "Sloane Square", + "940GZZLUTMP": "Temple", + "940GZZLUTWH": "Tower Hill", + "940GZZLUVIC": "Victoria", + "910GBLFR": "London Blackfriars Rail Station", + "940GZZLUACT": "Acton Town", + "940GZZLUBEC": "Becontree", + "940GZZLUBSC": "Barons Court", + "940GZZLUCWP": "Chiswick Park", + "940GZZLUDGE": "Dagenham East", + "940GZZLUDGY": "Dagenham Heathway", + "940GZZLUECM": "Ealing Common", + "940GZZLUEPK": "Elm Park", + "940GZZLUEPY": "East Putney", + "940GZZLUFBY": "Fulham Broadway", + "940GZZLUGBY": "Gunnersbury", + "940GZZLUHCH": "Hornchurch", + "940GZZLUHSD": "Hammersmith (Dist&Picc Line)", + "940GZZLUKOY": "Kensington (Olympia)", + "940GZZLUKWG": "Kew Gardens", + "940GZZLUPSG": "Parsons Green", + "940GZZLUPYB": "Putney Bridge", + "940GZZLURMD": "Richmond", + "940GZZLURVP": "Ravenscourt Park", + "940GZZLUSFB": "Stamford Brook", + "940GZZLUSFS": "Southfields", + "940GZZLUTNG": "Turnham Green", + "940GZZLUUPB": "Upminster Bridge", + "940GZZLUUPM": "Upminster", + "940GZZLUUPY": "Upney", + "940GZZLUWBN": "West Brompton", + "940GZZLUWIM": "Wimbledon", + "940GZZLUWIP": "Wimbledon Park", + "940GZZLUWKN": "West Kensington", + "940GZZLUAMS": "Amersham", + "940GZZLUCAL": "Chalfont & Latimer", + "940GZZLUCSM": "Chesham", + "940GZZLUCXY": "Croxley", + "940GZZLUCYD": "Chorleywood", + "940GZZLUEAE": "Eastcote", + "940GZZLUHGD": "Hillingdon", + "940GZZLUHOH": "Harrow-on-the-Hill", + "940GZZLUICK": "Ickenham", + "940GZZLUMPK": "Moor Park", + "940GZZLUNHA": "North Harrow", + "940GZZLUNKP": "Northwick Park", + "940GZZLUNOW": "Northwood", + "940GZZLUNWH": "Northwood Hills", + "940GZZLUPNR": "Pinner", + "940GZZLUPRD": "Preston Road", + "940GZZLURKW": "Rickmansworth", + "940GZZLURSM": "Ruislip Manor", + "940GZZLURSP": "Ruislip", + "940GZZLURYL": "Rayners Lane", + "940GZZLUUXB": "Uxbridge", + "940GZZLUWAF": "Watford", + "940GZZLUWHW": "West Harrow", + "940GZZLUBLR": "Blackhorse Road", + "940GZZLUBXN": "Brixton", + "940GZZLUEUS": "Euston", + "940GZZLUFPK": "Finsbury Park", + "940GZZLUHAI": "Highbury & Islington", + "940GZZLUPCO": "Pimlico", + "940GZZLUSKW": "Stockwell", + "940GZZLUSVS": "Seven Sisters", + "940GZZLUTMH": "Tottenham Hale", + "940GZZLUVXL": "Vauxhall", + "940GZZLUWRR": "Warren Street", + "940GZZLUWWL": "Walthamstow Central", + "940GZZLUACY": "Archway", + "940GZZLUAGL": "Angel", + "940GZZLUBLM": "Balham", + "940GZZLUBOR": "Borough", + "940GZZLUBTK": "Burnt Oak", + "940GZZLUBTX": "Brent Cross", + "940GZZLUBZP": "Belsize Park", + "940GZZLUCFM": "Chalk Farm", + "940GZZLUCND": "Colindale", + "940GZZLUCPC": "Clapham Common", + "940GZZLUCPN": "Clapham North", + "940GZZLUCPS": "Clapham South", + "940GZZLUCSD": "Colliers Wood", + "940GZZLUCTN": "Camden Town", + "940GZZLUEFY": "East Finchley", + "940GZZLUEGW": "Edgware", + "940GZZLUFYC": "Finchley Central", + "940GZZLUGDG": "Goodge Street", + "940GZZLUGGN": "Golders Green", + "940GZZLUHBT": "High Barnet", + "940GZZLUHCL": "Hendon Central", + "940GZZLUHGT": "Highgate", + "940GZZLUHTD": "Hampstead", + "940GZZLUKNG": "Kennington", + "940GZZLUKSH": "Kentish Town", + "940GZZLULSQ": "Leicester Square", + "940GZZLUMDN": "Morden", + "940GZZLUMHL": "Mill Hill East", + "940GZZLUMTC": "Mornington Crescent", + "940GZZLUODS": "Old Street", + "940GZZLUOVL": "Oval", + "940GZZLUSWN": "South Wimbledon", + "940GZZLUTAW": "Totteridge & Whetstone", + "940GZZLUTBC": "Tooting Bec", + "940GZZLUTBY": "Tooting Broadway", + "940GZZLUTFP": "Tufnell Park", + "940GZZLUWFN": "West Finchley", + "940GZZLUWOP": "Woodside Park", + "910GENFCOAK": "Oakwood Station", + "940GZZLUALP": "Alperton", + "940GZZLUASG": "Arnos Grove", + "940GZZLUASL": "Arsenal", + "940GZZLUBDS": "Bounds Green", + "940GZZLUBOS": "Boston Manor", + "940GZZLUCAR": "Caledonian Road", + "940GZZLUCGN": "Covent Garden", + "940GZZLUCKS": "Cockfosters", + "940GZZLUHNX": "Hatton Cross", + "940GZZLUHPC": "Hyde Park Corner", + "940GZZLUHR4": "Heathrow Terminal 4", + "940GZZLUHR5": "Heathrow Terminal 5", + "940GZZLUHRC": "Heathrow Terminals 1-2-3 ", + "940GZZLUHWC": "Hounslow Central", + "940GZZLUHWE": "Hounslow East", + "940GZZLUHWT": "Hounslow West", + "940GZZLUHWY": "Holloway Road", + "940GZZLUKNB": "Knightsbridge", + "940GZZLUMRH": "Manor House", + "940GZZLUNEN": "North Ealing", + "940GZZLUNFD": "Northfields", + "940GZZLUOAK": "Oakwood", + "940GZZLUOSY": "Osterley", + "940GZZLUPKR": "Park Royal", + "940GZZLURSQ": "Russell Square", + "940GZZLUSEA": "South Ealing", + "940GZZLUSGT": "Southgate", + "940GZZLUSHH": "South Harrow", + "940GZZLUSUH": "Sudbury Hill", + "940GZZLUSUT": "Sudbury Town", + "940GZZLUTPN": "Turnpike Lane", + "940GZZLUWOG": "Wood Green" +}; + +exports.stationsOnLines = { + "bakerloo": [ + "940GZZLUBST", + "940GZZLUCHX", + "940GZZLUEAC", + "940GZZLUEMB", + "940GZZLUERB", + "940GZZLUHAW", + "940GZZLUHSN", + "940GZZLUKEN", + "940GZZLUKPK", + "940GZZLUKSL", + "940GZZLULBN", + "940GZZLUMVL", + "940GZZLUMYB", + "940GZZLUNWY", + "940GZZLUOXC", + "940GZZLUPAC", + "940GZZLUPCC", + "940GZZLUQPS", + "940GZZLURGP", + "940GZZLUSGP", + "940GZZLUSKT", + "940GZZLUWJN", + "940GZZLUWKA", + "940GZZLUWLO", + "940GZZLUWYC" + ], + "central": [ + "940GZZLUBKE", + "940GZZLUBKH", + "940GZZLUBLG", + "940GZZLUBND", + "940GZZLUBNK", + "940GZZLUCHL", + "940GZZLUCWL", + "940GZZLUDBN", + "940GZZLUEAN", + "940GZZLUEBY", + "940GZZLUEPG", + "940GZZLUFLP", + "940GZZLUGFD", + "940GZZLUGGH", + "940GZZLUGTH", + "940GZZLUHBN", + "940GZZLUHGR", + "940GZZLUHLT", + "940GZZLUHPK", + "940GZZLULGN", + "940GZZLULGT", + "940GZZLULVT", + "940GZZLULYN", + "940GZZLULYS", + "940GZZLUMBA", + "940GZZLUMED", + "940GZZLUNAN", + "940GZZLUNBP", + "940GZZLUNHG", + "940GZZLUNHT", + "940GZZLUOXC", + "940GZZLUPVL", + "940GZZLUQWY", + "940GZZLURBG", + "940GZZLURSG", + "940GZZLURVY", + "940GZZLUSBC", + "940GZZLUSNB", + "940GZZLUSPU", + "940GZZLUSRP", + "940GZZLUSTD", + "940GZZLUSWF", + "940GZZLUTCR", + "940GZZLUTHB", + "940GZZLUWCY", + "940GZZLUWOF", + "940GZZLUWRP", + "940GZZLUWSD", + "940GZZLUWTA" + ], + "circle": [ + "940GZZLUADE", + "940GZZLUALD", + "940GZZLUBBB", + "940GZZLUBBN", + "940GZZLUBKF", + "940GZZLUBKG", + "940GZZLUBST", + "940GZZLUBWR", + "940GZZLUBWT", + "940GZZLUCST", + "940GZZLUECT", + "940GZZLUEHM", + "940GZZLUEMB", + "940GZZLUERC", + "940GZZLUESQ", + "940GZZLUFCN", + "940GZZLUGHK", + "940GZZLUGPS", + "940GZZLUGTR", + "940GZZLUHSC", + "940GZZLUHSK", + "940GZZLUKSX", + "940GZZLULAD", + "940GZZLULRD", + "940GZZLULVT", + "940GZZLUMED", + "940GZZLUMGT", + "940GZZLUMMT", + "940GZZLUMSH", + "940GZZLUNHG", + "940GZZLUPAC", + "940GZZLUPAH", + "940GZZLUPLW", + "940GZZLURYO", + "940GZZLUSBM", + "940GZZLUSGN", + "940GZZLUSJP", + "940GZZLUSKS", + "940GZZLUSSQ", + "940GZZLUTMP", + "940GZZLUTWH", + "940GZZLUUPK", + "940GZZLUVIC", + "940GZZLUWHM", + "940GZZLUWLA", + "940GZZLUWPL", + "940GZZLUWSM", + "940GZZLUWSP" + ], + "district": [ + "910GBLFR", + "940GZZLUACT", + "940GZZLUADE", + "940GZZLUBBB", + "940GZZLUBEC", + "940GZZLUBKF", + "940GZZLUBKG", + "940GZZLUBSC", + "940GZZLUBWR", + "940GZZLUBWT", + "940GZZLUCST", + "940GZZLUCWP", + "940GZZLUDGE", + "940GZZLUDGY", + "940GZZLUEBY", + "940GZZLUECM", + "940GZZLUECT", + "940GZZLUEHM", + "940GZZLUEMB", + "940GZZLUEPK", + "940GZZLUEPY", + "940GZZLUERC", + "940GZZLUFBY", + "940GZZLUGBY", + "940GZZLUGHK", + "940GZZLUGTR", + "940GZZLUHCH", + "940GZZLUHSC", + "940GZZLUHSD", + "940GZZLUHSK", + "940GZZLUKOY", + "940GZZLUKWG", + "940GZZLULAD", + "940GZZLULRD", + "940GZZLUMED", + "940GZZLUMMT", + "940GZZLUMSH", + "940GZZLUNHG", + "940GZZLUPAC", + "940GZZLUPAH", + "940GZZLUPLW", + "940GZZLUPSG", + "940GZZLUPYB", + "940GZZLURMD", + "940GZZLURVP", + "940GZZLURYO", + "940GZZLUSBM", + "940GZZLUSFB", + "940GZZLUSFS", + "940GZZLUSGN", + "940GZZLUSJP", + "940GZZLUSKS", + "940GZZLUSSQ", + "940GZZLUTMP", + "940GZZLUTNG", + "940GZZLUTWH", + "940GZZLUUPB", + "940GZZLUUPK", + "940GZZLUUPM", + "940GZZLUUPY", + "940GZZLUVIC", + "940GZZLUWBN", + "940GZZLUWHM", + "940GZZLUWIM", + "940GZZLUWIP", + "940GZZLUWKN", + "940GZZLUWLA", + "940GZZLUWPL", + "940GZZLUWSM", + "940GZZLUWSP" + ], + "hammersmith-city": [ + "940GZZLUADE", + "940GZZLUBBB", + "940GZZLUBBN", + "940GZZLUBKG", + "940GZZLUBST", + "940GZZLUBWR", + "940GZZLUEHM", + "940GZZLUERC", + "940GZZLUESQ", + "940GZZLUFCN", + "940GZZLUGHK", + "940GZZLUGPS", + "940GZZLUHSC", + "940GZZLUKSX", + "940GZZLULAD", + "940GZZLULRD", + "940GZZLULVT", + "940GZZLUMED", + "940GZZLUMGT", + "940GZZLUPAH", + "940GZZLUPLW", + "940GZZLURYO", + "940GZZLUSBM", + "940GZZLUSGN", + "940GZZLUUPK", + "940GZZLUWHM", + "940GZZLUWLA", + "940GZZLUWPL", + "940GZZLUWSP" + ], + "jubilee": [ + "940GZZLUBMY", + "940GZZLUBND", + "940GZZLUBST", + "940GZZLUCGT", + "940GZZLUCPK", + "940GZZLUCWR", + "940GZZLUCYF", + "940GZZLUDOH", + "940GZZLUFYR", + "940GZZLUGPK", + "940GZZLUKBN", + "940GZZLUKBY", + "940GZZLULNB", + "940GZZLUNDN", + "940GZZLUNGW", + "940GZZLUQBY", + "940GZZLUSJW", + "940GZZLUSTD", + "940GZZLUSTM", + "940GZZLUSWC", + "940GZZLUSWK", + "940GZZLUWHM", + "940GZZLUWHP", + "940GZZLUWIG", + "940GZZLUWLO", + "940GZZLUWSM", + "940GZZLUWYP" + ], + "metropolitan": [ + "940GZZLUALD", + "940GZZLUAMS", + "940GZZLUBBN", + "940GZZLUBST", + "940GZZLUCAL", + "940GZZLUCSM", + "940GZZLUCXY", + "940GZZLUCYD", + "940GZZLUEAE", + "940GZZLUESQ", + "940GZZLUFCN", + "940GZZLUFYR", + "940GZZLUGPS", + "940GZZLUHGD", + "940GZZLUHOH", + "940GZZLUICK", + "940GZZLUKSX", + "940GZZLULVT", + "940GZZLUMGT", + "940GZZLUMPK", + "940GZZLUNHA", + "940GZZLUNKP", + "940GZZLUNOW", + "940GZZLUNWH", + "940GZZLUPNR", + "940GZZLUPRD", + "940GZZLURKW", + "940GZZLURSM", + "940GZZLURSP", + "940GZZLURYL", + "940GZZLUUXB", + "940GZZLUWAF", + "940GZZLUWHW", + "940GZZLUWYP" + ], + "northern": [ + "940GZZLUACY", + "940GZZLUAGL", + "940GZZLUBLM", + "940GZZLUBNK", + "940GZZLUBOR", + "940GZZLUBTK", + "940GZZLUBTX", + "940GZZLUBZP", + "940GZZLUCFM", + "940GZZLUCHX", + "940GZZLUCND", + "940GZZLUCPC", + "940GZZLUCPN", + "940GZZLUCPS", + "940GZZLUCSD", + "940GZZLUCTN", + "940GZZLUEAC", + "940GZZLUEFY", + "940GZZLUEGW", + "940GZZLUEMB", + "940GZZLUEUS", + "940GZZLUFYC", + "940GZZLUGDG", + "940GZZLUGGN", + "940GZZLUHBT", + "940GZZLUHCL", + "940GZZLUHGT", + "940GZZLUHTD", + "940GZZLUKNG", + "940GZZLUKSH", + "940GZZLUKSX", + "940GZZLULNB", + "940GZZLULSQ", + "940GZZLUMDN", + "940GZZLUMGT", + "940GZZLUMHL", + "940GZZLUMTC", + "940GZZLUODS", + "940GZZLUOVL", + "940GZZLUSKW", + "940GZZLUSWN", + "940GZZLUTAW", + "940GZZLUTBC", + "940GZZLUTBY", + "940GZZLUTCR", + "940GZZLUTFP", + "940GZZLUWFN", + "940GZZLUWLO", + "940GZZLUWOP", + "940GZZLUWRR" + ], + "piccadilly": [ + "910GENFCOAK", + "940GZZLUACT", + "940GZZLUALP", + "940GZZLUASG", + "940GZZLUASL", + "940GZZLUBDS", + "940GZZLUBOS", + "940GZZLUBSC", + "940GZZLUCAR", + "940GZZLUCGN", + "940GZZLUCKS", + "940GZZLUCWP", + "940GZZLUEAE", + "940GZZLUECM", + "940GZZLUECT", + "940GZZLUFPK", + "940GZZLUGPK", + "940GZZLUGTR", + "940GZZLUHBN", + "940GZZLUHGD", + "940GZZLUHNX", + "940GZZLUHPC", + "940GZZLUHR4", + "940GZZLUHR5", + "940GZZLUHRC", + "940GZZLUHSD", + "940GZZLUHWC", + "940GZZLUHWE", + "940GZZLUHWT", + "940GZZLUHWY", + "940GZZLUICK", + "940GZZLUKNB", + "940GZZLUKSX", + "940GZZLULSQ", + "940GZZLUMRH", + "940GZZLUNEN", + "940GZZLUNFD", + "940GZZLUOAK", + "940GZZLUOSY", + "940GZZLUPCC", + "940GZZLUPKR", + "940GZZLURSM", + "940GZZLURSP", + "940GZZLURSQ", + "940GZZLURVP", + "940GZZLURYL", + "940GZZLUSEA", + "940GZZLUSFB", + "940GZZLUSGT", + "940GZZLUSHH", + "940GZZLUSKS", + "940GZZLUSUH", + "940GZZLUSUT", + "940GZZLUTNG", + "940GZZLUTPN", + "940GZZLUUXB", + "940GZZLUWOG" + ], + "victoria": [ + "940GZZLUBLR", + "940GZZLUBXN", + "940GZZLUEUS", + "940GZZLUFPK", + "940GZZLUGPK", + "940GZZLUHAI", + "940GZZLUKSX", + "940GZZLUOXC", + "940GZZLUPCO", + "940GZZLUSKW", + "940GZZLUSVS", + "940GZZLUTMH", + "940GZZLUVIC", + "940GZZLUVXL", + "940GZZLUWRR", + "940GZZLUWWL" + ], + "waterloo-city": [ + "940GZZLUBNK", + "940GZZLUWLO" + ] +}; diff --git a/app/utils.js b/app/common/utils.js similarity index 76% rename from app/utils.js rename to app/common/utils.js index efffa0a..9d9a2e2 100644 --- a/app/utils.js +++ b/app/common/utils.js @@ -14,7 +14,7 @@ exports.httpRequest = function(url, success, error) { request.onload = function() { if (this.status === 200) { - success(this.responseXML); + success(this.responseText); } else { error(new Error(this.status)); @@ -22,19 +22,20 @@ exports.httpRequest = function(url, success, error) { }; request.onerror = function() { - error(this.status); + error(new Error(this.status)); }; request.send(); }; -exports.proxyRequestURL = function(url) { - var query = "select * from xml where url='" + url + "'"; - return "http://query.yahooapis.com/v1/public/yql?q=" + encodeURIComponent(query); +exports.apiRequestURL = function(line, station) { + return "/api/" + line + "/" + station; }; -exports.validateResponse = function(responseDoc) { - return responseDoc.getElementsByTagName("S").length === 1; +exports.formattedTimeUntil = function(timeTo) { + var minutes = Math.round(timeTo / 60); + var seconds = Math.round((timeTo - (minutes * 60)) / 30) * 30; + return "" + minutes + ":" + (seconds < 10 ? "0" : "") + (seconds > 0 ? seconds : "0"); }; exports.getQueryString = function() { @@ -78,7 +79,3 @@ exports.isStationOnLine = function(line, station, data) { return this.isLine(line, data) && this.isStation(station, data) && data.stationsOnLines[line].indexOf(station) >= 0; }; - -exports.mapCircleLineStation = function(station, data) { - return data.circleLineMap[station]; -}; diff --git a/app/component/network.js b/app/component/network.jsx similarity index 94% rename from app/component/network.js rename to app/component/network.jsx index e2cc16f..3b7fdd7 100644 --- a/app/component/network.js +++ b/app/component/network.jsx @@ -1,12 +1,12 @@ /** @jsx React.DOM */ var React = require("react"); -var utils = require("../utils"); +var utils = require("../common/utils"); var Network = React.createClass({ getInitialState: function() { return { - collapsible: window.innerWidth <= 800, + collapsible: global ? false : window.innerWidth <= 800, open: false }; }, @@ -19,7 +19,7 @@ var Network = React.createClass({ this.setState({ collapsible: window.innerWidth <= 800 }); }, - componentWillMount: function() { + componentDidMount: function() { // Simple event debouncing to avoid multiple recalculations this.debounce = utils.debounceEvent(this.handleResize, 250); window.addEventListener("resize", this.debounce, false); @@ -78,7 +78,7 @@ var Line = React.createClass({ return (
-
+
{networkData.lines[lineCode]} diff --git a/app/component/predictions.js b/app/component/predictions.jsx similarity index 64% rename from app/component/predictions.js rename to app/component/predictions.jsx index 925e955..6af5f0d 100644 --- a/app/component/predictions.js +++ b/app/component/predictions.jsx @@ -1,26 +1,19 @@ /** @jsx React.DOM */ var React = require("react"); -var Prediction = require("../model/prediction"); -var utils = require("../utils"); +var utils = require("../common/utils"); var Predictions = React.createClass({ getInitialState: function() { - return { status: this.props.line && this.props.station ? "loading" : "welcome" }; + return { + status: this.props.initialData ? "success" : "welcome", + predictionData: this.props.initialData + }; }, fetchPredictions: function(line, station) { - // The circle line isn't defined in the API but shares platforms with other lines - if (line === "O") { - line = utils.mapCircleLineStation(station, this.props.networkData); - } - - var api = "http://cloud.tfl.gov.uk/TrackerNet/PredictionDetailed/" + line + "/" + station; - this.setState({ status: "loading" }); - - // The TrackerNet API does not support cross-origin requests so we must use a proxy - utils.httpRequest(utils.proxyRequestURL(api), this.predictionsSuccess, this.predictionsError); + utils.httpRequest(utils.apiRequestURL(line, station), this.predictionsSuccess, this.predictionsError); }, predictionsError: function(error) { @@ -33,19 +26,14 @@ var Predictions = React.createClass({ // Airbrake.push({ error: error }); }, - predictionsSuccess: function(responseDoc) { - // Because we're using a proxy it will return a 200 and XML even if the - // TrackerNet API is unavailable or request was invalid. - if (!utils.validateResponse(responseDoc)) { + predictionsSuccess: function(responseData) { + if (!responseData.length) { return this.predictionsError(new Error("Invalid API response")); } this.setState({ status: "success", - - // Dealing with XML in the browser is so ugly that I've - // used 'models' to abstract it away. - predictionData: new Prediction(responseDoc) + predictionData: JSON.parse(responseData) }); }, @@ -92,22 +80,21 @@ var Predictions = React.createClass({ var DepartureBoard = React.createClass({ render: function() { - var predictionData = this.props.predictionData; - var station = predictionData.station(); + var station = this.props.predictionData.station; + var platforms = this.props.predictionData.platforms; - var generatedPlatforms = station.platforms().map(function(platform) { + var generatedPlatforms = Object.keys(platforms).map(function(platform, i) { return ( -
-

{platform.name()}

- +
+

{platform}

+
); }); - // Heading does not account for circle line mapping, meh return (
-

{station.name() + " " + predictionData.line()}

+

{station.stationName + " Station, " + station.lineName + " Line"}

{generatedPlatforms}
); @@ -119,11 +106,13 @@ var Trains = React.createClass({ render: function() { var generatedTrains = this.props.trains.map(function(train) { + var timeTo = utils.formattedTimeUntil(train.timeToStation); + return ( - - {train.timeTo()} - {train.destination()} - {train.location()} + + {timeTo === "0:00" ? "-" : timeTo} + {train.towards} + {train.currentLocation} ); }); diff --git a/app/component/tube-tracker.js b/app/component/tube-tracker.jsx similarity index 72% rename from app/component/tube-tracker.js rename to app/component/tube-tracker.jsx index 4f74e4b..a5b8ad5 100644 --- a/app/component/tube-tracker.js +++ b/app/component/tube-tracker.jsx @@ -1,23 +1,18 @@ /** @jsx React.DOM */ var React = require("react"); -var Predictions = require("./predictions"); -var Network = require("./network"); -var utils = require("../utils"); +var utils = require("../common/utils"); +var Network = require("./network.jsx"); +var Predictions = require("./predictions.jsx"); var TubeTracker = React.createClass({ - validateUserInput: function(line, station) { - return /^[A-Z]{1}$/.test(line) && /^[A-Z]{3}$/.test(station) && - utils.isStationOnLine(line, station, this.props.networkData); - }, - formatAndValidateUserInput: function(userLine, userStation) { var line = null; var station = null; // We could have added extra states for invalid data // but it's easier simply to ignore it. - if (this.validateUserInput(userLine, userStation)) { + if (utils.isStationOnLine(userLine, userStation, this.props.networkData)) { line = userLine; station = userStation; } @@ -29,9 +24,11 @@ var TubeTracker = React.createClass({ }, getInitialState: function() { + var initialData = this.props.initialData; + return this.formatAndValidateUserInput( - utils.queryStringProperty(utils.getQueryString(), "line"), - utils.queryStringProperty(utils.getQueryString(), "station") + initialData ? initialData.request.lineCode : null, + initialData ? initialData.request.stationCode : null ); }, @@ -49,7 +46,7 @@ var TubeTracker = React.createClass({ window.history.pushState(null, null, utils.formatQueryString(newState)); }, - componentWillMount: function() { + componentDidMount: function() { window.addEventListener("tt:update", this.handleUpdate, false); }, @@ -64,7 +61,7 @@ var TubeTracker = React.createClass({
- +
); diff --git a/app/data.js b/app/data.js deleted file mode 100644 index bd28d2a..0000000 --- a/app/data.js +++ /dev/null @@ -1,594 +0,0 @@ -exports.lines = { - "B": "Bakerloo", - "C": "Central", - "O": "Circle", - "D": "District", - "H": "Hammersmith & City", - "J": "Jubilee", - "M": "Metropolitan", - "N": "Northern", - "P": "Piccadilly", - "V": "Victoria", - "W": "Waterloo & City" -}; - -/* -Stations missing from TfL's TrackerNet: -- Bayswater -- Chesham -- Goldhawk Road -- Ladbroke Grove -- Latimer Road -- Paddington Circle/District Line -- Preston Road -- Royal Oak -- Shepherd's Bush Market -- Westbourne Park -- Wood Lane -*/ -exports.stations = { - "BST": "Baker Street", - "CHX": "Charing Cross", - "ERB": "Edgware Road (Bakerloo)", - "ELE": "Elephant and Castle", - "EMB": "Embankment", - "HSD": "Harlesden", - "HAW": "Harrow and Wealdstone", - "KGN": "Kensal Green", - "KNT": "Kenton", - "KPK": "Kilburn Park", - "LAM": "Lambeth North", - "MDV": "Maida Vale", - "MYB": "Marylebone", - "NWM": "North Wembley", - "OXC": "Oxford Circus", - "PAD": "Paddington", - "PIC": "Piccadilly Circus", - "QPK": "Queen's Park", - "RPK": "Regent's Park", - "SKT": "South Kenton", - "SPK": "Stonebridge Park", - "WAR": "Warwick Avenue", - "WLO": "Waterloo", - "WEM": "Wembley Central", - "WJN": "Willesden Junction", - "BNK": "Bank", - "BDE": "Barkingside", - "BNG": "Bethnal Green", - "BDS": "Bond Street", - "BHL": "Buckhurst Hill", - "CYL": "Chancery Lane", - "CHG": "Chigwell", - "DEB": "Debden", - "EBY": "Ealing Broadway", - "EAC": "East Acton", - "EPP": "Epping", - "FLP": "Fairlop", - "GHL": "Gants Hill", - "GRH": "Grange Hill", - "GFD": "Greenford", - "HAI": "Hainault", - "HLN": "Hanger Lane", - "HOL": "Holborn", - "HPK": "Holland Park", - "LAN": "Lancaster Gate", - "LEY": "Leyton", - "LYS": "Leytonstone", - "LST": "Liverpool Street", - "LTN": "Loughton", - "MAR": "Marble Arch", - "MLE": "Mile End", - "NEP": "Newbury Park", - "NAC": "North Acton", - "NHT": "Northolt", - "NHG": "Notting Hill Gate", - "PER": "Perivale", - "QWY": "Queensway", - "RED": "Redbridge", - "ROD": "Roding Valley", - "RUG": "Ruislip Gardens", - "SBC": "Shepherd's Bush", - "SNB": "Snaresbrook", - "SRP": "South Ruislip", - "SWF": "South Woodford", - "STP": "St Paul's", - "SFD": "Stratford", - "THB": "Theydon Bois", - "TCR": "Tottenham Court Road", - "WAN": "Wanstead", - "WAC": "West Acton", - "WRP": "West Ruislip", - "WCT": "White City", - "WFD": "Woodford", - "ACT": "Acton Town", - "ALE": "Aldgate East", - "BKG": "Barking", - "BCT": "Barons Court", - "BEC": "Becontree", - "BLF": "Blackfriars", - "BWR": "Bow Road", - "BBB": "Bromley-by-Bow", - "CST": "Cannon Street", - "CHP": "Chiswick Park", - "DGE": "Dagenham East", - "DGH": "Dagenham Heathway", - "ECM": "Ealing Common", - "ECT": "Earl's Court", - "EHM": "East Ham", - "EPY": "East Putney", - "ERD": "Edgware Road (H & C)", - "EPK": "Elm Park", - "FBY": "Fulham Broadway", - "GRD": "Gloucester Road", - "GUN": "Gunnersbury", - "HMD": "Hammersmith (District and Picc)", - "HST": "High Street Kensington", - "HCH": "Hornchurch", - "OLY": "Kensington (Olympia)", - "KEW": "Kew Gardens", - "MAN": "Mansion House", - "MON": "Monument", - "PGR": "Parsons Green", - "PLW": "Plaistow", - "PUT": "Putney Bridge", - "RCP": "Ravenscourt Park", - "RMD": "Richmond", - "SSQ": "Sloane Square", - "SKN": "South Kensington", - "SFS": "Southfields", - "SJP": "St. James's Park", - "STB": "Stamford Brook", - "STG": "Stepney Green", - "TEM": "Temple", - "THL": "Tower Hill", - "TGR": "Turnham Green", - "UPM": "Upminster", - "UPB": "Upminster Bridge", - "UPY": "Upney", - "UPK": "Upton Park", - "VIC": "Victoria", - "WBT": "West Brompton", - "WHM": "West Ham", - "WKN": "West Kensington", - "WMS": "Westminster", - "WCL": "Whitechapel", - "WDN": "Wimbledon", - "WMP": "Wimbledon Park", - "ALD": "Aldgate", - "BAR": "Barbican", - "ESQ": "Euston Square", - "FAR": "Farringdon", - "GPS": "Great Portland Street", - "HMS": "Hammersmith", - "KXX": "King's Cross St Pancras", - "MGT": "Moorgate", - "BER": "Bermondsey", - "CWR": "Canada Water", - "CWF": "Canary Wharf", - "CNT": "Canning Town", - "CPK": "Canons Park", - "DHL": "Dollis Hill", - "FRD": "Finchley Road", - "GPK": "Green Park", - "KIL": "Kilburn", - "KBY": "Kingsbury", - "LON": "London Bridge", - "NEA": "Neasden", - "NGW": "North Greenwich", - "QBY": "Queensbury", - "SWK": "Southwark", - "SJW": "St John's Wood", - "STA": "Stanmore", - "SWC": "Swiss Cottage", - "WPK": "Wembley Park", - "WHD": "West Hampstead", - "WLG": "Willesden Green", - "AME": "Amersham", - "CLF": "Chalfont and Latimer", - "CWD": "Chorleywood", - "CLW": "Colliers Wood", - "CRX": "Croxley", - "ETE": "Eastcote", - "HOH": "Harrow on the Hill", - "HDN": "Hillingdon", - "ICK": "Ickenham", - "MPK": "Moor Park", - "NHR": "North Harrow", - "NWP": "Northwick Park", - "NWD": "Northwood", - "NWH": "Northwood Hills", - "PIN": "Pinner", - "RLN": "Rayners Lane", - "RKY": "Rickmansworth", - "RUI": "Ruislip", - "RUM": "Ruislip Manor", - "UXB": "Uxbridge", - "WAT": "Watford", - "WHR": "West Harrow", - "ANG": "Angel", - "ARC": "Archway", - "BAL": "Balham", - "BPK": "Belsize Park", - "BOR": "Borough", - "BTX": "Brent Cross", - "BUR": "Burnt Oak", - "CTN": "Camden Town", - "CHF": "Chalk Farm", - "CPC": "Clapham Common", - "CPN": "Clapham North", - "CPS": "Clapham South", - "COL": "Colindale", - "EFY": "East Finchley", - "EDG": "Edgware", - "EUS": "Euston", - "FYC": "Finchley Central", - "GGR": "Golders Green", - "GST": "Goodge Street", - "HMP": "Hampstead", - "HND": "Hendon Central", - "HBT": "High Barnet", - "HIG": "Highgate", - "KEN": "Kennington", - "KTN": "Kentish Town", - "LSQ": "Leicester Square", - "MHE": "Mill Hill East", - "MOR": "Morden", - "MCR": "Mornington Crescent", - "OLD": "Old Street", - "OVL": "Oval", - "SWM": "South Wimbledon", - "STK": "Stockwell", - "TBE": "Tooting Bec", - "TBY": "Tooting Broadway", - "TOT": "Totteridge and Whetstone", - "TPK": "Tufnell Park", - "WST": "Warren Street", - "WFY": "West Finchley", - "WSP": "Woodside Park", - "ALP": "Alperton", - "AGR": "Arnos Grove", - "ARL": "Arsenal", - "BOS": "Boston Manor", - "BGR": "Bounds Green", - "CRD": "Caledonian Road", - "CFS": "Cockfosters", - "COV": "Covent Garden", - "FPK": "Finsbury Park", - "HTX": "Hatton Cross", - "HTF": "Heathrow Terminal 4", - "HRV": "Heathrow Terminal 5", - "HRC": "Heathrow Terminals 123", - "HRD": "Holloway Road", - "HNC": "Hounslow Central", - "HNE": "Hounslow East", - "HNW": "Hounslow West", - "HPC": "Hyde Park Corner", - "KNB": "Knightsbridge", - "MNR": "Manor House", - "NEL": "North Ealing", - "NFD": "Northfields", - "OAK": "Oakwood", - "OST": "Osterley", - "PRY": "Park Royal", - "RSQ": "Russell Square", - "SEL": "South Ealing", - "SHR": "South Harrow", - "SGT": "Southgate", - "SHL": "Sudbury Hill", - "STN": "Sudbury Town", - "TPL": "Turnpike Lane", - "WGN": "Wood Green", - "BHR": "Blackhorse Road", - "BRX": "Brixton", - "HBY": "Highbury and Islington", - "PIM": "Pimlico", - "SVS": "Seven Sisters", - "TTH": "Tottenham Hale", - "VUX": "Vauxhall", - "WAL": "Walthamstow Central" -}; - -exports.stationsOnLines = { - "B": ["BST", "CHX", "ERB", "ELE", "EMB", "HSD", "HAW", "KGN", "KNT", "KPK", "LAM", "MDV", "MYB", "NWM", "OXC", "PAD", "PIC", "QPK", "RPK", "SKT", "SPK", "WAR", "WLO", "WEM", "WJN"], - "C": ["BNK", "BDE", "BNG", "BDS", "BHL", "CYL", "CHG", "DEB", "EBY", "EAC", "EPP", "FLP", "GHL", "GRH", "GFD", "HAI", "HLN", "HOL", "HPK", "LAN", "LEY", "LYS", "LST", "LTN", "MAR", "MLE", "NEP", "NAC", "NHT", "NHG", "OXC", "PER", "QWY", "RED", "ROD", "RUG", "SBC", "SNB", "SRP", "SWF", "STP", "SFD", "THB", "TCR", "WAN", "WAC", "WRP", "WCT", "WFD"], - "O": ["ALD", "BAR", "BLF", "BST", "CST", "EMB", "ERD", "ESQ", "FAR", "GPS", "GRD", "HMS", "HST", "KXX", "LST", "MAN", "MGT", "MON", "NHG", "SJP", "SKN", "SSQ", "TEM", "THL", "VIC", "WMS"], - "D": ["ACT", "ALE", "BKG", "BCT", "BEC", "BLF", "BWR", "BBB", "CST", "CHP", "DGE", "DGH", "EBY", "ECM", "ECT", "EHM", "EPY", "ERD", "EPK", "EMB", "FBY", "GRD", "GUN", "HMD", "HST", "HCH", "OLY", "KEW", "MAN", "MLE", "MON", "OLY", "PGR", "PLW", "PUT", "RCP", "RMD", "SSQ", "SKN", "SFS", "SJP", "STB", "STG", "TEM", "THL", "TGR", "UPM", "UPB", "UPY", "UPK", "VIC", "WBT", "WHM", "WKN", "WMS", "WCL", "WDN", "WMP"], - "H": ["ALD", "ALE", "BST", "BAR", "BKG", "BLF", "BWR", "BBB", "CST", "EHM", "ERD", "EMB", "ESQ", "FAR", "GRD", "GPS", "HMS", "HST", "KXX", "LST", "MAN", "MLE", "MON", "MGT", "PAD", "PLW", "SSQ", "SKN", "SJP", "STG", "TEM", "THL", "UPK", "VIC", "WHM", "WMS", "WCL"], - "J": ["BST", "BER", "BDS", "CWR", "CWF", "CNT", "CPK", "DHL", "FRD", "GPK", "KIL", "KBY", "LON", "NEA", "NGW", "QBY", "SWK", "SJW", "STA", "SFD", "SWC", "WLO", "WPK", "WHM", "WHD", "WMS", "WLG"], - "M": ["ALD", "AME", "BST", "BAR", "CLF", "CWD", "CLW", "CRX", "ETE", "ESQ", "FAR", "FRD", "GPS", "HOH", "HDN", "ICK", "KXX", "LST", "MPK", "MGT", "NHR", "NWP", "NWD", "NWH", "PIN", "RLN", "RKY", "RUI", "RUM", "UXB", "WAT", "WPK", "WHR"], - "N": ["ANG", "ARC", "BAL", "BNK", "BPK", "BOR", "BTX", "BUR", "CTN", "CHF", "CHX", "CPC", "CPN", "CPS", "COL", "CLW", "EFY", "EDG", "ELE", "EMB", "EUS", "FYC", "GGR", "GST", "HMP", "HND", "HBT", "HIG", "KEN", "KTN", "KXX", "LSQ", "LON", "MHE", "MGT", "MOR", "MCR", "OLD", "OVL", "SWM", "STK", "TBE", "TBY", "TCR", "TOT", "TPK", "WST", "WLO", "WFY", "WSP"], - "P": ["ACT", "ALP", "AGR", "ARL", "BCT", "BOS", "BGR", "CRD", "CFS", "COV", "ECM", "ECT", "ETE", "FPK", "GRD", "GPK", "HMD", "HTX", "HTF", "HRV", "HRC", "HDN", "HOL", "HRD", "HNC", "HNE", "HNW", "HPC", "ICK", "KXX", "KNB", "LSQ", "MNR", "NEL", "NFD", "OAK", "OST", "PRY", "PIC", "RLN", "RUI", "RUM", "RSQ", "SEL", "SHR", "SKN", "SGT", "SHL", "STN", "TGR", "TPL", "UXB", "WGN"], - "V": ["BHR", "BRX", "EUS", "FPK", "GPK", "HBY", "KXX", "OXC", "PIM", "SVS", "STK", "TTH", "VUX", "VIC", "WAL", "WST"], - "W": ["BNK", "WLO"] -}; - -exports.circleLineMap = { - "ALD": "M", - "BAR": "H", - "BLF": "D", - "BST": "H", - "CST": "D", - "EMB": "D", - "ERD": "H", - "ESQ": "H", - "FAR": "H", - "GPS": "H", - "GRD": "D", - "HMS": "H", - "HST": "D", - "KXX": "H", - "LST": "H", - "MAN": "D", - "MGT": "H", - "MON": "D", - "NHG": "D", - "SJP": "D", - "SKN": "D", - "SSQ": "D", - "TEM": "D", - "THL": "D", - "VIC": "D", - "WMS": "D" -}; - -exports.linesAtStations = { - "BST": ["B", "H", "J", "M"], - "CHX": ["B", "N"], - "ERB": ["B"], - "ELE": ["B", "N"], - "EMB": ["B", "D", "H", "N"], - "HSD": ["B"], - "HAW": ["B"], - "KGN": ["B"], - "KNT": ["B"], - "KPK": ["B"], - "LAM": ["B"], - "MDV": ["B"], - "MYB": ["B"], - "NWM": ["B"], - "OXC": ["B", "C", "V"], - "PAD": ["B", "H"], - "PIC": ["B", "P"], - "QPK": ["B"], - "RPK": ["B"], - "SKT": ["B"], - "SPK": ["B"], - "WAR": ["B"], - "WLO": ["B", "J", "N", "W"], - "WEM": ["B"], - "WJN": ["B"], - "BNK": ["C", "N", "W"], - "BDE": ["C"], - "BNG": ["C"], - "BDS": ["C", "J"], - "BHL": ["C"], - "CYL": ["C"], - "CHG": ["C"], - "DEB": ["C"], - "EBY": ["C", "D"], - "EAC": ["C"], - "EPP": ["C"], - "FLP": ["C"], - "GHL": ["C"], - "GRH": ["C"], - "GFD": ["C"], - "HAI": ["C"], - "HLN": ["C"], - "HOL": ["C", "P"], - "HPK": ["C"], - "LAN": ["C"], - "LEY": ["C"], - "LYS": ["C"], - "LST": ["C", "H", "M"], - "LTN": ["C"], - "MAR": ["C"], - "MLE": ["C", "D", "H"], - "NEP": ["C"], - "NAC": ["C"], - "NHT": ["C"], - "NHG": ["C"], - "PER": ["C"], - "QWY": ["C"], - "RED": ["C"], - "ROD": ["C"], - "RUG": ["C"], - "SBC": ["C"], - "SNB": ["C"], - "SRP": ["C"], - "SWF": ["C"], - "STP": ["C"], - "SFD": ["C", "J"], - "THB": ["C"], - "TCR": ["C", "N"], - "WAN": ["C"], - "WAC": ["C"], - "WRP": ["C"], - "WCT": ["C"], - "WFD": ["C"], - "ACT": ["D", "P"], - "ALE": ["D", "H"], - "BKG": ["D", "H"], - "BCT": ["D", "P"], - "BEC": ["D"], - "BLF": ["D", "H"], - "BWR": ["D", "H"], - "BBB": ["D", "H"], - "CST": ["D", "H"], - "CHP": ["D"], - "DGE": ["D"], - "DGH": ["D"], - "ECM": ["D", "P"], - "ECT": ["D", "P"], - "EHM": ["D", "H"], - "EPY": ["D"], - "ERD": ["D", "H"], - "EPK": ["D"], - "FBY": ["D"], - "GRD": ["D", "H", "P"], - "GUN": ["D"], - "HMD": ["D", "P"], - "HST": ["D", "H"], - "HCH": ["D"], - "OLY": ["D"], - "KEW": ["D"], - "MAN": ["D", "H"], - "MON": ["D", "H"], - "PGR": ["D"], - "PLW": ["D", "H"], - "PUT": ["D"], - "RCP": ["D"], - "RMD": ["D"], - "SSQ": ["D", "H"], - "SKN": ["D", "H", "P"], - "SFS": ["D"], - "SJP": ["D", "H"], - "STB": ["D"], - "STG": ["D", "H"], - "TEM": ["D", "H"], - "THL": ["D", "H"], - "TGR": ["D", "P"], - "UPM": ["D"], - "UPB": ["D"], - "UPY": ["D"], - "UPK": ["D", "H"], - "VIC": ["D", "H", "V"], - "WBT": ["D"], - "WHM": ["D", "H", "J"], - "WKN": ["D"], - "WMS": ["D", "H", "J"], - "WCL": ["D", "H"], - "WDN": ["D"], - "WMP": ["D"], - "ALD": ["H", "M"], - "BAR": ["H", "M"], - "ESQ": ["H", "M"], - "FAR": ["H", "M"], - "GPS": ["H", "M"], - "HMS": ["H"], - "KXX": ["H", "M", "N", "P", "V"], - "MGT": ["H", "M", "N"], - "BER": ["J"], - "CWR": ["J"], - "CWF": ["J"], - "CNT": ["J"], - "CPK": ["J"], - "DHL": ["J"], - "FRD": ["J", "M"], - "GPK": ["J", "P", "V"], - "KIL": ["J"], - "KBY": ["J"], - "LON": ["J", "N"], - "NEA": ["J"], - "NGW": ["J"], - "QBY": ["J"], - "SWK": ["J"], - "SJW": ["J"], - "STA": ["J"], - "SWC": ["J"], - "WPK": ["J", "M"], - "WHD": ["J"], - "WLG": ["J"], - "AME": ["M"], - "CLF": ["M"], - "CWD": ["M"], - "CLW": ["M", "N"], - "CRX": ["M"], - "ETE": ["M", "P"], - "HOH": ["M"], - "HDN": ["M", "P"], - "ICK": ["M", "P"], - "MPK": ["M"], - "NHR": ["M"], - "NWP": ["M"], - "NWD": ["M"], - "NWH": ["M"], - "PIN": ["M"], - "RLN": ["M", "P"], - "RKY": ["M"], - "RUI": ["M", "P"], - "RUM": ["M", "P"], - "UXB": ["M", "P"], - "WAT": ["M"], - "WHR": ["M"], - "ANG": ["N"], - "ARC": ["N"], - "BAL": ["N"], - "BPK": ["N"], - "BOR": ["N"], - "BTX": ["N"], - "BUR": ["N"], - "CTN": ["N"], - "CHF": ["N"], - "CPC": ["N"], - "CPN": ["N"], - "CPS": ["N"], - "COL": ["N"], - "EFY": ["N"], - "EDG": ["N"], - "EUS": ["N", "V"], - "FYC": ["N"], - "GGR": ["N"], - "GST": ["N"], - "HMP": ["N"], - "HND": ["N"], - "HBT": ["N"], - "HIG": ["N"], - "KEN": ["N"], - "KTN": ["N"], - "LSQ": ["N", "P"], - "MHE": ["N"], - "MOR": ["N"], - "MCR": ["N"], - "OLD": ["N"], - "OVL": ["N"], - "SWM": ["N"], - "STK": ["N", "V"], - "TBE": ["N"], - "TBY": ["N"], - "TOT": ["N"], - "TPK": ["N"], - "WST": ["N", "V"], - "WFY": ["N"], - "WSP": ["N"], - "ALP": ["P"], - "AGR": ["P"], - "ARL": ["P"], - "BOS": ["P"], - "BGR": ["P"], - "CRD": ["P"], - "CFS": ["P"], - "COV": ["P"], - "FPK": ["P", "V"], - "HTX": ["P"], - "HTF": ["P"], - "HRV": ["P"], - "HRC": ["P"], - "HRD": ["P"], - "HNC": ["P"], - "HNE": ["P"], - "HNW": ["P"], - "HPC": ["P"], - "KNB": ["P"], - "MNR": ["P"], - "NEL": ["P"], - "NFD": ["P"], - "OAK": ["P"], - "OST": ["P"], - "PRY": ["P"], - "RSQ": ["P"], - "SEL": ["P"], - "SHR": ["P"], - "SGT": ["P"], - "SHL": ["P"], - "STN": ["P"], - "TPL": ["P"], - "WGN": ["P"], - "BHR": ["V"], - "BRX": ["V"], - "HBY": ["V"], - "PIM": ["V"], - "SVS": ["V"], - "TTH": ["V"], - "VUX": ["V"], - "WAL": ["V"] -}; diff --git a/app/model/platform.js b/app/model/platform.js deleted file mode 100644 index 8e77bb2..0000000 --- a/app/model/platform.js +++ /dev/null @@ -1,30 +0,0 @@ -var Train = require("./train"); - -function Platform(data) { - this._raw = data; -}; - -Platform.prototype.name = function() { - return this._raw.getAttribute('N'); -}; - -Platform.prototype.number = function() { - return this._raw.getAttribute('Num'); -}; - -Platform.prototype.trains = function() { - var trains = []; - var nodes = this._raw.getElementsByTagName('T'); - - if (nodes.length > 5) { - nodes = Array.prototype.slice.call(nodes, 0, 5); - } - - Array.prototype.forEach.call(nodes, function(node) { - trains.push(new Train(node)); - }); - - return trains; -}; - -module.exports = Platform; diff --git a/app/model/prediction.js b/app/model/prediction.js deleted file mode 100644 index 79ee597..0000000 --- a/app/model/prediction.js +++ /dev/null @@ -1,17 +0,0 @@ -var Station = require("./station"); - -function Prediction(xmlDoc) { - this._raw = xmlDoc; -}; - -Prediction.prototype.line = function() { - var nodes = this._raw.getElementsByTagName('LineName'); - return nodes[0].textContent; -}; - -Prediction.prototype.station = function() { - var nodes = this._raw.getElementsByTagName('S'); - return new Station(nodes[0]); -}; - -module.exports = Prediction; diff --git a/app/model/station.js b/app/model/station.js deleted file mode 100644 index 070e57b..0000000 --- a/app/model/station.js +++ /dev/null @@ -1,22 +0,0 @@ -var Platform = require("./platform"); - -function Station(data) { - this._raw = data; -} - -Station.prototype.name = function() { - return this._raw.getAttribute('N'); -}; - -Station.prototype.platforms = function() { - var platforms = []; - var nodes = this._raw.getElementsByTagName('P'); - - Array.prototype.forEach.call(nodes, function(node) { - platforms.push(new Platform(node)); - }); - - return platforms; -}; - -module.exports = Station; diff --git a/app/model/train.js b/app/model/train.js deleted file mode 100644 index 953f93b..0000000 --- a/app/model/train.js +++ /dev/null @@ -1,25 +0,0 @@ -function Train(data) { - this._raw = data; -}; - -Train.prototype.id = function() { - return this._raw.getAttribute('LCID'); -}; - -Train.prototype.timeTo = function() { - return this._raw.getAttribute('TimeTo'); -}; - -Train.prototype.line = function() { - return this._raw.getAttribute('LN'); -}; - -Train.prototype.location = function() { - return this._raw.getAttribute('Location'); -}; - -Train.prototype.destination = function() { - return this._raw.getAttribute('Destination'); -}; - -module.exports = Train; diff --git a/app/server/api.js b/app/server/api.js new file mode 100644 index 0000000..5ad3bac --- /dev/null +++ b/app/server/api.js @@ -0,0 +1,105 @@ +var http = require("http"); +var utils = require("../common/utils"); +var networkData = require("../common/data"); + +function APIRequest(config) { + this.config = config; +} + +APIRequest.prototype.for = function(line, station) { + this.line = line; + this.station = station; + return this; +}; + +APIRequest.prototype.get = function(callback) { + if (!utils.isStationOnLine(this.line, this.station, networkData)) { + return callback(null, ""); + } + + var formatCallback = this.format.bind(this); + var path = "/Line/" + this.line + "/Arrivals/" + this.station; + var queryString = "?app_id=" + this.config.APP_ID + "&app_key=" + this.config.APP_KEY; + + var options = { + path: path + queryString, + hostname: "api.beta.tfl.gov.uk" + }; + + var request = http.request(options, function(response) { + var str = ""; + + response.setEncoding("utf8"); + + response.on("data", function(chunk) { + str+= chunk; + }); + + response.on("end", function() { + var responseJSON = formatCallback(str); + + if (responseJSON instanceof Error) { + callback(responseJSON, null); + } + else { + callback(null, responseJSON); + } + }); + }); + + request.on("error", function(err) { + callback(err); + }); + + request.end(); +}; + +APIRequest.prototype.format = function(responseText, callback) { + var parsedResponse = parseResponse(responseText); + + if (parsedResponse instanceof Error) { + return parsedResponse; + } + + return { + request: { + lineCode: this.line, + stationCode: this.station + }, + station: { + lineName: networkData.lines[this.line], + stationName: networkData.stations[this.station] + }, + platforms: formatData(parsedResponse) + }; +}; + +function parseResponse(responseText) { + var jsonData; + + try { + jsonData = JSON.parse(responseText); + } + catch(e) { + return new Error("Data could not be parsed"); + } + + return jsonData; +}; + +function formatData(responseData) { + var formattedData = {}; + + var sortedData = responseData.sort(function(a, b) { + return a.timeToStation - b.timeToStation; + }); + + sortedData.forEach(function(record) { + formattedData[record.platformName] = formattedData[record.platformName] || []; + formattedData[record.platformName].push(record); + }); + + return formattedData; +}; + +module.exports = APIRequest; diff --git a/app/server/bootstrap.jsx b/app/server/bootstrap.jsx new file mode 100644 index 0000000..272161e --- /dev/null +++ b/app/server/bootstrap.jsx @@ -0,0 +1,16 @@ +/** @jsx React.DOM */ +var React = require("react"); +var networkData = require("../common/data"); +var Template = require("../server/template"); +var TubeTracker = require("../component/tube-tracker.jsx"); + +function Bootstrap(data) { + this.data = data; +} + +Bootstrap.prototype.load = function(callback) { + var staticHTML = React.renderComponentToString(); + new Template("../view/index.html").render({ app: staticHTML, data: JSON.stringify(this.data) }, callback); +}; + +module.exports = Bootstrap; diff --git a/app/server/template.js b/app/server/template.js new file mode 100644 index 0000000..8c05478 --- /dev/null +++ b/app/server/template.js @@ -0,0 +1,24 @@ +var fs = require("fs"); +var path = require("path"); + +function Template(target) { + this.target = target; +} + +Template.prototype.render = function(data, callback) { + var fullPath = path.resolve(__dirname, this.target); + + fs.readFile(fullPath, { encoding: "utf8" }, function(err, template) { + if (err) { + return callback(err); + } + + var rendered = template.replace(/\{\{yield:([a-z0-9_]+)\}\}/g, function(match, property) { + return data[property]; + }); + + callback(null, rendered); + }); +}; + +module.exports = Template; diff --git a/public/index.html b/app/view/index.html similarity index 62% rename from public/index.html rename to app/view/index.html index 7abfb82..c394709 100644 --- a/public/index.html +++ b/app/view/index.html @@ -4,7 +4,7 @@ - + TfL London Underground @@ -13,6 +13,9 @@ + {{yield:app}} + + diff --git a/config.example.json b/config.example.json new file mode 100644 index 0000000..58115ee --- /dev/null +++ b/config.example.json @@ -0,0 +1,4 @@ +{ + "APP_ID": "", + "APP_KEY": "" +} diff --git a/package.json b/package.json index 0f7ff49..813e863 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tube-tracker", - "version": "0.2.0", + "version": "0.4.0", "devDependencies": { "browserify": "3.x", "reactify": "0.11.x", @@ -9,14 +9,15 @@ }, "dependencies": { "express": "4.x", - "react": "~0.10.0" + "react": "~0.10.0", + "node-jsx": "~0.10.0" }, "engines": { "node": ">=0.10.0" }, "scripts": { - "build-dev": "browserify -e app/bootstrap.js -t reactify -o public/scripts/bundle.dev.js -d", - "build-min": "browserify -e app/bootstrap.js -t reactify -t uglifyify -o public/scripts/bundle.min.js", + "build-dev": "browserify -e app/browser/bootstrap.jsx -t reactify -o public/scripts/bundle.dev.js -d", + "build-min": "browserify -e app/browser/bootstrap.jsx -t reactify -t uglifyify -o public/scripts/bundle.min.js", "build-tdd": "browserify -e test/spec/suite.js -t reactify -t rewireify -o test/spec/bundle.js" } } diff --git a/public/scripts/bundle.dev.js b/public/scripts/bundle.dev.js index d169633..5cedcb4 100644 --- a/public/scripts/bundle.dev.js +++ b/public/scripts/bundle.dev.js @@ -1,11 +1,12 @@ (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0 ? seconds : "0"); +}; + +exports.getQueryString = function() { + return window.location.search; +}; + +exports.formatQueryString = function(properties) { + var property; + var queryString = []; + + for (property in properties) { + if (properties.hasOwnProperty(property)) { + queryString.push("" + property + "=" + properties[property]); + } + } + + return "?" + queryString.join("&"); +}; + +exports.queryStringProperty = function(queryString, prop) { + var pairs = queryString.replace(/^\?/, "").replace(/\/$/, "").split("&"); + var properties = {}; + + pairs.forEach(function(pair) { + pair = pair.split("="); + properties[ pair[0] ] = pair[1]; + }); + + return properties[prop]; +}; + +exports.isLine = function(line, data) { + return line in data.lines; +}; + +exports.isStation = function(station, data) { + return station in data.stations; +}; + +exports.isStationOnLine = function(line, station, data) { + return this.isLine(line, data) && this.isStation(station, data) && + data.stationsOnLines[line].indexOf(station) >= 0; +}; + +},{}],4:[function(require,module,exports){ +(function (global){ /** @jsx React.DOM */ -var React = require("../../vendor/react/react"); -var utils = require("../utils"); +var React = require("react"); +var utils = require("../common/utils"); var Network = React.createClass({displayName: 'Network', getInitialState: function() { return { - collapsible: window.innerWidth <= 800, + collapsible: global ? false : window.innerWidth <= 800, open: false }; }, @@ -43,7 +851,7 @@ var Network = React.createClass({displayName: 'Network', this.setState({ collapsible: window.innerWidth <= 800 }); }, - componentWillMount: function() { + componentDidMount: function() { // Simple event debouncing to avoid multiple recalculations this.debounce = utils.debounceEvent(this.handleResize, 250); window.addEventListener("resize", this.debounce, false); @@ -102,7 +910,7 @@ var Line = React.createClass({displayName: 'Line', return ( React.DOM.form( {ref:"form", onSubmit:this.handleSubmit}, - React.DOM.fieldset( {className:"network__line network__line--" + lineCode.toLowerCase()}, + React.DOM.fieldset( {className:"network__line network__line--" + lineCode}, React.DOM.legend(null, networkData.lines[lineCode]), React.DOM.input( {type:"hidden", name:"line", value:lineCode} ), React.DOM.select( {name:"station", ref:"station"}, generatedOptions), @@ -116,30 +924,24 @@ var Line = React.createClass({displayName: 'Line', module.exports = Network; -},{"../../vendor/react/react":11,"../utils":10}],3:[function(require,module,exports){ +}).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"../common/utils":3,"react":142}],5:[function(require,module,exports){ /** @jsx React.DOM */ -var React = require("../../vendor/react/react"); -var Prediction = require("../model/prediction"); -var utils = require("../utils"); +var React = require("react"); +var utils = require("../common/utils"); var Predictions = React.createClass({displayName: 'Predictions', getInitialState: function() { - return { status: this.props.line && this.props.station ? "loading" : "welcome" }; + return { + status: this.props.initialData ? "success" : "welcome", + predictionData: this.props.initialData + }; }, fetchPredictions: function(line, station) { - // The circle line isn't defined in the API but shares platforms with other lines - if (line === "O") { - line = utils.mapCircleLineStation(station, this.props.networkData); - } - - var api = "http://cloud.tfl.gov.uk/TrackerNet/PredictionDetailed/" + line + "/" + station; - this.setState({ status: "loading" }); - - // The TrackerNet API does not support cross-origin requests so we must use a proxy - utils.httpRequest(utils.proxyRequestURL(api), this.predictionsSuccess, this.predictionsError); + utils.httpRequest(utils.apiRequestURL(line, station), this.predictionsSuccess, this.predictionsError); }, predictionsError: function(error) { @@ -152,19 +954,14 @@ var Predictions = React.createClass({displayName: 'Predictions', // Airbrake.push({ error: error }); }, - predictionsSuccess: function(responseDoc) { - // Because we're using a proxy it will return a 200 and XML even if the - // TrackerNet API is unavailble or request was invalid. - if (!utils.validateResponse(responseDoc)) { - return this.predictionError(new Error("Invalid API response")); + predictionsSuccess: function(responseData) { + if (!responseData.length) { + return this.predictionsError(new Error("Invalid API response")); } this.setState({ status: "success", - - // Dealing with XML in the browser is so ugly that I've - // used 'models' to abstract it away. - predictionData: new Prediction(responseDoc) + predictionData: JSON.parse(responseData) }); }, @@ -200,10 +997,10 @@ var Predictions = React.createClass({displayName: 'Predictions', render: function() { if (this.state.status === "success") { - return DepartureBoard( {predictionData:this.state.predictionData} ); + return DepartureBoard( {ref:"content", predictionData:this.state.predictionData} ); } - return Notice( {type:this.state.status} ); + return Notice( {ref:"content", type:this.state.status} ); } }); @@ -211,22 +1008,21 @@ var Predictions = React.createClass({displayName: 'Predictions', var DepartureBoard = React.createClass({displayName: 'DepartureBoard', render: function() { - var predictionData = this.props.predictionData; - var station = predictionData.station(); + var station = this.props.predictionData.station; + var platforms = this.props.predictionData.platforms; - var generatedPlatforms = station.platforms().map(function(platform) { + var generatedPlatforms = Object.keys(platforms).map(function(platform, i) { return ( - React.DOM.div( {className:"platform", key:"platform-" + platform.number()}, - React.DOM.h2( {className:"platform__heading"}, platform.name()), - Trains( {trains:platform.trains()} ) + React.DOM.div( {className:"platform", key:"platform-" + i}, + React.DOM.h2( {className:"platform__heading"}, platform), + Trains( {trains:platforms[platform]} ) ) ); }); - // Heading does not account for circle line mapping, meh return ( React.DOM.div( {className:"departures"}, - React.DOM.h1( {className:"departures__heading"}, station.name() + " " + predictionData.line()), + React.DOM.h1( {className:"departures__heading"}, station.stationName + " Station, " + station.lineName + " Line"), generatedPlatforms ) ); @@ -238,11 +1034,13 @@ var Trains = React.createClass({displayName: 'Trains', render: function() { var generatedTrains = this.props.trains.map(function(train) { + var timeTo = utils.formattedTimeUntil(train.timeToStation); + return ( - React.DOM.tr( {key:"train-" + train.id()}, - React.DOM.td(null, train.timeTo()), - React.DOM.td(null, train.destination()), - React.DOM.td(null, train.location()) + React.DOM.tr( {className:"trains__arrival", key:"train-" + train.vehicleId}, + React.DOM.td(null, timeTo === "0:00" ? "-" : timeTo), + React.DOM.td(null, train.towards), + React.DOM.td(null, train.currentLocation) ) ); }); @@ -272,7 +1070,7 @@ var Notice = React.createClass({displayName: 'Notice', switch (status) { case "error": - text = "Sorry an error occured, please try again."; + text = "Sorry an error occurred, please try again."; break; case "loading": text = "Loading predictions…" @@ -297,27 +1095,22 @@ var Notice = React.createClass({displayName: 'Notice', module.exports = Predictions; -},{"../../vendor/react/react":11,"../model/prediction":7,"../utils":10}],4:[function(require,module,exports){ +},{"../common/utils":3,"react":142}],6:[function(require,module,exports){ /** @jsx React.DOM */ -var React = require("../../vendor/react/react"); -var Predictions = require("./predictions"); -var Network = require("./network"); -var utils = require("../utils"); +var React = require("react"); +var utils = require("../common/utils"); +var Network = require("./network.jsx"); +var Predictions = require("./predictions.jsx"); var TubeTracker = React.createClass({displayName: 'TubeTracker', - validateUserInput: function(line, station) { - return /^[A-Z]$/.test(line) && /^[A-Z]{3}$/.test(station) && - utils.isStationOnLine(line, station, this.props.networkData); - }, - formatAndValidateUserInput: function(userLine, userStation) { var line = null; var station = null; // We could have added extra states for invalid data // but it's easier simply to ignore it. - if (this.validateUserInput(userLine, userStation)) { + if (utils.isStationOnLine(userLine, userStation, this.props.networkData)) { line = userLine; station = userStation; } @@ -329,14 +1122,20 @@ var TubeTracker = React.createClass({displayName: 'TubeTracker', }, getInitialState: function() { + var initialData = this.props.initialData; + return this.formatAndValidateUserInput( - utils.queryStringProperty(utils.getQueryString(), "line"), - utils.queryStringProperty(utils.getQueryString(), "station") + initialData ? initialData.request.lineCode : null, + initialData ? initialData.request.stationCode : null ); }, handleUpdate: function(e) { - this.setState(this.formatAndValidateUserInput(e.detail.line, e.detail.station)); + var input = this.formatAndValidateUserInput(e.detail.line, e.detail.station); + + if (input.line && input.station) { + this.setState(input); + } }, componentWillUpdate: function(newProps, newState) { @@ -345,7 +1144,7 @@ var TubeTracker = React.createClass({displayName: 'TubeTracker', window.history.pushState(null, null, utils.formatQueryString(newState)); }, - componentWillMount: function() { + componentDidMount: function() { window.addEventListener("tt:update", this.handleUpdate, false); }, @@ -360,7 +1159,7 @@ var TubeTracker = React.createClass({displayName: 'TubeTracker', Network( {networkData:this.props.networkData} ) ), React.DOM.div( {className:"layout__content"}, - Predictions( {line:this.state.line, station:this.state.station, networkData:this.props.networkData} ) + Predictions( {line:this.state.line, station:this.state.station, networkData:this.props.networkData, initialData:this.props.initialData} ) ) ) ); @@ -370,798 +1169,69 @@ var TubeTracker = React.createClass({displayName: 'TubeTracker', module.exports = TubeTracker; -},{"../../vendor/react/react":11,"../utils":10,"./network":2,"./predictions":3}],5:[function(require,module,exports){ -exports.lines = { - "B": "Bakerloo", - "C": "Central", - "O": "Circle", - "D": "District", - "H": "Hammersmith & City", - "J": "Jubilee", - "M": "Metropolitan", - "N": "Northern", - "P": "Piccadilly", - "V": "Victoria", - "W": "Waterloo & City" -}; +},{"../common/utils":3,"./network.jsx":4,"./predictions.jsx":5,"react":142}],7:[function(require,module,exports){ +// shim for using process in browser -/* -Stations missing from TfL's TrackerNet: -- Bayswater -- Chesham -- Goldhawk Road -- Ladbroke Grove -- Latimer Road -- Paddington Circle/District Line -- Preston Road -- Royal Oak -- Shepherd's Bush Market -- Westbourne Park -- Wood Lane -*/ -exports.stations = { - "BST": "Baker Street", - "CHX": "Charing Cross", - "ERB": "Edgware Road (Bakerloo)", - "ELE": "Elephant and Castle", - "EMB": "Embankment", - "HSD": "Harlesden", - "HAW": "Harrow and Wealdstone", - "KGN": "Kensal Green", - "KNT": "Kenton", - "KPK": "Kilburn Park", - "LAM": "Lambeth North", - "MDV": "Maida Vale", - "MYB": "Marylebone", - "NWM": "North Wembley", - "OXC": "Oxford Circus", - "PAD": "Paddington", - "PIC": "Piccadilly Circus", - "QPK": "Queen's Park", - "RPK": "Regent's Park", - "SKT": "South Kenton", - "SPK": "Stonebridge Park", - "WAR": "Warwick Avenue", - "WLO": "Waterloo", - "WEM": "Wembley Central", - "WJN": "Willesden Junction", - "BNK": "Bank", - "BDE": "Barkingside", - "BNG": "Bethnal Green", - "BDS": "Bond Street", - "BHL": "Buckhurst Hill", - "CYL": "Chancery Lane", - "CHG": "Chigwell", - "DEB": "Debden", - "EBY": "Ealing Broadway", - "EAC": "East Acton", - "EPP": "Epping", - "FLP": "Fairlop", - "GHL": "Gants Hill", - "GRH": "Grange Hill", - "GFD": "Greenford", - "HAI": "Hainault", - "HLN": "Hanger Lane", - "HOL": "Holborn", - "HPK": "Holland Park", - "LAN": "Lancaster Gate", - "LEY": "Leyton", - "LYS": "Leytonstone", - "LST": "Liverpool Street", - "LTN": "Loughton", - "MAR": "Marble Arch", - "MLE": "Mile End", - "NEP": "Newbury Park", - "NAC": "North Acton", - "NHT": "Northolt", - "NHG": "Notting Hill Gate", - "PER": "Perivale", - "QWY": "Queensway", - "RED": "Redbridge", - "ROD": "Roding Valley", - "RUG": "Ruislip Gardens", - "SBC": "Shepherd's Bush", - "SNB": "Snaresbrook", - "SRP": "South Ruislip", - "SWF": "South Woodford", - "STP": "St Paul's", - "SFD": "Stratford", - "THB": "Theydon Bois", - "TCR": "Tottenham Court Road", - "WAN": "Wanstead", - "WAC": "West Acton", - "WRP": "West Ruislip", - "WCT": "White City", - "WFD": "Woodford", - "ACT": "Acton Town", - "ALE": "Aldgate East", - "BKG": "Barking", - "BCT": "Barons Court", - "BEC": "Becontree", - "BLF": "Blackfriars", - "BWR": "Bow Road", - "BBB": "Bromley-by-Bow", - "CST": "Cannon Street", - "CHP": "Chiswick Park", - "DGE": "Dagenham East", - "DGH": "Dagenham Heathway", - "ECM": "Ealing Common", - "ECT": "Earl's Court", - "EHM": "East Ham", - "EPY": "East Putney", - "ERD": "Edgware Road (H & C)", - "EPK": "Elm Park", - "FBY": "Fulham Broadway", - "GRD": "Gloucester Road", - "GUN": "Gunnersbury", - "HMD": "Hammersmith (District and Picc)", - "HST": "High Street Kensington", - "HCH": "Hornchurch", - "OLY": "Kensington (Olympia)", - "KEW": "Kew Gardens", - "MAN": "Mansion House", - "MON": "Monument", - "PGR": "Parsons Green", - "PLW": "Plaistow", - "PUT": "Putney Bridge", - "RCP": "Ravenscourt Park", - "RMD": "Richmond", - "SSQ": "Sloane Square", - "SKN": "South Kensington", - "SFS": "Southfields", - "SJP": "St. James's Park", - "STB": "Stamford Brook", - "STG": "Stepney Green", - "TEM": "Temple", - "THL": "Tower Hill", - "TGR": "Turnham Green", - "UPM": "Upminster", - "UPB": "Upminster Bridge", - "UPY": "Upney", - "UPK": "Upton Park", - "VIC": "Victoria", - "WBT": "West Brompton", - "WHM": "West Ham", - "WKN": "West Kensington", - "WMS": "Westminster", - "WCL": "Whitechapel", - "WDN": "Wimbledon", - "WMP": "Wimbledon Park", - "ALD": "Aldgate", - "BAR": "Barbican", - "ESQ": "Euston Square", - "FAR": "Farringdon", - "GPS": "Great Portland Street", - "HMS": "Hammersmith", - "KXX": "King's Cross St Pancras", - "MGT": "Moorgate", - "BER": "Bermondsey", - "CWR": "Canada Water", - "CWF": "Canary Wharf", - "CNT": "Canning Town", - "CPK": "Canons Park", - "DHL": "Dollis Hill", - "FRD": "Finchley Road", - "GPK": "Green Park", - "KIL": "Kilburn", - "KBY": "Kingsbury", - "LON": "London Bridge", - "NEA": "Neasden", - "NGW": "North Greenwich", - "QBY": "Queensbury", - "SWK": "Southwark", - "SJW": "St John's Wood", - "STA": "Stanmore", - "SWC": "Swiss Cottage", - "WPK": "Wembley Park", - "WHD": "West Hampstead", - "WLG": "Willesden Green", - "AME": "Amersham", - "CLF": "Chalfont and Latimer", - "CWD": "Chorleywood", - "CLW": "Colliers Wood", - "CRX": "Croxley", - "ETE": "Eastcote", - "HOH": "Harrow on the Hill", - "HDN": "Hillingdon", - "ICK": "Ickenham", - "MPK": "Moor Park", - "NHR": "North Harrow", - "NWP": "Northwick Park", - "NWD": "Northwood", - "NWH": "Northwood Hills", - "PIN": "Pinner", - "RLN": "Rayners Lane", - "RKY": "Rickmansworth", - "RUI": "Ruislip", - "RUM": "Ruislip Manor", - "UXB": "Uxbridge", - "WAT": "Watford", - "WHR": "West Harrow", - "ANG": "Angel", - "ARC": "Archway", - "BAL": "Balham", - "BPK": "Belsize Park", - "BOR": "Borough", - "BTX": "Brent Cross", - "BUR": "Burnt Oak", - "CTN": "Camden Town", - "CHF": "Chalk Farm", - "CPC": "Clapham Common", - "CPN": "Clapham North", - "CPS": "Clapham South", - "COL": "Colindale", - "EFY": "East Finchley", - "EDG": "Edgware", - "EUS": "Euston", - "FYC": "Finchley Central", - "GGR": "Golders Green", - "GST": "Goodge Street", - "HMP": "Hampstead", - "HND": "Hendon Central", - "HBT": "High Barnet", - "HIG": "Highgate", - "KEN": "Kennington", - "KTN": "Kentish Town", - "LSQ": "Leicester Square", - "MHE": "Mill Hill East", - "MOR": "Morden", - "MCR": "Mornington Crescent", - "OLD": "Old Street", - "OVL": "Oval", - "SWM": "South Wimbledon", - "STK": "Stockwell", - "TBE": "Tooting Bec", - "TBY": "Tooting Broadway", - "TOT": "Totteridge and Whetstone", - "TPK": "Tufnell Park", - "WST": "Warren Street", - "WFY": "West Finchley", - "WSP": "Woodside Park", - "ALP": "Alperton", - "AGR": "Arnos Grove", - "ARL": "Arsenal", - "BOS": "Boston Manor", - "BGR": "Bounds Green", - "CRD": "Caledonian Road", - "CFS": "Cockfosters", - "COV": "Covent Garden", - "FPK": "Finsbury Park", - "HTX": "Hatton Cross", - "HTF": "Heathrow Terminal 4", - "HRV": "Heathrow Terminal 5", - "HRC": "Heathrow Terminals 123", - "HRD": "Holloway Road", - "HNC": "Hounslow Central", - "HNE": "Hounslow East", - "HNW": "Hounslow West", - "HPC": "Hyde Park Corner", - "KNB": "Knightsbridge", - "MNR": "Manor House", - "NEL": "North Ealing", - "NFD": "Northfields", - "OAK": "Oakwood", - "OST": "Osterley", - "PRY": "Park Royal", - "RSQ": "Russell Square", - "SEL": "South Ealing", - "SHR": "South Harrow", - "SGT": "Southgate", - "SHL": "Sudbury Hill", - "STN": "Sudbury Town", - "TPL": "Turnpike Lane", - "WGN": "Wood Green", - "BHR": "Blackhorse Road", - "BRX": "Brixton", - "HBY": "Highbury and Islington", - "PIM": "Pimlico", - "SVS": "Seven Sisters", - "TTH": "Tottenham Hale", - "VUX": "Vauxhall", - "WAL": "Walthamstow Central" -}; - -exports.stationsOnLines = { - "B": ["BST", "CHX", "ERB", "ELE", "EMB", "HSD", "HAW", "KGN", "KNT", "KPK", "LAM", "MDV", "MYB", "NWM", "OXC", "PAD", "PIC", "QPK", "RPK", "SKT", "SPK", "WAR", "WLO", "WEM", "WJN"], - "C": ["BNK", "BDE", "BNG", "BDS", "BHL", "CYL", "CHG", "DEB", "EBY", "EAC", "EPP", "FLP", "GHL", "GRH", "GFD", "HAI", "HLN", "HOL", "HPK", "LAN", "LEY", "LYS", "LST", "LTN", "MAR", "MLE", "NEP", "NAC", "NHT", "NHG", "OXC", "PER", "QWY", "RED", "ROD", "RUG", "SBC", "SNB", "SRP", "SWF", "STP", "SFD", "THB", "TCR", "WAN", "WAC", "WRP", "WCT", "WFD"], - "O": ["ALD", "BAR", "BLF", "BST", "CST", "EMB", "ERD", "ESQ", "FAR", "GPS", "GRD", "HMS", "HST", "KXX", "LST", "MAN", "MGT", "MON", "NHG", "SJP", "SKN", "SSQ", "TEM", "THL", "VIC", "WMS"], - "D": ["ACT", "ALE", "BKG", "BCT", "BEC", "BLF", "BWR", "BBB", "CST", "CHP", "DGE", "DGH", "EBY", "ECM", "ECT", "EHM", "EPY", "ERD", "EPK", "EMB", "FBY", "GRD", "GUN", "HMD", "HST", "HCH", "OLY", "KEW", "MAN", "MLE", "MON", "OLY", "PGR", "PLW", "PUT", "RCP", "RMD", "SSQ", "SKN", "SFS", "SJP", "STB", "STG", "TEM", "THL", "TGR", "UPM", "UPB", "UPY", "UPK", "VIC", "WBT", "WHM", "WKN", "WMS", "WCL", "WDN", "WMP"], - "H": ["ALD", "ALE", "BST", "BAR", "BKG", "BLF", "BWR", "BBB", "CST", "EHM", "ERD", "EMB", "ESQ", "FAR", "GRD", "GPS", "HMS", "HST", "KXX", "LST", "MAN", "MLE", "MON", "MGT", "PAD", "PLW", "SSQ", "SKN", "SJP", "STG", "TEM", "THL", "UPK", "VIC", "WHM", "WMS", "WCL"], - "J": ["BST", "BER", "BDS", "CWR", "CWF", "CNT", "CPK", "DHL", "FRD", "GPK", "KIL", "KBY", "LON", "NEA", "NGW", "QBY", "SWK", "SJW", "STA", "SFD", "SWC", "WLO", "WPK", "WHM", "WHD", "WMS", "WLG"], - "M": ["ALD", "AME", "BST", "BAR", "CLF", "CWD", "CLW", "CRX", "ETE", "ESQ", "FAR", "FRD", "GPS", "HOH", "HDN", "ICK", "KXX", "LST", "MPK", "MGT", "NHR", "NWP", "NWD", "NWH", "PIN", "RLN", "RKY", "RUI", "RUM", "UXB", "WAT", "WPK", "WHR"], - "N": ["ANG", "ARC", "BAL", "BNK", "BPK", "BOR", "BTX", "BUR", "CTN", "CHF", "CHX", "CPC", "CPN", "CPS", "COL", "CLW", "EFY", "EDG", "ELE", "EMB", "EUS", "FYC", "GGR", "GST", "HMP", "HND", "HBT", "HIG", "KEN", "KTN", "KXX", "LSQ", "LON", "MHE", "MGT", "MOR", "MCR", "OLD", "OVL", "SWM", "STK", "TBE", "TBY", "TCR", "TOT", "TPK", "WST", "WLO", "WFY", "WSP"], - "P": ["ACT", "ALP", "AGR", "ARL", "BCT", "BOS", "BGR", "CRD", "CFS", "COV", "ECM", "ECT", "ETE", "FPK", "GRD", "GPK", "HMD", "HTX", "HTF", "HRV", "HRC", "HDN", "HOL", "HRD", "HNC", "HNE", "HNW", "HPC", "ICK", "KXX", "KNB", "LSQ", "MNR", "NEL", "NFD", "OAK", "OST", "PRY", "PIC", "RLN", "RUI", "RUM", "RSQ", "SEL", "SHR", "SKN", "SGT", "SHL", "STN", "TGR", "TPL", "UXB", "WGN"], - "V": ["BHR", "BRX", "EUS", "FPK", "GPK", "HBY", "KXX", "OXC", "PIM", "SVS", "STK", "TTH", "VUX", "VIC", "WAL", "WST"], - "W": ["BNK", "WLO"] -}; - -exports.circleLineMap = { - "ALD": "M", - "BAR": "H", - "BLF": "D", - "BST": "H", - "CST": "D", - "EMB": "D", - "ERD": "H", - "ESQ": "H", - "FAR": "H", - "GPS": "H", - "GRD": "D", - "HMS": "H", - "HST": "D", - "KXX": "H", - "LST": "H", - "MAN": "D", - "MGT": "H", - "MON": "D", - "NHG": "D", - "SJP": "D", - "SKN": "D", - "SSQ": "D", - "TEM": "D", - "THL": "D", - "VIC": "D", - "WMS": "D" -}; - -exports.linesAtStations = { - "BST": ["B", "H", "J", "M"], - "CHX": ["B", "N"], - "ERB": ["B"], - "ELE": ["B", "N"], - "EMB": ["B", "D", "H", "N"], - "HSD": ["B"], - "HAW": ["B"], - "KGN": ["B"], - "KNT": ["B"], - "KPK": ["B"], - "LAM": ["B"], - "MDV": ["B"], - "MYB": ["B"], - "NWM": ["B"], - "OXC": ["B", "C", "V"], - "PAD": ["B", "H"], - "PIC": ["B", "P"], - "QPK": ["B"], - "RPK": ["B"], - "SKT": ["B"], - "SPK": ["B"], - "WAR": ["B"], - "WLO": ["B", "J", "N", "W"], - "WEM": ["B"], - "WJN": ["B"], - "BNK": ["C", "N", "W"], - "BDE": ["C"], - "BNG": ["C"], - "BDS": ["C", "J"], - "BHL": ["C"], - "CYL": ["C"], - "CHG": ["C"], - "DEB": ["C"], - "EBY": ["C", "D"], - "EAC": ["C"], - "EPP": ["C"], - "FLP": ["C"], - "GHL": ["C"], - "GRH": ["C"], - "GFD": ["C"], - "HAI": ["C"], - "HLN": ["C"], - "HOL": ["C", "P"], - "HPK": ["C"], - "LAN": ["C"], - "LEY": ["C"], - "LYS": ["C"], - "LST": ["C", "H", "M"], - "LTN": ["C"], - "MAR": ["C"], - "MLE": ["C", "D", "H"], - "NEP": ["C"], - "NAC": ["C"], - "NHT": ["C"], - "NHG": ["C"], - "PER": ["C"], - "QWY": ["C"], - "RED": ["C"], - "ROD": ["C"], - "RUG": ["C"], - "SBC": ["C"], - "SNB": ["C"], - "SRP": ["C"], - "SWF": ["C"], - "STP": ["C"], - "SFD": ["C", "J"], - "THB": ["C"], - "TCR": ["C", "N"], - "WAN": ["C"], - "WAC": ["C"], - "WRP": ["C"], - "WCT": ["C"], - "WFD": ["C"], - "ACT": ["D", "P"], - "ALE": ["D", "H"], - "BKG": ["D", "H"], - "BCT": ["D", "P"], - "BEC": ["D"], - "BLF": ["D", "H"], - "BWR": ["D", "H"], - "BBB": ["D", "H"], - "CST": ["D", "H"], - "CHP": ["D"], - "DGE": ["D"], - "DGH": ["D"], - "ECM": ["D", "P"], - "ECT": ["D", "P"], - "EHM": ["D", "H"], - "EPY": ["D"], - "ERD": ["D", "H"], - "EPK": ["D"], - "FBY": ["D"], - "GRD": ["D", "H", "P"], - "GUN": ["D"], - "HMD": ["D", "P"], - "HST": ["D", "H"], - "HCH": ["D"], - "OLY": ["D"], - "KEW": ["D"], - "MAN": ["D", "H"], - "MON": ["D", "H"], - "PGR": ["D"], - "PLW": ["D", "H"], - "PUT": ["D"], - "RCP": ["D"], - "RMD": ["D"], - "SSQ": ["D", "H"], - "SKN": ["D", "H", "P"], - "SFS": ["D"], - "SJP": ["D", "H"], - "STB": ["D"], - "STG": ["D", "H"], - "TEM": ["D", "H"], - "THL": ["D", "H"], - "TGR": ["D", "P"], - "UPM": ["D"], - "UPB": ["D"], - "UPY": ["D"], - "UPK": ["D", "H"], - "VIC": ["D", "H", "V"], - "WBT": ["D"], - "WHM": ["D", "H", "J"], - "WKN": ["D"], - "WMS": ["D", "H", "J"], - "WCL": ["D", "H"], - "WDN": ["D"], - "WMP": ["D"], - "ALD": ["H", "M"], - "BAR": ["H", "M"], - "ESQ": ["H", "M"], - "FAR": ["H", "M"], - "GPS": ["H", "M"], - "HMS": ["H"], - "KXX": ["H", "M", "N", "P", "V"], - "MGT": ["H", "M", "N"], - "BER": ["J"], - "CWR": ["J"], - "CWF": ["J"], - "CNT": ["J"], - "CPK": ["J"], - "DHL": ["J"], - "FRD": ["J", "M"], - "GPK": ["J", "P", "V"], - "KIL": ["J"], - "KBY": ["J"], - "LON": ["J", "N"], - "NEA": ["J"], - "NGW": ["J"], - "QBY": ["J"], - "SWK": ["J"], - "SJW": ["J"], - "STA": ["J"], - "SWC": ["J"], - "WPK": ["J", "M"], - "WHD": ["J"], - "WLG": ["J"], - "AME": ["M"], - "CLF": ["M"], - "CWD": ["M"], - "CLW": ["M", "N"], - "CRX": ["M"], - "ETE": ["M", "P"], - "HOH": ["M"], - "HDN": ["M", "P"], - "ICK": ["M", "P"], - "MPK": ["M"], - "NHR": ["M"], - "NWP": ["M"], - "NWD": ["M"], - "NWH": ["M"], - "PIN": ["M"], - "RLN": ["M", "P"], - "RKY": ["M"], - "RUI": ["M", "P"], - "RUM": ["M", "P"], - "UXB": ["M", "P"], - "WAT": ["M"], - "WHR": ["M"], - "ANG": ["N"], - "ARC": ["N"], - "BAL": ["N"], - "BPK": ["N"], - "BOR": ["N"], - "BTX": ["N"], - "BUR": ["N"], - "CTN": ["N"], - "CHF": ["N"], - "CPC": ["N"], - "CPN": ["N"], - "CPS": ["N"], - "COL": ["N"], - "EFY": ["N"], - "EDG": ["N"], - "EUS": ["N", "V"], - "FYC": ["N"], - "GGR": ["N"], - "GST": ["N"], - "HMP": ["N"], - "HND": ["N"], - "HBT": ["N"], - "HIG": ["N"], - "KEN": ["N"], - "KTN": ["N"], - "LSQ": ["N", "P"], - "MHE": ["N"], - "MOR": ["N"], - "MCR": ["N"], - "OLD": ["N"], - "OVL": ["N"], - "SWM": ["N"], - "STK": ["N", "V"], - "TBE": ["N"], - "TBY": ["N"], - "TOT": ["N"], - "TPK": ["N"], - "WST": ["N", "V"], - "WFY": ["N"], - "WSP": ["N"], - "ALP": ["P"], - "AGR": ["P"], - "ARL": ["P"], - "BOS": ["P"], - "BGR": ["P"], - "CRD": ["P"], - "CFS": ["P"], - "COV": ["P"], - "FPK": ["P", "V"], - "HTX": ["P"], - "HTF": ["P"], - "HRV": ["P"], - "HRC": ["P"], - "HRD": ["P"], - "HNC": ["P"], - "HNE": ["P"], - "HNW": ["P"], - "HPC": ["P"], - "KNB": ["P"], - "MNR": ["P"], - "NEL": ["P"], - "NFD": ["P"], - "OAK": ["P"], - "OST": ["P"], - "PRY": ["P"], - "RSQ": ["P"], - "SEL": ["P"], - "SHR": ["P"], - "SGT": ["P"], - "SHL": ["P"], - "STN": ["P"], - "TPL": ["P"], - "WGN": ["P"], - "BHR": ["V"], - "BRX": ["V"], - "HBY": ["V"], - "PIM": ["V"], - "SVS": ["V"], - "TTH": ["V"], - "VUX": ["V"], - "WAL": ["V"] -}; - -},{}],6:[function(require,module,exports){ -var Train = require("./train"); - -function Platform(data) { - this._raw = data; -}; +var process = module.exports = {}; -Platform.prototype.name = function() { - return this._raw.getAttribute('N'); -}; - -Platform.prototype.number = function() { - return this._raw.getAttribute('Num'); -}; +process.nextTick = (function () { + var canSetImmediate = typeof window !== 'undefined' + && window.setImmediate; + var canPost = typeof window !== 'undefined' + && window.postMessage && window.addEventListener + ; -Platform.prototype.trains = function() { - var trains = []; - var nodes = this._raw.getElementsByTagName('T'); - - if (nodes.length > 5) { - nodes = Array.prototype.slice.call(nodes, 0, 5); - } - - Array.prototype.forEach.call(nodes, function(node) { - trains.push(new Train(node)); - }); - - return trains; -}; - -module.exports = Platform; - -},{"./train":9}],7:[function(require,module,exports){ -var Station = require("./station"); - -function Prediction(xmlDoc) { - this._raw = xmlDoc; -}; - -Prediction.prototype.line = function() { - var nodes = this._raw.getElementsByTagName('LineName'); - return nodes[0].textContent; -}; - -Prediction.prototype.station = function() { - var nodes = this._raw.getElementsByTagName('S'); - return new Station(nodes[0]); -}; - -module.exports = Prediction; - -},{"./station":8}],8:[function(require,module,exports){ -var Platform = require("./platform"); - -function Station(data) { - this._raw = data; -} - -Station.prototype.name = function() { - return this._raw.getAttribute('N'); -}; - -Station.prototype.platforms = function() { - var platforms = []; - var nodes = this._raw.getElementsByTagName('P'); - - Array.prototype.forEach.call(nodes, function(node) { - platforms.push(new Platform(node)); - }); - - return platforms; -}; - -module.exports = Station; - -},{"./platform":6}],9:[function(require,module,exports){ -function Train(data) { - this._raw = data; -}; - -Train.prototype.id = function() { - return this._raw.getAttribute('LCID'); -}; - -Train.prototype.timeTo = function() { - return this._raw.getAttribute('TimeTo'); -}; - -Train.prototype.line = function() { - return this._raw.getAttribute('LN'); -}; - -Train.prototype.location = function() { - return this._raw.getAttribute('Location'); -}; - -Train.prototype.destination = function() { - return this._raw.getAttribute('Destination'); -}; - -module.exports = Train; - -},{}],10:[function(require,module,exports){ -var data = require("./data"); - -exports.debounceEvent = function(callback, wait) { - var timeout; - - return function() { - clearTimeout(timeout); - timeout = setTimeout(callback, wait); - }; -}; - -exports.httpRequest = function(url, success, error) { - var request = new XMLHttpRequest; - - request.open("GET", url); - - request.onload = function() { - if (this.status === 200) { - success(this.responseXML); + if (canSetImmediate) { + return function (f) { return window.setImmediate(f) }; } - else { - error(new Error(this.status)); - } - }; - request.onerror = function() { - error(this.status); - }; - - request.send(); -}; - -exports.proxyRequestURL = function(url) { - var query = "select * from xml where url='" + url + "'"; - return "http://query.yahooapis.com/v1/public/yql?q=" + encodeURIComponent(query); -}; - -exports.validateResponse = function(responseDoc) { - return responseDoc.getElementsByTagName("S").length === 1; -}; - -exports.getQueryString = function() { - return window.location.search.replace(/^\?/, "").replace(/\/$/, ""); -}; - -exports.formatQueryString = function(properties) { - var property; - var queryString = []; + if (canPost) { + var queue = []; + window.addEventListener('message', function (ev) { + var source = ev.source; + if ((source === window || source === null) && ev.data === 'process-tick') { + ev.stopPropagation(); + if (queue.length > 0) { + var fn = queue.shift(); + fn(); + } + } + }, true); - for (property in properties) { - if (properties.hasOwnProperty(property)) { - queryString.push("" + property + "=" + properties[property]); + return function nextTick(fn) { + queue.push(fn); + window.postMessage('process-tick', '*'); + }; } - } - - return "?" + queryString.join("&"); -}; -exports.queryStringProperty = function(queryString, prop) { - var pairs = queryString.split("&"); - var properties = {}; + return function nextTick(fn) { + setTimeout(fn, 0); + }; +})(); - pairs.forEach(function(pair) { - pair = pair.split("="); - properties[ pair[0] ] = pair[1]; - }); +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; - return properties[prop]; -}; +function noop() {} -exports.isLine = function(line, data) { - return line in data.lines; -}; +process.on = noop; +process.once = noop; +process.off = noop; +process.emit = noop; -exports.isStation = function(station, data) { - return station in data.stations; -}; - -exports.isStationOnLine = function(line, station, data) { - return this.isLine(line, data) && this.isStation(station, data) && - data.stationsOnLines[line].indexOf(station) >= 0; -}; +process.binding = function (name) { + throw new Error('process.binding is not supported'); +} -exports.mapCircleLineStation = function(station, data) { - return data.circleLineMap[station]; +// TODO(shtylman) +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); }; -},{"./data":5}],11:[function(require,module,exports){ -(function (global){ -/** - * React v0.10.0 - */ -!function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.React=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o]+)/; var RESULT_INDEX_ATTR = 'data-danger-index'; @@ -2789,7 +2864,7 @@ var Danger = { * @internal */ dangerouslyRenderMarkup: function(markupList) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( ExecutionEnvironment.canUseDOM, 'dangerouslyRenderMarkup(...): Cannot render markup in a Worker ' + 'thread. This is likely a bug in the framework. Please report ' + @@ -2799,7 +2874,7 @@ var Danger = { var markupByNodeName = {}; // Group markup by `nodeName` if a wrap is necessary, else by '*'. for (var i = 0; i < markupList.length; i++) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( markupList[i], 'dangerouslyRenderMarkup(...): Missing markup.' ) : invariant(markupList[i])); @@ -2848,7 +2923,7 @@ var Danger = { resultIndex = +renderNode.getAttribute(RESULT_INDEX_ATTR); renderNode.removeAttribute(RESULT_INDEX_ATTR); - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( !resultList.hasOwnProperty(resultIndex), 'Danger: Assigning to an already-occupied result index.' ) : invariant(!resultList.hasOwnProperty(resultIndex))); @@ -2859,7 +2934,7 @@ var Danger = { // we're done. resultListAssignmentCount += 1; - } else if ("production" !== "development") { + } else if ("production" !== process.env.NODE_ENV) { console.error( "Danger: Discarding unexpected node:", renderNode @@ -2870,12 +2945,12 @@ var Danger = { // Although resultList was populated out of order, it should now be a dense // array. - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( resultListAssignmentCount === resultList.length, 'Danger: Did not assign to every index of resultList.' ) : invariant(resultListAssignmentCount === resultList.length)); - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( resultList.length === markupList.length, 'Danger: Expected markup to render %s nodes, but rendered %s.', markupList.length, @@ -2894,14 +2969,14 @@ var Danger = { * @internal */ dangerouslyReplaceNodeWithMarkup: function(oldChild, markup) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( ExecutionEnvironment.canUseDOM, 'dangerouslyReplaceNodeWithMarkup(...): Cannot render markup in a ' + 'worker thread. This is likely a bug in the framework. Please report ' + 'immediately.' ) : invariant(ExecutionEnvironment.canUseDOM)); - ("production" !== "development" ? invariant(markup, 'dangerouslyReplaceNodeWithMarkup(...): Missing markup.') : invariant(markup)); - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant(markup, 'dangerouslyReplaceNodeWithMarkup(...): Missing markup.') : invariant(markup)); + ("production" !== process.env.NODE_ENV ? invariant( oldChild.tagName.toLowerCase() !== 'html', 'dangerouslyReplaceNodeWithMarkup(...): Cannot replace markup of the ' + ' node. This is because browser quirks make this unreliable ' + @@ -2917,7 +2992,8 @@ var Danger = { module.exports = Danger; -},{"./ExecutionEnvironment":20,"./createNodesFromMarkup":93,"./emptyFunction":96,"./getMarkupWrap":105,"./invariant":112}],11:[function(_dereq_,module,exports){ +}).call(this,require("/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js")) +},{"./ExecutionEnvironment":27,"./createNodesFromMarkup":100,"./emptyFunction":103,"./getMarkupWrap":112,"./invariant":119,"/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":7}],18:[function(require,module,exports){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -2940,7 +3016,7 @@ module.exports = Danger; "use strict"; -var DOMProperty = _dereq_("./DOMProperty"); +var DOMProperty = require("./DOMProperty"); var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE; var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY; @@ -3115,7 +3191,7 @@ var DefaultDOMPropertyConfig = { module.exports = DefaultDOMPropertyConfig; -},{"./DOMProperty":8}],12:[function(_dereq_,module,exports){ +},{"./DOMProperty":15}],19:[function(require,module,exports){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -3136,7 +3212,7 @@ module.exports = DefaultDOMPropertyConfig; "use strict"; - var keyOf = _dereq_("./keyOf"); + var keyOf = require("./keyOf"); /** * Module that is injectable into `EventPluginHub`, that specifies a @@ -3161,7 +3237,7 @@ var DefaultEventPluginOrder = [ module.exports = DefaultEventPluginOrder; -},{"./keyOf":119}],13:[function(_dereq_,module,exports){ +},{"./keyOf":126}],20:[function(require,module,exports){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -3183,12 +3259,12 @@ module.exports = DefaultEventPluginOrder; "use strict"; -var EventConstants = _dereq_("./EventConstants"); -var EventPropagators = _dereq_("./EventPropagators"); -var SyntheticMouseEvent = _dereq_("./SyntheticMouseEvent"); +var EventConstants = require("./EventConstants"); +var EventPropagators = require("./EventPropagators"); +var SyntheticMouseEvent = require("./SyntheticMouseEvent"); -var ReactMount = _dereq_("./ReactMount"); -var keyOf = _dereq_("./keyOf"); +var ReactMount = require("./ReactMount"); +var keyOf = require("./keyOf"); var topLevelTypes = EventConstants.topLevelTypes; var getFirstReactDOM = ReactMount.getFirstReactDOM; @@ -3308,7 +3384,7 @@ var EnterLeaveEventPlugin = { module.exports = EnterLeaveEventPlugin; -},{"./EventConstants":14,"./EventPropagators":19,"./ReactMount":55,"./SyntheticMouseEvent":81,"./keyOf":119}],14:[function(_dereq_,module,exports){ +},{"./EventConstants":21,"./EventPropagators":26,"./ReactMount":62,"./SyntheticMouseEvent":88,"./keyOf":126}],21:[function(require,module,exports){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -3329,7 +3405,7 @@ module.exports = EnterLeaveEventPlugin; "use strict"; -var keyMirror = _dereq_("./keyMirror"); +var keyMirror = require("./keyMirror"); var PropagationPhases = keyMirror({bubbled: null, captured: null}); @@ -3386,12 +3462,13 @@ var EventConstants = { module.exports = EventConstants; -},{"./keyMirror":118}],15:[function(_dereq_,module,exports){ +},{"./keyMirror":125}],22:[function(require,module,exports){ +(function (process){ /** * @providesModule EventListener */ -var emptyFunction = _dereq_("./emptyFunction"); +var emptyFunction = require("./emptyFunction"); /** * Upstream version of event listener. Does not take into account specific @@ -3434,7 +3511,7 @@ var EventListener = { */ capture: function(target, eventType, callback) { if (!target.addEventListener) { - if ("production" !== "development") { + if ("production" !== process.env.NODE_ENV) { console.error( 'Attempted to listen to events during the capture phase on a ' + 'browser that does not support the capture phase. Your application ' + @@ -3457,7 +3534,9 @@ var EventListener = { module.exports = EventListener; -},{"./emptyFunction":96}],16:[function(_dereq_,module,exports){ +}).call(this,require("/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js")) +},{"./emptyFunction":103,"/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":7}],23:[function(require,module,exports){ +(function (process){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -3478,15 +3557,15 @@ module.exports = EventListener; "use strict"; -var EventPluginRegistry = _dereq_("./EventPluginRegistry"); -var EventPluginUtils = _dereq_("./EventPluginUtils"); -var ExecutionEnvironment = _dereq_("./ExecutionEnvironment"); +var EventPluginRegistry = require("./EventPluginRegistry"); +var EventPluginUtils = require("./EventPluginUtils"); +var ExecutionEnvironment = require("./ExecutionEnvironment"); -var accumulate = _dereq_("./accumulate"); -var forEachAccumulated = _dereq_("./forEachAccumulated"); -var invariant = _dereq_("./invariant"); -var isEventSupported = _dereq_("./isEventSupported"); -var monitorCodeUse = _dereq_("./monitorCodeUse"); +var accumulate = require("./accumulate"); +var forEachAccumulated = require("./forEachAccumulated"); +var invariant = require("./invariant"); +var isEventSupported = require("./isEventSupported"); +var monitorCodeUse = require("./monitorCodeUse"); /** * Internal store for event listeners @@ -3577,13 +3656,13 @@ var EventPluginHub = { */ injectInstanceHandle: function(InjectedInstanceHandle) { InstanceHandle = InjectedInstanceHandle; - if ("production" !== "development") { + if ("production" !== process.env.NODE_ENV) { validateInstanceHandle(); } }, getInstanceHandle: function() { - if ("production" !== "development") { + if ("production" !== process.env.NODE_ENV) { validateInstanceHandle(); } return InstanceHandle; @@ -3614,17 +3693,17 @@ var EventPluginHub = { * @param {?function} listener The callback to store. */ putListener: function(id, registrationName, listener) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( ExecutionEnvironment.canUseDOM, 'Cannot call putListener() in a non-DOM environment.' ) : invariant(ExecutionEnvironment.canUseDOM)); - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( !listener || typeof listener === 'function', 'Expected %s listener to be a function, instead got type %s', registrationName, typeof listener ) : invariant(!listener || typeof listener === 'function')); - if ("production" !== "development") { + if ("production" !== process.env.NODE_ENV) { // IE8 has no API for event capturing and the `onScroll` event doesn't // bubble. if (registrationName === 'onScroll' && @@ -3732,7 +3811,7 @@ var EventPluginHub = { var processingEventQueue = eventQueue; eventQueue = null; forEachAccumulated(processingEventQueue, executeDispatchesAndRelease); - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( !eventQueue, 'processEventQueue(): Additional events were enqueued while processing ' + 'an event queue. Support for this has not yet been implemented.' @@ -3754,7 +3833,9 @@ var EventPluginHub = { module.exports = EventPluginHub; -},{"./EventPluginRegistry":17,"./EventPluginUtils":18,"./ExecutionEnvironment":20,"./accumulate":87,"./forEachAccumulated":101,"./invariant":112,"./isEventSupported":113,"./monitorCodeUse":125}],17:[function(_dereq_,module,exports){ +}).call(this,require("/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js")) +},{"./EventPluginRegistry":24,"./EventPluginUtils":25,"./ExecutionEnvironment":27,"./accumulate":94,"./forEachAccumulated":108,"./invariant":119,"./isEventSupported":120,"./monitorCodeUse":132,"/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":7}],24:[function(require,module,exports){ +(function (process){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -3776,7 +3857,7 @@ module.exports = EventPluginHub; "use strict"; -var invariant = _dereq_("./invariant"); +var invariant = require("./invariant"); /** * Injectable ordering of event plugins. @@ -3801,7 +3882,7 @@ function recomputePluginOrdering() { for (var pluginName in namesToPlugins) { var PluginModule = namesToPlugins[pluginName]; var pluginIndex = EventPluginOrder.indexOf(pluginName); - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( pluginIndex > -1, 'EventPluginRegistry: Cannot inject event plugins that do not exist in ' + 'the plugin ordering, `%s`.', @@ -3810,7 +3891,7 @@ function recomputePluginOrdering() { if (EventPluginRegistry.plugins[pluginIndex]) { continue; } - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( PluginModule.extractEvents, 'EventPluginRegistry: Event plugins must implement an `extractEvents` ' + 'method, but `%s` does not.', @@ -3819,7 +3900,7 @@ function recomputePluginOrdering() { EventPluginRegistry.plugins[pluginIndex] = PluginModule; var publishedEvents = PluginModule.eventTypes; for (var eventName in publishedEvents) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( publishEventForPlugin( publishedEvents[eventName], PluginModule, @@ -3846,7 +3927,7 @@ function recomputePluginOrdering() { * @private */ function publishEventForPlugin(dispatchConfig, PluginModule, eventName) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( !EventPluginRegistry.eventNameDispatchConfigs[eventName], 'EventPluginHub: More than one plugin attempted to publish the same ' + 'event name, `%s`.', @@ -3887,7 +3968,7 @@ function publishEventForPlugin(dispatchConfig, PluginModule, eventName) { * @private */ function publishRegistrationName(registrationName, PluginModule, eventName) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( !EventPluginRegistry.registrationNameModules[registrationName], 'EventPluginHub: More than one plugin attempted to publish the same ' + 'registration name, `%s`.', @@ -3935,7 +4016,7 @@ var EventPluginRegistry = { * @see {EventPluginHub.injection.injectEventPluginOrder} */ injectEventPluginOrder: function(InjectedEventPluginOrder) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( !EventPluginOrder, 'EventPluginRegistry: Cannot inject event plugin ordering more than once.' ) : invariant(!EventPluginOrder)); @@ -3962,7 +4043,7 @@ var EventPluginRegistry = { } var PluginModule = injectedNamesToPlugins[pluginName]; if (namesToPlugins[pluginName] !== PluginModule) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( !namesToPlugins[pluginName], 'EventPluginRegistry: Cannot inject two different event plugins ' + 'using the same name, `%s`.', @@ -4037,7 +4118,9 @@ var EventPluginRegistry = { module.exports = EventPluginRegistry; -},{"./invariant":112}],18:[function(_dereq_,module,exports){ +}).call(this,require("/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js")) +},{"./invariant":119,"/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":7}],25:[function(require,module,exports){ +(function (process){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -4058,9 +4141,9 @@ module.exports = EventPluginRegistry; "use strict"; -var EventConstants = _dereq_("./EventConstants"); +var EventConstants = require("./EventConstants"); -var invariant = _dereq_("./invariant"); +var invariant = require("./invariant"); /** * Injected dependencies: @@ -4074,8 +4157,8 @@ var injection = { Mount: null, injectMount: function(InjectedMount) { injection.Mount = InjectedMount; - if ("production" !== "development") { - ("production" !== "development" ? invariant( + if ("production" !== process.env.NODE_ENV) { + ("production" !== process.env.NODE_ENV ? invariant( InjectedMount && InjectedMount.getNode, 'EventPluginUtils.injection.injectMount(...): Injected Mount module ' + 'is missing getNode.' @@ -4103,7 +4186,7 @@ function isStartish(topLevelType) { var validateEventDispatches; -if ("production" !== "development") { +if ("production" !== process.env.NODE_ENV) { validateEventDispatches = function(event) { var dispatchListeners = event._dispatchListeners; var dispatchIDs = event._dispatchIDs; @@ -4115,7 +4198,7 @@ if ("production" !== "development") { dispatchListeners.length : dispatchListeners ? 1 : 0; - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( idsIsArr === listenersIsArr && IDsLen === listenersLen, 'EventPluginUtils: Invalid `event`.' ) : invariant(idsIsArr === listenersIsArr && IDsLen === listenersLen)); @@ -4130,7 +4213,7 @@ if ("production" !== "development") { function forEachEventDispatch(event, cb) { var dispatchListeners = event._dispatchListeners; var dispatchIDs = event._dispatchIDs; - if ("production" !== "development") { + if ("production" !== process.env.NODE_ENV) { validateEventDispatches(event); } if (Array.isArray(dispatchListeners)) { @@ -4178,7 +4261,7 @@ function executeDispatchesInOrder(event, executeDispatch) { function executeDispatchesInOrderStopAtTrue(event) { var dispatchListeners = event._dispatchListeners; var dispatchIDs = event._dispatchIDs; - if ("production" !== "development") { + if ("production" !== process.env.NODE_ENV) { validateEventDispatches(event); } if (Array.isArray(dispatchListeners)) { @@ -4209,12 +4292,12 @@ function executeDispatchesInOrderStopAtTrue(event) { * @return The return value of executing the single dispatch. */ function executeDirectDispatch(event) { - if ("production" !== "development") { + if ("production" !== process.env.NODE_ENV) { validateEventDispatches(event); } var dispatchListener = event._dispatchListeners; var dispatchID = event._dispatchIDs; - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( !Array.isArray(dispatchListener), 'executeDirectDispatch(...): Invalid `event`.' ) : invariant(!Array.isArray(dispatchListener))); @@ -4253,7 +4336,9 @@ var EventPluginUtils = { module.exports = EventPluginUtils; -},{"./EventConstants":14,"./invariant":112}],19:[function(_dereq_,module,exports){ +}).call(this,require("/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js")) +},{"./EventConstants":21,"./invariant":119,"/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":7}],26:[function(require,module,exports){ +(function (process){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -4274,11 +4359,11 @@ module.exports = EventPluginUtils; "use strict"; -var EventConstants = _dereq_("./EventConstants"); -var EventPluginHub = _dereq_("./EventPluginHub"); +var EventConstants = require("./EventConstants"); +var EventPluginHub = require("./EventPluginHub"); -var accumulate = _dereq_("./accumulate"); -var forEachAccumulated = _dereq_("./forEachAccumulated"); +var accumulate = require("./accumulate"); +var forEachAccumulated = require("./forEachAccumulated"); var PropagationPhases = EventConstants.PropagationPhases; var getListener = EventPluginHub.getListener; @@ -4300,7 +4385,7 @@ function listenerAtPhase(id, event, propagationPhase) { * "dispatch" object that pairs the event with the listener. */ function accumulateDirectionalDispatches(domID, upwards, event) { - if ("production" !== "development") { + if ("production" !== process.env.NODE_ENV) { if (!domID) { throw new Error('Dispatching id must not be null'); } @@ -4398,7 +4483,8 @@ var EventPropagators = { module.exports = EventPropagators; -},{"./EventConstants":14,"./EventPluginHub":16,"./accumulate":87,"./forEachAccumulated":101}],20:[function(_dereq_,module,exports){ +}).call(this,require("/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js")) +},{"./EventConstants":21,"./EventPluginHub":23,"./accumulate":94,"./forEachAccumulated":108,"/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":7}],27:[function(require,module,exports){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -4444,7 +4530,8 @@ var ExecutionEnvironment = { module.exports = ExecutionEnvironment; -},{}],21:[function(_dereq_,module,exports){ +},{}],28:[function(require,module,exports){ +(function (process){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -4466,10 +4553,10 @@ module.exports = ExecutionEnvironment; "use strict"; -var ReactPropTypes = _dereq_("./ReactPropTypes"); +var ReactPropTypes = require("./ReactPropTypes"); -var invariant = _dereq_("./invariant"); -var warning = _dereq_("./warning"); +var invariant = require("./invariant"); +var warning = require("./warning"); var hasReadOnlyValue = { 'button': true, @@ -4482,7 +4569,7 @@ var hasReadOnlyValue = { }; function _assertSingleLink(input) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( input.props.checkedLink == null || input.props.valueLink == null, 'Cannot provide a checkedLink and a valueLink. If you want to use ' + 'checkedLink, you probably don\'t want to use valueLink and vice versa.' @@ -4490,7 +4577,7 @@ function _assertSingleLink(input) { } function _assertValueLink(input) { _assertSingleLink(input); - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( input.props.value == null && input.props.onChange == null, 'Cannot provide a valueLink and a value or onChange event. If you want ' + 'to use value or onChange, you probably don\'t want to use valueLink.' @@ -4499,7 +4586,7 @@ function _assertValueLink(input) { function _assertCheckedLink(input) { _assertSingleLink(input); - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( input.props.checked == null && input.props.onChange == null, 'Cannot provide a checkedLink and a checked property or onChange event. ' + 'If you want to use checked or onChange, you probably don\'t want to ' + @@ -4531,8 +4618,8 @@ var LinkedValueUtils = { Mixin: { propTypes: { value: function(props, propName, componentName) { - if ("production" !== "development") { - ("production" !== "development" ? warning( + if ("production" !== process.env.NODE_ENV) { + ("production" !== process.env.NODE_ENV ? warning( !props[propName] || hasReadOnlyValue[props.type] || props.onChange || @@ -4546,8 +4633,8 @@ var LinkedValueUtils = { } }, checked: function(props, propName, componentName) { - if ("production" !== "development") { - ("production" !== "development" ? warning( + if ("production" !== process.env.NODE_ENV) { + ("production" !== process.env.NODE_ENV ? warning( !props[propName] || props.onChange || props.readOnly || @@ -4606,7 +4693,8 @@ var LinkedValueUtils = { module.exports = LinkedValueUtils; -},{"./ReactPropTypes":64,"./invariant":112,"./warning":134}],22:[function(_dereq_,module,exports){ +}).call(this,require("/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js")) +},{"./ReactPropTypes":71,"./invariant":119,"./warning":141,"/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":7}],29:[function(require,module,exports){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -4628,9 +4716,9 @@ module.exports = LinkedValueUtils; "use strict"; -var EventConstants = _dereq_("./EventConstants"); +var EventConstants = require("./EventConstants"); -var emptyFunction = _dereq_("./emptyFunction"); +var emptyFunction = require("./emptyFunction"); var topLevelTypes = EventConstants.topLevelTypes; @@ -4671,7 +4759,8 @@ var MobileSafariClickEventPlugin = { module.exports = MobileSafariClickEventPlugin; -},{"./EventConstants":14,"./emptyFunction":96}],23:[function(_dereq_,module,exports){ +},{"./EventConstants":21,"./emptyFunction":103}],30:[function(require,module,exports){ +(function (process){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -4692,7 +4781,7 @@ module.exports = MobileSafariClickEventPlugin; "use strict"; -var invariant = _dereq_("./invariant"); +var invariant = require("./invariant"); /** * Static poolers. Several custom versions for each potential number of @@ -4747,7 +4836,7 @@ var fiveArgumentPooler = function(a1, a2, a3, a4, a5) { var standardReleaser = function(instance) { var Klass = this; - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( instance instanceof Klass, 'Trying to release an instance into a pool of a different type.' ) : invariant(instance instanceof Klass)); @@ -4792,7 +4881,9 @@ var PooledClass = { module.exports = PooledClass; -},{"./invariant":112}],24:[function(_dereq_,module,exports){ +}).call(this,require("/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js")) +},{"./invariant":119,"/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":7}],31:[function(require,module,exports){ +(function (process){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -4813,25 +4904,25 @@ module.exports = PooledClass; "use strict"; -var DOMPropertyOperations = _dereq_("./DOMPropertyOperations"); -var EventPluginUtils = _dereq_("./EventPluginUtils"); -var ReactChildren = _dereq_("./ReactChildren"); -var ReactComponent = _dereq_("./ReactComponent"); -var ReactCompositeComponent = _dereq_("./ReactCompositeComponent"); -var ReactContext = _dereq_("./ReactContext"); -var ReactCurrentOwner = _dereq_("./ReactCurrentOwner"); -var ReactDOM = _dereq_("./ReactDOM"); -var ReactDOMComponent = _dereq_("./ReactDOMComponent"); -var ReactDefaultInjection = _dereq_("./ReactDefaultInjection"); -var ReactInstanceHandles = _dereq_("./ReactInstanceHandles"); -var ReactMount = _dereq_("./ReactMount"); -var ReactMultiChild = _dereq_("./ReactMultiChild"); -var ReactPerf = _dereq_("./ReactPerf"); -var ReactPropTypes = _dereq_("./ReactPropTypes"); -var ReactServerRendering = _dereq_("./ReactServerRendering"); -var ReactTextComponent = _dereq_("./ReactTextComponent"); - -var onlyChild = _dereq_("./onlyChild"); +var DOMPropertyOperations = require("./DOMPropertyOperations"); +var EventPluginUtils = require("./EventPluginUtils"); +var ReactChildren = require("./ReactChildren"); +var ReactComponent = require("./ReactComponent"); +var ReactCompositeComponent = require("./ReactCompositeComponent"); +var ReactContext = require("./ReactContext"); +var ReactCurrentOwner = require("./ReactCurrentOwner"); +var ReactDOM = require("./ReactDOM"); +var ReactDOMComponent = require("./ReactDOMComponent"); +var ReactDefaultInjection = require("./ReactDefaultInjection"); +var ReactInstanceHandles = require("./ReactInstanceHandles"); +var ReactMount = require("./ReactMount"); +var ReactMultiChild = require("./ReactMultiChild"); +var ReactPerf = require("./ReactPerf"); +var ReactPropTypes = require("./ReactPropTypes"); +var ReactServerRendering = require("./ReactServerRendering"); +var ReactTextComponent = require("./ReactTextComponent"); + +var onlyChild = require("./onlyChild"); ReactDefaultInjection.inject(); @@ -4873,8 +4964,8 @@ var React = { } }; -if ("production" !== "development") { - var ExecutionEnvironment = _dereq_("./ExecutionEnvironment"); +if ("production" !== process.env.NODE_ENV) { + var ExecutionEnvironment = require("./ExecutionEnvironment"); if (ExecutionEnvironment.canUseDOM && window.top === window.self && navigator.userAgent.indexOf('Chrome') > -1) { @@ -4891,7 +4982,9 @@ React.version = '0.10.0'; module.exports = React; -},{"./DOMPropertyOperations":9,"./EventPluginUtils":18,"./ExecutionEnvironment":20,"./ReactChildren":26,"./ReactComponent":27,"./ReactCompositeComponent":29,"./ReactContext":30,"./ReactCurrentOwner":31,"./ReactDOM":32,"./ReactDOMComponent":34,"./ReactDefaultInjection":44,"./ReactInstanceHandles":53,"./ReactMount":55,"./ReactMultiChild":57,"./ReactPerf":60,"./ReactPropTypes":64,"./ReactServerRendering":68,"./ReactTextComponent":70,"./onlyChild":128}],25:[function(_dereq_,module,exports){ +}).call(this,require("/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js")) +},{"./DOMPropertyOperations":16,"./EventPluginUtils":25,"./ExecutionEnvironment":27,"./ReactChildren":33,"./ReactComponent":34,"./ReactCompositeComponent":36,"./ReactContext":37,"./ReactCurrentOwner":38,"./ReactDOM":39,"./ReactDOMComponent":41,"./ReactDefaultInjection":51,"./ReactInstanceHandles":60,"./ReactMount":62,"./ReactMultiChild":64,"./ReactPerf":67,"./ReactPropTypes":71,"./ReactServerRendering":75,"./ReactTextComponent":77,"./onlyChild":135,"/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":7}],32:[function(require,module,exports){ +(function (process){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -4912,9 +5005,9 @@ module.exports = React; "use strict"; -var ReactMount = _dereq_("./ReactMount"); +var ReactMount = require("./ReactMount"); -var invariant = _dereq_("./invariant"); +var invariant = require("./invariant"); var ReactBrowserComponentMixin = { /** @@ -4925,7 +5018,7 @@ var ReactBrowserComponentMixin = { * @protected */ getDOMNode: function() { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( this.isMounted(), 'getDOMNode(): A component must be mounted to have a DOM node.' ) : invariant(this.isMounted())); @@ -4935,7 +5028,9 @@ var ReactBrowserComponentMixin = { module.exports = ReactBrowserComponentMixin; -},{"./ReactMount":55,"./invariant":112}],26:[function(_dereq_,module,exports){ +}).call(this,require("/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js")) +},{"./ReactMount":62,"./invariant":119,"/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":7}],33:[function(require,module,exports){ +(function (process){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -4956,10 +5051,10 @@ module.exports = ReactBrowserComponentMixin; "use strict"; -var PooledClass = _dereq_("./PooledClass"); +var PooledClass = require("./PooledClass"); -var invariant = _dereq_("./invariant"); -var traverseAllChildren = _dereq_("./traverseAllChildren"); +var invariant = require("./invariant"); +var traverseAllChildren = require("./traverseAllChildren"); var twoArgumentPooler = PooledClass.twoArgumentPooler; var threeArgumentPooler = PooledClass.threeArgumentPooler; @@ -5027,7 +5122,7 @@ function mapSingleChildIntoContext(traverseContext, child, name, i) { var mappedChild = mapBookKeeping.mapFunction.call(mapBookKeeping.mapContext, child, i); // We found a component instance - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( !mapResult.hasOwnProperty(name), 'ReactChildren.map(...): Encountered two children with the same key, ' + '`%s`. Children keys must be unique.', @@ -5069,7 +5164,9 @@ var ReactChildren = { module.exports = ReactChildren; -},{"./PooledClass":23,"./invariant":112,"./traverseAllChildren":133}],27:[function(_dereq_,module,exports){ +}).call(this,require("/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js")) +},{"./PooledClass":30,"./invariant":119,"./traverseAllChildren":140,"/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":7}],34:[function(require,module,exports){ +(function (process){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -5090,14 +5187,14 @@ module.exports = ReactChildren; "use strict"; -var ReactCurrentOwner = _dereq_("./ReactCurrentOwner"); -var ReactOwner = _dereq_("./ReactOwner"); -var ReactUpdates = _dereq_("./ReactUpdates"); +var ReactCurrentOwner = require("./ReactCurrentOwner"); +var ReactOwner = require("./ReactOwner"); +var ReactUpdates = require("./ReactUpdates"); -var invariant = _dereq_("./invariant"); -var keyMirror = _dereq_("./keyMirror"); -var merge = _dereq_("./merge"); -var monitorCodeUse = _dereq_("./monitorCodeUse"); +var invariant = require("./invariant"); +var keyMirror = require("./keyMirror"); +var merge = require("./merge"); +var monitorCodeUse = require("./monitorCodeUse"); /** * Every React component is in one of these life cycles. @@ -5301,7 +5398,7 @@ var ReactComponent = { injection: { injectEnvironment: function(ReactComponentEnvironment) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( !injected, 'ReactComponent: injectEnvironment() can only be called once.' ) : invariant(!injected)); @@ -5402,11 +5499,11 @@ var ReactComponent = { * @public */ replaceProps: function(props, callback) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( this.isMounted(), 'replaceProps(...): Can only update a mounted component.' ) : invariant(this.isMounted())); - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( this._mountDepth === 0, 'replaceProps(...): You called `setProps` or `replaceProps` on a ' + 'component with a parent. This is an anti-pattern since props will ' + @@ -5447,14 +5544,14 @@ var ReactComponent = { // Children can be more than one argument var childrenLength = arguments.length - 1; if (childrenLength === 1) { - if ("production" !== "development") { + if ("production" !== process.env.NODE_ENV) { validateChildKeys(children); } this.props.children = children; } else if (childrenLength > 1) { var childArray = Array(childrenLength); for (var i = 0; i < childrenLength; i++) { - if ("production" !== "development") { + if ("production" !== process.env.NODE_ENV) { validateChildKeys(arguments[i + 1]); } childArray[i] = arguments[i + 1]; @@ -5478,7 +5575,7 @@ var ReactComponent = { * @internal */ mountComponent: function(rootID, transaction, mountDepth) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( !this.isMounted(), 'mountComponent(%s, ...): Can only mount an unmounted component. ' + 'Make sure to avoid storing components between renders or reusing a ' + @@ -5506,7 +5603,7 @@ var ReactComponent = { * @internal */ unmountComponent: function() { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( this.isMounted(), 'unmountComponent(): Can only unmount a mounted component.' ) : invariant(this.isMounted())); @@ -5531,7 +5628,7 @@ var ReactComponent = { * @internal */ receiveComponent: function(nextComponent, transaction) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( this.isMounted(), 'receiveComponent(...): Can only update a mounted component.' ) : invariant(this.isMounted())); @@ -5666,7 +5763,9 @@ var ReactComponent = { module.exports = ReactComponent; -},{"./ReactCurrentOwner":31,"./ReactOwner":59,"./ReactUpdates":71,"./invariant":112,"./keyMirror":118,"./merge":121,"./monitorCodeUse":125}],28:[function(_dereq_,module,exports){ +}).call(this,require("/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js")) +},{"./ReactCurrentOwner":38,"./ReactOwner":66,"./ReactUpdates":78,"./invariant":119,"./keyMirror":125,"./merge":128,"./monitorCodeUse":132,"/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":7}],35:[function(require,module,exports){ +(function (process){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -5689,14 +5788,14 @@ module.exports = ReactComponent; "use strict"; -var ReactDOMIDOperations = _dereq_("./ReactDOMIDOperations"); -var ReactMarkupChecksum = _dereq_("./ReactMarkupChecksum"); -var ReactMount = _dereq_("./ReactMount"); -var ReactPerf = _dereq_("./ReactPerf"); -var ReactReconcileTransaction = _dereq_("./ReactReconcileTransaction"); +var ReactDOMIDOperations = require("./ReactDOMIDOperations"); +var ReactMarkupChecksum = require("./ReactMarkupChecksum"); +var ReactMount = require("./ReactMount"); +var ReactPerf = require("./ReactPerf"); +var ReactReconcileTransaction = require("./ReactReconcileTransaction"); -var getReactRootElementInContainer = _dereq_("./getReactRootElementInContainer"); -var invariant = _dereq_("./invariant"); +var getReactRootElementInContainer = require("./getReactRootElementInContainer"); +var invariant = require("./invariant"); var ELEMENT_NODE_TYPE = 1; @@ -5733,7 +5832,7 @@ var ReactComponentBrowserEnvironment = { 'ReactComponentBrowserEnvironment', 'mountImageIntoNode', function(markup, container, shouldReuseMarkup) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( container && ( container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE @@ -5750,7 +5849,7 @@ var ReactComponentBrowserEnvironment = { getReactRootElementInContainer(container))) { return; } else { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( container.nodeType !== DOC_NODE_TYPE, 'You\'re trying to render a component to the document using ' + 'server rendering but the checksum was invalid. This usually ' + @@ -5762,7 +5861,7 @@ var ReactComponentBrowserEnvironment = { 'and ensure the props are the same client and server side.' ) : invariant(container.nodeType !== DOC_NODE_TYPE)); - if ("production" !== "development") { + if ("production" !== process.env.NODE_ENV) { console.warn( 'React attempted to use reuse markup in a container but the ' + 'checksum was invalid. This generally means that you are ' + @@ -5777,7 +5876,7 @@ var ReactComponentBrowserEnvironment = { } } - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( container.nodeType !== DOC_NODE_TYPE, 'You\'re trying to render a component to the document but ' + 'you didn\'t use server rendering. We can\'t do this ' + @@ -5792,7 +5891,9 @@ var ReactComponentBrowserEnvironment = { module.exports = ReactComponentBrowserEnvironment; -},{"./ReactDOMIDOperations":36,"./ReactMarkupChecksum":54,"./ReactMount":55,"./ReactPerf":60,"./ReactReconcileTransaction":66,"./getReactRootElementInContainer":107,"./invariant":112}],29:[function(_dereq_,module,exports){ +}).call(this,require("/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js")) +},{"./ReactDOMIDOperations":43,"./ReactMarkupChecksum":61,"./ReactMount":62,"./ReactPerf":67,"./ReactReconcileTransaction":73,"./getReactRootElementInContainer":114,"./invariant":119,"/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":7}],36:[function(require,module,exports){ +(function (process){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -5813,26 +5914,26 @@ module.exports = ReactComponentBrowserEnvironment; "use strict"; -var ReactComponent = _dereq_("./ReactComponent"); -var ReactContext = _dereq_("./ReactContext"); -var ReactCurrentOwner = _dereq_("./ReactCurrentOwner"); -var ReactErrorUtils = _dereq_("./ReactErrorUtils"); -var ReactOwner = _dereq_("./ReactOwner"); -var ReactPerf = _dereq_("./ReactPerf"); -var ReactPropTransferer = _dereq_("./ReactPropTransferer"); -var ReactPropTypeLocations = _dereq_("./ReactPropTypeLocations"); -var ReactPropTypeLocationNames = _dereq_("./ReactPropTypeLocationNames"); -var ReactUpdates = _dereq_("./ReactUpdates"); - -var instantiateReactComponent = _dereq_("./instantiateReactComponent"); -var invariant = _dereq_("./invariant"); -var keyMirror = _dereq_("./keyMirror"); -var merge = _dereq_("./merge"); -var mixInto = _dereq_("./mixInto"); -var monitorCodeUse = _dereq_("./monitorCodeUse"); -var objMap = _dereq_("./objMap"); -var shouldUpdateReactComponent = _dereq_("./shouldUpdateReactComponent"); -var warning = _dereq_("./warning"); +var ReactComponent = require("./ReactComponent"); +var ReactContext = require("./ReactContext"); +var ReactCurrentOwner = require("./ReactCurrentOwner"); +var ReactErrorUtils = require("./ReactErrorUtils"); +var ReactOwner = require("./ReactOwner"); +var ReactPerf = require("./ReactPerf"); +var ReactPropTransferer = require("./ReactPropTransferer"); +var ReactPropTypeLocations = require("./ReactPropTypeLocations"); +var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames"); +var ReactUpdates = require("./ReactUpdates"); + +var instantiateReactComponent = require("./instantiateReactComponent"); +var invariant = require("./invariant"); +var keyMirror = require("./keyMirror"); +var merge = require("./merge"); +var mixInto = require("./mixInto"); +var monitorCodeUse = require("./monitorCodeUse"); +var objMap = require("./objMap"); +var shouldUpdateReactComponent = require("./shouldUpdateReactComponent"); +var warning = require("./warning"); /** * Policies that describe methods in `ReactCompositeComponentInterface`. @@ -6169,7 +6270,7 @@ var RESERVED_SPEC_KEYS = { function validateTypeDef(Constructor, typeDef, location) { for (var propName in typeDef) { if (typeDef.hasOwnProperty(propName)) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( typeof typeDef[propName] == 'function', '%s: %s type `%s` is invalid; it must be a function, usually from ' + 'React.PropTypes.', @@ -6186,7 +6287,7 @@ function validateMethodOverride(proto, name) { // Disallow overriding of base class methods unless explicitly allowed. if (ReactCompositeComponentMixin.hasOwnProperty(name)) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( specPolicy === SpecPolicy.OVERRIDE_BASE, 'ReactCompositeComponentInterface: You are attempting to override ' + '`%s` from your class specification. Ensure that your method names ' + @@ -6197,7 +6298,7 @@ function validateMethodOverride(proto, name) { // Disallow defining methods more than once unless explicitly allowed. if (proto.hasOwnProperty(name)) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( specPolicy === SpecPolicy.DEFINE_MANY || specPolicy === SpecPolicy.DEFINE_MANY_MERGED, 'ReactCompositeComponentInterface: You are attempting to define ' + @@ -6211,18 +6312,18 @@ function validateMethodOverride(proto, name) { function validateLifeCycleOnReplaceState(instance) { var compositeLifeCycleState = instance._compositeLifeCycleState; - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( instance.isMounted() || compositeLifeCycleState === CompositeLifeCycle.MOUNTING, 'replaceState(...): Can only update a mounted or mounting component.' ) : invariant(instance.isMounted() || compositeLifeCycleState === CompositeLifeCycle.MOUNTING)); - ("production" !== "development" ? invariant(compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE, + ("production" !== process.env.NODE_ENV ? invariant(compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE, 'replaceState(...): Cannot update during an existing state transition ' + '(such as within `render`). This could potentially cause an infinite ' + 'loop so it is forbidden.' ) : invariant(compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE)); - ("production" !== "development" ? invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING, + ("production" !== process.env.NODE_ENV ? invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING, 'replaceState(...): Cannot update while unmounting component. This ' + 'usually means you called setState() on an unmounted component.' ) : invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING)); @@ -6233,12 +6334,12 @@ function validateLifeCycleOnReplaceState(instance) { * specification keys when building `ReactCompositeComponent` classses. */ function mixSpecIntoComponent(ConvenienceConstructor, spec) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( !isValidClass(spec), 'ReactCompositeComponent: You\'re attempting to ' + 'use a component class as a mixin. Instead, just use a regular object.' ) : invariant(!isValidClass(spec))); - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( !ReactComponent.isValidComponent(spec), 'ReactCompositeComponent: You\'re attempting to ' + 'use a component as a mixin. Instead, just use a regular object.' @@ -6311,7 +6412,7 @@ function mixStaticSpecIntoComponent(ConvenienceConstructor, statics) { var existingProperty = ConvenienceConstructor[name]; var existingType = typeof existingProperty; var propertyType = typeof property; - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( existingType === 'function' && propertyType === 'function', 'ReactCompositeComponent: You are attempting to define ' + '`%s` on your component more than once, but that is only supported ' + @@ -6334,13 +6435,13 @@ function mixStaticSpecIntoComponent(ConvenienceConstructor, statics) { * @return {object} one after it has been mutated to contain everything in two. */ function mergeObjectsWithNoDuplicateKeys(one, two) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( one && two && typeof one === 'object' && typeof two === 'object', 'mergeObjectsWithNoDuplicateKeys(): Cannot merge non-objects' ) : invariant(one && two && typeof one === 'object' && typeof two === 'object')); objMap(two, function(value, key) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( one[key] === undefined, 'mergeObjectsWithNoDuplicateKeys(): ' + 'Tried to merge two objects with the same key: %s', @@ -6387,7 +6488,7 @@ function createChainedFunction(one, two) { }; } -if ("production" !== "development") { +if ("production" !== process.env.NODE_ENV) { var unmountedPropertyWhitelist = { constructor: true, @@ -6719,7 +6820,7 @@ var ReactCompositeComponentMixin = { } this.state = this.getInitialState ? this.getInitialState() : null; - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( typeof this.state === 'object' && !Array.isArray(this.state), '%s.getInitialState(): must return an object or null', this.constructor.displayName || 'ReactCompositeComponent' @@ -6800,12 +6901,12 @@ var ReactCompositeComponentMixin = { * @protected */ setState: function(partialState, callback) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( typeof partialState === 'object' || partialState == null, 'setState(...): takes an object of state variables to update.' ) : invariant(typeof partialState === 'object' || partialState == null)); - if ("production" !== "development") { - ("production" !== "development" ? warning( + if ("production" !== process.env.NODE_ENV) { + ("production" !== process.env.NODE_ENV ? warning( partialState != null, 'setState(...): You passed an undefined or null state object; ' + 'instead, use forceUpdate().' @@ -6852,7 +6953,7 @@ var ReactCompositeComponentMixin = { for (var contextName in contextTypes) { maskedContext[contextName] = context[contextName]; } - if ("production" !== "development") { + if ("production" !== process.env.NODE_ENV) { this._checkPropTypes( contextTypes, maskedContext, @@ -6872,13 +6973,13 @@ var ReactCompositeComponentMixin = { var childContext = this.getChildContext && this.getChildContext(); var displayName = this.constructor.displayName || 'ReactCompositeComponent'; if (childContext) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( typeof this.constructor.childContextTypes === 'object', '%s.getChildContext(): childContextTypes must be defined in order to ' + 'use getChildContext().', displayName ) : invariant(typeof this.constructor.childContextTypes === 'object')); - if ("production" !== "development") { + if ("production" !== process.env.NODE_ENV) { this._checkPropTypes( this.constructor.childContextTypes, childContext, @@ -6886,7 +6987,7 @@ var ReactCompositeComponentMixin = { ); } for (var name in childContext) { - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( name in this.constructor.childContextTypes, '%s.getChildContext(): key "%s" is not defined in childContextTypes.', displayName, @@ -6915,7 +7016,7 @@ var ReactCompositeComponentMixin = { props[propName] = defaultProps[propName]; } } - if ("production" !== "development") { + if ("production" !== process.env.NODE_ENV) { var propTypes = this.constructor.propTypes; if (propTypes) { this._checkPropTypes(propTypes, props, ReactPropTypeLocations.prop); @@ -7156,14 +7257,14 @@ var ReactCompositeComponentMixin = { */ forceUpdate: function(callback) { var compositeLifeCycleState = this._compositeLifeCycleState; - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( this.isMounted() || compositeLifeCycleState === CompositeLifeCycle.MOUNTING, 'forceUpdate(...): Can only force an update on mounted or mounting ' + 'components.' ) : invariant(this.isMounted() || compositeLifeCycleState === CompositeLifeCycle.MOUNTING)); - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE && compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING, 'forceUpdate(...): Cannot force an update while unmounting component ' + @@ -7191,7 +7292,7 @@ var ReactCompositeComponentMixin = { ReactContext.current = previousContext; ReactCurrentOwner.current = null; } - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( ReactComponent.isValidComponent(renderedComponent), '%s.render(): A valid ReactComponent must be returned. You may have ' + 'returned null, undefined, an array, or some other invalid object.', @@ -7228,7 +7329,7 @@ var ReactCompositeComponentMixin = { var boundMethod = function() { return method.apply(component, arguments); }; - if ("production" !== "development") { + if ("production" !== process.env.NODE_ENV) { boundMethod.__reactBoundContext = component; boundMethod.__reactBoundMethod = method; boundMethod.__reactBoundArguments = null; @@ -7325,12 +7426,12 @@ var ReactCompositeComponent = { mixSpecIntoComponent(ConvenienceConstructor, spec); - ("production" !== "development" ? invariant( + ("production" !== process.env.NODE_ENV ? invariant( Constructor.prototype.render, 'createClass(...): Class specification must implement a `render` method.' ) : invariant(Constructor.prototype.render)); - if ("production" !== "development") { + if ("production" !== process.env.NODE_ENV) { if (Constructor.prototype.componentShouldUpdate) { monitorCodeUse( 'react_component_should_update_warning', @@ -7360,7 +7461,7 @@ var ReactCompositeComponent = { } } - if ("production" !== "development") { + if ("production" !== process.env.NODE_ENV) { // In DEV the convenience constructor generates a proxy to another // instance around it to warn about access to properties on the // descriptor. @@ -7381,7 +7482,8 @@ var ReactCompositeComponent = { module.exports = ReactCompositeComponent; -},{"./ReactComponent":27,"./ReactContext":30,"./ReactCurrentOwner":31,"./ReactErrorUtils":47,"./ReactOwner":59,"./ReactPerf":60,"./ReactPropTransferer":61,"./ReactPropTypeLocationNames":62,"./ReactPropTypeLocations":63,"./ReactUpdates":71,"./instantiateReactComponent":111,"./invariant":112,"./keyMirror":118,"./merge":121,"./mixInto":124,"./monitorCodeUse":125,"./objMap":126,"./shouldUpdateReactComponent":131,"./warning":134}],30:[function(_dereq_,module,exports){ +}).call(this,require("/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js")) +},{"./ReactComponent":34,"./ReactContext":37,"./ReactCurrentOwner":38,"./ReactErrorUtils":54,"./ReactOwner":66,"./ReactPerf":67,"./ReactPropTransferer":68,"./ReactPropTypeLocationNames":69,"./ReactPropTypeLocations":70,"./ReactUpdates":78,"./instantiateReactComponent":118,"./invariant":119,"./keyMirror":125,"./merge":128,"./mixInto":131,"./monitorCodeUse":132,"./objMap":133,"./shouldUpdateReactComponent":138,"./warning":141,"/Users/matt/Code/tube-tracker/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":7}],37:[function(require,module,exports){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -7402,7 +7504,7 @@ module.exports = ReactCompositeComponent; "use strict"; -var merge = _dereq_("./merge"); +var merge = require("./merge"); /** * Keeps track of the current context. @@ -7450,7 +7552,7 @@ var ReactContext = { module.exports = ReactContext; -},{"./merge":121}],31:[function(_dereq_,module,exports){ +},{"./merge":128}],38:[function(require,module,exports){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -7491,7 +7593,7 @@ var ReactCurrentOwner = { module.exports = ReactCurrentOwner; -},{}],32:[function(_dereq_,module,exports){ +},{}],39:[function(require,module,exports){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -7513,10 +7615,10 @@ module.exports = ReactCurrentOwner; "use strict"; -var ReactDOMComponent = _dereq_("./ReactDOMComponent"); +var ReactDOMComponent = require("./ReactDOMComponent"); -var mergeInto = _dereq_("./mergeInto"); -var objMapKeyVal = _dereq_("./objMapKeyVal"); +var mergeInto = require("./mergeInto"); +var objMapKeyVal = require("./objMapKeyVal"); /** * Creates a new React class that is idempotent and capable of containing other @@ -7700,7 +7802,7 @@ ReactDOM.injection = injection; module.exports = ReactDOM; -},{"./ReactDOMComponent":34,"./mergeInto":123,"./objMapKeyVal":127}],33:[function(_dereq_,module,exports){ +},{"./ReactDOMComponent":41,"./mergeInto":130,"./objMapKeyVal":134}],40:[function(require,module,exports){ /** * Copyright 2013-2014 Facebook, Inc. * @@ -7721,12 +7823,12 @@ module.exports = ReactDOM; "use strict"; -var AutoFocusMixin = _dereq_("./AutoFocusMixin"); -var ReactBrowserComponentMixin = _dereq_("./ReactBrowserComponentMixin"); -var ReactCompositeComponent = _dereq_("./ReactCompositeComponent"); -var ReactDOM = _dereq_("./ReactDOM"); +var AutoFocusMixin = require("./AutoFocusMixin"); +var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin"); +var ReactCompositeComponent = require("./ReactCompositeComponent"); +var ReactDOM = require("./ReactDOM"); -var keyMirror = _dereq_("./keyMirror"); +var keyMirror = require("./keyMirror"); // Store a reference to the