1(function(){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);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}return e})()({1:[function(require,module,exports){ 2 3var Config = { 4 5 // cdn: 'path to your cdn server goes here', 6 cdn: '/', 7 8 fonts: { 9 BRANDON: "'Brandon Grotesque Regular', sans-serif", 10 BRANDONBLACK: "'Brandon Grotesque Black', sans-serif" 11 }, 12 13 colors: { 14 ORANGE: "#f15c28", 15 BROWN: "#44312e", 16 BASEUI: 'rgba(195, 77, 36, 0.75)' 17 }, 18 19 easing: { 20 MAIN: "easeOutCubic" 21 } 22} 23 24module.exports = Config; 25 26},{}],2:[function(require,module,exports){ 27var Data = { 28 29 navigation: { 30 31 sections: [ 32 { 33 key: "history", 34 title: "History", 35 url: "#/history" 36 }, 37 { 38 key: "players", 39 title: "Players", 40 url: "#/players" 41 }, 42 { 43 key: "about", 44 title: "About", 45 url: "#/about" 46 }, 47 { 48 key: "membership", 49 title: "Membership", 50 url: "https://membership.thestlbrowns.com" 51 }, 52 { 53 key: "merchandise", 54 title: "Merchandise", 55 url: "https://membership.thestlbrowns.com/stl-browns-shop/" 56 }, 57 { 58 key: "gallery", 59 title: "Gallery", 60 url: "https://membership.thestlbrowns.com/gallery/" 61 }, 62 { 63 key: "popflies", 64 title: "Popflies", 65 url: "https://membership.thestlbrowns.com/popflies/" 66 }, 67 { 68 key: "events", 69 title: "Events", 70 url: "https://membership.thestlbrowns.com/events/" 71 }, 72 { 73 key: "blog", 74 title: "Blog", 75 url: "https://membership.thestlbrowns.com/blog/" 76 }, 77 { 78 key: "contact", 79 title: "Contact Us", 80 url: "https://membership.thestlbrowns.com/contact-us" 81 } 82 83 84 85 ], 86 87 social: [ 88 { 89 key: "twitter", 90 title: "Twitter", 91 url: "https://twitter.com/Stl_browns", 92 ogImage: "", 93 ogDesc: "" 94 }, 95 { 96 key: "facebook", 97 title: "Facebook", 98 url: "https://www.facebook.com/SaintLouisBrowns", 99 ogImage: "", 100 ogDesc: "" 101 }, 102 { 103 key: "youtube", 104 title: "YouTube", 105 url: "https://www.youtube.com/user/OfficialSTLBrowns", 106 ogImage: "", 107 ogDesc: "" 108 } 109 ], 110 111 }, 112 113 historySection: { 114 115 title: "History", 116 117 sections: [ 118 119 { 120 key: "the-early-years", 121 title: "The Early Years", 122 overviewImage: "the-early-years-index.jpg", 123 hero: { 124 image: "bg-the-early-years.jpg", 125 coverImage: "cover-the-early-years.png" 126 }, 127 dates: { 128 from: 1902, 129 to: 1922 130 }, 131 overlayData: { 132 "ty-cobb": { 133 title: "The Ty Cobb Scandal", 134 body: "<p>Ty Cobb was the almost-certain winner for the 1910 AL batting title. So certain, in fact, that he took the last day of the season off. Nap Lajoie, hardly behind by a hair, saw an opportunity â and so did Browns manager Jack O’Connor, who happened to have it out for Cobb. O’Connor ordered his third baseman to play deep on the grass for Lajoie, putting a perfect game well within reach. It was all Lajoie needed to surpass Cobb. In the end, Lajoie reached his last base on an error, giving Cobb the title he righteously earned. O’Connor, and coach Harry Howell, who tried to bribe the official scorer out of the call, were fired from the Browns and never returned to the game.</p><p>Cobb’s season was reinvestigated 70 years later. Sporting News historian Paul McFarlane found that he’d been mistakenly credited for 2 hits â a difference that would’ve given Lajoie the clear lead. Yet, the baseball commissioner at the time refused to strip Cobb of his honor, keeping Cobb’s 9-season title streak in tact.</p>" 135 }, 136 "almost": { 137 title: "6½ Games Out", 138 body: "<p>Years 2 through 6 weren’t the Browns’ finest. They nearly hit 100 losses in 1905, but came back with a winning season (76-73) in 1906. Climbing out of the slump, the 1908 Browns were reasonably in the running for the pennant. They finished in 4th place, just 6 and a half games out of first.</p>" 139 } 140 } 141 }, 142 143 { 144 key: "the-bottom-dwellers", 145 title: "The Bottom Dwellers", 146 overviewImage: "the-bottom-dwellers-index.jpg", 147 hero: { 148 image: "bg-the-bottom-dwellers.jpg", 149 coverImage: "cover-the-bottom-dwellers.png" 150 }, 151 dates: { 152 from: 1926, 153 to: 1941 154 }, 155 overlayData: { 156 "dewitt": { 157 title: "Bill DeWitt, Sr. (1902 – 1982)", 158 body: "<p>After the Browns moved to Baltimore, DeWitt headed north. He was the assistant general manager of the New York Yankees from 1954 to 1958, then served as president and GM of the Detroit Tigers from 1959 to 1960.</p><p>His third move had a bit more staying power. He was GM of the Cincinnati Reds from 1960 to 1966. He became sole owner and led them to pennant victory in 1961, built up a productive farm system, and maintained the team’s status as a serious contender throughout his tenure.</p><p>DeWitt sold the Reds in 1966. Regardless, DeWitt was still credited for drafting, developing and trading for the players who’d become the league-dominating “Big Red Machine”
158 of the 1970s.</p><p>For his final run, he sat as chairman of the Chicago White Sox from 1975-1981, working once again with the unforgettable Bill Veeck.</p><p>Baseball is a continued tradition in the DeWitt family. His son, William DeWitt, Jr., is the principal owner and managing partner of the St. Louis Cardinals. His grandson, William DeWitt, III, is the Cardinals’ president.</p>" 159 } 160 } 161 }, 162 163 { 164 key: "the-war-years", 165 title: "The War Years", 166 overviewImage: "the-war-years-index.jpg", 167 hero: { 168 image: "bg-the-war-years.jpg", 169 coverImage: "cover-the-war-years.png" 170 }, 171 dates: { 172 from: 1942, 173 to: 1946 174 } 175 }, 176 177 { 178 key: "the-bill-veeck-era", 179 title: "The Bill Veeck Era", 180 overviewImage: "the-bill-veeck-era-index.jpg", 181 hero: { 182 image: "bg-the-veeck-era.jpg", 183 coverImage: "cover-the-veeck-era.png" 184 }, 185 dates: { 186 from: 1949, 187 to: 1953 188 }, 189 overlayData: { 190 "veeck": { 191 title: "Bill Veeck (1914 – 1986)", 192 body: "<p>After the St. Louis Browns, Bill Veeck licked his wounds, and returned to baseball again. When the White Sox won their first pennant in 40 years (1959), Bill Veeck was pulling the strings behind the scenes.</p><p>He had to sell his share of the White Sox in 1961 due to poor health, and briefly held down a commentating gig before disappearing from baseball for 14 years. In 1975, Veeck bought the White Sox and became the club’s sole proprietor. He was back in the game, and back to his old clever ways.</p><p>He famously had Harry Caray sing “Take Me Out to the Ball Game” during the 7th-inning stretch. He offered fans free admission after the White Sox were defeated 10-2 on Opening Day in 1979. He held Disco Demolition Night, which ended in a riot at Comiskey Park and a forfeit to the Tigers.</p><p>When the free agent era arrived, Veeck couldn’t keep up financially, so he sold the White Sox in early 1981. But he didn’t exit the game entirely. Fans spotted him frequently at Wrigley Field, cheering on the Cubs, as he’d done in his childhood.</p><p>Veeck was inducted to the Hall of Fame in 1991, five years after his death. He earned this recognition not solely for his wild promotions, but for the lasting and positive impact his approach had on the game. If it weren’t for Veeck, baseball might not be the game we know and love today.</p>" 193 } 194 } 195 } 196 ] 197 }, 198 199 players: { 200 201 title: "Players", 202 203 players: [ 204 205 { 206 key: "clint-courtney", 207 firstName: "Clint", 208 lastName: "Courtney", 209 url: "http://www.baseball-reference.com/players/c/courtcl01.shtml", 210 bio: "<p>Listed at 5’ 8” and 180 pounds, Courtney was an American League catcher whose pugnacity and timely base hits made headlines in the 1950s. Fiercely combative, he played his position under unusual handicaps. A natural left-hander, he taught himself to use his right arm, and he also was myopic, being widely considered as the first Major League catcher to wear eyeglasses. On July 16, 1953, Courtney entered the record books when the Browns tied, by then, a Major League mark with three successive home runs during the first inning of an 8â6 victory over the Yankees</p>", 211 details: { 212 position: "C", 213 bats: "Left", 214 arm: "Right", 215 height: { 216 feet: 5, 217 inches: 8 218 }, 219 weight: 180, 220 city: "Hall Summit, LA", 221 born: { 222 year: 1927, 223 month: 5, 224 day: 16 225 } 226 } 227 }, 228 229 { 230 key: "les-moss", 231 firstName: "Les", 232 lastName: "Moss", 233 url: "http://www.baseball-reference.com/players/m/mossle01.shtml", 234 bio: "<p>Les Moss platooned alongside left-handed-hitting catcher Jake Early, producing a .157 batting average in 96 games during the 1947 season. He caught the majority of the games for the Browns in 1948 while his hitting improved substantially, with a .257 average along with 14 home runs and 46 runs batted in. In 1949, the Browns acquired 24-year-old Sherm Lollar from the New York Yankees and, Moss became the second string catcher. Moss’ hitting continued to improve with a .291 average and an impressive .399 on-base percentage.</p>", 235 details: { 236 position: "C", 237 bats: "Right", 238 arm: "Right", 239 height: { 240 feet: 5, 241 inches: 11 242 }, 243 weight: 205, 244 city: "Tulsa, OK", 245 born: { 246 year: 1925, 247 month: 5, 248 day: 14 249 } 250 } 251 }, 252 253 { 254 key: "heinie-manush", 255 firstName: "Heinie", 256 lastName: "Manush", 257 url: "http://www.baseball-reference.com/players/m/manushe01.shtml", 258 bio: "<p>Henry Emmett Manush, nicknamed “Heinie,” was an American baseball outfielder. On December 13, 1927, the Tigers traded Manush and first baseman Lu Blue to the St. Louis Browns in exchange for outfielder Harry Rice, pitcher Elam Vangilder, and a player to be named later. The trade was promptly criticized as being one-sided in favor of St. Louis, and proved as much when Manush had an outstanding 1928 season for the Browns. Manu
258sh appeared in all 154 games as the Browns' starting left fielder in 1928 and compiled a .378 batting average, narrowly missing a second batting title to Goose Goslin who hit .379, one point higher than Manush.</p><p>The battle for the batting title was the closest in 18 years, and Manush, who appeared in 19 more games than Goslin, led the league with 241 hits, 68 more than Goslin. Manush also led the American League in 1928 with 241 hits and 47 doubles and finished among the league leaders with 367 total bases (second behind Babe Ruth), 20 triples (second), a 6.8 offensive wins above replacement rating (third behind Ruth and Lou Gehrig), 80 extra base hits (third behind Ruth and Gehrig), a .575 slugging percentage (fourth), and 108 RBIs (fourth). He helped the Browns improve by 23 wins from a 59-94 record in 1927 to an 82-72 record in 1928. He also finished second behind Mickey Cochrane in close voting for the 1928 American League Most Valuable Player award, with Cochrane garnering 53 vote points to 51 for Manush.</p>", 259 details: { 260 position: "LF", 261 bats: "Left", 262 arm: "Left", 263 height: { 264 feet: 6, 265 inches: 1 266 }, 267 weight: 200, 268 city: "Tuscumbia, AL", 269 born: { 270 year: 1901, 271 month: 7, 272 day: 20 273 } 274 } 275 }, 276 277 { 278 key: "goose-goslin", 279 firstName: "Goose", 280 lastName: "Goslin", 281 url: "http://www.baseball-reference.com/players/g/gosligo01.shtml", 282 bio: "<p>Leon Allen “Goose” Goslin was a left fielder in Major League Baseball known for his powerful left-handed swing and dependable clutch hitting. He played 18 seasons with the St. Louis Browns. He was inducted into the Baseball Hall of Fame in 1968. The 1928 batting title was not decided until the last day of the season.</p><p>Goslin and Heinie Manush of the St. Louis Browns were tied going into the final game, and the Senators and Browns played each other in the final game. Goslin was leading Manush when his turn came to bat in the ninth inning. If Goslin made an out, he would lose the batting crown. In 101 games for the Browns, Goslin had 30 home runs, 100 RBI, and 62 extra base hits. Goslin had another solid year for the Browns in 1931, batting .328 with a career-high 42 doubles, 76 extra base hits and 105 RBI.</p>", 283 hallOfFame: true, 284 details: { 285 position: "LF", 286 bats: "Left", 287 arm: "Right", 288 height: { 289 feet: 5, 290 inches: 11 291 }, 292 weight: 185, 293 city: "Salem, NJ", 294 born: { 295 year: 1900, 296 month: 10, 297 day: 16 298 } 299 } 300 }, 301 302 { 303 key: "eddie-plank", 304 firstName: "Eddie", 305 lastName: "Plank", 306 url: "http://www.baseball-reference.com/players/p/planked01.shtml", 307 bio: "<p>Edward Stewart Plank, nicknamed “Gettysburg Eddie,” was an American professional baseball player. A pitcher, Plank played in Major League Baseball for the St. Louis Browns in 1916 and 1917. When the Federal League folded, Plank applied for free agency but was declared to belong to the St. Louis Browns for 1916. In September of that year, Plank predicted that he might be able to pitch ten more seasons, saying, “I don’t know whether it is that I have more on the ball this season than I had in other years, but at any rate I feel that I have just as much stuff as I ever did.”</p>", 308 hallOfFame: true, 309 details: { 310 position: "P", 311 bats: "Left", 312 arm: "Left", 313 height: { 314 feet: 5, 315 inches: 11 316 }, 317 weight: 175, 318 city: "Gettysburg, PA", 319 born: { 320 year: 1875, 321 month: 8, 322 day: 31 323 } 324 } 325 }, 326 327 { 328 key: "george-stone", 329 firstName: "George", 330 lastName: "Stone", 331 url: "http://www.baseball-reference.com/players/s/stonege01.shtml", 332 bio: "<p>Nicknamed Silent George, he was a left fielder in Major League Baseball who played for the St. Louis Browns from 1905â1910. Stone batted and threw left-handed. He was the 1906 American League batting champion. In a seven-season career, Stone posted a .301 batting average with 23 home runs and 268 RBI in 848 games played.</p>", 333 details: { 334 position: "LF", 335 bats: "Left", 336 arm: "Left", 337 height: { 338 feet: 5, 339 inches: 9 340 }, 341 weight: 175, 342 city: "Lost Nation, IA", 343 born: { 344 year: 1876, 345 month: 9, 346 day: 3 347 } 348 } 349 }, 350 351 { 352 key: "wayne-bromley-wright", 353 firstName: "Wayne Bromley “Rasty”", 354 lastName: "Wright", 355 url: "http://www.baseball-reference.com/players/w/wrighra02.shtml", 356 bio: "<p>Wayne Bromley “Rasty” Wright was a professional baseball pitcher. He played all or part of five seasons in Major League Baseball for the St. Louis Browns between 1917 and 1923.</p>", 357 details: { 358 position: "P", 359 bats: "Right", 360 arm: "Right", 361 height: { 362 feet: 5, 363 inches: 11 364 }, 365 weight: 160, 366 city: "Ceredo, WV", 367 born: { 368 year: 1895, 369 month: 11, 370 day: 5 371 } 372 } 373 }, 374 375 { 376 key: "rube-waddell", 377 firstName: "Rube", 378 lastName: "Waddell", 379 url: "http://www.baseball-reference.com/players/w/wadderu01.shtml", 380 bio: "<p>George Edward “Rube” Waddell was an American southpaw pitcher in Major League Baseball (MLB). In a career spanning 13 years, he played for the St. Louis Browns (1908â10) in the American League. Born in Bradford, Pennsylvania, Waddell was elected to the Baseball Hall of Fame in 1946. Born in 1876 outside of Bradford, Pennsylvania, Waddell grew up in the country. Biographer Alan Levy writes that Waddell was “a decidedly different sort of child.” At the age of three, he wandered over to a local fire station and stayed for several days.
380</p><p>Waddell did not attend school very often, but he was considered to be literate. He strengthened his arm as a child by throwing rocks at birds he encountered while plowing the family's land. He also worked on mining and drilling sites as a youngster, which helped his conditioning. Waddell was a remarkably dominant strikeout pitcher in an era when batters mostly slapped at the ball to get singles. He had an excellent fastball, a sharp-breaking curve, a screwball, and superb control (his strikeout-to-walk ratio was almost 3-to-1). He led the major leagues in strikeouts for six consecutive years. </p>", 381 hallOfFame: true, 382 details: { 383 position: "P", 384 bats: "Right", 385 arm: "Left", 386 height: { 387 feet: 6, 388 inches: 1 389 }, 390 weight: 196, 391 city: "Bradford, PA", 392 born: { 393 year: 1876, 394 month: 10, 395 day: 13 396 } 397 } 398 }, 399 400 { 401 key: "rollie-stiles", 402 firstName: "Rollie", 403 lastName: "Stiles", 404 url: "http://www.baseball-reference.com/players/s/stilero01.shtml", 405 bio: "<p>Rolland Mays Stiles was an American right-handed pitcher in Major League Baseball who played for the St. Louis Browns from 1930 to 1933. Born in Ratcliff, Arkansas, he batted and threw right-handed, and was 9â14 with an earned run average of 5.92 in his three seasons. Rollie attended Southeastern State Teachers College. His first game in the major leagues was on June 19, 1930, and his last game was October 1, 1933. Stiles’ nicknames when playing baseball were “Leapin’ Lena,” “Lena,” and “Rollie,” all typical of how he signed autographs for baseball fans. He died in his sleep at age 100 on July 22, 2007 at the Bethesda Southgate Nursing Home in St. Louis. He was the last living person to have pitched to Babe Ruth.</p>", 406 details: { 407 position: "P", 408 bats: "Right", 409 arm: "Right", 410 height: { 411 feet: 6, 412 inches: 1 413 }, 414 weight: 180, 415 city: "Ratcliff, AR", 416 born: { 417 year: 1906, 418 month: 11, 419 day: 17 420 } 421 } 422 }, 423 424 { 425 key: "dale-long", 426 firstName: "Dale", 427 lastName: "Long", 428 url: "http://www.baseball-reference.com/players/l/longda02.shtml", 429 bio: "<p>A native of Springfield, Missouri, Long turned down an offer from the Green Bay Packers to play football, opting instead to play baseball. Long spent six seasons in the minor leagues, playing for five different organizations before he debuted with the Pittsburgh Pirates in 1951, ending that season with the St. Louis Browns. </p>", 430 details: { 431 position: "1B", 432 bats: "Left", 433 arm: "Left", 434 height: { 435 feet: 6, 436 inches: 4 437 }, 438 weight: 205, 439 city: "Springfield, MO", 440 born: { 441 year: 1926, 442 month: 2, 443 day: 6 444 } 445 } 446 }, 447 448 { 449 key: "bob-dillinger", 450 firstName: "Bob", 451 lastName: "Dillinger", 452 url: "http://www.baseball-reference.com/players/d/dillibo01.shtml", 453 bio: "<p>Born in Glendale, California, Dillinger attended the University of Idaho in Moscow and played football for the Vandals, but broke his collarbone as a freshman in 1936 and was injured again as a sophomore; he left the school in the spring of 1938. He was signed by the Browns as an amateur free agent in 1939.</p>", 454 details: { 455 position: "3B", 456 bats: "Right", 457 arm: "Right", 458 height: { 459 feet: 5, 460 inches: 11 461 }, 462 weight: 170, 463 city: "Glendale, CA", 464 born: { 465 year: 1918, 466 month: 9, 467 day: 17 468 } 469 } 470 }, 471 472 { 473 key: "rick-ferrell", 474 firstName: "Rick", 475 lastName: "Ferrell", 476 url: "http://www.baseball-reference.com/players/f/ferreri01.shtml", 477 bio: "<p>Rick Ferrell cut his teeth as catcher at home â his six brothers all wanted to be pitchers. It paid off. With a knack for catching knuckleballs and picking off stolen base attempts, this 8-time All-Star* became known as one of the best catchers in the game during the ‘30s and ‘40s. His skills at the plate weren’t just limited to catching. Among catchers with 3,000 at-bats, Ferrell’s .378 career on-base percentage is 8th all-time, and 4th among the 13 major league Hall of Fame catchers. Ferrell played for the Browns twice during his peak: from 1929-1933, and from 1941-1943.</p><p>As for his brothers? Only one of them, Wes, made it to the majors. When asked how it was to play against his brother, Rick said, “We were brothers off the field, but there was no love lost on it. We fought like cats and dogs. Wes was always trying to strike me out, and meantime, I was always trying to hit a home run off him.”</p><p>*His eighth appearance never actually happened. The 1945 All-Star Game was cancelled due to wartime travel restrictions.</p>", 478 hallOfFame: true, 479 details: { 480 position: "C", 481 bats: "Right", 482 arm: "Right", 483 height: { 484 feet: 5, 485 inches: 10 486 }, 487 weight: 160, 488 city: "Durham, NC", 489 born: { 490 year: 1905, 491 month: 10, 492 day: 12 493 } 494 } 495 }, 496 497 { 498 key: "bobby-wallace", 499 firstName: "Bobby", 500 lastName: "Wallace", 501 url: "http://www.baseball-reference.com/players/w/wallabo01.shtml", 502 bio: "<p>Bobby Wallace holds the record for longest career by a player who never reached the World Series. But that’s not the only reason he’s noteworthy. He was a top-10 RBI leader for eight seasons in the peak of his career. He also holds the American League record for most chances accepted in one game: 17 (against the Boston Red Sox on June 10, 1902).</p><p>What he lacked in height, he made up in his mental fortitude. Wallace reflected, “As more speed afoot was constantly demanded for big league ball, I noticed the many infield bounders which the runner beat to first only by the thinnest fractions of a second. I also noted that the old-time three-phase movement â fielding a ball, coming erect for a toss and throwing to first â wouldn't do on certain hits with fast men… It was plain that the stop and toss had to be combined into a continuous movement.”</p><p>In 1911, Pittsburgh Pirates owner Barney Dreyfuss declared, “The best player in the American League, the only man I would get if I could, plays on a tail-end team, and few people pay any attention to him. I mean Bobby Wallace of St. Louis. I wish I had him.” Indeed, this Hall of Famer might be the greatest defensive shortstop of his generation.</p>", 503 hallOfFame: true, 504 cardinalsPlayer: true, 505 details: { 506 position: "SS, 3B", 507 bats: "Right", 508 arm: "Right", 509 height: { 510 feet: 5, 511 inches: 8 512 }, 513 weight: 170, 514 city: "Pittsburgh, PA", 515 born: { 516 year: 1873, 517 month: 11, 518 day: 4 519 } 520 } 521 }, 522 523 { 524 key: "dizzy-dean", 525 firstName: "Dizzy", 526 lastName: "Dean",
527 url: "http://www.baseball-reference.com/players/d/deandi01.shtml", 528 bio: "<p>From 1932 to 1937, Dizzy Dean was arguably the best pitcher in all of baseball. But in the 1937 All-Star game, a line drive back to the mound fractured Dizzy’s toe, or as he would say “Fractured, hell, the damn thing's broken!” Dizzy was never the same man on the mound â a change in mechanics to deal with the toe injury led to an arm injury.</p><p>Thankfully, when it came to his colorful use of the English language, he hadn’t changed a bit, as he quickly transitioned to a career in broadcasting. His wit and perfectly placed malapropisms earned him a large following as the radio voice for the Browns. Oddly, this led him to one more appearance on the mound. The pitching was so bad during the Browns’ lowly 1947 season, Dizzy would often remark in his broadcasts that he could do better. Six years removed from throwing in a game, Dizzy left his booth to be the Browns’ starting pitcher for the last game of the year. He pitched four shutout innings, and even got a hit, before leaving the game with a pulled muscle â the final injury of his playing career.</p>", 529 hallOfFame: true, 530 cardinalsPlayer: true, 531 details: { 532 position: "P", 533 bats: "Right", 534 arm: "Right", 535 height: { 536 feet: 6, 537 inches: 2 538 }, 539 weight: 182, 540 city: "Lucas, AR", 541 born: { 542 year: 1910, 543 month: 1, 544 day: 16 545 } 546 } 547 }, 548 549 { 550 key: "george-sisler", 551 firstName: "George", 552 lastName: "Sisler", 553 url: "http://www.baseball-reference.com/players/s/sislege01.shtml", 554 bio: "<p>Who is George Sisler? Unquestionably, the greatest player in St. Louis Browns’ history. Once considered an equal to the likes of Ruth, Cobb and Hornsby, “The Sizzler” won the AL batting title twice (hitting over .400 both times), led the AL in stolen bases four times, and held the single-season hit record (257) for 84 years. He is also regarded as one of the best defensive first basemen to play the game.</p><p>Today, he’s quite possibly the best player most baseball fans have never heard of. But greatness has a way of being rediscovered. Born 6,000 miles away and 80 years later, Ichiro Suzuki broke Sisler’
554s single-season hit record in 2004. He later laid flowers on Sisler’s grave to honor him. With the symbolic tip of his cap, Suzuki reawakened fans to one of baseball’s greatest, nearly forgotten treasures.</p>", 555 hallOfFame: true, 556 details: { 557 position: "1B", 558 bats: "Left", 559 arm: "Left", 560 height: { 561 feet: 5, 562 inches: 11 563 }, 564 weight: 180, 565 city: "Manchester, OH", 566 born: { 567 year: 1893, 568 month: 3, 569 day: 24 570 } 571 } 572 }, 573 574 { 575 key: "ken-williams", 576 firstName: "Ken", 577 lastName: "Williams", 578 url: "http://www.baseball-reference.com/players/w/willike01.shtml", 579 bio: "<p>First player to poke two home runs in one inning. First to hit 30 out of the park and steal 30 bases in the same season. A six-game streak with a tater in each. League leader in homers and ribbies. Ken Williams didn’t compile these stats over the course of a long career â it all happened in 1922. Despite the offensive prowess, Williams and the ‘22 Browns (the organization’s best club) still fell a game and a half short of the AL pennant.</p>", 580 details: { 581 position: "LF", 582 bats: "Left", 583 arm: "Right", 584 height: { 585 feet: 6, 586 inches: 0 587 }, 588 weight: 170, 589 city: "Grants Pass, OR", 590 born: { 591 year: 1890, 592 month: 6, 593 day: 28 594 } 595 } 596 }, 597 598 { 599 key: "baby-doll-jacobson", 600 firstName: "Baby Doll", 601 lastName: "Jacobson", 602 url: "http://www.baseball-reference.com/players/j/jacobba01.shtml", 603 bio: "<p>Baby Doll Jacobson rivaled The Babe in stats and stature. Batting better than .300 for 7 consecutive seasons (1919-1925), he was no small threat to his opponents.</p><p>So, why the nickname? At a game in 1912, the band was playing “Oh, You Beautiful Doll” as Jacobson walked up to the plate. First pitch, he smoked the ball halfway to China. A lady shouted from stands, “You must be that beautiful doll they were talking about.” The rest is history.</p><p>After the Browns: “Although he never received more than a passing glance in the Hall of Fame voting, Jacobson's credentials are superior to many of the old-timers who have been enshrined.” — written in The Sporting News following Jacobson’s death in 1977. Traded to the Boston Red Sox in 1926, Jacobson’s .981 fielding percentage that season was second among AL center fielders. After short stints with the Indians, the Athletics and a few minor league teams, Jacobson left baseball and spent the remainder of his years on his Illinois farm, not too far from where he grew up.</p>", 604 details: { 605 position: "CF", 606 bats: "Right", 607 arm: "Right", 608 height: { 609 feet: 6, 610 inches: 3 611 }, 612 weight: 215, 613 city: "Cable, IL", 614 born: { 615 year: 1890, 616 month: 8, 617 day: 16 618 } 619 } 620 }, 621 622 { 623 key: "jack-tobin", 624 firstName: "Jack", 625 lastName: "Tobin", 626 url: "http://www.baseball-reference.com/players/t/tobinja01.shtml", 627 bio: "<p>To his friends and the newspapers in St. Louis, he was Johnny. But in the record books, he was Jack. To teammate and legend-in-the-making George Sisler, he was “one of the best leadoff men I ever saw… He was fast and a good outfielder with a strong throwing arm and, above all, he was the best drag-bunter anyone ever saw.”</p><p>Tobin didn’t see much playing time in his first year with the Browns (1916). However, he did face his former team, the Federal League’s St. Louis Terriers, in a so-called City Series. They lost, but Tobin and the Browns swept the Cardinals in the City Series two years later.</p><p>After a productive trip to the Pacific Coast League, Tobin was back on the Browns by 1918. His best run was from 1919 to 1923. Tobin batted well over .300 every year, topping out at .352, and roping 13 homers two seasons in a row. He led the league in 1921 with 18 triples, and was second in runs scored with 132. When he dipped a point below .300 in 1924, legend has it that he had his teeth removed.</p><p>
627In 1925, Tobin was out-hit by rightfielder Harry Rice, and lost his starting privileges. He was traded to the Washington Senators before the start of the 1926 season.</p>", 628 details: { 629 position: "RF", 630 bats: "Left", 631 arm: "Left", 632 height: { 633 feet: 5, 634 inches: 8 635 }, 636 weight: 142, 637 city: "St. Louis, MO", 638 born: { 639 year: 1892, 640 month: 5, 641 day: 4 642 } 643 } 644 }, 645 646 { 647 key: "pete-gray", 648 firstName: "Pete", 649 lastName: "Gray", 650 url: "http://www.baseball-reference.com/players/g/graype01.shtml", 651 bio: "<p>Before there was Jim Abbott, there was Pete Gray. At age six, Gray lost his right arm in a farming accident. But he never lost his determination to play ball. The natural righty learned to bat and throw left-handed to pursue his dream. After an MVP season in the minors, he was called up to play for the Browns in 1945. It was his only year in the majors; like so many two-handed players before him, Gray couldn't hit the off-speed pitch. Gray, more than anyone, knew his opportunity to play came about from depleted wartime rosters. While he himself couldn’t serve, he honored veterans by visiting them at the hospital, becoming an inspiration for thousands of disabled servicemen returning from the war.</p>", 652 details: { 653 position: "OF", 654 bats: "Left", 655 arm: "Left", 656 height: { 657 feet: 6, 658 inches: 1 659 }, 660 weight: 169, 661 city: "Nanticoke, PA", 662 born: { 663 year: 1915, 664 month: 3, 665 day: 6 666 } 667 } 668 }, 669 670 { 671 key: "eddie-gaedel", 672 firstName: "Eddie", 673 lastName: "Gaedel", 674 url: "http://www.baseball-reference.com/players/g/gaedeed01.shtml", 675 bio: "<p>Normally, one plate appearance wouldn’t leave a mark on the history of baseball. But normally, Eddie Gaedel wasn’t up to bat. On August 19, 1951, as part of a trademark Bill Veeck promotional stunt, the 3-foot-7 Gaedel came to the plate to pinch hit. He wore the number â on a jersey made for Bill DeWitt’s son. Four balls later, Gaedel achieved a career on-base percentage of 1.000. Even though his contract was voided by the league two days later, Gaedel’s jersey still has a spot in the National Baseball Hall of Fame.</p><p>“He was, by golly, the best damn midget who ever played big-league ball. He was also the only one.” - Bill Veeck</p>", 676 details: { 677 position: "PH", 678 bats: "Right", 679 arm: "Left", 680 height: { 681 feet: 3, 682 inches: 7 683 }, 684 weight: 65, 685 city: "Chicago, IL", 686 born: { 687 year: 1925, 688 month: 6, 689 day: 8 690 } 691 } 692 }, 693 694 { 695 key: "ned-garver", 696 firstName: "Ned", 697 lastName: "Garver", 698 url: "http://www.baseball-reference.com/players/g/garvene01.shtml", 699 bio: "<p>In 1951, while the Browns lost 102 games, Ned Garver racked up 20 wins â the only pitcher in the majors to do so well for such a losing team, even to this day. He also led the American League in complete games (24) and was the starting pitcher for the All-Star game in Detroit. That same year, he earned (and clearly deserved) the highest salary on the team: a whopping $25,000.</p><p>Despite his triumphs on the mound, he never pitched in a World Series. Garver thought, “If you played in a World Series, people get the impression that you were somewhat more of an outstanding player than if you never did. You're put in a kind of special category if you were on a pennant winning team.”</p><p>Still, that didn’t stop him from becoming a legend. Ted Williams, one of baseball’s greatest hitters, said of Ned, “He could throw anything up there and get me out.”</p>", 700 details: { 701 position: "P", 702 bats: "Right", 703 arm: "Right", 704 height: { 705 feet: 5, 706 inches: 10 707 }, 708 weight: 180, 709 city: "Ney, OH", 710 born: { 711 year: 1925, 712 month: 12, 713 day: 25 714 } 715 } 716 }, 717 718 { 719 key: "satchel-paige", 720 firstName: "Satchel", 721 lastName: "Paige", 722 url: "http://www.baseball-reference.com/players/p/paigesa01.shtml", 723 bio: "<p>As the Cleveland Indians owner, Bill Veeck signed Satchel to his first major league contract in 1948, when Satchel was 42, making him the oldest rookie ever in the major leagues. After Veeck bought into the Browns in 1951, he signed Paige once again. In 1952, Paige had proved himself to be such an asset, he either started or came in for relief every three games. That same year, Paige represented the Browns in the All-Star Game, but didn’t see any playing time, so Casey Stengel nominated him again for the 1953 team.</p><p>The selling of the Browns to Baltimore was the last of Paige’s major league career, until he returned with the Kansas City Athletics in 1965. (He went back to the Negro Leagues in between.) Although his major league career was only 6 seasons, his name will be remembered forever.</p><p>“If Satch and I were pitching on the same team, we’d clinch the pennant by the fourth of July and go fishing until World Series time.” —
723 Dizzy Dean</p>", 724 hallOfFame: true, 725 details: { 726 position: "P", 727 bats: "Right", 728 arm: "Right", 729 height: { 730 feet: 6, 731 inches: 3 732 }, 733 weight: 180, 734 city: "Mobile, AL", 735 born: { 736 year: 1906, 737 month: 7, 738 day: 7 739 } 740 } 741 }, 742 743 { 744 key: "vern-stephens", 745 firstName: "Vern", 746 lastName: "Stephens", 747 url: "http://www.baseball-reference.com/players/s/stephve01.shtml", 748 bio: "<p>With peers like Phil Rizzuto, Marty Marion, Pee Wee Reese and Johnny Pesky, Vern Stephens was part of a special crop of shortstops from the 1940s. While the legends of his peers have grown, the memory of Vern “Junior” Stephens has largely faded over time. It’s a shame, because he just might have been the best of that bunch.</p><p>Growing up, Stephens was a slight kid, weighing in at just 100 lbs. But he built himself up, and soon became known for his power at the plate. An 8-time All-Star, 3-time RBI champ, and perennial MVP candidate, Stephens had an arm like a shotgun, and a trick knee that kept him from being drafted. History may have nearly forgotten him, but his stat lines will forever tell the story of one of the greatest power-hitting shortstops in baseball.</p>", 749 details: { 750 position: "SS, 3B", 751 bats: "Right", 752 arm: "Right", 753 height: { 754 feet: 5, 755 inches: 10 756 }, 757 weight: 185, 758 city: "McAllister, NM", 759 born: { 760 year: 1920, 761 month: 23, 762 day: 10 763 } 764 } 765 }, 766 767 { 768 key: "len-schulte", 769 firstName: "Len", 770 lastName: "Schulte", 771 url: "http://www.baseball-reference.com/players/s/schulle01.shtml", 772 bio: "<p>Len Schulte’s big league debut was soggy. In his only appearance for the 1944 Browns, Schulte drew a walk in a rainy late September 4-1 loss to the Boston Red Sox. He saw less rain and more playing time the next season, appearing in 110 games at third-base.</p>", 773 details: { 774 position: "3B, 2B, SS", 775 bats: "Right", 776 arm: "Right", 777 height: { 778 feet: 5, 779 inches: 10 780 }, 781 weight: 160, 782 city: "St. Charles, MO", 783 born: { 784 year: 1916, 785 month: 12, 786 day: 5 787 } 788 } 789 }, 790 791 { 792 key: "george-caster", 793 firstName: "George", 794 lastName: "Caster", 795 url: "http://www.baseball-reference.com/players/c/castege01.shtml", 796 bio: "<p>After joining the Browns as a starting pitcher in 1941, George “Ug” Caster found his calling as a closer. “I like to be in there when the going is tough, trying to save a game,” Caster said. And save games he did â Caster led the American League in saves as he helped the Browns take the pennant in 1944.</p>", 797 details: { 798 position: "P", 799 bats: "Right", 800 arm: "Right", 801 height: { 802 feet: 6, 803 inches: 1 804 }, 805 weight: 180, 806 city: "Colton, CA", 807 born: { 808 year: 1907, 809 month: 8, 810 day: 4 811 } 812 } 813 }, 814 815 { 816 key: "frank-demaree", 817 firstName: "Frank", 818 lastName: "Demaree", 819 url: "http://www.baseball-reference.com/players/d/demarfr02.shtml", 820 bio: "<p>A veteran outfielder, Frank Demaree joined the Browns just before the start of the 1944 season. He played in 16 games before being released, going 0-for-3 in what would be his final major league appearance. Had he made it to the postseason, he would have been on the losing side of five different World Series throughout his career.</p>", 821 details: { 822 position: "OF", 823 bats: "Right", 824 arm: "Right", 825 cardinalsPlayer: true, 826 height: { 827 feet: 5, 828 inches: 11 829 }, 830 weight: 185, 831 city: "Winters, CA", 832 born: { 833 year: 1910, 834 month: 6, 835 day: 10 836 } 837 } 838 }, 839 840 { 841 key: "denny-galehouse", 842 firstName: "Denny", 843 lastName: "Galehouse", 844 url: "http://www.baseball-reference.com/players/g/galehde01.shtml", 845 bio: "<p>After two seasons with the Browns (1942-1943), Denny Galehouse left the team to help the war effort, working 6 days a week at a plant in Akron, Ohio. Midway through the ‘44 season, the Browns persuaded Galehouse to be their “Sunday pitcher.” After his Saturday shift, he’d take an overnight train to St. Louis, pitch the first game of the Sunday double-header, then go back to Akron. It soon became clear that the Browns were on their way to first place in the American League. Galehouse came back to the Browns full-time, helping them win the pennant and Game 1 of the World Series.</p><p>“The World Series Cardinals had Stan Musial, Whitey Kurowski, Marty Marion, Walker Cooper, Mort Cooper… they had pretty much a big league team,” Galehouse recalled. (Most major league teams, like the Browns, were made up of 4-F guys who weren’t able to fight in the war.) “They weren’t an easy squad,” he said. But that didn’t stop him from getting the win.</p>", 846 details: { 847 position: "P", 848 bats: "Right", 849 arm: "Right", 850 height: { 851 feet: 6, 852 inches: 1 853 }, 854 weight: 195, 855 city: "Marshallville, OH", 856 born: { 857 year: 1911, 858 month: 12, 859 day: 7 860 } 861 } 862 }, 863 864 { 865 key: "hal-epps", 866 firstName: "Hal", 867 lastName: "Epps", 868 url: "http://www.baseball-reference.com/players/e/eppsha01.shtml", 869 bio: "<p>Hal Epps, known to some as “The Reindeer,” was one of just a handful of players to claim allegiance to both St. Louis teams. After a few years in the minors, 28 games with the Cardinals (in 1938 and 1940), and a tour in the South Pacific, Epps joined the Browns in 1943. Known for his speedy wheels and his dedication to making tough plays, Epps contributed greatly to the 9-game winning streak that helped the Browns win the 1944 AL pennant.</p>", 870 cardinalsPlayer: true, 871 details: { 872 position: "CF", 873 bats: "Left", 874 arm: "Left", 875 height: { 876 feet: 6, 877 inches: 0 878 }, 879 weight: 175, 880 city: "Athens, GA", 881 born: { 882 year: 1914, 883 month: 3, 884 day: 26 885 } 886 } 887 }, 888 889 { 890 key: "al-hollingsworth", 891 firstName: "Al", 892 lastName: "Hollingsworth", 893 url: "http://www.baseball-reference.com/players/h/hollial01.shtml", 894 bio: "<p>He was the pitcher they called “Boots.” 4 was not his lucky number â he came into Game 4 of the 1944 World Series in the 4th inning, 4 runs back, and never had the opportunity for a save. However, the following year, Boots brought home his second winning record of his Browns career and an ERA under 3.00.</p><p>After the Browns: Hollingsworth played his last game on September 22, 1946, as a member of the White Sox club, ending his professional playing career of 20 consecutive seasons (including time in the minors). He then became a manager for the St. Louis Cardinals and Cleveland Indians, a pitching coach for the Redbirds, and a scout for 4 major league teams.</p>", 895 details: { 896 position: "P", 897 bats: "Left", 898 arm: "Left", 899 height: { 900 feet: 6, 901 inches: 0 902 }, 903 weight: 174, 904 city: "Cincinatti, OH", 905 born: { 906 year: 1908, 907 month: 2, 908 day: 25 909 } 910 } 911 }, 912 913 { 914 key: "willis-hudlin", 915 firstName: "Willis", 916 lastName: "Hudlin", 917 url: "http://www.baseball-reference.com/players/h/hudliwi01.shtml", 918 bio: "<p>Nicknamed “Ace,” Willis Hudlin was known for his sinker. It must have been a good one, because four teams wanted it… in one season. In 1940, Ace played for four different clubs, a distinction he shares with only a handful of other MLB players. There’s one achievement that’s all his own, giving up Babe Ruth’s 500th home run. Don’t feel too bad for Ace, though, he won the game 6-5.</p>", 919 details: { 920 position: "P", 921 bats: "Right", 922 arm: "Right", 923 height: { 924 feet: 6, 925 inches: 0 926 }, 927 weight: 190, 928 city: "Wagoner, OK", 929 born: { 930 year: 1906, 931 month: 5, 932 day: 23 933 } 934 } 935 }, 936 937 { 938 key: "tom-hafey", 939 firstName: "Tom", 940 lastName: "Hafey", 941 url: "http://www.baseball-reference.com/players/h/hafeyto01.shtml", 942 bio: "<p>Tom “Heave-O” Hafey was born into a baseball family â his brother Bud and cousin Chick also played in the majors. While he had a rocket of an arm, his brief career skipped around a bit. After a season with the Giants in 1939, Hafey joined the Browns for 8 games in 1944. He played a game at first base, a game at third base, three games in left field, pinch hit four times, then said goodbye to baseball.</p>", 943 details: { 944 position: "3B, LF", 945 bats: "Right", 946 arm: "Right", 947 height: { 948 feet: 6, 949 inches: 1 950 }, 951 weight: 180, 952 city: "Berkeley, CA", 953 born: { 954 year: 1913, 955 month: 7, 956 day: 12 957 } 958 } 959 }, 960 961 { 962 key: "mike-kreevich", 963 firstName: "Mike", 964 lastName: "Kreevich", 965 url: "http://www.baseball-reference.com/players/k/kreevmi01.shtml", 966 bio: "<p>By the time he reached the Browns in 1943, 35-year-old Mike Kreevich had seen a lot: coal mines, the Great Depression, and both Chicago baseball teams. But in 1944, he saw something really special: a World Series. Sure, he struck out five times. But he still managed three doubles and a .231 average for the Series.</p>", 967 details: { 968 position: "CF", 969 bats: "Right", 970 arm: "Right", 971 height: { 972 feet: 5, 973 inches: 7 974 }, 975 weight: 168, 976 city: "Mount Olive, IL", 977 born: { 978 year: 1908, 979 month: 10, 980 day: 6 981 } 982 } 983 }, 984 985 { 986 key: "sig-jackuki", 987 firstName: "Sig", 988 lastName: "Jackuki", 989 url: "http://www.baseball-reference.com/players/j/jakucsi01.shtml", 990 bio: "<p>On the field and off, Big Sig Jakucki’s story is as much of a roller coaster as the entirety of the Browns’ legacy. Ellis Clary recalls, “He’s a tough son of a bitch… but you couldn’t help but like him if he was on your side. He was a fun guy, but gee, at night he’d get a few belts and turn over a joint somewhere. No matter where he was, he’d get in trouble.”</p><p>Signed to the team in 1936, Jakucki’s first year was a bust. Then, when World War II left the Browns lacking for players in 1944, they re-signed him. Jakucki not only went 13-9 that year, he pitched the last game of the season against the Yankees, helping the Browns clinch the pennant with a 5-2 win. Unfortunately, he went down fighting in a 5-1 loss in Game 4 of the World Series, giving up 4 runs before the 4th inning. Still, the Browns would never have gotten that far without him.</p>", 991 details: { 992 position: "P", 993 bats: "Right", 994 arm: "Right", 995 height: { 996 feet: 6, 997 inches: 2 998 }, 999 weight: 198, 1000 city: "Camden, NJ", 1001 born: { 1002 year: 1909, 1003 month: 8, 1004 day: 20 1005 } 1006 } 1007 }, 1008 1009 { 1010 key: "chet-laabs", 1011 firstName: "Chet", 1012 lastName: "Laabs", 1013 url: "http://www.baseball-reference.com/players/l/laabsch01.shtml", 1014 bio: "<p>Two home runs in back-to-back innings? That’s a big deal for any player. But in a game that clinched the Browns’ only American League pennant, on the last day of the season? That’s legendary. And that’s the legend of Chet Laabs.</p>", 1015 details: { 1016 position: "OF", 1017 bats: "Right", 1018 arm: "Right", 1019 height: { 1020 feet: 5, 1021 inches: 8 1022 }, 1023 weight: 175, 1024 city: "Milwaukee, WI", 1025 born: { 1026 year: 1912, 1027 month: 04, 1028 day: 30 1029 } 1030 } 1031 }, 1032 1033 { 1034 key: "jack-kramer", 1035 firstName: "Jack", 1036 lastName: "Kramer", 1037 url: "http://www.baseball-reference.com/players/k/krameja01.shtml", 1038 bio: "<p>At the start of the 1943 season, Jack Kramer earned the Browns their 8th straight Opening Day victory. Just a week later, he claimed the 6th win of the team’s 9-game streak â the last of which he also won. With an impressive 17-13 regular season record, Kramer no doubt helped the Browns earn the pennant. Yet, his most notable moment awaited him in the post-season: He pitched a victorious Game Three in that year’s historic all-St. Louis World Series.</p><p>This three-time All-Star (1945-1947) kept the dugout in stitches with his Bugs Bunny impression and wicked wit, but he occasionally let his wild side get the best of him. In 1944, Indians player-manager Lou Boudreau came up to the plate. The dugout was talking smack behind him. Kramer had no qualms about giving Boudreau a fastball to the ribs. Kramer met him at the first-baseline with a warning: “If you don’t keep those guys on the bench quiet, I’ll stick one in your ear the next time you come to bat.”</p>", 1039 details: { 1040 position: "P", 1041 bats: "Right", 1042 arm: "Right", 1043 height: { 1044 feet: 6, 1045 inches: 2 1046 }, 1047 weight: 190, 1048 city: "New Orleans, LA", 1049 born: { 1050 year: 1918, 1051 month: 1, 1052 day: 5 1053 } 1054 } 1055 }, 1056 1057 { 1058 key: "gene-moore", 1059 firstName: "Gene", 1060 lastName: "Moore", 1061 url: "http://www.baseball-reference.com/players/m/moorege03.shtml", 1062 bio: "<p>Gene “Rowdy” Moore played 14 seasons in the majors, but it was number 13 that was especially lucky. The journeyman outfielder played for six different teams before joining the ‘44 Browns, where he hit 13 doubles on the way to winning the American League pennant.</p>", 1063 cardinalsPlayer: true, 1064 details: { 1065 position: "RF", 1066 bats: "Left", 1067 arm: "Left", 1068 height: { 1069 feet: 5, 1070 inches: 11 1071 }, 1072 weight: 175, 1073 city: "Lancaster, TX", 1074 born: { 1075 year: 1909, 1076 month: 26, 1077 day: 8 1078 } 1079 } 1080 }, 1081 1082 { 1083 key: "bob-muncrief", 1084 firstName: "Bob", 1085 lastName: "Muncrief", 1086 url: "http://www.baseball-reference.com/players/m/muncrbo01.shtml", 1087 bio: "<p>Bob Muncrief pitched for the Browns for 9 seasons. In 1941, he almost â almost â ended DiMaggio’s hitting streak at 35. Later, he helped the Browns fight their way to the 1944 American League pennant victory. He also played in the All-Star Game that same year.</p>", 1088 details: { 1089 position: "P", 1090 bats: "Right", 1091 arm: "Right", 1092 height: { 1093 feet: 6, 1094 inches: 2 1095 }, 1096 weight: 190, 1097 city: "Madill, OK", 1098 born: { 1099 year: 1916, 1100 month: 1, 1101 day: 28 1102 } 1103 } 1104 }, 1105 1106 { 1107 key: "tom-turner", 1108 firstName: "Tom", 1109 lastName: "Turner", 1110 url: "http://www.baseball-reference.com/players/t/turneto01.shtml", 1111 bio: "<p>Tom Turner broke into the bigs as a 23-year-old rookie. He was the Browns’ backstop in 1944, then went off to serve his country in WWII. Turner returned from service, but never returned to the majors. After a brief stint in the Pacific Coast League in 1946, he put down his lumber for good and retired among the timbers of the Pacific N
1111orthwest.</p>", 1112 details: { 1113 position: "C", 1114 bats: "Right", 1115 arm: "Right", 1116 height: { 1117 feet: 6, 1118 inches: 2 1119 }, 1120 weight: 195, 1121 city: "Custer, OK", 1122 born: { 1123 year: 1916, 1124 month: 9, 1125 day: 8 1126 } 1127 } 1128 }, 1129 1130 { 1131 key: "nels-potter", 1132 firstName: "Nels", 1133 lastName: "Potter", 1134 url: "http://www.baseball-reference.com/players/p/pottene01.shtml", 1135 bio: "<p>Nels Potter never shaved on days he took the mound. Whether it was due to his superstition or his stinky cheddar, Nels went 19-7 in 1944 regular season games. But for some reason, he shaved before his start in Game Two of the 1944 World Series â a game he should’ve won. Despite the loss, Potter’s 1944 season was still remarkable. He finished 9th in American League MVP voting, had 16 complete games under his belt, 3 shutouts and a 2.83 ERA. Potter continued to play for the Browns with mixed results until 1948.</p>", 1136 cardinalsPlayer: true, 1137 details: { 1138 position: "P", 1139 bats: "Left", 1140 arm: "Right", 1141 height: { 1142 feet: 5, 1143 inches: 11 1144 }, 1145 weight: 180, 1146 city: "Mount Morris, IL", 1147 born: { 1148 year: 1911, 1149 month: 23, 1150 day: 8 1151 } 1152 } 1153 }, 1154 1155 { 1156 key: "floyd-baker", 1157 firstName: "Floyd", 1158 lastName: "Baker", 1159 url: "http://www.baseball-reference.com/players/b/bakerfl01.shtml", 1160 bio: "<p>In his second year with the Browns, Floyd Baker played in 44 games. The year was 1944. And it was the only year the Browns clinched the American League pennant. Coincidence? Possibly. But Baker still called that season the “highlight of [his] career.”</p>", 1161 details: { 1162 position: "3B, 2B, SS", 1163 bats: "Left", 1164 arm: "Right", 1165 height: { 1166 feet: 5, 1167 inches: 9 1168 }, 1169 weight: 160, 1170 city: "Luray, VA", 1171 born: { 1172 year: 1916, 1173 month: 10, 1174 day: 10 1175 } 1176 } 1177 }, 1178 1179 { 1180 key: "alvis-shirley", 1181 firstName: "Alvis “Tex”", 1182 lastName: "Shirley", 1183 url: "http://www.baseball-reference.com/players/s/shirlte01.shtml", 1184 bio: "<p>They called him “Tex” for good reason. He was known to be a little rowdy, on the mound and off, and he never went without a hat. In Game Four of the 1944 World Series, Tex pitched the last two innings without allowing a run.</p>", 1185 details: { 1186 position: "P", 1187 bats: "Switch", 1188 arm: "Right", 1189 height: { 1190 feet: 6, 1191 inches: 1 1192 }, 1193 weight: 175, 1194 city: "Birthright, TX", 1195 born: { 1196 year: 1918, 1197 month: 4, 1198 day: 25 1199 } 1200 } 1201 }, 1202 1203 { 1204 key: "mike-chartak", 1205 firstName: "Mike", 1206 lastName: "Chartak", 1207 url: "http://www.baseball-reference.com/players/c/chartmi01.shtml", 1208 bio: "<p>It wasn’t hard for Mike Chartak to choose between what he was doing (working the line at a war production factory) and what he wanted to do (play professional baseball full time). It was hard, however, for Chartak to hit the ball in the ‘44 World Series. Two at-bats, two strikeouts â the second of which ended the Browns’ hopes for a Game 7.</p>", 1209 details: { 1210 position: "RF, 1B", 1211 bats: "Left", 1212 arm: "Left", 1213 height: { 1214 feet: 6, 1215 inches: 2 1216 }, 1217 weight: 180, 1218 city: "Brooklyn, NY", 1219 born: { 1220 year: 1916, 1221 month: 4, 1222 day: 28 1223 } 1224 } 1225 }, 1226 1227 { 1228 key: "steve-sundra", 1229 firstName: "Steve", 1230 lastName: "Sundra", 1231 url: "http://www.baseball-reference.com/players/s/sundrst01.shtml", 1232 bio: "<p>Steve Sundra tasted World Series victory in 1938, as a member of the Yankees club. He brought a whiff of that victory with him when he joined the Browns, bringing home three consecutive winning records (1942—1944). He went on to serve in the military for a year, then rejoined the team for a short and much less productive stint.</p>", 1233 details: { 1234 position: "P", 1235 bats: "Right", 1236 arm: "Right", 1237 height: { 1238 feet: 6, 1239 inches: 2 1240 }, 1241 weight: 190, 1242 city: "Luxor, PA", 1243 born: { 1244 year: 1910, 1245 month: 3, 1246 day: 27 1247 } 1248 } 1249 }, 1250 1251 { 1252 key: "mark-christman", 1253 firstName: "Mark", 1254 lastName: "Christman", 1255 url: "http://www.baseball-reference.com/players/c/chrisma01.shtml", 1256 bio: "<p>Born and raised on Browns’ baseball, Mark Christman got 148 hits in 148 games for the pennant-winning 1944 team. Christman, with a number six on his jersey, played in all six World Series games, but ended up with six strikeouts and just one RB
1256I. Maybe six wasn’t really his number.</p>", 1257 details: { 1258 position: "P", 1259 bats: "Right", 1260 arm: "Right", 1261 height: { 1262 feet: 5, 1263 inches: 11 1264 }, 1265 weight: 175, 1266 city: "Maplewood, MO", 1267 born: { 1268 year: 1913, 1269 month: 10, 1270 day: 21 1271 } 1272 } 1273 }, 1274 1275 { 1276 key: "lefty-west", 1277 firstName: "Lefty", 1278 lastName: "West", 1279 url: "http://www.baseball-reference.com/players/w/westle01.shtml", 1280 bio: "<p>If Lefty West would have picked up a bat before he picked up a ball, he might have gone by Righty â he hit from the right side of the plate but pitched from the left. West spent ‘44 with the Browns as a reliever and transitioned to a starter in 1945 before bowing out of the big leagues in September of that year.</p>", 1281 details: { 1282 position: "P", 1283 bats: "Right", 1284 arm: "Left", 1285 height: { 1286 feet: 6, 1287 inches: 0 1288 }, 1289 weight: 165, 1290 city: "Gibsonville, NC", 1291 born: { 1292 year: 1915, 1293 month: 9, 1294 day: 3 1295 } 1296 } 1297 }, 1298 1299 { 1300 key: "ellis-clary", 1301 firstName: "Ellis", 1302 lastName: "Clary", 1303 url: "http://www.baseball-reference.com/players/c/claryel01.shtml", 1304 bio: "<p>He might have gone by “Cat,” but it was said that Ellis Clary could even make dogs laugh. Batting .256 during his Browns career, Clary probably cracked more jokes than bats. He only saw one at-bat in the ‘44 World Series, but between their habits and his humor, he had a good time. “They drank anything that would pour. If you went out with them, you wore a football helmet,” he said about the 1944 team. According to some accounts, he’d also sneak a listen to Chicago Bears games on the radio during the regular season. But lack of time at the plate didn’t keep him out of the game. Clary went on to become a coach and well-respected scout for much of the next 50 years.</p>", 1305 details: { 1306 position: "2B, 3B", 1307 bats: "Right", 1308 arm: "Right", 1309 height: { 1310 feet: 5, 1311 inches: 8 1312 }, 1313 weight: 160, 1314 city: "Valdosta, GA", 1315 born: { 1316 year: 1916, 1317 month: 9, 1318 day: 11 1319 } 1320 } 1321 }, 1322 1323 { 1324 key: "sam-zoldak", 1325 firstName: "Sam", 1326 lastName: "Zoldak", 1327 url: "http://www.baseball-reference.com/players/z/zoldasa01.shtml", 1328 bio: "<p>“Sad Sam” Zoldak was a rookie reliever for the 1944 Browns club, but the southpaw never pitched in the World Series. However, he still had a lot to smile about. With his sharp location, he went 23-27 and averaged a respectable 3.59 ERA over his 125-game Browns career. In 1948, Zoldak was traded to the Cleveland Indians for Bill Kennedy and $100,000 â but again was left out of the Fall Classic.</p>", 1329 details: { 1330 position: "P", 1331 bats: "Left", 1332 arm: "Left", 1333 height: { 1334 feet: 5, 1335 inches: 11 1336 }, 1337 weight: 185, 1338 city: "Brooklyn, NY", 1339 born: { 1340 year: 1918, 1341 month: 12, 1342 day: 8 1343 } 1344 } 1345 }, 1346 1347 { 1348 key: "don-gutteridge", 1349 firstName: "Don", 1350 lastName: "Gutteridge", 1351 url: "http://www.baseball-reference.com/players/g/guttedo01.shtml", 1352 bio: "<p>Don Gutteridge started his major league career as a Cardinal in 1936, and joined the team across town 6 seasons later. Gutteridge was was a skillful and speedy fielder â he once turned 5 double-plays in a single game â though he was more known for his Gas House Gang style. According to Gutteridge, he was in good company: He said the Browns were “a bunch of raggedy-assed guys, no college education. They just loved to play baseball.” (A mostly true observation.)</p><p>Gutteridge was the leadoff batter in the Game One of the 1944 World Series. But before that, he was witness to the final out in the pennant-clinching last game of the season. He was playing second base when Oscar Grimes popped out to George McQuinn, just behind first. “It was a foul ball and it went way high and I run over there… and I hollered, ‘Squeeze it George, squeeze it George, squeeze it!’ And old George squeezed it and we won the pennant,” Gutteridge recalls. “It took me about 15 minutes to get back to the dugout,” he explains, “because the minute that last ball hit into George [McQuinn]’s glove, we were swamped. George and I had to fight our way over to our dugout… There was a lot, a lot of people on that field long before we ever got there. I think (the fans) already jumped over the wall and they swarmed us.”</p>", 1353 cardinalsPlayer: true, 1354 details: { 1355 position: "2B, 3B", 1356 bats: "Right", 1357 arm: "Right", 1358 height: { 1359 feet: 5, 1360 inches: 10 1361 }, 1362 weight: 165, 1363 city: "Pittsburg, KS", 1364 born: { 1365 year: 1912, 1366 month: 6, 1367 day: 19 1368 } 1369 } 1370 }, 1371 1372 { 1373 key: "red-hayworth", 1374 firstName: "Red", 1375 lastName: "Hayworth", 1376 url: "http://www.baseball-reference.com/players/h/haywora01.shtml", 1377 bio: "<p>Red Hayworth’s older brother, Ray, was a longtime catcher for the Detroit Tigers, and briefly played for the Brooklyn Dodgers and the New York Giants. In 1942, Ray even caught a game for the St. Louis Browns. Red joined the Browns two years later, after being stuck in the Yankees’ minor league clubs. Red’s first season with the Browns (1944) was the highlight of his 2-year major league career. He was the starting catcher for all 6 games of the Browns’ only World Series appearance.</p>", 1378 details: { 1379 position: "C", 1380 bats: "Right", 1381 arm: "Right", 1382 height: { 1383 feet: 6, 1384 inches: 1 1385 }, 1386 weight: 200, 1387 city: "High Point, NC", 1388 born: { 1389 year: 1916, 1390 month: 5, 1391 day: 14 1392 } 1393 } 1394 }, 1395 1396 { 1397 key: "george-mcquinn", 1398 firstName: "George", 1399 lastName: "McQuinn", 1400 url: "http://www.baseball-reference.com/players/m/mcquige02.shtml", 1401 bio: "<p>The only thing that wasn’
1401t quiet about George McQuinn was his bat. He consistently led the Browns at the plate, racking up over 1,200 hits in his 8 years with the team. He also caught the final pop fly that clinched the AL pennant for the Browns. (Don Gutteridge tells it vividly.) The star of the ‘44 World Series, he hit .438 and drove in 5 of the team’s 9 runs. The six time All-Star also hit the Browns’ only home run in the series, leading the team to a 2-1 victory in Game One.</p>", 1402 details: { 1403 position: "1B", 1404 bats: "Left", 1405 arm: "Left", 1406 height: { 1407 feet: 5, 1408 inches: 11 1409 }, 1410 weight: 165, 1411 city: "Arlington, VA", 1412 born: { 1413 year: 1910, 1414 month: 29, 1415 day: 05 1416 } 1417 } 1418 }, 1419 1420 { 1421 key: "frank-mancuso", 1422 firstName: "Frank", 1423 lastName: "Mancuso", 1424 url: "http://www.baseball-reference.com/players/m/mancufr01.shtml", 1425 bio: "<p>In 1943, Frank Mancuso couldn’t even walk. As an Army paratrooper, he broke his back and leg in a botched practice jump. Doctors told him he’d never play baseball again. They were wrong.</p><p>Because of his injury, he couldn’t field fly balls â he’d pass out if he looked straight up. But that didn’t keep him from a big-time win. Together with fellow first-year catcher Myron “Red” Hayworth, Mancuso helped the ‘44 Browns capture the American League championship, the first team to ever do so with two rookie catchers.</p>", 1426 details: { 1427 position: "C", 1428 bats: "Right", 1429 arm: "Right", 1430 height: { 1431 feet: 6, 1432 inches: 0 1433 }, 1434 weight: 195, 1435 city: "Houston, TX", 1436 born: { 1437 year: 1918, 1438 month: 5, 1439 day: 23 1440 } 1441 } 1442 }, 1443 1444 { 1445 key: "milt-byrnes", 1446 firstName: "Milt", 1447 lastName: "Byrnes", 1448 url: "http://www.baseball-reference.com/players/b/byrnemi01.shtml", 1449 bio: "<p>They called him Skippy, but Milt Byrnes sure knew how to draw a walk. In his 3-year major league career, he earned 199 bases on balls â the 26th highest BB count of all batters since 1901 with 1,500 career at-bats.</p>", 1450 details: { 1451 position: "OF", 1452 bats: "Left", 1453 arm: "Left", 1454 height: { 1455 feet: 5, 1456 inches: 10 1457 }, 1458 weight: 170, 1459 city: "St. Louis, MO", 1460 born: { 1461 year: 1916, 1462 month: 11, 1463 day: 15 1464 } 1465 } 1466 }, 1467 1468 { 1469 key: "joe-schultz", 1470 firstName: "Joe", 1471 lastName: "Schultz", 1472 url: "http://www.baseball-reference.com/players/s/schuljo05.shtml", 1473 bio: "<p>Joe Schultz was practically born at the backstop. His dad, Joe Sr., was an outfielder for all but one of the National League teams. In 1932, Joe Sr. was managing the Class A Houston Buffaloes. Though he was just the batboy, Joe Jr. made his first professional plate appearance as a pinch hitter at the ripe age of 13. Ultimately, Joe Jr. would spend most of his career in his hometown. He was a backup catcher and pinch hitter for the Browns, bringing his solid glove and even better sense of humor to 218 games over 6 years (1943-1948).</p>", 1474 details: { 1475 position: "C, PH", 1476 bats: "Left", 1477 arm: "Right", 1478 height: { 1479 feet: 5, 1480 inches: 11 1481 }, 1482 weight: 180, 1483 city: "Chicago, IL", 1484 born: { 1485 year: 1918, 1486 month: 8, 1487 day: 29 1488 } 1489 } 1490 }, 1491 1492 { 1493 key: "al-zarilla", 1494 firstName: "Al", 1495 lastName: "Zarilla", 1496 url: "http://www.baseball-reference.com/players/z/zarilal01.shtml", 1497 bio: "<p>“Zarilla slud into third!” called Dizzy Dean. This now-sorta-famous quip isn’t the only reason we remember Al “Zeke” Zarilla. He scored and drove in a run to help the Browns win Game 3 of the 1944 World Series.</p><p>After the Browns: Zarilla was traded to the Boston Red Sox in 1949, where he would later achieve career highs in slugging percentage, runs and walks. On June 8, 1950, he tied a still-standing major league record when he hit 4 doubles in a game. He also spent time with the White Sox and, returned to the Browns briefly, but he finished out his career with the Red Sox in 1953.</p>", 1498 details: { 1499 position: "OF", 1500 bats: "Left", 1501 arm: "Right", 1502 height: { 1503 feet: 5, 1504 inches: 11 1505 }, 1506 weight: 180, 1507 city: "Los Angeles, CA", 1508 born: { 1509 year: 1919, 1510 month: 5, 1511 day: 1 1512 } 1513 } 1514 }, 1515 1516 { 1517 key: "chuck-stevens", 1518 firstName: "Chuck", 1519 lastName: "Stevens", 1520 url: "http://www.baseball-reference.com/players/s/stevech01.shtml", 1521 bio: "<p>After a handful of years in the Browns’ minor league clubs, Chuck Stevens landed a major league gig in 1941. However, he only played 4 games with the Browns before he left for the Air Force. Stevens rejoined the Browns for a season in 1946, and again in 1948.</p><p>On July 9, 1948, Stevens came up to bat against Satchel Paige. It was Paige&r
1521squo;s first game in the Bigs. The two had faced each other in several exhibition games in California, and, although Paige’s pitching reputation preceded him, Stevens hadn’t thought too much of it. On the second pitch, he smacked a line drive out to left field, marking the first major league hit off of the soon-to-be legend.</p><p>“Everybody was taken by Satchel and his reputation was awesome,” Stevens said. “When I got that hit against him, I was never terribly impressed by it, but the people thought that was a great accomplishment. To me, it was just, he was just another pitcher.”</p>", 1522 details: { 1523 position: "1B", 1524 bats: "Switch", 1525 arm: "Left", 1526 height: { 1527 feet: 6, 1528 inches: 1 1529 }, 1530 weight: 180, 1531 city: "Van Houten, NM", 1532 born: { 1533 year: 1918, 1534 month: 7, 1535 day: 10 1536 } 1537 } 1538 }, 1539 1540 { 1541 key: "tom-jordan", 1542 firstName: "Tom", 1543 lastName: "Jordan", 1544 url: "http://www.baseball-reference.com/players/j/jordato01.shtml", 1545 bio: "<p>Tom Jordan appeared in all of 39 games in the majors, but spent nearly 20 years playing the game he loved. Jordan started his baseball career at age 18 on a Class D team. Over the next six years, he worked his way up through the system. In 1944, he finally got his chance in the big show. His last cup of coffee was his first plate appearance for the Browns in 1948. Jordan returned to the minors and unaffiliated ball in 1949, where he stayed as a player/manager until the age of 37. Not a bad life for a kid from Lawton, Oklahoma.</p>", 1546 details: { 1547 position: "C, PH", 1548 bats: "Right", 1549 arm: "Right", 1550 height: { 1551 feet: 6, 1552 inches: 1 1553 }, 1554 weight: 195, 1555 city: "Lawton, OK", 1556 born: { 1557 year: 1919, 1558 month: 9, 1559 day: 5 1560 } 1561 } 1562 }, 1563 1564 { 1565 key: "dick-starr", 1566 firstName: "Dick", 1567 lastName: "Starr", 1568 url: "http://www.baseball-reference.com/players/s/starrdi01.shtml", 1569 bio: "<p>After a rough first season with the Browns (1949), Dick Starr was a bright spot for the Browns in 1950. With a 7-5 record, he was the Browns’ only pitcher with a winning record. </p>", 1570 details: { 1571 position: "P", 1572 bats: "Right", 1573 arm: "Right", 1574 height: { 1575 feet: 6, 1576 inches: 3 1577 }, 1578 weight: 190, 1579 city: "Kittanning, PA", 1580 born: { 1581 year: 1921, 1582 month: 3, 1583 day: 2 1584 } 1585 } 1586 }, 1587 1588 { 1589 key: "george-elder", 1590 firstName: "George", 1591 lastName: "Elder", 1592 url: "http://www.baseball-reference.com/players/e/elderge01.shtml", 1593 bio: "<p>George Elder appeared in only 41 games during his major league career, all with the Browns in 1949. In his career, he hit exactly as many times as he struck out â 11 apiece. He is one of only two major league baseball players from Lebanon, KY.</p>", 1594 details: { 1595 position: "PH, PR, LF", 1596 bats: "Left", 1597 arm: "Right", 1598 height: { 1599 feet: 5, 1600 inches: 11 1601 }, 1602 weight: 180, 1603 city: "Lebanon, KY", 1604 born: { 1605 year: 1921, 1606 month: 3, 1607 day: 10 1608 } 1609 } 1610 }, 1611 1612 { 1613 key: "neil-berry", 1614 firstName: "Neil", 1615 lastName: "Berry", 1616 url: "http://www.baseball-reference.com/players/b/berryne01.shtml", 1617 bio: "<p>Neil Berry was a utility infielder for the Browns for a mere 37 games in 1953. He was released in late August, then picked up by the Chicago White Sox a few days later. Some would consider it irony when he was traded to Baltimore’s shiny new team (sort of) for the 1954 season.</p>", 1618 details: { 1619 position: "SS, 2B, 3B", 1620 bats: "Right", 1621 arm: "Right", 1622 height: { 1623 feet: 5, 1624 inches: 10 1625 }, 1626 weight: 168, 1627 city: "Kalamazoo, MI", 1628 born: { 1629 year: 1922, 1630 month: 1, 1631 day: 11 1632 } 1633 } 1634 }, 1635 1636 { 1637 key: "johnny-hetki", 1638 firstName: "Johnny", 1639 lastName: "Hetki", 1640 url: "http://www.baseball-reference.com/players/h/hetkijo01.shtml", 1641 bio: "<p>Even though Johnny Hetki only pitched in three games for the 1952 Browns, he still managed to net four strikeouts. He took the mound in a Browns uniform for 9.1 innings total, which is technically a complete game. It just didn’t happen all at the same time.</p>", 1642 details: { 1643 position: "P", 1644 bats: "Right", 1645 arm: "Right", 1646 height: { 1647 feet: 6, 1648 inches: 1 1649 }, 1650 weight: 202, 1651 city: "Leavenworth, KS", 1652 born: { 1653 year: 1922, 1654 month: 5, 1655 day: 12 1656 } 1657 } 1658 }, 1659 1660 { 1661 key: "jim-rivera", 1662 firstName: "Jim", 1663 lastName: "Rivera", 1664 url: "http://www.baseball-reference.com/players/r/riverji01.shtml", 1665 bio: "<p>Daredevil. Army Corpsman. Light-heavyweight boxer. Inmate. And finally, major leaguer. Jungle Jim Rivera, as he came to be called, had many identities. Not all of them were friendly, but they earned him a lot of attention.</p><p>In 1951, Rivera was named the Pacific Coast League MVP. The White Sox quickly snapped him up, then the Browns got him in a 3-team, 8-player trade before the start of the 1952 season.</p><p>Browns manager Rogers Hornsby once said that Rivera was “the only man I would pay admission to see.” He slid head-first before it was in style. He made crowd-pleasing, game-saving catches. He was an all-around clutch player. As one reporter put it, “He runs in the outfield like a deer, on the bases like an express train, and he throws like a rifle.”</p><p>Unfortunately, Rivera’s spunk and style didn’t outweigh his early-season slump. He was traded back to the White Sox, and continued to make the news for the next 10 years.</p>", 1666 details: { 1667 position: "OF", 1668 bats: "Left", 1669 arm: "Left", 1670 height: { 1671 feet: 6, 1672 inches: 0 1673 }, 1674 weight: 196, 1675 city: "New York, NY", 1676 born: { 1677 year: 1921, 1678 month: 7, 1679 day: 22 1680 } 1681 } 1682 }, 1683 1684 { 1685 key: "don-lenhardt", 1686 firstName: "Don", 1687 lastName: "Lenhardt", 1688 url: "http://www.baseball-reference.com/players/l/lenhado01.shtml", 1689 bio: "<p>Don Lenhardt was nicknamed “Footsie” because he often had trouble finding shoes that fit. He also had trouble finding a club that fit â he was traded 6 times in 5 years. With a career high of 22 home runs, his best season was his first. (This begs the question: which came first, the trades or the stats?) Lenhardt was also one of the players to be transplanted when the Browns became the Baltimore Orioles in 1954.</p>", 1690 details: { 1691 position: "LF, 1B, 3B", 1692 bats: "Right", 1693 arm: "Right", 1694 height: { 1695 feet: 6, 1696 inches: 3 1697 }, 1698 weight: 190, 1699 city: "Alton, IL", 1700 born: { 1701 year: 1922, 1702 month: 10, 1703 day: 4 1704 } 1705 } 1706 }, 1707 1708 { 1709 key: "tom-wright", 1710 firstName: "Tom", 1711 lastName: "Wright", 1712 url: "http://www.baseball-reference.com/players/w/wrighto01.shtml", 1713 bio: "<p>Tom Wright was known as a pinch hitting specialist. In a 1950 Sporting News article, Steve O’Neill said, “You can call on him any time and he’s just as likely as not to deliver the hit you need. Lots of players lose that split-second timing when they lay off for a while. But Tom can sit on the bench for three weeks, then get up and hit just as well as if he was in there every day.” Wright would have much rather played every day than sit on the bench for three weeks, but it’s good to know he could have done either equally as well.</p>", 1714 details: { 1715 position: "PH, OF", 1716 bats: "Left", 1717 arm: "Right", 1718 height: { 1719 feet: 5, 1720 inches: 11 1721 }, 1722 weight: 180, 1723 city: "Shelby, NC", 1724 born: { 1725 year: 1923, 1726 month: 9, 1727 day: 22 1728 } 1729 } 1730 }, 1731 1732 { 1733 key: "billy-demars", 1734 firstName: "Billy", 1735 lastName: "Demars",
1736 url: "http://www.baseball-reference.com/players/d/demarbi01.shtml", 1737 bio: "<p>In his 209 games with the Browns, Billy “Kid” DeMars only had 13 RBIs. Although he came up short on the field, he went on to become one of the game’s most respected batting coaches.</p><p>“Baseball was my lifetime, 58 years. Every job has its ups and downs, but I still can't see me doing anything else. It was a great ride.” — Billy DeMars</p><p>After the Browns: Billy DeMars didn’t move with the Browns to Baltimore, but in 1958 he began an 11-year post as a manager in the Orioles’ farm system. From there, he moved up to the majors and found success as a batting coach. He was with the Phillies for 13 years, including their franchise-first World Series win in 1980. He later coached the Expos and the Reds, and earned the high respect of Pete Rose, who said DeMars was the best hitting coach he’d ever had.</p>", 1738 details: { 1739 position: "SS, 3B", 1740 bats: "Right", 1741 arm: "Right", 1742 height: { 1743 feet: 5, 1744 inches: 10 1745 }, 1746 weight: 160, 1747 city: "Brooklyn, NY", 1748 born: { 1749 year: 1925, 1750 month: 8, 1751 day: 26 1752 } 1753 } 1754 }, 1755 1756 { 1757 key: "frank-saucier", 1758 firstName: "Frank", 1759 lastName: "Saucier", 1760 url: "http://www.baseball-reference.com/players/s/saucifr01.shtml", 1761 bio: "<p>Out of the 14 times that Frank Saucier stepped up to the plate for the 1951 Browns, he’s usually remembered for the one time he was asked not to. Saucier was replaced by pinch-hitter and shortest-ever baseball player Eddie Gaedel as part of a Bill Veeck promotional stunt in August 1951.</p>", 1762 details: { 1763 position: "PH, PR, OF", 1764 bats: "Left", 1765 arm: "Right", 1766 height: { 1767 feet: 6, 1768 inches: 1 1769 }, 1770 weight: 180, 1771 city: "Leslie, MO", 1772 born: { 1773 year: 1926, 1774 month: 5, 1775 day: 28 1776 } 1777 } 1778 }, 1779 1780 { 1781 key: "johnny-groth", 1782 firstName: "Johnny", 1783 lastName: "Groth", 1784 url: "http://www.baseball-reference.com/players/g/grothjo01.shtml", 1785 bio: "<p>In 1949, Life magazine dubbed a young Johnny Groth the next Joe DiMaggio. Just 4 years later, Groth had the worst season of his career with the Browns during their final season in St. Louis. Even after a dismal season, he provided a little light at the end of a long tunnel for the soon-to-be defunct team: He scored the last-ever run for the Browns in a 2-1 loss to the Chicago White Sox on September 27, 1953.</p>", 1786 details: { 1787 position: "CF", 1788 bats: "Right", 1789 arm: "Right", 1790 height: { 1791 feet: 6, 1792 inches: 0 1793 }, 1794 weight: 182, 1795 city: "Chicago, IL", 1796 born: { 1797 year: 1926, 1798 month: 7, 1799 day: 23 1800 } 1801 } 1802 }, 1803 1804 { 1805 key: "ed-mickelson", 1806 firstName: "Ed", 1807 lastName: "Mickelson", 1808 url: "http://www.baseball-reference.com/players/m/mickeed01.shtml", 1809 bio: "<p>Ed Mickelson recorded his first hit with the Browns’ cross-town rivals in 1950, but his last one was a little more memorable. Mickelson recorded the last-ever RBI for the Browns in a 2-1 extra-innings loss to the Chicago White Sox in September 1953.</p>", 1810 cardinalsPlayer: true, 1811 details: { 1812 position: "1B", 1813 bats: "Right", 1814 arm: "Right", 1815 height: { 1816 feet: 6, 1817 inches: 3 1818 }, 1819 weight: 205, 1820 city: "Ottawa, IL", 1821 born: { 1822 year: 1926, 1823 month: 9, 1824 day: 9 1825 } 1826 } 1827 }, 1828 1829 { 1830 key: "don-johnson", 1831 firstName: "Don", 1832 lastName: "Johnson", 1833 url: "http://www.baseball-reference.com/players/j/johnsdo03.shtml", 1834 bio: "<p>Although he wasn’t exactly a rookie, one could say Don Johnson cut his pitching teeth during his years with the Browns. His two losing seasons (1950-1951) were a poor measure of his future prowess â he went on to become the International League’s most valuable pitcher in 1957.</p>", 1835 details: { 1836 position: "P", 1837 bats: "Right", 1838 arm: "Right", 1839 height: { 1840 feet: 6, 1841 inches: 3 1842 }, 1843 weight: 200, 1844 city: "Portland, OR", 1845 born: { 1846 year: 1926, 1847 month: 11, 1848 day: 12 1849 } 1850 } 1851 }, 1852 1853 { 1854 key: "roy-sievers", 1855 firstName: "Roy", 1856 lastName: "Sievers", 1857 url: "http://www.baseball-reference.com/players/s/sievero01.shtml", 1858 bio: "<p>Roy “Squirrel”
1858 Sievers had a stellar rookie year. In fact, he was the American League Rookie of the Year in 1949, and was 18th in line for MVP. Sievers certainly earned it â he batted .306 with 16 home runs and 91 RBI. Shoulder and arm injuries crippled his playing time in his last three years with the Browns, but he remained a full-time major league player until the mid-1960s.</p>", 1859 details: { 1860 position: "OF, 1B", 1861 bats: "Right", 1862 arm: "Right", 1863 height: { 1864 feet: 6, 1865 inches: 1 1866 }, 1867 weight: 195, 1868 city: "St. Louis, MO", 1869 born: { 1870 year: 1926, 1871 month: 11, 1872 day: 18 1873 } 1874 } 1875 }, 1876 1877 { 1878 key: "hal-hudson", 1879 firstName: "Hal", 1880 lastName: "Hudson", 1881 url: "http://www.baseball-reference.com/players/h/hudsoha01.shtml", 1882 bio: "<p>Some called him “Bud.” Others called him “Lefty.” After 9 seasons working his way through the Browns’ minor league clubs, he was finally called up. In 1952, the southpaw pitched relief in 3 games â half of his entire major league career.</p>", 1883 details: { 1884 position: "P", 1885 bats: "Left", 1886 arm: "Left", 1887 height: { 1888 feet: 5, 1889 inches: 10 1890 }, 1891 weight: 175, 1892 city: "Grosse Pointe, MI", 1893 born: { 1894 year: 1927, 1895 month: 5, 1896 day: 4 1897 } 1898 } 1899 }, 1900 1901 { 1902 key: "al-naples", 1903 firstName: "Al", 1904 lastName: "Naples", 1905 url: "http://www.baseball-reference.com/players/n/napleal01.shtml", 1906 bio: "<p>Al Naples’ most memorable hit was also his only hit. Ever. It was a double. Way to hustle, Al.</p><p>“I ran like all get-out when I poked that double down the right field line for my first hit in the Big Show. I felt rather good after that.” — Al Naples, in One Hit Wonders: Baseball Stories (George Rose)</p>", 1907 details: { 1908 position: "SS", 1909 bats: "Right", 1910 arm: "Right", 1911 height: { 1912 feet: 5, 1913 inches: 9 1914 }, 1915 weight: 168, 1916 city: "Staten Island, NY", 1917 born: { 1918 year: 1926, 1919 month: 8, 1920 day: 29 1921 } 1922 } 1923 }, 1924 1925 { 1926 key: "billy-hunter", 1927 firstName: "Billy", 1928 lastName: "Hunter", 1929 url: "http://www.baseball-reference.com/players/h/huntebi03.shtml", 1930 bio: "<p>Billy Hunter’s first year with the Browns was the last year the club existed: 1953. Batting just over the Mendoza line, Hunter earned his keep as starting shortstop by flashing his leather â and his team spirit. Perhaps surprisingly, Hunter hit the last home run in Browns history on September 26, 1953. Hunter was one of few Brownies who went on to play for the 1954 Baltimore Orioles club.</p>", 1931 details: { 1932 position: "SS", 1933 bats: "Right", 1934 arm: "Right", 1935 height: { 1936 feet: 6, 1937 inches: 0 1938 }, 1939 weight: 180, 1940 city: "Punxatawney, PA", 1941 born: { 1942 year: 1928, 1943 month: 4, 1944 day: 6 1945 } 1946 } 1947 }, 1948 1949 { 1950 key: "joe-demaestri", 1951 firstName: "Joe", 1952 lastName: "Demaestri", 1953 url: "http://www.baseball-reference.com/players/d/demaejo01.shtml", 1954 bio: "<p>Joe DeMaestri didn’t have much of a bat, but he had a solid glove. And when it came to Rogers Hornsby, he had sharp words and no sugar for coating. “He was the worst manager and worst person I ever played for,” DeMaestri said. “Everyone hated him.” The only time he liked Hornsby was when Hornsby got fired. Marty Marion became skipper, and DeMaestri took Marion’s spot at short. Also short was DeMaestri’s time on the Browns. He was traded to the White Sox after just 81 games with the team.</p>", 1955 details: { 1956 position: "SS", 1957 bats: "Right", 1958 arm: "Right", 1959 height: { 1960 feet: 6, 1961 inches: 0 1962 }, 1963 weight: 170, 1964 city: "San Francisco, CA", 1965 born: { 1966 year: 1928, 1967 month: 12, 1968 day: 9 1969 } 1970 } 1971 }, 1972 1973 { 1974 key: "bud-thomas", 1975 firstName: "Bud", 1976 lastName: "Thomas", 1977 url: "http://www.baseball-reference.com/players/t/thomabu02.shtml", 1978 bio: "<p>Bud Thomas played all 14 games of his career in September 1951. During those 14 games, he had 20 at-bats, 7 hits, 2 stolen bases and 1 home run. Not too shabby, Bud.</p>", 1979 details: { 1980 position: "SS", 1981 bats: "Right", 1982 arm: "Right", 1983 height: { 1984 feet: 6, 1985 inches: 0 1986 }, 1987 weight: 180, 1988 city: "Sedalia, MO", 1989 born: { 1990 year: 1929, 1991 month: 3, 1992 day: 10 1993 } 1994 } 1995 }, 1996 1997 { 1998 key: "don-larsen", 1999 firstName: "Don", 2000 lastName: "Larsen", 2001 url: "http://www.baseball-reference.com/players/l/larsedo01.shtml", 2002 bio: "<p>His rookie (and only) season with the Browns, Don Larsen finished with a 7-12 record. But he was first on the team in innings pitched (192â ) and complete games (7), and second in strikeouts. He also held the then-record for consecutive hits by a pitcher, with 7. Yet, his greatest victory didn’t come until 1956, when he pitched the only perfect game in World Series history… for the Yankees.</p><p>After the Browns: Larsen stayed on in Baltimore when the Browns became the Orioles in 1954. That year, he led the league in losses, but one of his three wins included a 10-0 shutout against the Yankees. In 1956, his luck had turned around. He pitched a 4-hit shutout in a regular season doubleheader against the Orioles. Then, he made baseball â and World Series â history. One of only 23 perfect games in MLB history, Larsen’s 97-pitch no-no came in Game 5, wearing Yankee pinstripes, facing the Dodgers.</p>", 2003 details: { 2004 position: "P", 2005 bats: "Right", 2006 arm: "Right", 2007 height: { 2008 feet: 6, 2009 inches: 4 2010 }, 2011 weight: 215, 2012 city: "Mmichigan City, IN", 2013 born: { 2014 year: 1929, 2015 month: 8, 2016 day: 7 2017 } 2018 } 2019 }, 2020 2021 { 2022 key: "jw-porter", 2023 firstName: "J.W.", 2024 lastName: "Porter", 2025 url: "http://www.baseball-reference.com/players/p/porteja01.shtml", 2026 bio: "<p>Browns GM/Owner Bill Veeck wasn’t just J.W. Porter’s boss when he joined the club in 1952. He was his roommate. Porter, then just 19, lived with Veeck at Sportsman’s Park during his 33-game career with the team. Porter might have been better at eating eggs than playing ball. His favorite meal was “two dozen over light,” which he’d eat in one sitting. That’s almost 5 times the number of runs he scored during his tenure with the squad.</p>", 2027 cardinalsPlayer: true, 2028 details: { 2029 position: "C, PH, OF", 2030 bats: "Right", 2031 arm: "Right", 2032 height: { 2033 feet: 6, 2034 inches: 2 2035 }, 2036 weight: 180, 2037 city: "Shawnee, OK", 2038 born: { 2039 year: 1933, 2040 month: 1, 2041 day: 17 2042 } 2043 } 2044 }, 2045 { 2046 key: "babe-martin", 2047 firstName: "Babe", 2048 lastName: "Martin", 2049 url: "http://www.baseball-reference.com/players/m/martiba01.shtml", 2050 bio: "<p>Babe Martin was born Boris Michael Martinovich in Seattle, Washington to Serbian immigrant parents. The Martinovich family moved to Zeigler, Illinois when Babe was year old and subsequently moved to St. Louis, Missouri after the death of Babeâs father.</p><p>He started his professional baseball career in 1940 and had a breakout year in 1944 with the Toledo Mud Hens, batting .350 in 114 games. The following season, he joined the St. Louis Browns. Martin retired in 1954. In 69 Major League games, he had 2 home runs, 18 RBI, and a .214 batting average.</p>", 2051 cardinalsPlayer: false, 2052 details: { 2053 position: "LF, 1B, C", 2054 bats: "Right", 2055 arm: "Right", 2056 height: { 2057 feet: 5, 2058 inches: 11 2059 }, 2060 weight: 194, 2061 city: "Seattle, WA", 2062 born: { 2063 year: 1920, 2064 month: 3, 2065 day: 28 2066 } 2067 } 2068 }, 2069 { 2070 key: "bill-jennings", 2071 firstName: "Bill", 2072 lastName: "Jennings", 2073 url: "http://www.baseball-reference.com/players/j/jennibi01.shtml", 2074 bio: "<p>A native of St. Louis, Missouri, Jennings played briefly for the St. Louis Browns during the 1951 season. Jennings posted a .179 average (35-for-195) in 64 games for the Browns, driving in 13 runs and scoring 20 times, while collecting 10 doubles, two triples, and one stolen base.</p>", 2075 cardinalsPlayer: false, 2076 details: { 2077 position: "SS", 2078 bats: "Right", 2079 arm: "Right", 2080 height: { 2081 feet: 6, 2082 inches: 2 2083 }, 2084 weight: 175, 2085 city: "St. Louis, MO", 2086 born: { 2087 year: 1925, 2088 month: 9, 2089 day: 28 2090 } 2091 } 2092 } 2093 ] 2094 }, 2095 2096 blog: { 2097 2098 title: "News & Events", 2099 2100 posts: [ 2101 { 2102 title: 'âThe Saint Louis Browns: The Team That Baseball Forgotâ Premieres on Nine Network', 2103 slug: "browns-documentary-premiere", 2104 date: "February 20, 2018", 2105 excerpt: "Documentary Preserves a Legacy that was Nearly Erased", 2106 images: { 2107 news: "/images/blog/browns-news-generic1.jpg", 2108 article: "/images/blog/browns-article-generic1.jpg" 2109 }, 2110 body: '<p>Continuing our efforts to preserve our beloved teamâs legacy, we are excited and proud to announce the premiere of our new documentary âThe St. Louis Browns: The Team That Baseball Forgot.â The film will air on Thursday, March 8, 2018 at 8 p.m. CT on KETC-TV, St. Louisâs local PBS affiliate.<p>Thank you to all of the people who contributed time, resources and commentary to this documentary, and a special thanks to our partners at HLK for producing and directing this hour-long film.<p>Narrated by actor and St. Louis native Jon Hamm, the documentary follows the journey from the teamâs inception, through their ups and downs, until the sale of the franchise to Baltimore, where they became the Orioles and the history of the Browns was nearly erased. Fans can reminisce at the teamâs on-field antics and St. Louisâs original baseball rivalry. Those unfamiliar with the Browns will be introduced to characters like 3-foot-7-inch Eddie Gaedel, a surprise pinch-hitter wearing a batboy uniform with the number 1/8, and will quickly understand the undeniable lovability of this misfit franchise. Audiences everywhere will see that, beneath the tarnish, there is true baseball gold.<p>âThe St. Louis Browns: The Team That Baseball Forgotâ features archival photos and video footage of the Browns, discussions with St. Louis Browns Historical Society board members Bill Rogers and Emmett McAuliffe, and current interviews with some of the teamâs last living players. The film follows the 2017 release of the critically acclaimed book, <i>St. Louis Browns: The Story of a Beloved Team</i>, by Bill Borst, Bill Rogers and Ed Wheatley, and the 2015 launch of our award-winning website.<p>So, tune in and watch as we take a look back and relive the story of what could have been, but never was â of baseball legends lost to time, glorious gimmicks and a beloved team turned fraternity of failure. This is the story of a team that found its place in history by losing its home. But thanks to this documentary, it\'s a story forgotten no more.' 2111 }, 2112 { 2113 title: "The St. Louis Browns 2017 Reunion Luncheon", 2114 slug: "browns-2017-reunion-luncheon", 2115 date: "August 30, 2017", 2116 excerpt: "Browns 2017 Reunion Luncheon Set for September 26, 2017", 2117 images: { 2118 news: "/images/blog/browns-news-generic2.jpg", 2119 article: "/images/blog/browns-article-generic2.jpg" 2120 }, 2121 body: '<p>Browns 2017 Reunion Luncheon Set for September 26, 2017</p><p>The St. Louis Browns Historical Society and Fan Club announced their 2017 Reunion luncheon set for September 26 featuring Whitey Herzog, Don Larsen and Sonny Siebert. The luncheon will be held at the Holiday Inn Hwy 66 located at 10709 Watson Rd. at Lindbergh, in Sunset Hills â St. Louis, MO at 11:15.</p><p>Reservations for the luncheon can be made on-line from our <a target="_blank" href="http://thestlbrowns.blogspot.com/2017/08/invitation-to-annual-st-louis-browns.html">reservation blog site</a>. Information is available at 314-892-8632 or e-mail to <a target="_blank" href="mailto:[email protected]">[email protected]</a>.</p>' 2122 }, 2123 { 2124 title: "Introducing a new book: The St. Louis Browns â The Story Of A Beloved Team", 2125 slug: "the-story-of-a-beloved-team", 2126 date: "August 30, 2017", 2127 excerpt: "Introducing a new book: The St. Louis Browns â The Story Of A Beloved Team", 2128 images: { 2129 news: "/images/blog/browns-news-generic1.jpg", 2130 article: "/images/blog/browns-article-generic1.jpg" 2131 }, 2132 body: '<p>On September 15, 2017 there will be a national release of St. Louis Browns: The Story of a Beloved Team, by Bill Borst, Bill Rogers and Ed Wheatley; published by Reedy Press of St. Louis, with a special forward by Bob
2132Costas.</p><p>Be sure to get in on a first edition of what will certainly become a baseball collectorâs item. Our first run is 4000 books and, in addition to being sold through our Fan Club, copies will also be available nationwide in major box stores, as well as online sellers like Amazon and Barnes & Noble, so weâre expecting the first run to go fast. The best way to get your copy is to reserve one when you make your reservations for the St. Louis Browns Fan Club Annual Luncheon, scheduled for Tuesday, September 26, 2017.</p><p>Reservations for the luncheon can be made on-line from our <a target="_blank" href="http://thestlbrowns.blogspot.com/2017/08/introducing-new-book-st-louis-browns.html">reservation blog site</a>. Information is available at 314-892-8632 or e-mail to <a target="_blank" href="mailto:[email protected]">[email protected]</a>.</p>' 2133 }, 2134 { 2135 title: "Browns 32nd Reunion Luncheon Set for June 9, 2016", 2136 slug: "browns-32nd-reunion-luncheon", 2137 date: "May 5, 2016", 2138 excerpt: "Browns 32nd Reunion Luncheon Set for June 9, 2016", 2139 images: { 2140 news: "/images/blog/browns-news-generic2.jpg", 2141 article: "/images/blog/browns-article-generic2.jpg" 2142 }, 2143 body: '<p>Browns 32nd Reunion Luncheon Set for June 9, 2016</p><p>The St. Louis Browns Historical Society and Fan Club announced their 32nd annual luncheon set for June 9 at the Sheraton Westport Chalet Hotel. More than 300 fans are expected with some traveling from coast to coast.</p><p>Club president, Bill Rogers, reports invitations have been sent to family members of the Rogers Hornsby and Satchel Paige families. According to Bill Rogers, these two players rank in the very top of professional baseball history. We may not know if any family members are able to attend , but weâre in close touch with them, says Rogers.</p><p>Reservations for the luncheon can be made on-line from our reservation blog site at <a target="_blank" href="http://2015browns.blogspot.com" >http://2015browns.blogspot.com</a> or by mail. Send check for $48 per reservation to St. Louis Browns Fan Club, PO Box 510047, St. Louis, MO 63161. Information is available at 314-892-8632 or e-mail to <a target="_blank" href="mailto:[email protected]">[email protected]</a>.</p>' 2144 }, 2145 { 2146 title: "Yogi, Garver and the 1951 AL MVP Award", 2147 slug: "yogi-garver-and-1951-al-mvp-award", 2148 date: "September 27, 2015", 2149 excerpt: "The passing of Yogi Berra reminds us of a controversey near and dear to the hearts of Browns fans.", 2150 images: { 2151 news: "/images/blog/browns-news-yogi.jpg", 2152 article: "/images/blog/browns-article-yogi.jpg" 2153 }, 2154 body: '<p>In 1951, Browns’ right-handed pitcher Ned Garver was setting the record that still stands for pitchers who won 20 games for a team that finished in last place and lost 100 games.  Better still, Ned was in the fourth year of an incredible four-year rWAR spurt (4.6, 4.1, 7.3, and 5.6) which started right in Garver’s rookie season, 1948.  Meanwhile, in ’51, Yogi could rise no higher than seventh in any major batting category (except for home runs where he was in a three-way tie for fourth place with a not-so-incredible 27 dingers).</p><p>Yogi of course also had “being a catcher” going for him.  But the Yanks had only the third-best pitching staff in the eight-team league.  And the staff featured - not kids who might need some grooming from their battery-mate - but veteran all-stars like Vic Raschi, Allie Reynolds and Eddie Lopat.  So “Where was the beef?” (as Yogi might have said himself).</p><p>Fielding-wise, Yogi was solid, but not spectacular, ranking only third in caught-stealing and fielding percentages and ranking first in errors.</p><p>Garver seemed to be the clear MVP.</p><p>And so Ned thought. The night before the announcement was due, back home for the off-season in Ney, Ohio, Ned received a call from a wire service reporter out of Cleveland (Ned doesn’t remember whether it was AP or UPI) congratulating Ned on his MVP victory, and asking for his comment.</p><p>But then the announcement came out that Berra had won.</p><div class="image-list"><div class="image"><img src="/images/blog/browns-article-yogi.jpg" alt="Yogi Berra AL M.V.P."><div class="caption">A griming Yogi Berra, center, Squat New York Yankee catcher, receives thumping congratulation from other Major Leaguers at American Baseball Academy in New York on Nov. 7, 1951 after learning that he will be named on November 8, most valuable player in the American League for 1951. Berra polled 184 votes to 157 for runner-up Ned Garver of the St. Louis Browns. From Left to right are: Sid Gordon, Boston Braves; Ed Lopat, Yankees; Berra; Gil Hodges, Brooklyn Dodgers, and Gil McDougald, Yankees. (AP Photo/John Rooney) <em>(John Rooney)</em></div></div></div><p>The theory is that the votes were rigged by the New York press. Both American League and (especially importantly) New York Yankee attendance was falling in 1951, after robust postwar gains for several years. The baseball minions â and the press â decided that the very last thing the game needed was for a member of the laughingstock St. Louis Browns to win the MVP, and a pitcher at that. The likable and comical Yogi was the candidate to bring everybody out of the doldrums.</p><p>Ned himself says that the information he received down through the years was that the New York press even left Garver’s name off of some ballots.</p><p>Yogi would repeat the MVP award in 1954 and 1955 with somewhat more formidable numbers.  But his 1951 award was the most inauspicious AL MVP winner until 1965’s Zoilo Versailles of the Minnesota Twins.  The Browns, for their part, would never win a modern (post-1931) MVP award.</p><div class="image-list"><div class="image"><img src="/images/blog/ned-garver-browns_6.jpg" alt="Ned Garver"><div class="caption large">“Gee, Yogi, gimme a break!”</div></div></div>' 2155 }, 2156 { 2157 title: "Last of the Living Former Browns", 2158 slug: "last-of-living-former-browns", 2159 date: "August 20, 2015", 2160 excerpt: "In 1902, the original Milwaukee Brewers moved to St. Louis and became the St. Louis Browns.", 2161 images: { 2162 news: "/images/blog/browns-news-generic1.jpg", 2163 article: "/images/blog/browns-article-generic1.jpg" 2164 }, 2165 body: '<p>From 1902 through 1953, the St. Louis Browns, won only a single American League pennant and that was in the 1944 WWII year in which much of their Brownie good fortunes were attributable to the fact the Yankees and several other clubs were missing key players to military service while the St. Louis entry fared well with older players and draft-deferred flat foots. The Browns lost to their St. Louis NL rivals, the Cardinals, in six games in the 1944 World Series.</p><p>Over the years, the Browns were known best for finishing last or next to last; the great Hall of Fame first baseman George Sisler, who also led the city’s greatest AL club, the 1922 Browns, to a one-game finish behind the Yankees; the single pennant of 1944; Willard Brown hits the first American League HR by a black player for the 1947 Browns; the Barnum & Bailey world of new-in-1951 owner Bill Veeck; the August 19, 1951 appearance of 3’7â³ Eddie Gaedel as a pinch hitter; Satchel Paige; Fan Manager Night, also in 1951 under Veeck; and Ned Garver winning 20 games for a last place Browns club that won only 52 games the entire season.</p><p>The Garver feat led to one of the most memorable anecdotes in baseball history. When Garver asked for a raise in 1952, owner Veeck is said to have turned him down with a very simple explanation: “No way. We could have finished last without you.”</p><p>After a couple of years of falling attendance, more losing baseball, chicanery with also suffering Cardinals, and political pressure from the AL owners who wanted to get rid of Bill Veeck, the Browns were sold to Baltimore interests after the 1953 season. They were re-christened as the Baltimore Orioles in 1954.</p><p>The St. Louis Browns Historical Society and Browns Fan Club has existed since 1984 for the purpose of keeping alive the memory of the St. Louis Browns baseball club. The Pecan Park Eagle wants to thank current president <strong>Bill Rogers</strong> for sending us this new list of the current surviving Browns players. With death of former shortstop Bud Thomas on Saturday, August 15, 2015, the list of living former Browns now has dropped to only twenty names.</p><p><strong>The 20 Surviving St. Louis Browns Players </strong><strong>Through 8/16/2015<br>
2165From Oldest to Youngest by Name, Birthdate, and Age in 2015</strong></p><ol><li>Chuck Stevens 07/10/18 â 97</li><li>Tom Jordan 09/05/19 â 94</li><li>Dick Starr 03/02/21 â 94</li><li>George Elder 03/10/21 â 94</li><li>Neil Berry 01/11/22 â 92</li><li>Johnny Hetki 05/12/22 â 93</li><li>Jim Rivera 07/22/22 â 93</li><li>Tom Wright 09/22/23 â 92</li><li>Billy DeMars 08/26/25 â 90</li><li>Ned Garver 12/25/25 â 90</li><li>Frank Saucier 05/28/26 â 89</li><li>Johnny Groth 07/23/26 â 89</li><li>Ed Mickelson 09/09/26 â 89</li><li>Roy Sievers 11/18/26 â 89</li><li>Hal Hudson 05/04/27 â 88</li><li>Al Naples 08/29/27 â 88</li><li>Billy Hunter 06/04/28 â 87</li><li>Joe DeMaestri 12/09/28 â 87</li><li>Don Larsen 08/07/29 â 86</li><li>J.W. Porter 01/17/33 â 82</li></ol>' 2166 }, 2167 { 2168 title: "Celebrating 64th Anniversary of the Smallest Professional (?) Baseball Player Ever", 2169 slug: "celebrating-64th-anniversary-of", 2170 date: "August 20, 2015", 2171 excerpt: "It was August 19, 1951 when Eddie Gaedel stepped up to the plate as a pinch hitter for Frank Saucier. Today we have Eddie Gaedel Societies popping up around the country recognizing short people.", 2172 images: { 2173 news: "/images/blog/browns-news-keefe.jpg", 2174 article: "/images/blog/browns-article-keefe.jpg" 2175 }, 2176 body: '<p>Pictured here is Bill Rogers, President of the St. Louis Browns Historical Society and Emmett McAuliffe, VP of the Organization. While not short in physical size, they say they are short of money. Who isn’t?</p><div class="image-list"><div class="image"><img src="/images/blog/rogers-mcauliffe.jpg" alt="Bill Rogers and Emmett McAuliffe"></div></div><p>Pictured in the outset at top left is Tom Keefe, founder of the Eddie Gaedel Society, preaching the gospel about Eddie Gaedel.</p><p>There is one surviving member of this 1951 event, Frank Saucier. Frank is pictured on the Browns luncheon flyer and can be seen at: <a href="http://2015browns.blogspot.com" target="_blank">http://2015browns.blogspot.com</a>.</p>' 2177 }, 2178 { 2179 title: "Browns Lose Another Member of History", 2180 slug: "browns-lose-another-member-of-history", 2181 date: "August 19, 2015", 2182 excerpt: "Bud Thomas, 86, passed away on August 15, 2015 in Sedalia, MO. Bud had a short-lived career for the Browns playing in just one season in 1951.", 2183 images: { 2184 news: "/images/blog/browns-news-bud-thomas.jpg", 2185 article: "/images/blog/browns-article-bud-thomas.jpg" 2186 }, 2187 body: '<p>Although his time was brief, Bud hit .350 in 20 at bats for the ’51 team.</p><p>Bud was born in Sedalia in 1929 and was selected by the Browns in the amateur draft in 1947 after then owner Bill Veeck saw him perform at Yankee Stadium under the tutelage of Ty Cobb and Babe Ruth. Although he had an abbreviated career in baseball, he touched many lives during his career as a teacher, principal and school administrator. Give your thoughts and prayers to the Thomas family.</p>' 2188 }, 2189 { 2190 title: "Rugger Ardizoia, 95, Made Lone Big League Appearance at Sportsman's Park in '47", 2191 slug: "rugger-ardizoia-95-made-lone-appearance", 2192 date: "July 21, 2015", 2193 excerpt: "Pitcher Mopped Up 15-5 Loss to Muddy Ruel's Browns*", 2194 images: { 2195 news: "/images/blog/browns-news-ardizoia.jpg", 2196 article: "/images/blog/browns-article-ardizoia.jpg" 2197 }, 2198 body: '<p>Gave Up 2-Run Homer to Fellow San Franciscan and Iwo Jima ‘Teammate’ Wally Judnich.</p><p>Yankee Was One of Only 7 Players in Major League History Born in Italy.</p><p><em>* There are no surviving members of the 1947 Browns. The last survivor, John Lester “Les” Moss, died August 29, 2012.</em></p>' 2199 }, 2200 { 2201 title: 'Cubs Manager Maddon: "Browns were more popular than Cardinals"', 2202 slug: "cubs-manager-maddon-browns-were-more", 2203 date: "June 28, 2015", 2204 excerpt: "Chicago Cubs manager Joe Maddon was discussing with MLB Network the tenacity of Central-division rivals the St. Louis Cardinals and felt the need to name-check the Browns.", 2205 images: { 2206 news: "/images/blog/browns-news-maddon.jpg", 2207 article: "/images/blog/browns-article-maddon.jpg" 2208 }, 2209 body: '<p>Keep the name alive Joe! I wonder if he would want to take our fan club membership <a href="/#/membership">pledge</a>?</p><p>Read Joe’s Browns comment at: <a href="http://m.mlb.com/news/article/122414962/mike-bauman-no-adam-wainwright-no-problem-for-determined-cardinals" target="_blank">http://m.mlb.com/news/article/122414962/mike-bauman-no-adam-wainwright-no-problem-for-determined-cardinals</a></p>' 2210 }, 2211 { 2212 title: "Present-day Cardinals Slugger Has Browns Family Roots", 2213 slug: "present-day-cardinals-slugger-has", 2214 date: "June 28, 2015", 2215 excerpt: "When recent AAA call-up Greg Garcia hit his first major-league homerun Friday night, a pinch-hit job, most fans probably did not realize that Garcia comes from a fam
2215ily with deep baseball roots", 2216 images: { 2217 news: "/images/blog/browns-news-garcia.jpg", 2218 article: "/images/blog/browns-article-garcia.jpg" 2219 }, 2220 body: '<p>... that all started with the St. Louis Browns in 1937.  The 24-year old infielder’s 94-year old grandfather, <strong>Dave Garcia Sr.</strong>,  was an infielder signed by the St. Louis Browns as a 16-year-old in 1937.</p><p>The elder Garcia, well and active at age 94 living in San Diego, spent a lifetime in baseball as a manager, coach and scout. He has watched every living Hall of Famer from the dugout or the field. He was a minor league teammate of Ty Cobb Jr. <a href="http://www.nytimes.com/2009/05/03/sports/baseball/03garcia.html" target="_blank">A semi-recent New York Times article on Dave.</a></p><div class="image-list"><div class="image"><img src="/images/blog/browns-article-garcia.jpg" alt="Dave Garcia Sr."></div><div class="image"><img src="/images/blog/059f40ab_mlbam.jpg" alt="Greg Garcia" width="212" height="320"></div></div>' 2221 }, 2222 { 2223 title: "When the Browns Weren't the Browns: Alternate Nicknames, 1902-1953", 2224 slug: "when-browns-werent-browns-alternate", 2225 date: "June 28, 2015", 2226 excerpt: "If you go back into the early days of baseball, team nicknames were more informal than they are today. Indeed many fans took to calling their team what their favorite newspaper called them.", 2227 images: { 2228 news: "/images/blog/browns-news-raven.jpg", 2229 article: "/images/blog/browns-article-raven.jpg" 2230 }, 2231 body: '<p>Although “the Browns” was the official nickname of the franchise beginning in 1902, a few other names popped up, even one that appeared to be official.</p><p>According to <em>Baseball Team Names: A Worldwide Dictionary, 1869-2011</em>, “In the era 1890-1910, some teams received bird nicknames based on their stocking color, i.e. Blackbirds, Bluebirds, Blue Jays, Cardinals, Crows, Doves, Ravens and Redbirds.” In 1905 and 1906, according to this book, the Browns were actually officially called <em>the Ravens</em>.</p><p>Through 1909 some newspapers took to referring to the team as the <em>Macaleerites, </em>after the team’s inaugural manager, Jimmy McAleer.</p><p>In 1928 the Sporting News Guide referred to the Browns as <em>Howley’s Sensations</em>. Dan Howley was the manager of the 1928 team and indeed he seemed to have started the Browns on something of an uptick after the short and futile managerial reign of player-manager George Sisler.</p><p>In 1939, the year the Browns set a franchise record for lowest winning percentage which still stands, they were apparently referred to as the <em>Little Brownies</em>.</p><p>In 1944 the Browns only pennant spurred an explosion of journalistic creativity: <em>Cinderella Boys, Cinderella Brownies, Rags-to-Riches Boys, Sackcloth Brownies, </em>and <em>Sewell’s Wonders. </em>And add to the list<em>Sewellmen</em> which I personally have seen in the 1944 <em>Sporting News</em>.</p><p> All in all, the “St. Louis Americans” suffered through much less nickname identity crisis than did other franchises of the time (see Brooklyn, Cleveland, Boston N.L., Philadelphia N.L. e.g.).</p>' 2232 }, 2233 { 2234 title: "Francona Missed High School Graduation to Report to Browns", 2235 slug: "francona-missed-high-school-graduation", 2236 date: "June 13, 2015", 2237 excerpt: "John Patsy “Tito” Francona was inducted this week in the Western Pennsylvania Interscholastic Athletic League Hall of Fame.", 2238 images: { 2239 news: "/images/blog/browns-news-tito-francona.jpg", 2240 article: "/images/blog/browns-article-tito-francona.jpg" 2241 }, 2242 body: '<p>At that banquet, Tito told a story about the circumstances of his being signed by the St. Louis Browns in 1952. It seems he signed with the Browns the very day before he graduated high school. And baseball - and the Browns’ management - proved to be a harsh mistress.</p><p><em>He was ordered to skip graduation ceremonies and report directly to the Browns’ Class B farm team!</em></p><p>The decision to forgo cap-and-gown and don pinstripes was a good one for Tito. He went on to have a successful major-league career as a first baseman-outfielder including being elected by Cleveland baseball writers as the 1959 Man of the Year, and an appearance in the second 1961 All-Star game.</p><p>Tito played two years in the Browns farm system before the team was sold to Baltimore: one year with the <strong>York White Roses</strong> and one year with the <strong>Aberdeen Pheasants</strong>. At Aberdeen, Tito met his future wife, a local girl named Roberta Jackson. <strong>Terry Francona</strong>, their son and current manager of the Cleveland Indians, was born in Aberdeen in 1959.</p><p>Here is a scorecard featuring Tito as an Aberdeen Pheasant. Note that <strong>Roger Maris</strong> (misspelled Maras), is in the lineup that day as a right-fielder for the <strong>Fargo-Moorhead Twins</strong>.</p><div class="image-list"><div class="image"><img src="/images/blog/aberdeen-pheasants.jpg" alt=""></div><div class="image"><img src="/images/blog/aberdeen-pheasants-2.png" alt=""></div></div><p>The Western Pennsylvania Interscholastic Athletic League was founded in 1907 for high school sports. Its Hall Of Fame includes <strong>Stan Musial</strong> and<strong>Arnold Palmer</strong>.</p><p>Other famous Aberdeen Pheasants that later came up to be major leaguers include <strong>Don Larsen, Bob Turley, Don Lenhardt, Perry Currin</strong> (all very recent attendees at the annual St. Louis Browns Fan Club and Historical Society banquet) and <strong>Blackie Schwamb</strong>.</p><p>Although Tito did not make it up to the big leagues in time to be a Brownie, he did eventually make it to Sportsman’s Park as a St. Louis Cardinal. Tito also played with Baltimore, Cleveland, Chicago (AL), Detroit, Atlanta, Philadelphia, Oakland and Milwaukee.</p><h3>Tito Trivia</h3><ul class="bulleted"><li>was traded twice for the same player: Larry Doby. Once by the Orioles, and once by the Tigers.</li><li>shares the record (with Paul Baka) of being the player who played in the most contiguous states. Francona played for teams in seven contiguous states: MO, IL, WI, MI, OH, PA, MD.</li><li>is the only player signed by the Browns to have played into the 1970s.
2242</li></ul><p>Read more: <a href="http://triblive.com/sports/hssports/otherhighschoolsports/8542448-74/wpial-francona-basketball#ixzz3cyUWtJcO" target="_blank">http://triblive.com/sporas a member of the St. Louis Cardinals ts/hssports/otherhighschoolsports/8542448-74/wpial-francona-basketball#ixzz3cyUWtJcO</a></p>' 2243 }, 2244 { 2245 title: "Bitsy parade is big on spunk", 2246 slug: "bitsy-parade-is-big-on-spunk", 2247 date: "June 10, 2015", 2248 excerpt: "Dozens gathered around the Tiny Bar on Locust Street to witness the self-proclaimed "world's tiniest parade" to honor the 90th birthday of former Browns player Eddie Gaedel.", 2249 images: { 2250 news: "/images/blog/browns-news-gaedel.jpg", 2251 article: "/images/blog/browns-article-gaedel.jpg" 2252 }, 2253 body: '<p><strong>(The following story appeared on the front page of the June 10, 2015 <i>St. Louis Post-Dispatch</i>. The Browns are finally front-page news, 61 years after their last season).</strong></p><p>by Jack Witthaus of the St. Louis Post-Dispatch staff</p><p><strong>ST. LOUIS </strong> Emmett McAuliffe remembers exchanging baseball cards with an older kid in Creve Coeur in the 1960s and happening upon one from the Browns.</p><p>He couldn’t believe it. There was another baseball team in St. Louis besides the Cardinals? Immediately, the team’s colors, losing tendencies and elf logo mystified him.</p><p>Now, McAuliffe, [an officer in the St. Louis Browns Fan Club,] collects hats and other gear from the Browns. On Monday, he donned a milky white Browns jersey and a bow tie as he told stories about the team’s history.</p><p>McAuliffe was among dozens gathered Monday night around the Tiny Bar on Locust Street to witness the self-proclaimed "world’s tiniest parade" to honor the 90th birthday of former Browns player Eddie Gaedel.</p><p>The parade featured a Smart car, a float in a child-size wagon pulled by child, a toy dog, a one-man band and the world’s smallest horse, Thumbelina. Led by Mayor Francis Slay, the 1/8th-block-long parade started and ended in minutes. Attendees broke into applause when the parade halted at the entrance of the Tiny Bar.</p><p>Parade organizer Aaron Perlut — a founding partner of Elasticity, a digital marketing and public relations firm at 1010 Locust Street — helped open the Tiny Bar on May 27. Perlut said the 250-square-foot establishment is used to celebrate the "little guy" in a world that often cherishes huge things.</p><p>At 3 feet, 7 inches, Gaedel was the shortest Major League Baseball player ever to record an at-bat. During his August 1951 debut, Gaedel walked on four straight pitches. Then-Browns owner Bill Veeck signed Gaedel as a part of a stunt. Gaedel died in 1961 at the age of 36.</p><p>A large Gaedel mural greets guests who enter the Tiny Bar, and his name is part of the bar’s Wi-Fi password. "He’s the patron saint," Perlut said.</p><p>Although the city issued a permit for Monday’s little celebration, Cindy Riordan, executive assistant to the director of streets, said the streets department didn’t call the "tiny parade" a parade for permit purposes. Due to the small size, the parade was dubbed a "special event." Riordan said people who apply for parade permits generally do not ask to hold parades less than a block long.</p><p>"It’s definitely the smallest one anyone’s called a parade," she said, noting that it might have been the shortest one in St. Louis history.</p><p>Travis Sheridan operated the 2010 yellow Smart car that was in the parade. He said he liked the atmosphere of the event. Music played while attendees milled around and ate birthday cake.</p><p>Sheridan said St. Louis might have an inferiority complex, but it shouldn’t see itself as little. Small events like Monday’s parade make Sheridan, a friend of Perlut’s, optimistic about the future of the city that he moved to about three years ago.</p><p>"People doing tiny things can have a big impact for St. Louis," Sheridan said.</p>' 2254 }, 2255 { 2256 title: "Marlin's Dee Gordon Chasing Feat Done Only by Cobb, Wagner and Browns' George Sisler.", 2257 slug: "marlins-dee-gordon-chasing-feat-done", 2258 date: "May 30, 2015", 2259 excerpt: "The Miami Marlins' Dee Gordon is chasing this year a feat that has only been accomplished by the Uber-Hall of Famers Ty Cobb, Honus Wagner and Brownie George Sisler.", 2260 images: { 2261 news: "/images/blog/browns-news-george-sisler.jpg", 2262 article: "/images/blog/browns-article-george-sisler.jpg" 2263 }, 2264 body: '<p>That feat is leading the major leagues in both batting average and stolen bases.</p><div class="image-list"><div class="image"><img src="/images/blog/dee-gordon.png" alt="Dee Gordon"></div></div><div class="image-list"><div class="image"><img src="/images/blog/browns-article-george-sisler.jpg" alt="George Sisler"><div class="caption medium">George Sisler</div></div><div class="image"><img src="/images/blog/honus-wagner.jpg" alt="Honus Wagner"><div class="caption medium">Honus Wagner</div></div><div class="image"><img src="/images/blog/ty-cobb.jpg" alt="Ty Cobb"><div class="caption medium">Ty Cobb</div></div></div><p>
2264Good luck to Dee! <a href="http://www.nytimes.com/2015/05/31/sports/baseball/marlins-gordon-tries-to-match-notable-names-cobb-sisler-snuffy-stirnweiss.html?_r=0" target="_blank">http://www.nytimes.com/2015/05/31/sports/baseball/marlins-gordon-tries-to-match-notable-names-cobb-sisler-snuffy-stirnweiss.html?_r=0</a></p>' 2265 }, 2266 { 2267 title: "75 Years-Ago: First Pro Baseball Game Under the Lights in St. Louis", 2268 slug: "75-years-ago-first-pro-baseball-game", 2269 date: "May 24, 2015", 2270 excerpt: "Browns vs. Indians (and Bob Feller), Attendance. 24,827", 2271 images: { 2272 news: "/images/blog/browns-news-night-baseball.jpg", 2273 article: "/images/blog/browns-article-night-baseball.jpg" 2274 }, 2275 body: '<p>Since the Browns owned the stadium, they got the honors of hosting the first night game. (The Cardinals first was on June 4, and drew only 23,500.)</p><p><a href="http://www.baseball-reference.com/boxes/SLA/SLA194005240.shtml" target="_blank">http://www.baseball-reference.com/boxes/SLA/SLA194005240.shtml</a></p><div class="image-list"><div class="image"><img src="/images/blog/browns-article-night-baseball.jpg" alt=""></div></div>' 2276 }, 2277 { 2278 title: "Lookee down by the train depot! I do declare, the St. Louis Browns are passing through our lil' ol' town!", 2279 slug: "lookee-down-by-train-depot-st-louis", 2280 date: "May 7, 2015", 2281 excerpt: "100 years ago this week, the <em>Daily Journal-Gazette</em> of Mattoon, Ill., reported in their April 30 edition:", 2282 images: { 2283 news: "/images/blog/browns-news-branch-rickey.jpg", 2284 article: "/images/blog/browns-article-branch-rickey.jpg" 2285 }, 2286 body: '<p>MATTOON — The St. Louis Browns baseball club of the American League will pass through Mattoon on the Big Four Railroad the morning of May 2.</p><p>I shall leave it to our readers in the railroad buff community to explain the details of the Big Four Railroad (the name popularly given to the Central Pacific Railroad, a/k/a the first transcontinental railroad).*</p><p>The Browns were finishing up a road trip in Cleveland and heading home to St. Louis to begin a homestand Tuesday. <strong>Robert Lee Hedges</strong>, the original owner of the Browns is still owner for one last year. Still on the team is Hall of Famer <strong>Bobby Wallace</strong>, who goes all the way back to the St. Louis Perfectos (they of <a href="http://www.vivaelbirdos.com/2015/5/5/8551277/the-st-louis-perfectos-and-the-birth-of-modern-baseball" target="_blank">“best opening record in franchise history fame”</a>). <strong>Branch Rickey</strong> is the manager. The Browns are stagnant in 8th place.</p><p>You can peruse other stories noted on April 30, 1915, courtesy of the <em>Mattoon Journal Gazette and Times-Courier</em> <a href="http://jg-tc.com/news/opinion/glancing-back-april--may/article_37f98a07-c319-57fd-bd47-9828b340d1d0.html" target="_blank">website</a>.</p><p>I would note three things:</p><ol class="bulleted"><li>The daily newspaper was the thing, not twitter. But the amount of minutia is roughly the same.</li><li>The Browns are in last place, but simply being part of the “Big 8 teams” of any one of the three major leagues operating at the time, was, at least by Mattoon standards, an attraction.</li><li>Not sure if there is a freight rail-line still passing through Mattoon, but look at how amazingly straight-arrow it is to pass over there “as the crow flies” from Cleveland to St. Louis.</li></ol><div class="image-list"><div class="image"><img src="/images/blog/map-stlouis-to-cleveland.png" alt="Google Maps route from St. Louis, MO to Cleveland, OH via airplane"></div></div><p>If you went by Amtrak today, you would have to go through Chicago; if you drove, through Effingham.</p><p><em>* Though I can’t resist pointing out that the railroad had its origins with a bill introduced by Senator Thomas Hart Benton of Missouri for a “Great National Highway from St. Louis to the Pacific Ocean, straight as may be, with branches to Oregon and Mexico. The Government was to reserve a strip one mile wide for it, so as to provide for every kind of a road and means of conveyance â railway, plank, macadamized, with railroad trains, wagons, stages, pack trains and even sleds in Winter.”</em></p>' 2287 }, 2288 { 2289 title: "The One-Month Brown", 2290 slug: "the-one-month-brown", 2291 date: "March 25, 2015", 2292 excerpt: "My Way, a new book by Colin Gunderson about Tommy Lasorda, chronicles the life of one of the greatest managers and personalities in baseball history.", 2293 images: { 2294 news: "/images/blog/browns-news-lasorda.jpg", 2295 article: "/images/blog/browns-article-lasorda.jpg" 2296 }, 2297 body: '<p>The book leads you on a journey through time as Gunderson takes you from Tommy’s upbringing in Norristown, Pennsylvania to his continued service as an admirable baseball ambassador with the Dodgers. However, for a one-month period in 1953, Tommy was destined to be a starting pitcher for the St. Louis Browns.</p><p>Prior to the Browns final season in St. Louis in 1953, Bill Veeck acquired Lasorda for $50,
2297000 from the Brooklyn Dodgers. Convinced that he was going to be able to move the team to Baltimore, Veeck began acquiring talent in anticipation of the move and the $2 million he was promised once he landed in Baltimore. But at this point, Veeck has made too many enemies throughout the league and his continual attempts to move were blocked by other owners determined to force him to sell the team. So, Veeck was obliged to return Lasorda back to the Dodgers during spring training.</p><p>Lasorda would go on to a dubious major league playing career followed by a Hall of Fame managerial career with the Los Angeles Dodgers. Tommy brought championships to Los Angeles in 1981 and 1988 and has served as one of the Dodgers and baseball’s greatest champions. However, if not for financial issues and the hatred of Bill Veeck around the league, the man who famously said Dodger blue runs through his veins may, in fact, have bled brown.</p><p>Tommy was gracious enough to be the keynote speaker at the 2010 St. Louis Browns Historical Society luncheon. You can view his speech <a href="https://www.youtube.com/watch?v=GNamjlsXH6U" target="_blank">here</a> and also <a href="http://www.amazon.com/Tommy-Lasorda-Way-Colin-Gunderson/dp/1629370711" target="_blank">buy</a> his new book to learn more about the one-month Brown.</p>' 2298 }, 2299 { 2300 title: "St. Louis Browns Historical Society Unveils New Digital Experience", 2301 slug: "new-digital-experience", 2302 date: "March 4, 2015", 2303 excerpt: "Site brings forgotten franchise back to the forefront of baseball history", 2304 images: { 2305 news: "/images/blog/browns-news-generic2.jpg", 2306 article: "/images/blog/browns-article-generic2.jpg" 2307 }, 2308 body: '<p>ST. LOUIS — As the Orioles embark on their 62nd season after abandoning St. Louis, The St. Louis Browns Historical Society, an organization dedicated to preserving the story and legacy of the St. Louis Browns baseball team, today announced the launch of its new website. St. Louis-based digital agency, HLK, developed the new site, <a href="www.thestlbrowns.com" target="_blank">www.thestlbrowns.com</a>.</p><p>“What the Browns lacked in the win column, they more than made up for with peculiar happenings and stunts on the diamond, as well as various, records that will never be broken,” said Emmett McAuliffe, Historical Society board member. “You could not write a Hollywood script better than what actually happened during the 52 years that this team tried to win games and attract fans on a shoestring budget.”</p><p>The Browns Historical Society celebrated the launch of the new site yesterday at Tiny Bar in downtown St. Louis, Mo. A photo from the event can be found at <a href="http://bit.ly/1H7ZkNb" target="_blank">http://bit.ly/1H7ZkNb</a> (from left to right: Joe Leahy, partner, HLK; Emmett McAuliffe, board member, Browns Historical Society; Bill Rogers, president, Browns Historical Society; and Eric Karlovic, partner, HLK).</p><p>Featuring an enhanced experience, the site includes a comprehensive overview of the franchise’s storied history, biographies and statistics on St. Louis Browns players, and information about the Society and its members.</p><p>“At HLK we believe, it is essential to preserve history through digital channels,” noted Eric Karlovic, partner at St. Louis-based digital agency HLK. “This site was designed in a meaningful storytelling style and experience that will appeal to existing fans and open an avenue to new audiences so the team and players are never forgotten.”</p><p>The site launch is the first tactic of a larger strategy for the Society to preserve and remember the St. Louis Browns history, as well as create interest and increase membership in the Society, including the introduction of new merchandise and a documentary, which are set to launch over the next year.</p><p>The Browns moved to St. Louis in 1902, after playing as the Milwaukee Brewers for only one season, joining the already established Cardinals franchise in a baseball-crazy town. Named the Browns by owners, Robert Lee Hedges and the Orthwein brothers, Ralph and Max, the team reopened Sportsman’s Park, which had previously served as home for the American Association St. Louis Browns (who one four-straight pennants). In the Browns’ 52 years in St. Louis, the team finished sixth or worse in the American League 33 times and had 41 losing seasons, making the phrase “St. Louis. First in shoes, first in booze, and last in the American League” popular among the locals.</p><p>Along with a losing record the franchise was often plagued with poor attendance, with the 1935
2308season only drawing 80,922 total fans to home games. The Browns had many memorable and notable players, and 13 future Hall of Famers would play for the club at one point in their careers, including George Sisler and Bobby Wallace.</p><p>The franchise played in the World Series only once, in 1944; however, this success did not come without criticism, as most clubs during the time had lost many of their best players to fight in World War II. The Browns lost the Series to the Cardinals, and within three years, the team was back to last place in the American League.</p><p>Following a string of short-lived owners, the Browns were sold to the colorful Bill Veeck, , who would stop at nothing to attract fans with creative promotions. For his first game as the team’s owner, Veeck offered all attendees a free beer or soda. Then, on August 19, 1951, Veeck had 3-foot-7-inch Eddie Gaedel, wearing a batboys’ uniform, pinch hit. Veeck took a $1,000,000 life insurance policy on Gaedel and threatened his life if he tried to swing at a pitch.</p><p>Although he had some valiant efforts, Veeck was unsuccessful in drawing a crowd and eventually sold the team to a Baltimore attorney at the end of the 1953 season. The club played its last game in St. Louis to a crowd of only 3,174 fans before moving to Baltimore to become the Orioles.</p> <p>“It’s been over a century since the Browns played their first game in St. Louis, and the Historical Society is dedicated to keeping all of the great, and not so great, moments of the team’s history alive,” said Bill Rogers, president of the St. Louis Browns Historical Society. “We’re excited to give fans a new way to learn about and remember the Browns.”</p><h3>About the St. Louis Browns Historical Society</h3><p>The St. Louis Browns Historical Society and Fan Club is an organization dedicated to preserving every stat and story of the franchise, so that the history of baseball’s most intriguing underdogs can continue to entertain fans. To learn more about the Browns history, players or to become a member of the Society, visit <a target="_blank" href="www.thestlbrowns.com">www.thestlbrowns.com</a>.</p><h3>About HLK</h3><p>HLK is a full-service digital agency driven to create authentic brand experiences. Active clients include Ameren, Nestle Purina, Monsanto, On The Run, Germ-X, St. Louis Cardinals, MapQuest, St. Patrick Center and Webster University.</p>' 2309 }, 2310 { 2311 title: "Hank Peters, Baseball Executive, Died January 4, 2015 ", 2312 slug: "hank-peters", 2313 date: "January 5, 2015", 2314 excerpt: "Henry J. “Hank” Peters began his career after answering an ad from the St. Louis Browns, eventually working his way up to the scouting department.", 2315 images: { 2316 news: "/images/blog/browns-news-hank-peters.jpg", 2317 article: "/images/blog/browns-article-hank-peters.jpg" 2318 }, 2319 body: '<p>When the team moved to Baltimore after the 1953 season, Peters declined to make the move and subsequently joined the front office of the <a target="_blank" href="http://en.wikipedia.org/wiki/Oakland_Athletics">Kansas City Athletics</a>.</p><p>During more than a decade with the franchise, Peters would eventually direct the team’s scouting and minor league system in the mid-1960s under owner <a target="_blank" href="http://en.wikipedia.org/wiki/Charlie_Finley">Charlie Finley</a>. He held the title of <a target="_blank" href="http://en.wikipedia.org/wiki/General_manager_(baseball)">general manager</a> of the Athletics during the <a target="_blank" href="http://en.wikipedia.org/wiki/1965_Major_League_Baseball_season">1965</a> season.</p><p>Peters joined the <a target="_blank" href="http://en.wikipedia.org/wiki/Cleveland_Indians">Cleveland Indians</a> following the 1965 campaign as director of player personnel and assistant general manager to <a target="_blank" href="http://en.wikipedia.org/wiki/Gabe_Paul">Gabe Paul</a> for the remainder of the 1960s through 1971. He then served as the sixth president in the history of the National Association of Professional Baseball Leagues, the umbrella group that governs <a target="_blank" href="http://en.wikipedia.org/wiki/Minor_league_baseball">minor league baseball</a>, from 1972 to 1975, president and general manager of the Orioles from 1975 to 1987, and president of the Indians from 1987 to 1991.</p><p>As Orioles’ general manager, he kept the team competitive in the tough American League <a target="_blank" href="http://en.wikipedia.org/wiki/American_League_East_Division">East Division</a>, and won AL pennants in <a target="_blank" href="http://en.wikipedia.org/wiki/1979_Major_League_Baseball_season">1979</a> and <a target="_blank" href="http://en.wikipedia.org/wiki/1983_Major_League_Baseball_season">1983</a>, as well as the <a target="_blank" href="http://en.wikipedia.org/wiki/1983_World_Series">1983</a> World Series.</p><p>Prior to his baseball career, Peters served in the United States Army during World War II. He died of complications from a stroke in <a target="_blank" href="http://en.wikipedia.org/wiki/Boca_Raton,_Florida">Boca Raton, Florida</a> on January 4, 2015, aged 90.</p>' 2320 }, 2321 { 2322 title: "He Threw Games for Gamblers Yet He Still Holds Record for Most Innings Pitched Without Allowing a Home Run", 2323 slug: "he-threw-games-for-gamblers", 2324 date: "December 29, 2014", 2325 images: { 2326 news: "/images/blog/browns-news-joe-blong.jpg", 2327 article: "/images/blog/browns-article-joe-blong.jpg" 2328 }, 2329 excerpt: "We present now for your amusement, the curious case of one Joe Blong. St. Louis Brown Stockings right-handed pitcher, St. Louis native, son of Irish immigrants, and University of Notre Dame alumnus.", 2330 body: '<p>He holds the major league record for most innings pitched without allowing a home run in a career (320.1 innings). But it also seems he had a nasty habit of throwing games, “hippodroming”
2330 as the newspapers of the day colorfully called it, and was kicked out of baseball for it not once but twice.</p><p>When Joe and two other Browns teammates were kicked out of baseball and blacklisted from all respectable leagues in November 1877, it was curtains for repeat-offender Blong. How do you develop a reputation for throwing games and still hold a positive record that lasts forever? Perhaps he had so much pitching control that he was able to serve up only singles and doubles so that it did not look too obvious that he was throwing a game? In that case, still remarkable control for a pitcher.</p><p>The modern record is quite a ways off from Blong’s mark: (269.1 Greg Minton, San Francisco Giants reliever - June 1, 1979 through May 1, 1982), symptomatic of home runs that happen about 8 times as often as they did in the eighteen seventies. But nonetheless even if someday someone surpasses 320.1 innings, it is not likely to represent the entire career of that pitcher. Organized baseball did not know what a favor they were doing for Joe when they expelled him in 1877: bestowing him with an almost impossible record of pitching an entire career, consisting of more than 300 innings, without giving up a home run.</p><p>Blong is buried in Calvary Cemetery in north St. Louis.</p><p>p.s. for Notre Dame fans, one of Blong’s partners in crime was the unfortunately named ballplayer Trick McSorley, his classmate at Notre Dame.</p><p>Here is the account from <a href="http://thisgameofgames.blogspot.com/2007/09/joe-blong.html" target="_blank">This Game of Games</a> blog.</p>' 2331 }, 2332 { 2333 title: "St. Louis Browns Were Colorful", 2334 slug: "st-louis-browns-were-colorful", 2335 date: "December 9, 2014", 2336 images: { 2337 news: "/images/blog/browns-news-branch-rickey.jpg", 2338 article: "/images/blog/browns-article-branch-rickey.jpg" 2339 }, 2340 excerpt: "Major League Baseball fans in Illinois are divided into several camps. Cardinals fans rule the south, while White Sox fans creep in farther north. The Cubs have a strong base statewide. Sixty years ago, there was another, more interesting choice.", 2341 body: '<p>Until 1953, St. Louis was home to two teams, the National League‘s Cardinals as well as the Browns of the American League. Though the Browns lost a bundle of games over the decades, they left a legacy of some of baseball’s most colorful moments.</p><p>The Browns opened play in St. Louis in 1902, a year after the founding of the American League, when the last-place Milwaukee franchise moved to the Gateway City after only one season. They were named for the color of their uniforms, which were replete with brown trim. The name also had been an early moniker of the other team in town, the Cardinals, before the turn of the century.</p><p>The Browns finished second at 78-58 in that inaugural season, which was not a sign of things to come. In their 52 years in St. Louis, the Browns finished first once, second twice and sixth or worse 33 times. Their ineptitude gave rise to the saying, “St. Louis. First in shoes, first in booze and last in the American League.”</p><p>Despite their struggles, the Browns never lacked for color. The team gave rise to the brilliant career of Branch Rickey, who came to St. Louis in 1913 from a successful stint as head baseball coach at the </p><p>University of Michigan. Rickey later moved across town and built the first minor-league farm system, which helped the Cardinals win four World Series titles before he left in 1942 for Brooklyn. There, he introduced Jackie Robinson, the first African-American to play in the major leagues.</p><p>“The owner of the Browns at the time did not recognize Rickey’s value,” said Bill Rogers, of St. Louis, who has researched the Browns extensively. “Had Rickey stayed on, I think things would have turned out much differently.”</p><p>Rickey also is responsible for the player that many believe was the greatest in Browns history. First baseman George Sisler was a former Michigan star who batted .420 with 51 stolen bases and 105 RBIs in 1922 to lead the Browns to a 93-61 record, their best ever. Sisler batted .340 in a 15-year major league career, 12 with the Browns. He was elected to the Baseball Hall of Fame in 1939.</p><p>Poor attendance was a recurring theme in Browns history. The 1935 team drew 80,922 fans for the entire season, and the Great Depression was not entirely to blame. St. Louis never won more than 67 games in a 154-game season at any point in the 1930s and was a miserable 43-111 in 1939.</p><p>Finally, the Browns broke through in 1942, finishing third at 82-69 under manager Luke Sewell.</p><p>With a strong pitching staff and a formidable infield, St. Louis was primed for a run. In 1944, they remained in contention for most of the season and swept a season-ending, four-game series against the Yankees at home to capture the pennant with an 89-65 mark.</p><p>Ironically, their World Series opponents were their crosstown rivals, the Cardinals. Since the early 1920s, the Browns actually had been the Cardinals’ landlords as the owners of Sportsmans’ Park. Unfortunately for the Browns, they had to suffer as the Cardinals rose to the top of the National League and routinely outdrew their counterparts at the box office.</p><p>The Browns jumped to a 2-1 Series lead, but the Cardinals won the last three to clinch in six games. “The Series appearance was a tremendous shot in the arm for the Browns,” said Rogers. “But in St. Louis, the fans of one team did not like the other team. Even Stan Musial remarked about that once.”</p><p>The Browns nearly repeated in 1945, but were eliminated from the pennant race on the last day of the season. That year, the star attraction for the Browns was Pete Gray, a one-armed outfielder who batted .218 in 77 games in his sole major league season.</p><p>For most of their existence, the Browns were financially strapped, and often had to sell off star players simply to keep afloat. After their glorious run of the mid-1940s, many top players were sold for needed cash, and the team fell into steep decline.</p><p>“I hate to say it, but I think the Browns were often mismanaged,” remarked Rogers. “That put them in a financial bind often, and they had to trade or sell their best players to cover expenses.”</p><p>However, there were plenty of memorable episodes. Many were courtesy of the flamboyant Bill Veeck, who bought the team in 1951 from an ownership tandem including Bill DeWitt, whose son is a current Cardinals’ team owner. Veeck challenged the Cardinals head on with a series of wacky promotions.</p><p>Soon after buying the team, Veeck signed Eddie Gaedel, a three-foot-seven-inch midget to a one-day contract and sent him up to bat in the second game of an Aug. 19, 1951, doubleheader against Detroit. Wearing the number “1/8" and creating a strike zone of a mere inch-and-a-half, Gaedel walked on four pitches.</p><p>Six days later, the Browns hosted “Grandstand Manager’s Night,” in which fans were allowed to make on-field decisions. Manager Zack Taylor held up signs such as “Should the Browns Bunt?,” “Take Out the Pitcher?” and “Steal?,” while spectators held signs replying “Yes” or “No.” The Browns knocked off the Philadelphia A’s 5-3 that night, a highlight for a squad that went 52-102.</p><p>Still, many of the players preferred playing for the Browns than the other team in town. Though the Cardinals never finished lower than second from 1941-49, many Browns were happier with their cellar-dwelling franchise. In an interview for a 2000 book, Don Gutteridge, a former Cardinal who was the Browns’ second baseman through their 1940s heyday, said that “the Cardinals were always pinching pennies. The Browns were a better club to play for than the Cardinals.”</p><p>Some of the later Browns are among the franchise’s most recognizable names. They include the legendary Satchel Paige, who won 12 games at age 46 in 1952, as well as righthander Ned Garver, who won 20 games in 1951. Garver is one of 23 surviving Browns players today, a list that includes Ottawa native Ed Mickelson, who saw action in seven games for the Browns in 1953 and is said to have driven in the final run in Browns history.</p><p>Mickelson, now 88, played in a total of 18 Major League games over three seasons with the Browns, White Sox and Cardinals and later wrote a memoir of his 11 seasons in pro ball, mostly in the minors.</p><p>Another surviving ex-Brown is Don Larsen, a St. Louis rookie in 1953. Three years later, he tossed a perfect game for New York in the 1956 World Series.</p><p>When the Cardinals were sold to Anheuser-Busch in December 1952, Veeck realized he could no longer survive against a larger-budget rival. His tumultuous run as Browns’ owner came to an end when he sold the team after the 1953 season. The franchise moved to Baltimore and became the Orioles.</p><p>Sixty years later, the Browns are hardly forgotten. In 1984, the St. Louis Browns Fan Club was founded and now numbers 370 members. The club holds an annual banquet, publishes an in-house magazine and offers a line of collectibles.</p><p>“Interest in the Browns is extremely high,” said Rogers, the president of the club. “Even though only 23 Browns survive, there are tens of thousands of fans left. Even younger people have experienced the Browns through the memories of their parents and grandparents. Like one person said to me, ‘we can’t bring back the Browns, but we can at least keep their memory alive.’ ”</p>' 2342 } 2343 ] 2344 } 2345} 2346 2347module.exports = Data; 2348 2349},{}],3:[function(require,module,exports){ 2350 2351var Router = require('./Router');
2352var ViewManager = require('./ViewManager'); 2353var ViewMediator = require('./ViewMediator'); 2354 2355function Application( descriptor ) { 2356 2357 if( !( this instanceof Application ) ) 2358 return new Application( descriptor ); 2359 2360 this.settings = descriptor; 2361} 2362 2363Application.prototype = { 2364 2365 init: function() { 2366 2367 var s = this.settings; 2368 2369 if( s === undefined ) 2370 throw new Error( 'You must define a settings object at initialization' ); 2371 2372 if( s.routes === undefined ) 2373 throw new Error( 'You must define routes in your settings object' ); 2374 2375 s.autoResize = s.autoResize === undefined ? true : s.autoResize; 2376 2377 this.onRouteCallback = s.onRoute; 2378 s.routes.onRoute = this.show.bind( this ); 2379 this.router = Router(s.routes); 2380 2381 this.vm = ViewManager( this.settings ); 2382 2383 if( s.autoResize ) { 2384 2385 window.addEventListener( 'resize', this.onResize.bind( this ) ); 2386 window.addEventListener( 'orientationchange', this.onResize.bind( this ) ); 2387 this.onResize(); 2388 } 2389 2390 if( s.initSection ) { 2391 this.show( s.initSection.bind( undefined, this.router.init.bind( this.router ) ) ); 2392 } else { 2393 this.router.init(); 2394 } 2395 }, 2396 2397 show: function( content, data ) { 2398 2399 if( this.onRouteCallback ) 2400 this.onRouteCallback( content, data ); 2401 2402 if( Array.isArray( content ) ) { 2403 2404 var contents = []; 2405 2406 for( var i = 0, l = content.length; i < l; i ++ ) { 2407 2408 if( typeof content[ i ] == 'object' ) { 2409 contents[ i ] = content[ i ]; 2410 } else if( typeof content[ i ] == 'function' ) { 2411 contents[ i ] = new content[ i ]; 2412 } 2413 } 2414 2415 this.doShow( ViewMediator.apply( undefined, contents ), data ); 2416 } else if( typeof content == 'object' ) { 2417 2418 this.doShow( content, data ); 2419 } else if( typeof content == 'function' ) { 2420 2421 this.doShow( new content, data ); 2422 } 2423 }, 2424 2425 doShow: function( content, data ) { 2426 2427 this.vm.show( content, data ); 2428 }, 2429 2430 resize: function( w, h ) { 2431 2432 this.vm.resize( w, h ); 2433 }, 2434 2435 onResize: function( w, h ) { 2436 2437 this.resize( window.innerWidth, window.innerHeight ); 2438 }, 2439 2440 go: function( to ) { 2441 2442 this.router.go( to ); 2443 } 2444} 2445 2446module.exports = Application; 2447},{"./Router":17,"./ViewManager":24,"./ViewMediator":25}],4:[function(require,module,exports){ 2448module.exports = ["images/about-photo-bill-borst.png","images/about-photo-bill-rogers.png","images/about-photo-emmett.png","images/about-photo-fred-heger.png","images/about-photo-stl-browns.png","images/about-photo-vicki-martin.png","images/about-stlsports-hof.png","images/arrow-left.png","images/arrow-right.png","images/bg-blog-post-border.jpg","images/bg-border-h.jpg","images/bg-border-v.jpg","images/bg-input.png","images/bg-nav-icon-1-dark.png","images/bg-nav-icon-1.png","images/bg-overlay.png","images/bg-players-controls.png","images/bg-social-email.png","images/bg-social-facebook.png","images/bg-social-twitter.png","images/cards-badge.png","images/hof-badge.png","images/home-text.png","images/icn-facebook-hover.png","images/icn-facebook.png","images/icn-nav-dark.png","images/icn-nav.png","images/icn-twitter-hover.png","images/icn-twitter.png","images/icn-youtube-hover.png","images/icn-youtube.png","images/img-footer-logo.png","images/img-intro-icon.png","images/main-dark.jpg","images/main-light-large.jpg","images/main-light.jpg","images/member-level-bleed-brown.png","images/member-level-gold.png","images/member-level-silver.png","images/type-dark.png","images/type.png"]; 2449},{}],5:[function(require,module,exports){ 2450 2451var $ = require('./DOM'); 2452var Class = require('./oop/Class'); 2453var Device = require('./Device'); 2454var Util = require('./Utils'); 2455var Velocity = require('velocity-animate'); 2456 2457var arrowRight, arrowLeft; 2458 2459var Carousel = new Class({ 2460 2461 initialize: function( element, opts ) { 2462 2463 this.options = opts; 2464 this.index = 0; 2465 this.el = element; 2466 this.wrapper = $.select('.slides', element); 2467 this.slides = $.select('.slide', element); 2468 2469 this.addListeners(); 2470 this.move(); 2471 }, 2472 2473 addListeners: function() { 2474 2475 var _this = this; 2476 arrowRight = $.select('.arrow-right', this.el)[ 0 ]; 2477 arrowLeft = $.select('.arrow-left', this.el)[ 0 ]; 2478 2479 if( Device.system.touch ) { 2480 2481 $.on( arrowRight, 'touchend', function() { _this.updateIndex(1) } ); 2482 $.on( arrowLeft, 'touchend', function() { _this.updateIndex(-1) } ); 2483 } else { 2484 2485 $.on( arrowRight, 'click', function() { _this.updateIndex(1) } ); 2486 $.on( arrowLeft, 'click', function() { _this.updateIndex(-1) } ); 2487 } 2488 }, 2489 2490 move: function() { 2491 2492 var amt = (this.slides[ 0 ].scrollWidth) * (this.index * -1); 2493 2494 Velocity(this.wrapper, { 2495 translateX: amt, 2496 translateZ: 0 2497 }, { 2498 duration: this.options.speed || 350, 2499 easing: this.options.easing || 'easeInOutCubic', 2500 queue: false 2501 }); 2502 2503 $.show(arrowLeft); 2504 $.show(arrowRight); 2505 2506 if( this.index == 0 ) $.hide(arrowLeft); 2507 if( this.index == (this.slides.length - 1) ) $.hide(arrowRight); 2508 }, 2509 2510 updateIndex: function( amt ) { 2511 2512 this.index = Util.clamp(this.index + amt, 0, this.slides.length - 1); 2513 this.move(); 2514 }, 2515 2516 resize: function() { 2517 2518 this.move(); 2519 } 2520}); 2521 2522module.exports = Carousel; 2523},{"./DOM":6,"./Device":7,"./Utils":22,"./oop/Class":28,"velocity-animate":54}],6:[function(require,module,exports){ 2524 2525var Class = require('./oop/Class'); 2526var qwery = require('qwery'); 2527var bonzo = require('bonzo'); 2528var on = require('dom-event'); 2529var off = on.off; 2530 2531var DOMObj = { 2532 2533 _bonzo: bonzo, 2534 2535 select: function( selector, context ) { 2536 2537 var el = qwery( selector, context ); 2538 2539 return el; 2540 }, 2541 2542 addChild: function( type, parent ) { 2543 2544 var el = document.createElement(type); 2545 2546 parent.appendChild(el); 2547 2548 return el; 2549 }, 2550 2551 append: function( el, parent ) { 2552 2553 bonzo(parent).append(el); 2554 }, 2555
2556 prepend: function( el, parent ) { 2557 2558 bonzo(parent).prepend(el); 2559 }, 2560 2561 addClass: function( klass, element ) { 2562 2563 if( !element ) { 2564 2565 var html = qwery('html'); 2566 bonzo(html).addClass(klass); 2567 2568 } else { 2569 bonzo( element ).addClass( klass ); 2570 } 2571 2572 return this; 2573 }, 2574 2575 setClass: function( klass, element ) { 2576 2577 bonzo( element ).attr('class', klass); 2578 }, 2579 2580 removeClass: function( element, klass ) { 2581 2582 bonzo(element).removeClass(klass); 2583 2584 return this; 2585 }, 2586 2587 attr: function( element, attribute ) { 2588 2589 return bonzo(element).attr(attribute); 2590 }, 2591 2592 hasClass: function(element, klass) { 2593 2594 return bonzo(element).hasClass(klass); 2595 }, 2596 2597 css: function( element, styles ) { 2598 2599 bonzo( element ).css( styles ); 2600 2601 return this; 2602 }, 2603 2604 hide: function( element ) { 2605 2606 bonzo( element ).hide(); 2607 2608 return this; 2609 }, 2610 2611 show: function( element ) { 2612 2613 bonzo( element ).show(); 2614 2615 return this; 2616 }, 2617 2618 center: function( element, w, h ) { 2619 2620 var height = w || bonzo( element ).dim().height; 2621 var width = h || bonzo( element ).dim().width; 2622 2623 bonzo( element ).css({ 2624 position: 'absolute', 2625 top: '50%', 2626 left: '50%', 2627 marginTop: height / -2, 2628 marginLeft: width / -2 2629 }); 2630 2631 return this; 2632 }, 2633 2634 size: function( element, w, h ) { 2635 2636 var styles = { 2637 width: w, 2638 height: h ? h : w 2639 }; 2640 2641 bonzo(element).css(styles); 2642 2643 return this; 2644 }, 2645 2646 on: function( el, ev, func ) { 2647 2648 on(el, ev, func); 2649 }, 2650 2651 off: function( el, ev, func ) { 2652 2653 off(el, ev, func); 2654 }, 2655 2656 html: function( el, html ) { 2657 2658 bonzo(el).html(html); 2659 }, 2660 2661 hover: function( el, over, out ) { 2662 2663 this.css(el, { cursor: 'pointer' }); 2664 2665 on(el, 'mouseover', over); 2666 on(el, 'mouseout', out); 2667 }, 2668 2669 width: function( el, w ) { 2670 2671 if( !w ) 2672 return bonzo(el).dim().width 2673 else 2674 bonzo(el).css({ 2675 width: h 2676 }); 2677 }, 2678 2679 height: function( el, h ) { 2680 2681 if( !w ) { 2682 2683 return bonzo(el).dim().height 2684 } else { 2685 2686 bonzo(el).css({ 2687 height: h 2688 }); 2689 } 2690 }, 2691 2692 transform: function( el, values ) { 2693 2694 var t = ""; 2695 var force2d = false; 2696 2697 if ( values.x ) t += "translateX(" + values.x + "px) "; 2698 if ( values.y ) t += "translateY(" + values.y + "px) "; 2699 if ( !force2d ) t += "translateZ(0) "; 2700 2701 if ( values.rotX ) t += "rotateX(" + values.rotX + "deg) "; 2702 if ( values.rotY ) t += "rotateY(" + values.rotY + "deg)"; 2703 if ( values.rotZ ) t += "rotateZ(" + values.rotZ + "deg) "; 2704 else if (values.rotZ ) t += "rotate(" + values.rotZ + "deg) "; 2705 2706 if ( values.scaleX && values.scaleX != 1 ) t += "scaleX(" + values.scaleX + ") "; 2707 if ( values.scaleY && values.scaleY != 1 ) t += "scaleY(" + values.scaleY + ") "; 2708 if ( values.scaleZ && values.scaleZ != 1 ) t += "scaleZ(" + values.scaleZ + ")"; 2709 if ( values.scale && values.scale != 1 ) t += "scale(" + values.scale + ")"; 2710 2711 bonzo(el).css({ 2712 "transform": t 2713 }); 2714 2715 return this; 2716 } 2717 2718}; 2719 2720module.exports = DOMObj; 2721},{"./oop/Class":28,"bonzo":41,"dom-event":42,"qwery":47}],7:[function(require,module,exports){ 2722String.prototype.strpos = function(e) { 2723 return this.indexOf(e) != -1 2724}; 2725 2726var Device = function() { 2727 2728 var b = this; 2729 this.agent = navigator.userAgent.toLowerCase(); 2730 function a(f) { 2731 var e = document.createElement("div"), d = "Khtml ms O Moz Webkit".split(" "), c = d.length; 2732 if (f in e.style) { 2733 return true 2734 } 2735 f = f.replace(/^[a-z]/, function(g) { 2736 return g.toUpperCase() 2737 }); 2738 while (c--) { 2739 if (d[c] + f in e.style) { 2740 return true 2741 } 2742 } 2743 return false 2744 } 2745 this.detect = function(d) { 2746 if (typeof d === "string") { 2747 d = [d] 2748 } 2749 for (var c = 0; c < d.length; c++) { 2750 if (this.agent.strpos(d[c])) { 2751 return true 2752 } 2753 } 2754 return false 2755 }; 2756 this.mobile = (!!("ontouchstart" in window) && this.detect(["ios", "iphone", "ipad", "windows phone", "android", "blackberry"])) ? {} : false; 2757 if (this.mobile) { 2758 this.mobile.tablet = window.innerWidth > 1000 || window.innerHeight > 900; 2759 this.mobile.phone = !this.mobile.tablet 2760 } 2761 this.browser = new Object(); 2762 this.browser.chrome = this.detect("chrome"); 2763 this.browser.safari = !this.browser.chrome && this.detect("safari"); 2764 this.browser.firefox = this.detect("firefox"); 2765 this.browser.ie = (function() { 2766 if (b.detect("msie")) { 2767 return true 2768 } 2769 if (b.detect("trident") && b.detect("rv:")) { 2770 return true 2771 } 2772 })(); 2773 this.browser.version = (function() { 2774 try { 2775 if (b.browser.chrome) { 2776 return Number(b.agent.split("chrome/")[1].split(".")[0]) 2777 } 2778 if (b.browser.firefox) { 2779 return Number(b.agent.split("firefox/")[1].split(".")[0]) 2780 } 2781 if (b.browser.safari) { 2782 return Number(b.agent.split("version/")[1].split(".")[0].charAt(0)) 2783 } 2784 if (b.browser.ie) { 2785 if (b.detect("msie")) { 2786 return Number(b.agent.split("msie ")[1].split(".")[0]) 2787 } 2788 return Number(b.agent.split("rv:")[1].split(".")[0]) 2789 } 2790 } catch (c) { 2791 return -1 2792 } 2793 })(); 2794 this.vendor = (function() { 2795 if (b.browser.firefox) { 2796 return "moz" 2797 } 2798 if (b.browser.opera) { 2799 return "o" 2800 } 2801 if (b.browser.ie && b.browser.version >= 11) { 2802 return "" 2803 } 2804 if (b.browser.ie) { 2805 return "ms" 2806 } 2807 return "webkit" 2808 })(); 2809 this.system = new Object(); 2810 this.system.retina = window.devicePixelRatio > 1 ? true : false;
2811 this.system.webworker = typeof window.Worker !== "undefined"; 2812 this.system.offline = typeof window.applicationCache !== "undefined"; 2813 this.system.touch = 'ontouchstart' in document; 2814 this.system.geolocation = typeof navigator.geolocation !== "undefined"; 2815 this.system.pushstate = typeof window.history.pushState !== "undefined"; 2816 this.system.webcam = !!(navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia); 2817 this.system.language = window.navigator.userLanguage || window.navigator.language; 2818 this.system.webaudio = typeof window.webkitAudioContext !== "undefined" || typeof window.AudioContent !== "undefined"; 2819 this.system.localStorage = typeof window.localStorage !== "undefined"; 2820 this.system.fullscreen = typeof document[b.vendor + "CancelFullScreen"] !== "undefined"; 2821 this.system.os = (function() { 2822 if (b.detect("mac os")) { 2823 return "mac" 2824 } else { 2825 if (b.detect("windows nt 6.3")) { 2826 return "windows8.1" 2827 } else { 2828 if (b.detect("windows nt 6.2")) { 2829 return "windows8" 2830 } else { 2831 if (b.detect("windows nt 6.1")) { 2832 return "windows7" 2833 } else { 2834 if (b.detect("windows nt 6.0")) { 2835 return "windowsvista" 2836 } else { 2837 if (b.detect("windows nt 5.1")) { 2838 return "windowsxp" 2839 } else { 2840 if (b.detect("linux")) { 2841 return "linux" 2842 } 2843 } 2844 } 2845 } 2846 } 2847 } 2848 } 2849 return "undetected" 2850 })(); 2851 this.media = new Object(); 2852 this.media.audio = (function() { 2853 if (!!document.createElement("audio").canPlayType) { 2854 return b.detect(["firefox", "opera"]) ? "ogg" : "mp3" 2855 } else { 2856 return false 2857 } 2858 })(); 2859 this.media.video = (function() { 2860 var c = document.createElement("video"); 2861 if (!!c.canPlayType) { 2862 if (Device.mobile) { 2863 return "mp4" 2864 } 2865 if (b.browser.chrome) { 2866 return "webm" 2867 } 2868 if (b.browser.firefox || b.browser.opera) { 2869 if (c.canPlayType('video/webm; codecs="vorbis,vp8"')) { 2870 return "webm" 2871 } 2872 return "ogv" 2873 } 2874 return "mp4" 2875 } else { 2876 return false 2877 } 2878 })(); 2879 this.graphics = new Object(); 2880 this.graphics.webgl = (function() { 2881 try { 2882 return !!window.WebGLRenderingContext && !!document.createElement("canvas").getContext("experimental-webgl") 2883 } catch (c) { 2884 } 2885 })(); 2886 this.graphics.canvas = (function() { 2887 var c = document.createElement("canvas"); 2888 return c.getContext ? true : false 2889 })(); 2890 this.styles = new Object(); 2891 this.styles.filter = a("filter") && !b.browser.firefox; 2892 this.styles.shader = b.browser.chrome; 2893 this.styles.vendor = (function() { 2894 if (b.browser.firefox) { 2895 return "Moz" 2896 } 2897 if (b.browser.opera) { 2898 return "O" 2899 } 2900 if (b.browser.ie && b.browser.version >= 11) { 2901 return "" 2902 } 2903 if (b.browser.ie) { 2904 return "ms" 2905 } 2906 return "Webkit" 2907 })(); 2908 this.styles.vendorTransition = this.styles.vendor.length ? this.styles.vendor + "Transition" : "transition"; 2909 this.styles.vendorTransform = this.styles.vendor.length ? this.styles.vendor + "Transform" : "transform"; 2910 this.tween = new Object(); 2911 this.tween.transition = a("transition"); 2912 this.tween.css2d = a("transform"); 2913 this.tween.css3d = a("perspective"); 2914 this.tween.complete = (function() { 2915 if (b.browser.firefox || b.browser.ie) { 2916 return "transitionend" 2917 } 2918 if (b.browser.opera) { 2919 return "oTransitionEnd" 2920 } 2921 return "webkitTransitionEnd" 2922 })(); 2923 this.openFullscreen = function(c) { 2924 c = c || __body; 2925 if (c && b.system.fullscreen) { 2926 if (c == __body) { 2927 c.css({top: 0}) 2928 } 2929 c.div[b.vendor + "RequestFullScreen"]() 2930 } 2931 }; 2932 this.closeFullscreen = function() { 2933 if (b.system.fullscreen) { 2934 document[b.vendor + "CancelFullScreen"]() 2935 } 2936 }; 2937 this.getFullscreen = function() { 2938 return document[b.vendor + "IsFullScreen"] 2939 } 2940}; 2941 2942var d = new Device(); 2943 2944module.exports = d; 2945},{}],8:[function(require,module,exports){ 2946var Util = require('./Utils'); 2947 2948var Easer = function(_ease) { 2949 2950 var ease = _ease || 1; 2951 2952 var pos = 0, 2953 target = 0, 2954 min = -100000000, 2955 max = 1000000000; 2956 var MAXDELTA = 100000; 2957 2958 var e = { 2959 velocity: 0 2960 }; 2961 2962 e.setTarget = function(_target) { 2963 2964 target = _target; 2965 } 2966 2967 e.getTarget = function() { 2968 2969 return target; 2970 } 2971 2972 e.updateTarget = function(delta) { 2973 2974 target += delta; 2975 } 2976 2977 e.setLimits = function(_min, _max) { 2978 2979 min = _min; 2980 max = _max; 2981 } 2982 2983 e.easeVal = function() { 2984 2985 target = Util.clamp(target, min, max); 2986 e.velocity = (target - pos) * ease; 2987 pos += e.velocity; 2988 return pos; 2989 } 2990 2991 e.setEase = function(e) { 2992 2993 ease = e; 2994 } 2995 2996 e.reset = function(val) { 2997 2998 pos = val || 0; 2999 target = val || 0; 3000 } 3001 3002 e.toString = function() { 3003 3004 return 'min: ' + min + ' / max: ' + max + ' / target: ' + target + ' / pos: ' + pos; 3005 } 3006 3007 return e; 3008} 3009 3010module.exports = Easer; 3011},{"./Utils":22}],9:[function(require,module,exports){ 3012 3013function serialize(form) { 3014 if (!form || form.nodeName !== "FORM") { 3015 return; 3016 } 3017 var i, j, q = []; 3018 for (i = form.elements.length - 1; i >= 0; i = i - 1) { 3019 if (form.elements[i].name === "") { 3020 continue; 3021 } 3022 switch (form.elements[i].nodeName) { 3023 case 'INPUT': 3024 switch (form.elements[i].type) { 3025 case 'text': 3026 case 'email': 3027 case 'hidden': 3028 case 'password': 3029 case 'button': 3030 case 'reset': 3031 case 'submit': 3032 q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value)); 3033 break; 3034 case 'checkbox': 3035 case 'radio': 3036 if (form.elements[i].checked) { 3037 q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value)); 3038 } 3039 break; 3040 case 'file': 3041 break; 3042 } 3043 break; 3044 case 'TEXTAREA': 3045 q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value)); 3046 break; 3047 case 'SELECT': 3048 switch (form.elements[i].type) { 3049 case 'select-one': 3050 q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value)); 3051 break; 3052 case 'select-multiple': 3053 for (j = form.elements[i].options.length - 1; j >= 0; j = j - 1) { 3054 if (form.elements[i].options[j].selected) { 3055 q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].options[j].value)); 3056 } 3057 } 3058 break; 3059 } 3060 break; 3061 case 'BUTTON': 3062 switch (form.elements[i].type) { 3063 case 'reset': 3064 case 'submit': 3065 case 'button': 3066 q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value)); 3067 break; 3068 } 3069 break; 3070 } 3071 } 3072 return q.join("&"); 3073} 3074 3075module.exports = serialize; 3076},{}],10:[function(require,module,exports){ 3077 3078 3079 3080var Class = require('./oop/Class'); 3081var View = require('./View'); 3082 3083var $ = require('./DOM'); 3084var Config = require('./../Config'); 3085 3086var Ticker = require('./../components/Ticker'); 3087 3088var winHeight = window.innerHeight; 3089var winWidth = window.innerWidth; 3090 3091var mouse = { 3092 x: winWidth / 2, 3093 y: winHeight / 2 3094}; 3095 3096var mouseTarget = { 3097 x: mouse.x, 3098 y: mouse.y 3099}; 3100 3101var onMouseMove = function(e) { 3102 3103 mouse.x = (winWidth / 2) - e.pageX; 3104 mouse.y = (winHeight / 2) - e.pageY; 3105}; 3106 3107var Hero = new Class({ 3108 3109 name: 'hero', 3110 Extends: View, 3111 template: "<img src=\"{{ config.cdn }}images/history/hero/{{ hero.coverImage }}\" alt=\"\" class=\"cover-image\" />\n\n<div class=\"scroll\">\n\t<div>Scroll</div>\n\t<div>\n\t\t<span>↓</span>\n\t\t<span>↓</span>\n\t</div>\n</div>\n\n<video src=\"{{ config.cdn }}video/flicker.mp4\" loop autoplay></video>\n<img src=\"{{ config.cdn }}images/history/hero/{{ hero.image }}\" alt=\"\" class=\"background-image\" />", 3112 3113 initialize: function( data ) { 3114 3115 var _this = this; 3116 3117 data.config = Config; 3118 3119 this.render(data); 3120 3121 this.addListeners(); 3122 3123 this.coverImg = $.select('.cover-image', this.div); 3124 this.backgroundImg = $.select('.background-image', this.div); 3125 3126 //- build number tickers for years 3127 this.ticker1 = new Ticker(data.dates.from); 3128 this.ticker2 = new Ticker(data.dates.to); 3129 3130 $.append(this.ticker1.div, this.div); 3131 $.append(this.ticker2.div, this.div); 3132 }, 3133 3134 addListeners: function() { 3135 3136 $.on(document, "mousemove", onMouseMove); 3137 }, 3138 3139 removeListeners: function() { 3140 3141 $.off(document, 'mousemove', onMouseMove); 3142 }, 3143 3144 onRender: function(scr) { 3145 3146 mouseTarget.x += (mouseTarget.x - mouse.x) * -0.075;
3147 mouseTarget.y += (mouseTarget.y - mouse.y) * -0.075; 3148 3149 $.css(this.div, { 3150 transform: 'translateY(' + scr * 0.35 + 'px)' 3151 }); 3152 3153 var x = mouseTarget.x / -100; 3154 var y = mouseTarget.y / -100; 3155 3156 var op = 1 - ((scr / 10) / -100); 3157 3158 $.css(this.coverImg, { 3159 marginTop: (y * 1.5) + (scr * 0.175), 3160 marginLeft: x * 1.5, 3161 opacity: op 3162 }); 3163 3164 $.css(this.backgroundImg, { 3165 marginTop: y * 1, 3166 marginLeft: x * 1 3167 }); 3168 3169 $.transform(this.ticker1.div, { 3170 y: (y * 3) + (scr * 0.175), 3171 x: x * 3 3172 }).css(this.ticker1.div, { 3173 opacity: op 3174 }); 3175 3176 $.transform(this.ticker2.div, { 3177 y: (y * 3) + (scr * 0.175), 3178 x: x * 3 3179 }).css(this.ticker2.div, { 3180 opacity: op 3181 }); 3182 }, 3183 3184 animateIn: function() { 3185 3186 this.ticker1.animateIn(); 3187 this.ticker2.animateIn(); 3188 }, 3189 3190 animateOut: function() { 3191 3192 this.removeListeners(); 3193 }, 3194 3195 resize: function( w, h ) { 3196 3197 $.css(this.div, { 3198 width: w, 3199 height: h 3200 }); 3201 } 3202}); 3203 3204module.exports = Hero; 3205},{"./../Config":1,"./../components/Ticker":21,"./DOM":6,"./View":23,"./oop/Class":28}],11:[function(require,module,exports){ 3206 3207 3208 3209var Class = require('./oop/Class'); 3210var View = require('./View'); 3211 3212var $ = require('./DOM'); 3213var Config = require('./../Config'); 3214 3215var ShuffleLetters = require('./ShuffleLetters')(); 3216 3217var HistoryTimeline = new Class({ 3218 3219 name: 'history-timeline', 3220 Extends: View, 3221 template: "<div class=\"indicator\"></div>\n<div class=\"year\"></div>\n<div class=\"title\"></div>", 3222 active: false, 3223 3224 initialize: function( data ) { 3225 3226 this.render(); 3227 3228 this.bar = $.select('.bar', this.div); 3229 this.year = $.select('.year', this.div); 3230 this.title = $.select('.title', this.div); 3231 this.indicator = $.select('.indicator', this.div); 3232 }, 3233 3234 update: function( _year, _title ) { 3235 3236 ShuffleLetters(this.year, _year); 3237 ShuffleLetters(this.title, _title); 3238 }, 3239 3240 animateIn: function() { 3241 3242 3243 }, 3244 3245 animateOut: function() { 3246 3247 this.removeListeners(); 3248 } 3249}); 3250 3251module.exports = HistoryTimeline; 3252},{"./../Config":1,"./DOM":6,"./ShuffleLetters":18,"./View":23,"./oop/Class":28}],12:[function(require,module,exports){ 3253var Loader = { 3254 3255 loadText: function(path, onLoadedFunc) { 3256 3257 var request = new XMLHttpRequest(); 3258 request.open("GET", path); 3259 3260 request.onreadystatechange = function() { 3261 3262 if (request.readyState == 4) { 3263 onLoadedFunc.call(null, request.responseText); 3264 } 3265 }; 3266 3267 request.send(); 3268 }, 3269 3270 post: function(path, data, onLoadedFunc) { 3271 3272 if( typeof data === 'function' && onLoadedFunc === 'undefined' ) { 3273 3274 onLoadedFunc = data; 3275 data = {}; 3276 } 3277 3278 var request = new XMLHttpRequest(); 3279 3280 request.onreadystatechange = function() { 3281 3282 if (request.readyState == 4) { 3283 var r = JSON.parse(request.responseText) 3284 onLoadedFunc.call(null, r); 3285 } 3286 }; 3287 3288 request.open("POST", path); 3289 request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') 3290 3291 request.send(data) 3292 }, 3293 3294 loadJSON: function(path, onLoadedFunc) { 3295 3296 Loader.loadText(path, function(text) { 3297 onLoadedFunc(JSON.parse(text)); 3298 }); 3299 }, 3300 3301 loadImage:function(src, callback) { 3302 3303 var img = new Image(); 3304 img.onload = callback(img); 3305 setTimeout(function() { 3306 img.src = src; 3307 }, 10); 3308 } 3309 3310}; 3311 3312module.exports = Loader; 3313},{}],13:[function(require,module,exports){ 3314 3315 3316var Velocity = require('velocity-animate'); 3317var UIPack = require('velocity-animate/velocity.ui'); 3318var Class = require('./oop/Class'); 3319var View = require('./../components/View'); 3320var $ = require('./../components/DOM'); 3321var Util = require('./Utils'); 3322var Device = require('./Device'); 3323 3324var NavController = require('./NavController'); 3325var Config = require('./../Config'); 3326var data = require('./../Data').navigation; 3327 3328var Nav = new Class({ 3329 3330 name: "nav", 3331 Extends: View, 3332 active: false, 3333 template: "\n<div class=\"content\">\n\n\t{{ #sections }}\n\n\t\t<div class=\"section {{ #secondary }}section-secondary{{ /secondary }} {{ key }}\">\n\t\t\t<a href=\"{{ url }}\">{{{ title }}}</a>\n\t\t</div>\n\n\t{{ /sections }}\n\n\t<ul class=\"social\">\n\t\t\n\t\t{{ #social }}\n\n\t\t\t<li class=\"{{ key }}\">\n\t\t\t\t<a href=\"{{ url }}\" target=\"_blank\">\n\t\t\t\t\t<img src=\"{{ config.cdn }}images/icn-{{ key }}.png\" alt=\"St Louis Brows: {{ key }}\" />\n\t\t\t\t\t<img src=\"{{ config.cdn }}images/icn-{{ key }}-hover.png\" alt=\"St Louis Brows: {{ key }}\" />\n\t\t\t\t</a>\n\t\t\t</li>\n\n\t\t{{ /social }}\n\n\t</ul>\n\t\n</div>", 3334 3335 initialize: function( onComplete ) { 3336 3337 data.config = Config; 3338 3339 this.Controller = new NavController(this); 3340 this.render(data, document.body, true); 3341 3342 this.Controller.animateIn(); 3343 3344 this.Sections = $.select('.section, .social', this.div); 3345 3346 Velocity.hook(this.div, "transform-origin", "top center"); 3347 }, 3348 3349 animateIn: function() { 3350 3351 this.active = true; 3352 3353 this.dark = $.hasClass(this.Controller.div, 'dark'); 3354 3355 $.css(this.div, { 3356 display: 'block' 3357 }); 3358 3359 var controllers = $.select('.nav-controller', document.body); 3360 $.addClass('dark', controllers); 3361 3362 Velocity(this.Sections, "transition.fadeIn", 3363 { 3364 stagger: 100, 3365 duration: 400, 3366 display: 'block', 3367 delay: 500 3368 }); 3369 3370 Velocity(this.div, { 3371 opacity: [ 1, 0 ], 3372 translateY: [ 0, 25 ] 3373 }, { 3374 duration: 1200, 3375 delay: 500, 3376 easing: 'easeOutCubic' 3377 }); 3378 3379 Velocity(Stage, { 3380 blur: ( Device.system.touch ) ? 0 : [ 10, 0 ], 3381 scale: ( Device.system.touch ) ? 1 : 1.01, 3382 opacity: ( Device.system.touch ) ? 0.15 : 0.25, 3383 translateZ: 0 3384 }, { 3385 duration: 2000,
3386 easing: 'easeOutCubic' 3387 }); 3388 }, 3389 3390 animateOut: function() { 3391 3392 var controller = $.select('.nav-controller'); 3393 3394 if( this.dark ) { 3395 $.addClass('dark', controller); 3396 } else { 3397 $.removeClass(controller, 'dark'); 3398 } 3399 3400 $.removeClass(controller, 'active'); 3401 3402 this.active = false; 3403 3404 Velocity(this.Sections, "transition.fadeOut", 3405 { 3406 stagger: 50, 3407 duration: 250, 3408 display: 'block' 3409 }); 3410 3411 Velocity(this.div, { 3412 opacity: 0, 3413 translateY: 10 3414 }, { 3415 duration: 350, 3416 display: 'none' 3417 }); 3418 3419 Velocity(Stage, { 3420 blur: 0, 3421 opacity: 1, 3422 scale: 1, 3423 translateZ: 0 3424 }, { 3425 duration: 1000, 3426 easing: 'linear' 3427 }); 3428 } 3429}); 3430 3431module.exports = Nav; 3432},{"./../Config":1,"./../Data":2,"./../components/DOM":6,"./../components/View":23,"./Device":7,"./NavController":14,"./Utils":22,"./oop/Class":28,"velocity-animate":54,"velocity-animate/velocity.ui":55}],14:[function(require,module,exports){ 3433 3434 3435var Velocity = require('velocity-animate'); 3436var Class = require('./oop/Class'); 3437var View = require('./../components/View'); 3438var $ = require('./../components/DOM'); 3439var Device = require('./../components/Device'); 3440 3441var Nav = require('./Nav'); 3442var Config = require('./../Config'); 3443var _data = require('./../Data'); 3444 3445var NavController = new Class({ 3446 3447 name: "nav-controller", 3448 template: "\n<div class=\"icon\">\n\t<span class=\"ball\"></span>\n\t<span class=\"bars\">\n\t\t<div></div>\n\t\t<div></div>\n\t\t<div></div>\n\t</span>\n\t<span class=\"close\">\n\t\t<div></div>\n\t\t<div></div>\n\t</span>\n</div>\n\n<div class=\"text\">\n\tMenu\n</div>", 3449 Extends: View, 3450 3451 initialize: function( parent ) { 3452 3453 this.render(_data, document.body, true); 3454 3455 Velocity.hook(this.div, "opacity", 0); 3456 3457 setTimeout(this.addListeners( parent ), 10000); 3458 }, 3459 3460 addListeners: function( parent ) { 3461 3462 var _this = this; 3463 var icon = $.select('.icon', this.div); 3464 var items = $.select('span', icon); 3465 var text = $.select('.text', this.div); 3466 3467 function handler(e) { 3468 3469 e.preventDefault(); 3470 3471 if( parent.active ) { 3472 parent.animateOut(); 3473 $.removeClass(_this.div, 'active'); 3474 parent.active = false; 3475 } 3476 else { 3477 parent.animateIn(); 3478 $.addClass('active', _this.div); 3479 parent.active = true; 3480 } 3481 } 3482 3483 if( Device.system.touch ) { 3484 $.on(this.div, 'touchend', handler); 3485 } else { 3486 $.on(this.div, 'click', handler); 3487 } 3488 }, 3489 3490 animateIn: function() { 3491 3492 var t = $.select('.title-text', document.body); 3493 3494 Velocity(this.div, { 3495 opacity: [ 1, 0 ] 3496 }, { 3497 duration: 1200, 3498 easing: 'easeOutCubic', 3499 delay: 500 3500 }); 3501 3502 Velocity(t, { 3503 opacity: [ 1, 0 ] 3504 }, { 3505 duration: 1200, 3506 easing: 'easeOutCubic', 3507 delay: 500 3508 }); 3509 } 3510}); 3511 3512module.exports = NavController; 3513},{"./../Config":1,"./../Data":2,"./../components/DOM":6,"./../components/Device":7,"./../components/View":23,"./Nav":13,"./oop/Class":28,"velocity-animate":54}],15:[function(require,module,exports){ 3514 3515 3516 3517var Class = require('./oop/Class'); 3518var View = require('./View'); 3519 3520var $ = require('./DOM'); 3521var Loader = require('./Loader'); 3522var Config = require('./../Config'); 3523var Velocity = require('velocity-animate'); 3524var Device = require('./../components/Device'); 3525 3526var Overlay = new Class({ 3527 3528 Extends: View, 3529 name: 'overlay', 3530 template: '', 3531 templates: { 3532 players: "<div class=\"align\">\n\n\t<div class=\"inner\">\n\n\t\t<div class=\"close\">×</div>\n\n\t\t<h2>{{{ firstName }}} {{{ lastName }}}</h2>\n\t\t{{{ bio }}}\n\n\t\t<hr />\n\n\t\t<div class=\"stats grid\">\n\n\t\t\t<div>\n\t\t\t\t<h5>Position</h5>\n\t\t\t\t<p>{{ details.position }}</p>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h5>Bats</h5>\n\t\t\t\t<p>{{ details.bats }}</p>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h5>Throws</h5>\n\t\t\t\t<p>{{ details.arm }}</p>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h5>Height</h5>\n\t\t\t\t<p>{{ details.height.feet }}’ {{ details.height.inches }}
3532”</p>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h5>Weight</h5>\n\t\t\t\t<p>{{ details.weight }}</p>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h5>Hometown</h5>\n\t\t\t\t<p>{{ details.city }}</p>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h5>Born</h5>\n\t\t\t\t<p>{{ details.born.month }}/{{ details.born.day }}/{{ details.born.year }}</p>\n\t\t\t</div>\n\n\t\t</div>\n\n\t</div>\n\n\t<div class=\"url\">\n\t\t<a href=\"{{ url }}\" target=\"_blank\">More Stats →</a>\n\t</div>\n\n</div>", 3533 'history-section': "<div class=\"align\">\n\n\t<div class=\"inner\">\n\n\t\t<div class=\"close\">×</div>\n\t\t<h2>{{{ title }}}</h2>\n\t\t{{{ body }}}\n\n\t</div>\n\n</div>" 3534 }, 3535 active: false, 3536 3537 init: function( parent ) { 3538 3539 this.parent = parent; 3540 3541 Velocity.hook(this.div, "opacity", 0); 3542 3543 $.append(this.div, parent.div); 3544 }, 3545 3546 populate: function( playerData, tpl ) { 3547 3548 this.template = this.templates[ tpl ]; 3549 var _this = this; 3550 3551 this.render(playerData); 3552 this.content = $.select('.inner', this.div); 3553 this.items = $.select('.stats > div', this.div); 3554 this.mouseBug = $.select('.mouse-bug', this.div); 3555 this.closeBtn = $.select('.close', this.div); 3556 3557 setTimeout(function() { 3558 _this.resize(); 3559 }, 100); 3560 3561 this.animateIn(); 3562 }, 3563 3564 animateIn: function() { 3565 3566 var url = $.select('.url', this.div); 3567 var controller = $.select('.nav-controller'); 3568 3569 $.removeClass(controller, 'dark'); 3570 3571 Velocity(this.div, { 3572 opacity: 1, 3573 translateZ: 0 3574 }, { 3575 display: 'block', 3576 easing: 'easeOutCubic', 3577 duration: 500 3578 }); 3579 3580 Velocity(this.content, { 3581 blur: [ 0, 5 ], 3582 top: [ 0, 35 ], 3583 opacity: [ 1, 0 ], 3584 translateZ: 0 3585 }, { 3586 easing: 'easeOutCubic', 3587 duration: 1200 3588 }); 3589 3590 Velocity(this.items, "transition.slideUpIn", { 3591 stagger: 100 3592 }); 3593 3594 Velocity(this.closeBtn, { 3595 opacity: [ 1, 0 ] 3596 }, { 3597 duration: 500, 3598 easing: "easeOutCubic" 3599 }); 3600 3601 Velocity(url, { 3602 opacity: [ 1, 0 ] 3603 }, { 3604 duration: 750, 3605 delay: 1000, 3606 easing: "easeOutCubic" 3607 }); 3608 }, 3609 3610 animateOut: function() { 3611 3612 Velocity(this.div, { 3613 opacity: 0 3614 }, { 3615 display: 'none', 3616 easing: 'easeOutCubic', 3617 duration: 500 3618 }); 3619 3620 var controller = $.select('.nav-controller'); 3621 3622 $.addClass('dark', controller); 3623 }, 3624 3625 resize: function( w, h ) { 3626 3627 3628 } 3629}); 3630 3631module.exports = Overlay; 3632},{"./../Config":1,"./../components/Device":7,"./DOM":6,"./Loader":12,"./View":23,"./oop/Class":28,"velocity-animate":54}],16:[function(require,module,exports){ 3633 3634 3635var Config = require('./../Config'); 3636var Class = require('./oop/Class'); 3637var hasNative = 'addEventListener' in ( new Image() ); 3638 3639function checkProgress( src, image ) { 3640 3641 // intermediate checker for queue remaining. not exported. 3642 // called on preLoader instance as scope 3643 var args = []; 3644 var o = this.options; 3645 3646 // call onProgress 3647 o.onProgress && src && o.onProgress.call(this, src, image, this.completed.length); 3648 3649 if (this.completed.length + this.errors.length === this.queue.length) { 3650 args.push(this.completed); 3651 this.errors.length && args.push(this.errors); 3652 o.onComplete.apply(this, args); 3653 } 3654 3655 return this; 3656} 3657 3658var Preloader = new Class({ 3659 3660 initialize: function(images, options) { 3661 3662 this.options = { 3663 pipeline: false, 3664 auto: true, 3665 prefetch: false, 3666 onComplete: function() {} 3667 }; 3668 3669 options && typeof options == 'object' && this.setOptions(options); 3670 3671 this.addQueue(images); 3672 this.queue.length && this.options.auto && this.processQueue(); 3673 }, 3674 3675 animateIn: function( onComplete ) { 3676 3677 3678 }, 3679 3680 animateOut: function( onComplete ) { 3681 3682 var _this = this; 3683 3684 Velocity(this.div, { 3685 opacity: 0 3686 }, { 3687 duration: 500, 3688 complete: function() { 3689 3690 _this.engine.stop(); 3691 onComplete(); 3692 } 3693 }); 3694 }, 3695 3696 setOptions: function( options ) { 3697 3698 // shallow copy 3699 var o = this.options, key; 3700 3701 for (key in options) options.hasOwnProperty(key) && (o[key] = options[key]); 3702 3703 return this; 3704 }, 3705 3706 addQueue: function( images ) { 3707 3708 this.queue = images; 3709 3710 return this; 3711 }, 3712 3713 reset: function() { 3714 3715 this.completed = []; 3716 this.errors = []; 3717 3718 return this; 3719 }, 3720 3721 addEvents: function(image, src, index) { 3722 3723 var _this = this; 3724 var o = this.options; 3725 3726 var cleanup = function() { 3727 3728 this.removeEventListener('error', abort); 3729 this.removeEventListener('abort', abort); 3730 this.removeEventListener('load', load); 3731 }; 3732 3733 var abort = function() { 3734 3735 cleanup.call(this); 3736 3737 _this.errors.push(src); 3738 o.onError && o.onError.call(_this, src); 3739 checkProgress.call(_this, src); 3740 o.pipeline && _this.loadNext(index); 3741 }; 3742 3743 var load = function() { 3744 3745 cleanup.call(this); 3746 3747 // store progress. this === image 3748 _this.completed.push(src); // this.src may differ 3749 checkProgress.call(_this, src, this); 3750 o.pipeline && _this.loadNext(index); 3751 }; 3752 3753 image.addEventListener('error', abort, false); 3754 image.addEventListener('abort', abort, false); 3755 image.addEventListener('load', load, false); 3756 3757 return this; 3758 }, 3759 3760 load: function( src, index ) { 3761 3762 var image = new Image; 3763 3764 this.addEvents(image, Config.cdn + src, index); 3765 3766 // actually load 3767 image.src = Config.cdn + src; 3768 3769 return this; 3770 }, 3771 3772 loadNext: function( index ) { 3773 3774 // when pipeline loading is enabled, calls next item 3775 index++; 3776 this.queue[index] && this.load(this.queue[index], index); 3777 3778 return this; 3779 }, 3780 3781 processQueue: function() { 3782 3783 // runs through all queued items. 3784 var i = 0, 3785 queue = this.queue, 3786 len = queue.length; 3787 3788 // process all queue items 3789 this.reset(); 3790 3791 if (!this.options.pipeline) 3792 for (; i < len; ++i) this.load(queue[i], i); 3793 else this.load(queue[0], 0); 3794 3795 return this; 3796 } 3797}) 3798 3799module.exports = Preloader; 3800},{"./../Config":1,"./oop/Class":28}],17:[function(require,module,exports){ 3801var routes = require( 'routes' ); 3802 3803var noop = function() {}; 3804 3805function router( settings ) { 3806 3807 if( !( this instanceof router ) ) { 3808 3809 return new router( settings ); 3810 } 3811 3812 var s = this.s = settings || {}; 3813 3814 s.postHash = s.postHash || ''; 3815 s.onRoute = s.onRoute || function() {}; 3816 3817 this.router = routes(); 3818} 3819 3820router.prototype = { 3821 3822 init: function() { 3823 3824 var s = this.s; 3825 3826 // figure out a start section 3827 if( s[ '/' ] === undefined ) { 3828
3829 // find the first path which would be a section 3830 for( var i in s ) { 3831 3832 if( i[ 0 ] == '/' ) { 3833 3834 s.start = i; 3835 3836 break; 3837 } 3838 } 3839 } else { 3840 3841 s.start = '/'; 3842 } 3843 3844 3845 // now setup routes 3846 for( var i in s ) { 3847 3848 if( i[ 0 ] == '/' ) { 3849 3850 this.router.addRoute( i, noop ); 3851 } 3852 } 3853 3854 window.addEventListener( 'hashchange', this.onURL.bind( this ) ) 3855 3856 // force a hash change to start things up 3857 this.onURL(); 3858 3859 return this; 3860 }, 3861 3862 add: function( route, section ) { 3863 3864 var s = this.s; 3865 3866 s[ route ] = section; 3867 3868 return this; 3869 }, 3870 3871 go: function( routeStr ) { 3872 3873 if( routeStr[ 0 ] != '/' ) 3874 routeStr = '/' + routeStr; 3875 3876 var routeData = this.getRouteData( routeStr ), 3877 section = this.getSection( routeData ); 3878 3879 // if this is not a section descriptor or it is a descriptor and we should updateURL 3880 if( this.useURL( section ) ) 3881 window.location.hash = this.s.postHash + routeStr; 3882 else 3883 this.doRoute( routeData, section ); 3884 }, 3885 3886 doRoute: function( routeData, section ) { 3887 3888 var s = this.s; 3889 3890 if( section ) { 3891 3892 // check if this is a redirect 3893 if( typeof section == 'string' ) { 3894 3895 this.go( section ); 3896 // otherwise treat it as a regular section 3897 } else { 3898 3899 // if this is a object definition vs a section definition 3900 if( section.section ) { 3901 3902 s.onRoute( section.section, routeData ); 3903 // this is a regular section or array 3904 } else { 3905 3906 s.onRoute( section, routeData ); 3907 } 3908 } 3909 3910 } else if( s[ '404' ] ) { 3911 3912 s.onRoute( s[ '404' ], routeData ); 3913 } 3914 }, 3915 3916 getRouteData: function( routeStr ) { 3917 3918 return this.router.match( routeStr ); 3919 }, 3920 3921 getSection: function( routeData ) { 3922 3923 if( routeData ) { 3924 3925 return this.s[ routeData.route ]; 3926 } else { 3927 3928 return null; 3929 } 3930 }, 3931 3932 useURL: function( section ) { 3933 3934 return section && 3935 ( section.section === undefined || // if this is not a section descriptor update url 3936 ( section.section && section.useURL || section.useURL === undefined ) ) //is descriptor and has useURL or undefined 3937 }, 3938 3939 onURL: function() { 3940 3941 var routeStr = '/', 3942 routeData, section; 3943 3944 if( window.location.hash != '' ) { 3945 3946 routeStr = window.location.hash.substr( 1 + this.s.postHash.length ); 3947 } 3948 3949 routeData = this.getRouteData( routeStr ); 3950 section = this.getSection( routeData ); 3951 3952 // see if we can deep link into this section 3953 if( this.useURL( section ) ) 3954 this.doRoute( routeData, section ); 3955 // we should 404. Pass null value for section for the 404 to come up 3956 else 3957 this.doRoute( routeData, null ); 3958 } 3959}; 3960 3961module.exports = router; 3962},{"routes":52}],18:[function(require,module,exports){ 3963var $ = require('./DOM'); 3964 3965function randomChar(type){ 3966 var pool = ""; 3967 3968 if (type == "lowerLetter"){ 3969 pool = "abcdefghijklmnopqrstuvwxyz0123456789"; 3970 } 3971 else if (type == "upperLetter"){ 3972 pool = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 3973 } 3974 else if (type == "symbol"){ 3975 pool = "1234567890"; 3976 } 3977 3978 var arr = pool.split(''); 3979 return arr[Math.floor(Math.random()*arr.length)]; 3980} 3981 3982 3983var ShuffleLetters = function( el, _text ) { 3984 3985 var options = { 3986 "step" : 12, // How many times should the letters be changed 3987 "fps" : 30, // Frames Per Second 3988 "text" : "", // Use this text instead of the contents 3989 "callback" : function() {} // Run once the animation is complete 3990 }; 3991 3992 return function(_el, _text) { 3993 3994 var el = $._bonzo(_el), 3995 str = ""; 3996 3997 options.text = _text; 3998 3999 // Preventing parallel animations using a flag; 4000 4001 if( el.data('animated') ){ 4002 return true; 4003 } 4004 4005 el.data( 'animated', true ); 4006 4007 4008 if( options.text ) { 4009 str = options.text.split(''); 4010 } 4011 else { 4012 str = el.text().split(''); 4013 } 4014 4015 // The types array holds the type for each character; 4016 // Letters holds the positions of non-space characters; 4017 4018 var types = [], 4019 letters = []; 4020 4021 // Looping through all the chars of the string 4022 4023 for( var i = 0; i < str.length; i ++ ) { 4024 4025 var ch = str[i]; 4026 4027 if( ch == " " ){ 4028 types[i] = "space"; 4029 continue; 4030 } 4031 else if( /[a-z]/.test(ch) ){ 4032 types[i] = "lowerLetter"; 4033 } 4034 else if( /[A-Z]/.test(ch) ){ 4035 types[i] = "upperLetter"; 4036 } 4037 else { 4038 types[i] = "symbol"; 4039 } 4040 4041 letters.push(i); 4042 } 4043 4044 $.html(el, ""); 4045 4046 // Self executing named function expression: 4047 4048 (function shuffle(start) { 4049 4050 // This code is run options.fps times per second 4051 // and updates the contents of the page element 4052 4053 var i, 4054 len = letters.length, 4055 strCopy = str.slice(0); // Fresh copy of the string 4056 4057 if( start > len ){ 4058 4059 // The animation is complete. Updating the 4060 // flag and triggering the callback; 4061 4062 el.data('animated',false); 4063 options.callback(el); 4064 return; 4065 } 4066 4067 // All the work gets done here 4068 for(i=Math.max(start,0); i < len; i++){ 4069 4070 // The start argument and options.step limit 4071 // the characters we will be working on at once 4072 4073 if( i < start+options.step){ 4074 // Generate a random character at thsi position 4075 strCopy[letters[i]] = randomChar(types[letters[i]]); 4076 } 4077 else { 4078 strCopy[letters[i]] = ""; 4079 } 4080 } 4081 4082 el.text(strCopy.join("")); 4083 4084 setTimeout(function(){ 4085 4086 shuffle(start+1); 4087 4088 },1000/options.fps); 4089 4090 })(-options.step); 4091 4092 4093 }; 4094}; 4095 4096module.exports = ShuffleLetters; 4097},{"./DOM":6}],19:[function(require,module,exports){ 4098 4099 4100var Class = require('./oop/Class'); 4101 4102var Easer = require('./Easer'); 4103var VirtualScroll = require('./VirtualScroll')(); 4104var Loop = require('raf-loop'); 4105 4106var SmoothScroll = new Class({ 4107 4108 initialize: function( callback, easeVal ) { 4109 4110 easeVal = easeVal || 0.15; 4111 4112 this.callback = null; 4113 this.callback = callback; 4114 this.easer = new Easer( easeVal ); 4115 this.engine = new Loop( this.onRender.bind(this) ); 4116 }, 4117 4118 setLimits: function(_min, _max) { 4119 4120 this.easer.setLimits(_min, _max); 4121 }, 4122 4123 addListeners: function() { 4124 4125 VirtualScroll.on( this.onScroll.bind(this) ); 4126 }, 4127 4128 removeListeners: function() { 4129 4130 VirtualScroll.off( this.onScroll.bind(this) ); 4131 }, 4132 4133 onScroll: function(e) { 4134 4135 if( e.originalEvent.type && e.originalEvent.type !== 'keydown' ) e.originalEvent.preventDefault(); 4136 4137 var d = (e.deltaX + e.deltaY) * 0.5; 4138 this.easer.updateTarget(d); 4139 }, 4140 4141 onRender: function(delta) { 4142 4143 var scr = this.easer.easeVal(); 4144 this.callback(scr, delta); 4145 }, 4146 4147 startRender: function() { 4148 4149 this.addListeners(); 4150 this.engine.start(); 4151 }, 4152 4153 stopRender: function() { 4154 4155 this.engine.stop(); 4156 this.removeListeners(); 4157 }, 4158 4159 setTarget: function( target ) { 4160 4161 this.easer.setTarget( target ); 4162 } 4163}); 4164 4165module.exports = SmoothScroll; 4166},{"./Easer":8,"./VirtualScroll":26,"./oop/Class":28,"raf-loop":48}],20:[function(require,module,exports){ 4167 4168var Class = require('./oop/Class'); 4169 4170var Easer = require('./Easer'); 4171var VirtualScroll = require('./VirtualScroll')(); 4172var Loop = require('raf-loop'); 4173var Util = require('./Utils'); 4174 4175var lastAnimation = null; 4176var timeNow = null; 4177var waitTime = 1000; 4178var index = 0; 4179 4180var SnappyScroll = new Class({ 4181 4182 initialize: function( callback, easeVal, wait ) { 4183 4184 easeVal = easeVal || 0.15; 4185 4186 if( wait ) waitTime = wait; 4187 4188 this.callback = callback; 4189 this.easer = new Easer( easeVal ); 4190 this.engine = new Loop( this.onRender.bind(this) ); 4191 this.scrAmt = 0; 4192 }, 4193 4194 setIndex: function( idx ) { 4195 4196 var e = {
4197 deltaX: (index < idx) ? -1 : 1, 4198 deltaY: 0, 4199 x: 0, 4200 Y: 0, 4201 originalEvent: { 4202 type: null 4203 } 4204 } 4205 4206 this.onScroll(e); 4207 }, 4208 4209 setMaxIndex: function( i ) { 4210 4211 this.maxIndex = parseInt(i) - 1; 4212 }, 4213 4214 setWidth: function( _width ) { 4215 4216 this.scrAmt = _width; 4217 }, 4218 4219 setLimits: function(_min, _max) { 4220 4221 this.easer.setLimits(_min, _max); 4222 }, 4223 4224 addListeners: function() { 4225 4226 VirtualScroll.on( this.onScroll.bind(this) ); 4227 }, 4228 4229 removeListeners: function() { 4230 4231 VirtualScroll.off( this.onScroll.bind(this) ); 4232 }, 4233 4234 onScroll: function(e) { 4235 4236 if( e.originalEvent.type && e.originalEvent.type !== 'keydown' ) e.originalEvent.preventDefault(); 4237 4238 timeNow = new Date().getTime(); 4239 4240 if (timeNow - lastAnimation < waitTime) { 4241 4242 return false; 4243 } else { 4244 4245 // update scroll position here 4246 var a; 4247 var b = this.easer.getTarget(); 4248 var amtX = Math.abs( e.deltaX ); 4249 var amtY = Math.abs( e.deltaY ); 4250 4251 if( amtX > amtY ) { 4252 4253 a = e.deltaX < 0 ? this.scrAmt * -1 : this.scrAmt; 4254 (e.deltaX < 0) ? (index = index + 1) : (index = index - 1); 4255 } else if( amtY > amtX ) { 4256 4257 a = e.deltaY < 0 ? this.scrAmt * -1 : this.scrAmt; 4258 (e.deltaY < 0) ? (index = index + 1) : (index = index - 1); 4259 } 4260 4261 index = Util.clamp(index, 0, this.maxIndex); 4262 4263 b += a; 4264 4265 this.easer.setTarget(b); 4266 4267 if( this.onScrollUpdate ) 4268 this.onScrollUpdate( index ); 4269 } 4270 4271 lastAnimation = timeNow; 4272 }, 4273 4274 onRender: function(delta) { 4275 4276 var scr = this.easer.easeVal(); 4277 this.callback(scr, delta); 4278 }, 4279 4280 startRender: function() { 4281 4282 this.addListeners(); 4283 this.engine.start(); 4284 4285 if( this.onScrollUpdate ) 4286 this.onScrollUpdate( index ); 4287 }, 4288 4289 stopRender: function() { 4290 4291 this.engine.stop(); 4292 this.removeListeners(); 4293 }, 4294 4295 setTarget: function( target ) { 4296 4297 this.easer.setTarget( target ); 4298 } 4299}); 4300 4301module.exports = SnappyScroll; 4302},{"./Easer":8,"./Utils":22,"./VirtualScroll":26,"./oop/Class":28,"raf-loop":48}],21:[function(require,module,exports){ 4303 4304 4305var Class = require('./oop/Class'); 4306var View = require('./View'); 4307 4308var $ = require('./DOM'); 4309var Velocity = require('velocity-animate'); 4310 4311var Ticker = new Class({ 4312 4313 name: 'ticker', 4314 Extends: View, 4315 4316 initialize: function( _num ) { 4317 4318 this.div = document.createElement('div'); 4319 this.div.className = 'ticker'; 4320 4321 var numbers = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ].join('\n'); 4322 var num = '<span>' + numbers + '</span>'; 4323 var tpl = '<div class="row row-top">' + num + num + '</div><div class="row row-bottom">' + num + num + '</div>'; 4324 4325 this.div.innerHTML = tpl; 4326 4327 this.arr = _num.toString().split(''); 4328 }, 4329 4330 animateIn: function() { 4331 4332 var _this = this; 4333 var el = $.select('span', this.div); 4334 4335 for( var i = 0; i < this.arr.length; i ++ ) { 4336 4337 var amt = parseInt(this.arr[ i ]) * -10 + '%'; 4338 4339 Velocity(el[ i ], { 4340 translateY: amt 4341 }, { 4342 duration: 1000, 4343 delay: (100 * i) + 250, 4344 easing: 'easeOutCubic' 4345 }); 4346 } 4347 }, 4348 4349 animateOut: function() { 4350 4351 4352 } 4353}); 4354 4355module.exports = Ticker; 4356},{"./DOM":6,"./View":23,"./oop/Class":28,"velocity-animate":54}],22:[function(require,module,exports){ 4357 4358var $ = require('./DOM'); 4359 4360var Utils = { 4361 4362 randomChar: function(type){ 4363 4364 var pool = ""; 4365 4366 if (type == "lowerLetter"){ 4367 pool = "abcdefghijklmnopqrstuvwxyz0123456789"; 4368 } 4369 else if (type == "upperLetter"){ 4370 pool = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 4371 } 4372 else if (type == "symbol"){ 4373 pool = ",.?/\\(^)![]{}*&^%$#'\""; 4374 } 4375 4376 var arr = pool.split(''); 4377 return arr[Math.floor(Math.random()*arr.length)]; 4378 }, 4379 4380 clamp: function(value, start, end) { 4381 if(value < start) return start; 4382 else if(value > end) return end; 4383 else return value; 4384 }, 4385 4386 scrollCheck: function(el, scr, callback) { 4387 4388 var all = $.select(el); 4389 4390 for (var i = 0; i < all.length; i ++) { 4391 4392 var _this = all[i]; 4393 4394 if ( $.hasClass(_this, 'active') ) { 4395 continue 4396 } 4397 4398 var top_fifth_of_object = _this.offsetTop + _this.scrollHeight / 3 - 100; 4399 var bottom_of_window = scr + window.innerHeight; 4400 4401 /* If the object is a third over the fold, fade it in */ 4402 if( bottom_of_window > top_fifth_of_object ) { 4403 $.addClass(_this, 'active'); 4404 callback(_this, i); 4405 } 4406 } 4407 }, 4408 4409 debounce: function(func, wait, immediate) { 4410 4411 var timeout; 4412 return function() { 4413 4414 var context = this, args = arguments; 4415 4416 var later = function() { 4417 4418 timeout = null;
4419 if (!immediate) func.apply(context, args); 4420 }; 4421 4422 var callNow = immediate && !timeout; 4423 4424 clearTimeout(timeout); 4425 4426 timeout = setTimeout(later, wait); 4427 4428 if (callNow) func.apply(context, args); 4429 } 4430 }, 4431 4432 norm: function(value , min, max) { 4433 //- Normalizes a number from another range into a value between 0 and 1. 4434 return (value - min) / (max - min); 4435 }, 4436 4437 splitText: function(el) { 4438 4439 var t = el.innerText; 4440 var arr = t.split(''); 4441 var inject = ''; 4442 4443 if (arr.length) { 4444 4445 for( var i = 0; i < arr.length; i ++ ) { 4446 4447 var item = arr[ i ]; 4448 4449 if( item == ' ' ) 4450 item = ' '; 4451 inject += '<span>' + item + '</span>'; 4452 } 4453 4454 el.innerHTML = ''; 4455 el.innerHTML = inject; 4456 } 4457 }, 4458 4459 randomBtwn: function(minVal, maxVal) { 4460 return minVal + (Math.random() * (maxVal - minVal)); 4461 }, 4462 4463 truncate: function(str, len) { 4464 4465 //trim the string to the maximum length 4466 var trimmedString = str.substr(0, len); 4467 4468 //re-trim if we are in the middle of a word 4469 trimmedString = trimmedString.substr(0, Math.min(trimmedString.length, trimmedString.lastIndexOf(" "))) 4470 4471 return trimmedString; 4472 } 4473 4474}; 4475 4476module.exports = Utils; 4477},{"./DOM":6}],23:[function(require,module,exports){ 4478 4479var Class = require('./oop/Class'); 4480var Mustache = require('mustache'); 4481var bonzo = require('bonzo'); 4482 4483var View = new Class({ 4484 4485 initialize: function() { 4486 4487 this.div = document.createElement('div'); 4488 4489 if( this.name ) 4490 this.div.className = this.name; 4491 4492 if( this.template ) 4493 Mustache.parse(this.template); 4494 }, 4495 4496 render: function( data, parent, prepend ) { 4497 4498 var html = Mustache.render( this.template, data ); 4499 4500 this.div.innerHTML = html; 4501 4502 if( parent ) { 4503 4504 if( prepend ) 4505 bonzo(parent).prepend(this.div); 4506 else 4507 bonzo(parent).append(this.div); 4508 } 4509 }, 4510 4511 destroy: function() { 4512 4513 this.div.parentNode.removeChild( this.div ); 4514 } 4515}); 4516 4517module.exports = View; 4518},{"./oop/Class":28,"bonzo":41,"mustache":45}],24:[function(require,module,exports){ 4519function ViewManager( settings ) { 4520 4521 if( !( this instanceof ViewManager ) ) 4522 return new ViewManager( settings ); 4523 4524 var s = this.settings = settings || {}; 4525 s.overlap = s.overlap === undefined ? true : s.overlap; 4526 this.width = s.width || 1000; 4527 this.height = s.height || 800; 4528 4529 this.currentContent = null; 4530 this.newContent = null; 4531} 4532 4533ViewManager.prototype = { 4534 4535 get overlap() { 4536 4537 return this.settings.overlap; 4538 }, 4539 4540 set overlap( value ) { 4541 4542 this.settings.overlap = value; 4543 }, 4544 4545 show: function( content, data, onComplete ) { 4546 4547 if( onComplete === undefined && typeof data == 'function' ) { 4548 4549 onComplete = data; 4550 data = null; 4551 } 4552 4553 if( content != this.newContent && content != this.currentContent ) { 4554 4555 if( this.newContent && this.newContent.destroy ) 4556 this.newContent.destroy(); 4557 4558 this.newContent = content; 4559 4560 if( content.init ) { 4561 4562 if( data ) 4563 content.init( data, this.swap.bind( this, this.newContent, onComplete ) ); 4564 else 4565 content.init( this.swap.bind( this, this.newContent, onComplete ) ); 4566 } else { 4567 4568 this.swap( this.newContent, onComplete ); 4569 } 4570 } 4571 }, 4572 4573 clear: function( onComplete ) { 4574 4575 if( this.newContent && this.newContent.destroy ) 4576 this.newContent.destroy(); 4577 4578 if( this.currentContent ) { 4579 4580 var oldOut = function( oldContent ) { 4581 4582 if( oldContent.destroy ) 4583 oldContent.destroy(); 4584 4585 if( onComplete ) 4586 onComplete( oldContent ); 4587 }.bind( this, this.currentContent ); 4588 4589 if( this.currentContent.animateOut ) 4590 this.currentContent.animateOut( oldOut ); 4591 else 4592 oldOut(); 4593 } 4594 }, 4595 4596 resize: function( w, h ) { 4597 4598 var s = this.settings; 4599 4600 s.width = w; 4601 s.height = h; 4602 4603 if( this.currentContent && this.currentContent.resize ) 4604 this.currentContent.resize( w, h ); 4605 }, 4606 4607 swap: function( newContent, onComplete ) { 4608 4609 if( newContent == this.newContent ) { 4610 4611 var s = this.settings; 4612 var oldContent = this.currentContent; 4613 var onOldContentOut; 4614 var onNewContentIn = function() { 4615 4616 if( s.endAnimateIn ) 4617 s.onEndAnimateIn( newContent, onComplete ); 4618 4619 if( onComplete ) 4620 onComplete( newContent, oldContent ); 4621 } 4622 4623 //- resize content if it can be resized 4624 newContent.resize && newContent.resize( s.width, s.height ); 4625 4626 //- start animate in callback 4627 if( s.onStartAnimateIn ) 4628 s.onStartAnimateIn( newContent, this.currentContent ); 4629
4630 //- check for content on screen already 4631 if( this.currentContent ) { 4632 4633 onOldContentOut = function() { 4634 4635 if( s.onEndAnimateOut ) 4636 s.onEndAnimateOut( newContent, oldContent ); 4637 4638 if( oldContent.destroy ) 4639 oldContent.destroy(); 4640 4641 if( !s.overlap ) { 4642 4643 if( newContent.animateIn ) 4644 newContent.animateIn( onNewContentIn ); 4645 else 4646 onNewContentIn(); 4647 } 4648 }; 4649 4650 if( s.onStartAnimateOut ) 4651 s.onStartAnimateOut( newContent, oldContent ); 4652 4653 if( oldContent.animateOut ) 4654 oldContent.animateOut( onOldContentOut ); 4655 else 4656 onOldContentOut(); 4657 4658 if( s.overlap ) { 4659 4660 if( newContent.animateIn ) 4661 newContent.animateIn( onNewContentIn ); 4662 else 4663 onNewContentIn(); 4664 } 4665 } else { 4666 4667 //- just bring in new content 4668 if( newContent.animateIn ) 4669 newContent.animateIn( onNewContentIn ); 4670 else 4671 onNewContentIn(); 4672 } 4673 4674 this.currentContent = newContent; 4675 this.newContent = null; 4676 } 4677 } 4678}; 4679 4680module.exports = ViewManager; 4681},{}],25:[function(require,module,exports){ 4682function mediator() { 4683 4684 if( !( this instanceof mediator ) ) { 4685 4686 var rVal = Object.create( mediator.prototype ); 4687 mediator.apply( rVal, arguments ); 4688 return rVal; 4689 } 4690 4691 this.items = arguments; 4692} 4693 4694mediator.prototype = { 4695 4696 init: function( data, onComplete ) { 4697 4698 var numInit = 0, 4699 numToInit = 0, 4700 numItem = this.items.length, 4701 onInit = function() { 4702 4703 if( ++numInit == numToInit ) 4704 onComplete(); 4705 }; 4706 4707 // the following needs to be done in two for loops 4708 // because init may complete immediately 4709 // looks odd but it's needed 4710 for( var i = 0; i < numItem; i++ ) { 4711 4712 if( typeof this.items[ i ].init == 'function' ) 4713 numToInit++; 4714 } 4715 4716 // now finally do the initialization 4717 for( var i = 0; i < numItem; i++ ) { 4718 4719 if( typeof this.items[ i ].init == 'function' ) 4720 this.items[ i ].init( data, onInit ); 4721 } 4722 }, 4723 4724 resize: function( w, h ) { 4725 4726 for( var i = 0, len = this.items.length; i < len; i++ ) { 4727 4728 if( typeof this.items[ i ].resize == 'function' ) 4729 this.items[ i ].resize( w, h ); 4730 } 4731 }, 4732 4733 aniIn: function( onComplete ) { 4734 4735 this.doAni( 'aniIn', onComplete ); 4736 }, 4737 4738 aniOut: function( onComplete ) { 4739 4740 this.doAni( 'aniOut', onComplete ); 4741 }, 4742 4743 doAni: function( func, onComplete ) { 4744 4745 var numAni = numItem = 0, 4746 onAni = function() { 4747 4748 if( ++numAni == numItem ) 4749 onComplete(); 4750 }; 4751 4752 // we need to do two loops here just in case onComplete gets called immediately 4753 for( var i = 0, len = this.items.length; i < len; i++ ) { 4754 4755 if( typeof this.items[ i ][ func ] == 'function' ) 4756 numItem++; 4757 } 4758 4759 // now call the animate in functions 4760 for( var i = 0, len = this.items.length; i < len; i++ ) { 4761 4762 if( typeof this.items[ i ][ func ] == 'function' ) 4763 this.items[ i ][ func ]( onAni ); 4764 } 4765 }, 4766 4767 destroy: function() { 4768 4769 for( var i = 0, len = this.items.length; i < len; i++ ) { 4770 4771 if( typeof this.items[ i ].destroy == 'function' ) 4772 this.items[ i ].destroy(); 4773 } 4774 } 4775}; 4776 4777 4778module.exports = mediator; 4779},{}],26:[function(require,module,exports){ 4780 4781 4782var VirtualScroll = function() { 4783 4784 var vs = {}; 4785 4786 var numListeners, listeners = [], initialized = false; 4787 4788 var touchStartX, touchStartY; 4789 4790 // [ These settings can be customized with the options() function below ] 4791 // Mutiply the touch action by two making the scroll a bit faster than finger movement 4792 var touchMult = 2; 4793 // Firefox on Windows needs a boost, since scrolling is very slow 4794 var firefoxMult = 15; 4795 // How many pixels to move with each key press 4796 var keyStep = 500; 4797 // General multiplier for all mousehweel including FF 4798 var mouseMult = 1; 4799 4800 var bodyTouchAction; 4801 4802 var hasWheelEvent = 'onwheel' in document; 4803 var hasMouseWheelEvent = 'onmousewheel' in document; 4804 var hasTouch = 'ontouchstart' in document; 4805 var hasTouchWin = navigator.msMaxTouchPoints && navigator.msMaxTouchPoints > 1; 4806 var hasPointer = !!window.navigator.msPointerEnabled; 4807 var hasKeyDown = 'onkeydown' in document; 4808 4809 var isFirefox = navigator.userAgent.indexOf('Firefox') > -1; 4810 4811 var event = { 4812 y: 0, 4813 x: 0, 4814 deltaX: 0, 4815 deltaY: 0, 4816 originalEvent: null 4817 }; 4818 4819 vs.on = function(f) { 4820 if(!initialized) initListeners(); 4821 listeners.push(f); 4822 numListeners = listeners.length; 4823 } 4824 4825 vs.options = function(opt) { 4826 keyStep = opt.keyStep || 120; 4827 firefoxMult = opt.firefoxMult || 15; 4828 touchMult = opt.touchMult || 2; 4829 mouseMult = opt.mouseMult || 1; 4830 } 4831 4832 vs.off = function(f) { 4833 listeners.splice(f, 1); 4834 numListeners = listeners.length; 4835 if(numListeners <= 0) destroyListeners(); 4836 } 4837 4838 var notify = function(e) { 4839 event.x += event.deltaX; 4840 event.y += event.deltaY; 4841 event.originalEvent = e; 4842 4843 for(var i = 0; i < numListeners; i++) { 4844 listeners[i](event); 4845 } 4846 } 4847 4848 var onWheel = function(e) { 4849 // In Chrome and in Firefox (at least the new one) 4850 event.deltaX = e.wheelDeltaX || e.deltaX * -1; 4851 event.deltaY = e.wheelDeltaY || e.deltaY * -1; 4852 4853 // for our purpose deltamode = 1 means user is on a wheel mouse, not touch pad 4854 // real meaning: https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent#Delta_modes 4855 if(isFirefox && e.deltaMode == 1) { 4856 event.deltaX *= firefoxMult; 4857 event.deltaY *= firefoxMult; 4858 } 4859 4860 event.deltaX *= mouseMult; 4861 event.deltaY *= mouseMult; 4862 4863 notify(e); 4864 } 4865 4866 var onMouseWheel = function(e) { 4867 // In Safari, IE and in Chrome if 'wheel' isn't defined 4868 event.deltaX = (e.wheelDeltaX) ? e.wheelDeltaX : 0; 4869 event.deltaY = (e.wheelDeltaY) ? e.wheelDeltaY : e.wheelDelta; 4870 4871 notify(e); 4872 } 4873 4874 var onTouchStart = function(e) { 4875 var t = (e.targetTouches) ? e.targetTouches[0] : e; 4876 touchStartX = t.pageX; 4877 touchStartY = t.pageY; 4878 } 4879 4880 var onTouchMove = function(e) { 4881 // e.preventDefault(); // < This needs to be managed externally 4882 var t = (e.targetTouches) ? e.targetTouches[0] : e; 4883 4884 event.deltaX = (t.pageX - touchStartX) * touchMult; 4885 event.deltaY = (t.pageY - touchStartY) * touchMult; 4886 4887 touchStartX = t.pageX; 4888 touchStartY = t.pageY; 4889 4890 notify(e); 4891 } 4892 4893 var onKeyDown = function(e) { 4894 4895 // 37 left arrow, 38 up arrow, 39 right arrow, 40 down arrow 4896 event.deltaX = event.deltaY = 0; 4897 switch(e.keyCode) { 4898 case 37: 4899 event.deltaX = -keyStep; 4900 break; 4901 case 39: 4902 event.deltaX = keyStep; 4903 break; 4904 case 38: 4905 event.deltaY = keyStep; 4906 break; 4907 case 40: 4908 event.deltaY = -keyStep; 4909 break; 4910 } 4911 4912 if( e.ctrlKey && e.keyCode == 40 ) { 4913 event.deltaY = -1000000; 4914 } 4915 4916 if( e.ctrlKey && e.keyCode == 38 ) { 4917 event.deltaY = 1000000; 4918 } 4919 4920 notify(e); 4921 } 4922 4923 var initListeners = function() { 4924 if(hasWheelEvent) document.addEventListener("wheel", onWheel); 4925 if(hasMouseWheelEvent) document.addEventListener("mousewheel", onMouseWheel); 4926 4927 if(hasTouch) { 4928 document.addEventListener("touchstart", onTouchStart); 4929 document.addEventListener("touchmove", onTouchMove); 4930 } 4931 4932 if(hasPointer && hasTouchWin) { 4933 bodyTouchAction = document.body.style.msTouchAction; 4934 document.body.style.msTouchAction = "none"; 4935 document.addEventListener("MSPointerDown", onTouchStart, true); 4936 document.addEventListener("MSPointerMove", onTouchMove, true); 4937 } 4938 4939 if(hasKeyDown) document.addEventListener("keydown", onKeyDown); 4940 4941 initialized = true; 4942 } 4943 4944 var destroyListeners = function() { 4945 if(hasWheelEvent) document.removeEventListener("wheel", onWheel); 4946 if(hasMouseWheelEvent) document.removeEventListener("mousewheel", onMouseWheel); 4947 4948 if(hasTouch) { 4949 document.removeEventListener("touchstart", onTouchStart); 4950 document.removeEventListener("touchmove", onTouchMove); 4951 } 4952 4953 if(hasPointer && hasTouchWin) { 4954 document.body.style.msTouchAction = bodyTouchAction; 4955 document.removeEventListener("MSPointerDown", onTouchStart, true); 4956 document.removeEventListener("MSPointerMove", onTouchMove, true); 4957 } 4958 4959 if(hasKeyDown) document.removeEventListener("keydown", onKeyDown); 4960 4961 initialized = false;
4962 } 4963 4964 return vs; 4965}; 4966 4967module.exports = VirtualScroll; 4968},{}],27:[function(require,module,exports){ 4969module.exports = { 4970 4971 parent: function() { 4972 4973 //- if the current function calling is the constructor 4974 if( this.parent.caller._isConstructor ) { 4975 4976 var parentFunction = this.parent.caller._parentConstructor; 4977 } else { 4978 4979 if( this.parent.caller._name ) { 4980 4981 var callerName = this.parent.caller._name; 4982 var isGetter = this.parent.caller._owner._getters[ callerName ]; 4983 var isSetter = this.parent.caller._owner._setters[ callerName ]; 4984 4985 if( arguments.length == 1 && isSetter ) { 4986 4987 var parentFunction = Object.getPrototypeOf( this.parent.caller._owner )._setters[ callerName ]; 4988 4989 if( parentFunction === undefined ) { 4990 throw 'No setter defined in parent'; 4991 } 4992 } else if( arguments.length == 0 && isGetter ) { 4993 4994 var parentFunction = Object.getPrototypeOf( this.parent.caller._owner )._getters[ callerName ]; 4995 4996 if( parentFunction === undefined ) { 4997 throw 'No getter defined in parent'; 4998 } 4999 } else if( isSetter || isGetter ) { 5000 5001 throw 'Incorrect amount of arguments sent to getter or setter'; 5002 } else { 5003 5004 var parentFunction = Object.getPrototypeOf( this.parent.caller._owner )[ callerName ]; 5005 5006 if( parentFunction === undefined ) { 5007 throw 'No parent function defined for ' + callerName; 5008 } 5009 } 5010 } else { 5011 5012 throw 'Parent cannot be used in this context'; 5013 } 5014 } 5015 5016 return parentFunction.apply( this, arguments ); 5017 } 5018}; 5019},{}],28:[function(require,module,exports){ 5020var BaseClass = require( './BaseClass' ); 5021 5022var Class = function( descriptor ) { 5023 5024 var rval = undefined; 5025 5026 if ( descriptor === undefined ) { 5027 5028 descriptor = {}; 5029 } 5030 5031 if( descriptor.initialize ) { 5032 5033 rval = descriptor.initialize; 5034 delete descriptor.initialize; 5035 } else { 5036 5037 rval = function() { 5038 5039 Array.prototype.splice.apply( arguments, [ 0, 0, this ] ); 5040 5041 Class.parent.apply( undefined, arguments ); 5042 }; 5043 } 5044 5045 if( descriptor.Extends !== undefined ) { 5046 5047 descriptor.Extends(); 5048 descriptor.Extends._isConstructor = true; 5049 5050 rval.prototype = Object.create( descriptor.Extends.prototype ); 5051 5052 // this will be used to call the parent constructor 5053 rval._parentConstructor = descriptor.Extends; 5054 delete descriptor.Extends; 5055 } else { 5056 5057 rval.prototype = Object.create( BaseClass ); 5058 rval._parentConstructor = function() {}; 5059 } 5060 5061 rval.prototype._getters = {}; 5062 rval.prototype._setters = {}; 5063 5064 for( var i in descriptor ) { 5065 if( typeof descriptor[ i ] == 'function' ) { 5066 descriptor[ i ]._name = i; 5067 descriptor[ i ]._owner = rval.prototype; 5068 5069 rval.prototype[ i ] = descriptor[ i ]; 5070 } else if( descriptor[ i ] && typeof descriptor[ i ] == 'object' && ( descriptor[ i ].get || descriptor[ i ].set ) ) { 5071 Object.defineProperty( rval.prototype, i , descriptor[ i ] ); 5072 5073 if( descriptor[ i ].get ) { 5074 rval.prototype._getters[ i ] = descriptor[ i ].get; 5075 descriptor[ i ].get._name = i; 5076 descriptor[ i ].get._owner = rval.prototype; 5077 } 5078 5079 if( descriptor[ i ].set ) { 5080 rval.prototype._setters[ i ] = descriptor[ i ].set; 5081 descriptor[ i ].set._name = i; 5082 descriptor[ i ].set._owner = rval.prototype; 5083 } 5084 } else { 5085 rval.prototype[ i ] = descriptor[ i ]; 5086 } 5087 } 5088 5089 // this will be used to check if the caller function is the consructor 5090 rval._isConstructor = true; 5091 5092 // now we'll check interfaces 5093 for( var i = 1; i < arguments.length; i++ ) { 5094 arguments[ i ].compare( rval ); 5095 } 5096 5097 return rval; 5098}; 5099 5100Class.parent = function( scope ) { 5101 5102 var caller = Class.parent.caller; 5103 5104 arguments = Array.prototype.slice.apply( arguments, [ 1 ] ) 5105 5106 // if the current function calling is the constructor 5107 if( caller._isConstructor ) { 5108 var parentFunction = caller._parentConstructor; 5109 } else { 5110 if( caller._name ) { 5111 var callerName = caller._name; 5112 var isGetter = caller._owner._getters[ callerName ]; 5113 var isSetter = caller._owner._setters[ callerName ]; 5114 5115 if( arguments.length == 1 && isSetter ) { 5116 var parentFunction = Object.getPrototypeOf( caller._owner )._setters[ callerName ]; 5117 5118 if( parentFunction === undefined ) { 5119 throw 'No setter defined in parent'; 5120 } 5121 } else if( arguments.length == 0 && isGetter ) { 5122 var parentFunction = Object.getPrototypeOf( caller._owner )._getters[ callerName ]; 5123 5124 if( parentFunction === undefined ) { 5125 throw 'No getter defined in parent'; 5126 } 5127 } else if( isSetter || isGetter ) { 5128 throw 'Incorrect amount of arguments sent to getter or setter'; 5129 } else { 5130 var parentFunction = Object.getPrototypeOf( caller._owner )[ callerName ]; 5131 5132 if( parentFunction === undefined ) { 5133 throw 'No parent function defined for ' + callerName; 5134 } 5135 } 5136 } else { 5137 throw 'You cannot call parent here'; 5138 } 5139 } 5140 5141 return parentFunction.apply( scope, arguments ); 5142}; 5143 5144module.exports = Class; 5145},{"./BaseClass":27}],29:[function(require,module,exports){ 5146 5147 5148var Class = require('./../components/oop/Class'); 5149var View = require('./../components/View'); 5150var Velocity = require('velocity-animate'); 5151var $ = require('./../components/DOM'); 5152var SmoothScroll = require('./../components/SmoothScroll'); 5153 5154var _ = require('underscore'); 5155var _data = require('./../Data').blog; 5156
5157var headerDark = false; 5158 5159var BlogView = new Class({ 5160 5161 name: "blog-post-view", 5162 Extends: View, 5163 template: "<div class=\"page-title\">\n\t<h1>News & Events</h1>\n</div>\n\n<div class=\"post\">\n\n\t<div class=\"inner\">\n\t\t\n\t\t<div class=\"social\">\n\t\t\t<ul>\n\t\t\t\t<li>\n\t\t\t\t\t<a href=\"http://www.facebook.com/sharer.php?s=100&p[url]=http://www.thestlbrowns.com/%23/news-and-events/{{ slug }}&p[images][0]=/og-image.jpg&p[title]=The St. Louis Browns Historical Society&p[summary]=The St. Louis Browns Historical Society and Fan Club is dedicated to preserving every stat and story, so the legend of baseball's most colorful underdogs can endure forever.\" target=\"_blank\" class=\"facebook\">F</a>\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<a href=\"https://twitter.com/intent/tweet?text=The St. Louis Browns Historical Society and Fan Club is dedicated to preserving every stat and story, so the legend of baseball's most colorful underdogs can endure forever.&url=http://www.thestlbrowns.com/%23/news-and-events/{{ slug }}\" target=\"_blank\" class=\"twitter\">T</a>\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<a href=\"mailto:?body=Here is a link to an article I found on the St. Louis Browns Historical Society website: http://www.thestlbrowns.com/%23/news-and-events/{{ slug }}&subject=An article from the St. Louis Browns Historical Society\" class=\"email\">M</a>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</div>\n\n\t\t<div class=\"post-body\">\n\t\t\t\n\t\t\t<p class=\"date\">{{ date }}</p>\n\t\t\t<h2>{{ title }}</h2>\n\t\t\t<p class=\"lead\">{{{ excerpt }}}</p>\n\n\t\t\t{{ #images.article }}\n\t\t\t<div class=\"post-image\">\n\t\t\t\t<img src=\"{{ . }}\" alt=\"\" />\n\t\t\t</div>\n\t\t\t{{ /images.article }}\n\n\t\t\t{{{ body }}}\n\t\n\t\t\t<hr />\n\t\t\t<p>\n\t\t\t\t<a href=\"#/news-and-events\">← Back to all posts</a>\n\t\t\t</p>\n\t\t\t\n\t\t</div>\n\n\t</div>\n\n</div>", 5164 5165 init: function( routeData, onComplete ) { 5166 5167 var _this = this; 5168 5169 this.renderer = new SmoothScroll( this.onRender.bind(this) ); 5170 5171 var postId = routeData.params.id; 5172 5173 var postData = _.findWhere(_data.posts, { slug: postId }); 5174 5175 this.render(postData, Stage); 5176 $.addClass('page', this.div); 5177 5178 this.content = $.select('.post', this.div); 5179 this.title = $.select('.page-title h1', this.div); 5180 5181 var header = $.select('.page-title', this.div); 5182 this.headerHeight = header[ 0 ].scrollHeight; 5183 5184 onComplete(); 5185 5186 setTimeout(function() { 5187 5188 _this.resize(); 5189 }, 100); 5190 5191 this.addListeners(); 5192 }, 5193 5194 addListeners: function() { 5195 5196 $.on(this.div, 'click', function(e) { 5197 5198 if( $.hasClass(e.target, 'twitter') || $.hasClass(e.target, 'facebook') ) { 5199 5200 e.preventDefault(); 5201 5202 var href = e.target.getAttribute('href'); 5203 5204 window.open(href, null, 'height=420, width=550'); 5205 } 5206 }); 5207 }, 5208 5209 animateOut: function( onComplete ) { 5210 5211 Velocity(this.div, { 5212 opacity: [ 0, 1 ] 5213 }, { 5214 duration: 1000, 5215 complete: onComplete 5216 }); 5217 5218 this.renderer.stopRender(); 5219 }, 5220 5221 animateIn: function( onComplete ) { 5222 5223 this.renderer.startRender(); 5224 5225 Velocity(this.div, { 5226 opacity: [ 1, 0 ] 5227 }, { 5228 duration: 1000, 5229 complete: onComplete, 5230 easing: 'linear' 5231 }); 5232 }, 5233 5234 onRender: function( scr ) { 5235 5236 var op = 1 - ((scr / 5) / -100); 5237 5238 $.transform(this.content, { 5239 y: scr 5240 }); 5241 5242 $.transform(this.title, { 5243 y: (scr * 0.15) 5244 }).css(this.title, { 5245 opacity: op 5246 }); 5247 5248 if( scr < -this.headerHeight && !headerDark ) { 5249 5250 $.addClass('dark', this.navController); 5251 headerDark = true; 5252 } else if( scr > -this.headerHeight && headerDark ) { 5253 5254 $.removeClass(this.navController, 'dark'); 5255 headerDark = false; 5256 } 5257 }, 5258 5259 resize: function( w, h ) { 5260 5261 var max = Math.max(0, (this.div.scrollHeight - window.innerHeight)); 5262 this.renderer.setLimits((max * -1), 0); 5263 5264 var header = $.select('.page-title', this.div); 5265 this.headerHeight = header[ 0 ].scrollHeight; 5266 } 5267}); 5268 5269module.exports = BlogView; 5270},{"./../Data":2,"./../components/DOM":6,"./../components/SmoothScroll":19,"./../components/View":23,"./../components/oop/Class":28,"underscore":53,"velocity-animate":54}],30:[function(require,module,exports){ 5271 5272 5273var Class = require('./../components/oop/Class'); 5274var View = require('./../components/View'); 5275var Velocity = require('velocity-animate'); 5276var $ = require('./../components/DOM'); 5277 5278var ContactView = new Class({ 5279 5280 name: "contact-view", 5281 Extends: View, 5282 template: "<div class=\"page-title\">\n\t<h1>Contact</h1>\n</div>\n\n<div class=\"content\">\n\t\n\t<div class=\"inner\">\n\t\n\t\t<div class=\"grid grid-padded\">\n\t\t\t\n\t\t\t<div>\n\t\t\t\t\n\t\t\t\t<h2>Contact The Society</h2>\n\t\t\t\t<p>If you want to learn more about the St. Louis Browns, the Historical Society, membership, upcoming events, or any other related topic, please fill out the form below. Someone will get back to you shortly.</p>\n\n\t\t\t</div>\n\n\t\t\t<div>\n\n\t\t\t\t<form id=\"contact\" novalidate>\n\t\t\t\t\t<div class=\"form-group\" data-required>\n\t\t\t\t\t\t<input id=\"name\" name=\"name\" type=\"text\" placeholder=\"Your Name\" />\n\t\t\t\t\t</div>\n\t\t\t\t\t\n\t\t\t\t\t<div class=\"form-group\" data-required>\n\t\t\t\t\t\t<input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Email Address\" />\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"form-group\" data-required>\n\t\t\t\t\t\t<input id=\"phone\" name=\"phone\" type=\"text\" placeholder=\"Phone Number\" />\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"form-group\" data-required>\n\t\t\t\t\t\t<textarea id=\"comment\" name=\"comment\" placeholder=\"Question/Comment\"></textarea>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"form-group error\">\n\t\t\t\t\t\t<p>All fields are required.</p>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<button type=\"submit\" class=\"submit\">Submit</button>\n\t\t\t\t</form>\n\n\t\t\t</div>\n\n\t\t</div>\n\n\t</div>\n\n</div>", 5283 5284 init: function( data, onComplete ) { 5285 5286 var nav = $.select('.nav-controller'); 5287 $.addClass('dark', nav); 5288 5289 this.render(data, Stage); 5290 $.addClass('page', this.div); 5291 5292 onComplete(); 5293 }, 5294 5295 animateOut: function( onComplete ) { 5296 5297 Velocity(this.div, { 5298 opacity: [ 0, 1 ] 5299 }, { 5300 duration: 1000, 5301 complete: onComplete 5302 }); 5303 }, 5304 5305 animateIn: function( onComplete ) { 5306 5307 Velocity(this.div, { 5308 opacity: [ 1, 0 ] 5309 }, { 5310 duration: 1000, 5311 complete: onComplete 5312 }); 5313 }, 5314 5315 resize: function( w, h ) { 5316 5317 // console.log(w, h); 5318 } 5319}); 5320 5321module.exports = ContactView; 5322},{"./../components/DOM":6,"./../components/View":23,"./../components/oop/Class":28,"velocity-animate":54}],31:[function(require,module,exports){ 5323 5324 5325var Class = require('./../components/oop/Class'); 5326var View = require('./../components/View'); 5327var Velocity = require('velocity-animate'); 5328var $ = require('./../components/DOM'); 5329 5330var Data = require('./../Data'); 5331var Config = require('./../Config'); 5332var Serialize = require('./../components/FormSerializer');
5333var Loader = require('./../components/Loader'); 5334var Util = require('./../components/Utils'); 5335 5336var SmoothScroll = require('./../components/SmoothScroll'); 5337 5338var headerDark = false, headerHeight; 5339var footer = "<footer>\n\t\n\t<div class=\"inner\">\n\t\t\n\t\t<div class=\"grid grid-middle\">\n\n\t\t\t<div class=\"logo\">\n\t\t\t\t<img src=\"/images/img-footer-logo.png\" alt=\"\" />\n\t\t\t</div>\n\t\t\t\n\t\t\t<div>\n\t\t\t\t<a href=\"#/\">Home</a>\n\t\t\t</div>\n\n\t\t\t<div>\n\t\t\t\t<a href=\"#/history\">history</a>\n\t\t\t</div>\n\n\t\t\t<div>\n\t\t\t\t<a href=\"#/players\">Players</a>\n\t\t\t</div>\n\n\t\t\t<div>\n\t\t\t\t<a href=\"#/about\">About</a>\n\t\t\t</div>\n\n\t\t\t<div>\n\t\t\t\t<a href=\"#/membership\">Membership</a>\n\t\t\t</div>\n\n\t\t\t<div>\n\t\t\t\t<a href=\"#/news-and-events\">News & Events</a>\n\t\t\t</div>\n\n\t\t\t<div>\n\t\t\t\t<a href=\"#/contact\">Contact</a>\n\t\t\t</div>\n\n\t\t</div>\n\n\t</div>\n\n</footer>"; 5340 5341var testEmail = function(email) { 5342 5343 var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 5344 return re.test(email); 5345} 5346 5347var isVisible = function(el) { 5348 5349 var rect = el.getBoundingClientRect(); 5350 5351 return ( 5352 rect.top >= -rect.height && 5353 rect.bottom >= 0 5354 ); 5355}; 5356 5357var GenericView = new Class({ 5358 5359 name: "generic-view", 5360 Extends: View, 5361 templates: { 5362 5363 "about": "<div class=\"page-title\">\n\t<h1>About The Society</h1>\n</div>\n\n<div class=\"content\">\n\n\t<div class=\"top\">\n\n\t\t<div class=\"intro\">\n\n\t\t\t<h5>Overview</h5>\n\t\t\t<p>41 losing seasons in 52 years. A whiff of a World Series. Misfits, a midget, and money problems. The Browns are baseballâs losingest and least remembered team. But beneath the tarnish is true baseball gold. Heroes of the greatest generation. Moments of grit, guts and glory. A roller coaster of ruin and redemption. The St. Louis Browns Historical Society and Fan Club is dedicated to preserving every stat and story, so the legend of baseballâs most colorful underdogs can endure forever.</p>\n\n\t\t</div>\n\n\t\t<div class=\"board\">\n\n\t\t\t<h2>Board Members</h2>\n\n\t\t\t<div class=\"grid\">\n\n\t\t\t\t<div>\n\t\t\t\t\t<img src=\"{{ Config.cdn }}images/about-photo-ed-wheatley.png\" alt=\"\" />\n\t\t\t\t\t<h6>Ed Wheatley, President</h6>\n\t\t\t\t\t<p>Ed grew up in and around the world of baseball, from his youth when his dad played professionally through his own baseball activities as he continues to play senior league games across the country. After a 36 year business career, Ed sought to make baseball his full time passion by working to preserve the legacy of this transplanted American League team co-authoring the award winning The St. Louis Browns: The Story of A Beloved Team and authoring Incredible Cardinals and Baseball in St. Louis â Little Leagues to Major Leagues. These works led to two films he helped produce shown on the PBS network in 2018 and 19 that received an EMMY nomination and selection into the National Baseball Hall of Fameâs Annual Film Series in Cooperstown in 2018 and 19 where Ed had the honor of introducing the films and speaking on the Browns.</p>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<img src=\"{{ Config.cdn }}images/about-photo-emmett.png\" alt=\"\" />\n\t\t\t\t\t<h6>Emmett McAuliffe</h6>\n\t\t\t\t\t<p>Emmett is an attorney and partner with Riezman Berger, P.C., a law firm in Clayton, MO. His practice focuses on intellectual property, offering special services to the music, film, art and fashion communities. From 2008 to 2011, he served as a gubernatorial appointment to the Missouri Arts Council. A lifelong St. Louisan, Emmett became a Browns fan as a five-year-old in the mid-1960s when an older boy showed him a Browns baseball card.</p>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<img src=\"{{ Config.cdn }}images/about-photo-vicki-martin.png\" alt=\"\" />\n\t\t\t\t\t<h6>Vicki Martin</h6>\n\t\t\t\t\t<p>Vicki Martin was a supervisor at the St. Louis Family Court â Juvenile Division for 38 years. As a director on the Browns Historical Society board, she is responsible for marketing the fan club services and products. Ms. Martin grew up in a baseball family and is the niece of former Browns player, Babe Martin. Babe played for six years, splitting time between the Browns and the Boston Red Sox.</p>\n\t\t\t\t</div>\n\n\t\t\t</div>\n\n\t\t\t<div class=\"grid\">\n\n\t\t\t\t<div>\n\t\t\t\t\t<img src=\"{{ Config.cdn }}images/about-photo-lewis-levey.png\" alt=\"\" />\n\t\t\t\t\t<h6>Lewis Levey</h6>\n\t\t\t\t\t<p>For most of his business career, Lewis A. Levey was a real estate developer focused on office buildings and apartment communities in many different states. Currently, he serves as Chairman of Enhanced Value Strategies, Inc., a company providing strategic real estate consulting and advisory services to both private and institutional investors. Mr. Levey serves on the Board of Directors of two public companies, as well as several not-for-profit organizations in the St. Louis area, including Washington University Olin School of Business N
5363ational Council and Alumni Board, the St. Louis Sports Commission, and others. A long-time sports enthusiast, he still has the baseball he caught at a Browns game in 1951.</p>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<img src=\"{{ Config.cdn }}images/about-photo-bill-borst.png\" alt=\"\" />\n\t\t\t\t\t<h6>Bill Borst</h6>\n\t\t\t\t\t<p>A native New Yorker, Bill founded the St. Louis Browns Historical Society in 1984. He was the club’s first president and launched many of its publications. Known as the “Baseball Professor,” Bill taught the first accredited baseball history course in the Midwest at Maryville College in 1973. He has previously hosted baseball call-in shows on WGNU radio and has written several non-fiction novels, including The Scorpion and the Frog: A Natural Conspiracy.</p>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<img src=\"{{ Config.cdn }}images/about-photo-stl-browns.png\" alt=\"\" />\n\t\t\t\t\t<h6></h6>\n\t\t\t\t\t<p></p>\n\t\t\t\t</div>\n\n\t\t\t</div>\n\n\t\t</div>\n\n\t\t<div class=\"hof grid grid-padded grid-middle\">\n\n\t\t\t<div class=\"image\">\n\t\t\t\t<img src=\"{{ Config.cdn }}images/about-stlsports-hof.png\" alt=\"\" />\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h2>St. Louis Sports Hall of Fame</h2>\n\t\t\t\t<p>The St. Louis Browns Fan Club is honored to be a member of the St. Louis Sports Hall of Fame, which preserves the memories of the greatest moments and events in St. Louis sports history. Our extensive exhibit includes Browns uniforms, photos of games and players, pennants, and other memorabilia.</p>\n\t\t\t</div>\n\n\t\t</div><div class=\"hof grid grid-padded grid-middle\">\n\n\t\t\t<div class=\"image\">\n\t\t\t\t<img src=\"{{ Config.cdn }}images/amateur-baseball.png\" alt=\"\" />\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h2>Greater St. Louis Amateur Baseball HOF</h2>\n\t\t\t\t<p>The St. Louis Browns Historical Society & Fan Club is a proud partner and supporter of the Greater St. Louis Amateur Baseball Hall of Fame and recipient of the HOFâs first Legacy Award Winner in 2018.</p>\n\t\t\t</div>\n\n\t\t</div>\n\n\t\t<img src=\"{{ Config.cdn }}images/bg/bg-about.png\" alt=\"\" class=\"bg\" />\n\n\t</div>\n\n\t<div class=\"form dark\">\n\n\t\t<div class=\"inner grid grid-padded grid-middle\">\n\t\t\t<div>\n\t\t\t\t<h2>Become a member</h2>\n\t\t\t\t<p>By joining, you’ll help support our organization’s efforts to preserve the history of the St. Louis Browns. Fill out the form to the right, and someone from the Browns Historical Society will contact you to complete your membership.</p>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<form id=\"contact\" novalidate>\n\t\t\t\t\t<div class=\"form-group\" data-required>\n\t\t\t\t\t\t<input id=\"name\" name=\"name\" type=\"text\" placeholder=\"Your Name\" />\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"form-group\" data-required>\n\t\t\t\t\t\t<input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Email Address\" />\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"form-group\" data-required>\n\t\t\t\t\t\t<input id=\"phone\" name=\"phone\" type=\"text\" placeholder=\"Phone Number\" />\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"form-group\" data-required>\n\t\t\t\t\t\t<textarea id=\"comment\" name=\"comment\" placeholder=\"Question/Comment\"></textarea>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<button type=\"submit\" class=\"submit\">Submit</button>\n\t\t\t\t</form>\n\t\t\t</div>\n\t\t</div>\n\n\t</div>\n\n\t<div class=\"next-section\">\n\t\t<h2>\n\t\t\t<a href=\"#/history\">The History of the Browns →</a>\n\t\t</h2>\n\t</div>\n\n</div>", 5364 "membership": "<div class=\"page-title\">\n\t<h1>Membership</h1>\n</div>\n\n<div class=\"content\">\n\n\t<div class=\"top\">\n\t\n\t\t<div class=\"intro\">\n\n\t\t\t<h5>Membership Pledge</h5>\n\t\t\t<p>As a member of the St. Louis Browns Fan Club, I pledge to protect, preserve and promote the St. Louis Browns. I accept the duty to defend the honor of the Browns wherever it may be maligned and tell Browns stories wherever and whenever I can. I will exercise careful stewardship over Browns artifacts and memorabilia. I gladly accept the duty of preventing our Browns from ever becoming forgotten by future generations of baseball fans. </p>\n\n\t\t</div>\n\t\t\n\t\t<div class=\"membership-levels\">\n\n\t\t\t<h2>Membership Levels</h2>\n\t\t\t<div class=\"grid grid-middle\">\n\t\t\t\t<div class=\"icon\">\n\t\t\t\t\t<img src=\"{{ Config.cdn }}images/member-level-bleed-brown.png\" alt=\"Bleed Brown\" />\n\t\t\t\t</div>\n\t\t\t\t<div><b>$100 per year*</b> // Includes membership ID card; an invitation to all Browns Historical Society activities, including the players dinner before the annual luncheon (extra fee); a subscription to Pop Flies, the St. Louis Browns magazine; a special issue of Pop Flies with highlights of the 70th anniversary of the â44 World Series; a DVD of the 1944 World Series; your name listed on the donor honor roll; a Browns/Cardinals 70th anniversary World Series pennant.</div>\n\t\t\t</div>\n\t\t\t<div class=\"grid grid-middle\">\n\t\t\t\t<div class=\"icon\">\n\t\t\t\t\t<img src=\"{{ Config.cdn }}images/member-level-gold.png\" alt=\"Gold\" />\n\t\t\t\t</div>\n\t\t\t\t<div><b>$60 per year*</b> // Includes membership ID card; a subscription to Pop Flies, the St. Louis Browns magazine; a special issue of Pop Flies with highlights of the 70th anniversary of the â44 World Series; historical search help; a Browns lapel pin; DVD highlights of the last member luncheon; your name listed on the donor honor roll.</div>\n\t\t\t</div>\n\t\t\t<div class=\"grid grid-middle\">\n\t\t\t\t<div class=\"icon\">\n\t\t\t\t\t<img src=\"{{ Config.cdn }}images/member-level-silver.png\" alt=\"Silver\" />\n\t\t\t\t</div>\n\t\t\t\t<div><b>$30 per year*</b> // Includes membership ID card; a subscription to Pop Flies, the St. Louis Browns magazine; historical search help; an invitation to Browns Historical Society activities (extra fees may apply).</
5364div>\n\t\t\t</div>\n\t\t\t<div class=\"legal\">*Membership fees are tax deductible. The St. Louis Browns Historical Society and Fan Club is a 501c3 organization.</div>\n\n\t\t</div>\n\n\t\t<img src=\"{{ Config.cdn }}images/bg/bg-membership.png\" alt=\"\" class=\"bg\" />\n\n\t</div>\n\t\t\n\t<div class=\"form dark\">\n\n\t\t<div class=\"inner grid grid-padded grid-middle\">\n\t\t\t<div>\n\t\t\t\t<h2>Become a member</h2>\n\t\t\t\t<p>If you want to learn more about the St. Louis Browns, the Historical Society, membership, upcoming events, or any other related topic, please fill out the form below. Someone will get back to you shortly to discuss payment options.</p>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<form id=\"contact\" novalidate>\n\t\t\t\t\t<div class=\"form-group\" data-required>\n\t\t\t\t\t\t<input id=\"name\" name=\"name\" type=\"text\" placeholder=\"Your Name\" />\n\t\t\t\t\t</div>\n\t\t\t\t\t\n\t\t\t\t\t<div class=\"form-group\" data-required>\n\t\t\t\t\t\t<input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Email Address\" />\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"form-group\" data-required>\n\t\t\t\t\t\t<input id=\"phone\" name=\"phone\" type=\"text\" placeholder=\"Phone Number\" />\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"form-group select\" data-required>\n\t\t\t\t\t\t<select name=\"memberlevel\" id=\"membership-level\">\n\t\t\t\t\t\t\t<option value=\"\">Select membership level...</option>\n\t\t\t\t\t\t\t<option value=\"silver\">Silver</option>\n\t\t\t\t\t\t\t<option value=\"gold\">Gold</option>\n\t\t\t\t\t\t\t<option value=\"bleed-brown\">Bleed Brown</option>\n\t\t\t\t\t\t</select>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"form-group error\">\n\t\t\t\t\t\t<p>All fields are required.</p>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<button type=\"submit\" class=\"submit\">Submit Membership Request</button>\n\t\t\t\t</form>\n\t\t\t</div>\n\t\t</div>\n\n\t</div>\n\n\t<div class=\"next-section\">\n\t\t<h2>\n\t\t\t<a href=\"#/players\">Browns Players →</a>\n\t\t</h2>\n\t</div>\n\n</div>", 5365 "news-and-events": "<div class=\"page-title\">\n\t<h1>News & Events</h1>\n</div>\n\n<div class=\"content\">\n\t\n\t<div class=\"posts\">\n\t\t{{ #blog.posts }}\n\n\t\t\t<div class=\"post grid grid-middle\">\n\t\t\t\t\n\t\t\t\t{{ #images.news }}\n\t\t\t\t\t<div class=\"image\" style=\"background-image: url( '{{ . }}' );\"></div>\n\t\t\t\t{{ /images.news }}\n\t\t\t\t<article>\n\t\t\t\t\t<p class=\"date\">{{ date }}</p>\n\t\t\t\t\t<h2>{{ #trimmedTitle }}{{ title }}{{ /trimmedTitle }}</h2>\n\t\t\t\t\t<a href=\"#/news-and-events/{{ slug }}\" class=\"btn\">Read More</a>\n\t\t\t\t</article>\n\n\t\t\t\t<div class=\"social\">\n\t\t\t\t\t<ul>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<a href=\"http://www.facebook.com/sharer.php?s=100&p[url]=http://www.thestlbrowns.com/%23/news-and-events/{{ slug }}&p[images][0]=/og-image.jpg&p[title]=The St. Louis Browns Historical Society&p[summary]={{ #trimmedTitle }}{{ title }}{{ /trimmedTitle }}\" target=\"_blank\" class=\"facebook\">F</a>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<a href=\"https://twitter.com/intent/tweet?text={{ #trimmedTitle }}{{ title }}{{ /trimmedTitle }}&url=http://www.thestlbrowns.com/%23/news-and-events/{{ slug }}\" target=\"_blank\" class=\"twitter\">T</a>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<a href=\"mailto:?body=Here is a link to an article I found on the St. Louis Browns Historical Society website: http://www.thestlbrowns.com/%23/news-and-events/{{ slug }}&subject=An article from the St. Louis Browns Historical Society\" class=\"email\">M</a>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\n\t\t\t</div>\n\n\t\t{{ /blog.posts }}\n\t</div>\n\n</div>\n\n", 5366 "contact": "<div class=\"page-title\">\n\t<h1>Contact</h1>\n</div>\n\n<div class=\"content\">\n\t\n\t<div class=\"inner\">\n\t\n\t\t<div class=\"grid grid-padded\">\n\t\t\t\n\t\t\t<div>\n\t\t\t\t\n\t\t\t\t<h2>Contact The Society</h2>\n\t\t\t\t<p>If you want to learn more about the St. Louis Browns, the Historical Society, membership, upcoming events, or any other related topic, please fill out the form below. Someone will get back to you shortly.</p>\n\n\t\t\t</div>\n\n\t\t\t<div>\n\n\t\t\t\t<form id=\"contact\" novalidate>\n\t\t\t\t\t<div class=\"form-group\" data-required>\n\t\t\t\t\t\t<input id=\"name\" name=\"name\" type=\"text\" placeholder=\"Your Name\" />\n\t\t\t\t\t</div>\n\t\t\t\t\t\n\t\t\t\t\t<div class=\"form-group\" data-required>\n\t\t\t\t\t\t<input id=\"email\" name=\"email\" type=\"email\" placeholder=\"Email Address\" />\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"form-group\" data-required>\n\t\t\t\t\t\t<input id=\"phone\" name=\"phone\" type=\"text\" placeholder=\"Phone Number\" />\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"form-group\" data-required>\n\t\t\t\t\t\t<textarea id=\"comment\" name=\"comment\" placeholder=\"Question/Comment\"></textarea>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"form-group error\">\n\t\t\t\t\t\t<p>All fields are required.</p>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<button type=\"submit\" class=\"submit\">Submit</button>\n\t\t\t\t</form>\n\n\t\t\t</div>\n\n\t\t</div>\n\n\t</div>\n\n</div>" 5367 5368 },
5369 5370 init: function( data, onComplete ) { 5371 5372 var _this = this; 5373 var r = data.route.split('/')[ 1 ] 5374 this.template = this.templates[ r ]; 5375 Data.Config = Config; 5376 5377 Data.trimmedTitle = function() { 5378 5379 return function (text, render) { 5380 5381 var t = render(text); 5382 5383 if( t.length > 70 ) { 5384 var tr = Util.truncate(t, 70) + '...'; 5385 return tr; 5386 } else { 5387 return t; 5388 } 5389 } 5390 }; 5391 5392 var nav = this.navController = $.select('.nav-controller'); 5393 $.removeClass(nav, 'dark'); 5394 5395 this.render(Data, Stage); 5396 5397 $.addClass('page ' + r + '-view', this.div); 5398 5399 //- set up smooth scroll renderer 5400 this.renderer = new SmoothScroll( this.onRender.bind(this) ); 5401 5402 this.content = $.select('.content', this.div); 5403 this.title = $.select('.page-title h1', this.div); 5404 this.backgroundImage = $.select('.bg', Stage); 5405 5406 var header = $.select('.page-title', this.div); 5407 headerHeight = header[ 0 ].scrollHeight; 5408 5409 // attach footer to content div 5410 this.content[ 0 ].innerHTML += footer; 5411 5412 this.bindUI(); 5413 5414 setTimeout(onComplete, 100); 5415 }, 5416 5417 bindUI: function() { 5418 5419 var form = this.form = $.select('form', this.div)[ 0 ]; 5420 5421 if( form ) $.on(form, 'submit', this.formSubmit); 5422 5423 $.on(this.div, 'click', function(e) { 5424 5425 if( $.hasClass(e.target, 'twitter') || $.hasClass(e.target, 'facebook') ) { 5426 5427 e.preventDefault(); 5428 5429 var href = e.target.getAttribute('href'); 5430 5431 window.open(href, null, 'height=420, width=550'); 5432 } 5433 }); 5434 }, 5435 5436 formSubmit: function( e ) { 5437 5438 var form = this.form; 5439 5440 var error = $.select('.error', form)[ 0 ]; 5441 var button = $.select('.submit', form)[ 0 ]; 5442 5443 e.preventDefault(); 5444 5445 $.css(error, { display: 'none' }); 5446 button.disabled = true; 5447 5448 var valid = true; 5449 var required = $.select('[data-required]', form); 5450 5451 for( var i = 0; i < required.length; i ++ ) { 5452 5453 var input = $.select('input, textarea, select', required[ i ])[ 0 ]; 5454 var type = input.getAttribute('type') || 'text'; 5455 var val = input.value; 5456 5457 if( type == 'text' && val == '' ) valid = false; 5458 if( type == 'email' && !testEmail(val) ) valid = false; 5459 } 5460 5461 if( valid ) { 5462 5463 var data = Serialize(e.target); 5464 var form = $.select('#contact')[ 0 ]; 5465 5466 $.css(form, { 5467 height: form.scrollHeight 5468 }); 5469 5470 Loader.post('/api/contact?', data, function( res ) { 5471 5472 form.innerHTML = '<p>' + res.message + '</p>'; 5473 }); 5474 } else { 5475 5476 $.css(error, { display: 'block' }); 5477 button.disabled = false; 5478 } 5479 }, 5480 5481 animateOut: function( onComplete ) { 5482 5483 Velocity(this.div, { 5484 opacity: [ 0, 1 ] 5485 }, { 5486 duration: 1000, 5487 complete: onComplete 5488 }); 5489 5490 this.renderer.stopRender(); 5491 }, 5492 5493 animateIn: function( onComplete ) { 5494 5495 this.renderer.startRender(); 5496 5497 Velocity(this.div, { 5498 opacity: [ 1, 0 ] 5499 }, { 5500 duration: 1000, 5501 complete: onComplete, 5502 easing: 'linear' 5503 }); 5504 5505 this.backgroundImage = $.select('.bg', Stage); 5506 this.sections = $.select('.top', this.div); 5507 this.resize(); 5508 }, 5509 5510 onRender: function( scr ) { 5511 5512 var op = 1 - ((scr / 2) / -100); 5513 5514 $.transform(this.content, { 5515 y: scr 5516 }); 5517 5518 $.transform(this.backgroundImage, { 5519 y: (scr * -0.075) 5520 }); 5521 5522 $.transform(this.title, { 5523 y: (scr * 0.15) 5524 }).css(this.title, { 5525 opacity: op 5526 }); 5527 5528 for( var i = 0; i < this.sections.length; i ++ ) { 5529 5530 var visible = isVisible(this.sections[ i ]); 5531 5532 if( scr < -headerHeight ) { 5533 5534 if( visible && !headerDark ) { 5535 5536 $.addClass('dark', this.navController); 5537 headerDark = true; 5538 } else if( !visible && headerDark ) { 5539 5540 $.removeClass(this.navController, 'dark'); 5541 headerDark = false; 5542 } 5543 } else { 5544 5545 if( headerDark ) { 5546 5547 $.removeClass(this.navController, 'dark'); 5548 headerDark = false; 5549 } 5550 } 5551 } 5552 }, 5553 5554 resize: function( w, h ) { 5555 5556 var max = Math.max(0, (this.div.scrollHeight - window.innerHeight)); 5557 this.renderer.setLimits((max * -1), 0); 5558 5559 var header = $.select('.page-title', this.div); 5560 headerHeight = header[ 0 ].scrollHeight; 5561 } 5562}); 5563 5564module.exports = GenericView; 5565},{"./../Config":1,"./../Data":2,"./../components/DOM":6,"./../components/FormSerializer":9,"./../components/Loader":12,"./../components/SmoothScroll":19,"./../components/Utils":22,"./../components/View":23,"./../components/oop/Class":28,"velocity-animate":54}],32:[function(require,module,exports){ 5566 5567 5568 5569var Class = require('./../components/oop/Class'); 5570var View = require('./../components/View'); 5571var Velocity = require('velocity-animate'); 5572var _ = require('underscore'); 5573 5574var Hero = require('./../components/HistoryHero'); 5575var HistoryTimeline = require('./../components/HistoryTimeline'); 5576 5577var $ = require('./../components/DOM'); 5578var _data = require('./../Data').historySection; 5579var Config = require('./../Config'); 5580var Util = require('./../components/Utils'); 5581var Device = require('./../components/Device'); 5582 5583var Overlay = require('./../components/Overlay');
5584var Carousel = require('./../components/Carousel'); 5585 5586var SmoothScroll = require('./../components/SmoothScroll'); 5587var VirtualScroll = require('./../components/VirtualScroll')(); 5588 5589var threshold = 0.8; 5590 5591var isVisible = function(el) { 5592 5593 var rect = el.getBoundingClientRect(); 5594 5595 return ( 5596 rect.top <= (window.innerHeight * threshold) && 5597 rect.bottom >= (window.innerHeight * threshold) && 5598 rect.left >= 0 && 5599 rect.right <= window.innerWidth 5600 ); 5601}; 5602 5603var HistoryView = new Class({ 5604 5605 name: "history-section-view", 5606 Extends: View, 5607 overlay: new Overlay(), 5608 5609 templates: { 5610 "the-early-years": "<div class=\"border border-top\"></div>\n<div class=\"border border-right\"></div>\n<div class=\"border border-bottom\"></div>\n<div class=\"border border-left\"></div>\n\n<div class=\"inner\">\n\n\t<div class=\"timeline-bar\"></div>\n\n\t<section class=\"browns-town\">\n\n\t\t<div class=\"content\" data-theme=\"light\" data-year=\"1902\" data-section-title=\"Inaugural Season\">\n\t\t\t<div class=\"grid section-1 contain grid-middle\">\n\n\t\t\t\t<div class=\"grid-item\">\n\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-early-years/img-1902.png\" alt=\"\" />\n\t\t\t\t</div>\n\t\t\t\t<div class=\"grid-item\">\n\t\t\t\t\t<h2>Becoming A Browns Town</h2>\n\t\t\t\t\t<p>In 1902, the Milwaukee Brewers moved to St. Louis with carriage-maker Robert Lee Hedges as the new owner. The club joined the National League’s Cardinals to become the town’s second (and soon favorite) baseball team. St. Louis loved baseball, and baseball loved it back.</p>\n\t\t\t\t\t<p>Giving a nod to the Cardinals’ former moniker (the Brown Stockings, for the color they wore), Hedges named his team the Browns. Then, he pinched several of the Redbirds’ notable players, including 1901 batting champ Jesse Burkett, future Hall-of-Fame shortstop Bobby Wallace and three of their best pitchers. Hedges rebuilt Sportsman’s Park, which was first erected in 1881, the former home of the St. Louis Cardinals.</p>\n\t\t\t\t\t<p>With this, the Browns’ legacy â and a hometown rivalry â began.</p>\n\t\t\t\t</div>\n\n\t\t\t</div>\n\n\t\t\t<div class=\"section-2\">\n\t\t\t\t<h5>Inaugural Season</h5>\n\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-early-years/img-78-58.png\" alt=\"\" class=\"big-stuff\" />\n\t\t\t\t<p>The Browns’ 1902 record. Good enough for second in the American League.</p>\n\t\t\t\t<p><a href=\"/#/\" class=\"btn show-overlay\" data-overlay=\"almost\">The Story</a></p>\n\t\t\t</div>\n\t\t</div>\n\n\t</section>\n\n\t<section class=\"sportsmans-park dark\">\n\n\t\t<div class=\"content\">\n\t\t\t<div class=\"section-1 contain\" data-theme=\"dark\" data-year=\"1909\" data-section-title=\"Sportsman’s Park\">\n\t\t\t\t<h2>Sportsman’s Park III</h2>\n\t\t\t\t<p>A third grandstand was built in Sportsman’s Park in 1909, with the diamond anchored at the southwest corner. It was also the third concrete-and-steel structure of its kind in the majors. Here, the Browns would beat out the Cardinals - in attendance.</p>\n\t\t\t</div>\n\n\t\t\t<div class=\"section-2\" data-theme=\"dark\" data-year=\"1910\" data-section-title=\"To the cellar\">\n\t\t\t\t<h5>Loss Record</h5>\n\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-early-years/img-107.png\" alt=\"\" class=\"big-stuff\" />\n\t\t\t\t<p class=\"center\">The number of losses for the Browns, two years in a row. They finished 47-107 in 1910, and 45-107 in 1911.</p>\n\t\t\t</div>\n\t\t</div>\n\n\t</section>\n\n\t<section class=\"branch-rickey\">\n\t\t<div class=\"content\">\n\t\t\t<div class=\"section-1\" data-theme=\"light\" data-year=\"1910\" data-section-title=\"THE TY COBB SCANDAL\">\n\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-early-years/img-up-in-arms.png\" alt=\"\" class=\"big-stuff\" />\n\t\t\t\t<p>St. Louis Post-Dispatch, October 1910, regarding Browns manager Jack O’Connor’s ploy to block Ty Cobb from the batting title</p>\n\t\t\t\t<p><a href=\"/#/\" class=\"btn show-overlay\" data-overlay=\"ty-cobb\">The Story</a></p>\n\t\t\t</div>\n\n\t\t\t<div class=\"section-2 contain\" data-theme=\"light\" data-year=\"1914\" data-section-title=\"BRANCH RICKEY AS MANAGER\">\n\t\t\t\t<h2>Branch Rickey</h2>\n\t\t\t\t<p>In his first full season as the club’s manager (1914), Branch Rickey helped the team improve their record to 71-82. The following year, Rickey left the field for the front office, transferring managing duties to Fielder Jones. Also in 1915, Rickey signed George Sisler to the Browns â perhaps the best thing to ever happen to the team.</p>\n\t\t\t</div>\n\t\t</div>\n\t</section>\n\n\t<section class=\"phil-ball dark\">\n\t\t<div class=\"content\">\n\n\t\t\t<div class=\"grid grid-middle contain section-1\" data-theme=\"dark\" data-year=\"1916\" data-section-title=\"Phil Ball\">\n\t\t\t\t<div class=\"grid-item\">\n\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-early-years/img-newspaper-clip.png\" alt=\"\" />\n\t\t\t\t</div>\n\t\t\t\t<div class=\"grid-item\">\n\t\t\t\t\t<h2>Sold To Ball</h2>\n\t\t\t\t\t<p>
5610In 1916, owner Robert Hedges sold the team to Philip Ball, previously the owner of the St. Louis Terriers (of the defunct Federal League).</p>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<img src=\"{{ Config.cdn }}images/history/the-early-years/img-wwi-interlude.png\" alt=\"\" class=\"wwi-interlude\" />\n\n\t\t\t<div class=\"section-2\" data-theme=\"dark\" data-year=\"1916-1922\" data-section-title=\"Ball’s Blunders\">\n\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-early-years/img-balls-blunders.png\" alt=\"\" />\n\n\t\t\t\t<h5>Blunder 1</h5>\n\t\t\t\t<p>Fired Branch Rickey, who subsequently turned the Cardinals into one of baseball’s premier teams, and later made history when he signed Jackie Robinson to the Brooklyn Dodgers.</p>\n\n\t\t\t\t<h5>Blunder 2</h5>\n\t\t\t\t<p>Allowed the Cardinals to share Sportsman’s Park, freeing up enough funds for the Cards to build a farm system. </p>\n\n\t\t\t\t<h5>Blunder 3</h5>\n\t\t\t\t<p>Spent capital expanding Sportsman’s Park in 1922, predicting a World Series there by 1926. Indeed, it came… but not for the Browns. The Cardinals faced the Yankees in the ‘26 Fall Classic, and won.</p>\n\t\t\t</div>\n\t\t</div>\n\t</section>\n\n\t<section class=\"sizzlin-sisler\">\n\t\t<div class=\"content\">\n\n\t\t\t<div class=\"section-1\" data-theme=\"light\" data-year=\"1920\" data-section-title=\"SIZZLIN’ SISLER\">\n\t\t\t\t<h5>Sizzlin’ Sisler</h5>\n\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-early-years/img-407-257.png\" alt=\"\" class=\"big-stuff\" />\n\t\t\t\t<p>George Sisler’s batting average and number of hits in 1920. The latter was a major league record for 84 years.</p>\n\t\t\t</div>\n\n\t\t\t<div class=\"section-2 contain\" data-theme=\"light\" data-year=\"1922\" data-section-title=\"The Hot Squad\">\n\t\t\t\t<h2>The Hot Squad</h2>\n\t\t\t\t<p>In 1922, the Browns outfield was on fire. Ken Williams, Baby Doll Jacobson and Jack Tobin were all .300 or better, for the 4th season in a row. (They’d continue the streak in 1923, and repeat the feat in 1925.) Williams not only led the league in RBIs and beat out Babe Ruth for the home run title, he was the founding member of the 30-30 Club â and the only member in the majors until 1956.</p>\n\t\t\t\t<p>That’s not all. With a .420 average, future Hall-of-Famer George Sisler’s bat was hotter than lightning. He hit safely in 41 consecutive games, stole 51 bases, and became the first official MVP for the American League. </p>\n\t\t\t\t<p>Further contributions to the Browns’ best-ever 93-61 record: Sisler and Williams were the top two base-stealers; Urban Shocker tallied up 24 Ws as his compatriots on the mound helped earn the league’s lowest combined ERA.</p>\n\t\t\t</div>\n\t\t</div>\n\t</section>\n\n\t<section class=\"hot-squad\">\n\t\t<div class=\"content\">\n\t\t\t<h5>The Hot Squad</h5>\n\t\t\t<img src=\"{{ Config.cdn }}images/history/the-early-years/img-stlb-nyy.png\" alt=\"\" class=\"big-stuff\" />\n\t\t\t<p>One more win and the Browns would’ve tied the Yanks for the 1922 AL pennant.</p>\n\t\t</div>\n\t</section>\n\n\t<a href=\"/#/history/the-bottom-dwellers\">\n\t\t<section class=\"next-section\" data-theme=\"\">\n\t\t\t<div class=\"content\">\n\t\t\t\t<p>Chapter 2</p>\n\t\t\t\t<h2>The Bottom Dwellers <span>→</span></h2>\n\t\t\t\t<p>1926-1941</p>\n\t\t\t</div>\n\t\t</section>\n\t</a>\n</div>", 5611 "the-bottom-dwellers": "<div class=\"border border-top\"></div>\n<div class=\"border border-right\"></div>\n<div class=\"border border-bottom\"></div>\n<div class=\"border border-left\"></div>\n\n<div class=\"inner\">\n\n\t<div class=\"timeline-bar\"></div>\n\n\t<section class=\"cardinals\">\n\n\t\t<div class=\"content\">\n\t\t\t<div class=\"grid grid-middle grid-padded section-1 contain\" data-theme=\"light\" data-year=\"1926\" data-section-title=\"Cardinals Win World Series\">\n\n\t\t\t\t<div class=\"grid-item\">\n\t\t\t\t\t<h2>Painting the Town Red</h2>\n\t\t\t\t\t<p>The 1926 World Series in Sportsman’s Park saw the Cardinals beat the Yankees. This resulted in a fanbase coup â the Redbirds went on to win (or, win back) the hearts of local baseball fans. No longer was St. Louis a “Browns Town.”</p>\n\t\t\t\t</div>\n\n\t\t\t\t<div class=\"grid-item image\">\n\t\t\t\t\t<img src=\"/images/history/the-bottom-dwellers/img-score-card.png\" alt=\"\" />\n\t\t\t\t</div>\n\n\t\t\t</div>\n\t\t\t\n\t\t\t<div class=\"section-2\" data-theme=\"light\" data-year=\"1926-27\" data-section-title=\"Browns lose 90 games\">\n\t\t\t\t<h5>90-loss Seasons</h5>\n\t\t\t\t<img src=\"/images/history/the-bottom-dwellers/img-26-27.png\" alt=\"\" class=\"big-stuff\" />\n\t\t\t\t<p>The Browns had two 90-loss seasons in a row â 92 in 1926, and 94 in 1927. Not surprisingly, they finished in seventh place both times.</p>\n\t\t\t</div>\n\n\t\t\t<div class=\"section-3\" data-theme=\"light\" data-year=\"1929\" data-section-title=\"Manush hits .355\">\n\t\t\t\t<img src=\"/images/history/the-bottom-dwellers/img-choke-up.png\" alt=\"\" />\n\t\t\t\t<p>Ty Cobb gave this fine piece of advice to Browns outfielder Heinie Manush in 1929. It must have done some good, because Manush averaged .355 that year, helping the Browns record their second straight winning season (79-73).</p>\n\t\t\t</div>\n\t\t</div>\n\n\t</section>\n\n\t<section class=\"attendance-woes dark\">\n\t\t\n\t\t<div class=\"content\">\n\t\t\t<div class=\"section-1\" data-theme=\"dark\" data-year=\"1933\" data-section-title=\"just 33 attend Browns game\">\n\t\t\t\t<h5>
5611Attendance Woes</h5>\n\t\t\t\t<img src=\"/images/history/the-bottom-dwellers/img-33.png\" alt=\"\" class=\"big-stuff\" />\n\t\t\t\t<p class=\"contain\">After a string of years with 90+ losses, the Browns played one game for just 33 paying fans. The club faced a catch 22: they needed good players to attract a crowd, but they needed a crowd to afford good players.</p>\n\t\t\t</div>\n\n\t\t\t<div class=\"section-2 contain\" data-theme=\"dark\" data-year=\"1933\" data-section-title=\"Browns tab hornsby\">\n\t\t\t\t\n\t\t\t\t<div class=\"grid grid-padded grid-middle\">\n\t\t\t\t\t\n\t\t\t\t\t<div class=\"image\">\n\t\t\t\t\t\t<img src=\"/images/history/the-bottom-dwellers/img-card-back.png\" alt=\"\" />\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h2>The Rajah</h2>\n\t\t\t\t\t\t<p>Phil Ball picked up Rogers Hornsby as player-manager in 1933, trying to lure Cardinals fans to Browns games. Hornsby holds the second best career batting average of all time (surpassed only by Ty Cobb). Despite his prowess, “The Rajah” didn’t put himself in the lineup enough to scoop the Browns out of what would become a decade-long losing streak. However, he did hit the last home run of his career as a Brownie, helping his team beat the White Sox in a rare 15-10 victory.</p>\n\t\t\t\t\t</div>\n\n\t\t\t\t</div>\n\n\t\t\t</div>\n\n\t\t\t<div class=\"section-3\" data-theme=\"dark\" data-year=\"1935\" data-section-title=\"Record low attendance\">\n\t\t\t\t\n\t\t\t\t<h5>Another depressing low</h5>\n\t\t\t\t<img src=\"/images/history/the-bottom-dwellers/img-80000.png\" alt=\"\" class=\"big-stuff\" />\n\t\t\t\t<p class=\"contain\">The depths of the Great Depression brought another famous low â the Browns’ worst single-season attendance record, woefully attained in 1935. This record still stands as a major league low.</p>\n\n\t\t\t</div>\n\t\t</div>\n\n\t</section>\n\n\t<section class=\"barnes-dewitt\">\n\n\t\t<div class=\"content\">\n\t\t\t<div class=\"section-1\" data-theme=\"light\" data-year=\"1936\" data-section-title=\"Barnes & Dewitt Buy Browns\">\n\t\t\t\t\n\t\t\t\t<div class=\"grid grid-padded grid-middle contain\">\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h2>Barnes & Dewitt</h2>\n\t\t\t\t\t\t<p>New ownership took hold of the team in 1936 â Donald Lee Barnes became the majority stockholder and owner, and Bill DeWitt, Sr., became minority owner and general manager. The first few years remained rocky, but an upswing was on its way.</p>\n\t\t\t\t\t\t<div class=\"note\">\n\t\t\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/after-the-browns.png\" alt=\"\" class=\"show-overlay\" data-overlay=\"dewitt\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<img src=\"/images/history/the-bottom-dwellers/img-dewitt.png\" alt=\"\" />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\n\t\t\t</div>\n\n\t\t\t<div class=\"section-2 contain\" data-theme=\"light\" data-year=\"1939\" data-section-title=\"Browns All-time worst record\">\n\t\t\t\t<h5>All-time worst</h5>\n\t\t\t\t<img src=\"/images/history/the-bottom-dwellers/img-43-111.png\" alt=\"\" class=\"big-stuff\" />\n\t\t\t\t<p class=\"contain\">The Browns’ all-time worst record put them 64 and a half games out of first for the 1939 season. The pitching staffâs combined ERA was 6.01, which could have been the main culprit.</p>\n\t\t\t</div>\n\t\t\t\n\t\t\t<div class=\"section-3 contain\" data-theme=\"light\" data-year=\"1941\" data-section-title=\"Attack on pearl harbor\">\n\t\t\t\t\n\t\t\t\t<h2>Disastrous Timing</h2>\n\t\t\t\t<p>Owner Don Barnes was trying to move the team to Los Angeles, hoping for a better financial outlook. A league meeting to bestow final approval was slated for December 8th, 1941. The attack on Pearl Harbor happened on December 7th. Needless to say, the meeting didnât happen, and the team stayed put.</p>\n\n\t\t\t</div>\n\t\t</div>\n\t</section>\n\n\t<section class=\"rebuilding dark\" data-theme=\"dark\" data-year=\"1941\" data-section-title=\"Browns Rebuild\">\n\n\t\t<div class=\"content\">\n\t\t\t\n\t\t\t<img src=\"/images/history/the-bottom-dwellers/img-rebuilding.png\" alt=\"\" class=\"big-stuff\" />\n\t\t\t<p class=\"contain\">New manager Luke Sewell establishes a rebuilding program in 1941. This would be the chance the Browns had always been waiting for.</p>\n\t\t\t\n\t\t</div>\n\n\t</section>\n\n\t<a href=\"/#/history/the-war-years\">\n\t\t<section class=\"next-section\" data-theme=\"\">\n\t\t\t<div class=\"content\">\n\t\t\t\t<p>Chapter 3</p>\n\t\t\t\t<h2>The War Years <span>→</span></h2>\n\t\t\t\t<p>1942-1946</p>\n\t\t\t</div>\n\t\t</section>\n\t</a>\n</div>", 5612 "the-war-years": "<div class=\"border border-top\"></div>\n<div class=\"border border-right\"></div>\n<div class=\"border border-bottom\"></div>\n<div class=\"border border-left\"></div>\n\n<div class=\"inner\">\n\n\t<div class=\"timeline-bar\"></div>\n\n\t<section class=\"roosevelt\">\n\n\t\t<div class=\"content\">\n\t\t\t<div class=\"section-1 contain\" data-theme=\"light\" data-year=\"1942\" data-section-title=\"Honesty\">\n\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-honestly.png\" alt=\"\" />\n\t\t\t\t<p class=\"attr\">President Franklin D. Roosevelt</p>\n\t\t\t</div>\n\n\t\t\t<div class=\"section-2\">\n\t\t\t\t<div class=\"grid grid-middle contain\">\n\t\t\t\t\t\n\t\t\t\t\t<div class=\"text\">\n\t\t\t\t\t\t<p>The first World War had prematurely ended the 1918 baseball season, and many feared World War 2 would do the same. On January 15, 1942, President Roosevelt responded to a plea from Commissioner Kenesaw Mountain
5612Landis, in what was come to be known as the ‘Green Light Letter.” Not only did he ensure the continuation of wartime baseball, he also pushed for more night games to give the hard-working people behind the war production effort a well-deserved break.</p>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-letter.png\" alt=\"\" />\n\t\t\t\t\t</div>\n\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div class=\"section-3 contain\" data-theme=\"light\" data-year=\"1942\" data-section-title=\"Building a Winner\">\n\t\t\t\t<h2>Building a Winner</h2>\n\t\t\t\t<p>With the go-ahead to keep playing, Luke Sewell got surgical with his 1942 roster. He got rid of lazy players and weak bats. He signed promising rookies. And he traded for veterans with positive attitudes and overlooked power. Some of the gems Sewell brought on board included Don Gutteridge, Vern Stephens, Ellis Clary, Steve Sundra, and Al Hollingsworth.</p>\n\t\t\t\t<p>The Browns lost some players to the war effort, but they didn’t lose star-level power like Joe Dimaggio, Hank Greenberg or Ted Williams. So, as the other teams in the league said goodbye to their key players, the Browns’ chances of winning got better and better.</p>\n\t\t\t</div>\n\n\t\t\t<div class=\"section-4\">\n\t\t\t\t<h5>1942 SEASON</h5>\n\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-82-69.png\" alt=\"\" class=\"big-stuff\">\n\t\t\t\t<p>The 1942 Browns brought home the team’s first winning season since 1929.</p>\n\t\t\t</div>\n\t\t</div>\n\n\t</section>\n\n\t<section class=\"cold-springs dark\">\n\t\t\n\t\t<div class=\"content\">\n\t\t\t<div class=\"section-1 contain\" data-theme=\"dark\" data-year=\"1943\" data-section-title=\"Cold Springs\">\n\t\t\t\t<h2>Cold Springs</h2>\n\t\t\t\t<p>From 1943 to 1945, Commissioner Landis required all Major League Teams to stay close to home for spring training, explaining that long-distance travel resources were best left to those involved in the war effort. The Browns trained just 100 miles south of St. Louis in Cape Girardeau, Missouri. Theirs was a much better plight than the many northeast teams, who made training grounds out of airport hangars, horse stables, hotel rooms, and â when the baseball fields were too frosty â golf fairways.</p>\n\t\t\t</div>\n\n\t\t\t<div class=\"section-2\" data-theme=\"dark\" data-year=\"1943\" data-section-title=\"Balata Ball\">\n\t\t\t\t<div class=\"grid grid-middle contain\">\n\t\t\t\t\t\n\t\t\t\t\t<div class=\"text\">\n\t\t\t\t\t\t<h2>Balata Ball</h2>\n\t\t\t\t\t\t<p>Rubber was in high demand for the war, so regular baseballs got the shaft. For the 1943 season, major leaguers had to play with a ‘balata ball,’ which had a hard plastic core and didn’t travel as far. Lower scoring games were common. Batters were not thrilled.</p>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-ball.png\" alt=\"\" />\n\t\t\t\t\t</div>\n\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t</section>\n\n\t<section class=\"infield\">\n\t\t\n\t\t<div class=\"content\">\n\t\t\t\n\t\t\t<div class=\"section-1 contain\" data-theme=\"light\" data-year=\"1944\" data-section-title=\"All 4-F Infield\">\n\t\t\t\t<h2>All 4-F Infield</h2>\n\t\t\t\t<p>Every player on the 1944 Browns infield was 4-F, or excused from military service for one reason or another.</p>\n\n\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-infield.png\" alt=\"\" />\n\t\t\t</div>\n\n\t\t\t<div class=\"section-2\">\n\t\t\t\t<h2>9 Straight W’s</h2>\n\t\t\t\t<p>The Browns opened the 1944 season with a bang â or a crack â or a whopping, righteous blast â nine straight wins.</p>\n\t\t\t</div>\n\n\t\t\t<div class=\"section-3\">\n\t\t\t\t<h2>Almost Perfect</h2>\n\t\t\t\t<p>On May 26, 1944, Nels Potter retired 23 batters in a row. Sadly, Jim Tabor, of the opposing Red Sox, got a hit in the 8th to dash Potter’s hopes of a perfect game.</p>\n\t\t\t</div>\n\n\t\t\t<div class=\"section-4 contain\" data-theme=\"light\" data-year=\"1944\" data-section-title=\"The 1st Illegal Pitcher\">\n\n\t\t\t\t<div class=\"grid grid-middle\">\n\t\t\t\t\t\n\t\t\t\t\t<div class=\"image\">\n\t\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-pitcher.png\" alt=\"\" />\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h2>The 1st Illegal Pitcher</h2>\n\t\t\t\t\t\t<p>Browns pitcher Nels Potter was caught ‘moistening his fingers’ before every pitch in a game against the Yankees on July 20, 1944. He was suspended for 10 games, becoming the first player in MLB history to be suspended for throwing an illegal pitch.</p>\n\t\t\t\t\t</div>\n\n\t\t\t\t</div>\n\t\t\t\t\n\t\t\t</div>\n\n\t\t</div>\n\n\t</section>\n\n\t<section class=\"scrabeenies dark\">\n\t\t\n\t\t<div class=\"content\">\n\t\t\t\n\t\t\t<div class=\"section-1\" data-theme=\"dark\" data-year=\"1944\" data-section-title=\"Scrabeenies\">\n\t\t\t\t<div class=\"contain\">\n\t\t\t\t\t<h2>Scrabeenies</h2>\n\t\t\t\t\t<p>Ellis Clary crowned himself the “manager” of the Browns’ backup players, who called themselves the scrabeenies. Most of these utility guys didn’t show their stuff when given the chance. But Al Zarilla went 2 for 2 in a July game against the Red Sox, earning himself a more frequent spot in the lineup for the remainder of the season. So
5612on after, this former scrabeenie pounded out an 11-game hitting streak.</p>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div class=\"section-2\">\n\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-25000.png\" alt=\"\" class=\"big-stuff\" />\n\t\t\t\t<p class=\"contain\">Every major league team was required to host one game where all net proceeds would be given to a national war relief organization. On July 26, 1944, the Browns played the Philadelphia Athletics â in front of their biggest crowd since their first night game in 1940 â and raised $25,000.</p>\n\t\t\t</div>\n\n\t\t\t<div class=\"section-3\" data-theme=\"dark\" data-year=\"1944\" data-section-title=\"70 Days In First\">\n\t\t\t\t<h2>70 Days in 1st</h2>\n\t\t\t\t<p>On August 8th, the Browns broke their previous record, set in 1922, for consecutive days leading the American League.</p>\n\t\t\t</div>\n\n\t\t\t<div class=\"section-4 contain\" data-theme=\"dark\" data-year=\"1944\" data-section-title=\"Fight!\">\n\t\t\t\t\n\t\t\t\t<div class=\"grid grid-padded grid-middle\">\n\t\t\t\t\t\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-fight.png\" alt=\"\" class=\"flush-bottom\" />\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<p class=\"flush-bottom\">On September 21, 1944, the Browns were in the last game of the last series against the Senators. A fight broke out between Browns catcher Tom Turner and Senators outfielder Roberto Ortiz. The Senators would go on to play the Tigers, who the Browns were racing for first-place. So, when Ortiz broke his hand in the fight with Turner, the Browns weren’t too happy about it, either.</p>\n\t\t\t\t\t</div>\n\n\t\t\t\t</div>\n\n\t\t\t</div>\n\n\t\t\t<div class=\"section-5\" data-theme=\"dark\" data-year=\"1944\" data-section-title=\"The Heat Is On\">\n\t\t\t\t\n\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-84-64.png\" alt=\"\" class=\"big-stuff\" />\n\t\t\t\t<p>The Browns and the Tigers were tied for first with an identical record. There were 6 games left in the season. The heat was on.</p>\n\n\t\t\t</div>\n\n\t\t</div>\n\n\t</section>\n\n\t<section class=\"pennant\">\n\t\t\n\t\t<div class=\"content\" data-theme=\"light\" data-year=\"1944\" data-section-title=\"The Clincher\">\n\t\t\t\n\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-clincher.png\" alt=\"\" class=\"big-stuff\" />\n\n\t\t\t<div class=\"section-1\">\n\t\t\t\t<div class=\"highlight\">\n\t\t\t\t\t<h5>Highlight 1</h5>\n\t\t\t\t\t<p>Wild man Sig Jakucki took the mound for the Browns.</p>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"highlight\">\n\t\t\t\t\t<h5>Highlight 2</h5>\n\t\t\t\t\t<p>He retired the first two Yanks.</p>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"highlight\">\n\t\t\t\t\t<h5>Highlight 3</h5>\n\t\t\t\t\t<p>The Browns were hitless through the third. Key errors put the Yankees up 2-0.</p>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"highlight\">\n\t\t\t\t\t<h5>Highlight 4</h5>\n\t\t\t\t\t<p>Chet Laabs crushed a fastball over the bleachers to tie the game.</p>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-scoreboard.png\" alt=\"\" class=\"big-stuff\" />\n\n\t\t\t<div class=\"section-2\" data-theme=\"light\" data-year=\"1944\" data-section-title=\"The Fightenâst Team Ever To Wear A Uniform!\">\n\t\t\t\t<div class=\"highlight\">\n\t\t\t\t\t<h5>Highlight 5</h5>\n\t\t\t\t\t<p>Bottom 5, Laabs was up for his third at-bat, and ripped another 2-run homer.</p>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"highlight\">\n\t\t\t\t\t<h5>Highlight 6</h5>\n\t\t\t\t\t<p>In the remaining innings, Jakucki only allowed one more batter to reach 3rd.</p>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"highlight\">\n\t\t\t\t\t<h5>Highlight 7</h5>\n\t\t\t\t\t<p>The Browns led 5-2 into the ninth. Johnny Lindell blasted a pitch from Jakucki, but it was caught for a long out by Browns right fielder Gene Moore. The crowd exhaled.</p>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"highlight\">\n\t\t\t\t\t<h5>Highlight 8</h5>\n\t\t\t\t\t<p>Down to the final out, Oscar Grimes spikes a high fly ball into foul territory. Browns first baseman George Mc
5612Quinn finds it in his glove.</p>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-pennant.png\" alt=\"\" class=\"big-stuff\" />\n\n\t\t</div>\n\n\t</section>\n\n\t<section class=\"street-car dark\">\n\t\t\n\t\t<div class=\"content\">\n\t\t\t\n\t\t\t<div class=\"section-1\" data-theme=\"dark\" data-year=\"1944\" data-section-title=\"The Streetcar Series\">\n\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-streetcar.png\" alt=\"\" class=\"big-stuff\" />\n\t\t\t</div>\n\n\t\t\t<div class=\"section-2\">\n\t\t\t\t\n\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-world-series.png\" alt=\"\" class=\"big-stuff\" />\n\t\t\t\t<p>Stan Musial, St. Louis Cardinals</p>\n\n\t\t\t</div>\n\n\t\t\t<div class=\"section-3\">\n\t\t\t\t\n\t\t\t\t<div class=\"grid contain grid-middle\" data-theme=\"dark\" data-year=\"1944\" data-section-title=\"Shared Turf\">\n\t\t\t\t\t\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h2>Shared Turf</h2>\n\t\t\t\t\t\t<p>The Cardinals and the Browns both called Sportsman’s Park home. So, both teams would have the home team advantage… The Cards for the first two and the last two games, and the Browns for the three in the middle.</p>\n\t\t\t\t\t\t<p>The teams shared more than just the stadium. Luke Sewell and Cardinals manager Billy Southworth shared an apartment in St. Louis. They agreed that Sewell would stay there during the Series, and Southworth would reside at a hotel until it was over.</p>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"image\">\n\t\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-poster.png\" alt=\"\" />\n\t\t\t\t\t</div>\n\n\t\t\t\t</div>\n\n\t\t\t</div>\n\n\t\t\t<div class=\"section-4\" data-theme=\"dark\" data-year=\"1944\" data-section-title=\"The World Series\">\n\n\t\t\t\t<div class=\"carousel\">\n\t\t\t\t\t<div class=\"arrow-right\"><img src=\"{{ Config.cdn }}images/arrow-right.png\" alt=\"\" /></div>\n\t\t\t\t\t<div class=\"arrow-left\"><img src=\"{{ Config.cdn }}images/arrow-left.png\" alt=\"\" /></div>\n\t\t\t\t\t<div class=\"slides\">\n\t\t\t\t\t\t<div class=\"slide\">\n\t\t\t\t\t\t\t<div class=\"wrapper\">\n\t\t\t\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-game-1.png\" alt=\"\" />\n\t\t\t\t\t\t\t\t<p>No player on the 1944 Browns roster had ever made it to a World Series. The veteran Cardinals were favored to win, but the Browns didn’t care. They came out with a fighting spirit. Denny Galehouse out-pitched Mort Cooper and the Cardinals. George McQuinn hit a two-run jack in the fourth inning. And the Browns won it, 2-1.</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div class=\"slide\">\n\t\t\t\t\t\t\t<div class=\"wrapper\">\n\t\t\t\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-game-2.png\" alt=\"\" />\n\t\t\t\t\t\t\t\t<p>The Browns were hoping luck stayed on their side. Missouri Senator, Democratic Party vice presidential nominee and future president Harry S. Truman was in the audience. The St. Louis Beer Company had given each player a silver horseshoe to hang over their lockers. However, Nelson Potter, who normally didn’t shave before he started a game, took the mound clean-shaven. </p>\n\t\t\t\t\t\t\t\t<p>The Cardinals led 2-0 through the 6th, thanks to Blix Donnelly’s stellar arm and a series of errant defensive plays. With 2 outs in the 7th, the Browns tied it up. The game stretched until the 11th, when Cardinals backup catcher and pinch hitter Ken O’Dea hit a game-winning RBI single to end the game. </p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div class=\"slide\">\n\t\t\t\t\t\t\t<div class=\"wrapper\">\n\t\t\t\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-game-3.png\" alt=\"\" />\n\t\t\t\t\t\t\t\t<p>Still at Sportsman’s Park, but now the Browns were the home team. The advantage served them well â Browns pitcher Jack Kramer gave up only 7 hits, and struck out 10 batters.</p>\n\t\t\t\t\t\t\t\t<p>It wasn’t all smooth sailing, though. Browns shortstop Vern Stephens booted a ground ball, resulting in a two-base error that eventually let the Cards score 1 in the first. The Browns came up empty-handed in the second inning with a bases-loaded strikeout. </p>\n\t\t\t\t\t\t\t\t<p>The Browns seemed to crack the code in the third, playing small ball and scoring 3 on singles, eventually landing a 6-2 victory. To that point, all of the Browns’ 10 runs in the series had been scored on 2 outs. </p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div class=\"slide\">\n\t\t\t\t\t\t\t<div class=\"wrapper\">\n\t\t\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-game-4.png\" alt=\"\" />\n\t\t\t\t\t\t\t\t<p>The Cardinals had Sig Jakucki’s number for Game 4. The 35-year-old pitcher had been out of baseball for 5 years prior to the 1944 season, but he’d still brought in 13 wins that year. But most of this game was robbery.</p> \n\t\t\t\t\t\t\t\t<p>Stan Musial took a big cut at a low fastball, and sent it out of the park. Double plays and an over-the-shoulder
5612catch suffocated the Browns offense. And an error made it 4-0, Cardinals, in the 3rd. Jakucki was pulled in the bottom of that inning. Outfielder Chet Laabs hit into a double play that scored the Browns’ one and only run, and the Redbirds went on to win it 5-1.</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div class=\"slide\">\n\t\t\t\t\t\t\t<div class=\"wrapper\">\n\t\t\t\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-game-5.png\" alt=\"\" />\n\t\t\t\t\t\t\t\t<p>With the series tied 2-2, the Browns were hoping that the Galehouse-Cooper matchup would be a repeat of their success in the first game. Through 5, it was a pitcher’s duel, with no hits for either team. </p>\n\t\t\t\t\t\t\t\t<p>Then, Ray Sanders hit a solo shot onto the right field roof â the first homer Galehouse had allowed since August 6th. Galehouse took it in stride, until Danny Litwhiler followed suit in the 8th. Cooper’s pitching struck out 12 men, just one shy of the record at the time, as he shut out the Browns, 2-0.</p> \n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div class=\"slide\">\n\t\t\t\t\t\t\t<div class=\"wrapper\">\n\t\t\t\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-game-6.png\" alt=\"\" />\n\t\t\t\t\t\t\t\t<p>It was a frosty night. Nelson Potter was back on the Browns mound, and Max Lanier threw for the Cards (who were the home team once again). The Browns took an early lead in the second within RBI single by George McQuinn, but they couldn’t hold on to the lead. A walk and a handful of singles put the Cardinals on top in the fourth inning, and that’s where they stayed. The Browns said goodbye to their “Cinderella season,” and their last-ever appearance in a World Series, with a 3-1 loss.</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\n\t\t\t</div>\n\n\t\t</div>\n\n\t</section>\n\n\t<section class=\"war-ends\">\n\t\t\n\t\t<div class=\"content\">\n\t\t\t\n\t\t\t<div class=\"section-1\" data-theme=\"light\" data-year=\"1946\" data-section-title=\"The War Ends\">\n\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-1945.png\" alt=\"\" class=\"big-stuff\" />\n\t\t\t\t<div class=\"contain\">\n\t\t\t\t\t<p>Although the Browns didn’t win the World Series, they unbelievably captured the 1944 pennant. The next year, they still had enough steam to contend in the pennant race, finishing 6 games back to take 3rd in the American League. Also in 1945, Don Barnes sold the Browns to Richard Muckerman.</p>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div class=\"section-2 contain\">\n\t\t\t\t<div class=\"grid grid-padded grid-middle\">\n\t\t\t\t\t<div class=\"grid-item image\">\n\t\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-war-years/img-crowd.png\" alt=\"\" />\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"grid-item\">\n\t\t\t\t\t\t<h2>THE WAR ENDS</h2>\n\t\t\t\t\t\t<p>Many of the baseball greats who had gone off to serve in World War II had returned home for the 1946 season, and were returning to the field. The rest of the league’s talent was replenished, and the Browns’ best years were put behind them. The 1947 and 1948 seasons saw the Browns’ return to an ever-so-familiar place â last in the American League. Both years ended with 59 wins and more than 90 losses.</p>\t\t\t\t\t\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t</div>\n\n\t</section>\n\n\t<a href=\"/#/history/the-bill-veeck-era\">\n\t\t<section class=\"next-section\" data-theme=\"\">\n\t\t\t<div class=\"content\">\n\t\t\t\t<p>Chapter 4</p>\n\t\t\t\t<h2>The Bill Veeck Era <span>→</span></h2>\n\t\t\t\t<p>1949-1953</p>\n\t\t\t</div>\n\t\t</section>\n\t</a>\n</div>", 5613 "the-bill-veeck-era": "<div class=\"border border-top\"></div>\n<div class=\"border border-right\"></div>\n<div class=\"border border-bottom\"></div>\n<div class=\"border border-left\"></div>\n\n<div class=\"inner\">\n\n\t<div class=\"timeline-bar\"></div>\n\n\t<section class=\"dewitt-brothers\">\n\n\t\t<div class=\"content\">\n\t\t\t<div class=\"section-1 contain\" data-theme=\"light\" data-year=\"1948\" data-section-title=\"The Dewitt Bros. buy the browns\">\n\n\t\t\t\t<h2>The DeWitt Brothers</h2>\n\t\t\t\t<p>Owner Richard Muckerman had proven to be ineffective during his 4 seasons as owner (1945-1948). This was quite a disappointment, following the Browns’ 1944 pennant victory. In hopes to resurrect the team’s potential, Bill DeWitt and his brother, Charlie, bought the Browns club after the 1948 season.</p>\n\n\t\t\t</div>\n\t\t\t\n\t\t\t<div class=\"section-2 contain\" data-theme=\"light\" data-year=\"1949\" data-section-title=\"Browns lose 90 games\">\n\t\t\t\t<div class=\"grid grid-middle\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-veeck-era/img-senators.jpg\" alt=\"\" />\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h2>Better Than the Senators</h2>\n\t\t\t\t\t\t<p>That was about the only recognition the Browns could muster up for the ‘49 season. They finished in 7th place with a 53-101 record, just a few games better than the 50-104 Washington Senators.</p>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t</section>\n\n\t<section class=\"veeck-background dark\">\n\t\t\n\t\t<div class=\"content\">\n\t\t\t<div class=\"section-1 contain\" data-theme=\"dark\" data-year=\"1950\" data-section-title=\"Bill Veeck buys the Browns\">\n\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-veeck-era/img-quote-beautiful.png\" alt=\"\" />\n\t\t\t\t<p class=\"attr\">- Bill Veeck</p>\n\t\t\t</div>\n\n\t\t\t<div class=\"section-2 contain\">\n\t\t\t\t<h2>
5613Bill Veeck: Background</h2>\n\t\t\t\t<p>The DeWitts sold the Browns to Bill Veeck in 1951. Veeck was coming off the best and most tumultuous times of his life. He’d signed the first black player to the American League in 1947. A year later, he signed Satchel Paige, the oldest rookie in the majors. He also led the Cleveland Indians to the team’s first pennant and World Series title since 1920. Sadly, his first wife divorced him in 1949. Strapped for cash, he sold the Indians.</p>\n\t\t\t\t<p>Things were on the upswing for him by 1950 â he married his new true love, Mary Frances Ackerman, and bought 80% stake in the Browns organization.</p>\n\n\t\t\t\t<div class=\"note\">\n\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/after-the-browns.png\" alt=\"\" class=\"show-overlay\" data-overlay=\"veeck\" />\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div data-theme=\"dark\" data-year=\"1951\" data-section-title=\"Veeck competes with Cardinals\">\n\t\t\t\t<div class=\"section-3 contain\">\n\t\t\t\t\t\n\t\t\t\t\t<div class=\"grid grid-middle\">\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-veeck-era/img-program.png\" alt=\"\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<h2>Two’s a Crowd</h2>\n\t\t\t\t\t\t\t<p>Since Day 1, Bill Veeck saw the Cardinals as a threat, not just a friendly rivalry. He tried to push them out â or at least stir up some drama at their shared home park. Veeck brought three former Cardinals over to the Browns: Rogers Hornsby and Marty Marion as coaches, and Dizzy Dean as announcer. He also decorated Sportsman’s Park solely with Browns memorabilia.</p>\n\t\t\t\t\t\t</div>\n\n\t\t\t\t\t</div>\n\n\t\t\t\t</div>\n\n\t\t\t\t<div class=\"section-4 contain\">\n\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-veeck-era/img-quote-argyin.png\" alt=\"\" />\n\t\t\t\t\t<p class=\"attr\">- Dizzy Dean</p>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t</section>\n\n\t<section class=\"free-beer\">\n\t\t<div class=\"content\">\n\t\t\t<div class=\"section-1 contain\" data-theme=\"light\" data-year=\"1951\" data-section-title=\"Free Beer Night\">\n\t\t\t\t<h2>Free Beer</h2>\n\t\t\t\t<p>For his first game as owner, Bill Veeck gave everyone in the ballpark a free beer or soda. Just imagine what he’d think of ballpark prices today.</p>\n\t\t\t</div>\n\n\t\t\t<div data-theme=\"light\" data-year=\"1951\" data-section-title=\"Eddie Gaedal walks\">\n\t\t\t\t<div class=\"section-2 contain\">\n\t\t\t\t\t<div class=\"grid grid-middle grid-padded\">\n\t\t\t\t\t\t<div class=\"image\">\n\t\t\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-veeck-era/img-1-8.png\" alt=\"\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<p>Of all of Veeck’s radical promotions â or, in his eyes, creative ways to attract a much-needed crowd â this little one left a big impact on fans’ memories. Eddie Gaedel, standing just 3-foot-7, appeared as a pinch hitter on August 19, 1951. Wearing the number â
on a jersey made for Bill DeWitt’s son, Gaedel drew four straight balls. His strike zone was tiny, as were his legs. He was replaced by a pinch runner, but his 1.000 career on-base percentage remains in tact.</p>\t\t\t\t\t\t\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t\n\t\t\t\t<div class=\"section-3\">\n\t\t\t\t\t<h5>A small threat</h5>\n\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-veeck-era/img-1000000.png\" alt=\"\" />\n\t\t\t\t\t<p>The life insurance policy Bill Veeck took out for Eddie Gaedel. Veeck threatened Gaedel with his life if he dared to swing the bat.</p>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</section>\n\n\t<section class=\"dreamers dark\">\n\t\t<div class=\"content\">\n\t\n\t\t\t<div data-theme=\"dark\" data-year=\"1951\" data-section-title=\"Fans manage from stands\">\n\t\t\t\t<div class=\"section-1 contain\">\n\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-veeck-era/img-quote-dreamers.png\" alt=\"\" />\n\t\t\t\t\t<p class=\"attr\">- Bill Veeck</p>\n\t\t\t\t</div>\n\t\t\t\t\n\t\t\t\t<div class=\"section-2 contain\">\n\t\t\t\t\t<div class=\"grid grid-padded grid-middle\">\n\t\t\t\t\t\t<div class=\"image\">\n\t\t\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-veeck-era/img-grandstand.jpg\" alt=\"\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<h2>Grandstand Manager’s Day</h2>\n\t\t\t\t\t\t\t<p>No, the managers weren’t in the stands. No, the grandstands didn’t have a new manager. Indeed, Bill Veeck appointed the fans in the grandstand to make managerial decisions throughout the game. They w
5613ould vote on whether a player should bunt, steal a base, change pitchers, and more, by holding up signs that read âYESâ or âNO.â The Browns went on to win that game 5-3, breaking their 4-game losing streak.</p>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</section>\n\n\t<section class=\"california\">\n\t\t<div class=\"content\">\n\n\t\t\t<div class=\"section-1 contain\" data-theme=\"light\" data-year=\"1952\" data-section-title=\"Veeck attempts move to L.A.\">\n\t\t\t\t<h2>California or Bust</h2>\n\t\t\t\t<p>Despite all of his efforts to bring in a crowd, Bill Veeck couldn’t bring home enough wins. The 1951 season ended with a 52-102 record. The ‘52 season was just a shade better at 64-90. Veeck tried to move the Browns to Los Angeles, but with most other teams in the Midwest or on the East Coast, the travel expenses â and the ire of other team owners â were too much for MLB execs to approve it.</p>\n\t\t\t</div>\n\t\t\t\n\t\t\t<div class=\"section-2 contain\" data-theme=\"light\" data-year=\"1953\" data-section-title=\"Anheuser-Busch buys Cardinals\">\n\t\t\t\t<div class=\"grid grid-padded grid-middle\">\n\t\t\t\t\t<div class=\"image\">\n\t\t\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-veeck-era/img-anheuser.png\" alt=\"\" />\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h2>How Beer Wrecked Veeck</h2>\n\t\t\t\t\t\t<p>Cardinals owner Fred Saigh was forced to sell the team after he was convicted of income tax evasion. It looked like Veeck had won… until August Busch, Jr., owner of Anheuser-Busch, came to bat for the Redbirds. Veeck knew the Cardinals were here to stay, and he was no match for the financial, political and social power of the Busch family.</p>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div class=\"section-3 contain\" data-theme=\"light\" data-year=\"1953\" data-section-title=\"Veeck sells Park to Cards\">\n\t\t\t\t\n\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-veeck-era/img-quote-villian.png\" alt=\"\" />\n\t\t\t\t<p class=\"attr\">â Bill Veeck in his autobiography, Veeck â As In Wreck: The Autobiography of Bill Veeck</p>\n\t\t\t\t<p>Veeck was running out of options, and running out of cash. He sold Sportsman’s Park to August Busch, Jr., for $800,000 during the 1953 season.</p>\n\n\t\t\t</div>\n\n\t\t\t<div class=\"section-4 contain\" data-theme=\"light\" data-year=\"1953\" data-section-title=\"Browns Sold and moved to Baltimore\">\n\t\t\t\t\n\t\t\t\t<h2>Baltimore-Bound</h2>\n\t\t\t\t<p>Bill Veeck wanted to move the team to Baltimore. But the American League decision-makers were still so riled up about Veeck’s antics, they denied the transfer. It’s not that they didn’t want the team to move â they simply didn’t want Veeck in Baltimore. Veeck’s only move was to sell all of his shares to a Baltimore attorney and baseball-lover, Clarence Miles.</p>\n\n\t\t\t</div>\n\t\t</div>\n\t</section>\n\n\t<section class=\"final dark\" data-theme=\"dark\" data-year=\"1953\" data-section-title=\"The End\">\n\t\t\n\t\t<div class=\"content\">\n\t\t\t<div class=\"contain\">\n\t\t\t\t<img src=\"{{ Config.cdn }}images/history/the-veeck-era/img-final-tally.png\" alt=\"\" />\n\t\t\t</div>\n\t\t</div>\n\n\t</section>\n\n\t<a href=\"/#/players\">\n\t\t<section class=\"next-section\" data-theme=\"\" data-year=\"\" data-section-title=\"\">\n\t\t\t<div class=\"content\">\n\t\t\t\t<p>More Browns History</p>\n\t\t\t\t<h2>See The Players →</h2>\n\t\t\t</div>\n\t\t</section>\n\t</a>\n\n</div>" 5614 }, 5615 5616 init: function( routeData, onComplete ) { 5617 5618 var id = routeData.params.id; 5619 5620 //- set up container 5621 $.addClass(id + ' page', this.div); 5622 5623 $.css(this.div, { 5624 padding: 0 5625 }); 5626 5627 var nav = this.nav = $.select('.nav-controller', document.body); 5628 $.removeClass(nav, 'dark'); 5629 5630 //- save current section 5631 var id = this.id = routeData.params.id; 5632 this.template = this.templates[ id ]; 5633 5634 var sectionData = this.data = _.findWhere(_data.sections, { key: id }); 5635 sectionData.Config = Config; 5636 5637 //- render main view 5638 this.render( sectionData ); 5639 5640 //- build hero 5641 this.hero = new Hero( sectionData ); 5642 5643 //- build timeline 5644 this.timeline = new HistoryTimeline(); 5645 5646 //- render hero and timeline 5647 $.prepend( this.hero.div, this.div); 5648 $.prepend( this.timeline.div, this.div); 5649 5650 //- add to the scene 5651 $.append(this.div, Stage); 5652 5653 //- save DOM queries 5654 this.wrapper = $.select('.inner', this.div); 5655 this.sections = $.select('section', this.div); 5656 this.borders = $.select('.border', this.div); 5657 this.years = $.select('[data-year]', this.div); 5658 this.timelineBar = $.select('.timeline-bar', this.div); 5659 this.carousels = []; 5660 5661 this.currentYear = null; 5662 this.currentSection = null; 5663 5664 //- create carousel(only one of them...) 5665 var c = $.select('.carousel', this.div); 5666 5667 for( var i = 0; i < c.length; i ++ ) { 5668 this.carousels[ i ] = new Carousel( c[ i ], {} ); 5669 } 5670 5671 //- save scroll position 5672 this.scr = 0; 5673 5674 //- wire event listeners 5675 this.addListeners(); 5676 5677 //- set up renderer for smooooooooooth scrolling 5678 this.renderer = new SmoothScroll( this.onRender.bind(this) ); 5679 5680 //- set scroll limits on renderer 5681 this.resize(); 5682 5683 Velocity.hook(this.timeline.div, "opacity", 0); 5684 5685 this.overlay.init( this ); 5686 5687 //- animate in 5688 onComplete(); 5689 }, 5690 5691 addListeners: function() { 5692 5693 var _this = this; 5694 var bug = $.select('.scroll', this.div); 5695 var wrapper = $.select('.inner', this.div); 5696 var max = Math.max(0, wrapper[0].scrollHeight); 5697 5698 $.on(bug[ 0 ], 'click', function() { 5699 5700 _this.renderer.setTarget(window.innerHeight * -1); 5701 5702 setTimeout(function() { 5703 _this.scrollCheck(); 5704 }, 350); 5705 }); 5706 5707 var handler = function(e) { 5708 5709 if( $.hasClass(e.target, 'show-overlay') ) { 5710 5711 e.preventDefault(); 5712 5713 var section = $.attr(e.target, 'data-overlay'); 5714 var data = _this.data[ 'overlayData' ][ section ]; 5715 5716 _this.overlay.populate(data, 'history-section'); 5717 } 5718 5719 if( $.hasClass(e.target, 'close') ) { 5720 5721 _this.overlay.animateOut(); 5722 } 5723 }; 5724 5725 if( Device.system.touch ) { 5726 $.on(this.div, 'touchend', handler); 5727 } else { 5728 $.on(this.div, 'click', handler); 5729 } 5730 5731 VirtualScroll.on(function(e) { 5732 _this.scrollCheck(e); 5733 }); 5734 }, 5735 5736 scrollCheck: Util.debounce(function(e) { 5737 5738 threshold = (e.deltaY > 0) ? 0 : 0.8; 5739 5740 if( this.scr > -100 ) { 5741 5742 $.removeClass(this.borders, 'light dark'); 5743 $.removeClass(this.timeline.div, 'light dark'); 5744 $.removeClass(this.timelineBar, 'light dark'); 5745 $.removeClass(this.nav, 'light dark'); 5746 5747 this.currentSection = 'hero'; 5748 this.currentYear = ''; 5749 } 5750 5751 if( this.scr <= (window.innerHeight * -0.65) ) { 5752 5753 if( !this.timeline.active ) { 5754 5755 this.timeline.active = true; 5756 5757 Velocity(this.timeline.div, { 5758 opacity: 1 5759 }, { 5760 duration: 1000, 5761 easing: 'easeOutCubic', 5762 }); 5763 } 5764 } else { 5765 5766 if( this.timeline.active ) { 5767 5768 this.timeline.active = false;
5769 5770 Velocity(this.timeline.div, { 5771 opacity: 0 5772 }, { 5773 duration: 250, 5774 easing: 'easeOutCubic', 5775 }); 5776 } 5777 } 5778 5779 //- check viewport vis for sections 5780 for( var i = 0; i < this.sections.length; i ++ ) { 5781 5782 var _this = this.sections[ i ]; 5783 5784 if( isVisible(_this) && _this !== this.currentSection ) { 5785 5786 this.currentSection = _this; 5787 var content = $.select('.content', _this); 5788 5789 if( !$._bonzo(content).data('visible') ) { 5790 5791 $._bonzo(content).data('visible', true); 5792 5793 Velocity(content, { 5794 opacity: [ 1, 0 ], 5795 translateY: [ 0, 50 ] 5796 }, { 5797 duration: 1200, 5798 easing: 'easeOutCubic', 5799 delay: 250 5800 }); 5801 } 5802 } 5803 } 5804 5805 //- check viewport vis for items tagged with years 5806 for( var i = 0; i < this.years.length; i ++ ) { 5807 5808 var _this = this.years[ i ]; 5809 5810 if( isVisible(_this) && this.currentYear !== _this ) { 5811 5812 // console.log(_this); 5813 5814 this.currentYear = _this; 5815 5816 var year = $.attr(_this, 'data-year'); 5817 var title = $.attr(_this, 'data-section-title'); 5818 var theme = $.attr(_this, 'data-theme') || ''; 5819 var navTheme = ( theme == "dark" ) ? '' : 'dark'; 5820 5821 $.removeClass(this.borders, 'light dark'); 5822 $.removeClass(this.timeline.div, 'light dark'); 5823 $.removeClass(this.timelineBar, 'light dark'); 5824 $.removeClass(this.nav, 'light dark'); 5825 5826 $.addClass(theme, this.borders); 5827 $.addClass(theme, this.timeline.div); 5828 $.addClass(theme, this.timelineBar); 5829 $.addClass(navTheme, this.nav); 5830 5831 this.timeline.update(year, title); 5832 } 5833 } 5834 }, 15), 5835 5836 onRender: function( scr ) { 5837 5838 this.scr = scr; 5839 5840 this.hero.onRender(scr); 5841 5842 $.transform(this.wrapper, { 5843 y: scr 5844 }); 5845 }, 5846 5847 animateOut: function( onComplete ) { 5848 5849 Velocity(this.div, { 5850 opacity: [ 0, 1 ] 5851 }, { 5852 duration: 1000, 5853 complete: onComplete 5854 }); 5855 5856 this.hero.animateOut(); 5857 this.renderer.stopRender(); 5858 }, 5859 5860 animateIn: function( onComplete ) { 5861 5862 var _this = this; 5863 5864 setTimeout(function() { 5865 _this.resize(); 5866 }, 100); 5867 5868 Velocity(this.div, { 5869 opacity: [ 1, 0 ] 5870 }, { 5871 duration: 1000, 5872 complete: onComplete, 5873 easing: 'linear' 5874 }); 5875 5876 this.renderer.startRender(); 5877 this.hero.animateIn(); 5878 }, 5879 5880 resize: function( w, h ) { 5881 5882 this.hero.resize( w, h ); 5883 5884 var wrapper = $.select('.inner', this.div); 5885 var max = Math.max(0, wrapper[0].scrollHeight); 5886 5887 this.renderer.setLimits((max * -1), 0); 5888 5889 for( var i = 0; i < this.carousels.length; i ++ ) { 5890 Util.debounce(this.carousels[ i ].resize( w, h ), 1000, false); 5891 } 5892 } 5893}); 5894 5895module.exports = HistoryView; 5896},{"./../Config":1,"./../Data":2,"./../components/Carousel":5,"./../components/DOM":6,"./../components/Device":7,"./../components/HistoryHero":10,"./../components/HistoryTimeline":11,"./../components/Overlay":15,"./../components/SmoothScroll":19,"./../components/Utils":22,"./../components/View":23,"./../components/VirtualScroll":26,"./../components/oop/Class":28,"underscore":53,"velocity-animate":54}],33:[function(require,module,exports){ 5897 5898 5899var Class = require('./../components/oop/Class'); 5900var View = require('./../components/View'); 5901var Velocity = require('velocity-animate'); 5902var $ = require('./../components/DOM'); 5903 5904var Config = require('./../Config'); 5905var _data = require('./../Data').historySection; 5906var Util = require('./../components/Utils'); 5907var SnappyScroll = require('./../components/SnappyScroll'); 5908var Shuffle = require('./../components/ShuffleLetters')(); 5909 5910var HistoryView = new Class({ 5911 5912 name: "history-view", 5913 Extends: View, 5914 template: "\n<div class=\"page-title\">\n\t<h1>{{ title }}</h1>\n</div>\n\n<div class=\"scroll-bug\">\n\t<div><img src=\"{{ config.cdn }}images/bg/icn-right-arrow.png\" alt=\"\" /></div>\n\t<h5>Scroll to explore the chapters</h5>\n</div>\n\n<div class=\"content\">\n\t\n\t<div class=\"inner\">\n\t\t<ul class=\"history-sections\">\n\t\t\t{{ #sections }}\n\t\t\t\t<li>\n\t\t\t\t\t<a href=\"/#/history/{{ key }}\">\n\t\t\t\t\t\t<img src=\"{{ config.cdn }}images/fpo/{{ overviewImage }}\" alt=\"\" />\n\t\t\t\t\t</a>\t\n\t\t\t\t</li>\n\t\t\t{{ /sections }}\n\t\t</ul>\n\t</div>\n\n</div>\n\n<div class=\"title\">\n\t<p><span>Chapter 1:</span> <a href=\"/#/history\" class=\"btn\">The Early Years</a></p>\n</div>", 5915 5916 init: function( routeData, onComplete ) { 5917 5918 _data.config = Config; 5919 5920 var nav = $.select('.nav-controller'); 5921 $.addClass('dark', nav); 5922 5923 this.render(_data); 5924 $.addClass('page', this.div); 5925 5926 this.sections = $.select('.grid-item', this.div); 5927 Velocity.hook(this.sections, "opacity", 0); 5928 5929 $.append(this.div, Stage); 5930 5931 this.wrapper = $.select('.history-sections', this.div); 5932 this.content = $.select('li', this.wrapper); 5933 this.title = $.select('.title', this.div); 5934 5935 this.renderer = new SnappyScroll( this.onRender.bind(this) ); 5936 this.renderer.setWidth( 770 ); 5937 this.renderer.setMaxIndex( this.content.length ); 5938 this.renderer.onScrollUpdate = this.onScrollUpdate.bind(this); 5939 5940 this.addListeners(); 5941 onComplete(); 5942 }, 5943 5944 addListeners: function() { 5945 5946 var _this = this; 5947 5948 $.on(this.div, 'click', function(e) { 5949 5950 var t = e.target.parentNode.parentNode; // ... 5951 5952 if( t !== _this.currentItem ) { 5953 5954 e.preventDefault(); 5955 5956 var idx = _this.content.indexOf( t ); 5957 _this.renderer.setIndex(idx); 5958 } 5959 }); 5960 }, 5961 5962 onRender: function( scr ) { 5963 5964 $.transform(this.wrapper, { 5965 x: scr 5966 }); 5967 5968 for( var i = 0; i < this.content.length; i ++ ) { 5969 5970 var offset = this.content[ i ].offsetLeft; 5971 var position = offset + scr; 5972 var absPosition = Math.abs(position); 5973 5974 //- opacity 5975 var o = (( absPosition / 15 ) / 100); 5976 o = Util.clamp(o, 0, 1); 5977 o = 1 - o; 5978 5979 //- scale 5980 var s = (( absPosition / 50 ) / 100); 5981 s = Util.clamp(s, 0, 1); 5982 s = 1 - s; 5983 5984 $.css(this.content[ i ], { 5985 opacity: o 5986 }).transform(this.content[ i ], { 5987 scale: s 5988 }); 5989 } 5990 }, 5991 5992 onScrollUpdate: function( index ) { 5993 5994 if( index !== this.lastScroll ) { 5995 5996 var item = this.currentItem = this.content[ index ]; 5997 5998 var d = _data.sections[ index ]; 5999 var ch = 'Chapter ' + (parseInt(index) + 1) + ':'; 6000 6001 var l = $.select('a', this.title); 6002 var p = $.select('span', this.title); 6003 6004 Shuffle(p, ch); 6005 Shuffle(l, d.title) 6006 6007 l[ 0 ].href = '#/history/' + d.key; 6008 } 6009 6010 this.lastScroll = index; 6011 }, 6012 6013 animateOut: function( onComplete ) { 6014 6015 Velocity(this.div, { 6016 opacity: [ 0, 1 ] 6017 }, { 6018 duration: 1000, 6019 complete: onComplete 6020 }); 6021 6022 Velocity(this.sections, "transition.fadeOut", { 6023 stagger: 500, 6024 duration: 1000, 6025 delay: 500 6026 }); 6027 6028 this.renderer.stopRender(); 6029 }, 6030 6031 animateIn: function( onComplete ) { 6032 6033 var content = $.select('.inner', this.div); 6034 var bug = $.select('.scroll-bug'); 6035 $.show(bug); 6036 6037 Velocity(this.div, { 6038 opacity: [ 1, 0 ] 6039 }, { 6040 duration: 1000, 6041 complete: onComplete, 6042 easing: 'linear' 6043 }); 6044 6045 Velocity(this.sections, "transition.fadeIn", { 6046 stagger: 500, 6047 duration: 1000, 6048 delay: 500 6049 }); 6050 6051 Velocity(content, { 6052 opacity: [ 1, 0 ], 6053 translateX: [ 0, -100 ] 6054 }, { 6055 duration: 1500, 6056 display: 'block', 6057 easing: 'easeOutCubic' 6058 }); 6059 6060 Velocity(bug, { 6061 opacity: [ 1, 0 ] 6062 }, { 6063 duration: 500, 6064 easing: 'easeOutCubic' 6065 }); 6066 6067 this.renderer.startRender(); 6068 }, 6069 6070 resize: function( w, h ) { 6071 6072 var wrapper = $.select('.history-sections', this.div); 6073 var max = Math.max(0, wrapper[0].scrollWidth - 770); 6074 6075 this.renderer.setLimits(-max, 0); 6076 } 6077}); 6078 6079module.exports = HistoryView; 6080},{"./../Config":1,"./../Data":2,"./../components/DOM":6,"./../components/ShuffleLetters":18,"./../components/SnappyScroll":20,"./../components/Utils":22,"./../components/View":23,"./../components/oop/Class":28,"velocity-animate":54}],34:[function(require,module,exports){ 6081 6082 6083var Device = require('./../components/Device'); 6084var Class = require('./../components/oop/Class'); 6085var View = require('./../components/View'); 6086var Velocity = require('velocity-animate'); 6087var $ = require('./../components/DOM'); 6088var Config = require('./../Config'); 6089 6090var HomeView = new Class({ 6091 6092 name: "home-view", 6093 Extends: View, 6094 template: "\n<div class=\"content\">\n\t<div class=\"inner\">\n\n\t\t<div class=\"title icon\">\n\t\t\tThe Indelible History <img src=\"{{ config.cdn }}images/img-intro-icon.png\" alt=\"\" /> of The St. Louis Browns \n\t\t</div>\n\n\t\t<img src=\"{{ config.cdn }}images/home-text.png\" alt=\"\" class=\"title\" />\n\n\t\t<div class=\"title play-ball\">\n\t\t\t<a href=\"/#/history\">\n\t\t\t\t<span>Play Ball →</span>\n\t\t\t\t<span>Play Ball →</span>\n\t\t\t</a>\n\t\t</div>\n\n\t</div>\n</div>", 6095 6096 init: function( data, onComplete ) { 6097 6098 var _this = this; 6099 var nav = $.select('.nav-controller'); 6100 $.removeClass(nav, 'dark'); 6101 6102 data.config = Config; 6103 6104 this.render( data ); 6105 $.addClass('page', this.div); 6106 6107 this.titles = $.select('.title', this.div); 6108 6109 Velocity.hook(this.titles, "opacity", 0); 6110 6111 if( !Device.system.touch ) { 6112 6113 var video = document.createElement('video'); 6114 video.autoplay = true; 6115 video.loop = true; 6116 6117 video.src = Config.cdn + 'video/home-loop.' + Device.media.video; 6118 6119 $.css(video, {
6120 opacity: 0 6121 }); 6122 6123 video.addEventListener('loadeddata', function(e) { 6124 6125 _this.div.appendChild(video); 6126 6127 Velocity(video, { 6128 opacity: 1 6129 }, { 6130 duration: 500 6131 }); 6132 }); 6133 6134 } 6135 6136 $.append(this.div, Stage); 6137 6138 onComplete(); 6139 }, 6140 6141 animateIn: function( onComplete ) { 6142 6143 var content = $.select('.content .inner', this.div); 6144 6145 Velocity(this.div, { 6146 opacity: [ 1, 0 ], 6147 translateZ: 0 6148 }, { 6149 duration: 4000, 6150 complete: onComplete, 6151 easing: 'easeOutCubic' 6152 }); 6153 6154 Velocity(this.titles, "transition.slideUpIn", { 6155 stagger: 400, 6156 duration: 1000, 6157 easing: 'easeOutCubic' 6158 }); 6159 6160 Velocity(content, { 6161 rotateX: [ 0, 15 ] 6162 }, { 6163 duration: 1200, 6164 easing: 'easeOutCubic' 6165 }); 6166 6167 setInterval(function() { 6168 6169 var x = (Math.random() * 6) - 3; 6170 var y = (Math.random() * 6) - 3; 6171 6172 Velocity(content, { 6173 blur: 3, 6174 translateX: x, 6175 translateY: y, 6176 translateZ: 0 6177 }, { 6178 duration: 10, 6179 loop: 1 6180 }); 6181 }, 4000); 6182 }, 6183 6184 animateOut: function( onComplete ) { 6185 6186 Velocity(this.div, { 6187 opacity: 0, 6188 translateZ: 0 6189 }, { 6190 duration: 2000, 6191 complete: onComplete, 6192 easing: 'easeOutCubic' 6193 }); 6194 6195 Velocity(this.titles, "transition.slideDownOut", { 6196 stagger: 100, 6197 duration: 500, 6198 easing: 'easeOutCubic' 6199 }); 6200 6201 }, 6202 6203 resize: function( w, h ) { 6204 6205 // console.log(w, h); 6206 } 6207}); 6208 6209module.exports = HomeView; 6210},{"./../Config":1,"./../components/DOM":6,"./../components/Device":7,"./../components/View":23,"./../components/oop/Class":28,"velocity-animate":54}],35:[function(require,module,exports){ 6211 6212 6213var Class = require('./../components/oop/Class'); 6214var View = require('./../components/View'); 6215var Velocity = require('velocity-animate'); 6216var Loop = require('raf-loop'); 6217 6218var $ = require('./../components/DOM'); 6219var Config = require('./../Config'); 6220var VirtualScroll = require('./../components/VirtualScroll')(); 6221var Util = require('./../components/Utils'); 6222 6223var _ = require('underscore'); 6224var _data = require('./../Data').players; 6225 6226var PlayersView = new Class({ 6227 6228 name: "players-list-view", 6229 Extends: View, 6230 template: "<ol class=\"players-list\">\n\t{{#players}}\n\t\t<li>\n\t\t\t<a href=\"#\" data-href=\"{{ key }}\" class=\"btn info\">\n\t\t\t\t<span data-href=\"{{ key }}\" class=\"info\">{{{ firstName }}} {{{ lastName }}}</span>\n\t\t\t</a>\n\t\t</li>\n\t{{/players}}\n</ol>", 6231 6232 init: function( data, onComplete ) { 6233 6234 var sorted = _.sortBy(_data.players, "lastName"); 6235 _data.players = sorted; 6236 6237 this.render(_data); 6238 6239 var content = $.select('.content', '.players-view'); 6240 $.append(this.div, content); 6241 6242 this.list = $.select('li', this.div); 6243 6244 $.hide(this.div); 6245 6246 Velocity.hook(this.list, "opacity", 0); 6247 }, 6248 6249 animateOut: function( newContent ) { 6250 6251 var _this = this; 6252 6253 Velocity(this.div, { 6254 opacity: 0 6255 }, { 6256 mobileHA: false, 6257 stagger: 100, 6258 duration: 250, 6259 display: 'none', 6260 complete: function() { 6261 6262 // _this.destroy(); 6263 if( newContent && newContent.animateIn ) newContent.animateIn(); 6264 } 6265 }); 6266 }, 6267 6268 animateIn: function( onComplete ) { 6269 6270 $.show(this.div); 6271 6272 Velocity(this.div, { 6273 opacity: 1 6274 }, { 6275 mobileHA: false, 6276 duration: 500 6277 }); 6278 6279 Velocity(this.list, "transition.fadeIn", { 6280 stagger: 40, 6281 duration: 400, 6282 mobileHA: false 6283 }); 6284 }, 6285 6286 resize: function( w, h ) { 6287 6288 // console.log(w, h); 6289 } 6290}); 6291 6292module.exports = PlayersView; 6293},{"./../Config":1,"./../Data":2,"./../components/DOM":6,"./../components/Utils":22,"./../components/View":23,"./../components/VirtualScroll":26,"./../components/oop/Class":28,"raf-loop":48,"underscore":53,"velocity-animate":54}],36:[function(require,module,exports){ 6294 6295 6296var Class = require('./../components/oop/Class'); 6297var View = require('./../components/View'); 6298var Velocity = require('velocity-animate'); 6299var Device = require('./../components/Device'); 6300 6301var $ = require('./../components/DOM'); 6302var Config = require('./../Config'); 6303var Util = require('./../components/Utils'); 6304var SmoothScroll = require('./../components/SmoothScroll'); 6305var Config = require('./../Config'); 6306 6307var _ = require('underscore'); 6308var _data = require('./../Data').players; 6309 6310var lastCategory = ""; 6311var isVisible = function(el) { 6312 6313 var rect = el.getBoundingClientRect(); 6314 var threshold = 0.25; 6315 6316 return ( 6317 rect.top <= (window.innerHeight * threshold) && 6318 rect.bottom >= (window.innerHeight * threshold) && 6319 rect.left >= -100 && 6320 rect.right <= window.innerWidth 6321 ); 6322}; 6323 6324var PlayersPhotoView = new Class({ 6325 6326 name: "players-photo-view", 6327 Extends: View, 6328 template: "<ol class=\"player-photos\">\n\t{{ #players }}
6328\n\t\t<li {{ #category }} data-category=\"{{ category }}\" {{ /category }}>\n\t\t\t<img src=\"{{ config.cdn }}images/players/{{ key }}.png\" alt=\"{{ name }}\" class=\"player\" />\n\t\t\t<div class=\"more-info\">\n\t\t\t\t{{ #hallOfFame }}\n\t\t\t\t\t<img src=\"{{ config.cdn }}images/hof-badge.png\" alt=\"\" class=\"badge\" />\n\t\t\t\t{{ /hallOfFame }}\n\t\t\t\t{{ #cardinalsPlayer }}\n\t\t\t\t\t<img src=\"{{ config.cdn }}images/cards-badge.png\" alt=\"\" class=\"badge\" />\n\t\t\t\t{{ /cardinalsPlayer }}\n\t\t\t\t<h2 class=\"info\" data-href=\"{{ key }}\">{{{ firstName }}} {{{ lastName }}}</h2>\n\t\t\t\t<a href=\"#\" data-href=\"{{ key }}\" class=\"btn info\">More Info</a>\n\t\t\t</div>\n\t\t</li>\n\t{{ /players }}\n</ol>\n\n<div class=\"alpha-controls\">\n\t<div class=\"grid\">\n\t\t<div class=\"indicator\"></div>\n\t\t<div data-category=\"a\" class=\"active\">A</div>\n\t\t<div data-category=\"b\">B</div>\n\t\t<div data-category=\"c\">C</div>\n\t\t<div data-category=\"d\">D</div>\n\t\t<div data-category=\"e\">E</div>\n\t\t<div data-category=\"f\">F</div>\n\t\t<div data-category=\"g\">G</div>\n\t\t<div data-category=\"h\">H</div>\n\t\t<div data-category=\"i\">I</div>\n\t\t<div data-category=\"j\">J</div>\n\t\t<div data-category=\"k\">K</div>\n\t\t<div data-category=\"l\">L</div>\n\t\t<div data-category=\"m\">M</div>\n\t\t<div data-category=\"n\">N</div>\n\t\t<div data-category=\"o\">O</div>\n\t\t<div data-category=\"p\">P</div>\n\t\t<div data-category=\"q\">Q</div>\n\t\t<div data-category=\"r\">R</div>\n\t\t<div data-category=\"s\">S</div>\n\t\t<div data-category=\"t\">T</div>\n\t\t<div data-category=\"u\">U</div>\n\t\t<div data-category=\"v\">V</div>\n\t\t<div data-category=\"w\">W</div>\n\t\t<div data-category=\"x\">X</div>\n\t\t<div data-category=\"y\">Y</div>\n\t\t<div data-category=\"z\">Z</div>\n\t</div>\n</div>", 6329 6330 init: function( data, onComplete ) { 6331 6332 var lastCategory; 6333 6334 _data.activeCategories = []; 6335 6336 var sorted = _.sortBy(_data.players, "lastName"); 6337 var grouped = _.each(sorted, function( player ) { 6338 6339 var category = player['lastName'].substr(0, 1).toLowerCase(); 6340 6341 if( category !== lastCategory ) { 6342 6343 player.category = category; 6344 lastCategory = category; 6345 6346 _data.activeCategories.push(category); 6347 } 6348 }); 6349 6350 _data.players = grouped; 6351 _data.config = Config; 6352 6353 this.render(_data); 6354 6355 var content = $.select('.content', '.players-view'); 6356 $.append(this.div, content); 6357 6358 this.controls = $.select('.alpha-controls', this.div); 6359 this.list = $.select('li', this.div); 6360 this.wrapper = $.select('.player-photos', this.div); 6361 6362 this.renderer = new SmoothScroll( this.onRender.bind(this), 0.0875 ); 6363 6364 _.each(_data.activeCategories, function(e) { 6365 6366 var el = $.select('[data-category=' + e + ']', this.controls); 6367 $.addClass('selected', el); 6368 }); 6369 6370 this.addListeners(); 6371 }, 6372 6373 addListeners: function() { 6374 6375 var _this = this; 6376 var controls = $.select('div', this.controls); 6377 var indicator = $.select('.indicator', this.controls); 6378 6379 $.on(this.controls[ 0 ], 'click', function(e) { 6380 6381 if( !$.hasClass(e.target, 'indicator') ) { 6382 6383 var category = e.target.innerHTML.toLowerCase(); 6384 var target = $.select('.player-photos [data-category=' + category + ']', Stage)[ 0 ]; 6385 6386 if( target ) { 6387 6388 _this.renderer.easer.setTarget(-target.offsetLeft); 6389 6390 $.removeClass(controls, 'active'); 6391 $.addClass('active', e.target); 6392 6393 var active = $.select('.active', _this.controls[ 0 ]); 6394 var offset = active[ 0 ].offsetLeft; 6395 6396 Velocity(indicator, { 6397 translateX: offset 6398 }, { 6399 duration: 500, 6400 easing: 'easeInOutCubic' 6401 }); 6402 } 6403 } 6404 }); 6405 6406 $.on(this.div, 'click', function(e) { 6407 6408 if( $.hasClass(e.target, 'player') ) { 6409 6410 var t = e.target.parentNode; 6411 var offset = t.offsetLeft * -1; 6412 6413 _this.renderer.setTarget(offset); 6414 } 6415 }); 6416 }, 6417 6418 onRender: function( scr ) { 6419 6420 $.transform(this.wrapper, { 6421 x: scr 6422 }); 6423 6424 for( var i = 0; i < this.list.length; i ++ ) { 6425 6426 var offset = this.list[ i ].offsetLeft; 6427 var position = offset + scr; 6428 var absPosition = Math.abs(position); 6429 var category = $.attr(this.list[ i ], 'data-category'); 6430 6431 // get current letter in view 6432 if( category && category !== lastCategory && isVisible(this.list[ i ]) ) { 6433 6434 lastCategory = category; 6435 var controls = $.select('div', this.controls); 6436 var control = $.select('[data-category="' + category + '"]', this.controls); 6437 var offset = control[ 0 ].offsetLeft; 6438 var indicator = $.select('.indicator', this.controls); 6439 6440 $.removeClass(controls, 'active'); 6441 $.addClass('active', control); 6442 6443 Velocity(indicator, { 6444 translateX: offset 6445 }, { 6446 duration: 500, 6447 easing: 'easeOutCubic', 6448 queue: false 6449 }); 6450 } 6451 6452 if( !Device.system.touch ) { 6453 //- opacity 6454 var o = (( absPosition / 8 ) / 100); 6455 o = Util.clamp(o, 0, 1); 6456 o = 1 - o; 6457 6458 //- x offset 6459 var tx = absPosition / 7; 6460 Util.clamp(tx, 0, 100); 6461 6462 $.transform(this.list[ i ], { 6463 x: tx 6464 }); 6465 6466 $.css(this.list[ i ], { 6467 opacity: o 6468 }); 6469 } 6470 } 6471 }, 6472 6473 animateOut: function( newContent ) { 6474 6475 var _this = this; 6476 6477 Velocity(this.div, { 6478 opacity: 0, 6479 left: [ 100, 0 ] 6480 }, { 6481 duration: 750, 6482 easing: 'easeOutCubic', 6483 display: 'none', 6484 mobileHA: false, 6485 complete: function() { 6486 6487 if( newContent && newContent.animateIn ) newContent.animateIn(); 6488 } 6489 }); 6490 6491 // accomodate for whole div moving... 6492 Velocity(this.controls, { 6493 translateX: [ -100, 0 ], 6494 translateZ: 0 6495 }, { 6496 duration: 750, 6497 display: 'block', 6498 easing: 'easeOutCubic' 6499 }); 6500 6501 var bug = $.select('.scroll-bug'); 6502
6503 Velocity(bug, { 6504 opacity: 0 6505 }, { 6506 duration: 500, 6507 easing: 'easeOutCubic' 6508 }); 6509 6510 this.renderer.stopRender(); 6511 }, 6512 6513 animateIn: function( onComplete ) { 6514 6515 $.show(this.div); 6516 6517 this.renderer.startRender(); 6518 6519 Velocity(this.div, { 6520 opacity: [ 1, 0 ], 6521 left: [ 0, -100 ] 6522 }, { 6523 duration: 1500, 6524 display: 'block', 6525 easing: 'easeOutCubic', 6526 mobileHA: false 6527 }); 6528 6529 // accomodate for whole div moving... 6530 Velocity(this.controls, { 6531 translateX: [ 0, 100 ], 6532 translateZ: 0 6533 }, { 6534 duration: 1500, 6535 display: 'block', 6536 easing: 'easeOutCubic' 6537 }); 6538 6539 var bug = $.select('.scroll-bug'); 6540 Velocity.hook(bug, "opacity", 0); 6541 $.show(bug); 6542 6543 Velocity(bug, { 6544 opacity: 1 6545 }, { 6546 duration: 500, 6547 easing: 'easeOutCubic' 6548 }); 6549 }, 6550 6551 resize: function( w, h ) { 6552 6553 var wrapper = $.select('.player-photos', this.div); 6554 var max = Math.max(0, ( wrapper[0].scrollWidth - (window.innerWidth - 400) )); 6555 6556 this.renderer.setLimits((max * -1), 0); 6557 } 6558}); 6559 6560module.exports = PlayersPhotoView; 6561},{"./../Config":1,"./../Data":2,"./../components/DOM":6,"./../components/Device":7,"./../components/SmoothScroll":19,"./../components/Utils":22,"./../components/View":23,"./../components/oop/Class":28,"underscore":53,"velocity-animate":54}],37:[function(require,module,exports){ 6562 6563 6564var Class = require('./../components/oop/Class'); 6565var View = require('./../components/View'); 6566var Velocity = require('velocity-animate'); 6567 6568var ListView = require('./PlayersListView'); 6569var PhotoView = require('./PlayersPhotoView'); 6570var Overlay = require('./../components/Overlay'); 6571 6572var $ = require('./../components/DOM'); 6573var Config = require('./../Config'); 6574var VirtualScroll = require('./../components/VirtualScroll')(); 6575var Util = require('./../components/Utils'); 6576 6577var _ = require('underscore'); 6578var _data = require('./../Data').players; 6579 6580 6581var PlayersView = new Class({ 6582 6583 name: "players-view", 6584 Extends: View, 6585 template: "<div class=\"page-title\">\n\t<h1>{{ title}}</h1>\n</div>\n\n<div class=\"scroll-bug\" style=\"display: none;\">\n\t<div><img src=\"{{ config.cdn }}images/bg/icn-right-arrow.png\" alt=\"\" /></div>\n\t<h5>Scroll to explore notable and living browns players</h5>\n</div>\n\n<div class=\"content\"></div>\n\n<div class=\"controls\">\n\t<ul>\n\t\t<li class=\"explore active\">Explore</li>\n\t\t<li class=\"list\">List</li>\n\t</ul>\n</div>", 6586 overlay: new Overlay(), 6587 6588 init: function( data, onComplete ) { 6589 6590 var nav = $.select('.nav-controller'); 6591 $.addClass('dark', nav); 6592 6593 _data.config = Config; 6594 6595 this.data = _data; 6596 6597 this.render(this.data); 6598 $.addClass('page', this.div); 6599 6600 $.append(this.div, Stage); 6601 6602 //- initialize separate views 6603 this.photoView = new PhotoView(); 6604 this.listView = new ListView(); 6605 6606 this.listView.init(); 6607 this.photoView.init(); 6608 6609 this.overlay.init( this ); 6610 this.currentView = this.photoView; 6611 6612 this.addListeners(); 6613 onComplete(); 6614 }, 6615 6616 addListeners: function() { 6617 6618 var _this = this; 6619 var controls = $.select('.controls', this.div); 6620 var controlItems = $.select('li', controls); 6621 6622 $.on(controls[ 0 ], 'click', function(e) { 6623 6624 if( $.hasClass(e.target, 'list') ) { 6625 6626 $.removeClass(controlItems, 'active'); 6627 _this.swap(_this.listView); 6628 _this.currentView = _this.listView; 6629 $.addClass('active', controlItems[ 1 ]); 6630 } else if( $.hasClass(e.target, 'explore') ) { 6631 6632 $.removeClass(controlItems, 'active'); 6633 _this.swap(_this.photoView); 6634 _this.currentView = _this.photoView; 6635 $.addClass('active', controlItems[ 0 ]); 6636 } 6637 }); 6638 6639 $.on(this.div, 'click', function(e) { 6640 6641 var attr = $.attr(e.target, 'data-href'); 6642 var btn = $.hasClass(e.target, 'info'); 6643 var overlay = e.target.className == 'close'; 6644 6645 if( attr && btn ) { 6646 6647 e.preventDefault(); 6648 e.stopPropagation(); 6649 6650 var player = _.findWhere(_data.players, { "key": attr }); 6651 _this.showOverlay( player ); 6652 } else if( overlay ) { 6653 6654 e.preventDefault(); 6655 _this.hideOverlay(); 6656 } 6657 }); 6658 }, 6659 6660 swap: function( newContent ) { 6661 6662 this.currentView.animateOut(newContent); 6663 }, 6664 6665 animateOut: function( onComplete ) { 6666 6667 Velocity(this.div, { 6668 opacity: [ 0, 1 ] 6669 }, { 6670 duration: 1000, 6671 complete: onComplete 6672 }); 6673 6674 this.currentView.animateOut(); 6675 }, 6676 6677 animateIn: function( onComplete ) { 6678 6679 Velocity(this.div, { 6680 opacity: [ 1, 0 ] 6681 }, { 6682 duration: 1000, 6683 complete: onComplete, 6684 easing: 'linear' 6685 }); 6686 6687 this.currentView.animateIn(); 6688 }, 6689 6690 showOverlay: function( playerData ) { 6691 6692 this.overlay.populate( playerData, "players" ); 6693 6694 Velocity(this.currentView.div, { 6695 opacity: [ 0.5, 1 ] 6696 }, { 6697 duration: 1500, 6698 easing: 'easeOutCubic', 6699 mobileHA: false 6700 }); 6701 6702 if( this.currentView == this.photoView ) { 6703 6704 this.photoView.renderer.stopRender(); 6705 } 6706 }, 6707 6708 hideOverlay: function() { 6709 6710 Velocity(this.currentView.div, { 6711 opacity: [ 1, 0.5 ] 6712 }, { 6713 duration: 500, 6714 easing: 'easeOutCubic', 6715 mobileHA: false 6716 }); 6717 6718 this.overlay.animateOut(); 6719 6720 if( this.currentView == this.photoView ) { 6721 6722 this.photoView.renderer.startRender(); 6723 } 6724 }, 6725 6726 resize: function( w, h ) { 6727 6728 this.photoView.resize( w, h ); 6729 this.overlay.resize( w, h ); 6730 } 6731}); 6732 6733module.exports = PlayersView; 6734},{"./../Config":1,"./../Data":2,"./../components/DOM":6,"./../components/Overlay":15,"./../components/Utils":22,"./../components/View":23,"./../components/VirtualScroll":26,"./../components/oop/Class":28,"./PlayersListView":35,"./PlayersPhotoView":36,"underscore":53,"velocity-animate":54}],38:[function(require,module,exports){ 6735 6736 6737var Class = require('./../components/oop/Class'); 6738var View = require('./../components/View'); 6739var Velocity = require('velocity-animate'); 6740var $ = require('./../components/DOM'); 6741var Config = require('./../Config'); 6742 6743var Preloader = require('./../components/PreLoader'); 6744var Ticker = require('./../components/Ticker'); 6745 6746var Images = require('./../components/Bundle'); 6747var ImagesContainer = $.select('#image-store')[ 0 ]; 6748 6749var PreloaderView = new Class({ 6750 6751 name: "preloader", 6752 Extends: View, 6753 template: "<div class=\"content\">\n\t<img src=\"{{ config.cdn }}images/bg/loading.gif\" alt=\"\" />\n\t<div class=\"progress\"></div>\n</div>", 6754 6755 initialize: function( onComplete ) { 6756 6757 var _this = this; 6758 var data = { 6759 config: Config 6760 }; 6761 6762 this.onPreloadComplete = onComplete; 6763 6764 this.loader = new Preloader(Images, { 6765 pipeline: true, 6766 onProgress: _this.onProgress.bind(this), 6767 onComplete: _this.onComplete.bind(this) 6768 }); 6769 6770 this.render(data, document.body); 6771 6772 this.progress = $.select('.progress', this.div)[ 0 ]; 6773 }, 6774 6775 animateIn: function( onComplete ) { 6776 6777 6778 }, 6779 6780 animateOut: function( onComplete ) { 6781 6782 Velocity(this.div, { 6783 opacity: 0 6784 }, { 6785 display: 'none', 6786 duration: 1200,
6787 complete: onComplete 6788 }); 6789 }, 6790 6791 onProgress: function( img, imageEl, index ) { 6792 6793 // fires every time an image is done or errors. 6794 // imageEl will be falsy if error 6795 // console.log('just ' + (!imageEl ? 'failed: ' : 'loaded: ') + img); 6796 6797 ImagesContainer.appendChild( imageEl ); 6798 6799 var percent = Math.floor((100 / this.loader.queue.length) * this.loader.completed.length); 6800 6801 this.progress.innerHTML = percent + '%'; 6802 }, 6803 6804 onComplete: function( loaded, errors ) { 6805 6806 // fires when whole list is done. cache is primed. 6807 // console.log('done', loaded); 6808 6809 ImagesContainer.parentNode.removeChild( ImagesContainer ); 6810 6811 if ( errors ) { 6812 console.log('the following failed', errors); 6813 } 6814 6815 this.onPreloadComplete(); 6816 }, 6817 6818 destroy: function() { 6819 6820 document.body.removeChild(this.div); 6821 } 6822}); 6823 6824module.exports = PreloaderView; 6825},{"./../Config":1,"./../components/Bundle":4,"./../components/DOM":6,"./../components/PreLoader":16,"./../components/Ticker":21,"./../components/View":23,"./../components/oop/Class":28,"velocity-animate":54}],39:[function(require,module,exports){ 6826 6827 6828var Class = require('./../components/oop/Class'); 6829var View = require('./../components/View'); 6830var Velocity = require('velocity-animate'); 6831var $ = require('./../components/DOM'); 6832 6833var StoreView = new Class({ 6834 6835 name: "store-view", 6836 Extends: View, 6837 template: "<div class=\"page-title\">\n\t<h1>Store</h1>\n</div>", 6838 6839 init: function( data, onComplete ) { 6840 6841 var nav = $.select('.nav-controller'); 6842 $.addClass('dark', nav); 6843 6844 var stage = document.querySelector('#stage'); 6845 this.render(data, stage); 6846 $.addClass('page', this.div); 6847 6848 onComplete(); 6849 }, 6850 6851 animateOut: function( onComplete ) { 6852 6853 Velocity(this.div, { 6854 opacity: [ 0, 1 ] 6855 }, { 6856 duration: 1000, 6857 complete: onComplete 6858 }); 6859 }, 6860 6861 animateIn: function( onComplete ) { 6862 6863 Velocity(this.div, { 6864 opacity: [ 1, 0 ] 6865 }, { 6866 duration: 1000, 6867 complete: onComplete, 6868 easing: 'linear' 6869 }); 6870 }, 6871 6872 resize: function( w, h ) { 6873 6874 // console.log(w, h); 6875 } 6876}); 6877 6878module.exports = StoreView; 6879},{"./../components/DOM":6,"./../components/View":23,"./../components/oop/Class":28,"velocity-animate":54}],40:[function(require,module,exports){ 6880var Framework = require('./app/components/Application'); 6881var $ = require('./app/components/DOM'); 6882 6883var PreLoader = require('./app/views/PreloaderView'); 6884var Nav = require('./app/components/Nav'); 6885var HomeView = require('./app/views/HomeView'); 6886var HistoryView = require('./app/views/HistoryView'); 6887var HistorySectionView = require('./app/views/HistorySectionView'); 6888var PlayersView = require('./app/views/PlayersView'); 6889var StoreView = require('./app/views/StoreView'); 6890var BlogPostView = require('./app/views/BlogPostView'); 6891var ContactView = require('./app/views/ContactView'); 6892var GenericView = require('./app/views/GenericView'); 6893 6894var Device = require('./app/components/Device'); 6895 6896(function() { 6897 6898 var nav = new Nav(); 6899 6900 var app = Framework({ 6901 autoResize: true, 6902 overlap: !Device.system.touch, 6903 initSection: PreLoader, 6904 onRoute: nav.animateOut.bind( nav ), 6905 routes: { 6906 '/': HomeView, 6907 '/history': HistoryView, 6908 '/history/:id': HistorySectionView, 6909 '/players': PlayersView, 6910 '/about': GenericView, 6911 '/membership': GenericView, 6912 '/store': StoreView, 6913 '/news-and-events': GenericView, 6914 '/news-and-events/:id': BlogPostView, 6915 '/contact': GenericView 6916 } 6917 }); 6918 6919 //- kickitoff 6920 var exp = window && Device.system.pushstate && window.innerWidth > 767; 6921 6922 if( exp ) { 6923 6924 window.Stage = $.select('#stage')[ 0 ]; 6925 app.init(); 6926 6927 if( Device.system.touch ) { 6928 6929 document.addEventListener('touchmove', function(e) { 6930 6931 e.preventDefault(); 6932 }); 6933 } 6934 } else { 6935 6936 window.location = '/fallback'; 6937 } 6938})(); 6939},{"./app/components/Application":3,"./app/components/DOM":6,"./app/components/Device":7,"./app/components/Nav":13,"./app/views/BlogPostView":29,"./app/views/ContactView":30,"./app/views/GenericView":31,"./app/views/HistorySectionView":32,"./app/views/HistoryView":33,"./app/views/HomeView":34,"./app/views/PlayersView":37,"./app/views/PreloaderView":38,"./app/views/StoreView":39}],41:[function(require,module,exports){ 6940/*! 6941 * Bonzo: DOM Utility (c) Dustin Diaz 2012 6942 * https://github.com/ded/bonzo 6943 * License MIT 6944 */ 6945(function (name, context, definition) { 6946 if (typeof module != 'undefined' && module.exports) module.exports = definition() 6947 else if (typeof define == 'function' && define.amd) define(definition) 6948 else context[name] = definition() 6949}
6949)('bonzo', this, function() { 6950 var win = window 6951 , doc = win.document 6952 , html = doc.documentElement 6953 , parentNode = 'parentNode' 6954 , specialAttributes = /^(checked|value|selected|disabled)$/i 6955 // tags that we have trouble inserting *into* 6956 , specialTags = /^(select|fieldset|table|tbody|tfoot|td|tr|colgroup)$/i 6957 , simpleScriptTagRe = /\s*<script +src=['"]([^'"]+)['"]>/ 6958 , table = ['<table>', '</table>', 1] 6959 , td = ['<table><tbody><tr>', '</tr></tbody></table>', 3] 6960 , option = ['<select>', '</select>', 1] 6961 , noscope = ['_', '', 0, 1] 6962 , tagMap = { // tags that we have trouble *inserting* 6963 thead: table, tbody: table, tfoot: table, colgroup: table, caption: table 6964 , tr: ['<table><tbody>', '</tbody></table>', 2] 6965 , th: td , td: td 6966 , col: ['<table><colgroup>', '</colgroup></table>', 2] 6967 , fieldset: ['<form>', '</form>', 1] 6968 , legend: ['<form><fieldset>', '</fieldset></form>', 2] 6969 , option: option, optgroup: option 6970 , script: noscope, style: noscope, link: noscope, param: noscope, base: noscope 6971 } 6972 , stateAttributes = /^(checked|selected|disabled)$/ 6973 , hasClass, addClass, removeClass 6974 , uidMap = {} 6975 , uuids = 0 6976 , digit = /^-?[\d\.]+$/ 6977 , dattr = /^data-(.+)$/ 6978 , px = 'px' 6979 , setAttribute = 'setAttribute' 6980 , getAttribute = 'getAttribute' 6981 , features = function() { 6982 var e = doc.createElement('p') 6983 return { 6984 transform: function () { 6985 var props = ['transform', 'webkitTransform', 'MozTransform', 'OTransform', 'msTransform'], i 6986 for (i = 0; i < props.length; i++) { 6987 if (props[i] in e.style) return props[i] 6988 } 6989 }() 6990 , classList: 'classList' in e 6991 } 6992 }() 6993 , whitespaceRegex = /\s+/ 6994 , toString = String.prototype.toString 6995 , unitless = { lineHeight: 1, zoom: 1, zIndex: 1, opacity: 1, boxFlex: 1, WebkitBoxFlex: 1, MozBoxFlex: 1 } 6996 , query = doc.querySelectorAll && function (selector) { return doc.querySelectorAll(selector) } 6997 6998 6999 function getStyle(el, property) { 7000 var value = null 7001 , computed = doc.defaultView.getComputedStyle(el, '') 7002 computed && (value = computed[property]) 7003 return el.style[property] || value 7004 } 7005 7006 7007 function isNode(node) { 7008 return node && node.nodeName && (node.nodeType == 1 || node.nodeType == 11) 7009 } 7010 7011 7012 function normalize(node, host, clone) { 7013 var i, l, ret 7014 if (typeof node == 'string') return bonzo.create(node) 7015 if (isNode(node)) node = [ node ] 7016 if (clone) { 7017 ret = [] // don't change original array 7018 for (i = 0, l = node.length; i < l; i++) ret[i] = cloneNode(host, node[i]) 7019 return ret 7020 } 7021 return node 7022 } 7023 7024 /** 7025 * @param {string} c a class name to test 7026 * @return {boolean} 7027 */ 7028 function classReg(c) { 7029 return new RegExp('(^|\\s+)' + c + '(\\s+|$)') 7030 } 7031 7032 7033 /** 7034 * @param {Bonzo|Array} ar 7035 * @param {function(Object, number, (Bonzo|Array))} fn 7036 * @param {Object=} opt_scope 7037 * @param {boolean=} opt_rev 7038 * @return {Bonzo|Array} 7039 */ 7040 function each(ar, fn, opt_scope, opt_rev) { 7041 var ind, i = 0, l = ar.length 7042 for (; i < l; i++) { 7043 ind = opt_rev ? ar.length - i - 1 : i 7044 fn.call(opt_scope || ar[ind], ar[ind], ind, ar) 7045 } 7046 return ar 7047 } 7048 7049 7050 /** 7051 * @param {Bonzo|Array} ar 7052 * @param {function(Object, number, (Bonzo|Array))} fn 7053 * @param {Object=} opt_scope 7054 * @return {Bonzo|Array} 7055 */ 7056 function deepEach(ar, fn, opt_scope) { 7057 for (var i = 0, l = ar.length; i < l; i++) { 7058 if (isNode(ar[i])) { 7059 deepEach(ar[i].childNodes, fn, opt_scope) 7060 fn.call(opt_scope || ar[i], ar[i], i, ar) 7061 } 7062 } 7063 return ar 7064 } 7065 7066 7067 /** 7068 * @param {string} s 7069 * @return {string} 7070 */ 7071 function camelize(s) { 7072 return s.replace(/-(.)/g, function (m, m1) { 7073 return m1.toUpperCase() 7074 }) 7075 } 7076 7077 7078 /** 7079 * @param {string} s 7080 * @return {string} 7081 */ 7082 function decamelize(s) { 7083 return s ? s.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase() : s 7084 } 7085 7086 7087 /** 7088 * @param {Element} el 7089 * @return {*} 7090 */ 7091 function data(el) { 7092 el[getAttribute]('data-node-uid') || el[setAttribute]('data-node-uid', ++uuids) 7093 var uid = el[getAttribute]('data-node-uid') 7094 return uidMap[uid] || (uidMap[uid] = {}) 7095 } 7096 7097 7098 /** 7099 * removes the data associated with an element 7100 * @param {Element} el 7101 */ 7102 function clearData(el) { 7103 var uid = el[getAttribute]('data-node-uid') 7104 if (uid) delete uidMap[uid] 7105 } 7106 7107 7108 function dataValue(d) { 7109 var f 7110 try { 7111 return (d === null || d === undefined) ? undefined : 7112 d === 'true' ? true : 7113 d === 'false' ? false : 7114 d === 'null' ? null : 7115 (f = parseFloat(d)) == d ? f : d; 7116 } catch(e) {} 7117 return undefined 7118 } 7119 7120 7121 /** 7122 * @param {Bonzo|Array} ar 7123 * @param {function(Object, number, (Bonzo|Array))} fn 7124 * @param {Object=} opt_scope 7125 * @return {boolean} whether `some`thing was found 7126 */ 7127 function some(ar, fn, opt_scope) { 7128 for (var i = 0, j = ar.length; i < j; ++i) if (fn.call(opt_scope || null, ar[i], i, ar)) return true 7129 return false 7130 } 7131 7132 7133 /** 7134 * this could be a giant enum of CSS properties 7135 * but in favor of file size sans-closure deadcode optimizations 7136 * we're just asking for any ol string 7137 * then it gets transformed into the appropriate style property for JS access 7138 * @param {string} p 7139 * @return {string} 7140 */ 7141 function styleProperty(p) { 7142 (p == 'transform' && (p = features.transform)) || 7143 (/^transform-?[Oo]rigin$/.test(p) && (p = features.transform + 'Origin')) 7144 return p ? camelize(p) : null 7145 } 7146 7147 // this insert method is intense 7148 function insert(target, host, fn, rev) { 7149 var i = 0, self = host || this, r = [] 7150 // target nodes could be a css selector if it's a string and a selector engine is present 7151 // otherwise, just use target 7152 , nodes = query && typeof target == 'string' && target.charAt(0) != '<' ? query(target) : target 7153 // normalize each node in case it's still a string and we need to create nodes on the fly 7154 each(normalize(nodes), function (t, j) { 7155 each(self, function (el) { 7156 fn(t, r[i++] = j > 0 ? cloneNode(self, el) : el) 7157 }, null, rev) 7158 }, this, rev) 7159 self.length = i 7160 each(r, function (e) { 7161 self[--i] = e 7162 }, null, !rev) 7163 return self 7164 } 7165 7166 7167 /** 7168 * sets an element to an explicit x/y position on the page 7169 * @param {Element} el 7170 * @param {?number} x 7171 * @param {?number} y 7172 */ 7173 function xy(el, x, y) { 7174 var $el = bonzo(el) 7175 , style = $el.css('position') 7176 , offset = $el.offset() 7177 , rel = 'relative' 7178 , isRel = style == rel 7179 , delta = [parseInt($el.css('left'), 10), parseInt($el.css('top'), 10)] 7180 7181 if (style == 'static') { 7182 $el.css('position', rel) 7183 style = rel 7184 } 7185 7186 isNaN(delta[0]) && (delta[0] = isRel ? 0 : el.offsetLeft) 7187 isNaN(delta[1]) && (delta[1] = isRel ? 0 : el.offsetTop) 7188 7189 x != null && (el.style.left = x - offset.left + delta[0] + px) 7190 y != null && (el.style.top = y - offset.top + delta[1] + px) 7191 7192 } 7193 7194 // classList support for class management 7195 // altho to be fair, the api sucks because it won't accept multiple classes at once 7196 if (features.classList) { 7197 hasClass = function (el, c) { 7198 return el.classList.contains(c) 7199 } 7200 addClass = function (el, c) { 7201 el.classList.add(c) 7202 } 7203 removeClass = function (el, c) { 7204 el.classList.remove(c) 7205 } 7206 } 7207 else { 7208 hasClass = function (el, c) { 7209 return classReg(c).test(el.className) 7210 } 7211 addClass = function (el, c) { 7212 el.className = (el.className + ' ' + c).trim() 7213 } 7214 removeClass = function (el, c) { 7215 el.className = (el.className.replace(classReg(c), ' ')).trim() 7216 } 7217 } 7218 7219 7220 /** 7221 * this allows method calling for setting values 7222 * 7223 * @example 7224 * bonzo(elements).css('color', function (el) { 7225 * return el.getAttribute('data-original-color') 7226 * }) 7227 * 7228 * @param {Element} el 7229 * @param {function (Element)|string} v 7230 * @return {string} 7231 */ 7232 function setter(el, v) { 7233 return typeof v == 'function' ? v.call(el, el) : v 7234 } 7235 7236 function scroll(x, y, type) { 7237 var el = this[0] 7238 if (!el) return this 7239 if (x == null && y == null) { 7240 return (isBody(el) ? getWindowScroll() : { x: el.scrollLeft, y: el.scrollTop })[type] 7241 } 7242 if (isBody(el)) { 7243 win.scrollTo(x, y) 7244 } else { 7245 x != null && (el.scrollLeft = x) 7246 y != null && (el.scrollTop = y) 7247 } 7248 return this 7249 } 7250 7251 /** 7252 * @constructor 7253 * @param {Array.<Element>|Element|Node|string} elements 7254 */ 7255 function Bonzo(elements) { 7256 this.length = 0 7257 if (elements) { 7258 elements = typeof elements !== 'string' && 7259 !elements.nodeType && 7260 typeof elements.length !== 'undefined' ? 7261 elements : 7262 [elements] 7263 this.length = elements.length 7264 for (var i = 0; i < elements.length; i++) this[i] = elements[i] 7265 } 7266 } 7267 7268 Bonzo.prototype = { 7269 7270 /** 7271 * @param {number} index 7272 * @return {Element|Node} 7273 */ 7274 get: function (index) { 7275 return this[index] || null 7276 } 7277 7278 // itetators 7279 /** 7280 * @param {function(Element|Node)} fn 7281 * @param {Object=} opt_scope 7282 * @return {Bonzo} 7283 */ 7284 , each: function (fn, opt_scope) { 7285 return each(this, fn, opt_scope) 7286 } 7287 7288 /** 7289 * @param {Function} fn 7290 * @param {Object=} opt_scope 7291 * @return {Bonzo} 7292 */ 7293 , deepEach: function (fn, opt_scope) { 7294 return deepEach(this, fn, opt_scope) 7295 } 7296 7297 7298 /** 7299 * @param {Function} fn 7300 * @param {Function=} opt_reject 7301 * @return {Array} 7302 */ 7303 , map: function (fn, opt_reject) { 7304 var m = [], n, i 7305 for (i = 0; i < this.length; i++) { 7306 n = fn.call(this, this[i], i) 7307 opt_reject ? (opt_reject(n) && m.push(n)) : m.push(n) 7308 } 7309 return m 7310 } 7311 7312 // text and html inserters! 7313 7314 /** 7315 * @param {string} h the HTML to insert 7316 * @param {boolean=} opt_text whether to set or get text content 7317 * @return {Bonzo|string} 7318 */ 7319 , html: function (h, opt_text) { 7320 var method = opt_text 7321 ? 'textContent' 7322 : 'innerHTML' 7323 , that = this 7324 , append = function (el, i) { 7325 each(normalize(h, that, i), function (node) { 7326 el.appendChild(node) 7327 }) 7328 } 7329 , updateElement = function (el, i) { 7330 try { 7331 if (opt_text || (typeof h == 'string' && !specialTags.test(el.tagName))) { 7332 return el[method] = h 7333 } 7334 } catch (e) {} 7335 append(el, i) 7336 } 7337 return typeof h != 'undefined' 7338 ? this.empty().each(updateElement) 7339 : this[0] ? this[0][method] : '' 7340 } 7341 7342 /** 7343 * @param {string=} opt_text the text to set, otherwise this is a getter 7344 * @return {Bonzo|string} 7345 */ 7346 , text: function (opt_text) { 7347 return this.html(opt_text, true) 7348 } 7349 7350 // more related insertion methods 7351 7352 /** 7353 * @param {Bonzo|string|Element|Array} node 7354 * @return {Bonzo} 7355 */ 7356 , append: function (node) { 7357 var that = this 7358 return this.each(function (el, i) { 7359 each(normalize(node, that, i), function (i) { 7360 el.appendChild(i) 7361 }) 7362 }) 7363 } 7364 7365 7366 /** 7367 * @param {Bonzo|string|Element|Array} node 7368 * @return {Bonzo} 7369 */ 7370 , prepend: function (node) { 7371 var that = this 7372 return this.each(function (el, i) { 7373 var first = el.firstChild 7374 each(normalize(node, that, i), function (i) { 7375 el.insertBefore(i, first) 7376 }) 7377 }) 7378 } 7379 7380 7381 /** 7382 * @param {Bonzo|string|Element|Array} target the location for which you'll insert your new content 7383 * @param {Object=} opt_host an optional host scope (primarily used when integrated
7383with Ender) 7384 * @return {Bonzo} 7385 */ 7386 , appendTo: function (target, opt_host) { 7387 return insert.call(this, target, opt_host, function (t, el) { 7388 t.appendChild(el) 7389 }) 7390 } 7391 7392 7393 /** 7394 * @param {Bonzo|string|Element|Array} target the location for which you'll insert your new content 7395 * @param {Object=} opt_host an optional host scope (primarily used when integrated with Ender) 7396 * @return {Bonzo} 7397 */ 7398 , prependTo: function (target, opt_host) { 7399 return insert.call(this, target, opt_host, function (t, el) { 7400 t.insertBefore(el, t.firstChild) 7401 }, 1) 7402 } 7403 7404 7405 /** 7406 * @param {Bonzo|string|Element|Array} node 7407 * @return {Bonzo} 7408 */ 7409 , before: function (node) { 7410 var that = this 7411 return this.each(function (el, i) { 7412 each(normalize(node, that, i), function (i) { 7413 el[parentNode].insertBefore(i, el) 7414 }) 7415 }) 7416 } 7417 7418 7419 /** 7420 * @param {Bonzo|string|Element|Array} node 7421 * @return {Bonzo} 7422 */ 7423 , after: function (node) { 7424 var that = this 7425 return this.each(function (el, i) { 7426 each(normalize(node, that, i), function (i) { 7427 el[parentNode].insertBefore(i, el.nextSibling) 7428 }, null, 1) 7429 }) 7430 } 7431 7432 7433 /** 7434 * @param {Bonzo|string|Element|Array} target the location for which you'll insert your new content 7435 * @param {Object=} opt_host an optional host scope (primarily used when integrated with Ender) 7436 * @return {Bonzo} 7437 */ 7438 , insertBefore: function (target, opt_host) { 7439 return insert.call(this, target, opt_host, function (t, el) { 7440 t[parentNode].insertBefore(el, t) 7441 }) 7442 } 7443 7444 7445 /** 7446 * @param {Bonzo|string|Element|Array} target the location for which you'll insert your new content 7447 * @param {Object=} opt_host an optional host scope (primarily used when integrated with Ender) 7448 * @return {Bonzo} 7449 */ 7450 , insertAfter: function (target, opt_host) { 7451 return insert.call(this, target, opt_host, function (t, el) { 7452 var sibling = t.nextSibling 7453 sibling ? 7454 t[parentNode].insertBefore(el, sibling) : 7455 t[parentNode].appendChild(el) 7456 }, 1) 7457 } 7458 7459 7460 /** 7461 * @param {Bonzo|string|Element|Array} node 7462 * @return {Bonzo} 7463 */ 7464 , replaceWith: function (node) { 7465 var that = this 7466 return this.each(function (el, i) { 7467 each(normalize(node, that, i), function (i) { 7468 el[parentNode] && el[parentNode].replaceChild(i, el) 7469 }) 7470 }) 7471 } 7472 7473 /** 7474 * @param {Object=} opt_host an optional host scope (primarily used when integrated with Ender) 7475 * @return {Bonzo} 7476 */ 7477 , clone: function (opt_host) { 7478 var ret = [] // don't change original array 7479 , l, i 7480 for (i = 0, l = this.length; i < l; i++) ret[i] = cloneNode(opt_host || this, this[i]) 7481 return bonzo(ret) 7482 } 7483 7484 // class management 7485 7486 /** 7487 * @param {string} c 7488 * @return {Bonzo} 7489 */ 7490 , addClass: function (c) { 7491 c = toString.call(c).split(whitespaceRegex) 7492 return this.each(function (el) { 7493 // we `each` here so you can do $el.addClass('foo bar') 7494 each(c, function (c) { 7495 if (c && !hasClass(el, setter(el, c))) 7496 addClass(el, setter(el, c)) 7497 }) 7498 }) 7499 } 7500 7501 7502 /** 7503 * @param {string} c 7504 * @return {Bonzo} 7505 */ 7506 , removeClass: function (c) { 7507 c = toString.call(c).split(whitespaceRegex) 7508 return this.each(function (el) { 7509 each(c, function (c) { 7510 if (c && hasClass(el, setter(el, c))) 7511 removeClass(el, setter(el, c)) 7512 }) 7513 }) 7514 } 7515 7516 7517 /** 7518 * @param {string} c 7519 * @return {boolean} 7520 */ 7521 , hasClass: function (c) { 7522 c = toString.call(c).split(whitespaceRegex) 7523 return some(this, function (el) { 7524 return some(c, function (c) { 7525 return c && hasClass(el, c) 7526 }) 7527 }) 7528 } 7529 7530 7531 /** 7532 * @param {string} c classname to toggle 7533 * @param {boolean=} opt_condition whether to add or remove the class straight away 7534 * @return {Bonzo} 7535 */ 7536 , toggleClass: function (c, opt_condition) { 7537 c = toString.call(c).split(whitespaceRegex) 7538 return this.each(function (el) { 7539 each(c, function (c) { 7540 if (c) { 7541 typeof opt_condition !== 'undefined' ? 7542 opt_condition ? !hasClass(el, c) && addClass(el, c) : removeClass(el, c) : 7543 hasClass(el, c) ? removeClass(el, c) : addClass(el, c) 7544 } 7545 }) 7546 }) 7547 } 7548 7549 // display togglers 7550 7551 /** 7552 * @param {string=} opt_type useful to set back to anything other than an empty string 7553 * @return {Bonzo} 7554 */ 7555 , show: function (opt_type) { 7556 opt_type = typeof opt_type == 'string' ? opt_type : '' 7557 return this.each(function (el) { 7558 el.style.display = opt_type 7559 }) 7560 } 7561 7562 7563 /** 7564 * @return {Bonzo} 7565 */ 7566 , hide: function () { 7567 return this.each(function (el) { 7568 el.style.display = 'none' 7569 }) 7570 } 7571 7572 7573 /** 7574 * @param {Function=} opt_callback 7575 * @param {string=} opt_type 7576 * @return {Bonzo} 7577 */ 7578 , toggle: function (opt_callback, opt_type) { 7579 opt_type = typeof opt_type == 'string' ? opt_type : ''; 7580 typeof opt_callback != 'function' && (opt_callback = null) 7581 return this.each(function (el) { 7582 el.style.display = (el.offsetWidth || el.offsetHeight) ? 'none' : opt_type; 7583 opt_callback && opt_callback.call(el) 7584 }) 7585 } 7586 7587 7588 // DOM Walkers & getters 7589 7590 /** 7591 * @return {Element|Node} 7592 */ 7593 , first: function () { 7594 return bonzo(this.length ? this[0] : []) 7595 } 7596 7597 7598 /** 7599 * @return {Element|Node} 7600 */ 7601 , last: function () { 7602 return bonzo(this.length ? this[this.length - 1] : []) 7603 } 7604 7605 7606 /** 7607 * @return {Element|Node} 7608 */ 7609 , next: function () { 7610 return this.related('nextSibling') 7611 } 7612 7613 7614 /** 7615 * @return {Element|Node} 7616 */ 7617 , previous: function () { 7618 return this.related('previousSibling') 7619 } 7620 7621 7622 /** 7623 * @return {Element|Node} 7624 */ 7625 , parent: function() { 7626 return this.related(parentNode) 7627 } 7628 7629 7630 /** 7631 * @private 7632 * @param {string} method the directional DOM method 7633 * @return {Element|Node} 7634 */ 7635 , related: function (method) { 7636 return bonzo(this.map( 7637 function (el) { 7638 el = el[method] 7639 while (el && el.nodeType !== 1) { 7640 el = el[method] 7641 } 7642 return el || 0 7643 }, 7644 function (el) { 7645 return el 7646 } 7647 )) 7648 } 7649 7650 7651 /** 7652 * @return {Bonzo} 7653 */ 7654 , focus: function () { 7655 this.length && this[0].focus() 7656 return this 7657 } 7658 7659 7660 /** 7661 * @return {Bonzo} 7662 */ 7663 , blur: function () { 7664 this.length && this[0].blur() 7665 return this 7666 } 7667 7668 // style getter setter & related methods 7669 7670 /** 7671 * @param {Object|string} o 7672 * @param {string=} opt_v 7673 * @return {Bonzo|string} 7674 */ 7675 , css: function (o, opt_v) { 7676 var p, iter = o 7677 // is this a request for just getting a style? 7678 if (opt_v === undefined && typeof o == 'string') { 7679 // repurpose 'v' 7680 opt_v = this[0] 7681 if (!opt_v) return null 7682 if (opt_v === doc || opt_v === win) { 7683 p = (opt_v === doc) ? bonzo.doc() : bonzo.viewport() 7684 return o == 'width' ? p.width : o == 'height' ? p.height : '' 7685 } 7686 return (o = styleProperty(o)) ? getStyle(opt_v, o) : null 7687 } 7688 7689 if (typeof o == 'string') { 7690 iter = {} 7691 iter[o] = opt_v 7692 } 7693 7694 function fn(el, p, v) { 7695 for (var k in iter) { 7696 if (iter.hasOwnProperty(k)) { 7697 v = iter[k]; 7698 // change "5" to "5px" - unless you're line-height, which is allowed 7699 (p = styleProperty(k)) && digit.test(v) && !(p in unitless) && (v += px) 7700 try { el.style[p] = setter(el, v) } catch(e) {} 7701 } 7702 } 7703 } 7704 return this.each(fn) 7705 } 7706 7707 7708 /** 7709 * @param {number=} opt_x 7710 * @param {number=} opt_y 7711 * @return {Bonzo|number} 7712 */ 7713 , offset: function (opt_x, opt_y) { 7714 if (opt_x && typeof opt_x == 'object' && (typeof opt_x.top == 'number' || typeof opt_x.left == 'number')) { 7715 return this.each(function (el) { 7716 xy(el, opt_x.left, opt_x.top) 7717 }) 7718 } else if (typeof opt_x == 'number' || typeof opt_y == 'number') { 7719 return this.each(function (el) { 7720 xy(el, opt_x, opt_y) 7721 }) 7722 } 7723 if (!this[0]) return { 7724 top: 0 7725 , left: 0 7726 , height: 0 7727 , width: 0 7728 } 7729 var el = this[0] 7730 , de = el.ownerDocument.documentElement 7731 , bcr = el.getBoundingClientRect() 7732 , scroll = getWindowScroll() 7733 , width = el.offsetWidth 7734 , height = el.offsetHeight 7735 , top = bcr.top + scroll.y - Math.max(0, de && de.clientTop, doc.body.clientTop) 7736 , left = bcr.left + scroll.x - Math.max(0, de && de.clientLeft, doc.body.clientLeft) 7737 7738 return { 7739 top: top 7740 , left: left 7741 , height: height 7742 , width: width 7743 } 7744 } 7745 7746 7747 /** 7748 * @return {number} 7749 */ 7750 , dim: function () { 7751 if (!this.length) return { height: 0, width: 0 } 7752 var el = this[0] 7753 , de = el.nodeType == 9 && el.documentElement // document 7754 , orig = !de && !!el.style && !el.offsetWidth && !el.offsetHeight ? 7755 // el isn't visible, can't be measured properly, so fix that 7756 function (t) { 7757 var s = { 7758 position: el.style.position || '' 7759 , visibility: el.style.visibility || '' 7760 , display: el.style.display || '' 7761 } 7762 t.first().css({ 7763 position: 'absolute' 7764 , visibility: 'hidden' 7765 , display: 'block' 7766 }) 7767 return s 7768 }(this) : null 7769 , width = de 7770 ? Math.max(el.body.scrollWidth, el.body.offsetWidth, de.scrollWidth, de.offsetWidth, de.clientWidth) 7771 : el.offsetWidth 7772 , height = de 7773 ? Math.max(el.body.scrollHeight, el.body.offsetHeight, de.scrollHeight, de.offsetHeight, de.clientHeight) 7774 : el.offsetHeight 7775 7776 orig && this.first().css(orig) 7777 return { 7778 height: height 7779 , width: width 7780 } 7781 } 7782 7783 // attributes are hard. go shopping 7784 7785 /** 7786 * @param {string} k an attribute to get or set 7787 * @param {string=} opt_v the value to set 7788 * @return {Bonzo|string} 7789 */ 7790 , attr: function (k, opt_v) { 7791 var el = this[0] 7792 , n 7793 7794 if (typeof k != 'string' && !(k instanceof String)) { 7795 for (n in k) { 7796 k.hasOwnProperty(n) && this.attr(n, k[n]) 7797 } 7798 return this 7799 } 7800 7801 return typeof opt_v == 'undefined' ? 7802 !el ? null : specialAttributes.test(k) ? 7803 stateAttributes.test(k) && typeof el[k] == 'string' ? 7804 true : el[k] : el[getAttribute](k) : 7805 this.each(function (el) { 7806 specialAttributes.test(k) ? (el[k] = setter(el, opt_v)) : el[setAttribute](k, setter(el, opt_v)) 7807 }) 7808 } 7809 7810 7811 /** 7812 * @param {string} k 7813 * @return {Bonzo} 7814 */ 7815 , removeAttr: function (k) { 7816 return this.each(function (el) { 7817 stateAttributes.test(k) ? (el[k] = false) : el.removeAttribute(k) 7818 }) 7819 } 7820 7821 7822 /** 7823 * @param {string=} opt_s 7824 * @return {Bonzo|string} 7825 */ 7826 , val: function (s) { 7827 return (typeof s == 'string' || typeof s == 'number') ? 7828 this.attr('value', s) : 7829 this.length ? this[0].value : null 7830 } 7831 7832 // use with care and knowledge. this data() method uses data attributes on the DOM nodes 7833 // to do this differently costs a lot more code. c'est la vie 7834 /** 7835 * @param {string|Object=} opt_k the key for which to get or set data 7836 * @param {Object=} opt_v 7837 * @return {Bonzo|Object} 7838 */ 7839 , data: function (opt_k, opt_v) { 7840 var el = this[0], o, m 7841 if (typeof opt_v === 'undefined') { 7842 if (!el) return null 7843 o = data(el) 7844 if (typeof opt_k === 'undefined') { 7845 each(el.attributes, function (a) { 7846 (m = ('' + a.name).match(dattr)) && (o[camelize(m[1])] = dataValue(a.value)) 7847 }) 7848 return o 7849 } else { 7850 if (typeof o[opt_k] === 'undefined') 7851 o[opt_k] = dataValue(this.attr('data-' + decamelize(opt_k))) 7852 return o[opt_k] 7853 } 7854 } else { 7855 return this.each(function (el) { data(el)[opt_k] = opt_v }) 7856 } 7857 } 7858 7859 // DOM detachment & related 7860 7861 /** 7862 * @return {Bonzo} 7863 */ 7864 , remove: function () { 7865 this.deepEach(clearData) 7866 return this.detach() 7867 } 7868 7869 7870 /** 7871 * @return {Bonzo} 7872 */ 7873 , empty: function () { 7874 return this.each(function (el) { 7875 deepEach(el.childNodes, clearData) 7876 7877 while (el.firstChild) { 7878 el.removeChild(el.firstChild) 7879 } 7880 }) 7881 } 7882 7883 7884 /** 7885 * @return {Bonzo} 7886 */ 7887 , detach: function () { 7888 return this.each(function (el) { 7889 el[parentNode] && el[parentNode].removeChild(el) 7890 }) 7891 } 7892 7893 // who uses a mouse anyway? oh right. 7894 7895 /** 7896 * @param {number} y 7897 */ 7898 , scrollTop: function (y) { 7899 return scroll.call(this, null, y, 'y') 7900 } 7901 7902 7903 /** 7904 * @param {number} x 7905 */ 7906 , scrollLeft: function (x) { 7907 return scroll.call(this, x, null, 'x') 7908 } 7909 7910 } 7911 7912 7913 function cloneNode(host, el) { 7914 var c = el.cloneNode(true) 7915 , cloneElems 7916 , elElems 7917 , i 7918 7919 // check for existence of an event cloner 7920 // preferably https://github.com/fat/bean 7921 // otherwise Bonzo won't do this for you 7922 if (host.$ && typeof host.cloneEvents == 'function') { 7923 host.$(c).cloneEvents(el) 7924 7925 // clone events from every child node 7926 cloneElems = host.$(c).find('*') 7927 elElems = host.$(el).find('*') 7928 7929 for (i = 0; i < elElems.length; i++) 7930 host.$(cloneElems[i]).cloneEvents(elElems[i]) 7931 } 7932 return c 7933 } 7934 7935 function isBody(element) { 7936 return element === win || (/^(?:body|html)$/i).test(element.tagName) 7937 } 7938 7939 function getWindowScroll() { 7940 return { x: win.pageXOffset || html.scrollLeft, y: win.pageYOffset || html.scrollTop } 7941 } 7942 7943 function createScriptFromHtml(html) { 7944 var scriptEl = document.createElement('script') 7945 , matches = html.match(simpleScriptTagRe) 7946 scriptEl.src = matches[1] 7947 return scriptEl 7948 } 7949 7950 /** 7951 * @param {Array.<Element>|Element|Node|string} els 7952 * @return {Bonzo} 7953 */ 7954 function bonzo(els) { 7955 return new Bonzo(els) 7956 } 7957 7958 bonzo.setQueryEngine = function (q) { 7959 query = q; 7960 delete bonzo.setQueryEngine 7961 } 7962 7963 bonzo.aug = function (o, target) { 7964 // for those standalone bonzo users. this love is for you. 7965 for (var k in o) { 7966 o.hasOwnProperty(k) && ((target || Bonzo.prototype)[k] = o[k]) 7967 } 7968 } 7969 7970 bonzo.create = function (node) { 7971 // hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh 7972 return typeof node == 'string' && node !== '' ? 7973 function () { 7974 if (simpleScriptTagRe.test(node)) return [createScriptFromHtml(node)] 7975 var tag = node.match(/^\s*<([^\s>]+)/) 7976 , el = doc.createElement('div') 7977 , els = [] 7978 , p = tag ? tagMap[tag[1].toLowerCase()] : null 7979 , dep = p ? p[2] + 1 : 1 7980 , ns = p && p[3] 7981 , pn = parentNode 7982 7983 el.innerHTML = p ? (p[0] + node + p[1]) : node 7984 while (dep--) el
7984= el.firstChild 7985 // for IE NoScope, we may insert cruft at the begining just to get it to work 7986 if (ns && el && el.nodeType !== 1) el = el.nextSibling 7987 do { 7988 if (!tag || el.nodeType == 1) { 7989 els.push(el) 7990 } 7991 } while (el = el.nextSibling) 7992 // IE < 9 gives us a parentNode which messes up insert() check for cloning 7993 // `dep` > 1 can also cause problems with the insert() check (must do this last) 7994 each(els, function(el) { el[pn] && el[pn].removeChild(el) }) 7995 return els 7996 }() : isNode(node) ? [node.cloneNode(true)] : [] 7997 } 7998 7999 bonzo.doc = function () { 8000 var vp = bonzo.viewport() 8001 return { 8002 width: Math.max(doc.body.scrollWidth, html.scrollWidth, vp.width) 8003 , height: Math.max(doc.body.scrollHeight, html.scrollHeight, vp.height) 8004 } 8005 } 8006 8007 bonzo.firstChild = function (el) { 8008 for (var c = el.childNodes, i = 0, j = (c && c.length) || 0, e; i < j; i++) { 8009 if (c[i].nodeType === 1) e = c[j = i] 8010 } 8011 return e 8012 } 8013 8014 bonzo.viewport = function () { 8015 return { 8016 width: win.innerWidth 8017 , height: win.innerHeight 8018 } 8019 } 8020 8021 bonzo.isAncestor = 'compareDocumentPosition' in html ? 8022 function (container, element) { 8023 return (container.compareDocumentPosition(element) & 16) == 16 8024 } : 8025 function (container, element) { 8026 return container !== element && container.contains(element); 8027 } 8028 8029 return bonzo 8030}); // the only line we care about using a semi-colon. placed here for concatenation tools 8031 8032},{}],42:[function(require,module,exports){ 8033module.exports = on; 8034module.exports.on = on; 8035module.exports.off = off; 8036 8037function on (element, event, callback, capture) { 8038 !element.addEventListener && (event = 'on' + event); 8039 (element.addEventListener || element.attachEvent).call(element, event, callback, capture); 8040 return callback; 8041} 8042 8043function off (element, event, callback, capture) { 8044 !element.removeEventListener && (event = 'on' + event); 8045 (element.removeEventListener || element.detachEvent).call(element, event, callback, capture); 8046 return callback; 8047} 8048 8049},{}],43
vendor: 13,143 bytes, lines 8049-8479
8049:[function(require,module,exports){ 8050// Copyright Joyent, Inc. and other Node contributors. 8051// 8052// Permission is hereby granted, free of charge, to any person obtaining a 8053// copy of this software and associated documentation files (the 8054// "Software"), to deal in the Software without restriction, including 8055// without limitation the rights to use, copy, modify, merge, publish, 8056// distribute, sublicense, and/or sell copies of the Software, and to permit 8057// persons to whom the Software is furnished to do so, subject to the 8058// following conditions: 8059// 8060// The above copyright notice and this permission notice shall be included 8061// in all copies or substantial portions of the Software. 8062// 8063// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 8064// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 8065// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 8066// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 8067// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 8068// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 8069// USE OR OTHER DEALINGS IN THE SOFTWARE. 8070 8071var objectCreate = Object.create || objectCreatePolyfill 8072var objectKeys = Object.keys || objectKeysPolyfill 8073var bind = Function.prototype.bind || functionBindPolyfill 8074 8075function EventEmitter() { 8076 if (!this._events || !Object.prototype.hasOwnProperty.call(this, '_events')) { 8077 this._events = objectCreate(null); 8078 this._eventsCount = 0; 8079 } 8080 8081 this._maxListeners = this._maxListeners || undefined; 8082} 8083module.exports = EventEmitter; 8084 8085// Backwards-compat with node 0.10.x 8086EventEmitter.EventEmitter = EventEmitter; 8087 8088EventEmitter.prototype._events = undefined; 8089EventEmitter.prototype._maxListeners = undefined; 8090 8091// By default EventEmitters will print a warning if more than 10 listeners are 8092// added to it. This is a useful default which helps finding memory leaks. 8093var defaultMaxListeners = 10; 8094 8095var hasDefineProperty; 8096try { 8097 var o = {}; 8098 if (Object.defineProperty) Object.defineProperty(o, 'x', { value: 0 }); 8099 hasDefineProperty = o.x === 0; 8100} catch (err) { hasDefineProperty = false } 8101if (hasDefineProperty) { 8102 Object.defineProperty(EventEmitter, 'defaultMaxListeners', { 8103 enumerable: true, 8104 get: function() { 8105 return defaultMaxListeners; 8106 }, 8107 set: function(arg) { 8108 // check whether the input is a positive number (whose value is zero or 8109 // greater and not a NaN). 8110 if (typeof arg !== 'number' || arg < 0 || arg !== arg) 8111 throw new TypeError('"defaultMaxListeners" must be a positive number'); 8112 defaultMaxListeners = arg; 8113 } 8114 }); 8115} else { 8116 EventEmitter.defaultMaxListeners = defaultMaxListeners; 8117} 8118 8119// Obviously not all Emitters should be limited to 10. This function allows 8120// that to be increased. Set to zero for unlimited. 8121EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { 8122 if (typeof n !== 'number' || n < 0 || isNaN(n)) 8123 throw new TypeError('"n" argument must be a positive number'); 8124 this._maxListeners = n; 8125 return this; 8126}; 8127 8128function $getMaxListeners(that) { 8129 if (that._maxListeners === undefined) 8130 return EventEmitter.defaultMaxListeners; 8131 return that._maxListeners; 8132} 8133 8134EventEmitter.prototype.getMaxListeners = function getMaxListeners() { 8135 return $getMaxListeners(this); 8136}; 8137 8138// These standalone emit* functions are used to optimize calling of event 8139// handlers for fast cases because emit() itself often has a variable number of 8140// arguments and can be deoptimized because of that. These functions always have 8141// the same number of arguments and thus do not get deoptimized, so the code 8142// inside them can execute faster. 8143function emitNone(handler, isFn, self) { 8144 if (isFn) 8145 handler.call(self); 8146 else { 8147 var len = handler.length; 8148 var listeners = arrayClone(handler, len); 8149 for (var i = 0; i < len; ++i) 8150 listeners[i].call(self); 8151 } 8152} 8153function emitOne(handler, isFn, self, arg1) { 8154 if (isFn) 8155 handler.call(self, arg1); 8156 else { 8157 var len = handler.length; 8158 var listeners = arrayClone(handler, len); 8159 for (var i = 0; i < len; ++i) 8160 listeners[i].call(self, arg1); 8161 } 8162} 8163function emitTwo(handler, isFn, self, arg1, arg2) { 8164 if (isFn) 8165 handler.call(self, arg1, arg2); 8166 else { 8167 var len = handler.length; 8168 var listeners = arrayClone(handler, len); 8169 for (var i = 0; i < len; ++i) 8170 listeners[i].call(self, arg1, arg2); 8171 } 8172} 8173function emitThree(handler, isFn, self, arg1, arg2, arg3) { 8174 if (isFn) 8175 handler.call(self, arg1, arg2, arg3); 8176 else { 8177 var len = handler.length; 8178 var listeners = arrayClone(handler, len); 8179 for (var i = 0; i < len; ++i) 8180 listeners[i].call(self, arg1, arg2, arg3); 8181 } 8182} 8183 8184function emitMany(handler, isFn, self, args) { 8185 if (isFn) 8186 handler.apply(self, args); 8187 else { 8188 var len = handler.length; 8189 var listeners = arrayClone(handler, len); 8190 for (var i = 0; i < len; ++i) 8191 listeners[i].apply(self, args); 8192 } 8193} 8194 8195EventEmitter.prototype.emit = function emit(type) { 8196 var er, handler, len, args, i, events; 8197 var doError = (type === 'error'); 8198 8199 events = this._events; 8200 if (events) 8201 doError = (doError && events.error == null); 8202 else if (!doError) 8203 return false; 8204 8205 // If there is no 'error' event listener then throw. 8206 if (doError) { 8207 if (arguments.length > 1) 8208 er = arguments[1]; 8209 if (er instanceof Error) { 8210 throw er; // Unhandled 'error' event 8211 } else { 8212 // At least give some kind of context to the user 8213 var err = new Error('Unhandled "error" event. (' + er + ')'); 8214 err.context = er; 8215 throw err; 8216 } 8217 return false; 8218 } 8219 8220 handler = events[type]; 8221 8222 if (!handler) 8223 return false; 8224 8225 var isFn = typeof handler === 'function'; 8226 len = arguments.length; 8227 switch (len) { 8228 // fast cases 8229 case 1: 8230 emitNone(handler, isFn, this); 8231 break; 8232 case 2: 8233 emitOne(handler, isFn, this, arguments[1]); 8234 break; 8235 case 3: 8236 emitTwo(handler, isFn, this, arguments[1], arguments[2]); 8237 break; 8238 case 4: 8239 emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]); 8240 break; 8241 // slower 8242 default: 8243 args = new Array(len - 1); 8244 for (i = 1; i < len; i++) 8245 args[i - 1] = arguments[i]; 8246 emitMany(handler, isFn, this, args); 8247 } 8248 8249 return true; 8250}; 8251 8252function _addListener(target, type, listener, prepend) { 8253 var m; 8254 var events; 8255 var existing; 8256 8257 if (typeof listener !== 'function') 8258 throw new TypeError('"listener" argument must be a function'); 8259 8260 events = target._events; 8261 if (!events) { 8262 events = target._events = objectCreate(null); 8263 target._eventsCount = 0; 8264 } else { 8265 // To avoid recursion in the case that type === "newListener"! Before 8266 // adding it to the listeners, first emit "newListener". 8267 if (events.newListener) { 8268 target.emit('newListener', type, 8269 listener.listener ? listener.listener : listener); 8270 8271 // Re-assign `events` because a newListener handler could have caused the 8272 // this._events to be assigned to a new object 8273 events = target._events; 8274 } 8275 existing = events[type]; 8276 } 8277 8278 if (!existing) { 8279 // Optimize the case of one listener. Don't need the extra array object. 8280 existing = events[type] = listener; 8281 ++target._eventsCount; 8282 } else { 8283 if (typeof existing === 'function') { 8284 // Adding the second element, need to change to array. 8285 existing = events[type] = 8286 prepend ? [listener, existing] : [existing, listener]; 8287 } else { 8288 // If we've already got an array, just append. 8289 if (prepend) { 8290 existing.unshift(listener); 8291 } else { 8292 existing.push(listener); 8293 } 8294 } 8295 8296 // Check for listener leak 8297 if (!existing.warned) { 8298 m = $getMaxListeners(target); 8299 if (m && m > 0 && existing.length > m) { 8300 existing.warned = true; 8301 var w = new Error('Possible EventEmitter memory leak detected. ' + 8302 existing.length + ' "' + String(type) + '" listeners ' + 8303 'added. Use emitter.setMaxListeners() to ' + 8304 'increase limit.'); 8305 w.name = 'MaxListenersExceededWarning'; 8306 w.emitter = target; 8307 w.type = type; 8308 w.count = existing.length; 8309 if (typeof console === 'object' && console.warn) { 8310 console.warn('%s: %s', w.name, w.message); 8311 } 8312 } 8313 } 8314 } 8315 8316 return target; 8317} 8318 8319EventEmitter.prototype.addListener = function addListener(type, listener) { 8320 return _addListener(this, type, listener, false); 8321}; 8322 8323EventEmitter.prototype.on = EventEmitter.prototype.addListener; 8324 8325EventEmitter.prototype.prependListener = 8326 function prependListener(type, listener) { 8327 return _addListener(this, type, listener, true); 8328 }; 8329 8330function onceWrapper() { 8331 if (!this.fired) { 8332 this.target.removeListener(this.type, this.wrapFn); 8333 this.fired = true; 8334 switch (arguments.length) { 8335 case 0: 8336 return this.listener.call(this.target); 8337 case 1: 8338 return this.listener.call(this.target, arguments[0]); 8339 case 2: 8340 return this.listener.call(this.target, arguments[0], arguments[1]); 8341 case 3: 8342 return this.listener.call(this.target, arguments[0], arguments[1], 8343 arguments[2]); 8344 default: 8345 var args = new Array(arguments.length); 8346 for (var i = 0; i < args.length; ++i) 8347 args[i] = arguments[i]; 8348 this.listener.apply(this.target, args); 8349 } 8350 } 8351} 8352 8353function _onceWrap(target, type, listener) { 8354 var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener }; 8355 var wrapped = bind.call(onceWrapper, state); 8356 wrapped.listener = listener; 8357 state.wrapFn = wrapped; 8358 return wrapped; 8359} 8360 8361EventEmitter.prototype.once = function once(type, listener) { 8362 if (typeof listener !== 'function') 8363 throw new TypeError('"listener" argument must be a function'); 8364 this.on(type, _onceWrap(this, type, listener)); 8365 return this; 8366}; 8367 8368EventEmitter.prototype.prependOnceListener = 8369 function prependOnceListener(type, listener) { 8370 if (typeof listener !== 'function') 8371 throw new TypeError('"listener" argument must be a function'); 8372 this.prependListener(type, _onceWrap(this, type, listener)); 8373 return this; 8374 }; 8375 8376// Emits a 'removeListener' event if and only if the listener was removed. 8377EventEmitter.prototype.removeListener = 8378 function removeListener(type, listener) { 8379 var list, events, position, i, originalListener; 8380 8381 if (typeof listener !== 'function') 8382 throw new TypeError('"listener" argument must be a function'); 8383 8384 events = this._events; 8385 if (!events) 8386 return this; 8387 8388 list = events[type]; 8389 if (!list) 8390 return this; 8391 8392 if (list === listener || list.listener === listener) { 8393 if (--this._eventsCount === 0) 8394 this._events = objectCreate(null); 8395 else { 8396 delete events[type]; 8397 if (events.removeListener) 8398 this.emit('removeListener', type, list.listener || listener); 8399 } 8400 } else if (typeof list !== 'function') { 8401 position = -1; 8402 8403 for (i = list.length - 1; i >= 0; i--) { 8404 if (list[i] === listener || list[i].listener === listener) { 8405 originalListener = list[i].listener; 8406 position = i; 8407 break; 8408 } 8409 } 8410 8411 if (position < 0) 8412 return this; 8413 8414 if (position === 0) 8415 list.shift(); 8416 else 8417 spliceOne(list, position); 8418 8419 if (list.length === 1) 8420 events[type] = list[0]; 8421 8422 if (events.removeListener) 8423 this.emit('removeListener', type, originalListener || listener); 8424 } 8425 8426 return this; 8427 }; 8428 8429EventEmitter.prototype.removeAllListeners = 8430 function removeAllListeners(type) { 8431 var listeners, events, i; 8432 8433 events = this._events; 8434 if (!events) 8435 return this; 8436 8437 // not listening for removeListener, no need to emit 8438 if (!events.removeListener) { 8439 if (arguments.length === 0) { 8440 this._events = objectCreate(null); 8441 this._eventsCount = 0; 8442 } else if (events[type]) { 8443 if (--this._eventsCount === 0) 8444 this._events = objectCreate(null); 8445 else 8446 delete events[type]; 8447 } 8448 return this; 8449 } 8450 8451 // emit removeListener for all listeners on all events 8452 if (arguments.length === 0) { 8453 var keys = objectKeys(events); 8454 var key; 8455 for (i = 0; i < keys.length; ++i) { 8456 key = keys[i]; 8457 if (key === 'removeListener') continue; 8458 this.removeAllListeners(key); 8459 } 8460 this.removeAllListeners('removeListener'); 8461 this._events = objectCreate(null); 8462 this._eventsCount = 0; 8463 return this; 8464 } 8465 8466 listeners = events[type]; 8467 8468 if (typeof listeners === 'function') { 8469 this.removeListener(type, listeners); 8470 } else if (listeners) { 8471 // LIFO order 8472 for (i = listeners.length - 1; i >= 0; i--) { 8473 this.removeListener(type, listeners[i]); 8474 } 8475 } 8476 8477 return this; 8478 }; 8479
8480EventEmitter.prototype.listeners = function listeners(type) { 8481 var evlistener; 8482 var ret; 8483 var events = this._events; 8484 8485 if (!events) 8486 ret = []; 8487 else { 8488 evlistener = events[type]; 8489 if (!evlistener) 8490 ret = []; 8491 else if (typeof evlistener === 'function') 8492 ret = [evlistener.listener || evlistener]; 8493 else 8494 ret = unwrapListeners(evlistener); 8495 } 8496 8497 return ret; 8498}; 8499 8500EventEmitter.listenerCount = function(emitter, type) { 8501 if (typeof emitter.listenerCount === 'function') { 8502 return emitter.listenerCount(type); 8503 } else { 8504 return listenerCount.call(emitter, type); 8505 } 8506}; 8507 8508EventEmitter.prototype.listenerCount = listenerCount; 8509function listenerCount(type) { 8510 var events = this._events; 8511 8512 if (events) { 8513 var evlistener = events[type]; 8514 8515 if (typeof evlistener === 'function') { 8516 return 1; 8517 } else if (evlistener) { 8518 return evlistener.length; 8519 } 8520 } 8521 8522 return 0; 8523} 8524 8525EventEmitter.prototype.eventNames = function eventNames() { 8526 return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : []; 8527}; 8528 8529// About 1.5x faster than the two-arg version of Array#splice(). 8530function spliceOne(list, index) { 8531 for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1) 8532 list[i] = list[k]; 8533 list.pop(); 8534} 8535 8536function arrayClone(arr, n) { 8537 var copy = new Array(n); 8538 for (var i = 0; i < n; ++i) 8539 copy[i] = arr[i]; 8540 return copy; 8541} 8542 8543function unwrapListeners(arr) { 8544 var ret = new Array(arr.length); 8545 for (var i = 0; i < ret.length; ++i) { 8546 ret[i] = arr[i].listener || arr[i]; 8547 } 8548 return ret; 8549} 8550 8551function objectCreatePolyfill(proto) { 8552 var F = function() {}; 8553 F.prototype = proto; 8554 return new F; 8555} 8556function objectKeysPolyfill(obj) { 8557 var keys = []; 8558 for (var k in obj) if (Object.prototype.hasOwnProperty.call(obj, k)) { 8559 keys.push(k); 8560 } 8561 return k; 8562} 8563function functionBindPolyfill(context) { 8564 var fn = this; 8565 return function () { 8566 return fn.apply(context, arguments); 8567 }; 8568} 8569 8570},{}],44:[function(require,module,exports){ 8571if (typeof Object.create === 'function') { 8572 // implementation from standard node.js 'util' module 8573 module.exports = function inherits(ctor, superCtor) { 8574 ctor.super_ = superCtor 8575 ctor.prototype = Object.create(superCtor.prototype, { 8576 constructor: { 8577 value: ctor, 8578 enumerable: false, 8579 writable: true, 8580 configurable: true 8581 } 8582 }); 8583 }; 8584} else { 8585 // old school shim for old browsers 8586 module.exports = function inherits(ctor, superCtor) { 8587 ctor.super_ = superCtor 8588 var TempCtor = function () {} 8589 TempCtor.prototype = superCtor.prototype 8590 ctor.prototype = new TempCtor() 8591 ctor.prototype.constructor = ctor 8592 } 8593} 8594 8595},{}],45:[function(require,module,exports){ 8596/*! 8597 * mustache.js - Logic-less {{mustache}} templates with JavaScript 8598 * http://github.com/janl/mustache.js 8599 */ 8600 8601/*global define: false Mustache: true*/ 8602 8603(function defineMustache (global, factory) { 8604 if (typeof exports === 'object' && exports && typeof exports.nodeName !== 'string') { 8605 factory(exports); // CommonJS 8606 } else if (typeof define === 'function' && define.amd) { 8607 define(['exports'], factory); // AMD 8608 } else { 8609 global.Mustache = {}; 8610 factory(global.Mustache); // script, wsh, asp 8611 } 8612}(this, function mustacheFactory (mustache) { 8613 8614 var objectToString = Object.prototype.toString; 8615 var isArray = Array.isArray || function isArrayPolyfill (object) { 8616 return objectToString.call(object) === '[object Array]'; 8617 }; 8618 8619 function isFunction (object) { 8620 return typeof object === 'function'; 8621 } 8622 8623 /** 8624 * More correct typeof string handling array 8625 * which normally returns typeof 'object' 8626 */ 8627 function typeStr (obj) { 8628 return isArray(obj) ? 'array' : typeof obj; 8629 } 8630 8631 function escapeRegExp (string) { 8632 return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'); 8633 } 8634 8635 /** 8636 * Null safe way of checking whether or not an object, 8637 * including its prototype, has a given property 8638 */ 8639 function hasProperty (obj, propName) { 8640 return obj != null && typeof obj === 'object' && (propName in obj); 8641 } 8642 8643 // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577 8644 // See https://github.com/janl/mustache.js/issues/189 8645 var regExpTest = RegExp.prototype.test; 8646 function testRegExp (re, string) { 8647 return regExpTest.call(re, string); 8648 } 8649 8650 var nonSpaceRe = /\S/; 8651 function isWhitespace (string) { 8652 return !testRegExp(nonSpaceRe, string); 8653 } 8654 8655 var entityMap = { 8656 '&': '&', 8657 '<': '<', 8658 '>': '>', 8659 '"': '"', 8660 "'": ''', 8661 '/': '/', 8662 '`': '`', 8663 '=': '=' 8664 }; 8665 8666 function escapeHtml (string) { 8667 return String(string).replace(/[&<>
vendor: 17,446 bytes, lines 8667-9227
8667"'`=\/]/g, function fromEntityMap (s) { 8668 return entityMap[s]; 8669 }); 8670 } 8671 8672 var whiteRe = /\s*/; 8673 var spaceRe = /\s+/; 8674 var equalsRe = /\s*=/; 8675 var curlyRe = /\s*\}/; 8676 var tagRe = /#|\^|\/|>|\{|&|=|!/; 8677 8678 /** 8679 * Breaks up the given `template` string into a tree of tokens. If the `tags` 8680 * argument is given here it must be an array with two string values: the 8681 * opening and closing tags used in the template (e.g. [ "<%", "%>" ]). Of 8682 * course, the default is to use mustaches (i.e. mustache.tags). 8683 * 8684 * A token is an array with at least 4 elements. The first element is the 8685 * mustache symbol that was used inside the tag, e.g. "#" or "&". If the tag 8686 * did not contain a symbol (i.e. {{myValue}}) this element is "name". For 8687 * all text that appears outside a symbol this element is "text". 8688 * 8689 * The second element of a token is its "value". For mustache tags this is 8690 * whatever else was inside the tag besides the opening symbol. For text tokens 8691 * this is the text itself. 8692 * 8693 * The third and fourth elements of the token are the start and end indices, 8694 * respectively, of the token in the original template. 8695 * 8696 * Tokens that are the root node of a subtree contain two more elements: 1) an 8697 * array of tokens in the subtree and 2) the index in the original template at 8698 * which the closing tag for that section begins. 8699 */ 8700 function parseTemplate (template, tags) { 8701 if (!template) 8702 return []; 8703 8704 var sections = []; // Stack to hold section tokens 8705 var tokens = []; // Buffer to hold the tokens 8706 var spaces = []; // Indices of whitespace tokens on the current line 8707 var hasTag = false; // Is there a {{tag}} on the current line? 8708 var nonSpace = false; // Is there a non-space char on the current line? 8709 8710 // Strips all whitespace tokens array for the current line 8711 // if there was a {{#tag}} on it and otherwise only space. 8712 function stripSpace () { 8713 if (hasTag && !nonSpace) { 8714 while (spaces.length) 8715 delete tokens[spaces.pop()]; 8716 } else { 8717 spaces = []; 8718 } 8719 8720 hasTag = false; 8721 nonSpace = false; 8722 } 8723 8724 var openingTagRe, closingTagRe, closingCurlyRe; 8725 function compileTags (tagsToCompile) { 8726 if (typeof tagsToCompile === 'string') 8727 tagsToCompile = tagsToCompile.split(spaceRe, 2); 8728 8729 if (!isArray(tagsToCompile) || tagsToCompile.length !== 2) 8730 throw new Error('Invalid tags: ' + tagsToCompile); 8731 8732 openingTagRe = new RegExp(escapeRegExp(tagsToCompile[0]) + '\\s*'); 8733 closingTagRe = new RegExp('\\s*' + escapeRegExp(tagsToCompile[1])); 8734 closingCurlyRe = new RegExp('\\s*' + escapeRegExp('}' + tagsToCompile[1])); 8735 } 8736 8737 compileTags(tags || mustache.tags); 8738 8739 var scanner = new Scanner(template); 8740 8741 var start, type, value, chr, token, openSection; 8742 while (!scanner.eos()) { 8743 start = scanner.pos; 8744 8745 // Match any text between tags. 8746 value = scanner.scanUntil(openingTagRe); 8747 8748 if (value) { 8749 for (var i = 0, valueLength = value.length; i < valueLength; ++i) { 8750 chr = value.charAt(i); 8751 8752 if (isWhitespace(chr)) { 8753 spaces.push(tokens.length); 8754 } else { 8755 nonSpace = true; 8756 } 8757 8758 tokens.push([ 'text', chr, start, start + 1 ]); 8759 start += 1; 8760 8761 // Check for whitespace on the current line. 8762 if (chr === '\n') 8763 stripSpace(); 8764 } 8765 } 8766 8767 // Match the opening tag. 8768 if (!scanner.scan(openingTagRe)) 8769 break; 8770 8771 hasTag = true; 8772 8773 // Get the tag type. 8774 type = scanner.scan(tagRe) || 'name'; 8775 scanner.scan(whiteRe); 8776 8777 // Get the tag value. 8778 if (type === '=') { 8779 value = scanner.scanUntil(equalsRe); 8780 scanner.scan(equalsRe); 8781 scanner.scanUntil(closingTagRe); 8782 } else if (type === '{') { 8783 value = scanner.scanUntil(closingCurlyRe); 8784 scanner.scan(curlyRe); 8785 scanner.scanUntil(closingTagRe); 8786 type = '&'; 8787 } else { 8788 value = scanner.scanUntil(closingTagRe); 8789 } 8790 8791 // Match the closing tag. 8792 if (!scanner.scan(closingTagRe)) 8793 throw new Error('Unclosed tag at ' + scanner.pos); 8794 8795 token = [ type, value, start, scanner.pos ]; 8796 tokens.push(token); 8797 8798 if (type === '#' || type === '^') { 8799 sections.push(token); 8800 } else if (type === '/') { 8801 // Check section nesting. 8802 openSection = sections.pop(); 8803 8804 if (!openSection) 8805 throw new Error('Unopened section "' + value + '" at ' + start); 8806 8807 if (openSection[1] !== value) 8808 throw new Error('Unclosed section "' + openSection[1] + '" at ' + start); 8809 } else if (type === 'name' || type === '{' || type === '&') { 8810 nonSpace = true; 8811 } else if (type === '=') { 8812 // Set the tags for the next time around. 8813 compileTags(value); 8814 } 8815 } 8816 8817 // Make sure there are no open sections when we're done. 8818 openSection = sections.pop(); 8819 8820 if (openSection) 8821 throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos); 8822 8823 return nestTokens(squashTokens(tokens)); 8824 } 8825 8826 /** 8827 * Combines the values of consecutive text tokens in the given `tokens` array 8828 * to a single token. 8829 */ 8830 function squashTokens (tokens) { 8831 var squashedTokens = []; 8832 8833 var token, lastToken; 8834 for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) { 8835 token = tokens[i]; 8836 8837 if (token) { 8838 if (token[0] === 'text' && lastToken && lastToken[0] === 'text') { 8839 lastToken[1] += token[1]; 8840 lastToken[3] = token[3]; 8841 } else { 8842 squashedTokens.push(token); 8843 lastToken = token; 8844 } 8845 } 8846 } 8847 8848 return squashedTokens; 8849 } 8850 8851 /** 8852 * Forms the given array of `tokens` into a nested tree structure where 8853 * tokens that represent a section have two additional items: 1) an array of 8854 * all tokens that appear in that section and 2) the index in the original 8855 * template that represents the end of that section. 8856 */ 8857 function nestTokens (tokens) { 8858 var nestedTokens = []; 8859 var collector = nestedTokens; 8860 var sections = []; 8861 8862 var token, section; 8863 for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) { 8864 token = tokens[i]; 8865 8866 switch (token[0]) { 8867 case '#': 8868 case '^': 8869 collector.push(token); 8870 sections.push(token); 8871 collector = token[4] = []; 8872 break; 8873 case '/': 8874 section = sections.pop(); 8875 section[5] = token[2]; 8876 collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens; 8877 break; 8878 default: 8879 collector.push(token); 8880 } 8881 } 8882 8883 return nestedTokens; 8884 } 8885 8886 /** 8887 * A simple string scanner that is used by the template parser to find 8888 * tokens in template strings. 8889 */ 8890 function Scanner (string) { 8891 this.string = string; 8892 this.tail = string; 8893 this.pos = 0; 8894 } 8895 8896 /** 8897 * Returns `true` if the tail is empty (end of string). 8898 */ 8899 Scanner.prototype.eos = function eos () { 8900 return this.tail === ''; 8901 }; 8902 8903 /** 8904 * Tries to match the given regular expression at the current position. 8905 * Returns the matched text if it can match, the empty string otherwise. 8906 */ 8907 Scanner.prototype.scan = function scan (re) { 8908 var match = this.tail.match(re); 8909 8910 if (!match || match.index !== 0) 8911 return ''; 8912 8913 var string = match[0]; 8914 8915 this.tail = this.tail.substring(string.length); 8916 this.pos += string.length; 8917 8918 return string; 8919 }; 8920 8921 /** 8922 * Skips all text until the given regular expression can be matched. Returns 8923 * the skipped string, which is the entire tail if no match can be made. 8924 */ 8925 Scanner.prototype.scanUntil = function scanUntil (re) { 8926 var index = this.tail.search(re), match; 8927 8928 switch (index) { 8929 case -1: 8930 match = this.tail; 8931 this.tail = ''; 8932 break; 8933 case 0: 8934 match = ''; 8935 break; 8936 default: 8937 match = this.tail.substring(0, index); 8938 this.tail = this.tail.substring(index); 8939 } 8940 8941 this.pos += match.length; 8942 8943 return match; 8944 }; 8945 8946 /** 8947 * Represents a rendering context by wrapping a view object and 8948 * maintaining a reference to the parent context. 8949 */ 8950 function Context (view, parentContext) { 8951 this.view = view; 8952 this.cache = { '.': this.view }; 8953 this.parent = parentContext; 8954 } 8955 8956 /** 8957 * Creates a new context using the given view with this context 8958 * as the parent. 8959 */ 8960 Context.prototype.push = function push (view) { 8961 return new Context(view, this); 8962 }; 8963 8964 /** 8965 * Returns the value of the given name in this context, traversing 8966 * up the context hierarchy if the value is absent in this context's view. 8967 */ 8968 Context.prototype.lookup = function lookup (name) { 8969 var cache = this.cache; 8970 8971 var value; 8972 if (cache.hasOwnProperty(name)) { 8973 value = cache[name]; 8974 } else { 8975 var context = this, names, index, lookupHit = false; 8976 8977 while (context) { 8978 if (name.indexOf('.') > 0) { 8979 value = context.view; 8980 names = name.split('.'); 8981 index = 0; 8982 8983 /** 8984 * Using the dot notion path in `name`, we descend through the 8985 * nested objects. 8986 * 8987 * To be certain that the lookup has been successful, we have to 8988 * check if the last object in the path actually has the property 8989 * we are looking for. We store the result in `lookupHit`. 8990 * 8991 * This is specially necessary for when the value has been set to 8992 * `undefined` and we want to avoid looking up parent contexts. 8993 **/ 8994 while (value != null && index < names.length) { 8995 if (index === names.length - 1) 8996 lookupHit = hasProperty(value, names[index]); 8997 8998 value = value[names[index++]]; 8999 } 9000 } else { 9001 value = context.view[name]; 9002 lookupHit = hasProperty(context.view, name); 9003 } 9004 9005 if (lookupHit) 9006 break; 9007 9008 context = context.parent; 9009 } 9010 9011 cache[name] = value; 9012 } 9013 9014 if (isFunction(value)) 9015 value = value.call(this.view); 9016 9017 return value; 9018 }; 9019 9020 /** 9021 * A Writer knows how to take a stream of tokens and render them to a 9022 * string, given a context. It also maintains a cache of templates to 9023 * avoid the need to parse the same template twice. 9024 */ 9025 function Writer () { 9026 this.cache = {}; 9027 } 9028 9029 /** 9030 * Clears all cached templates in this writer. 9031 */ 9032 Writer.prototype.clearCache = function clearCache () { 9033 this.cache = {}; 9034 }; 9035 9036 /** 9037 * Parses and caches the given `template` and returns the array of tokens 9038 * that is generated from the parse. 9039 */ 9040 Writer.prototype.parse = function parse (template, tags) { 9041 var cache = this.cache; 9042 var tokens = cache[template]; 9043 9044 if (tokens == null) 9045 tokens = cache[template] = parseTemplate(template, tags); 9046 9047 return tokens; 9048 }; 9049 9050 /** 9051 * High-level method that is used to render the given `template` with 9052 * the given `view`. 9053 * 9054 * The optional `partials` argument may be an object that contains the 9055 * names and templates of partials that are used in the template. It may 9056 * also be a function that is used to load partial templates on the fly 9057 * that takes a single argument: the name of the partial. 9058 */ 9059 Writer.prototype.render = function render (template, view, partials) { 9060 var tokens = this.parse(template); 9061 var context = (view instanceof Context) ? view : new Context(view); 9062 return this.renderTokens(tokens, context, partials, template); 9063 }; 9064 9065 /** 9066 * Low-level method that renders the given array of `tokens` using 9067 * the given `context` and `partials`. 9068 * 9069 * Note: The `originalTemplate` is only ever used to extract the portion 9070 * of the original template that was contained in a higher-order section. 9071 * If the template doesn't use higher-order sections, this argument may 9072 * be omitted. 9073 */ 9074 Writer.prototype.renderTokens = function renderTokens (tokens, context, partials, originalTemplate) { 9075 var buffer = ''; 9076 9077 var token, symbol, value; 9078 for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) { 9079 value = undefined; 9080 token = tokens[i]; 9081 symbol = token[0]; 9082 9083 if (symbol === '#') value = this.renderSection(token, context, partials, originalTemplate); 9084 else if (symbol === '^') value = this.renderInverted(token, context, partials, originalTemplate); 9085 else if (symbol === '>') value = this.renderPartial(token, context, partials, originalTemplate); 9086 else if (symbol === '&') value = this.unescapedValue(token, context); 9087 else if (symbol === 'name') value = this.escapedValue(token, context); 9088 else if (symbol === 'text') value = this.rawValue(token); 9089 9090 if (value !== undefined) 9091 buffer += value; 9092 } 9093 9094 return buffer; 9095 }; 9096 9097 Writer.prototype.renderSection = function renderSection (token, context, partials, originalTemplate) { 9098 var self = this; 9099 var buffer = ''; 9100 var value = context.lookup(token[1]); 9101 9102 // This function is used to render an arbitrary template 9103 // in the current context by higher-order sections. 9104 function subRender (template) { 9105 return self.render(template, context, partials); 9106 } 9107 9108 if (!value) return; 9109 9110 if (isArray(value)) { 9111 for (var j = 0, valueLength = value.length; j < valueLength; ++j) { 9112 buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate); 9113 } 9114 } else if (typeof value === 'object' || typeof value === 'string' || typeof value === 'number') { 9115 buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate); 9116 } else if (isFunction(value)) { 9117 if (typeof originalTemplate !== 'string') 9118 throw new Error('Cannot use higher-order sections without the original template'); 9119 9120 // Extract the portion of the original template that the section contains. 9121 value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender); 9122 9123 if (value != null) 9124 buffer += value; 9125 } else { 9126 buffer += this.renderTokens(token[4], context, partials, originalTemplate); 9127 } 9128 return buffer; 9129 }; 9130 9131 Writer.prototype.renderInverted = function renderInverted (token, context, partials, originalTemplate) { 9132 var value = context.lookup(token[1]); 9133 9134 // Use JavaScript's definition of falsy. Include empty arrays. 9135 // See https://github.com/janl/mustache.js/issues/186 9136 if (!value || (isArray(value) && value.length === 0)) 9137 return this.renderTokens(token[4], context, partials, originalTemplate); 9138 }; 9139 9140 Writer.prototype.renderPartial = function renderPartial (token, context, partials) { 9141 if (!partials) return; 9142 9143 var value = isFunction(partials) ? partials(token[1]) : partials[token[1]]; 9144 if (value != null) 9145 return this.renderTokens(this.parse(value), context, partials, value); 9146 }; 9147 9148 Writer.prototype.unescapedValue = function unescapedValue (token, context) { 9149 var value = context.lookup(token[1]); 9150 if (value != null) 9151 return value; 9152 }; 9153 9154 Writer.prototype.escapedValue = function escapedValue (token, context) { 9155 var value = context.lookup(token[1]); 9156 if (value != null) 9157 return mustache.escape(value); 9158 }; 9159 9160 Writer.prototype.rawValue = function rawValue (token) { 9161 return token[1]; 9162 }; 9163 9164 mustache.name = 'mustache.js'; 9165 mustache.version = '2.3.0'; 9166 mustache.tags = [ '{{', '}}' ]; 9167 9168 // All high-level mustache.* functions use this writer. 9169 var defaultWriter = new Writer(); 9170 9171 /** 9172 * Clears all cached templates in the default writer. 9173 */ 9174 mustache.clearCache = function clearCache () { 9175 return defaultWriter.clearCache(); 9176 }; 9177 9178 /** 9179 * Parses and caches the given template in the default writer and returns the 9180 * array of tokens it contains. Doing this ahead of time avoids the need to 9181 * parse templates on the fly as they are rendered. 9182 */ 9183 mustache.parse = function parse (template, tags) { 9184 return defaultWriter.parse(template, tags); 9185 }; 9186 9187 /** 9188 * Renders the `template` with the given `view` and `partials` using the 9189 * default writer. 9190 */ 9191 mustache.render = function render (template, view, partials) { 9192 if (typeof template !== 'string') { 9193 throw new TypeError('Invalid template! Template should be a "string" ' + 9194 'but "' + typeStr(template) + '" was given as the first ' + 9195 'argument for mustache#render(template, view, partials)'); 9196 } 9197 9198 return defaultWriter.render(template, view, partials); 9199 }; 9200 9201 // This is here for backwards compatibility with 0.4.x., 9202 /*eslint-disable */ // eslint wants camel cased function name 9203 mustache.to_html = function to_html (template, view, partials, send) { 9204 /*eslint-enable*/ 9205 9206 var result = mustache.render(template, view, partials); 9207 9208 if (isFunction(send)) { 9209 send(result); 9210 } else { 9211 return result; 9212 } 9213 }; 9214 9215 // Export the escaping function so that the user may override it. 9216 // See https://github.com/janl/mustache.js/issues/244 9217 mustache.escape = escapeHtml; 9218 9219 // Export these mainly for testing, but also for advanced usage. 9220 mustache.Scanner = Scanner; 9221 mustache.Context = Context; 9222 mustache.Writer = Writer; 9223 9224 return mustache; 9225})); 9226 9227},{}],46
vendor: 5,461 bytes, lines 9227-9413
9227:[function(require,module,exports){ 9228// shim for using process in browser 9229var process = module.exports = {}; 9230 9231// cached from whatever global is present so that test runners that stub it 9232// don't break things. But we need to wrap it in a try catch in case it is 9233// wrapped in strict mode code which doesn't define any globals. It's inside a 9234// function because try/catches deoptimize in certain engines. 9235 9236var cachedSetTimeout; 9237var cachedClearTimeout; 9238 9239function defaultSetTimout() { 9240 throw new Error('setTimeout has not been defined'); 9241} 9242function defaultClearTimeout () { 9243 throw new Error('clearTimeout has not been defined'); 9244} 9245(function () { 9246 try { 9247 if (typeof setTimeout === 'function') { 9248 cachedSetTimeout = setTimeout; 9249 } else { 9250 cachedSetTimeout = defaultSetTimout; 9251 } 9252 } catch (e) { 9253 cachedSetTimeout = defaultSetTimout; 9254 } 9255 try { 9256 if (typeof clearTimeout === 'function') { 9257 cachedClearTimeout = clearTimeout; 9258 } else { 9259 cachedClearTimeout = defaultClearTimeout; 9260 } 9261 } catch (e) { 9262 cachedClearTimeout = defaultClearTimeout; 9263 } 9264} ()) 9265function runTimeout(fun) { 9266 if (cachedSetTimeout === setTimeout) { 9267 //normal enviroments in sane situations 9268 return setTimeout(fun, 0); 9269 } 9270 // if setTimeout wasn't available but was latter defined 9271 if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { 9272 cachedSetTimeout = setTimeout; 9273 return setTimeout(fun, 0); 9274 } 9275 try { 9276 // when when somebody has screwed with setTimeout but no I.E. maddness 9277 return cachedSetTimeout(fun, 0); 9278 } catch(e){ 9279 try { 9280 // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally 9281 return cachedSetTimeout.call(null, fun, 0); 9282 } catch(e){ 9283 // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error 9284 return cachedSetTimeout.call(this, fun, 0); 9285 } 9286 } 9287 9288 9289} 9290function runClearTimeout(marker) { 9291 if (cachedClearTimeout === clearTimeout) { 9292 //normal enviroments in sane situations 9293 return clearTimeout(marker); 9294 } 9295 // if clearTimeout wasn't available but was latter defined 9296 if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { 9297 cachedClearTimeout = clearTimeout; 9298 return clearTimeout(marker); 9299 } 9300 try { 9301 // when when somebody has screwed with setTimeout but no I.E. maddness 9302 return cachedClearTimeout(marker); 9303 } catch (e){ 9304 try { 9305 // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally 9306 return cachedClearTimeout.call(null, marker); 9307 } catch (e){ 9308 // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. 9309 // Some versions of I.E. have different rules for clearTimeout vs setTimeout 9310 return cachedClearTimeout.call(this, marker); 9311 } 9312 } 9313 9314 9315 9316} 9317var queue = []; 9318var draining = false; 9319var currentQueue; 9320var queueIndex = -1; 9321 9322function cleanUpNextTick() { 9323 if (!draining || !currentQueue) { 9324 return; 9325 } 9326 draining = false; 9327 if (currentQueue.length) { 9328 queue = currentQueue.concat(queue); 9329 } else { 9330 queueIndex = -1; 9331 } 9332 if (queue.length) { 9333 drainQueue(); 9334 } 9335} 9336 9337function drainQueue() { 9338 if (draining) { 9339 return; 9340 } 9341 var timeout = runTimeout(cleanUpNextTick); 9342 draining = true; 9343 9344 var len = queue.length; 9345 while(len) { 9346 currentQueue = queue; 9347 queue = []; 9348 while (++queueIndex < len) { 9349 if (currentQueue) { 9350 currentQueue[queueIndex].run(); 9351 } 9352 } 9353 queueIndex = -1; 9354 len = queue.length; 9355 } 9356 currentQueue = null; 9357 draining = false; 9358 runClearTimeout(timeout); 9359} 9360 9361process.nextTick = function (fun) { 9362 var args = new Array(arguments.length - 1); 9363 if (arguments.length > 1) { 9364 for (var i = 1; i < arguments.length; i++) { 9365 args[i - 1] = arguments[i]; 9366 } 9367 } 9368 queue.push(new Item(fun, args)); 9369 if (queue.length === 1 && !draining) { 9370 runTimeout(drainQueue); 9371 } 9372}; 9373 9374// v8 likes predictible objects 9375function Item(fun, array) { 9376 this.fun = fun; 9377 this.array = array; 9378} 9379Item.prototype.run = function () { 9380 this.fun.apply(null, this.array); 9381}; 9382process.title = 'browser'; 9383process.browser = true; 9384process.env = {}; 9385process.argv = []; 9386process.version = ''; // empty string to avoid regexp issues 9387process.versions = {}; 9388 9389function noop() {} 9390 9391process.on = noop; 9392process.addListener = noop; 9393process.once = noop; 9394process.off = noop; 9395process.removeListener = noop; 9396process.removeAllListeners = noop; 9397process.emit = noop; 9398process.prependListener = noop; 9399process.prependOnceListener = noop; 9400 9401process.listeners = function (name) { return [] } 9402 9403process.binding = function (name) { 9404 throw new Error('process.binding is not supported'); 9405}; 9406 9407process.cwd = function () { return '/' }; 9408process.chdir = function (dir) { 9409 throw new Error('process.chdir is not supported'); 9410}; 9411process.umask = function() { return 0; }; 9412 9413},{}],
941347:[function(require,module,exports){ 9414/*! 9415 * @preserve Qwery - A selector engine 9416 * https://github.com/ded/qwery 9417 * (c) Dustin Diaz 2014 | License MIT 9418 */ 9419 9420(function (name, context, definition) { 9421 if (typeof module != 'undefined' && module.exports) module.exports = definition() 9422 else if (typeof define == 'function' && define.amd) define(definition) 9423 else context[name] = definition() 9424})('qwery', this, function () { 9425 9426 var classOnly = /^\.([\w\-]+)$/ 9427 , doc = document 9428 , win = window 9429 , html = doc.documentElement 9430 , nodeType = 'nodeType' 9431 var isAncestor = 'compareDocumentPosition' in html ? 9432 function (element, container) { 9433 return (container.compareDocumentPosition(element) & 16) == 16 9434 } : 9435 function (element, container) { 9436 container = container == doc || container == window ? html : container 9437 return container !== element && container.contains(element) 9438 } 9439 9440 function toArray(ar) { 9441 return [].slice.call(ar, 0) 9442 } 9443 9444 function isNode(el) { 9445 var t 9446 return el && typeof el === 'object' && (t = el.nodeType) && (t == 1 || t == 9) 9447 } 9448 9449 function arrayLike(o) { 9450 return (typeof o === 'object' && isFinite(o.length)) 9451 } 9452 9453 function flatten(ar) { 9454 for (var r = [], i = 0, l = ar.length; i < l; ++i) arrayLike(ar[i]) ? (r = r.concat(ar[i])) : (r[r.length] = ar[i]) 9455 return r 9456 } 9457 9458 function uniq(ar) { 9459 var a = [], i, j 9460 label: 9461 for (i = 0; i < ar.length; i++) { 9462 for (j = 0; j < a.length; j++) { 9463 if (a[j] == ar[i]) { 9464 continue label 9465 } 9466 } 9467 a[a.length] = ar[i] 9468 } 9469 return a 9470 } 9471 9472 9473 function normalizeRoot(root) { 9474 if (!root) return doc 9475 if (typeof root == 'string') return qwery(root)[0] 9476 if (!root[nodeType] && arrayLike(root)) return root[0] 9477 return root 9478 } 9479 9480 /** 9481 * @param {string|Array.<Element>|Element|Node} selector 9482 * @param {string|Array.<Element>|Element|Node=} opt_root 9483 * @return {Array.<Element>} 9484 */ 9485 function qwery(selector, opt_root) { 9486 var m, root = normalizeRoot(opt_root) 9487 if (!root || !selector) return [] 9488 if (selector === win || isNode(selector)) { 9489 return !opt_root || (selector !== win && isNode(root) && isAncestor(selector, root)) ? [selector] : [] 9490 } 9491 if (selector && arrayLike(selector)) return flatten(selector) 9492 9493 9494 if (doc.getElementsByClassName && selector == 'string' && (m = selector.match(classOnly))) { 9495 return toArray((root).getElementsByClassName(m[1])) 9496 } 9497 // using duck typing for 'a' window or 'a' document (not 'the' window || document) 9498 if (selector && (selector.document || (selector.nodeType && selector.nodeType == 9))) { 9499 return !opt_root ? [selector] : [] 9500 } 9501 return toArray((root).querySelectorAll(selector)) 9502 } 9503 9504 qwery.uniq = uniq 9505 9506 return qwery 9507}, this); 9508 9509},{}],48:[function(require,module,exports){ 9510var inherits = require('inherits') 9511var EventEmitter = require('events').EventEmitter 9512var now = require('right-now') 9513var raf = require('raf') 9514 9515module.exports = Engine 9516function Engine(fn) { 9517 if (!(this instanceof Engine)) 9518 return new Engine(fn) 9519 this.running = false 9520 this.last = now() 9521 this._frame = 0 9522 this._tick = this.tick.bind(this) 9523 9524 if (fn) 9525 this.on('tick', fn) 9526} 9527 9528inherits(Engine, EventEmitter) 9529 9530Engine.prototype.start = function() { 9531 if (this.running) 9532 return 9533 this.running = true 9534 this.last = now() 9535 this._frame = raf(this._tick) 9536 return this 9537} 9538 9539Engine.prototype.stop = function() { 9540 this.running = false 9541 if (this._frame !== 0) 9542 raf.cancel(this._frame) 9543 this._frame = 0 9544 return this 9545} 9546 9547Engine.prototype.tick = function() { 9548 this._frame = raf(this._tick) 9549 var time = now() 9550 var dt = time - this.last
9551 this.emit('tick', dt) 9552 this.last = time 9553} 9554},{"events":43,"inherits":44,"raf":49,"right-now":51}],49:[function(require,module,exports){ 9555(function (global){ 9556var now = require('performance-now') 9557 , root = typeof window === 'undefined' ? global : window 9558 , vendors = ['moz', 'webkit'] 9559 , suffix = 'AnimationFrame' 9560 , raf = root['request' + suffix] 9561 , caf = root['cancel' + suffix] || root['cancelRequest' + suffix] 9562 9563for(var i = 0; !raf && i < vendors.length; i++) { 9564 raf = root[vendors[i] + 'Request' + suffix] 9565 caf = root[vendors[i] + 'Cancel' + suffix] 9566 || root[vendors[i] + 'CancelRequest' + suffix] 9567} 9568 9569// Some versions of FF have rAF but not cAF 9570if(!raf || !caf) { 9571 var last = 0 9572 , id = 0 9573 , queue = [] 9574 , frameDuration = 1000 / 60 9575 9576 raf = function(callback) { 9577 if(queue.length === 0) { 9578 var _now = now() 9579 , next = Math.max(0, frameDuration - (_now - last)) 9580 last = next + _now 9581 setTimeout(function() { 9582 var cp = queue.slice(0) 9583 // Clear queue here to prevent 9584 // callbacks from appending listeners 9585 // to the current frame's queue 9586 queue.length = 0 9587 for(var i = 0; i < cp.length; i++) { 9588 if(!cp[i].cancelled) { 9589 try{ 9590 cp[i].callback(last) 9591 } catch(e) { 9592 setTimeout(function() { throw e }, 0) 9593 } 9594 } 9595 } 9596 }, Math.round(next)) 9597 } 9598 queue.push({ 9599 handle: ++id, 9600 callback: callback, 9601 cancelled: false 9602 }) 9603 return id 9604 } 9605 9606 caf = function(handle) { 9607 for(var i = 0; i < queue.length; i++) { 9608 if(queue[i].handle === handle) { 9609 queue[i].cancelled = true 9610 } 9611 } 9612 } 9613} 9614 9615module.exports = function(fn) { 9616 // Wrap in a new function to prevent 9617 // `cancel` potentially being assigned 9618 // to the native rAF function 9619 return raf.call(root, fn) 9620} 9621module.exports.cancel = function() { 9622 caf.apply(root, arguments) 9623} 9624module.exports.polyfill = function(object) { 9625 if (!object) { 9626 object = root; 9627 } 9628 object.requestAnimationFrame = raf 9629 object.cancelAnimationFrame = caf 9630} 9631 9632}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 9633},{"performance-now":50}],50:[function(require,module,exports){ 9634(function (process){ 9635// Generated by CoffeeScript 1.12.2 9636(function() { 9637 var getNanoSeconds, hrtime, loadTime, moduleLoadTime, nodeLoadTime, upTime; 9638 9639 if ((typeof performance !== "undefined" && performance !== null) && performance.now) { 9640 module.exports = function() { 9641 return performance.now(); 9642 }; 9643 } else if ((typeof process !== "undefined" && process !== null) && process.hrtime) { 9644 module.exports = function() { 9645 return (getNanoSeconds() - nodeLoadTime) / 1e6; 9646 }; 9647 hrtime = process.hrtime; 9648 getNanoSeconds = function() { 9649 var hr; 9650 hr = hrtime(); 9651 return hr[0] * 1e9 + hr[1]; 9652 }; 9653 moduleLoadTime = getNanoSeconds(); 9654 upTime = process.uptime() * 1e9; 9655 nodeLoadTime = moduleLoadTime - upTime; 9656 } else if (Date.now) { 9657 module.exports = function() { 9658 return Date.now() - loadTime; 9659 }; 9660 loadTime = Date.now(); 9661 } else { 9662 module.exports = function() { 9663 return new Date().getTime() - loadTime; 9664 }; 9665 loadTime = new Date().getTime(); 9666 } 9667 9668}).call(this); 9669 9670 9671 9672}).call(this,require('_process')) 9673},{"_process":46}],51:[function(require,module,exports){ 9674(function (global){ 9675module.exports = 9676 global.performance && 9677 global.performance.now ? function now() { 9678 return performance.now() 9679 } : Date.now || function now() { 9680 return +new Date 9681 } 9682 9683}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 9684},{}],52:[function(require,module,exports){ 9685(function (global){ 9686!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.routes=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<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ 9687 9688var localRoutes = []; 9689 9690 9691/** 9692 * Convert path to route object 9693 * 9694 * A string or RegExp should be passed, 9695 * will return { re, src, keys} obj 9696 * 9697 * @param {String / RegExp} path 9698 * @return {Object} 9699 */ 9700 9701var Route = function(path){
9702 //using 'new' is optional 9703 9704 var src, re, keys = []; 9705 9706 if(path instanceof RegExp){ 9707 re = path; 9708 src = path.toString(); 9709 }else{ 9710 re = pathToRegExp(path, keys); 9711 src = path; 9712 } 9713 9714 return { 9715 re: re, 9716 src: path.toString(), 9717 keys: keys 9718 } 9719}; 9720 9721/** 9722 * Normalize the given path string, 9723 * returning a regular expression. 9724 * 9725 * An empty array should be passed, 9726 * which will contain the placeholder 9727 * key names. For example "/user/:id" will 9728 * then contain ["id"]. 9729 * 9730 * @param {String} path 9731 * @param {Array} keys 9732 * @return {RegExp} 9733 */ 9734var pathToRegExp = function (path, keys) { 9735 path = path 9736 .concat('/?') 9737 .replace(/\/\(/g, '(?:/') 9738 .replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?|\*/g, function(_, slash, format, key, capture, optional){ 9739 if (_ === "*"){ 9740 keys.push(undefined); 9741 return _; 9742 } 9743 9744 keys.push(key); 9745 slash = slash || ''; 9746 return '' 9747 + (optional ? '' : slash) 9748 + '(?:' 9749 + (optional ? slash : '') 9750 + (format || '') + (capture || '([^/]+?)') + ')' 9751 + (optional || ''); 9752 }) 9753 .replace(/([\/.])/g, '\\$1') 9754 .replace(/\*/g, '(.*)'); 9755 return new RegExp('^' + path + '$', 'i'); 9756}; 9757 9758/** 9759 * Attempt to match the given request to 9760 * one of the routes. When successful 9761 * a {fn, params, splats} obj is returned 9762 * 9763 * @param {Array} routes 9764 * @param {String} uri 9765 * @return {Object} 9766 */ 9767var match = function (routes, uri, startAt) { 9768 var captures, i = startAt || 0; 9769 9770 for (var len = routes.length; i < len; ++i) { 9771 var route = routes[i], 9772 re = route.re, 9773 keys = route.keys, 9774 splats = [], 9775 params = {}; 9776 9777 if (captures = uri.match(re)) { 9778 for (var j = 1, len = captures.length; j < len; ++j) { 9779 var key = keys[j-1], 9780 val = typeof captures[j] === 'string' 9781 ? unescape(captures[j]) 9782 : captures[j]; 9783 if (key) { 9784 params[key] = val; 9785 } else { 9786 splats.push(val); 9787 } 9788 } 9789 return { 9790 params: params, 9791 splats: splats, 9792 route: route.src, 9793 next: i + 1 9794 }; 9795 } 9796 } 9797}; 9798 9799/** 9800 * Default "normal" router constructor. 9801 * accepts path, fn tuples via addRoute 9802 * returns {fn, params, splats, route} 9803 * via match 9804 * 9805 * @return {Object} 9806 */ 9807 9808var Router = function(){ 9809 //using 'new' is optional 9810 return { 9811 routes: [], 9812 routeMap : {}, 9813 addRoute: function(path, fn){ 9814 if (!path) throw new Error(' route requires a path'); 9815 if (!fn) throw new Error(' route ' + path.toString() + ' requires a callback'); 9816 9817 if (this.routeMap[path]) { 9818 throw new Error('path is already defined: ' + path); 9819 } 9820 9821 var route = Route(path); 9822 route.fn = fn; 9823 9824 this.routes.push(route); 9825 this.routeMap[path] = fn; 9826 }, 9827 9828 removeRoute: function(path) { 9829 if (!path) throw new Error(' route requires a path'); 9830 if (!this.routeMap[path]) { 9831 throw new Error('path does not exist: ' + path); 9832 } 9833 9834 var match; 9835 var newRoutes = []; 9836 9837 // copy the routes excluding the route being removed 9838 for (var i = 0; i < this.routes.length; i++) { 9839 var route = this.routes[i]; 9840 if (route.src !== path) { 9841 newRoutes.push(route); 9842 } 9843 } 9844 this.routes = newRoutes; 9845 delete this.routeMap[path]; 9846 }, 9847 9848 match: function(pathname, startAt){ 9849 var route = match(this.routes, pathname, startAt); 9850 if(route){ 9851 route.fn = this.routeMap[route.route]; 9852 route.next = this.match.bind(this, pathname, route.next) 9853 } 9854 return route; 9855 } 9856 } 9857}; 9858 9859Router.Route = Route 9860Router.pathToRegExp = pathToRegExp 9861Router.match = match 9862// back compat 9863Router.Router = Router 9864 9865module.exports = Router 9866 9867},{}]},{},[1]) 9868(1) 9869}); 9870}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 9871},{}],53
vendor: 52,962 bytes, lines 9871-11421
9871:[function(require,module,exports){ 9872// Underscore.js 1.8.3 9873// http://underscorejs.org 9874// (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 9875// Underscore may be freely distributed under the MIT license. 9876 9877(function() { 9878 9879 // Baseline setup 9880 // -------------- 9881 9882 // Establish the root object, `window` in the browser, or `exports` on the server. 9883 var root = this; 9884 9885 // Save the previous value of the `_` variable. 9886 var previousUnderscore = root._; 9887 9888 // Save bytes in the minified (but not gzipped) version: 9889 var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; 9890 9891 // Create quick reference variables for speed access to core prototypes. 9892 var 9893 push = ArrayProto.push, 9894 slice = ArrayProto.slice, 9895 toString = ObjProto.toString, 9896 hasOwnProperty = ObjProto.hasOwnProperty; 9897 9898 // All **ECMAScript 5** native function implementations that we hope to use 9899 // are declared here. 9900 var 9901 nativeIsArray = Array.isArray, 9902 nativeKeys = Object.keys, 9903 nativeBind = FuncProto.bind, 9904 nativeCreate = Object.create; 9905 9906 // Naked function reference for surrogate-prototype-swapping. 9907 var Ctor = function(){}; 9908 9909 // Create a safe reference to the Underscore object for use below. 9910 var _ = function(obj) { 9911 if (obj instanceof _) return obj; 9912 if (!(this instanceof _)) return new _(obj); 9913 this._wrapped = obj; 9914 }; 9915 9916 // Export the Underscore object for **Node.js**, with 9917 // backwards-compatibility for the old `require()` API. If we're in 9918 // the browser, add `_` as a global object. 9919 if (typeof exports !== 'undefined') { 9920 if (typeof module !== 'undefined' && module.exports) { 9921 exports = module.exports = _; 9922 } 9923 exports._ = _; 9924 } else { 9925 root._ = _; 9926 } 9927 9928 // Current version. 9929 _.VERSION = '1.8.3'; 9930 9931 // Internal function that returns an efficient (for current engines) version 9932 // of the passed-in callback, to be repeatedly applied in other Underscore 9933 // functions. 9934 var optimizeCb = function(func, context, argCount) { 9935 if (context === void 0) return func; 9936 switch (argCount == null ? 3 : argCount) { 9937 case 1: return function(value) { 9938 return func.call(context, value); 9939 }; 9940 case 2: return function(value, other) { 9941 return func.call(context, value, other); 9942 }; 9943 case 3: return function(value, index, collection) { 9944 return func.call(context, value, index, collection); 9945 }; 9946 case 4: return function(accumulator, value, index, collection) { 9947 return func.call(context, accumulator, value, index, collection); 9948 }; 9949 } 9950 return function() { 9951 return func.apply(context, arguments); 9952 }; 9953 }; 9954 9955 // A mostly-internal function to generate callbacks that can be applied 9956 // to each element in a collection, returning the desired result â either 9957 // identity, an arbitrary callback, a property matcher, or a property accessor. 9958 var cb = function(value, context, argCount) { 9959 if (value == null) return _.identity; 9960 if (_.isFunction(value)) return optimizeCb(value, context, argCount); 9961 if (_.isObject(value)) return _.matcher(value); 9962 return _.property(value); 9963 }; 9964 _.iteratee = function(value, context) { 9965 return cb(value, context, Infinity); 9966 }; 9967 9968 // An internal function for creating assigner functions. 9969 var createAssigner = function(keysFunc, undefinedOnly) { 9970 return function(obj) { 9971 var length = arguments.length; 9972 if (length < 2 || obj == null) return obj; 9973 for (var index = 1; index < length; index++) { 9974 var source = arguments[index], 9975 keys = keysFunc(source), 9976 l = keys.length; 9977 for (var i = 0; i < l; i++) { 9978 var key = keys[i]; 9979 if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key]; 9980 } 9981 } 9982 return obj; 9983 }; 9984 }; 9985 9986 // An internal function for creating a new object that inherits from another. 9987 var baseCreate = function(prototype) { 9988 if (!_.isObject(prototype)) return {}; 9989 if (nativeCreate) return nativeCreate(prototype); 9990 Ctor.prototype = prototype; 9991 var result = new Ctor; 9992 Ctor.prototype = null; 9993 return result; 9994 }; 9995 9996 var property = function(key) { 9997 return function(obj) { 9998 return obj == null ? void 0 : obj[key]; 9999 }; 10000 }; 10001 10002 // Helper for collection methods to determine whether a collection 10003 // should be iterated as an array or as an object 10004 // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength 10005 // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094 10006 var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; 10007 var getLength = property('length'); 10008 var isArrayLike = function(collection) { 10009 var length = getLength(collection); 10010 return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; 10011 }; 10012 10013 // Collection Functions 10014 // -------------------- 10015 10016 // The cornerstone, an `each` implementation, aka `forEach`. 10017 // Handles raw objects in addition to array-likes. Treats all 10018 // sparse array-likes as if they were dense. 10019 _.each = _.forEach = function(obj, iteratee, context) { 10020 iteratee = optimizeCb(iteratee, context); 10021 var i, length; 10022 if (isArrayLike(obj)) { 10023 for (i = 0, length = obj.length; i < length; i++) { 10024 iteratee(obj[i], i, obj); 10025 } 10026 } else { 10027 var keys = _.keys(obj); 10028 for (i = 0, length = keys.length; i < length; i++) { 10029 iteratee(obj[keys[i]], keys[i], obj); 10030 } 10031 } 10032 return obj; 10033 }; 10034 10035 // Return the results of applying the iteratee to each element. 10036 _.map = _.collect = function(obj, iteratee, context) { 10037 iteratee = cb(iteratee, context); 10038 var keys = !isArrayLike(obj) && _.keys(obj), 10039 length = (keys || obj).length, 10040 results = Array(length); 10041 for (var index = 0; index < length; index++) { 10042 var currentKey = keys ? keys[index] : index; 10043 results[index] = iteratee(obj[currentKey], currentKey, obj); 10044 } 10045 return results; 10046 }; 10047 10048 // Create a reducing function iterating left or right. 10049 function createReduce(dir) { 10050 // Optimized iterator function as using arguments.length 10051 // in the main function will deoptimize the, see #1991. 10052 function iterator(obj, iteratee, memo, keys, index, length) { 10053 for (; index >= 0 && index < length; index += dir) { 10054 var currentKey = keys ? keys[index] : index; 10055 memo = iteratee(memo, obj[currentKey], currentKey, obj); 10056 } 10057 return memo; 10058 } 10059 10060 return function(obj, iteratee, memo, context) { 10061 iteratee = optimizeCb(iteratee, context, 4); 10062 var keys = !isArrayLike(obj) && _.keys(obj), 10063 length = (keys || obj).length, 10064 index = dir > 0 ? 0 : length - 1; 10065 // Determine the initial value if none is provided. 10066 if (arguments.length < 3) { 10067 memo = obj[keys ? keys[index] : index]; 10068 index += dir; 10069 } 10070 return iterator(obj, iteratee, memo, keys, index, length); 10071 }; 10072 } 10073 10074 // **Reduce** builds up a single result from a list of values, aka `inject`, 10075 // or `foldl`. 10076 _.reduce = _.foldl = _.inject = createReduce(1); 10077 10078 // The right-associative version of reduce, also known as `foldr`. 10079 _.reduceRight = _.foldr = createReduce(-1); 10080 10081 // Return the first value which passes a truth test. Aliased as `detect`. 10082 _.find = _.detect = function(obj, predicate, context) { 10083 var key; 10084 if (isArrayLike(obj)) { 10085 key = _.findIndex(obj, predicate, context); 10086 } else { 10087 key = _.findKey(obj, predicate, context); 10088 } 10089 if (key !== void 0 && key !== -1) return obj[key]; 10090 }; 10091 10092 // Return all the elements that pass a truth test. 10093 // Aliased as `select`. 10094 _.filter = _.select = function(obj, predicate, context) { 10095 var results = []; 10096 predicate = cb(predicate, context); 10097 _.each(obj, function(value, index, list) { 10098 if (predicate(value, index, list)) results.push(value); 10099 }); 10100 return results; 10101 }; 10102 10103 // Return all the elements for which a truth test fails. 10104 _.reject = function(obj, predicate, context) { 10105 return _.filter(obj, _.negate(cb(predicate)), context); 10106 }; 10107 10108 // Determine whether all of the elements match a truth test. 10109 // Aliased as `all`. 10110 _.every = _.all = function(obj, predicate, context) { 10111 predicate = cb(predicate, context); 10112 var keys = !isArrayLike(obj) && _.keys(obj), 10113 length = (keys || obj).length; 10114 for (var index = 0; index < length; index++) { 10115 var currentKey = keys ? keys[index] : index; 10116 if (!predicate(obj[currentKey], currentKey, obj)) return false; 10117 } 10118 return true; 10119 }; 10120 10121 // Determine if at least one element in the object matches a truth test. 10122 // Aliased as `any`. 10123 _.some = _.any = function(obj, predicate, context) { 10124 predicate = cb(predicate, context); 10125 var keys = !isArrayLike(obj) && _.keys(obj), 10126 length = (keys || obj).length; 10127 for (var index = 0; index < length; index++) { 10128 var currentKey = keys ? keys[index] : index; 10129 if (predicate(obj[currentKey], currentKey, obj)) return true; 10130 } 10131 return false; 10132 }; 10133 10134 // Determine if the array or object contains a given item (using `===`). 10135 // Aliased as `includes` and `include`. 10136 _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) { 10137 if (!isArrayLike(obj)) obj = _.values(obj); 10138 if (typeof fromIndex != 'number' || guard) fromIndex = 0; 10139 return _.indexOf(obj, item, fromIndex) >= 0; 10140 }; 10141 10142 // Invoke a method (with arguments) on every item in a collection. 10143 _.invoke = function(obj, method) { 10144 var args = slice.call(arguments, 2); 10145 var isFunc = _.isFunction(method); 10146 return _.map(obj, function(value) { 10147 var func = isFunc ? method : value[method]; 10148 return func == null ? func : func.apply(value, args); 10149 }); 10150 }; 10151 10152 // Convenience version of a common use case of `map`: fetching a property. 10153 _.pluck = function(obj, key) { 10154 return _.map(obj, _.property(key)); 10155 }; 10156 10157 // Convenience version of a common use case of `filter`: selecting only objects 10158 // containing specific `key:value` pairs. 10159 _.where = function(obj, attrs) { 10160 return _.filter(obj, _.matcher(attrs)); 10161 }; 10162 10163 // Convenience version of a common use case of `find`: getting the first object 10164 // containing specific `key:value` pairs. 10165 _.findWhere = function(obj, attrs) { 10166 return _.find(obj, _.matcher(attrs)); 10167 }; 10168 10169 // Return the maximum element (or element-based computation). 10170 _.max = function(obj, iteratee, context) { 10171 var result = -Infinity, lastComputed = -Infinity, 10172 value, computed; 10173 if (iteratee == null && obj != null) { 10174 obj = isArrayLike(obj) ? obj : _.values(obj); 10175 for (var i = 0, length = obj.length; i < length; i++) { 10176 value = obj[i]; 10177 if (value > result) { 10178 result = value; 10179 } 10180 } 10181 } else { 10182 iteratee = cb(iteratee, context); 10183 _.each(obj, function(value, index, list) { 10184 computed = iteratee(value, index, list); 10185 if (computed > lastComputed || computed === -Infinity && result === -Infinity) { 10186 result = value; 10187 lastComputed = computed; 10188 } 10189 }); 10190 } 10191 return result; 10192 }; 10193 10194 // Return the minimum element (or element-based computation). 10195 _.min = function(obj, iteratee, context) { 10196 var result = Infinity, lastComputed = Infinity, 10197 value, computed; 10198 if (iteratee == null && obj != null) { 10199 obj = isArrayLike(obj) ? obj : _.values(obj); 10200 for (var i = 0, length = obj.length; i < length; i++) { 10201 value = obj[i]; 10202 if (value < result) { 10203 result = value; 10204 } 10205 } 10206 } else { 10207 iteratee = cb(iteratee, context); 10208 _.each(obj, function(value, index, list) { 10209 computed = iteratee(value, index, list); 10210 if (computed < lastComputed || computed === Infinity && result === Infinity) { 10211 result = value; 10212 lastComputed = computed; 10213 } 10214 }); 10215 } 10216 return result; 10217 }; 10218 10219 // Shuffle a collection, using the modern version of the 10220 // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/FisherâYates_shuffle). 10221 _.shuffle = function(obj) { 10222 var set = isArrayLike(obj) ? obj : _.values(obj); 10223 var length = set.length; 10224 var shuffled = Array(length); 10225 for (var index = 0, rand; index < length; index++) { 10226 rand = _.random(0, index); 10227 if (rand !== index) shuffled[index] = shuffled[rand]; 10228 shuffled[rand] = set[index]; 10229 } 10230 return shuffled; 10231 }; 10232 10233 // Sample **n** random values from a collection. 10234 // If **n** is not specified, returns a single random element. 10235 // The internal `guard` argument allows it to work with `map`. 10236 _.sample = function(obj, n, guard) { 10237 if (n == null || guard) { 10238 if (!isArrayLike(obj)) obj = _.values(obj); 10239 return obj[_.random(obj.length - 1)]; 10240 } 10241 return _.shuffle(obj).slice(0, Math.max(0, n)); 10242 }; 10243 10244 // Sort the object's values by a criterion produced by an iteratee. 10245 _.sortBy = function(obj, iteratee, context) { 10246 iteratee = cb(iteratee, context); 10247 return _.pluck(_.map(obj, function(value, index, list) { 10248 return { 10249 value: value, 10250 index: index, 10251 criteria: iteratee(value, index, list) 10252 }; 10253 }).sort(function(left, right) { 10254 var a = left.criteria; 10255 var b = right.criteria; 10256 if (a !== b) { 10257 if (a > b || a === void 0) return 1; 10258 if (a < b || b === void 0) return -1; 10259 } 10260 return left.index - right.index; 10261 }), 'value'); 10262 }; 10263 10264 // An internal function used for aggregate "group by" operations. 10265 var group = function(behavior) { 10266 return function(obj, iteratee, context) { 10267 var result = {}; 10268 iteratee = cb(iteratee, context); 10269 _.each(obj, function(value, index) { 10270 var key = iteratee(value, index, obj); 10271 behavior(result, value, key); 10272 }); 10273 return result; 10274 }; 10275 }; 10276 10277 // Groups the object's values by a criterion. Pass either a string attribute 10278 // to group by, or a function that returns the criterion. 10279 _.groupBy = group(function(result, value, key) { 10280 if (_.has(result, key)) result[key].push(value); else result[key] = [value]; 10281 }); 10282 10283 // Indexes the object's values by a criterion, similar to `groupBy`, but for 10284 // when you know that your index values will be unique. 10285 _.indexBy = group(function(result, value, key) { 10286 result[key] = value; 10287 }); 10288 10289 // Counts instances of an object that group by a certain criterion. Pass 10290 // either a string attribute to count by, or a function that returns the 10291 // criterion. 10292 _.countBy = group(function(result, value, key) { 10293 if (_.has(result, key)) result[key]++; else result[key] = 1; 10294 }); 10295 10296 // Safely create a real, live array from anything iterable. 10297 _.toArray = function(obj) { 10298 if (!obj) return []; 10299 if (_.isArray(obj)) return slice.call(obj); 10300 if (isArrayLike(obj)) return _.map(obj, _.identity); 10301 return _.values(obj); 10302 }; 10303 10304 // Return the number of elements in an object. 10305 _.size = function(obj) { 10306 if (obj == null) return 0; 10307 return isArrayLike(obj) ? obj.length : _.keys(obj).length; 10308 }; 10309 10310 // Split a collection into two arrays: one whose elements all satisfy the given 10311 // predicate, and one whose elements all do not satisfy the predicate. 10312 _.partition = function(obj, predicate, context) { 10313 predicate = cb(predicate, context); 10314 var pass = [], fail = []; 10315 _.each(obj, function(value, key, obj) { 10316 (predicate(value, key, obj) ? pass : fail).push(value); 10317 }); 10318 return [pass, fail]; 10319 }; 10320 10321 // Array Functions 10322 // --------------- 10323 10324 // Get the first element of an array. Passing **n** will return the first N 10325 // values in the array. Aliased as `head` and `take`. The **guard** check 10326 // allows it to work with `_.map`. 10327 _.first = _.head = _.take = function(array, n, guard) { 10328 if (array == null) return void 0; 10329 if (n == null || guard) return array[0]; 10330 return _.initial(array, array.length - n); 10331 }; 10332 10333 // Returns everything but the last entry of the array. Especially useful on 10334 // the arguments object. Passing **n** will return all the values in 10335 // the array, excluding the last N. 10336 _.initial = function(array, n, guard) { 10337 return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n))); 10338 }; 10339 10340 // Get the last element of an array. Passing **n** will return the last N 10341 // values in the array. 10342 _.last = function(array, n, guard) { 10343 if (array == null) return void 0; 10344 if (n == null || guard) return array[array.length - 1]; 10345 return _.rest(array, Math.max(0, array.length - n)); 10346 }; 10347 10348 // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. 10349 // Especially useful on the arguments object. Passing an **n** will return 10350 // the rest N values in the array. 10351 _.rest = _.tail = _.drop = function(array, n, guard) { 10352 return slice.call(array, n == null || guard ? 1 : n); 10353 }; 10354 10355 // Trim out all falsy values from an array. 10356 _.compact = function(array) { 10357 return _.filter(array, _.identity); 10358 }; 10359 10360 // Internal implementation of a recursive `flatten` function. 10361 var flatten = function(input, shallow, strict, startIndex) { 10362 var output = [], idx = 0; 10363 for (var i = startIndex || 0, length = getLength(input); i < length; i++) { 10364 var value = input[i]; 10365 if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) { 10366 //flatten current level of array or arguments object 10367 if (!shallow) value = flatten(value, shallow, strict); 10368 var j = 0, len = value.length; 10369 output.length += len; 10370 while (j < len) { 10371 output[idx++] = value[j++]; 10372 } 10373 } else if (!strict) { 10374 output[idx++] = value; 10375 } 10376 } 10377 return output; 10378 }; 10379 10380 // Flatten out an array, either recursively (by default), or just one level. 10381 _.flatten = function(array, shallow) { 10382 return flatten(array, shallow, false); 10383 }; 10384 10385 // Return a version of the array that does not contain the specified value(s). 10386 _.without = function(array) { 10387 return _.difference(array, slice.call(arguments, 1)); 10388 }; 10389 10390 // Produce a duplicate-free version of the array. If the array has already 10391 // been sorted, you have the option of using a faster algorithm. 10392 // Aliased as `unique`. 10393 _.uniq = _.unique = function(array, isSorted, iteratee, context) { 10394 if (!_.isBoolean(isSorted)) { 10395 context = iteratee; 10396 iteratee = isSorted; 10397 isSorted = false; 10398 } 10399 if (iteratee != null) iteratee = cb(iteratee, context); 10400 var result = []; 10401 var seen = []; 10402 for (var i = 0, length = getLength(array); i < length; i++) { 10403 var value = array[i], 10404 computed = iteratee ? iteratee(value, i, array) : value; 10405 if (isSorted) { 10406 if (!i || seen !== computed) result.push(value); 10407 seen = computed; 10408 } else if (iteratee) { 10409 if (!_.contains(seen, computed)) { 10410 seen.push(computed); 10411 result.push(value); 10412 } 10413 } else if (!_.contains(result, value)) { 10414 result.push(value); 10415 } 10416 } 10417 return result; 10418 }; 10419 10420 // Produce an array that contains the union: each distinct element from all of 10421 // the passed-in arrays. 10422 _.union = function() { 10423 return _.uniq(flatten(arguments, true, true)); 10424 }; 10425 10426 // Produce an array that contains every item shared between all the 10427 // passed-in arrays. 10428 _.intersection = function(array) { 10429 var result = []; 10430 var argsLength = arguments.length; 10431 for (var i = 0, length = getLength(array); i < length; i++) { 10432 var item = array[i]; 10433 if (_.contains(result, item)) continue; 10434 for (var j = 1; j < argsLength; j++) { 10435 if (!_.contains(arguments[j], item)) break; 10436 } 10437 if (j === argsLength) result.push(item); 10438 } 10439 return result; 10440 }; 10441 10442 // Take the difference between one array and a number of other arrays. 10443 // Only the elements present in just the first array will remain. 10444 _.difference = function(array) { 10445 var rest = flatten(arguments, true, true, 1); 10446 return _.filter(array, function(value){ 10447 return !_.contains(rest, value); 10448 }); 10449 }; 10450 10451 // Zip together multiple lists into a single array -- elements that share 10452 // an index go together. 10453 _.zip = function() { 10454 return _.unzip(arguments); 10455 }; 10456 10457 // Complement of _.zip. Unzip accepts an array of arrays and groups 10458 // each array's elements on shared indices 10459 _.unzip = function(array) { 10460 var length = array && _.max(array, getLength).length || 0; 10461 var result = Array(length); 10462 10463 for (var index = 0; index < length; index++) { 10464 result[index] = _.pluck(array, index); 10465 } 10466 return result; 10467 }; 10468 10469 // Converts lists into objects. Pass either a single array of `[key, value]` 10470 // pairs, or two parallel arrays of the same length -- one of keys, and one of 10471 // the corresponding values. 10472 _.object = function(list, values) { 10473 var result = {}; 10474 for (var i = 0, length = getLength(list); i < length; i++) { 10475 if (values) { 10476 result[list[i]] = values[i]; 10477 } else { 10478 result[list[i][0]] = list[i][1]; 10479 } 10480 } 10481 return result; 10482 }; 10483 10484 // Generator function to create the findIndex and findLastIndex functions 10485 function createPredicateIndexFinder(dir) { 10486 return function(array, predicate, context) { 10487 predicate = cb(predicate, context); 10488 var length = getLength(array); 10489 var index = dir > 0 ? 0 : length - 1; 10490 for (; index >= 0 && index < length; index += dir) { 10491 if (predicate(array[index], index, array)) return index; 10492 } 10493 return -1; 10494 }; 10495 } 10496 10497 // Returns the first index on an array-like that passes a predicate test 10498 _.findIndex = createPredicateIndexFinder(1); 10499 _.findLastIndex = createPredicateIndexFinder(-1); 10500 10501 // Use a comparator function to figure out the smallest index at which 10502 // an object should be inserted so as to maintain order. Uses binary search. 10503 _.sortedIndex = function(array, obj, iteratee, context) { 10504 iteratee = cb(iteratee, context, 1); 10505 var value = iteratee(obj); 10506 var low = 0, high = getLength(array); 10507 while (low < high) { 10508 var mid = Math.floor((low + high) / 2); 10509 if (iteratee(array[mid]) < value) low = mid + 1; else high = mid; 10510 } 10511 return low; 10512 }; 10513 10514 // Generator function to create the indexOf and lastIndexOf functions 10515 function createIndexFinder(dir, predicateFind, sortedIndex) { 10516 return function(array, item, idx) { 10517 var i = 0, length = getLength(array); 10518 if (typeof idx == 'number') { 10519 if (dir > 0) { 10520 i = idx >= 0 ? idx : Math.max(idx + length, i); 10521 } else { 10522 length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1; 10523 } 10524 } else if (sortedIndex && idx && length) { 10525 idx = sortedIndex(array, item); 10526 return array[idx] === item ? idx : -1; 10527 } 10528 if (item !== item) { 10529 idx = predicateFind(slice.call(array, i, length), _.isNaN); 10530 return idx >= 0 ? idx + i : -1; 10531 } 10532 for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) { 10533 if (array[idx] === item) return idx; 10534 } 10535 return -1; 10536 }; 10537 } 10538 10539 // Return the position of the first occurrence of an item in an array, 10540 // or -1 if the item is not included in the array. 10541 // If the array is large and already in sort order, pass `true` 10542 // for **isSorted** to use binary search. 10543 _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex); 10544 _.lastIndexOf = createIndexFinder(-1, _.findLastIndex); 10545 10546 // Generate an integer Array containing an arithmetic progression. A port of 10547 // the native Python `range()` function. See 10548 // [the Python documentation](http://docs.python.org/library/functions.html#range). 10549 _.range = function(start, stop, step) { 10550 if (stop == null) { 10551 stop = start || 0; 10552 start = 0; 10553 } 10554 step = step || 1; 10555 10556 var length = Math.max(Math.ceil((stop - start) / step), 0); 10557 var range = Array(length); 10558 10559 for (var idx = 0; idx < length; idx++, start += step) { 10560 range[idx] = start; 10561 } 10562 10563 return range; 10564 }; 10565 10566 // Function (ahem) Functions 10567 // ------------------ 10568 10569 // Determines whether to execute a function as a constructor 10570 // or a normal function with the provided arguments 10571 var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) { 10572 if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); 10573 var self = baseCreate(sourceFunc.prototype); 10574 var result = sourceFunc.apply(self, args); 10575 if (_.isObject(result)) return result; 10576 return self; 10577 }; 10578 10579 // Create a function bound to a given object (assigning `this`, and arguments, 10580 // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if 10581 // available. 10582 _.bind = function(func, context) { 10583 if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); 10584 if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function'); 10585 var args = slice.call(arguments, 2); 10586 var bound = function() { 10587 return executeBound(func, bound, context, this, args.concat(slice.call(arguments))); 10588 }; 10589 return bound; 10590 }; 10591 10592 // Partially apply a function by creating a version that has had some of its 10593 // arguments pre-filled, without changing its dynamic `this` context. _ acts 10594 // as a placeholder, allowing any combination of arguments to be pre-filled. 10595 _.partial = function(func) { 10596 var boundArgs = slice.call(arguments, 1); 10597 var bound = function() { 10598 var position = 0, length = boundArgs.length; 10599 var args = Array(length); 10600 for (var i = 0; i < length; i++) { 10601 args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i]; 10602 } 10603 while (position < arguments.length) args.push(arguments[position++]); 10604 return executeBound(func, bound, this, this, args); 10605 }; 10606 return bound; 10607 }; 10608 10609 // Bind a number of an object's methods to that object. Remaining arguments 10610 // are the method names to be bound. Useful for ensuring that all callbacks 10611 // defined on an object belong to it. 10612 _.bindAll = function(obj) { 10613 var i, length = arguments.length, key; 10614 if (length <= 1) throw new Error('bindAll must be passed function names'); 10615 for (i = 1; i < length; i++) { 10616 key = arguments[i]; 10617 obj[key] = _.bind(obj[key], obj); 10618 } 10619 return obj; 10620 }; 10621 10622 // Memoize an expensive function by storing its results. 10623 _.memoize = function(func, hasher) { 10624 var memoize = function(key) { 10625 var cache = memoize.cache; 10626 var address = '' + (hasher ? hasher.apply(this, arguments) : key); 10627 if (!_.has(cache, address)) cache[address] = func.apply(this, arguments); 10628 return cache[address]; 10629 }; 10630 memoize.cache = {}; 10631 return memoize; 10632 }; 10633 10634 // Delays a function for the given number of milliseconds, and then calls 10635 // it with the arguments supplied. 10636 _.delay = function(func, wait) { 10637 var args = slice.call(arguments, 2); 10638 return setTimeout(function(){ 10639 return func.apply(null, args); 10640 }, wait); 10641 }; 10642 10643 // Defers a function, scheduling it to run after the current call stack has 10644 // cleared. 10645 _.defer = _.partial(_.delay, _, 1); 10646 10647 // Returns a function, that, when invoked, will only be triggered at most once 10648 // during a given window of time. Normally, the throttled function will run 10649 // as much as it can, without ever going more than once per `wait` duration; 10650 // but if you'd like to disable the execution on the leading edge, pass 10651 // `{leading: false}`. To disable execution on the trailing edge, ditto. 10652 _.throttle = function(func, wait, options) { 10653 var context, args, result; 10654 var timeout = null; 10655 var previous = 0; 10656 if (!options) options = {}; 10657 var later = function() { 10658 previous = options.leading === false ? 0 : _.now(); 10659 timeout = null; 10660 result = func.apply(context, args); 10661 if (!timeout) context = args = null; 10662 }; 10663 return function() { 10664 var now = _.now(); 10665 if (!previous && options.leading === false) previous = now; 10666 var remaining = wait - (now - previous); 10667 context = this; 10668 args = arguments; 10669 if (remaining <= 0 || remaining > wait) { 10670 if (timeout) { 10671 clearTimeout(timeout); 10672 timeout = null; 10673 } 10674 previous = now; 10675 result = func.apply(context, args); 10676 if (!timeout) context = args = null; 10677 } else if (!timeout && options.trailing !== false) { 10678 timeout = setTimeout(later, remaining); 10679 } 10680 return result; 10681 }; 10682 }; 10683 10684 // Returns a function, that, as long as it continues to be invoked, will not 10685 // be triggered. The function will be called after it stops being called for 10686 // N milliseconds. If `immediate` is passed, trigger the function on the 10687 // leading edge, instead of the trailing. 10688 _.debounce = function(func, wait, immediate) { 10689 var timeout, args, context, timestamp, result; 10690 10691 var later = function() { 10692 var last = _.now() - timestamp; 10693 10694 if (last < wait && last >= 0) { 10695 timeout = setTimeout(later, wait - last); 10696 } else { 10697 timeout = null; 10698 if (!immediate) { 10699 result = func.apply(context, args); 10700 if (!timeout) context = args = null; 10701 } 10702 } 10703 }; 10704 10705 return function() { 10706 context = this; 10707 args = arguments; 10708 timestamp = _.now(); 10709 var callNow = immediate && !timeout; 10710 if (!timeout) timeout = setTimeout(later, wait); 10711 if (callNow) { 10712 result = func.apply(context, args); 10713 context = args = null; 10714 } 10715 10716 return result; 10717 }; 10718 }; 10719 10720 // Returns the first function passed as an argument to the second, 10721 // allowing you to adjust arguments, run code before and after, and 10722 // conditionally execute the original function. 10723 _.wrap = function(func, wrapper) { 10724 return _.partial(wrapper, func); 10725 }; 10726 10727 // Returns a negated version of the passed-in predicate. 10728 _.negate = function(predicate) { 10729 return function() { 10730 return !predicate.apply(this, arguments); 10731 }; 10732 }; 10733 10734 // Returns a function that is the composition of a list of functions, each 10735 // consuming the return value of the function that follows. 10736 _.compose = function() { 10737 var args = arguments; 10738 var start = args.length - 1; 10739 return function() { 10740 var i = start; 10741 var result = args[start].apply(this, arguments); 10742 while (i--) result = args[i].call(this, result); 10743 return result; 10744 }; 10745 }; 10746 10747 // Returns a function that will only be executed on and after the Nth call. 10748 _.after = function(times, func) { 10749 return function() { 10750 if (--times < 1) { 10751 return func.apply(this, arguments); 10752 } 10753 }; 10754 }; 10755 10756 // Returns a function that will only be executed up to (but not including) the Nth call. 10757 _.before = function(times, func) { 10758 var memo; 10759 return function() { 10760 if (--times > 0) { 10761 memo = func.apply(this, arguments); 10762 } 10763 if (times <= 1) func = null; 10764 return memo; 10765 }; 10766 }; 10767 10768 // Returns a function that will be executed at most one time, no matter how 10769 // often you call it. Useful for lazy initialization. 10770 _.once = _.partial(_.before, 2); 10771 10772 // Object Functions 10773 // ---------------- 10774 10775 // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed. 10776 var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString'); 10777 var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString', 10778 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; 10779 10780 function collectNonEnumProps(obj, keys) { 10781 var nonEnumIdx = nonEnumerableProps.length; 10782 var constructor = obj.constructor; 10783 var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto; 10784 10785 // Constructor is a special case. 10786 var prop = 'constructor'; 10787 if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop); 10788 10789 while (nonEnumIdx--) { 10790 prop = nonEnumerableProps[nonEnumIdx]; 10791 if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) { 10792 keys.push(prop); 10793 } 10794 } 10795 } 10796 10797 // Retrieve the names of an object's own properties. 10798 // Delegates to **ECMAScript 5**'s native `Object.keys` 10799 _.keys = function(obj) { 10800 if (!_.isObject(obj)) return []; 10801 if (nativeKeys) return nativeKeys(obj); 10802 var keys = []; 10803 for (var key in obj) if (_.has(obj, key)) keys.push(key); 10804 // Ahem, IE < 9. 10805 if (hasEnumBug) collectNonEnumProps(obj, keys); 10806 return keys; 10807 }; 10808 10809 // Retrieve all the property names of an object. 10810 _.allKeys = function(obj) { 10811 if (!_.isObject(obj)) return []; 10812 var keys = []; 10813 for (var key in obj) keys.push(key); 10814 // Ahem, IE < 9. 10815 if (hasEnumBug) collectNonEnumProps(obj, keys); 10816 return keys; 10817 }; 10818 10819 // Retrieve the values of an object's properties. 10820 _.values = function(obj) { 10821 var keys = _.keys(obj); 10822 var length = keys.length; 10823 var values = Array(length); 10824 for (var i = 0; i < length; i++) { 10825 values[i] = obj[keys[i]]; 10826 } 10827 return values; 10828 }; 10829 10830 // Returns the results of applying the iteratee to each element of the object 10831 // In contrast to _.map it returns an object 10832 _.mapObject = function(obj, iteratee, context) { 10833 iteratee = cb(iteratee, context); 10834 var keys = _.keys(obj), 10835 length = keys.length, 10836 results = {}, 10837 currentKey; 10838 for (var index = 0; index < length; index++) { 10839 currentKey = keys[index]; 10840 results[currentKey] = iteratee(obj[currentKey], currentKey, obj); 10841 } 10842 return results; 10843 }; 10844 10845 // Convert an object into a list of `[key, value]` pairs. 10846 _.pairs = function(obj) { 10847 var keys = _.keys(obj); 10848 var length = keys.length; 10849 var pairs = Array(length); 10850 for (var i = 0; i < length; i++) { 10851 pairs[i] = [keys[i], obj[keys[i]]]; 10852 } 10853 return pairs; 10854 }; 10855 10856 // Invert the keys and values of an object. The values must be serializable. 10857 _.invert = function(obj) { 10858 var result = {}; 10859 var keys = _.keys(obj); 10860 for (var i = 0, length = keys.length; i < length; i++) { 10861 result[obj[keys[i]]] = keys[i]; 10862 } 10863 return result; 10864 }; 10865 10866 // Return a sorted list of the function names available on the object. 10867 // Aliased as `methods` 10868 _.functions = _.methods = function(obj) { 10869 var names = []; 10870 for (var key in obj) { 10871 if (_.isFunction(obj[key])) names.push(key); 10872 } 10873 return names.sort(); 10874 }; 10875 10876 // Extend a given object with all the properties in passed-in object(s). 10877 _.extend = createAssigner(_.allKeys); 10878 10879 // Assigns a given object with all the own properties in the passed-in object(s) 10880 // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) 10881 _.extendOwn = _.assign = createAssigner(_.keys); 10882 10883 // Returns the first key on an object that passes a predicate test 10884 _.findKey = function(obj, predicate, context) { 10885 predicate = cb(predicate, context); 10886 var keys = _.keys(obj), key; 10887 for (var i = 0, length = keys.length; i < length; i++) { 10888 key = keys[i]; 10889 if (predicate(obj[key], key, obj)) return key; 10890 } 10891 }; 10892 10893 // Return a copy of the object only containing the whitelisted properties. 10894 _.pick = function(object, oiteratee, context) { 10895 var result = {}, obj = object, iteratee, keys; 10896 if (obj == null) return result; 10897 if (_.isFunction(oiteratee)) { 10898 keys = _.allKeys(obj); 10899 iteratee = optimizeCb(oiteratee, context); 10900 } else { 10901 keys = flatten(arguments, false, false, 1); 10902 iteratee = function(value, key, obj) { return key in obj; }; 10903 obj = Object(obj); 10904 } 10905 for (var i = 0, length = keys.length; i < length; i++) { 10906 var key = keys[i]; 10907 var value = obj[key]; 10908 if (iteratee(value, key, obj)) result[key] = value; 10909 } 10910 return result; 10911 }; 10912 10913 // Return a copy of the object without the blacklisted properties. 10914 _.omit = function(obj, iteratee, context) { 10915 if (_.isFunction(iteratee)) { 10916 iteratee = _.negate(iteratee); 10917 } else { 10918 var keys = _.map(flatten(arguments, false, false, 1), String); 10919 iteratee = function(value, key) { 10920 return !_.contains(keys, key); 10921 }; 10922 } 10923 return _.pick(obj, iteratee, context); 10924 }; 10925 10926 // Fill in a given object with default properties. 10927 _.defaults = createAssigner(_.allKeys, true); 10928 10929 // Creates an object that inherits from the given prototype object. 10930 // If additional properties are provided then they will be added to the 10931 // created object. 10932 _.create = function(prototype, props) { 10933 var result = baseCreate(prototype); 10934 if (props) _.extendOwn(result, props); 10935 return result; 10936 }; 10937 10938 // Create a (shallow-cloned) duplicate of an object. 10939 _.clone = function(obj) { 10940 if (!_.isObject(obj)) return obj; 10941 return _.isArray(obj) ? obj.slice() : _.extend({}, obj); 10942 }; 10943 10944 // Invokes interceptor with the obj, and then returns obj. 10945 // The primary purpose of this method is to "tap into" a method chain, in 10946 // order to perform operations on intermediate results within the chain. 10947 _.tap = function(obj, interceptor) { 10948 interceptor(obj); 10949 return obj; 10950 }; 10951 10952 // Returns whether an object has a given set of `key:value` pairs. 10953 _.isMatch = function(object, attrs) { 10954 var keys = _.keys(attrs), length = keys.length; 10955 if (object == null) return !length; 10956 var obj = Object(object); 10957 for (var i = 0; i < length; i++) { 10958 var key = keys[i]; 10959 if (attrs[key] !== obj[key] || !(key in obj)) return false; 10960 } 10961 return true; 10962 }; 10963 10964 10965 // Internal recursive comparison function for `isEqual`. 10966 var eq = function(a, b, aStack, bStack) { 10967 // Identical objects are equal. `0 === -0`, but they aren't identical. 10968 // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). 10969 if (a === b) return a !== 0 || 1 / a === 1 / b; 10970 // A strict comparison is necessary because `null == undefined`. 10971 if (a == null || b == null) return a === b; 10972 // Unwrap any wrapped objects. 10973 if (a instanceof _) a = a._wrapped; 10974 if (b instanceof _) b = b._wrapped; 10975 // Compare `[[Class]]` names. 10976 var className = toString.call(a); 10977 if (className !== toString.call(b)) return false; 10978 switch (className) { 10979 // Strings, numbers, regular expressions, dates, and booleans are compared by value. 10980 case '[object RegExp]': 10981 // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') 10982 case '[object String]': 10983 // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is 10984 // equivalent to `new String("5")`. 10985 return '' + a === '' + b; 10986 case '[object Number]': 10987 // `NaN`s are equivalent, but non-reflexive. 10988 // Object(NaN) is equivalent to NaN 10989 if (+a !== +a) return +b !== +b; 10990 // An `egal` comparison is performed for other numeric values. 10991 return +a === 0 ? 1 / +a === 1 / b : +a === +b; 10992 case '[object Date]': 10993 case '[object Boolean]': 10994 // Coerce dates and booleans to numeric primitive values. Dates are compared by their 10995 // millisecond representations. Note that invalid dates with millisecond representations 10996 // of `NaN` are not equivalent. 10997 return +a === +b; 10998 } 10999 11000 var areArrays = className === '[object Array]'; 11001 if (!areArrays) { 11002 if (typeof a != 'object' || typeof b != 'object') return false; 11003 11004 // Objects with different constructors are not equivalent, but `Object`s or `Array`s 11005 // from different frames are. 11006 var aCtor = a.constructor, bCtor = b.constructor; 11007 if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor && 11008 _.isFunction(bCtor) && bCtor instanceof bCtor) 11009 && ('constructor' in a && 'constructor' in b)) { 11010 return false; 11011 } 11012 } 11013 // Assume equality for cyclic structures. The algorithm for detecting cyclic 11014 // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. 11015 11016 // Initializing stack of traversed objects. 11017 // It's done here since we only need them for objects and arrays comparison. 11018 aStack = aStack || []; 11019 bStack = bStack || []; 11020 var length = aStack.length; 11021 while (length--) { 11022 // Linear search. Performance is inversely proportional to the number of 11023 // unique nested structures. 11024 if (aStack[length] === a) return bStack[length] === b; 11025 } 11026 11027 // Add the first object to the stack of traversed objects. 11028 aStack.push(a); 11029 bStack.push(b); 11030 11031 // Recursively compare objects and arrays. 11032 if (areArrays) { 11033 // Compare array lengths to determine if a deep comparison is necessary. 11034 length = a.length; 11035 if (length !== b.length) return false; 11036 // Deep compare the contents, ignoring non-numeric properties. 11037 while (length--) { 11038 if (!eq(a[length], b[length], aStack, bStack)) return false; 11039 } 11040 } else { 11041 // Deep compare objects. 11042 var keys = _.keys(a), key; 11043 length = keys.length; 11044 // Ensure that both objects contain the same number of properties before comparing deep equality. 11045 if (_.keys(b).length !== length) return false; 11046 while (length--) { 11047 // Deep compare each member 11048 key = keys[length]; 11049 if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false; 11050 } 11051 } 11052 // Remove the first object from the stack of traversed objects. 11053 aStack.pop(); 11054 bStack.pop(); 11055 return true; 11056 }; 11057 11058 // Perform a deep comparison to check if two objects are equal. 11059 _.isEqual = function(a, b) { 11060 return eq(a, b); 11061 }; 11062 11063 // Is a given array, string, or object empty? 11064 // An "empty" object has no enumerable own-properties. 11065 _.isEmpty = function(obj) { 11066 if (obj == null) return true; 11067 if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0; 11068 return _.keys(obj).length === 0; 11069 }; 11070 11071 // Is a given value a DOM element? 11072 _.isElement = function(obj) { 11073 return !!(obj && obj.nodeType === 1); 11074 }; 11075 11076 // Is a given value an array? 11077 // Delegates to ECMA5's native Array.isArray 11078 _.isArray = nativeIsArray || function(obj) { 11079 return toString.call(obj) === '[object Array]'; 11080 }; 11081 11082 // Is a given variable an object? 11083 _.isObject = function(obj) { 11084 var type = typeof obj; 11085 return type === 'function' || type === 'object' && !!obj; 11086 }; 11087 11088 // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError. 11089 _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) { 11090 _['is' + name] = function(obj) { 11091 return toString.call(obj) === '[object ' + name + ']'; 11092 }; 11093 }); 11094 11095 // Define a fallback version of the method in browsers (ahem, IE < 9), where 11096 // there isn't any inspectable "Arguments" type. 11097 if (!_.isArguments(arguments)) { 11098 _.isArguments = function(obj) { 11099 return _.has(obj, 'callee'); 11100 }; 11101 } 11102 11103 // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8, 11104 // IE 11 (#1621), and in Safari 8 (#1929). 11105 if (typeof /./ != 'function' && typeof Int8Array != 'object') { 11106 _.isFunction = function(obj) { 11107 return typeof obj == 'function' || false; 11108 }; 11109 } 11110 11111 // Is a given object a finite number? 11112 _.isFinite = function(obj) { 11113 return isFinite(obj) && !isNaN(parseFloat(obj)); 11114 }; 11115 11116 // Is the given value `NaN`? (NaN is the only number which does not equal itself). 11117 _.isNaN = function(obj) { 11118 return _.isNumber(obj) && obj !== +obj; 11119 }; 11120 11121 // Is a given value a boolean? 11122 _.isBoolean = function(obj) { 11123 return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; 11124 }; 11125 11126 // Is a given value equal to null? 11127 _.isNull = function(obj) { 11128 return obj === null; 11129 }; 11130 11131 // Is a given variable undefined? 11132 _.isUndefined = function(obj) { 11133 return obj === void 0; 11134 }; 11135 11136 // Shortcut function for checking if an object has a given property directly 11137 // on itself (in other words, not on a prototype). 11138 _.has = function(obj, key) { 11139 return obj != null && hasOwnProperty.call(obj, key); 11140 }; 11141 11142 // Utility Functions 11143 // ----------------- 11144 11145 // Run Underscore.js in *noConflict* mode, returning the `_` variable to its 11146 // previous owner. Returns a reference to the Underscore object. 11147 _.noConflict = function() { 11148 root._ = previousUnderscore; 11149 return this; 11150 }; 11151 11152 // Keep the identity function around for default iteratees. 11153 _.identity = function(value) { 11154 return value; 11155 }; 11156 11157 // Predicate-generating functions. Often useful outside of Underscore. 11158 _.constant = function(value) { 11159 return function() { 11160 return value; 11161 }; 11162 }; 11163 11164 _.noop = function(){}; 11165 11166 _.property = property; 11167 11168 // Generates a function for a given object that returns a given property. 11169 _.propertyOf = function(obj) { 11170 return obj == null ? function(){} : function(key) { 11171 return obj[key]; 11172 }; 11173 }; 11174 11175 // Returns a predicate for checking whether an object has a given set of 11176 // `key:value` pairs. 11177 _.matcher = _.matches = function(attrs) { 11178 attrs = _.extendOwn({}, attrs); 11179 return function(obj) { 11180 return _.isMatch(obj, attrs); 11181 }; 11182 }; 11183 11184 // Run a function **n** times. 11185 _.times = function(n, iteratee, context) { 11186 var accum = Array(Math.max(0, n)); 11187 iteratee = optimizeCb(iteratee, context, 1); 11188 for (var i = 0; i < n; i++) accum[i] = iteratee(i); 11189 return accum; 11190 }; 11191 11192 // Return a random integer between min and max (inclusive). 11193 _.random = function(min, max) { 11194 if (max == null) { 11195 max = min; 11196 min = 0; 11197 } 11198 return min + Math.floor(Math.random() * (max - min + 1)); 11199 }; 11200 11201 // A (possibly faster) way to get the current timestamp as an integer. 11202 _.now = Date.now || function() { 11203 return new Date().getTime(); 11204 }; 11205 11206 // List of HTML entities for escaping. 11207 var escapeMap = { 11208 '&': '&', 11209 '<': '<', 11210 '>': '>', 11211 '"': '"', 11212 "'": ''', 11213 '`': '`' 11214 }; 11215 var unescapeMap = _.invert(escapeMap); 11216 11217 // Functions for escaping and unescaping strings to/from HTML interpolation. 11218 var createEscaper = function(map) { 11219 var escaper = function(match) { 11220 return map[match]; 11221 }; 11222 // Regexes for identifying a key that needs to be escaped 11223 var source = '(?:' + _.keys(map).join('|') + ')'; 11224 var testRegexp = RegExp(source); 11225 var replaceRegexp = RegExp(source, 'g'); 11226 return function(string) { 11227 string = string == null ? '' : '' + string; 11228 return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string; 11229 }; 11230 }; 11231 _.escape = createEscaper(escapeMap); 11232 _.unescape = createEscaper(unescapeMap); 11233 11234 // If the value of the named `property` is a function then invoke it with the 11235 // `object` as context; otherwise, return it. 11236 _.result = function(object, property, fallback) { 11237 var value = object == null ? void 0 : object[property]; 11238 if (value === void 0) { 11239 value = fallback; 11240 } 11241 return _.isFunction(value) ? value.call(object) : value; 11242 }; 11243 11244 // Generate a unique integer id (unique within the entire client session). 11245 // Useful for temporary DOM ids. 11246 var idCounter = 0; 11247 _.uniqueId = function(prefix) { 11248 var id = ++idCounter + ''; 11249 return prefix ? prefix + id : id; 11250 }; 11251 11252 // By default, Underscore uses ERB-style template delimiters, change the 11253 // following template settings to use alternative delimiters. 11254 _.templateSettings = { 11255 evaluate : /<%([\s\S]+?)%>/g, 11256 interpolate : /<%=([\s\S]+?)%>/g, 11257 escape : /<%-([\s\S]+?)%>/g 11258 }; 11259 11260 // When customizing `templateSettings`, if you don't want to define an 11261 // interpolation, evaluation or escaping regex, we need one that is 11262 // guaranteed not to match. 11263 var noMatch = /(.)^/; 11264 11265 // Certain characters need to be escaped so that they can be put into a 11266 // string literal. 11267 var escapes = { 11268 "'": "'", 11269 '\\': '\\', 11270 '\r': 'r', 11271 '\n': 'n', 11272 '\u2028': 'u2028', 11273 '\u2029': 'u2029' 11274 }; 11275 11276 var escaper = /\\|'|\r|\n|\u2028|\u2029/g; 11277 11278 var escapeChar = function(match) { 11279 return '\\' + escapes[match]; 11280 }; 11281 11282 // JavaScript micro-templating, similar to John Resig's implementation. 11283 // Underscore templating handles arbitrary delimiters, preserves whitespace, 11284 // and correctly escapes quotes within interpolated code. 11285 // NB: `oldSettings` only exists for backwards compatibility. 11286 _.template = function(text, settings, oldSettings) { 11287 if (!settings && oldSettings) settings = oldSettings; 11288 settings = _.defaults({}, settings, _.templateSettings); 11289 11290 // Combine delimiters into one regular expression via alternation. 11291 var matcher = RegExp([ 11292 (settings.escape || noMatch).source, 11293 (settings.interpolate || noMatch).source, 11294 (settings.evaluate || noMatch).source 11295 ].join('|') + '|$', 'g'); 11296 11297 // Compile the template source, escaping string literals appropriately. 11298 var index = 0; 11299 var source = "__p+='"; 11300 text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { 11301 source += text.slice(index, offset).replace(escaper, escapeChar); 11302 index = offset + match.length; 11303 11304 if (escape) { 11305 source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; 11306 } else if (interpolate) { 11307 source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; 11308 } else if (evaluate) { 11309 source += "';\n" + evaluate + "\n__p+='"; 11310 } 11311 11312 // Adobe VMs need the match returned to produce the correct offest. 11313 return match; 11314 }); 11315 source += "';\n"; 11316 11317 // If a variable is not specified, place data values in local scope. 11318 if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; 11319 11320 source = "var __t,__p='',__j=Array.prototype.join," + 11321 "print=function(){__p+=__j.call(arguments,'');};\n" + 11322 source + 'return __p;\n'; 11323 11324 try { 11325 var render = new Function(settings.variable || 'obj', '_', source); 11326 } catch (e) { 11327 e.source = source; 11328 throw e; 11329 } 11330 11331 var template = function(data) { 11332 return render.call(this, data, _); 11333 }; 11334 11335 // Provide the compiled source as a convenience for precompilation. 11336 var argument = settings.variable || 'obj'; 11337 template.source = 'function(' + argument + '){\n' + source + '}'; 11338 11339 return template; 11340 }; 11341 11342 // Add a "chain" function. Start chaining a wrapped Underscore object. 11343 _.chain = function(obj) { 11344 var instance = _(obj); 11345 instance._chain = true; 11346 return instance; 11347 }; 11348 11349 // OOP 11350 // --------------- 11351 // If Underscore is called as a function, it returns a wrapped object that 11352 // can be used OO-style. This wrapper holds altered versions of all the 11353 // underscore functions. Wrapped objects may be chained. 11354 11355 // Helper function to continue chaining intermediate results. 11356 var result = function(instance, obj) { 11357 return instance._chain ? _(obj).chain() : obj; 11358 }; 11359 11360 // Add your own custom functions to the Underscore object. 11361 _.mixin = function(obj) { 11362 _.each(_.functions(obj), function(name) { 11363 var func = _[name] = obj[name]; 11364 _.prototype[name] = function() { 11365 var args = [this._wrapped]; 11366 push.apply(args, arguments); 11367 return result(this, func.apply(_, args)); 11368 }; 11369 }); 11370 }; 11371 11372 // Add all of the Underscore functions to the wrapper object. 11373 _.mixin(_); 11374 11375 // Add all mutator Array functions to the wrapper. 11376 _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { 11377 var method = ArrayProto[name]; 11378 _.prototype[name] = function() { 11379 var obj = this._wrapped; 11380 method.apply(obj, arguments); 11381 if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0]; 11382 return result(this, obj); 11383 }; 11384 }); 11385 11386 // Add all accessor Array functions to the wrapper. 11387 _.each(['concat', 'join', 'slice'], function(name) { 11388 var method = ArrayProto[name]; 11389 _.prototype[name] = function() { 11390 return result(this, method.apply(this._wrapped, arguments)); 11391 }; 11392 }); 11393 11394 // Extracts the result from a wrapped and chained object. 11395 _.prototype.value = function() { 11396 return this._wrapped; 11397 }; 11398 11399 // Provide unwrapping proxy for some methods used in engine operations 11400 // such as arithmetic and JSON stringification. 11401 _.prototype.valueOf = _.prototype.toJSON = _.prototype.value; 11402 11403 _.prototype.toString = function() { 11404 return '' + this._wrapped; 11405 }; 11406 11407 // AMD registration happens at the end for compatibility with AMD loaders 11408 // that may not enforce next-turn semantics on modules. Even though general 11409 // practice for AMD registration is to be anonymous, underscore registers 11410 // as a named module because, like jQuery, it is a base library that is 11411 // popular enough to be bundled in a third party lib, but not be part of 11412 // an AMD load request. Those cases could generate an error when an 11413 // anonymous define() is called outside of a loader request. 11414 if (typeof define === 'function' && define.amd) { 11415 define('underscore', [], function() { 11416 return _; 11417 }); 11418 } 11419}.call(this)); 11420 11421},{}],
1142154:[function(require,module,exports){ 11422/*! VelocityJS.org (1.5.0). (C) 2014 Julian Shapiro. MIT @license: en.wikipedia.org/wiki/MIT_License */ 11423 11424/************************* 11425 Velocity jQuery Shim 11426 *************************/ 11427
vendor: 195,945 bytes, lines 11428-16057
11428/*! VelocityJS.org jQuery Shim (1.0.1). (C) 2014 The jQuery Foundation. MIT @license: en.wikipedia.org/wiki/MIT_License. */ 11429 11430/* This file contains the jQuery functions that Velocity relies on, thereby removing Velocity's dependency on a full copy of jQuery, and allowing it to work in any environment. */ 11431/* These shimmed functions are only used if jQuery isn't present. If both this shim and jQuery are loaded, Velocity defaults to jQuery proper. */ 11432/* Browser support: Using this shim instead of jQuery proper removes support for IE8. */ 11433 11434(function(window) { 11435 "use strict"; 11436 /*************** 11437 Setup 11438 ***************/ 11439 11440 /* If jQuery is already loaded, there's no point in loading this shim. */ 11441 if (window.jQuery) { 11442 return; 11443 } 11444 11445 /* jQuery base. */ 11446 var $ = function(selector, context) { 11447 return new $.fn.init(selector, context); 11448 }; 11449 11450 /******************** 11451 Private Methods 11452 ********************/ 11453 11454 /* jQuery */ 11455 $.isWindow = function(obj) { 11456 /* jshint eqeqeq: false */ 11457 return obj && obj === obj.window; 11458 }; 11459 11460 /* jQuery */ 11461 $.type = function(obj) { 11462 if (!obj) { 11463 return obj + ""; 11464 } 11465 11466 return typeof obj === "object" || typeof obj === "function" ? 11467 class2type[toString.call(obj)] || "object" : 11468 typeof obj; 11469 }; 11470 11471 /* jQuery */ 11472 $.isArray = Array.isArray || function(obj) { 11473 return $.type(obj) === "array"; 11474 }; 11475 11476 /* jQuery */ 11477 function isArraylike(obj) { 11478 var length = obj.length, 11479 type = $.type(obj); 11480 11481 if (type === "function" || $.isWindow(obj)) { 11482 return false; 11483 } 11484 11485 if (obj.nodeType === 1 && length) { 11486 return true; 11487 } 11488 11489 return type === "array" || length === 0 || typeof length === "number" && length > 0 && (length - 1) in obj; 11490 } 11491 11492 /*************** 11493 $ Methods 11494 ***************/ 11495 11496 /* jQuery: Support removed for IE<9. */ 11497 $.isPlainObject = function(obj) { 11498 var key; 11499 11500 if (!obj || $.type(obj) !== "object" || obj.nodeType || $.isWindow(obj)) { 11501 return false; 11502 } 11503 11504 try { 11505 if (obj.constructor && 11506 !hasOwn.call(obj, "constructor") && 11507 !hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) { 11508 return false; 11509 } 11510 } catch (e) { 11511 return false; 11512 } 11513 11514 for (key in obj) { 11515 } 11516 11517 return key === undefined || hasOwn.call(obj, key); 11518 }; 11519 11520 /* jQuery */ 11521 $.each = function(obj, callback, args) { 11522 var value, 11523 i = 0, 11524 length = obj.length, 11525 isArray = isArraylike(obj); 11526 11527 if (args) { 11528 if (isArray) { 11529 for (; i < length; i++) { 11530 value = callback.apply(obj[i], args); 11531 11532 if (value === false) { 11533 break; 11534 } 11535 } 11536 } else { 11537 for (i in obj) { 11538 if (!obj.hasOwnProperty(i)) { 11539 continue; 11540 } 11541 value = callback.apply(obj[i], args); 11542 11543 if (value === false) { 11544 break; 11545 } 11546 } 11547 } 11548 11549 } else { 11550 if (isArray) { 11551 for (; i < length; i++) { 11552 value = callback.call(obj[i], i, obj[i]); 11553 11554 if (value === false) { 11555 break; 11556 } 11557 } 11558 } else { 11559 for (i in obj) { 11560 if (!obj.hasOwnProperty(i)) { 11561 continue; 11562 } 11563 value = callback.call(obj[i], i, obj[i]); 11564 11565 if (value === false) { 11566 break; 11567 } 11568 } 11569 } 11570 } 11571 11572 return obj; 11573 }; 11574 11575 /* Custom */ 11576 $.data = function(node, key, value) { 11577 /* $.getData() */ 11578 if (value === undefined) { 11579 var getId = node[$.expando], 11580 store = getId && cache[getId]; 11581 11582 if (key === undefined) { 11583 return store; 11584 } else if (store) { 11585 if (key in store) { 11586 return store[key]; 11587 } 11588 } 11589 /* $.setData() */ 11590 } else if (key !== undefined) { 11591 var setId = node[$.expando] || (node[$.expando] = ++$.uuid); 11592 11593 cache[setId] = cache[setId] || {}; 11594 cache[setId][key] = value; 11595 11596 return value; 11597 } 11598 }; 11599 11600 /* Custom */ 11601 $.removeData = function(node, keys) { 11602 var id = node[$.expando], 11603 store = id && cache[id]; 11604 11605 if (store) { 11606 // Cleanup the entire store if no keys are provided. 11607 if (!keys) { 11608 delete cache[id]; 11609 } else { 11610 $.each(keys, function(_, key) { 11611 delete store[key]; 11612 }); 11613 } 11614 } 11615 }; 11616 11617 /* jQuery */ 11618 $.extend = function() { 11619 var src, copyIsArray, copy, name, options, clone, 11620 target = arguments[0] || {}, 11621 i = 1, 11622 length = arguments.length, 11623 deep = false; 11624 11625 if (typeof target === "boolean") { 11626 deep = target; 11627 11628 target = arguments[i] || {}; 11629 i++; 11630 } 11631 11632 if (typeof target !== "object" && $.type(target) !== "function") { 11633 target = {}; 11634 } 11635 11636 if (i === length) { 11637 target = this; 11638 i--; 11639 } 11640 11641 for (; i < length; i++) { 11642 if ((options = arguments[i])) { 11643 for (name in options) { 11644 if (!options.hasOwnProperty(name)) { 11645 continue; 11646 } 11647 src = target[name]; 11648 copy = options[name]; 11649 11650 if (target === copy) { 11651 continue; 11652 } 11653 11654 if (deep && copy && ($.isPlainObject(copy) || (copyIsArray = $.isArray(copy)))) { 11655 if (copyIsArray) { 11656 copyIsArray = false; 11657 clone = src && $.isArray(src) ? src : []; 11658 11659 } else { 11660 clone = src && $.isPlainObject(src) ? src : {}; 11661 } 11662 11663 target[name] = $.extend(deep, clone, copy); 11664 11665 } else if (copy !== undefined) { 11666 target[name] = copy; 11667 } 11668 } 11669 } 11670 } 11671 11672 return target; 11673 }; 11674 11675 /* jQuery 1.4.3 */ 11676 $.queue = function(elem, type, data) { 11677 function $makeArray(arr, results) { 11678 var ret = results || []; 11679 11680 if (arr) { 11681 if (isArraylike(Object(arr))) { 11682 /* $.merge */ 11683 (function(first, second) { 11684 var len = +second.length, 11685 j = 0, 11686 i = first.length; 11687 11688 while (j < len) { 11689 first[i++] = second[j++]; 11690 } 11691 11692 if (len !== len) { 11693 while (second[j] !== undefined) { 11694 first[i++] = second[j++]; 11695 } 11696 } 11697 11698 first.length = i; 11699 11700 return first; 11701 })(ret, typeof arr === "string" ? [arr] : arr); 11702 } else { 11703 [].push.call(ret, arr); 11704 } 11705 } 11706 11707 return ret; 11708 } 11709 11710 if (!elem) { 11711 return; 11712 } 11713 11714 type = (type || "fx") + "queue"; 11715 11716 var q = $.data(elem, type); 11717 11718 if (!data) { 11719 return q || []; 11720 } 11721 11722 if (!q || $.isArray(data)) { 11723 q = $.data(elem, type, $makeArray(data)); 11724 } else { 11725 q.push(data); 11726 } 11727 11728 return q; 11729 }; 11730 11731 /* jQuery 1.4.3 */ 11732 $.dequeue = function(elems, type) { 11733 /* Custom: Embed element iteration. */ 11734 $.each(elems.nodeType ? [elems] : elems, function(i, elem) { 11735 type = type || "fx"; 11736 11737 var queue = $.queue(elem, type), 11738 fn = queue.shift(); 11739 11740 if (fn === "inprogress") { 11741 fn = queue.shift(); 11742 } 11743 11744 if (fn) { 11745 if (type === "fx") { 11746 queue.unshift("inprogress"); 11747 } 11748 11749 fn.call(elem, function() { 11750 $.dequeue(elem, type); 11751 }); 11752 } 11753 }); 11754 }; 11755 11756 /****************** 11757 $.fn Methods 11758 ******************/ 11759 11760 /* jQuery */ 11761 $.fn = $.prototype = { 11762 init: function(selector) { 11763 /* Just return the element wrapped inside an array; don't proceed with the actual jQuery node wrapping process. */ 11764 if (selector.nodeType) { 11765 this[0] = selector; 11766 11767 return this; 11768 } else { 11769 throw new Error("Not a DOM node."); 11770 } 11771 }, 11772 offset: function() { 11773 /* jQuery altered code: Dropped disconnected DOM node checking. */ 11774 var box = this[0].getBoundingClientRect ? this[0].getBoundingClientRect() : {top: 0, left: 0}; 11775 11776 return { 11777 top: box.top + (window.pageYOffset || document.scrollTop || 0) - (document.clientTop || 0), 11778 left: box.left + (window.pageXOffset || document.scrollLeft || 0) - (document.clientLeft || 0) 11779 }; 11780 }, 11781 position: function() { 11782 /* jQuery */ 11783 function offsetParentFn(elem) { 11784 var offsetParent = elem.offsetParent; 11785 11786 while (offsetParent && (offsetParent.nodeName.toLowerCase() !== "html" && offsetParent.style && offsetParent.style.position.toLowerCase() === "static")) { 11787 offsetParent = offsetParent.offsetParent; 11788 } 11789 11790 return offsetParent || document; 11791 } 11792 11793 /* Zepto */ 11794 var elem = this[0], 11795 offsetParent = offsetParentFn(elem), 11796 offset = this.offset(), 11797 parentOffset = /^(?:body|html)$/i.test(offsetParent.nodeName) ? {top: 0, left: 0} : $(offsetParent).offset(); 11798 11799 offset.top -= parseFloat(elem.style.marginTop) || 0; 11800 offset.left -= parseFloat(elem.style.marginLeft) || 0; 11801 11802 if (offsetParent.style) { 11803 parentOffset.top += parseFloat(offsetParent.style.borderTopWidth) || 0; 11804 parentOffset.left += parseFloat(offsetParent.style.borderLeftWidth) || 0; 11805 } 11806 11807 return { 11808 top: offset.top - parentOffset.top, 11809 left: offset.left - parentOffset.left 11810 }; 11811 } 11812 }; 11813 11814 /********************** 11815 Private Variables 11816 **********************/ 11817 11818 /* For $.data() */ 11819 var cache = {}; 11820 $.expando = "velocity" + (new Date().getTime()); 11821 $.uuid = 0; 11822 11823 /* For $.queue() */ 11824 var class2type = {}, 11825 hasOwn = class2type.hasOwnProperty, 11826 toString = class2type.toString; 11827 11828 var types = "Boolean Number String Function Array Date RegExp Object Error".split(" "); 11829 for (var i = 0; i < types.length; i++) { 11830 class2type["[object " + types[i] + "]"] = types[i].toLowerCase(); 11831 } 11832 11833 /* Makes $(node) possible, without having to call init. */ 11834 $.fn.init.prototype = $.fn; 11835 11836 /* Globalize Velocity onto the window, and assign its Utilities property. */ 11837 window.Velocity = {Utilities: $}; 11838})(window); 11839 11840/****************** 11841 Velocity.js 11842 ******************/ 11843 11844(function(factory) { 11845 "use strict"; 11846 /* CommonJS module. */ 11847 if (typeof module === "object" && typeof module.exports === "object") { 11848 module.exports = factory(); 11849 /* AMD module. */ 11850 } else if (typeof define === "function" && define.amd) { 11851 define(factory); 11852 /* Browser globals. */ 11853 } else { 11854 factory(); 11855 } 11856}(function() { 11857 "use strict"; 11858 return function(global, window, document, undefined) { 11859 11860 /*************** 11861 Summary 11862 ***************/ 11863 11864 /* 11865 - CSS: CSS stack that works independently from the rest of Velocity. 11866 - animate(): Core animation method that iterates over the targeted elements and queues the incoming call onto each element individually. 11867 - Pre-Queueing: Prepare the element for animation by instantiating its data cache and processing the call's options. 11868 - Queueing: The logic that runs once the call has reached its point of execution in the element's $.queue() stack. 11869 Most logic is placed here to avoid risking it becoming stale (if the element's properties have changed). 11870 - Pushing: Consolidation of the tween data followed by its push onto the global in-progress calls container. 11871 - tick(): The single requestAnimationFrame loop responsible for tweening all in-progress calls. 11872 - completeCall(): Handles the cleanup process for each Velocity call. 11873 */ 11874 11875 /********************* 11876 Helper Functions 11877 *********************/ 11878 11879 /* IE detection. Gist: https://gist.github.com/julianshapiro/9098609 */ 11880 var IE = (function() { 11881 if (document.documentMode) { 11882 return document.documentMode; 11883 } else { 11884 for (var i = 7; i > 4; i--) { 11885 var div = document.createElement("div"); 11886 11887 div.innerHTML = "<!--[if IE " + i + "]><span></span><![endif]-->"; 11888 11889 if (div.getElementsByTagName("span").length) { 11890 div = null; 11891 11892 return i; 11893 } 11894 } 11895 } 11896 11897 return undefined; 11898 })(); 11899 11900 /* rAF shim. Gist: https://gist.github.com/julianshapiro/9497513 */ 11901 var rAFShim = (function() { 11902 var timeLast = 0; 11903 11904 return window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { 11905 var timeCurrent = (new Date()).getTime(), 11906 timeDelta; 11907 11908 /* Dynamically set delay on a per-tick basis to match 60fps. */ 11909 /* Technique by Erik Moller. MIT license: https://gist.github.com/paulirish/1579671 */ 11910 timeDelta = Math.max(0, 16 - (timeCurrent - timeLast)); 11911 timeLast = timeCurrent + timeDelta; 11912 11913 return setTimeout(function() { 11914 callback(timeCurrent + timeDelta); 11915 }, timeDelta); 11916 }; 11917 })(); 11918 11919 var performance = (function() { 11920 var perf = window.performance || {}; 11921 11922 if (typeof perf.now !== "function") { 11923 var nowOffset = perf.timing && perf.timing.navigationStart ? perf.timing.navigationStart : (new Date()).getTime(); 11924 11925 perf.now = function() { 11926 return (new Date()).getTime() - nowOffset; 11927 }; 11928 } 11929 return perf; 11930 })(); 11931 11932 /* Array compacting. Copyright Lo-Dash. MIT License: https://github.com/lodash/lodash/blob/master/LICENSE.txt */ 11933 function compactSparseArray(array) { 11934 var index = -1, 11935 length = array ? array.length : 0, 11936 result = []; 11937 11938 while (++index < length) { 11939 var value = array[index]; 11940 11941 if (value) { 11942 result.push(value); 11943 } 11944 } 11945 11946 return result; 11947 } 11948 11949 /** 11950 * Shim for "fixing" IE's lack of support (IE < 9) for applying slice 11951 * on host objects like NamedNodeMap, NodeList, and HTMLCollection 11952 * (technically, since host objects have been implementation-dependent, 11953 * at least before ES2015, IE hasn't needed to work this way). 11954 * Also works on strings, fixes IE < 9 to allow an explicit undefined 11955 * for the 2nd argument (as in Firefox), and prevents errors when 11956 * called on other DOM objects. 11957 */ 11958 var _slice = (function() { 11959 var slice = Array.prototype.slice; 11960 11961 try { 11962 // Can't be used with DOM elements in IE < 9 11963 slice.call(document.documentElement); 11964 return slice; 11965 } catch (e) { // Fails in IE < 9 11966 11967 // This will work for genuine arrays, array-like objects, 11968 // NamedNodeMap (attributes, entities, notations), 11969 // NodeList (e.g., getElementsByTagName), HTMLCollection (e.g., childNodes), 11970 // and will not fail on other DOM objects (as do DOM elements in IE < 9) 11971 return function(begin, end) { 11972 var len = this.length; 11973 11974 if (typeof begin !== "number") { 11975 begin = 0; 11976 } 11977 // IE < 9 gets unhappy with an undefined end argument 11978 if (typeof end !== "number") { 11979 end = len; 11980 } 11981 // For native Array objects, we use the native slice function 11982 if (this.slice) { 11983 return slice.call(this, begin, end); 11984 } 11985 // For array like object we handle it ourselves. 11986 var i, 11987 cloned = [], 11988 // Handle negative value for "begin" 11989 start = (begin >= 0) ? begin : Math.max(0, len + begin), 11990 // Handle negative value for "end" 11991 upTo = end < 0 ? len + end : Math.min(end, len), 11992 // Actual expected size of the slice 11993 size = upTo - start; 11994 11995 if (size > 0) { 11996 cloned = new Array(size); 11997 if (this.charAt) { 11998 for (i = 0; i < size; i++) { 11999 cloned[i] = this.charAt(start + i); 12000 } 12001 } else { 12002 for (i = 0; i < size; i++) { 12003 cloned[i] = this[start + i]; 12004 } 12005 } 12006 } 12007 return cloned; 12008 }; 12009 } 12010 })(); 12011 12012 /* .indexOf doesn't exist in IE<9 */ 12013 var _inArray = (function() { 12014 if (Array.prototype.includes) { 12015 return function(arr, val) { 12016 return arr.includes(val); 12017 }; 12018 } 12019 if (Array.prototype.indexOf) { 12020 return function(arr, val) { 12021 return arr.indexOf(val) >= 0; 12022 }; 12023 } 12024 return function(arr, val) { 12025 for (var i = 0; i < arr.length; i++) { 12026 if (arr[i] === val) { 12027 return true; 12028 } 12029 } 12030 return false; 12031 }; 12032 }); 12033 12034 function sanitizeElements(elements) { 12035 /* Unwrap jQuery/Zepto objects. */ 12036 if (Type.isWrapped(elements)) { 12037 elements = _slice.call(elements); 12038 /* Wrap a single element in an array so that $.each() can iterate with the element instead of its node's children. */ 12039 } else if (Type.isNode(elements)) { 12040 elements = [elements]; 12041 } 12042 12043 return elements; 12044 } 12045 12046 var Type = { 12047 isNumber: function(variable) { 12048 return (typeof variable === "number"); 12049 }, 12050 isString: function(variable) { 12051 return (typeof variable === "string"); 12052 }, 12053 isArray: Array.isArray || function(variable) { 12054 return Object.prototype.toString.call(variable) === "[object Array]"; 12055 }, 12056 isFunction: function(variable) { 12057 return Object.prototype.toString.call(variable) === "[object Function]"; 12058 }, 12059 isNode: function(variable) { 12060 return variable && variable.nodeType; 12061 }, 12062 /* Determine if variable is an array-like wrapped jQuery, Zepto or similar element, or even a NodeList etc. */ 12063 /* NOTE: HTMLFormElements also have a length. */ 12064 isWrapped: function(variable) { 12065 return variable 12066 && variable !== window 12067 && Type.isNumber(variable.length) 12068 && !Type.isString(variable) 12069 && !Type.isFunction(variable) 12070 && !Type.isNode(variable) 12071 && (variable.length === 0 || Type.isNode(variable[0])); 12072 }, 12073 isSVG: function(variable) { 12074 return window.SVGElement && (variable instanceof window.SVGElement); 12075 }, 12076 isEmptyObject: function(variable) { 12077 for (var name in variable) { 12078 if (variable.hasOwnProperty(name)) { 12079 return false; 12080 } 12081 } 12082 12083 return true; 12084 } 12085 }; 12086 12087 /***************** 12088 Dependencies 12089 *****************/ 12090 12091 var $, 12092 isJQuery = false; 12093 12094 if (global.fn && global.fn.jquery) { 12095 $ = global; 12096 isJQuery = true; 12097 } else { 12098 $ = window.Velocity.Utilities; 12099 } 12100 12101 if (IE <= 8 && !isJQuery) { 12102 throw new Error("Velocity: IE8 and below require jQuery to be loaded before Velocity."); 12103 } else if (IE <= 7) { 12104 /* Revert to jQuery's $.animate(), and lose Velocity's extra features. */ 12105 jQuery.fn.velocity = jQuery.fn.animate; 12106 12107 /* Now that $.fn.velocity is aliased, abort this Velocity declaration. */ 12108 return; 12109 } 12110 12111 /***************** 12112 Constants 12113 *****************/ 12114 12115 var DURATION_DEFAULT = 400, 12116 EASING_DEFAULT = "swing"; 12117 12118 /************* 12119 State 12120 *************/ 12121 12122 var Velocity = { 12123 /* Container for page-wide Velocity state data. */ 12124 State: { 12125 /* Detect mobile devices to determine if mobileHA should be turned on. */ 12126 isMobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(window.navigator.userAgent), 12127 /* The mobileHA option's behavior changes on older Android devices (Gingerbread, versions 2.3.3-2.3.7). */ 12128 isAndroid: /Android/i.test(window.navigator.userAgent), 12129 isGingerbread: /Android 2\.3\.[3-7]/i.test(window.navigator.userAgent), 12130 isChrome: window.chrome, 12131 isFirefox: /Firefox/i.test(window.navigator.userAgent), 12132 /* Create a cached element for re-use when checking for CSS property prefixes. */ 12133 prefixElement: document.createElement("div"), 12134 /* Cache every prefix match to avoid repeating lookups. */ 12135 prefixMatches: {}, 12136 /* Cache the anchor used for animating window scrolling. */ 12137 scrollAnchor: null, 12138 /* Cache the browser-specific property names associated with the scroll anchor. */ 12139 scrollPropertyLeft: null, 12140 scrollPropertyTop: null, 12141 /* Keep track of whether our RAF tick is running. */ 12142 isTicking: false, 12143 /* Container for every in-progress call to Velocity. */ 12144 calls: [], 12145 delayedElements: { 12146 count: 0 12147 } 12148 }, 12149 /* Velocity's custom CSS stack. Made global for unit testing. */ 12150 CSS: {/* Defined below. */}, 12151 /* A shim of the jQuery utility functions used by Velocity -- provided by Velocity's optional jQuery shim. */ 12152 Utilities: $, 12153 /* Container for the user's custom animation redirects that are referenced by name in place of the properties map argument. */ 12154 Redirects: {/* Manually registered by the user. */}, 12155 Easings: {/* Defined below. */}, 12156 /* Attempt to use ES6 Promises by default. Users can override this with a third-party promises library. */ 12157 Promise: window.Promise, 12158 /* Velocity option defaults, which can be overriden by the user. */ 12159 defaults: { 12160 queue: "", 12161 duration: DURATION_DEFAULT, 12162 easing: EASING_DEFAULT, 12163 begin: undefined, 12164 complete: undefined, 12165 progress: undefined, 12166 display: undefined, 12167 visibility: undefined, 12168 loop: false, 12169 delay: false, 12170 mobileHA: true, 12171 /* Advanced: Set to false to prevent property values from being cached between consecutive Velocity-initiated chain calls. */ 12172 _cacheValues: true, 12173 /* Advanced: Set to false if the promise should always resolve on empty element lists. */ 12174 promiseRejectEmpty: true 12175 }, 12176 /* A design goal of Velocity is to cache data wherever possible in order to avoid DOM requerying. Accordingly, each element has a data cache. */ 12177 init: function(element) { 12178 $.data(element, "velocity", { 12179 /* Store whether this is an SVG element, since its properties are retrieved and updated differently than standard HTML elements. */ 12180 isSVG: Type.isSVG(element), 12181 /* Keep track of whether the element is currently being animated by Velocity. 12182 This is used to ensure that property values are not transferred between non-consecutive (stale) calls. */ 12183 isAnimating: false, 12184 /* A reference to the element's live computedStyle object. Learn more here: https://developer.mozilla.org/en/docs/Web/API/window.getComputedStyle */ 12185 computedStyle: null, 12186 /* Tween data is cached for each animation on the element so that data can be passed across calls -- 12187 in particular, end values are used as subsequent start values in consecutive Velocity calls. */ 12188 tweensContainer: null, 12189 /* The full root property values of each CSS hook being animated on this element are cached so that: 12190 1) Concurrently-animating hooks sharing the same root can have their root values' merged into one while tweening. 12191 2) Post-hook-injection root values can be transferred over to consecutively chained Velocity calls as starting root values. */ 12192 rootPropertyValueCache: {}, 12193 /* A cache for transform updates, which must be manually flushed via CSS.flushTransformCache(). */ 12194 transformCache: {} 12195 }); 12196 }, 12197 /* A parallel to jQuery's $.css(), used for getting/setting Velocity's hooked CSS properties. */ 12198 hook: null, /* Defined below. */ 12199 /* Velocity-wide animation time remapping for testing purposes. */ 12200 mock: false, 12201 version: {major: 1, minor: 5, patch: 1}, 12202 /* Set to 1 or 2 (most verbose) to output debug info to console. */ 12203 debug: false, 12204 /* Use rAF high resolution timestamp when available */ 12205 timestamp: true, 12206 /* Pause all animations */ 12207 pauseAll: function(queueName) { 12208 var currentTime = (new Date()).getTime(); 12209 12210 $.each(Velocity.State.calls, function(i, activeCall) { 12211 12212 if (activeCall) { 12213 12214 /* If we have a queueName and this call is not on that queue, skip */ 12215 if (queueName !== undefined && ((activeCall[2].queue !== queueName) || (activeCall[2].queue === false))) { 12216 return true; 12217 } 12218 12219 /* Set call to paused */ 12220 activeCall[5] = { 12221 resume: false 12222 }; 12223 } 12224 }); 12225 12226 /* Pause timers on any currently delayed calls */ 12227 $.each(Velocity.State.delayedElements, function(k, element) { 12228 if (!element) { 12229 return; 12230 } 12231 pauseDelayOnElement(element, currentTime); 12232 }); 12233 }, 12234 /* Resume all animations */ 12235 resumeAll: function(queueName) { 12236 var currentTime = (new Date()).getTime(); 12237 12238 $.each(Velocity.State.calls, function(i, activeCall) { 12239 12240 if (activeCall) { 12241 12242 /* If we have a queueName and this call is not on that queue, skip */ 12243 if (queueName !== undefined && ((activeCall[2].queue !== queueName) || (activeCall[2].queue === false))) { 12244 return true; 12245 } 12246 12247 /* Set call to resumed if it was paused */ 12248 if (activeCall[5]) { 12249 activeCall[5].resume = true; 12250 } 12251 } 12252 }); 12253 /* Resume timers on any currently delayed calls */ 12254 $.each(Velocity.State.delayedElements, function(k, element) { 12255 if (!element) { 12256 return; 12257 } 12258 resumeDelayOnElement(element, currentTime); 12259 }); 12260 } 12261 }; 12262 12263 /* Retrieve the appropriate scroll anchor and property name for the browser: https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY */ 12264 if (window.pageYOffset !== undefined) { 12265 Velocity.State.scrollAnchor = window; 12266 Velocity.State.scrollPropertyLeft = "pageXOffset"; 12267 Velocity.State.scrollPropertyTop = "pageYOffset"; 12268 } else { 12269 Velocity.State.scrollAnchor = document.documentElement || document.body.parentNode || document.body; 12270 Velocity.State.scrollPropertyLeft = "scrollLeft"; 12271 Velocity.State.scrollPropertyTop = "scrollTop"; 12272 } 12273 12274 /* Shorthand alias for jQuery's $.data() utility. */ 12275 function Data(element) { 12276 /* Hardcode a reference to the plugin name. */ 12277 var response = $.data(element, "velocity"); 12278 12279 /* jQuery <=1.4.2 returns null instead of undefined when no match is found. We normalize this behavior. */ 12280 return response === null ? undefined : response; 12281 } 12282 12283 /************** 12284 Delay Timer 12285 **************/ 12286 12287 function pauseDelayOnElement(element, currentTime) { 12288 /* Check for any delay timers, and pause the set timeouts (while preserving time data) 12289 to be resumed when the "resume" command is issued */ 12290 var data = Data(element); 12291 if (data && data.delayTimer && !data.delayPaused) { 12292 data.delayRemaining = data.delay - currentTime + data.delayBegin; 12293 data.delayPaused = true; 12294 clearTimeout(data.delayTimer.setTimeout); 12295 } 12296 } 12297 12298 function resumeDelayOnElement(element, currentTime) { 12299 /* Check for any paused timers and resume */ 12300 var data = Data(element); 12301 if (data && data.delayTimer && data.delayPaused) { 12302 /* If the element was mid-delay, re initiate the timeout with the remaining delay */ 12303 data.delayPaused = false; 12304 data.delayTimer.setTimeout = setTimeout(data.delayTimer.next, data.delayRemaining); 12305 } 12306 } 12307 12308 12309 12310 /************** 12311 Easing 12312 **************/ 12313 12314 /* Step easing generator. */ 12315 function generateStep(steps) { 12316 return function(p) { 12317 return Math.round(p * steps) * (1 / steps); 12318 }; 12319 } 12320 12321 /* Bezier curve function generator. Copyright Gaetan Renaudeau. MIT License: http://en.wikipedia.org/wiki/MIT_License */ 12322 function generateBezier(mX1, mY1, mX2, mY2) { 12323 var NEWTON_ITERATIONS = 4, 12324 NEWTON_MIN_SLOPE = 0.001, 12325 SUBDIVISION_PRECISION = 0.0000001, 12326 SUBDIVISION_MAX_ITERATIONS = 10, 12327 kSplineTableSize = 11, 12328 kSampleStepSize = 1.0 / (kSplineTableSize - 1.0), 12329 float32ArraySupported = "Float32Array" in window; 12330 12331 /* Must contain four arguments. */ 12332 if (arguments.length !== 4) { 12333 return false; 12334 } 12335 12336 /* Arguments must be numbers. */ 12337 for (var i = 0; i < 4; ++i) { 12338 if (typeof arguments[i] !== "number" || isNaN(arguments[i]) || !isFinite(arguments[i])) { 12339 return false; 12340 } 12341 } 12342 12343 /* X values must be in the [0, 1] range. */ 12344 mX1 = Math.min(mX1, 1); 12345 mX2 = Math.min(mX2, 1); 12346 mX1 = Math.max(mX1, 0); 12347 mX2 = Math.max(mX2, 0); 12348 12349 var mSampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize); 12350 12351 function A(aA1, aA2) { 12352 return 1.0 - 3.0 * aA2 + 3.0 * aA1; 12353 } 12354 function B(aA1, aA2) { 12355 return 3.0 * aA2 - 6.0 * aA1; 12356 } 12357 function C(aA1) { 12358 return 3.0 * aA1; 12359 } 12360 12361 function calcBezier(aT, aA1, aA2) { 12362 return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT; 12363 } 12364 12365 function getSlope(aT, aA1, aA2) { 12366 return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); 12367 } 12368 12369 function newtonRaphsonIterate(aX, aGuessT) { 12370 for (var i = 0; i < NEWTON_ITERATIONS; ++i) { 12371 var currentSlope = getSlope(aGuessT, mX1, mX2); 12372 12373 if (currentSlope === 0.0) { 12374 return aGuessT; 12375 } 12376 12377 var currentX = calcBezier(aGuessT, mX1, mX2) - aX; 12378 aGuessT -= currentX / currentSlope; 12379 } 12380 12381 return aGuessT; 12382 } 12383 12384 function calcSampleValues() { 12385 for (var i = 0; i < kSplineTableSize; ++i) { 12386 mSampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2); 12387 } 12388 } 12389 12390 function binarySubdivide(aX, aA, aB) { 12391 var currentX, currentT, i = 0; 12392 12393 do { 12394 currentT = aA + (aB - aA) / 2.0; 12395 currentX = calcBezier(currentT, mX1, mX2) - aX; 12396 if (currentX > 0.0) { 12397 aB = currentT; 12398 } else { 12399 aA = currentT; 12400 } 12401 } while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS); 12402 12403 return currentT; 12404 } 12405 12406 function getTForX(aX) { 12407 var intervalStart = 0.0, 12408 currentSample = 1, 12409 lastSample = kSplineTableSize - 1; 12410 12411 for (; currentSample !== lastSample && mSampleValues[currentSample] <= aX; ++currentSample) { 12412 intervalStart += kSampleStepSize; 12413 } 12414 12415 --currentSample; 12416 12417 var dist = (aX - mSampleValues[currentSample]) / (mSampleValues[currentSample + 1] - mSampleValues[currentSample]), 12418 guessForT = intervalStart + dist * kSampleStepSize, 12419 initialSlope = getSlope(guessForT, mX1, mX2); 12420 12421 if (initialSlope >= NEWTON_MIN_SLOPE) { 12422 return newtonRaphsonIterate(aX, guessForT); 12423 } else if (initialSlope === 0.0) { 12424 return guessForT; 12425 } else { 12426 return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize); 12427 } 12428 } 12429 12430 var _precomputed = false; 12431 12432 function precompute() { 12433 _precomputed = true; 12434 if (mX1 !== mY1 || mX2 !== mY2) { 12435 calcSampleValues(); 12436 } 12437 } 12438 12439 var f = function(aX) { 12440 if (!_precomputed) { 12441 precompute(); 12442 } 12443 if (mX1 === mY1 && mX2 === mY2) { 12444 return aX; 12445 } 12446 if (aX === 0) { 12447 return 0; 12448 } 12449 if (aX === 1) { 12450 return 1; 12451 } 12452 12453 return calcBezier(getTForX(aX), mY1, mY2); 12454 }; 12455 12456 f.getControlPoints = function() { 12457 return [{x: mX1, y: mY1}, {x: mX2, y: mY2}]; 12458 }; 12459 12460 var str = "generateBezier(" + [mX1, mY1, mX2, mY2] + ")"; 12461 f.toString = function() { 12462 return str; 12463 }; 12464 12465 return f; 12466 } 12467 12468 /* Runge-Kutta spring physics function generator. Adapted from Framer.js, copyright Koen Bok. MIT License: http://en.wikipedia.org/wiki/MIT_License */ 12469 /* Given a tension, friction, and duration, a simulation at 60FPS will first run without a defined duration in order to calculate the full path. A second pass 12470 then adjusts the time delta -- using the relation between actual time and duration -- to calculate the path for the duration-constrained animation. */ 12471 var generateSpringRK4 = (function() { 12472 function springAccelerationForState(state) { 12473 return (-state.tension * state.x) - (state.friction * state.v); 12474 } 12475 12476 function springEvaluateStateWithDerivative(initialState, dt, derivative) { 12477 var state = { 12478 x: initialState.x + derivative.dx * dt, 12479 v: initialState.v + derivative.dv * dt, 12480 tension: initialState.tension, 12481 friction: initialState.friction 12482 }; 12483 12484 return {dx: state.v, dv: springAccelerationForState(state)}; 12485 } 12486 12487 function springIntegrateState(state, dt) { 12488 var a = { 12489 dx: state.v, 12490 dv: springAccelerationForState(state) 12491 }, 12492 b = springEvaluateStateWithDerivative(state, dt * 0.5, a), 12493 c = springEvaluateStateWithDerivative(state, dt * 0.5, b), 12494 d = springEvaluateStateWithDerivative(state, dt, c), 12495 dxdt = 1.0 / 6.0 * (a.dx + 2.0 * (b.dx + c.dx) + d.dx), 12496 dvdt = 1.0 / 6.0 * (a.dv + 2.0 * (b.dv + c.dv) + d.dv); 12497 12498 state.x = state.x + dxdt * dt; 12499 state.v = state.v + dvdt * dt; 12500 12501 return state; 12502 } 12503 12504 return function springRK4Factory(tension, friction, duration) { 12505 12506 var initState = { 12507 x: -1, 12508 v: 0, 12509 tension: null, 12510 friction: null 12511 }, 12512 path = [0], 12513 time_lapsed = 0, 12514 tolerance = 1 / 10000, 12515 DT = 16 / 1000, 12516 have_duration, dt, last_state; 12517 12518 tension = parseFloat(tension) || 500; 12519 friction = parseFloat(friction) || 20; 12520 duration = duration || null; 12521 12522 initState.tension = tension; 12523 initState.friction = friction; 12524 12525 have_duration = duration !== null; 12526 12527 /* Calculate the actual time it takes for this animation to complete with the provided conditions. */ 12528 if (have_duration) { 12529 /* Run the simulation without a duration. */ 12530 time_lapsed = springRK4Factory(tension, friction); 12531 /* Compute the adjusted time delta. */ 12532 dt = time_lapsed / duration * DT; 12533 } else { 12534 dt = DT; 12535 } 12536 12537 while (true) { 12538 /* Next/step function .*/ 12539 last_state = springIntegrateState(last_state || initState, dt); 12540 /* Store the position. */ 12541 path.push(1 + last_state.x); 12542 time_lapsed += 16; 12543 /* If the change threshold is reached, break. */ 12544 if (!(Math.abs(last_state.x) > tolerance && Math.abs(last_state.v) > tolerance)) { 12545 break; 12546 } 12547 } 12548 12549 /* If duration is not defined, return the actual time required for completing this animation. Otherwise, return a closure that holds the 12550 computed path and returns a snapshot of the position according to a given percentComplete. */ 12551 return !have_duration ? time_lapsed : function(percentComplete) { 12552 return path[ (percentComplete * (path.length - 1)) | 0 ]; 12553 }; 12554 }; 12555 }()); 12556 12557 /* jQuery easings. */ 12558 Velocity.Easings = { 12559 linear: function(p) { 12560 return p; 12561 }, 12562 swing: function(p) { 12563 return 0.5 - Math.cos(p * Math.PI) / 2; 12564 }, 12565 /* Bonus "spring" easing, which is a less exaggerated version of easeInOutElastic. */ 12566 spring: function(p) { 12567 return 1 - (Math.cos(p * 4.5 * Math.PI) * Math.exp(-p * 6)); 12568 } 12569 }; 12570 12571 /* CSS3 and Robert Penner easings. */ 12572 $.each( 12573 [ 12574 ["ease", [0.25, 0.1, 0.25, 1.0]], 12575 ["ease-in", [0.42, 0.0, 1.00, 1.0]], 12576 ["ease-out", [0.00, 0.0, 0.58, 1.0]], 12577 ["ease-in-out", [0.42, 0.0, 0.58, 1.0]], 12578 ["easeInSine", [0.47, 0, 0.745, 0.715]], 12579 ["easeOutSine", [0.39, 0.575, 0.565, 1]], 12580 ["easeInOutSine", [0.445, 0.05, 0.55, 0.95]], 12581 ["easeInQuad", [0.55, 0.085, 0.68, 0.53]], 12582 ["easeOutQuad", [0.25, 0.46, 0.45, 0.94]], 12583 ["easeInOutQuad", [0.455, 0.03, 0.515, 0.955]], 12584 ["easeInCubic", [0.55, 0.055, 0.675, 0.19]], 12585 ["easeOutCubic", [0.215, 0.61, 0.355, 1]], 12586 ["easeInOutCubic", [0.645, 0.045, 0.355, 1]], 12587 ["easeInQuart", [0.895, 0.03, 0.685, 0.22]], 12588 ["easeOutQuart", [0.165, 0.84, 0.44, 1]], 12589 ["easeInOutQuart", [0.77, 0, 0.175, 1]], 12590 ["easeInQuint", [0.755, 0.05, 0.855, 0.06]], 12591 ["easeOutQuint", [0.23, 1, 0.32, 1]], 12592 ["easeInOutQuint", [0.86, 0, 0.07, 1]], 12593 ["easeInExpo", [0.95, 0.05, 0.795, 0.035]], 12594 ["easeOutExpo", [0.19, 1, 0.22, 1]], 12595 ["easeInOutExpo", [1, 0, 0, 1]], 12596 ["easeInCirc", [0.6, 0.04, 0.98, 0.335]], 12597 ["easeOutCirc", [0.075, 0.82, 0.165, 1]], 12598 ["easeInOutCirc", [0.785, 0.135, 0.15, 0.86]] 12599 ], function(i, easingArray) { 12600 Velocity.Easings[easingArray[0]] = generateBezier.apply(null, easingArray[1]); 12601 }); 12602 12603 /* Determine the appropriate easing type given an easing input. */ 12604 function getEasing(value, duration) { 12605 var easing = value; 12606 12607 /* The easing option can either be a string that references a pre-registered easing, 12608 or it can be a two-/four-item array of integers to be converted into a bezier/spring function. */ 12609 if (Type.isString(value)) { 12610 /* Ensure that the easing has been assigned to jQuery's Velocity.Easings object. */ 12611 if (!Velocity.Easings[value]) { 12612 easing = false; 12613 } 12614 } else if (Type.isArray(value) && value.length === 1) { 12615 easing = generateStep.apply(null, value); 12616 } else if (Type.isArray(value) && value.length === 2) { 12617 /* springRK4 must be passed the animation's duration. */ 12618 /* Note: If the springRK4 array contains non-numbers, generateSpringRK4() returns an easing 12619 function generated with default tension and friction values. */ 12620 easing = generateSpringRK4.apply(null, value.concat([duration])); 12621 } else if (Type.isArray(value) && value.length === 4) { 12622 /* Note: If the bezier array contains non-numbers, generateBezier() returns false. */ 12623 easing = generateBezier.apply(null, value); 12624 } else { 12625 easing = false; 12626 } 12627 12628 /* Revert to the Velocity-wide default easing type, or fall back to "swing" (which is also jQuery's default) 12629 if the Velocity-wide default has been incorrectly modified. */ 12630 if (easing === false) { 12631 if (Velocity.Easings[Velocity.defaults.easing]) { 12632 easing = Velocity.defaults.easing; 12633 } else { 12634 easing = EASING_DEFAULT; 12635 } 12636 } 12637 12638 return easing; 12639 } 12640 12641 /***************** 12642 CSS Stack 12643 *****************/ 12644 12645 /* The CSS object is a highly condensed and performant CSS stack that fully replaces jQuery's. 12646 It handles the validation, getting, and setting of both standard CSS properties and CSS property hooks. */ 12647 /* Note: A "CSS" shorthand is aliased so that our code is easier to read. */ 12648 var CSS = Velocity.CSS = { 12649 /************* 12650 RegEx 12651 *************/ 12652 12653 RegEx: { 12654 isHex: /^#([A-f\d]{3}){1,2}$/i, 12655 /* Unwrap a property value's surrounding text, e.g. "rgba(4, 3, 2, 1)" ==> "4, 3, 2, 1" and "rect(4px 3px 2px 1px)" ==> "4px 3px 2px 1px". */ 12656 valueUnwrap: /^[A-z]+\((.*)\)$/i, 12657 wrappedValueAlreadyExtracted: /[0-9.]+ [0-9.]+ [0-9.]+( [0-9.]+)?/, 12658 /* Split a multi-value property into an array of subvalues, e.g. "rgba(4, 3, 2, 1) 4px 3px 2px 1px" ==> [ "rgba(4, 3, 2, 1)", "4px", "3px", "2px", "1px" ]. */ 12659 valueSplit: /([A-z]+\(.+\))|(([A-z0-9#-.]+?)(?=\s|$))/ig 12660 }, 12661 /************ 12662 Lists 12663 ************/ 12664 12665 Lists: { 12666 colors: ["fill", "stroke", "stopColor", "color", "backgroundColor", "borderColor", "borderTopColor", "borderRightColor", "borderBottomColor", "borderLeftColor", "outlineColor"], 12667 transformsBase: ["translateX", "translateY", "scale", "scaleX", "scaleY", "skewX", "skewY", "rotateZ"], 12668 transforms3D: ["transformPerspective", "translateZ", "scaleZ", "rotateX", "rotateY"], 12669 units: [ 12670 "%", // relative 12671 "em", "ex", "ch", "rem", // font relative 12672 "vw", "vh", "vmin", "vmax", // viewport relative 12673 "cm", "mm", "Q", "in", "pc", "pt", "px", // absolute lengths 12674 "deg", "grad", "rad", "turn", // angles 12675 "s", "ms" // time 12676 ], 12677 colorNames: { 12678 "aliceblue": "240,248,255", 12679 "antiquewhite": "250,235,215", 12680 "aquamarine": "127,255,212", 12681 "aqua": "0,255,255", 12682 "azure": "240,255,255", 12683 "beige": "245,245,220", 12684 "bisque": "255,228,196", 12685 "black": "0,0,0", 12686 "blanchedalmond": "255,235,205", 12687 "blueviolet": "138,43,226", 12688 "blue": "0,0,255", 12689 "brown": "165,42,42", 12690 "burlywood": "222,184,135", 12691 "cadetblue": "95,158,160", 12692 "chartreuse": "127,255,0", 12693 "chocolate": "210,105,30", 12694 "coral": "255,127,80", 12695 "cornflowerblue": "100,149,237", 12696 "cornsilk": "255,248,220", 12697 "crimson": "220,20,60", 12698 "cyan": "0,255,255", 12699 "darkblue": "0,0,139", 12700 "darkcyan": "0,139,139", 12701 "darkgoldenrod": "184,134,11", 12702 "darkgray": "169,169,169", 12703 "darkgrey": "169,169,169", 12704 "darkgreen": "0,100,0", 12705 "darkkhaki": "189,183,107", 12706 "darkmagenta": "139,0,139", 12707 "darkolivegreen": "85,107,47", 12708 "darkorange": "255,140,0", 12709 "darkorchid": "153,50,204", 12710 "darkred": "139,0,0", 12711 "darksalmon": "233,150,122", 12712 "darkseagreen": "143,188,143", 12713 "darkslateblue": "72,61,139", 12714 "darkslategray": "47,79,79", 12715 "darkturquoise": "0,206,209", 12716 "darkviolet": "148,0,211", 12717 "deeppink": "255,20,147", 12718 "deepskyblue": "0,191,255", 12719 "dimgray": "105,105,105", 12720 "dimgrey": "105,105,105", 12721 "dodgerblue": "30,144,255", 12722 "firebrick": "178,34,34", 12723 "floralwhite": "255,250,240", 12724 "forestgreen": "34,139,34", 12725 "fuchsia": "255,0,255", 12726 "gainsboro": "220,220,220", 12727 "ghostwhite": "248,248,255", 12728 "gold": "255,215,0", 12729 "goldenrod": "218,165,32", 12730 "gray": "128,128,128", 12731 "grey": "128,128,128", 12732 "greenyellow": "173,255,47", 12733 "green": "0,128,0", 12734 "honeydew": "240,255,240", 12735 "hotpink": "255,105,180", 12736 "indianred": "205,92,92", 12737 "indigo": "75,0,130", 12738 "ivory": "255,255,240", 12739 "khaki": "240,230,140", 12740 "lavenderblush": "255,240,245", 12741 "lavender": "230,230,250", 12742 "lawngreen": "124,252,0", 12743 "lemonchiffon": "255,250,205", 12744 "lightblue": "173,216,230", 12745 "lightcoral": "240,128,128", 12746 "lightcyan": "224,255,255", 12747 "lightgoldenrodyellow": "250,250,210", 12748 "lightgray": "211,211,211", 12749 "lightgrey": "211,211,211", 12750 "lightgreen": "144,238,144", 12751 "lightpink": "255,182,193", 12752 "lightsalmon": "255,160,122", 12753 "lightseagreen": "32,178,170", 12754 "lightskyblue": "135,206,250", 12755 "lightslategray": "119,136,153", 12756 "lightsteelblue": "176,196,222", 12757 "lightyellow": "255,255,224", 12758 "limegreen": "50,205,50", 12759 "lime": "0,255,0", 12760 "linen": "250,240,230", 12761 "magenta": "255,0,255", 12762 "maroon": "128,0,0", 12763 "mediumaquamarine": "102,205,170", 12764 "mediumblue": "0,0,205", 12765 "mediumorchid": "186,85,211", 12766 "mediumpurple": "147,112,219", 12767 "mediumseagreen": "60,179,113", 12768 "mediumslateblue": "123,104,238", 12769 "mediumspringgreen": "0,250,154", 12770 "mediumturquoise": "72,209,204", 12771 "mediumvioletred": "199,21,133", 12772 "midnightblue": "25,25,112", 12773 "mintcream": "245,255,250", 12774 "mistyrose": "255,228,225", 12775 "moccasin": "255,228,181", 12776 "navajowhite": "255,222,173", 12777 "navy": "0,0,128", 12778 "oldlace": "253,245,230", 12779 "olivedrab": "107,142,35", 12780 "olive": "128,128,0", 12781 "orangered": "255,69,0", 12782 "orange": "255,165,0", 12783 "orchid": "218,112,214", 12784 "palegoldenrod": "238,232,170", 12785 "palegreen": "152,251,152", 12786 "paleturquoise": "175,238,238", 12787 "palevioletred": "219,112,147", 12788 "papayawhip": "255,239,213", 12789 "peachpuff": "255,218,185", 12790 "peru": "205,133,63", 12791 "pink": "255,192,203", 12792 "plum": "221,160,221", 12793 "powderblue": "176,224,230", 12794 "purple": "128,0,128", 12795 "red": "255,0,0", 12796 "rosybrown": "188,143,143", 12797 "royalblue": "65,105,225", 12798 "saddlebrown": "139,69,19", 12799 "salmon": "250,128,114", 12800 "sandybrown": "244,164,96", 12801 "seagreen": "46,139,87", 12802 "seashell": "255,245,238", 12803 "sienna": "160,82,45", 12804 "silver": "192,192,192", 12805 "skyblue": "135,206,235", 12806 "slateblue": "106,90,205", 12807 "slategray": "112,128,144", 12808 "snow": "255,250,250", 12809 "springgreen": "0,255,127", 12810 "steelblue": "70,130,180", 12811 "tan": "210,180,140", 12812 "teal": "0,128,128", 12813 "thistle": "216,191,216", 12814 "tomato": "255,99,71", 12815 "turquoise": "64,224,208", 12816 "violet": "238,130,238", 12817 "wheat": "245,222,179", 12818 "whitesmoke": "245,245,245", 12819 "white": "255,255,255", 12820 "yellowgreen": "154,205,50", 12821 "yellow": "255,255,0" 12822 } 12823 }, 12824 /************ 12825 Hooks 12826 ************/ 12827 12828 /* Hooks allow a subproperty (e.g. "boxShadowBlur") of a compound-value CSS property 12829 (e.g. "boxShadow: X Y Blur Spread Color") to be animated as if it were a discrete property. */ 12830 /* Note: Beyond enabling fine-grained property animation, hooking is necessary since Velocity only 12831 tweens properties with single numeric values; unlike CSS transitions, Velocity does not interpolate compound-values. */ 12832 Hooks: { 12833 /******************** 12834 Registration 12835 ********************/ 12836 12837 /* Templates are a concise way of indicating which subproperties must be individually registered for each compound-value CSS property. */ 12838 /* Each template consists of the compound-value's base name, its constituent subproperty names, and those subproperties' default values. */ 12839 templates: { 12840 "textShadow": ["Color X Y Blur", "black 0px 0px 0px"], 12841 "boxShadow": ["Color X Y Blur Spread", "black 0px 0px 0px 0px"], 12842 "clip": ["Top Right Bottom Left", "0px 0px 0px 0px"], 12843 "backgroundPosition": ["X Y", "0% 0%"], 12844 "transformOrigin": ["X Y Z", "50% 50% 0px"], 12845 "perspectiveOrigin": ["X Y", "50% 50%"] 12846 }, 12847 /* A "registered" hook is one that has been converted from its template form into a live, 12848 tweenable property. It contains data to associate it with its root property. */ 12849 registered: { 12850 /* Note: A registered hook looks like this ==> textShadowBlur: [ "textShadow", 3 ], 12851 which consists of the subproperty's name, the associated root property's name, 12852 and the subproperty's position in the root's value. */ 12853 }, 12854 /* Convert the templates into individual hooks then append them to the registered object above. */ 12855 register: function() { 12856 /* Color hooks registration: Colors are defaulted to white -- as opposed to black -- since colors that are 12857 currently set to "transparent" default to their respective template below when color-animated, 12858 and white is typically a closer match to transparent than black is. An exception is made for text ("color"), 12859 which is almost always set closer to black than white. */ 12860 for (var i = 0; i < CSS.Lists.colors.length; i++) { 12861 var rgbComponents = (CSS.Lists.colors[i] === "color") ? "0 0 0 1" : "255 255 255 1"; 12862 CSS.Hooks.templates[CSS.Lists.colors[i]] = ["Red Green Blue Alpha", rgbComponents]; 12863 } 12864 12865 var rootProperty, 12866 hookTemplate, 12867 hookNames; 12868 12869 /* In IE, color values inside compound-value properties are positioned at the end the value instead of at the beginning. 12870 Thus, we re-arrange the templates accordingly. */ 12871 if (IE) { 12872 for (rootProperty in CSS.Hooks.templates) { 12873 if (!CSS.Hooks.templates.hasOwnProperty(rootProperty)) { 12874 continue; 12875 } 12876 hookTemplate = CSS.Hooks.templates[rootProperty]; 12877 hookNames = hookTemplate[0].split(" "); 12878 12879 var defaultValues = hookTemplate[1].match(CSS.RegEx.valueSplit); 12880 12881 if (hookNames[0] === "Color") { 12882 /* Reposition both the hook's name and its default value to the end of their respective strings. */ 12883 hookNames.push(hookNames.shift()); 12884 defaultValues.push(defaultValues.shift()); 12885 12886 /* Replace the existing template for the hook's root property. */ 12887 CSS.Hooks.templates[rootProperty] = [hookNames.join(" "), defaultValues.join(" ")]; 12888 } 12889 } 12890 } 12891 12892 /* Hook registration. */ 12893 for (rootProperty in CSS.Hooks.templates) { 12894 if (!CSS.Hooks.templates.hasOwnProperty(rootProperty)) { 12895 continue; 12896 } 12897 hookTemplate = CSS.Hooks.templates[rootProperty]; 12898 hookNames = hookTemplate[0].split(" "); 12899 12900 for (var j in hookNames) { 12901 if (!hookNames.hasOwnProperty(j)) { 12902 continue; 12903 } 12904 var fullHookName = rootProperty + hookNames[j], 12905 hookPosition = j; 12906 12907 /* For each hook, register its full name (e.g. textShadowBlur) with its root property (e.g. textShadow) 12908 and the hook's position in its template's default value string. */ 12909 CSS.Hooks.registered[fullHookName] = [rootProperty, hookPosition]; 12910 } 12911 } 12912 }, 12913 /***************************** 12914 Injection and Extraction 12915 *****************************/ 12916 12917 /* Look up the root property associated with the hook (e.g. return "textShadow" for "textShadowBlur"). */ 12918 /* Since a hook cannot be set directly (the browser won't recognize it), style updating for hooks is routed through the hook's root property. */ 12919 getRoot: function(property) { 12920 var hookData = CSS.Hooks.registered[property]; 12921 12922 if (hookData) { 12923 return hookData[0]; 12924 } else { 12925 /* If there was no hook match, return the property name untouched. */ 12926 return property; 12927 } 12928 }, 12929 getUnit: function(str, start) { 12930 var unit = (str.substr(start || 0, 5).match(/^[a-z%]+/) || [])[0] || ""; 12931 12932 if (unit && _inArray(CSS.Lists.units, unit)) { 12933 return unit; 12934 } 12935 return ""; 12936 }, 12937 fixColors: function(str) { 12938 return str.replace(/(rgba?\(\s*)?(\b[a-z]+\b)/g, function($0, $1, $2) { 12939 if (CSS.Lists.colorNames.hasOwnProperty($2)) { 12940 return ($1 ? $1 : "rgba(") + CSS.Lists.colorNames[$2] + ($1 ? "" : ",1)"); 12941 } 12942 return $1 + $2; 12943 }); 12944 }, 12945 /* Convert any rootPropertyValue, null or otherwise, into a space-delimited list of hook values so that 12946 the targeted hook can be injected or extracted at its standard position. */ 12947 cleanRootPropertyValue: function(rootProperty, rootPropertyValue) { 12948 /* If the rootPropertyValue is wrapped with "rgb()", "clip()", etc., remove the wrapping to normalize the value before manipulation. */ 12949 if (CSS.RegEx.valueUnwrap.test(rootPropertyValue)) { 12950 rootPropertyValue = rootPropertyValue.match(CSS.RegEx.valueUnwrap)[1]; 12951 } 12952 12953 /* If rootPropertyValue is a CSS null-value (from which there's inherently no hook value to extract), 12954 default to the root's default value as defined in CSS.Hooks.templates. */ 12955 /* Note: CSS null-values include "none", "auto", and "transparent". They must be converted into their 12956 zero-values (e.g. textShadow: "none" ==> textShadow: "0px 0px 0px black") for hook manipulation to proceed. */ 12957 if (CSS.Values.isCSSNullValue(rootPropertyValue)) { 12958 rootPropertyValue = CSS.Hooks.templates[rootProperty][1]; 12959 } 12960 12961 return rootPropertyValue; 12962 }, 12963 /* Extracted the hook's value from its root property's value. This is used to get the starting value of an animating hook. */ 12964 extractValue: function(fullHookName, rootPropertyValue) { 12965 var hookData = CSS.Hooks.registered[fullHookName]; 12966 12967 if (hookData) { 12968 var hookRoot = hookData[0], 12969 hookPosition = hookData[1]; 12970 12971 rootPropertyValue = CSS.Hooks.cleanRootPropertyValue(hookRoot, rootPropertyValue); 12972 12973 /* Split rootPropertyValue into its constituent hook values then grab the desired hook at its standard position. */ 12974 return rootPropertyValue.toString().match(CSS.RegEx.valueSplit)[hookPosition]; 12975 } else { 12976 /* If the provided fullHookName isn't a registered hook, return the rootPropertyValue that was passed in. */ 12977 return rootPropertyValue; 12978 } 12979 }, 12980 /* Inject the hook's value into its root property's value. This is used to piece back together the root property 12981 once Velocity has updated one of its individually hooked values through tweening. */ 12982 injectValue: function(fullHookName, hookValue, rootPropertyValue) { 12983 var hookData = CSS.Hooks.registered[fullHookName]; 12984 12985 if (hookData) { 12986 var hookRoot = hookData[0], 12987 hookPosition = hookData[1], 12988 rootPropertyValueParts, 12989 rootPropertyValueUpdated; 12990 12991 rootPropertyValue = CSS.Hooks.cleanRootPropertyValue(hookRoot, rootPropertyValue); 12992 12993 /* Split rootPropertyValue into its individual hook values, replace the targeted value with hookValue, 12994 then reconstruct the rootPropertyValue string. */ 12995 rootPropertyValueParts = rootPropertyValue.toString().match(CSS.RegEx.valueSplit); 12996 rootPropertyValueParts[hookPosition] = hookValue; 12997 rootPropertyValueUpdated = rootPropertyValueParts.join(" "); 12998 12999 return rootPropertyValueUpdated; 13000 } else { 13001 /* If the provided fullHookName isn't a registered hook, return the rootPropertyValue that was passed in. */ 13002 return rootPropertyValue; 13003 } 13004 } 13005 }, 13006 /******************* 13007 Normalizations 13008 *******************/ 13009 13010 /* Normalizations standardize CSS property manipulation by pollyfilling browser-specific implementations (e.g. opacity) 13011 and reformatting special properties (e.g. clip, rgba) to look like standard ones. */ 13012 Normalizations: { 13013 /* Normalizations are passed a normalization target (either the property's name, its extracted value, or its injected value), 13014 the targeted element (which may need to be queried), and the targeted property value. */ 13015 registered: { 13016 clip: function(type, element, propertyValue) { 13017 switch (type) { 13018 case "name": 13019 return "clip"; 13020 /* Clip needs to be unwrapped and stripped of its commas during extraction. */ 13021 case "extract": 13022 var extracted; 13023 13024 /* If Velocity also extracted this value, skip extraction. */ 13025 if (CSS.RegEx.wrappedValueAlreadyExtracted.test(propertyValue)) { 13026 extracted = propertyValue; 13027 } else { 13028 /* Remove the "rect()" wrapper. */ 13029 extracted = propertyValue.toString().match(CSS.RegEx.valueUnwrap); 13030 13031 /* Strip off commas. */ 13032 extracted = extracted ? extracted[1].replace(/,(\s+)?/g, " ") : propertyValue; 13033 } 13034 13035 return extracted; 13036 /* Clip needs to be re-wrapped during injection. */ 13037 case "inject": 13038 return "rect(" + propertyValue + ")"; 13039 } 13040 }, 13041 blur: function(type, element, propertyValue) { 13042 switch (type) { 13043 case "name": 13044 return Velocity.State.isFirefox ? "filter" : "-webkit-filter"; 13045 case "extract": 13046 var extracted = parseFloat(propertyValue); 13047 13048 /* If extracted is NaN, meaning the value isn't already extracted. */ 13049 if (!(extracted || extracted === 0)) { 13050 var blurComponent = propertyValue.toString().match(/blur\(([0-9]+[A-z]+)\)/i); 13051 13052 /* If the filter string had a blur component, return just the blur value and unit type. */ 13053 if (blurComponent) { 13054 extracted = blurComponent[1]; 13055 /* If the component doesn't exist, default blur to 0. */ 13056 } else { 13057 extracted = 0; 13058 } 13059 } 13060 13061 return extracted; 13062 /* Blur needs to be re-wrapped during injection. */ 13063 case "inject": 13064 /* For the blur effect to be fully de-applied, it needs to be set to "none" instead of 0. */ 13065 if (!parseFloat(propertyValue)) { 13066 return "none"; 13067 } else { 13068 return "blur(" + propertyValue + ")"; 13069 } 13070 } 13071 }, 13072 /* <=IE8 do not support the standard opacity property. They use filter:alpha(opacity=INT) instead. */ 13073 opacity: function(type, element, propertyValue) { 13074 if (IE <= 8) { 13075 switch (type) { 13076 case "name": 13077 return "filter"; 13078 case "extract": 13079 /* <=IE8 return a "filter" value of "alpha(opacity=\d{1,3})". 13080 Extract the value and convert it to a decimal value to match the standard CSS opacity property's formatting. */ 13081 var extracted = propertyValue.toString().match(/alpha\(opacity=(.*)\)/i); 13082 13083 if (extracted) { 13084 /* Convert to decimal value. */ 13085 propertyValue = extracted[1] / 100; 13086 } else { 13087 /* When extracting opacity, default to 1 since a null value means opacity hasn't been set. */ 13088 propertyValue = 1; 13089 } 13090 13091 return propertyValue; 13092 case "inject": 13093 /* Opacified elements are required to have their zoom property set to a non-zero value. */ 13094 element.style.zoom = 1; 13095 13096 /* Setting the filter property on elements with certain font property combinations can result in a 13097 highly unappealing ultra-bolding effect. There's no way to remedy this throughout a tween, but dropping the 13098 value altogether (when opacity hits 1) at leasts ensures that the glitch is gone post-tweening. */ 13099 if (parseFloat(propertyValue) >= 1) { 13100 return ""; 13101 } else { 13102 /* As per the filter property's spec, convert the decimal value to a whole number and wrap the value. */ 13103 return "alpha(opacity=" + parseInt(parseFloat(propertyValue) * 100, 10) + ")"; 13104 } 13105 } 13106 /* With all other browsers, normalization is not required; return the same values that were passed in. */ 13107 } else { 13108 switch (type) { 13109 case "name": 13110 return "opacity"; 13111 case "extract": 13112 return propertyValue; 13113 case "inject": 13114 return propertyValue; 13115 } 13116 } 13117 } 13118 }, 13119 /***************************** 13120 Batched Registrations 13121 *****************************/ 13122 13123 /* Note: Batched normalizations extend the CSS.Normalizations.registered object. */ 13124 register: function() { 13125 13126 /***************** 13127 Transforms 13128 *****************/ 13129 13130 /* Transforms are the subproperties contained by the CSS "transform" property. Transforms must undergo normalization 13131 so that they can be referenced in a properties map by their individual names. */ 13132 /* Note: When transforms are "set", they are actually assigned to a per-element transformCache. When all transform 13133 setting is complete complete, CSS.flushTransformCache() must be manually called to flush the values to the DOM. 13134 Transform setting is batched in this way to improve performance: the transform style only needs to be updated 13135 once when multiple transform subproperties are being animated simultaneously. */ 13136 /* Note: IE9 and Android Gingerbread have support for 2D -- but not 3D -- transforms. Since animating unsupported 13137 transform properties results in the browser ignoring the *entire* transform string, we prevent these 3D values 13138 from being normalized for these browsers so that tweening skips these properties altogether 13139 (since it will ignore them as being unsupported by the browser.) */ 13140 if ((!IE || IE > 9) && !Velocity.State.isGingerbread) { 13141 /* Note: Since the standalone CSS "perspective" property and the CSS transform "perspective" subproperty 13142 share the same name, the latter is given a unique token within Velocity: "transformPerspective". */ 13143 CSS.Lists.transformsBase = CSS.Lists.transformsBase.concat(CSS.Lists.transforms3D); 13144 } 13145 13146 for (var i = 0; i < CSS.Lists.transformsBase.length; i++) { 13147 /* Wrap the dynamically generated normalization function in a new scope so that transformName's value is 13148 paired with its respective function. (Otherwise, all functions would take the final for loop's transformName.) */ 13149 (function() { 13150 var transformName = CSS.Lists.transformsBase[i]; 13151 13152 CSS.Normalizations.registered[transformName] = function(type, element, propertyValue) { 13153 switch (type) { 13154 /* The normalized property name is the parent "transform" property -- the property that is actually set in CSS. */ 13155 case "name": 13156 return "transform"; 13157 /* Transform values are cached onto a per-element transformCache object. */ 13158 case "extract": 13159 /* If this transform has yet to be assigned a value, return its null value. */ 13160 if (Data(element) === undefined || Data(element).transformCache[transformName] === undefined) { 13161 /* Scale CSS.Lists.transformsBase default to 1 whereas all other transform properties default to 0. */ 13162 return /^scale/i.test(transformName) ? 1 : 0; 13163 /* When transform values are set, they are wrapped in parentheses as per the CSS spec. 13164 Thus, when extracting their values (for tween calculations), we strip off the parentheses. */ 13165 } 13166 return Data(element).transformCache[transformName].replace(/[()]/g, ""); 13167 case "inject": 13168 var invalid = false; 13169 13170 /* If an individual transform property contains an unsupported unit type, the browser ignores the *entire* transform property. 13171 Thus, protect users from themselves by skipping setting for transform values supplied with invalid unit types. */ 13172 /* Switch on the base transform type; ignore the axis by removing the last letter from the transform's name. */ 13173 switch (transformName.substr(0, transformName.length - 1)) { 13174 /* Whitelist unit types for each transform. */ 13175 case "translate": 13176 invalid = !/(%|px|em|rem|vw|vh|\d)$/i.test(propertyValue); 13177 break; 13178 /* Since an axis-free "scale" property is supported as well, a little hack is used here to detect it by chopping off its last letter. */ 13179 case "scal": 13180 case "scale": 13181 /* Chrome on Android has a bug in which scaled elements blur if their initial scale 13182 value is below 1 (which can happen with forcefeeding). Thus, we detect a yet-unset scale property 13183 and ensure that its first value is always 1. More info: http://stackoverflow.com/questions/10417890/css3-animations-with-transform-causes-blurred-elements-on-webkit/10417962#10417962 */ 13184 if (Velocity.State.isAndroid && Data(element).transformCache[transformName] === undefined && propertyValue < 1) { 13185 propertyValue = 1; 13186 } 13187 13188 invalid = !/(\d)$/i.test(propertyValue); 13189 break; 13190 case "skew": 13191 invalid = !/(deg|\d)$/i.test(propertyValue); 13192 break; 13193 case "rotate": 13194 invalid = !/(deg|\d)$/i.test(propertyValue); 13195 break; 13196 } 13197 13198 if (!invalid) { 13199 /* As per the CSS spec, wrap the value in parentheses. */ 13200 Data(element).transformCache[transformName] = "(" + propertyValue + ")"; 13201 } 13202 13203 /* Although the value is set on the transformCache object, return the newly-updated value for the calling code to process as normal. */ 13204 return Data(element).transformCache[transformName]; 13205 } 13206 }; 13207 })(); 13208 } 13209 13210 /************* 13211 Colors 13212 *************/ 13213 13214 /* Since Velocity only animates a single numeric value per property, color animation is achieved by hooking the individual RGBA components of CSS color properties. 13215 Accordingly, color values must be normalized (e.g. "#ff0000", "red", and "rgb(255, 0, 0)" ==> "255 0 0 1") so that their components can be injected/extracted by CSS.Hooks logic. */ 13216 for (var j = 0; j < CSS.Lists.colors.length; j++) { 13217 /* Wrap the dynamically generated normalization function in a new scope so that colorName's value is paired with its respective function. 13218 (Otherwise, all functions would take the final for loop's colorName.) */ 13219 (function() { 13220 var colorName = CSS.Lists.colors[j]; 13221 13222 /* Note: In IE<=8, which support rgb but not rgba, color properties are reverted to rgb by stripping off the alpha component. */ 13223 CSS.Normalizations.registered[colorName] = function(type, element, propertyValue) { 13224 switch (type) { 13225 case "name": 13226 return colorName; 13227 /* Convert all color values into the rgb format. (Old IE can return hex values and color names instead of rgb/rgba.) */ 13228 case "extract": 13229 var extracted; 13230 13231 /* If the color is already in its hookable form (e.g. "255 255 255 1") due to having been previously extracted, skip extraction. */ 13232 if (CSS.RegEx.wrappedValueAlreadyExtracted.test(propertyValue)) { 13233 extracted = propertyValue; 13234 } else { 13235 var converted, 13236 colorNames = { 13237 black: "rgb(0, 0, 0)", 13238 blue: "rgb(0, 0, 255)", 13239 gray: "rgb(128, 128, 128)", 13240 green: "rgb(0, 128, 0)", 13241 red: "rgb(255, 0, 0)", 13242 white: "rgb(255, 255, 255)" 13243 }; 13244 13245 /* Convert color names to rgb. */ 13246 if (/^[A-z]+$/i.test(propertyValue)) { 13247 if (colorNames[propertyValue] !== undefined) { 13248 converted = colorNames[propertyValue]; 13249 } else { 13250 /* If an unmatched color name is provided, default to black. */ 13251 converted = colorNames.black; 13252 } 13253 /* Convert hex values to rgb. */ 13254 } else if (CSS.RegEx.isHex.test(propertyValue)) { 13255 converted = "rgb(" + CSS.Values.hexToRgb(propertyValue).join(" ") + ")"; 13256 /* If the provided color doesn't match any of the accepted color formats, default to black. */ 13257 } else if (!(/^rgba?\(/i.test(propertyValue))) { 13258 converted = colorNames.black; 13259 } 13260 13261 /* Remove the surrounding "rgb/rgba()" string then replace commas with spaces and strip 13262 repeated spaces (in case the value included spaces to begin with). */ 13263 extracted = (converted || propertyValue).toString().match(CSS.RegEx.valueUnwrap)[1].replace(/,(\s+)?/g, " "); 13264 } 13265 13266 /* So long as this isn't <=IE8, add a fourth (alpha) component if it's missing and default it to 1 (visible). */ 13267 if ((!IE || IE > 8) && extracted.split(" ").length === 3) { 13268 extracted += " 1"; 13269 } 13270 13271 return extracted; 13272 case "inject": 13273 /* If we have a pattern then it might already have the right values */ 13274 if (/^rgb/.test(propertyValue)) { 13275 return propertyValue; 13276 } 13277 13278 /* If this is IE<=8 and an alpha component exists, strip it off. */ 13279 if (IE <= 8) { 13280 if (propertyValue.split(" ").length === 4) { 13281 propertyValue = propertyValue.split(/\s+/).slice(0, 3).join(" "); 13282 } 13283 /* Otherwise, add a fourth (alpha) component if it's missing and default it to 1 (visible). */ 13284 } else if (propertyValue.split(" ").length === 3) { 13285 propertyValue += " 1"; 13286 } 13287 13288 /* Re-insert the browser-appropriate wrapper("rgb/rgba()"), insert commas, and strip off decimal units 13289 on all values but the fourth (R, G, and B only accept whole numbers). */ 13290 return (IE <= 8 ? "rgb" : "rgba") + "(" + propertyValue.replace(/\s+/g, ",").replace(/\.(\d)+(?=,)/g, "") + ")"; 13291 } 13292 }; 13293 })(); 13294 } 13295 13296 /************** 13297 Dimensions 13298 **************/ 13299 function augmentDimension(name, element, wantInner) { 13300 var isBorderBox = CSS.getPropertyValue(element, "boxSizing").toString().toLowerCase() === "border-box"; 13301 13302 if (isBorderBox === (wantInner || false)) { 13303 /* in box-sizing mode, the CSS width / height accessors already give the outerWidth / outerHeight. */ 13304 var i, 13305 value, 13306 augment = 0, 13307 sides = name === "width" ? ["Left", "Right"] : ["Top", "Bottom"], 13308 fields = ["padding" + sides[0], "padding" + sides[1], "border" + sides[0] + "Width", "border" + sides[1] + "Width"]; 13309 13310 for (i = 0; i < fields.length; i++) { 13311 value = parseFloat(CSS.getPropertyValue(element, fields[i])); 13312 if (!isNaN(value)) { 13313 augment += value; 13314 } 13315 } 13316 return wantInner ? -augment : augment; 13317 } 13318 return 0; 13319 } 13320 function getDimension(name, wantInner) { 13321 return function(type, element, propertyValue) { 13322 switch (type) { 13323 case "name": 13324 return name; 13325 case "extract": 13326 return parseFloat(propertyValue) + augmentDimension(name, element, wantInner); 13327 case "inject": 13328 return (parseFloat(propertyValue) - augmentDimension(name, element, wantInner)) + "px"; 13329 } 13330 }; 13331 } 13332 CSS.Normalizations.registered.innerWidth = getDimension("width", true); 13333 CSS.Normalizations.registered.innerHeight = getDimension("height", true); 13334 CSS.Normalizations.registered.outerWidth = getDimension("width"); 13335 CSS.Normalizations.registered.outerHeight = getDimension("height"); 13336 } 13337 }, 13338 /************************ 13339 CSS Property Names 13340 ************************/ 13341 13342 Names: { 13343 /* Camelcase a property name into its JavaScript notation (e.g. "background-color" ==> "backgroundColor"). 13344 Camelcasing is used to normalize property names between and across calls. */ 13345 camelCase: function(property) { 13346 return property.replace(/-(\w)/g, function(match, subMatch) { 13347 return subMatch.toUpperCase(); 13348 }); 13349 }, 13350 /* For SVG elements, some properties (namely, dimensional ones) are GET/SET via the element's HTML attributes (instead of via CSS styles). */ 13351 SVGAttribute: function(property) { 13352 var SVGAttributes = "width|height|x|y|cx|cy|r|rx|ry|x1|x2|y1|y2"; 13353 13354 /* Certain browsers require an SVG transform to be applied as an attribute. (Otherwise, application via CSS is preferable due to 3D support.) */ 13355 if (IE || (Velocity.State.isAndroid && !Velocity.State.isChrome)) { 13356 SVGAttributes += "|transform"; 13357 } 13358 13359 return new RegExp("^(" + SVGAttributes + ")$", "i").test(property); 13360 }, 13361 /* Determine whether a property should be set with a vendor prefix. */ 13362 /* If a prefixed version of the property exists, return it. Otherwise, return the original property name. 13363 If the property is not at all supported by the browser, return a false flag. */ 13364 prefixCheck: function(property) { 13365 /* If this property has already been checked, return the cached value. */ 13366 if (Velocity.State.prefixMatches[property]) { 13367 return [Velocity.State.prefixMatches[property], true]; 13368 } else { 13369 var vendors = ["", "Webkit", "Moz", "ms", "O"]; 13370 13371 for (var i = 0, vendorsLength = vendors.length; i < vendorsLength; i++) { 13372 var propertyPrefixed; 13373 13374 if (i === 0) { 13375 propertyPrefixed = property; 13376 } else { 13377 /* Capitalize the first letter of the property to conform to JavaScript vendor prefix notation (e.g. webkitFilter). */ 13378 propertyPrefixed = vendors[i] + property.replace(/^\w/, function(match) { 13379 return match.toUpperCase(); 13380 }); 13381 } 13382 13383 /* Check if the browser supports this property as prefixed. */ 13384 if (Type.isString(Velocity.State.prefixElement.style[propertyPrefixed])) { 13385 /* Cache the match. */ 13386 Velocity.State.prefixMatches[property] = propertyPrefixed; 13387 13388 return [propertyPrefixed, true]; 13389 } 13390 } 13391 13392 /* If the browser doesn't support this property in any form, include a false flag so that the caller can decide how to proceed. */ 13393 return [property, false]; 13394 } 13395 } 13396 }, 13397 /************************ 13398 CSS Property Values 13399 ************************/ 13400 13401 Values: { 13402 /* Hex to RGB conversion. Copyright Tim Down: http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb */ 13403 hexToRgb: function(hex) { 13404 var shortformRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i, 13405 longformRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i, 13406 rgbParts; 13407 13408 hex = hex.replace(shortformRegex, function(m, r, g, b) { 13409 return r + r + g + g + b + b; 13410 }); 13411 13412 rgbParts = longformRegex.exec(hex); 13413 13414 return rgbParts ? [parseInt(rgbParts[1], 16), parseInt(rgbParts[2], 16), parseInt(rgbParts[3], 16)] : [0, 0, 0]; 13415 }, 13416 isCSSNullValue: function(value) { 13417 /* The browser defaults CSS values that have not been set to either 0 or one of several possible null-value strings. 13418 Thus, we check for both falsiness and these special strings. */ 13419 /* Null-value checking is performed to default the special strings to 0 (for the sake of tweening) or their hook 13420 templates as defined as CSS.Hooks (for the sake of hook injection/extraction). */ 13421 /* Note: Chrome returns "rgba(0, 0, 0, 0)" for an undefined color whereas IE returns "transparent". */ 13422 return (!value || /^(none|auto|transparent|(rgba\(0, ?0, ?0, ?0\)))$/i.test(value)); 13423 }, 13424 /* Retrieve a property's default unit type. Used for assigning a unit type when one is not supplied by the user. */ 13425 getUnitType: function(property) { 13426 if (/^(rotate|skew)/i.test(property)) { 13427 return "deg"; 13428 } else if (/(^(scale|scaleX|scaleY|scaleZ|alpha|flexGrow|flexHeight|zIndex|fontWeight)$)|((opacity|red|green|blue|alpha)$)/i.test(property)) { 13429 /* The above properties are unitless. */ 13430 return ""; 13431 } else { 13432 /* Default to px for all other properties. */ 13433 return "px"; 13434 } 13435 }, 13436 /* HTML elements default to an associated display type when they're not set to display:none. */ 13437 /* Note: This function is used for correctly setting the non-"none" display value in certain Velocity redirects, such as fadeIn/Out. */ 13438 getDisplayType: function(element) { 13439 var tagName = element && element.tagName.toString().toLowerCase(); 13440 13441 if (/^(b|big|i|small|tt|abbr|acronym|cite|code|dfn|em|kbd|strong|samp|var|a|bdo|br|img|map|object|q|script|span|sub|sup|button|input|label|select|textarea)$/i.test(tagName)) { 13442 return "inline"; 13443 } else if (/^(li)$/i.test(tagName)) { 13444 return "list-item"; 13445 } else if (/^(tr)$/i.test(tagName)) { 13446 return "table-row"; 13447 } else if (/^(table)$/i.test(tagName)) { 13448 return "table"; 13449 } else if (/^(tbody)$/i.test(tagName)) { 13450 return "table-row-group"; 13451 /* Default to "block" when no match is found. */ 13452 } else { 13453 return "block"; 13454 } 13455 }, 13456 /* The class add/remove functions are used to temporarily apply a "velocity-animating" class to elements while they're animating. */ 13457 addClass: function(element, className) { 13458 if (element) { 13459 if (element.classList) { 13460 element.classList.add(className); 13461 } else if (Type.isString(element.className)) { 13462 // Element.className is around 15% faster then set/getAttribute 13463 element.className += (element.className.length ? " " : "") + className; 13464 } else { 13465 // Work around for IE strict mode animating SVG - and anything else that doesn't behave correctly - the same way jQuery does it 13466 var currentClass = element.getAttribute(IE <= 7 ? "className" : "class") || ""; 13467 13468 element.setAttribute("class", currentClass + (currentClass ? " " : "") + className); 13469 } 13470 } 13471 }, 13472 removeClass: function(element, className) { 13473 if (element) { 13474 if (element.classList) { 13475 element.classList.remove(className); 13476 } else if (Type.isString(element.className)) { 13477 // Element.className is around 15% faster then set/getAttribute 13478 // TODO: Need some jsperf tests on performance - can we get rid of the regex and maybe use split / array manipulation? 13479 element.className = element.className.toString().replace(new RegExp("(^|\\s)" + className.split(" ").join("|") + "(\\s|$)", "gi"), " "); 13480 } else { 13481 // Work around for IE strict mode animating SVG - and anything else that doesn't behave correctly - the same way jQuery does it 13482 var currentClass = element.getAttribute(IE <= 7 ? "className" : "class") || ""; 13483 13484 element.setAttribute("class", currentClass.replace(new RegExp("(^|\s)" + className.split(" ").join("|") + "(\s|$)", "gi"), " ")); 13485 } 13486 } 13487 } 13488 }, 13489 /**************************** 13490 Style Getting & Setting 13491 ****************************/ 13492 13493 /* The singular getPropertyValue, which routes the logic for all normalizations, hooks, and standard CSS properties. */ 13494 getPropertyValue: function(element, property, rootPropertyValue, forceStyleLookup) { 13495 /* Get an element's computed property value. */ 13496 /* Note: Retrieving the value of a CSS property cannot simply be performed by checking an element's 13497 style attribute (which only reflects user-defined values). Instead, the browser must be queried for a property's 13498 *computed* value. You can read more about getComputedStyle here: https://developer.mozilla.org/en/docs/Web/API/window.getComputedStyle */ 13499 function computePropertyValue(element, property) { 13500 /* When box-sizing isn't set to border-box, height and width style values are incorrectly computed when an 13501 element's scrollbars are visible (which expands the element's dimensions). Thus, we defer to the more accurate 13502 offsetHeight/Width property, which includes the total dimensions for interior, border, padding, and scrollbar. 13503 We subtract border and padding to get the sum of interior + scrollbar. */ 13504 var computedValue = 0; 13505 13506 /* IE<=8 doesn't support window.getComputedStyle, thus we defer to jQuery, which has an extensive array 13507 of hacks to accurately retrieve IE8 property values. Re-implementing that logic here is not worth bloating the 13508 codebase for a dying browser. The performance repercussions of using jQuery here are minimal since 13509 Velocity is optimized to rarely (and sometimes never) query the DOM. Further, the $.css() codepath isn't that slow. */ 13510 if (IE <= 8) { 13511 computedValue = $.css(element, property); /* GET */ 13512 /* All other browsers support getComputedStyle. The returned live object reference is cached onto its 13513 associated element so that it does not need to be refetched upon every GET. */ 13514 } else { 13515 /* Browsers do not return height and width values for elements that are set to display:"none". Thus, we temporarily 13516 toggle display to the element type's default value. */ 13517 var toggleDisplay = false; 13518 13519 if (/^(width|height)$/.test(property) && CSS.getPropertyValue(element, "display") === 0) { 13520 toggleDisplay = true; 13521 CSS.setPropertyValue(element, "display", CSS.Values.getDisplayType(element)); 13522 } 13523 13524 var revertDisplay = function() { 13525 if (toggleDisplay) { 13526 CSS.setPropertyValue(element, "display", "none"); 13527 } 13528 }; 13529 13530 if (!forceStyleLookup) { 13531 if (property === "height" && CSS.getPropertyValue(element, "boxSizing").toString().toLowerCase() !== "border-box") { 13532 var contentBoxHeight = element.offsetHeight - (parseFloat(CSS.getPropertyValue(element, "borderTopWidth")) || 0) - (parseFloat(CSS.getPropertyValue(element, "borderBottomWidth")) || 0) - (parseFloat(CSS.getPropertyValue(element, "paddingTop")) || 0) - (parseFloat(CSS.getPropertyValue(element, "paddingBottom")) || 0); 13533 revertDisplay(); 13534 13535 return contentBoxHeight; 13536 } else if (property === "width" && CSS.getPropertyValue(element, "boxSizing").toString().toLowerCase() !== "border-box") { 13537 var contentBoxWidth = element.offsetWidth - (parseFloat(CSS.getPropertyValue(element, "borderLeftWidth")) || 0) - (parseFloat(CSS.getPropertyValue(element, "borderRightWidth")) || 0) - (parseFloat(CSS.getPropertyValue(element, "paddingLeft")) || 0) - (parseFloat(CSS.getPropertyValue(element, "paddingRight")) || 0); 13538 revertDisplay(); 13539 13540 return contentBoxWidth; 13541 } 13542 } 13543 13544 var computedStyle; 13545 13546 /* For elements that Velocity hasn't been called on directly (e.g. when Velocity queries the DOM on behalf 13547 of a parent of an element its animating), perform a direct getComputedStyle lookup since the object isn't cached. */ 13548 if (Data(element) === undefined) { 13549 computedStyle = window.getComputedStyle(element, null); /* GET */ 13550 /* If the computedStyle object has yet to be cached, do so now. */ 13551 } else if (!Data(element).computedStyle) { 13552 computedStyle = Data(element).computedStyle = window.getComputedStyle(element, null); /* GET */ 13553 /* If computedStyle is cached, use it. */ 13554 } else { 13555 computedStyle = Data(element).computedStyle; 13556 } 13557 13558 /* IE and Firefox do not return a value for the generic borderColor -- they only return individual values for each border side's color. 13559 Also, in all browsers, when border colors aren't all the same, a compound value is returned that Velocity isn't setup to parse. 13560 So, as a polyfill for querying individual border side colors, we just return the top border's color and animate all borders from that value. */ 13561 if (property === "borderColor") { 13562 property = "borderTopColor"; 13563 } 13564 13565 /* IE9 has a bug in which the "filter" property must be accessed from computedStyle using the getPropertyValue method 13566 instead of a direct property lookup. The getPropertyValue method is slower than a direct lookup, which is why we avoid it by default. */ 13567 if (IE === 9 && property === "filter") { 13568 computedValue = computedStyle.getPropertyValue(property); /* GET */ 13569 } else { 13570 computedValue = computedStyle[property]; 13571 } 13572 13573 /* Fall back to the property's style value (if defined) when computedValue returns nothing, 13574 which can happen when the element hasn't been painted. */ 13575 if (computedValue === "" || computedValue === null) { 13576 computedValue = element.style[property]; 13577 } 13578 13579 revertDisplay(); 13580 } 13581 13582 /* For top, right, bottom, and left (TRBL) values that are set to "auto" on elements of "fixed" or "absolute" position, 13583 defer to jQuery for converting "auto" to a numeric value. (For elements with a "static" or "relative" position, "auto" has the same 13584 effect as being set to 0, so no conversion is necessary.) */ 13585 /* An example of why numeric conversion is necessary: When an element with "position:absolute" has an untouched "left" 13586 property, which reverts to "auto", left's value is 0 relative to its parent element, but is often non-zero relative 13587 to its *containing* (not parent) element, which is the nearest "position:relative" ancestor or the viewport (and always the viewport in the case of "position:fixed"). */ 13588 if (computedValue === "auto" && /^(top|right|bottom|left)$/i.test(property)) { 13589 var position = computePropertyValue(element, "position"); /* GET */ 13590 13591 /* For absolute positioning, jQuery's $.position() only returns values for top and left; 13592 right and bottom will have their "auto" value reverted to 0. */ 13593 /* Note: A jQuery object must be created here since jQuery doesn't have a low-level alias for $.position(). 13594 Not a big deal since we're currently in a GET batch anyway. */ 13595 if (position === "fixed" || (position === "absolute" && /top|left/i.test(property))) { 13596 /* Note: jQuery strips the pixel unit from its returned values; we re-add it here to conform with computePropertyValue's behavior. */ 13597 computedValue = $(element).position()[property] + "px"; /* GET */ 13598 } 13599 } 13600 13601 return computedValue; 13602 } 13603 13604 var propertyValue; 13605 13606 /* If this is a hooked property (e.g. "clipLeft" instead of the root property of "clip"), 13607 extract the hook's value from a normalized rootPropertyValue using CSS.Hooks.extractValue(). */ 13608 if (CSS.Hooks.registered[property]) { 13609 var hook = property, 13610 hookRoot = CSS.Hooks.getRoot(hook); 13611 13612 /* If a cached rootPropertyValue wasn't passed in (which Velocity always attempts to do in order to avoid requerying the DOM), 13613 query the DOM for the root property's value. */ 13614 if (rootPropertyValue === undefined) { 13615 /* Since the browser is now being directly queried, use the official post-prefixing property name for this lookup. */ 13616 rootPropertyValue = CSS.getPropertyValue(element, CSS.Names.prefixCheck(hookRoot)[0]); /* GET */ 13617 } 13618 13619 /* If this root has a normalization registered, peform the associated normalization extraction. */ 13620 if (CSS.Normalizations.registered[hookRoot]) { 13621 rootPropertyValue = CSS.Normalizations.registered[hookRoot]("extract", element, rootPropertyValue); 13622 } 13623 13624 /* Extract the hook's value. */ 13625 propertyValue = CSS.Hooks.extractValue(hook, rootPropertyValue); 13626 13627 /* If this is a normalized property (e.g. "opacity" becomes "filter" in <=IE8) or "translateX" becomes "transform"), 13628 normalize the property's name and value, and handle the special case of transforms. */ 13629 /* Note: Normalizing a property is mutually exclusive from hooking a property since hook-extracted values are strictly 13630 numerical and therefore do not require normalization extraction. */ 13631 } else if (CSS.Normalizations.registered[property]) { 13632 var normalizedPropertyName, 13633 normalizedPropertyValue; 13634 13635 normalizedPropertyName = CSS.Normalizations.registered[property]("name", element); 13636 13637 /* Transform values are calculated via normalization extraction (see below), which checks against the element's transformCache. 13638 At no point do transform GETs ever actually query the DOM; initial stylesheet values are never processed. 13639 This is because parsing 3D transform matrices is not always accurate and would bloat our codebase; 13640 thus, normalization extraction defaults initial transform values to their zero-values (e.g. 1 for scaleX and 0 for translateX). */ 13641 if (normalizedPropertyName !== "transform") { 13642 normalizedPropertyValue = computePropertyValue(element, CSS.Names.prefixCheck(normalizedPropertyName)[0]); /* GET */ 13643 13644 /* If the value is a CSS null-value and this property has a hook template, use that zero-value template so that hooks can be extracted from it. */ 13645 if (CSS.Values.isCSSNullValue(normalizedPropertyValue) && CSS.Hooks.templates[property]) { 13646 normalizedPropertyValue = CSS.Hooks.templates[property][1]; 13647 } 13648 } 13649 13650 propertyValue = CSS.Normalizations.registered[property]("extract", element, normalizedPropertyValue); 13651 } 13652 13653 /* If a (numeric) value wasn't produced via hook extraction or normalization, query the DOM. */ 13654 if (!/^[\d-]/.test(propertyValue)) { 13655 /* For SVG elements, dimensional properties (which SVGAttribute() detects) are tweened via 13656 their HTML attribute values instead of their CSS style values. */ 13657 var data = Data(element); 13658 13659 if (data && data.isSVG && CSS.Names.SVGAttribute(property)) { 13660 /* Since the height/width attribute values must be set manually, they don't reflect computed values. 13661 Thus, we use use getBBox() to ensure we always get values for elements with undefined height/width attributes. */ 13662 if (/^(height|width)$/i.test(property)) { 13663 /* Firefox throws an error if .getBBox() is called on an SVG that isn't attached to the DOM. */ 13664 try { 13665 propertyValue = element.getBBox()[property]; 13666 } catch (error) { 13667 propertyValue = 0; 13668 } 13669 /* Otherwise, access the attribute value directly. */ 13670 } else { 13671 propertyValue = element.getAttribute(property); 13672 } 13673 } else { 13674 propertyValue = computePropertyValue(element, CSS.Names.prefixCheck(property)[0]); /* GET */ 13675 } 13676 } 13677 13678 /* Since property lookups are for animation purposes (which entails computing the numeric delta between start and end values), 13679 convert CSS null-values to an integer of value 0. */ 13680 if (CSS.Values.isCSSNullValue(propertyValue)) { 13681 propertyValue = 0; 13682 } 13683 13684 if (Velocity.debug >= 2) { 13685 console.log("Get " + property + ": " + propertyValue); 13686 } 13687 13688 return propertyValue; 13689 }, 13690 /* The singular setPropertyValue, which routes the logic for all normalizations, hooks, and standard CSS properties. */ 13691 setPropertyValue: function(element, property, propertyValue, rootPropertyValue, scrollData) { 13692 var propertyName = property; 13693 13694 /* In order to be subjected to call options and element queueing, scroll animation is routed through Velocity as if it were a standard CSS property. */ 13695 if (property === "scroll") { 13696 /* If a container option is present, scroll the container instead of the browser window. */ 13697 if (scrollData.container) { 13698 scrollData.container["scroll" + scrollData.direction] = propertyValue; 13699 /* Otherwise, Velocity defaults to scrolling the browser window. */ 13700 } else { 13701 if (scrollData.direction === "Left") { 13702 window.scrollTo(propertyValue, scrollData.alternateValue); 13703 } else { 13704 window.scrollTo(scrollData.alternateValue, propertyValue); 13705 } 13706 } 13707 } else { 13708 /* Transforms (translateX, rotateZ, etc.) are applied to a per-element transformCache object, which is manually flushed via flushTransformCache(). 13709 Thus, for now, we merely cache transforms being SET. */ 13710 if (CSS.Normalizations.registered[property] && CSS.Normalizations.registered[property]("name", element) === "transform") { 13711 /* Perform a normalization injection. */ 13712 /* Note: The normalization logic handles the transformCache updating. */ 13713 CSS.Normalizations.registered[property]("inject", element, propertyValue); 13714 13715 propertyName = "transform"; 13716 propertyValue = Data(element).transformCache[property]; 13717 } else { 13718 /* Inject hooks. */ 13719 if (CSS.Hooks.registered[property]) { 13720 var hookName = property, 13721 hookRoot = CSS.Hooks.getRoot(property); 13722 13723 /* If a cached rootPropertyValue was not provided, query the DOM for the hookRoot's current value. */ 13724 rootPropertyValue = rootPropertyValue || CSS.getPropertyValue(element, hookRoot); /* GET */ 13725 13726 propertyValue = CSS.Hooks.injectValue(hookName, propertyValue, rootPropertyValue); 13727 property = hookRoot; 13728 } 13729 13730 /* Normalize names and values. */ 13731 if (CSS.Normalizations.registered[property]) { 13732 propertyValue = CSS.Normalizations.registered[property]("inject", element, propertyValue); 13733 property = CSS.Normalizations.registered[property]("name", element); 13734 } 13735 13736 /* Assign the appropriate vendor prefix before performing an official style update. */ 13737 propertyName = CSS.Names.prefixCheck(property)[0]; 13738 13739 /* A try/catch is used for IE<=8, which throws an error when "invalid" CSS values are set, e.g. a negative width. 13740 Try/catch is avoided for other browsers since it incurs a performance overhead. */ 13741 if (IE <= 8) { 13742 try { 13743 element.style[propertyName] = propertyValue; 13744 } catch (error) { 13745 if (Velocity.debug) { 13746 console.log("Browser does not support [" + propertyValue + "] for [" + propertyName + "]"); 13747 } 13748 } 13749 /* SVG elements have their dimensional properties (width, height, x, y, cx, etc.) applied directly as attributes instead of as styles. */ 13750 /* Note: IE8 does not support SVG elements, so it's okay that we skip it for SVG animation. */ 13751 } else { 13752 var data = Data(element); 13753 13754 if (data && data.isSVG && CSS.Names.SVGAttribute(property)) { 13755 /* Note: For SVG attributes, vendor-prefixed property names are never used. */ 13756 /* Note: Not all CSS properties can be animated via attributes, but the browser won't throw an error for unsupported properties. */ 13757 element.setAttribute(property, propertyValue); 13758 } else { 13759 element.style[propertyName] = propertyValue; 13760 } 13761 } 13762 13763 if (Velocity.debug >= 2) { 13764 console.log("Set " + property + " (" + propertyName + "): " + propertyValue); 13765 } 13766 } 13767 } 13768 13769 /* Return the normalized property name and value in case the caller wants to know how these values were modified before being applied to the DOM. */ 13770 return [propertyName, propertyValue]; 13771 }, 13772 /* To increase performance by batching transform updates into a single SET, transforms are not directly applied to an element until flushTransformCache() is called. */ 13773 /* Note: Velocity applies transform properties in the same order that they are chronogically introduced to the element's CSS styles. */ 13774 flushTransformCache: function(element) { 13775 var transformString = "", 13776 data = Data(element); 13777 13778 /* Certain browsers require that SVG transforms be applied as an attribute. However, the SVG transform attribute takes a modified version of CSS's transform string 13779 (units are dropped and, except for skewX/Y, subproperties are merged into their master property -- e.g. scaleX and scaleY are merged into scale(X Y). */ 13780 if ((IE || (Velocity.State.isAndroid && !Velocity.State.isChrome)) && data && data.isSVG) { 13781 /* Since transform values are stored in their parentheses-wrapped form, we use a helper function to strip out their numeric values. 13782 Further, SVG transform properties only take unitless (representing pixels) values, so it's okay that parseFloat() strips the unit suffixed to the float value. */ 13783 var getTransformFloat = function(transformProperty) { 13784 return parseFloat(CSS.getPropertyValue(element, transformProperty)); 13785 }; 13786 13787 /* Create an object to organize all the transforms that we'll apply to the SVG element. To keep the logic simple, 13788 we process *all* transform properties -- even those that may not be explicitly applied (since they default to their zero-values anyway). */ 13789 var SVGTransforms = { 13790 translate: [getTransformFloat("translateX"), getTransformFloat("translateY")], 13791 skewX: [getTransformFloat("skewX")], skewY: [getTransformFloat("skewY")], 13792 /* If the scale property is set (non-1), use that value for the scaleX and scaleY values 13793 (this behavior mimics the result of animating all these properties at once on HTML elements). */ 13794 scale: getTransformFloat("scale") !== 1 ? [getTransformFloat("scale"), getTransformFloat("scale")] : [getTransformFloat("scaleX"), getTransformFloat("scaleY")], 13795 /* Note: SVG's rotate transform takes three values: rotation degrees followed by the X and Y values 13796 defining the rotation's origin point. We ignore the origin values (default them to 0). */ 13797 rotate: [getTransformFloat("rotateZ"), 0, 0] 13798 }; 13799 13800 /* Iterate through the transform properties in the user-defined property map order. 13801 (This mimics the behavior of non-SVG transform animation.) */ 13802 $.each(Data(element).transformCache, function(transformName) { 13803 /* Except for with skewX/Y, revert the axis-specific transform subproperties to their axis-free master 13804 properties so that they match up with SVG's accepted transform properties. */ 13805 if (/^translate/i.test(transformName)) { 13806 transformName = "translate"; 13807 } else if (/^scale/i.test(transformName)) { 13808 transformName = "scale"; 13809 } else if (/^rotate/i.test(transformName)) { 13810 transformName = "rotate"; 13811 } 13812 13813 /* Check that we haven't yet deleted the property from the SVGTransforms container. */ 13814 if (SVGTransforms[transformName]) { 13815 /* Append the transform property in the SVG-supported transform format. As per the spec, surround the space-delimited values in parentheses. */ 13816 transformString += transformName + "(" + SVGTransforms[transformName].join(" ") + ")" + " "; 13817 13818 /* After processing an SVG transform property, delete it from the SVGTransforms container so we don't 13819 re-insert the same master property if we encounter another one of its axis-specific properties. */ 13820 delete SVGTransforms[transformName]; 13821 } 13822 }); 13823 } else { 13824 var transformValue, 13825 perspective; 13826 13827 /* Transform properties are stored as members of the transformCache object. Concatenate all the members into a string. */ 13828 $.each(Data(element).transformCache, function(transformName) { 13829 transformValue = Data(element).transformCache[transformName]; 13830 13831 /* Transform's perspective subproperty must be set first in order to take effect. Store it temporarily. */ 13832 if (transformName === "transformPerspective") { 13833 perspective = transformValue; 13834 return true; 13835 } 13836 13837 /* IE9 only supports one rotation type, rotateZ, which it refers to as "rotate". */ 13838 if (IE === 9 && transformName === "rotateZ") { 13839 transformName = "rotate"; 13840 } 13841 13842 transformString += transformName + transformValue + " "; 13843 }); 13844 13845 /* If present, set the perspective subproperty first. */ 13846 if (perspective) { 13847 transformString = "perspective" + perspective + " " + transformString; 13848 } 13849 } 13850 13851 CSS.setPropertyValue(element, "transform", transformString); 13852 } 13853 }; 13854 13855 /* Register hooks and normalizations. */ 13856 CSS.Hooks.register(); 13857 CSS.Normalizations.register(); 13858 13859 /* Allow hook setting in the same fashion as jQuery's $.css(). */ 13860 Velocity.hook = function(elements, arg2, arg3) { 13861 var value; 13862 13863 elements = sanitizeElements(elements); 13864 13865 $.each(elements, function(i, element) { 13866 /* Initialize Velocity's per-element data cache if this element hasn't previously been animated. */ 13867 if (Data(element) === undefined) { 13868 Velocity.init(element); 13869 } 13870 13871 /* Get property value. If an element set was passed in, only return the value for the first element. */ 13872 if (arg3 === undefined) { 13873 if (value === undefined) { 13874 value = CSS.getPropertyValue(element, arg2); 13875 } 13876 /* Set property value. */ 13877 } else { 13878 /* sPV returns an array of the normalized propertyName/propertyValue pair used to update the DOM. */ 13879 var adjustedSet = CSS.setPropertyValue(element, arg2, arg3); 13880 13881 /* Transform properties don't automatically set. They have to be flushed to the DOM. */ 13882 if (adjustedSet[0] === "transform") { 13883 Velocity.CSS.flushTransformCache(element); 13884 } 13885 13886 value = adjustedSet; 13887 } 13888 }); 13889 13890 return value; 13891 }; 13892 13893 /***************** 13894 Animation 13895 *****************/ 13896 13897 var animate = function() { 13898 var opts; 13899 13900 /****************** 13901 Call Chain 13902 ******************/ 13903 13904 /* Logic for determining what to return to the call stack when exiting out of Velocity. */ 13905 function getChain() { 13906 /* If we are using the utility function, attempt to return this call's promise. If no promise library was detected, 13907 default to null instead of returning the targeted elements so that utility function's return value is standardized. */ 13908 if (isUtility) { 13909 return promiseData.promise || null; 13910 /* Otherwise, if we're using $.fn, return the jQuery-/Zepto-wrapped element set. */ 13911 } else { 13912 return elementsWrapped; 13913 } 13914 } 13915 13916 /************************* 13917 Arguments Assignment 13918 *************************/ 13919 13920 /* To allow for expressive CoffeeScript code, Velocity supports an alternative syntax in which "elements" (or "e"), "properties" (or "p"), and "options" (or "o") 13921 objects are defined on a container object that's passed in as Velocity's sole argument. */ 13922 /* Note: Some browsers automatically populate arguments with a "properties" object. We detect it by checking for its default "names" property. */ 13923 var syntacticSugar = (arguments[0] && (arguments[0].p || (($.isPlainObject(arguments[0].properties) && !arguments[0].properties.names) || Type.isString(arguments[0].properties)))), 13924 /* Whether Velocity was called via the utility function (as opposed to on a jQuery/Zepto object). */ 13925 isUtility, 13926 /* When Velocity is called via the utility function ($.Velocity()/Velocity()), elements are explicitly 13927 passed in as the first parameter. Thus, argument positioning varies. We normalize them here. */ 13928 elementsWrapped, 13929 argumentIndex; 13930 13931 var elements, 13932 propertiesMap, 13933 options; 13934 13935 /* Detect jQuery/Zepto elements being animated via the $.fn method. */ 13936 if (Type.isWrapped(this)) { 13937 isUtility = false; 13938 13939 argumentIndex = 0; 13940 elements = this; 13941 elementsWrapped = this; 13942 /* Otherwise, raw elements are being animated via the utility function. */ 13943 } else { 13944 isUtility = true; 13945 13946 argumentIndex = 1; 13947 elements = syntacticSugar ? (arguments[0].elements || arguments[0].e) : arguments[0]; 13948 } 13949 13950 /*************** 13951 Promises 13952 ***************/ 13953 13954 var promiseData = { 13955 promise: null, 13956 resolver: null, 13957 rejecter: null 13958 }; 13959 13960 /* If this call was made via the utility function (which is the default method of invocation when jQuery/Zepto are not being used), and if 13961 promise support was detected, create a promise object for this call and store references to its resolver and rejecter methods. The resolve 13962 method is used when a call completes naturally or is prematurely stopped by the user. In both cases, completeCall() handles the associated 13963 call cleanup and promise resolving logic. The reject method is used when an invalid set of arguments is passed into a Velocity call. */ 13964 /* Note: Velocity employs a call-based queueing architecture, which means that stopping an animating element actually stops the full call that 13965 triggered it -- not that one element exclusively. Similarly, there is one promise per call, and all elements targeted by a Velocity call are 13966 grouped together for the purposes of resolving and rejecting a promise. */ 13967 if (isUtility && Velocity.Promise) { 13968 promiseData.promise = new Velocity.Promise(function(resolve, reject) { 13969 promiseData.resolver = resolve; 13970 promiseData.rejecter = reject; 13971 }); 13972 } 13973 13974 if (syntacticSugar) { 13975 propertiesMap = arguments[0].properties || arguments[0].p; 13976 options = arguments[0].options || arguments[0].o; 13977 } else { 13978 propertiesMap = arguments[argumentIndex]; 13979 options = arguments[argumentIndex + 1]; 13980 } 13981 13982 elements = sanitizeElements(elements); 13983 13984 if (!elements) { 13985 if (promiseData.promise) { 13986 if (!propertiesMap || !options || options.promiseRejectEmpty !== false) { 13987 promiseData.rejecter(); 13988 } else { 13989 promiseData.resolver(); 13990 } 13991 } 13992 return; 13993 } 13994 13995 /* The length of the element set (in the form of a nodeList or an array of elements) is defaulted to 1 in case a 13996 single raw DOM element is passed in (which doesn't contain a length property). */ 13997 var elementsLength = elements.length, 13998 elementsIndex = 0; 13999 14000 /*************************** 14001 Argument Overloading 14002 ***************************/ 14003 14004 /* Support is included for jQuery's argument overloading: $.animate(propertyMap [, duration] [, easing] [, complete]). 14005 Overloading is detected by checking for the absence of an object being passed into options. */ 14006 /* Note: The stop/finish/pause/resume actions do not accept animation options, and are therefore excluded from this check. */ 14007 if (!/^(stop|finish|finishAll|pause|resume)$/i.test(propertiesMap) && !$.isPlainObject(options)) { 14008 /* The utility function shifts all arguments one position to the right, so we adjust for that offset. */ 14009 var startingArgumentPosition = argumentIndex + 1; 14010 14011 options = {}; 14012 14013 /* Iterate through all options arguments */ 14014 for (var i = startingArgumentPosition; i < arguments.length; i++) { 14015 /* Treat a number as a duration. Parse it out. */ 14016 /* Note: The following RegEx will return true if passed an array with a number as its first item. 14017 Thus, arrays are skipped from this check. */ 14018 if (!Type.isArray(arguments[i]) && (/^(fast|normal|slow)$/i.test(arguments[i]) || /^\d/.test(arguments[i]))) { 14019 options.duration = arguments[i]; 14020 /* Treat strings and arrays as easings. */ 14021 } else if (Type.isString(arguments[i]) || Type.isArray(arguments[i])) { 14022 options.easing = arguments[i]; 14023 /* Treat a function as a complete callback. */ 14024 } else if (Type.isFunction(arguments[i])) { 14025 options.complete = arguments[i]; 14026 } 14027 } 14028 } 14029 14030 /********************* 14031 Action Detection 14032 *********************/ 14033 14034 /* Velocity's behavior is categorized into "actions": Elements can either be specially scrolled into view, 14035 or they can be started, stopped, paused, resumed, or reversed . If a literal or referenced properties map is passed in as Velocity's 14036 first argument, the associated action is "start". Alternatively, "scroll", "reverse", "pause", "resume" or "stop" can be passed in 14037 instead of a properties map. */ 14038 var action; 14039 14040 switch (propertiesMap) { 14041 case "scroll": 14042 action = "scroll"; 14043 break; 14044 14045 case "reverse": 14046 action = "reverse"; 14047 break; 14048 14049 case "pause": 14050 14051 /******************* 14052 Action: Pause 14053 *******************/ 14054 14055 var currentTime = (new Date()).getTime(); 14056 14057 /* Handle delay timers */ 14058 $.each(elements, function(i, element) { 14059 pauseDelayOnElement(element, currentTime); 14060 }); 14061 14062 /* Pause and Resume are call-wide (not on a per element basis). Thus, calling pause or resume on a 14063 single element will cause any calls that containt tweens for that element to be paused/resumed 14064 as well. */ 14065 14066 /* Iterate through all calls and pause any that contain any of our elements */ 14067 $.each(Velocity.State.calls, function(i, activeCall) { 14068 14069 var found = false; 14070 /* Inactive calls are set to false by the logic inside completeCall(). Skip them. */ 14071 if (activeCall) { 14072 /* Iterate through the active call's targeted elements. */ 14073 $.each(activeCall[1], function(k, activeElement) { 14074 var queueName = (options === undefined) ? "" : options; 14075 14076 if (queueName !== true && (activeCall[2].queue !== queueName) && !(options === undefined && activeCall[2].queue === false)) { 14077 return true; 14078 } 14079 14080 /* Iterate through the calls targeted by the stop command. */ 14081 $.each(elements, function(l, element) { 14082 /* Check that this call was applied to the target element. */ 14083 if (element === activeElement) { 14084 14085 /* Set call to paused */ 14086 activeCall[5] = { 14087 resume: false 14088 }; 14089 14090 /* Once we match an element, we can bounce out to the next call entirely */ 14091 found = true; 14092 return false; 14093 } 14094 }); 14095 14096 /* Proceed to check next call if we have already matched */ 14097 if (found) { 14098 return false; 14099 } 14100 }); 14101 } 14102 14103 }); 14104 14105 /* Since pause creates no new tweens, exit out of Velocity. */ 14106 return getChain(); 14107 14108 case "resume": 14109 14110 /******************* 14111 Action: Resume 14112 *******************/ 14113 14114 /* Handle delay timers */ 14115 $.each(elements, function(i, element) { 14116 resumeDelayOnElement(element, currentTime); 14117 }); 14118 14119 /* Pause and Resume are call-wide (not on a per elemnt basis). Thus, calling pause or resume on a 14120 single element will cause any calls that containt tweens for that element to be paused/resumed 14121 as well. */ 14122 14123 /* Iterate through all calls and pause any that contain any of our elements */ 14124 $.each(Velocity.State.calls, function(i, activeCall) { 14125 var found = false; 14126 /* Inactive calls are set to false by the logic inside completeCall(). Skip them. */ 14127 if (activeCall) { 14128 /* Iterate through the active call's targeted elements. */ 14129 $.each(activeCall[1], function(k, activeElement) { 14130 var queueName = (options === undefined) ? "" : options; 14131 14132 if (queueName !== true && (activeCall[2].queue !== queueName) && !(options === undefined && activeCall[2].queue === false)) { 14133 return true; 14134 } 14135 14136 /* Skip any calls that have never been paused */ 14137 if (!activeCall[5]) { 14138 return true; 14139 } 14140 14141 /* Iterate through the calls targeted by the stop command. */ 14142 $.each(elements, function(l, element) { 14143 /* Check that this call was applied to the target element. */ 14144 if (element === activeElement) { 14145 14146 /* Flag a pause object to be resumed, which will occur during the next tick. In 14147 addition, the pause object will at that time be deleted */ 14148 activeCall[5].resume = true; 14149 14150 /* Once we match an element, we can bounce out to the next call entirely */ 14151 found = true; 14152 return false; 14153 } 14154 }); 14155 14156 /* Proceed to check next call if we have already matched */ 14157 if (found) { 14158 return false; 14159 } 14160 }); 14161 } 14162 14163 }); 14164 14165 /* Since resume creates no new tweens, exit out of Velocity. */ 14166 return getChain(); 14167 14168 case "finish": 14169 case "finishAll": 14170 case "stop": 14171 /******************* 14172 Action: Stop 14173 *******************/ 14174 14175 /* Clear the currently-active delay on each targeted element. */ 14176 $.each(elements, function(i, element) { 14177 if (Data(element) && Data(element).delayTimer) { 14178 /* Stop the timer from triggering its cached next() function. */ 14179 clearTimeout(Data(element).delayTimer.setTimeout); 14180 14181 /* Manually call the next() function so that the subsequent queue items can progress. */ 14182 if (Data(element).delayTimer.next) { 14183 Data(element).delayTimer.next(); 14184 } 14185 14186 delete Data(element).delayTimer; 14187 } 14188 14189 /* If we want to finish everything in the queue, we have to iterate through it 14190 and call each function. This will make them active calls below, which will 14191 cause them to be applied via the duration setting. */ 14192 if (propertiesMap === "finishAll" && (options === true || Type.isString(options))) { 14193 /* Iterate through the items in the element's queue. */ 14194 $.each($.queue(element, Type.isString(options) ? options : ""), function(_, item) { 14195 /* The queue array can contain an "inprogress" string, which we skip. */ 14196 if (Type.isFunction(item)) { 14197 item(); 14198 } 14199 }); 14200 14201 /* Clearing the $.queue() array is achieved by resetting it to []. */ 14202 $.queue(element, Type.isString(options) ? options : "", []); 14203 } 14204 }); 14205 14206 var callsToStop = []; 14207 14208 /* When the stop action is triggered, the elements' currently active call is immediately stopped. The active call might have 14209 been applied to multiple elements, in which case all of the call's elements will be stopped. When an element 14210 is stopped, the next item in its animation queue is immediately triggered. */ 14211 /* An additional argument may be passed in to clear an element's remaining queued calls. Either true (which defaults to the "fx" queue) 14212 or a custom queue string can be passed in. */ 14213 /* Note: The stop command runs prior to Velocity's Queueing phase since its behavior is intended to take effect *immediately*, 14214 regardless of the element's current queue state. */ 14215 14216 /* Iterate through every active call. */ 14217 $.each(Velocity.State.calls, function(i, activeCall) { 14218 /* Inactive calls are set to false by the logic inside completeCall(). Skip them. */ 14219 if (activeCall) { 14220 /* Iterate through the active call's targeted elements. */ 14221 $.each(activeCall[1], function(k, activeElement) { 14222 /* If true was passed in as a secondary argument, clear absolutely all calls on this element. Otherwise, only 14223 clear calls associated with the relevant queue. */ 14224 /* Call stopping logic works as follows: 14225 - options === true --> stop current default queue calls (and queue:false calls), including remaining queued ones. 14226 - options === undefined --> stop current queue:"" call and all queue:false calls. 14227 - options === false --> stop only queue:false calls. 14228 - options === "custom" --> stop current queue:"custom" call, including remaining queued ones (there is no functionality to only clear the currently-running queue:"custom" call). */ 14229 var queueName = (options === undefined) ? "" : options; 14230 14231 if (queueName !== true && (activeCall[2].queue !== queueName) && !(options === undefined && activeCall[2].queue === false)) { 14232 return true; 14233 } 14234 14235 /* Iterate through the calls targeted by the stop command. */ 14236 $.each(elements, function(l, element) { 14237 /* Check that this call was applied to the target element. */ 14238 if (element === activeElement) { 14239 /* Optionally clear the remaining queued calls. If we're doing "finishAll" this won't find anything, 14240 due to the queue-clearing above. */ 14241 if (options === true || Type.isString(options)) { 14242 /* Iterate through the items in the element's queue. */ 14243 $.each($.queue(element, Type.isString(options) ? options : ""), function(_, item) { 14244 /* The queue array can contain an "inprogress" string, which we skip. */ 14245 if (Type.isFunction(item)) { 14246 /* Pass the item's callback a flag indicating that we want to abort from the queue call. 14247 (Specifically, the queue will resolve the call's associated promise then abort.) */ 14248 item(null, true); 14249 } 14250 }); 14251 14252 /* Clearing the $.queue() array is achieved by resetting it to []. */ 14253 $.queue(element, Type.isString(options) ? options : "", []); 14254 } 14255 14256 if (propertiesMap === "stop") { 14257 /* Since "reverse" uses cached start values (the previous call's endValues), these values must be 14258 changed to reflect the final value that the elements were actually tweened to. */ 14259 /* Note: If only queue:false animations are currently running on an element, it won't have a tweensContainer 14260 object. Also, queue:false animations can't be reversed. */ 14261 var data = Data(element); 14262 if (data && data.tweensContainer && queueName !== false) { 14263 $.each(data.tweensContainer, function(m, activeTween) { 14264 activeTween.endValue = activeTween.currentValue; 14265 }); 14266 } 14267 14268 callsToStop.push(i); 14269 } else if (propertiesMap === "finish" || propertiesMap === "finishAll") { 14270 /* To get active tweens to finish immediately, we forcefully shorten their durations to 1ms so that 14271 they finish upon the next rAf tick then proceed with normal call completion logic. */ 14272 activeCall[2].duration = 1; 14273 } 14274 } 14275 }); 14276 }); 14277 } 14278 }); 14279 14280 /* Prematurely call completeCall() on each matched active call. Pass an additional flag for "stop" to indicate 14281 that the complete callback and display:none setting should be skipped since we're completing prematurely. */ 14282 if (propertiesMap === "stop") { 14283 $.each(callsToStop, function(i, j) { 14284 completeCall(j, true); 14285 }); 14286 14287 if (promiseData.promise) { 14288 /* Immediately resolve the promise associated with this stop call since stop runs synchronously. */ 14289 promiseData.resolver(elements); 14290 } 14291 } 14292 14293 /* Since we're stopping, and not proceeding with queueing, exit out of Velocity. */ 14294 return getChain(); 14295 14296 default: 14297 /* Treat a non-empty plain object as a literal properties map. */ 14298 if ($.isPlainObject(propertiesMap) && !Type.isEmptyObject(propertiesMap)) { 14299 action = "start"; 14300 14301 /**************** 14302 Redirects 14303 ****************/ 14304 14305 /* Check if a string matches a registered redirect (see Redirects above). */ 14306 } else if (Type.isString(propertiesMap) && Velocity.Redirects[propertiesMap]) { 14307 opts = $.extend({}, options); 14308 14309 var durationOriginal = opts.duration, 14310 delayOriginal = opts.delay || 0; 14311 14312 /* If the backwards option was passed in, reverse the element set so that elements animate from the last to the first. */ 14313 if (opts.backwards === true) { 14314 elements = $.extend(true, [], elements).reverse(); 14315 } 14316 14317 /* Individually trigger the redirect for each element in the set to prevent users from having to handle iteration logic in their redirect. */ 14318 $.each(elements, function(elementIndex, element) { 14319 /* If the stagger option was passed in, successively delay each element by the stagger value (in ms). Retain the original delay value. */ 14320 if (parseFloat(opts.stagger)) { 14321 opts.delay = delayOriginal + (parseFloat(opts.stagger) * elementIndex); 14322 } else if (Type.isFunction(opts.stagger)) { 14323 opts.delay = delayOriginal + opts.stagger.call(element, elementIndex, elementsLength); 14324 } 14325 14326 /* If the drag option was passed in, successively increase/decrease (depending on the presense of opts.backwards) 14327 the duration of each element's animation, using floors to prevent producing very short durations. */ 14328 if (opts.drag) { 14329 /* Default the duration of UI pack effects (callouts and transitions) to 1000ms instead of the usual default duration of 400ms. */ 14330 opts.duration = parseFloat(durationOriginal) || (/^(callout|transition)/.test(propertiesMap) ? 1000 : DURATION_DEFAULT); 14331 14332 /* For each element, take the greater duration of: A) animation completion percentage relative to the original duration, 14333 B) 75% of the original duration, or C) a 200ms fallback (in case duration is already set to a low value). 14334 The end result is a baseline of 75% of the redirect's duration that increases/decreases as the end of the element set is approached. */ 14335 opts.duration = Math.max(opts.duration * (opts.backwards ? 1 - elementIndex / elementsLength : (elementIndex + 1) / elementsLength), opts.duration * 0.75, 200); 14336 } 14337 14338 /* Pass in the call's opts object so that the redirect can optionally extend it. It defaults to an empty object instead of null to 14339 reduce the opts checking logic required inside the redirect. */ 14340 Velocity.Redirects[propertiesMap].call(element, element, opts || {}, elementIndex, elementsLength, elements, promiseData.promise ? promiseData : undefined); 14341 }); 14342 14343 /* Since the animation logic resides within the redirect's own code, abort the remainder of this call. 14344 (The performance overhead up to this point is virtually non-existant.) */ 14345 /* Note: The jQuery call chain is kept intact by returning the complete element set. */ 14346 return getChain(); 14347 } else { 14348 var abortError = "Velocity: First argument (" + propertiesMap + ") was not a property map, a known action, or a registered redirect. Aborting."; 14349 14350 if (promiseData.promise) { 14351 promiseData.rejecter(new Error(abortError)); 14352 } else if (window.console) { 14353 console.log(abortError); 14354 } 14355 14356 return getChain(); 14357 } 14358 } 14359 14360 /************************** 14361 Call-Wide Variables 14362 **************************/ 14363 14364 /* A container for CSS unit conversion ratios (e.g. %, rem, and em ==> px) that is used to cache ratios across all elements 14365 being animated in a single Velocity call. Calculating unit ratios necessitates DOM querying and updating, and is therefore 14366 avoided (via caching) wherever possible. This container is call-wide instead of page-wide to avoid the risk of using stale 14367 conversion metrics across Velocity animations that are not immediately consecutively chained. */ 14368 var callUnitConversionData = { 14369 lastParent: null, 14370 lastPosition: null, 14371 lastFontSize: null, 14372 lastPercentToPxWidth: null, 14373 lastPercentToPxHeight: null, 14374 lastEmToPx: null, 14375 remToPx: null, 14376 vwToPx: null, 14377 vhToPx: null 14378 }; 14379 14380 /* A container for all the ensuing tween data and metadata associated with this call. This container gets pushed to the page-wide 14381 Velocity.State.calls array that is processed during animation ticking. */ 14382 var call = []; 14383 14384 /************************ 14385 Element Processing 14386 ************************/ 14387 14388 /* Element processing consists of three parts -- data processing that cannot go stale and data processing that *can* go stale (i.e. third-party style modifications): 14389 1) Pre-Queueing: Element-wide variables, including the element's data storage, are instantiated. Call options are prepared. If triggered, the Stop action is executed. 14390 2) Queueing: The logic that runs once this call has reached its point of execution in the element's $.queue() stack. Most logic is placed here to avoid risking it becoming stale. 14391 3) Pushing: Consolidation of the tween data followed by its push onto the global in-progress calls container. 14392 `elementArrayIndex` allows passing index of the element in the original array to value functions. 14393 If `elementsIndex` were used instead the index would be determined by the elements' per-element queue. 14394 */ 14395 function processElement(element, elementArrayIndex) { 14396 14397 /************************* 14398 Part I: Pre-Queueing 14399 *************************/ 14400 14401 /*************************** 14402 Element-Wide Variables 14403 ***************************/ 14404 14405 var /* The runtime opts object is the extension of the current call's options and Velocity's page-wide option defaults. */ 14406 opts = $.extend({}, Velocity.defaults, options), 14407 /* A container for the processed data associated with each property in the propertyMap. 14408 (Each property in the map produces its own "tween".) */ 14409 tweensContainer = {}, 14410 elementUnitConversionData; 14411 14412 /****************** 14413 Element Init 14414 ******************/ 14415 14416 if (Data(element) === undefined) { 14417 Velocity.init(element); 14418 } 14419 14420 /****************** 14421 Option: Delay 14422 ******************/ 14423 14424 /* Since queue:false doesn't respect the item's existing queue, we avoid injecting its delay here (it's set later on). */ 14425 /* Note: Velocity rolls its own delay function since jQuery doesn't have a utility alias for $.fn.delay() 14426 (and thus requires jQuery element creation, which we avoid since its overhead includes DOM querying). */ 14427 if (parseFloat(opts.delay) && opts.queue !== false) { 14428 $.queue(element, opts.queue, function(next, clearQueue) { 14429 if (clearQueue === true) { 14430 /* Do not continue with animation queueing. */ 14431 return true; 14432 } 14433 14434 /* This is a flag used to indicate to the upcoming completeCall() function that this queue entry was initiated by Velocity. See completeCall() for further details. */ 14435 Velocity.velocityQueueEntryFlag = true; 14436 14437 /* The ensuing queue item (which is assigned to the "next" argument that $.queue() automatically passes in) will be triggered after a setTimeout delay. 14438 The setTimeout is stored so that it can be subjected to clearTimeout() if this animation is prematurely stopped via Velocity's "stop" command, and 14439 delayBegin/delayTime is used to ensure we can "pause" and "resume" a tween that is still mid-delay. */ 14440 14441 /* Temporarily store delayed elements to facilite access for global pause/resume */ 14442 var callIndex = Velocity.State.delayedElements.count++; 14443 Velocity.State.delayedElements[callIndex] = element; 14444 14445 var delayComplete = (function(index) { 14446 return function() { 14447 /* Clear the temporary element */ 14448 Velocity.State.delayedElements[index] = false; 14449 14450 /* Finally, issue the call */ 14451 next(); 14452 }; 14453 })(callIndex); 14454 14455 14456 Data(element).delayBegin = (new Date()).getTime(); 14457 Data(element).delay = parseFloat(opts.delay); 14458 Data(element).delayTimer = { 14459 setTimeout: setTimeout(next, parseFloat(opts.delay)), 14460 next: delayComplete 14461 }; 14462 }); 14463 } 14464 14465 /********************* 14466 Option: Duration 14467 *********************/ 14468 14469 /* Support for jQuery's named durations. */ 14470 switch (opts.duration.toString().toLowerCase()) { 14471 case "fast": 14472 opts.duration = 200; 14473 break; 14474 14475 case "normal": 14476 opts.duration = DURATION_DEFAULT; 14477 break; 14478 14479 case "slow": 14480 opts.duration = 600; 14481 break; 14482 14483 default: 14484 /* Remove the potential "ms" suffix and default to 1 if the user is attempting to set a duration of 0 (in order to produce an immediate style change). */ 14485 opts.duration = parseFloat(opts.duration) || 1; 14486 } 14487 14488 /************************ 14489 Global Option: Mock 14490 ************************/ 14491 14492 if (Velocity.mock !== false) { 14493 /* In mock mode, all animations are forced to 1ms so that they occur immediately upon the next rAF tick. 14494 Alternatively, a multiplier can be passed in to time remap all delays and durations. */ 14495 if (Velocity.mock === true) { 14496 opts.duration = opts.delay = 1; 14497 } else { 14498 opts.duration *= parseFloat(Velocity.mock) || 1; 14499 opts.delay *= parseFloat(Velocity.mock) || 1; 14500 } 14501 } 14502 14503 /******************* 14504 Option: Easing 14505 *******************/ 14506 14507 opts.easing = getEasing(opts.easing, opts.duration); 14508 14509 /********************** 14510 Option: Callbacks 14511 **********************/ 14512 14513 /* Callbacks must functions. Otherwise, default to null. */ 14514 if (opts.begin && !Type.isFunction(opts.begin)) { 14515 opts.begin = null; 14516 } 14517 14518 if (opts.progress && !Type.isFunction(opts.progress)) { 14519 opts.progress = null; 14520 } 14521 14522 if (opts.complete && !Type.isFunction(opts.complete)) { 14523 opts.complete = null; 14524 } 14525 14526 /********************************* 14527 Option: Display & Visibility 14528 *********************************/ 14529 14530 /* Refer to Velocity's documentation (VelocityJS.org/#displayAndVisibility) for a description of the display and visibility options' behavior. */ 14531 /* Note: We strictly check for undefined instead of falsiness because display accepts an empty string value. */ 14532 if (opts.display !== undefined && opts.display !== null) { 14533 opts.display = opts.display.toString().toLowerCase(); 14534 14535 /* Users can pass in a special "auto" value to instruct Velocity to set the element to its default display value. */ 14536 if (opts.display === "auto") { 14537 opts.display = Velocity.CSS.Values.getDisplayType(element); 14538 } 14539 } 14540 14541 if (opts.visibility !== undefined && opts.visibility !== null) { 14542 opts.visibility = opts.visibility.toString().toLowerCase(); 14543 } 14544 14545 /********************** 14546 Option: mobileHA 14547 **********************/ 14548 14549 /* When set to true, and if this is a mobile device, mobileHA automatically enables hardware acceleration (via a null transform hack) 14550 on animating elements. HA is removed from the element at the completion of its animation. */ 14551 /* Note: Android Gingerbread doesn't support HA. If a null transform hack (mobileHA) is in fact set, it will prevent other tranform subproperties from taking effect. */ 14552 /* Note: You can read more about the use of mobileHA in Velocity's documentation: VelocityJS.org/#mobileHA. */ 14553 opts.mobileHA = (opts.mobileHA && Velocity.State.isMobile && !Velocity.State.isGingerbread); 14554 14555 /*********************** 14556 Part II: Queueing 14557 ***********************/ 14558 14559 /* When a set of elements is targeted by a Velocity call, the set is broken up and each element has the current Velocity call individually queued onto it. 14560 In this way, each element's existing queue is respected; some elements may already be animating and accordingly should not have this current Velocity call triggered immediately. */ 14561 /* In each queue, tween data is processed for each animating property then pushed onto the call-wide calls array. When the last element in the set has had its tweens processed, 14562 the call array is pushed to Velocity.State.calls for live processing by the requestAnimationFrame tick. */ 14563 function buildQueue(next) { 14564 var data, lastTweensContainer; 14565 14566 /******************* 14567 Option: Begin 14568 *******************/ 14569 14570 /* The begin callback is fired once per call -- not once per elemenet -- and is passed the full raw DOM element set as both its context and its first argument. */ 14571 if (opts.begin && elementsIndex === 0) { 14572 /* We throw callbacks in a setTimeout so that thrown errors don't halt the execution of Velocity itself. */ 14573 try { 14574 opts.begin.call(elements, elements); 14575 } catch (error) { 14576 setTimeout(function() { 14577 throw error; 14578 }, 1); 14579 } 14580 } 14581 14582 /***************************************** 14583 Tween Data Construction (for Scroll) 14584 *****************************************/ 14585 14586 /* Note: In order to be subjected to chaining and animation options, scroll's tweening is routed through Velocity as if it were a standard CSS property animation. */ 14587 if (action === "scroll") { 14588 /* The scroll action uniquely takes an optional "offset" option -- specified in pixels -- that offsets the targeted scroll position. */ 14589 var scrollDirection = (/^x$/i.test(opts.axis) ? "Left" : "Top"), 14590 scrollOffset = parseFloat(opts.offset) || 0, 14591 scrollPositionCurrent, 14592 scrollPositionCurrentAlternate, 14593 scrollPositionEnd; 14594 14595 /* Scroll also uniquely takes an optional "container" option, which indicates the parent element that should be scrolled -- 14596 as opposed to the browser window itself. This is useful for scrolling toward an element that's inside an overflowing parent element. */ 14597 if (opts.container) { 14598 /* Ensure that either a jQuery object or a raw DOM element was passed in. */ 14599 if (Type.isWrapped(opts.container) || Type.isNode(opts.container)) { 14600 /* Extract the raw DOM element from the jQuery wrapper. */ 14601 opts.container = opts.container[0] || opts.container; 14602 /* Note: Unlike other properties in Velocity, the browser's scroll position is never cached since it so frequently changes 14603 (due to the user's natural interaction with the page). */ 14604 scrollPositionCurrent = opts.container["scroll" + scrollDirection]; /* GET */ 14605 14606 /* $.position() values are relative to the container's currently viewable area (without taking into account the container's true dimensions 14607 -- say, for example, if the container was not overflowing). Thus, the scroll end value is the sum of the child element's position *and* 14608 the scroll container's current scroll position. */ 14609 scrollPositionEnd = (scrollPositionCurrent + $(element).position()[scrollDirection.toLowerCase()]) + scrollOffset; /* GET */ 14610 /* If a value other than a jQuery object or a raw DOM element was passed in, default to null so that this option is ignored. */ 14611 } else { 14612 opts.container = null; 14613 } 14614 } else { 14615 /* If the window itself is being scrolled -- not a containing element -- perform a live scroll position lookup using 14616 the appropriate cached property names (which differ based on browser type). */ 14617 scrollPositionCurrent = Velocity.State.scrollAnchor[Velocity.State["scrollProperty" + scrollDirection]]; /* GET */ 14618 /* When scrolling the browser window, cache the alternate axis's current value since window.scrollTo() doesn't let us change only one value at a time. */ 14619 scrollPositionCurrentAlternate = Velocity.State.scrollAnchor[Velocity.State["scrollProperty" + (scrollDirection === "Left" ? "Top" : "Left")]]; /* GET */ 14620 14621 /* Unlike $.position(), $.offset() values are relative to the browser window's true dimensions -- not merely its currently viewable area -- 14622 and therefore end values do not need to be compounded onto current values. */ 14623 scrollPositionEnd = $(element).offset()[scrollDirection.toLowerCase()] + scrollOffset; /* GET */ 14624 } 14625 14626 /* Since there's only one format that scroll's associated tweensContainer can take, we create it manually. */ 14627 tweensContainer = { 14628 scroll: { 14629 rootPropertyValue: false, 14630 startValue: scrollPositionCurrent, 14631 currentValue: scrollPositionCurrent, 14632 endValue: scrollPositionEnd, 14633 unitType: "", 14634 easing: opts.easing, 14635 scrollData: { 14636 container: opts.container, 14637 direction: scrollDirection, 14638 alternateValue: scrollPositionCurrentAlternate 14639 } 14640 }, 14641 element: element 14642 }; 14643 14644 if (Velocity.debug) { 14645 console.log("tweensContainer (scroll): ", tweensContainer.scroll, element); 14646 } 14647 14648 /****************************************** 14649 Tween Data Construction (for Reverse) 14650 ******************************************/ 14651 14652 /* Reverse acts like a "start" action in that a property map is animated toward. The only difference is 14653 that the property map used for reverse is the inverse of the map used in the previous call. Thus, we manipulate 14654 the previous call to construct our new map: use the previous map's end values as our new map's start values. Copy over all other data. */ 14655 /* Note: Reverse can be directly called via the "reverse" parameter, or it can be indirectly triggered via the loop option. (Loops are composed of multiple reverses.) */ 14656 /* Note: Reverse calls do not need to be consecutively chained onto a currently-animating element in order to operate on cached values; 14657 there is no harm to reverse being called on a potentially stale data cache since reverse's behavior is simply defined 14658 as reverting to the element's values as they were prior to the previous *Velocity* call. */ 14659 } else if (action === "reverse") { 14660 data = Data(element); 14661 14662 /* Abort if there is no prior animation data to reverse to. */ 14663 if (!data) { 14664 return; 14665 } 14666 14667 if (!data.tweensContainer) { 14668 /* Dequeue the element so that this queue entry releases itself immediately, allowing subsequent queue entries to run. */ 14669 $.dequeue(element, opts.queue); 14670 14671 return; 14672 } else { 14673 /********************* 14674 Options Parsing 14675 *********************/ 14676 14677 /* If the element was hidden via the display option in the previous call, 14678 revert display to "auto" prior to reversal so that the element is visible again. */ 14679 if (data.opts.display === "none") { 14680 data.opts.display = "auto"; 14681 } 14682 14683 if (data.opts.visibility === "hidden") { 14684 data.opts.visibility = "visible"; 14685 } 14686 14687 /* If the loop option was set in the previous call, disable it so that "reverse" calls aren't recursively generated. 14688 Further, remove the previous call's callback options; typically, users do not want these to be refired. */ 14689 data.opts.loop = false; 14690 data.opts.begin = null; 14691 data.opts.complete = null; 14692 14693 /* Since we're extending an opts object that has already been extended with the defaults options object, 14694 we remove non-explicitly-defined properties that are auto-assigned values. */ 14695 if (!options.easing) { 14696 delete opts.easing; 14697 } 14698 14699 if (!options.duration) { 14700 delete opts.duration; 14701 } 14702 14703 /* The opts object used for reversal is an extension of the options object optionally passed into this 14704 reverse call plus the options used in the previous Velocity call. */ 14705 opts = $.extend({}, data.opts, opts); 14706 14707 /************************************* 14708 Tweens Container Reconstruction 14709 *************************************/ 14710 14711 /* Create a deepy copy (indicated via the true flag) of the previous call's tweensContainer. */ 14712 lastTweensContainer = $.extend(true, {}, data ? data.tweensContainer : null); 14713 14714 /* Manipulate the previous tweensContainer by replacing its end values and currentValues with its start values. */ 14715 for (var lastTween in lastTweensContainer) { 14716 /* In addition to tween data, tweensContainers contain an element property that we ignore here. */ 14717 if (lastTweensContainer.hasOwnProperty(lastTween) && lastTween !== "element") { 14718 var lastStartValue = lastTweensContainer[lastTween].startValue; 14719 14720 lastTweensContainer[lastTween].startValue = lastTweensContainer[lastTween].currentValue = lastTweensContainer[lastTween].endValue; 14721 lastTweensContainer[lastTween].endValue = lastStartValue; 14722 14723 /* Easing is the only option that embeds into the individual tween data (since it can be defined on a per-property basis). 14724 Accordingly, every property's easing value must be updated when an options object is passed in with a reverse call. 14725 The side effect of this extensibility is that all per-property easing values are forcefully reset to the new value. */ 14726 if (!Type.isEmptyObject(options)) { 14727 lastTweensContainer[lastTween].easing = opts.easing; 14728 } 14729 14730 if (Velocity.debug) { 14731 console.log("reverse tweensContainer (" + lastTween + "): " + JSON.stringify(lastTweensContainer[lastTween]), element); 14732 } 14733 } 14734 } 14735 14736 tweensContainer = lastTweensContainer; 14737 } 14738 14739 /***************************************** 14740 Tween Data Construction (for Start) 14741 *****************************************/ 14742 14743 } else if (action === "start") { 14744 14745 /************************* 14746 Value Transferring 14747 *************************/ 14748 14749 /* If this queue entry follows a previous Velocity-initiated queue entry *and* if this entry was created 14750 while the element was in the process of being animated by Velocity, then this current call is safe to use 14751 the end values from the prior call as its start values. Velocity attempts to perform this value transfer 14752 process whenever possible in order to avoid requerying the DOM. */ 14753 /* If values aren't transferred from a prior call and start values were not forcefed by the user (more on this below), 14754 then the DOM is queried for the element's current values as a last resort. */ 14755 /* Note: Conversely, animation reversal (and looping) *always* perform inter-call value transfers; they never requery the DOM. */ 14756 14757 data = Data(element); 14758 14759 /* The per-element isAnimating flag is used to indicate whether it's safe (i.e. the data isn't stale) 14760 to transfer over end values to use as start values. If it's set to true and there is a previous 14761 Velocity call to pull values from, do so. */ 14762 if (data && data.tweensContainer && data.isAnimating === true) { 14763 lastTweensContainer = data.tweensContainer; 14764 } 14765 14766 /*************************** 14767 Tween Data Calculation 14768 ***************************/ 14769 14770 /* This function parses property data and defaults endValue, easing, and startValue as appropriate. */ 14771 /* Property map values can either take the form of 1) a single value representing the end value, 14772 or 2) an array in the form of [ endValue, [, easing] [, startValue] ]. 14773 The optional third parameter is a forcefed startValue to be used instead of querying the DOM for 14774 the element's current value. Read Velocity's docmentation to learn more about forcefeeding: VelocityJS.org/#forcefeeding */ 14775 var parsePropertyValue = function(valueData, skipResolvingEasing) { 14776 var endValue, easing, startValue; 14777 14778 /* If we have a function as the main argument then resolve it first, in case it returns an array that needs to be split */ 14779 if (Type.isFunction(valueData)) { 14780 valueData = valueData.call(element, elementArrayIndex, elementsLength); 14781 } 14782 14783 /* Handle the array format, which can be structured as one of three potential overloads: 14784 A) [ endValue, easing, startValue ], B) [ endValue, easing ], or C) [ endValue, startValue ] */ 14785 if (Type.isArray(valueData)) { 14786 /* endValue is always the first item in the array. Don't bother validating endValue's value now 14787 since the ensuing property cycling logic does that. */ 14788 endValue = valueData[0]; 14789 14790 /* Two-item array format: If the second item is a number, function, or hex string, treat it as a 14791 start value since easings can only be non-hex strings or arrays. */ 14792 if ((!Type.isArray(valueData[1]) && /^[\d-]/.test(valueData[1])) || Type.isFunction(valueData[1]) || CSS.RegEx.isHex.test(valueData[1])) { 14793 startValue = valueData[1]; 14794 /* Two or three-item array: If the second item is a non-hex string easing name or an array, treat it as an easing. */ 14795 } else if ((Type.isString(valueData[1]) && !CSS.RegEx.isHex.test(valueData[1]) && Velocity.Easings[valueData[1]]) || Type.isArray(valueData[1])) { 14796 easing = skipResolvingEasing ? valueData[1] : getEasing(valueData[1], opts.duration); 14797 14798 /* Don't bother validating startValue's value now since the ensuing property cycling logic inherently does that. */ 14799 startValue = valueData[2]; 14800 } else { 14801 startValue = valueData[1] || valueData[2]; 14802 } 14803 /* Handle the single-value format. */ 14804 } else { 14805 endValue = valueData; 14806 } 14807 14808 /* Default to the call's easing if a per-property easing type was not defined. */ 14809 if (!skipResolvingEasing) { 14810 easing = easing || opts.easing; 14811 } 14812 14813 /* If functions were passed in as values, pass the function the current element as its context, 14814 plus the element's index and the element set's size as arguments. Then, assign the returned value. */ 14815 if (Type.isFunction(endValue)) { 14816 endValue = endValue.call(element, elementArrayIndex, elementsLength); 14817 } 14818 14819 if (Type.isFunction(startValue)) { 14820 startValue = startValue.call(element, elementArrayIndex, elementsLength); 14821 } 14822 14823 /* Allow startValue to be left as undefined to indicate to the ensuing code that its value was not forcefed. */ 14824 return [endValue || 0, easing, startValue]; 14825 }; 14826 14827 var fixPropertyValue = function(property, valueData) { 14828 /* In case this property is a hook, there are circumstances where we will intend to work on the hook's root property and not the hooked subproperty. */ 14829 var rootProperty = CSS.Hooks.getRoot(property), 14830 rootPropertyValue = false, 14831 /* Parse out endValue, easing, and startValue from the property's data. */ 14832 endValue = valueData[0], 14833 easing = valueData[1], 14834 startValue = valueData[2], 14835 pattern; 14836 14837 /************************** 14838 Start Value Sourcing 14839 **************************/ 14840 14841 /* Other than for the dummy tween property, properties that are not supported by the browser (and do not have an associated normalization) will 14842 inherently produce no style changes when set, so they are skipped in order to decrease animation tick overhead. 14843 Property support is determined via prefixCheck(), which returns a false flag when no supported is detected. */ 14844 /* Note: Since SVG elements have some of their properties directly applied as HTML attributes, 14845 there is no way to check for their explicit browser support, and so we skip skip this check for them. */ 14846 if ((!data || !data.isSVG) && rootProperty !== "tween" && CSS.Names.prefixCheck(rootProperty)[1] === false && CSS.Normalizations.registered[rootProperty] === undefined) { 14847 if (Velocity.debug) { 14848 console.log("Skipping [" + rootProperty + "] due to a lack of browser support."); 14849 } 14850 return; 14851 } 14852 14853 /* If the display option is being set to a non-"none" (e.g. "block") and opacity (filter on IE<=8) is being 14854 animated to an endValue of non-zero, the user's intention is to fade in from invisible, thus we forcefeed opacity 14855 a startValue of 0 if its startValue hasn't already been sourced by value transferring or prior forcefeeding. */ 14856 if (((opts.display !== undefined && opts.display !== null && opts.display !== "none") || (opts.visibility !== undefined && opts.visibility !== "hidden")) && /opacity|filter/.test(property) && !startValue && endValue !== 0) { 14857 startValue = 0; 14858 } 14859 14860 /* If values have been transferred from the previous Velocity call, extract the endValue and rootPropertyValue 14861 for all of the current call's properties that were *also* animated in the previous call. */ 14862 /* Note: Value transferring can optionally be disabled by the user via the _cacheValues option. */ 14863 if (opts._cacheValues && lastTweensContainer && lastTweensContainer[property]) { 14864 if (startValue === undefined) { 14865 startValue = lastTweensContainer[property].endValue + lastTweensContainer[property].unitType; 14866 } 14867 14868 /* The previous call's rootPropertyValue is extracted from the element's data cache since that's the 14869 instance of rootPropertyValue that gets freshly updated by the tweening process, whereas the rootPropertyValue 14870 attached to the incoming lastTweensContainer is equal to the root property's value prior to any tweening. */ 14871 rootPropertyValue = data.rootPropertyValueCache[rootProperty]; 14872 /* If values were not transferred from a previous Velocity call, query the DOM as needed. */ 14873 } else { 14874 /* Handle hooked properties. */ 14875 if (CSS.Hooks.registered[property]) { 14876 if (startValue === undefined) { 14877 rootPropertyValue = CSS.getPropertyValue(element, rootProperty); /* GET */ 14878 /* Note: The following getPropertyValue() call does not actually trigger a DOM query; 14879 getPropertyValue() will extract the hook from rootPropertyValue. */ 14880 startValue = CSS.getPropertyValue(element, property, rootPropertyValue); 14881 /* If startValue is already defined via forcefeeding, do not query the DOM for the root property's value; 14882 just grab rootProperty's zero-value template from CSS.Hooks. This overwrites the element's actual 14883 root property value (if one is set), but this is acceptable since the primary reason users forcefeed is 14884 to avoid DOM queries, and thus we likewise avoid querying the DOM for the root property's value. */ 14885 } else { 14886 /* Grab this hook's zero-value template, e.g. "0px 0px 0px black". */ 14887 rootPropertyValue = CSS.Hooks.templates[rootProperty][1]; 14888 } 14889 /* Handle non-hooked properties that haven't already been defined via forcefeeding. */ 14890 } else if (startValue === undefined) { 14891 startValue = CSS.getPropertyValue(element, property); /* GET */ 14892 } 14893 } 14894 14895 /************************** 14896 Value Data Extraction 14897 **************************/ 14898 14899 var separatedValue, 14900 endValueUnitType, 14901 startValueUnitType, 14902 operator = false; 14903 14904 /* Separates a property value into its numeric value and its unit type. */ 14905 var separateValue = function(property, value) { 14906 var unitType, 14907 numericValue; 14908 14909 numericValue = (value || "0") 14910 .toString() 14911 .toLowerCase() 14912 /* Match the unit type at the end of the value. */ 14913 .replace(/[%A-z]+$/, function(match) { 14914 /* Grab the unit type. */ 14915 unitType = match; 14916 14917 /* Strip the unit type off of value. */ 14918 return ""; 14919 }); 14920 14921 /* If no unit type was supplied, assign one that is appropriate for this property (e.g. "deg" for rotateZ or "px" for width). */ 14922 if (!unitType) { 14923 unitType = CSS.Values.getUnitType(property); 14924 } 14925 14926 return [numericValue, unitType]; 14927 }; 14928 14929 if (startValue !== endValue && Type.isString(startValue) && Type.isString(endValue)) { 14930 pattern = ""; 14931 var iStart = 0, // index in startValue 14932 iEnd = 0, // index in endValue 14933 aStart = [], // array of startValue numbers 14934 aEnd = [], // array of endValue numbers 14935 inCalc = 0, // Keep track of being inside a "calc()" so we don't duplicate it 14936 inRGB = 0, // Keep track of being inside an RGB as we can't use fractional values 14937 inRGBA = 0; // Keep track of being inside an RGBA as we must pass fractional for the alpha channel 14938 14939 startValue = CSS.Hooks.fixColors(startValue); 14940 endValue = CSS.Hooks.fixColors(endValue); 14941 while (iStart < startValue.length && iEnd < endValue.length) { 14942 var cStart = startValue[iStart], 14943 cEnd = endValue[iEnd]; 14944 14945 if (/[\d\.-]/.test(cStart) && /[\d\.-]/.test(cEnd)) { 14946 var tStart = cStart, // temporary character buffer 14947 tEnd = cEnd, // temporary character buffer 14948 dotStart = ".", // Make sure we can only ever match a single dot in a decimal 14949 dotEnd = "."; // Make sure we can only ever match a single dot in a decimal 14950 14951 while (++iStart < startValue.length) { 14952 cStart = startValue[iStart]; 14953 if (cStart === dotStart) { 14954 dotStart = ".."; // Can never match two characters 14955 } else if (!/\d/.test(cStart)) { 14956 break; 14957 } 14958 tStart += cStart; 14959 } 14960 while (++iEnd < endValue.length) { 14961 cEnd = endValue[iEnd]; 14962 if (cEnd === dotEnd) { 14963 dotEnd = ".."; // Can never match two characters 14964 } else if (!/\d/.test(cEnd)) { 14965 break; 14966 } 14967 tEnd += cEnd; 14968 } 14969 var uStart = CSS.Hooks.getUnit(startValue, iStart), // temporary unit type 14970 uEnd = CSS.Hooks.getUnit(endValue, iEnd); // temporary unit type 14971 14972 iStart += uStart.length; 14973 iEnd += uEnd.length; 14974 if (uStart === uEnd) { 14975 // Same units 14976 if (tStart === tEnd) { 14977 // Same numbers, so just copy over 14978 pattern += tStart + uStart; 14979 } else { 14980 // Different numbers, so store them 14981 pattern += "{" + aStart.length + (inRGB ? "!" : "") + "}" + uStart; 14982 aStart.push(parseFloat(tStart)); 14983 aEnd.push(parseFloat(tEnd)); 14984 } 14985 } else { 14986 // Different units, so put into a "calc(from + to)" and animate each side to/from zero 14987 var nStart = parseFloat(tStart), 14988 nEnd = parseFloat(tEnd); 14989 14990 pattern += (inCalc < 5 ? "calc" : "") + "(" 14991 + (nStart ? "{" + aStart.length + (inRGB ? "!" : "") + "}" : "0") + uStart 14992 + " + " 14993 + (nEnd ? "{" + (aStart.length + (nStart ? 1 : 0)) + (inRGB ? "!" : "") + "}" : "0") + uEnd 14994 + ")"; 14995 if (nStart) { 14996 aStart.push(nStart); 14997 aEnd.push(0); 14998 } 14999 if (nEnd) { 15000 aStart.push(0); 15001 aEnd.push(nEnd); 15002 } 15003 } 15004 } else if (cStart === cEnd) { 15005 pattern += cStart; 15006 iStart++; 15007 iEnd++; 15008 // Keep track of being inside a calc() 15009 if (inCalc === 0 && cStart === "c" 15010 || inCalc === 1 && cStart === "a" 15011 || inCalc === 2 && cStart === "l" 15012 || inCalc === 3 && cStart === "c" 15013 || inCalc >= 4 && cStart === "(" 15014 ) { 15015 inCalc++; 15016 } else if ((inCalc && inCalc < 5) 15017 || inCalc >= 4 && cStart === ")" && --inCalc < 5) { 15018 inCalc = 0; 15019 } 15020 // Keep track of being inside an rgb() / rgba() 15021 if (inRGB === 0 && cStart === "r" 15022 || inRGB === 1 && cStart === "g" 15023 || inRGB === 2 && cStart === "b" 15024 || inRGB === 3 && cStart === "a" 15025 || inRGB >= 3 && cStart === "(" 15026 ) { 15027 if (inRGB === 3 && cStart === "a") { 15028 inRGBA = 1; 15029 } 15030 inRGB++; 15031 } else if (inRGBA && cStart === ",") { 15032 if (++inRGBA > 3) { 15033 inRGB = inRGBA = 0; 15034 } 15035 } else if ((inRGBA && inRGB < (inRGBA ? 5 : 4)) 15036 || inRGB >= (inRGBA ? 4 : 3) && cStart === ")" && --inRGB < (inRGBA ? 5 : 4)) { 15037 inRGB = inRGBA = 0; 15038 } 15039 } else { 15040 inCalc = 0; 15041 // TODO: changing units, fixing colours 15042 break; 15043 } 15044 } 15045 if (iStart !== startValue.length || iEnd !== endValue.length) { 15046 if (Velocity.debug) { 15047 console.error("Trying to pattern match mis-matched strings [\"" + endValue + "\", \"" + startValue + "\"]"); 15048 } 15049 pattern = undefined; 15050 } 15051 if (pattern) { 15052 if (aStart.length) { 15053 if (Velocity.debug) { 15054 console.log("Pattern found \"" + pattern + "\" -> ", aStart, aEnd, "[" + startValue + "," + endValue + "]"); 15055 } 15056 startValue = aStart; 15057 endValue = aEnd; 15058 endValueUnitType = startValueUnitType = ""; 15059 } else { 15060 pattern = undefined; 15061 } 15062 } 15063 } 15064 15065 if (!pattern) { 15066 /* Separate startValue. */ 15067 separatedValue = separateValue(property, startValue); 15068 startValue = separatedValue[0]; 15069 startValueUnitType = separatedValue[1]; 15070 15071 /* Separate endValue, and extract a value operator (e.g. "+=", "-=") if one exists. */ 15072 separatedValue = separateValue(property, endValue); 15073 endValue = separatedValue[0].replace(/^([+-\/*])=/, function(match, subMatch) { 15074 operator = subMatch; 15075 15076 /* Strip the operator off of the value. */ 15077 return ""; 15078 }); 15079 endValueUnitType = separatedValue[1]; 15080 15081 /* Parse float values from endValue and startValue. Default to 0 if NaN is returned. */ 15082 startValue = parseFloat(startValue) || 0; 15083 endValue = parseFloat(endValue) || 0; 15084 15085 /*************************************** 15086 Property-Specific Value Conversion 15087 ***************************************/ 15088 15089 /* Custom support for properties that don't actually accept the % unit type, but where pollyfilling is trivial and relatively foolproof. */ 15090 if (endValueUnitType === "%") { 15091 /* A %-value fontSize/lineHeight is relative to the parent's fontSize (as opposed to the parent's dimensions), 15092 which is identical to the em unit's behavior, so we piggyback off of that. */ 15093 if (/^(fontSize|lineHeight)$/.test(property)) { 15094 /* Convert % into an em decimal value. */ 15095 endValue = endValue / 100; 15096 endValueUnitType = "em"; 15097 /* For scaleX and scaleY, convert the value into its decimal format and strip off the unit type. */ 15098 } else if (/^scale/.test(property)) { 15099 endValue = endValue / 100; 15100 endValueUnitType = ""; 15101 /* For RGB components, take the defined percentage of 255 and strip off the unit type. */ 15102 } else if (/(Red|Green|Blue)$/i.test(property)) { 15103 endValue = (endValue / 100) * 255; 15104 endValueUnitType = ""; 15105 } 15106 } 15107 } 15108 15109 /*************************** 15110 Unit Ratio Calculation 15111 ***************************/ 15112 15113 /* When queried, the browser returns (most) CSS property values in pixels. Therefore, if an endValue with a unit type of 15114 %, em, or rem is animated toward, startValue must be converted from pixels into the same unit type as endValue in order 15115 for value manipulation logic (increment/decrement) to proceed. Further, if the startValue was forcefed or transferred 15116 from a previous call, startValue may also not be in pixels. Unit conversion logic therefore consists of two steps: 15117 1) Calculating the ratio of %/em/rem/vh/vw relative to pixels 15118 2) Converting startValue into the same unit of measurement as endValue based on these ratios. */ 15119 /* Unit conversion ratios are calculated by inserting a sibling node next to the target node, copying over its position property, 15120 setting values with the target unit type then comparing the returned pixel value. */ 15121 /* Note: Even if only one of these unit types is being animated, all unit ratios are calculated at once since the overhead 15122 of batching the SETs and GETs together upfront outweights the potential overhead 15123 of layout thrashing caused by re-querying for uncalculated ratios for subsequently-processed properties. */ 15124 /* Todo: Shift this logic into the calls' first tick instance so that it's synced with RAF. */ 15125 var calculateUnitRatios = function() { 15126 15127 /************************ 15128 Same Ratio Checks 15129 ************************/ 15130 15131 /* The properties below are used to determine whether the element differs sufficiently from this call's 15132 previously iterated element to also differ in its unit conversion ratios. If the properties match up with those 15133 of the prior element, the prior element's conversion ratios are used. Like most optimizations in Velocity, 15134 this is done to minimize DOM querying. */ 15135 var sameRatioIndicators = { 15136 myParent: element.parentNode || document.body, /* GET */ 15137 position: CSS.getPropertyValue(element, "position"), /* GET */ 15138 fontSize: CSS.getPropertyValue(element, "fontSize") /* GET */ 15139 }, 15140 /* Determine if the same % ratio can be used. % is based on the element's position value and its parent's width and height dimensions. */ 15141 samePercentRatio = ((sameRatioIndicators.position === callUnitConversionData.lastPosition) && (sameRatioIndicators.myParent === callUnitConversionData.lastParent)), 15142 /* Determine if the same em ratio can be used. em is relative to the element's fontSize. */ 15143 sameEmRatio = (sameRatioIndicators.fontSize === callUnitConversionData.lastFontSize); 15144 15145 /* Store these ratio indicators call-wide for the next element to compare against. */ 15146 callUnitConversionData.lastParent = sameRatioIndicators.myParent; 15147 callUnitConversionData.lastPosition = sameRatioIndicators.position; 15148 callUnitConversionData.lastFontSize = sameRatioIndicators.fontSize; 15149 15150 /*************************** 15151 Element-Specific Units 15152 ***************************/ 15153 15154 /* Note: IE8 rounds to the nearest pixel when returning CSS values, thus we perform conversions using a measurement 15155 of 100 (instead of 1) to give our ratios a precision of at least 2 decimal values. */ 15156 var measurement = 100, 15157 unitRatios = {}; 15158 15159 if (!sameEmRatio || !samePercentRatio) { 15160 var dummy = data && data.isSVG ? document.createElementNS("http://www.w3.org/2000/svg", "rect") : document.createElement("div"); 15161 15162 Velocity.init(dummy); 15163 sameRatioIndicators.myParent.appendChild(dummy); 15164 15165 /* To accurately and consistently calculate conversion ratios, the element's cascaded overflow and box-sizing are stripped. 15166 Similarly, since width/height can be artificially constrained by their min-/max- equivalents, these are controlled for as well. */ 15167 /* Note: Overflow must be also be controlled for per-axis since the overflow property overwrites its per-axis values. */ 15168 $.each(["overflow", "overflowX", "overflowY"], function(i, property) { 15169 Velocity.CSS.setPropertyValue(dummy, property, "hidden"); 15170 }); 15171 Velocity.CSS.setPropertyValue(dummy, "position", sameRatioIndicators.position); 15172 Velocity.CSS.setPropertyValue(dummy, "fontSize", sameRatioIndicators.fontSize); 15173 Velocity.CSS.setPropertyValue(dummy, "boxSizing", "content-box"); 15174 15175 /* width and height act as our proxy properties for measuring the horizontal and vertical % ratios. */ 15176 $.each(["minWidth", "maxWidth", "width", "minHeight", "maxHeight", "height"], function(i, property) { 15177 Velocity.CSS.setPropertyValue(dummy, property, measurement + "%"); 15178 }); 15179 /* paddingLeft arbitrarily acts as our proxy property for the em ratio. */ 15180 Velocity.CSS.setPropertyValue(dummy, "paddingLeft", measurement + "em"); 15181 15182 /* Divide the returned value by the measurement to get the ratio between 1% and 1px. Default to 1 since working with 0 can produce Infinite. */ 15183 unitRatios.percentToPxWidth = callUnitConversionData.lastPercentToPxWidth = (parseFloat(CSS.getPropertyValue(dummy, "width", null, true)) || 1) / measurement; /* GET */ 15184 unitRatios.percentToPxHeight = callUnitConversionData.lastPercentToPxHeight = (parseFloat(CSS.getPropertyValue(dummy, "height", null, true)) || 1) / measurement; /* GET */ 15185 unitRatios.emToPx = callUnitConversionData.lastEmToPx = (parseFloat(CSS.getPropertyValue(dummy, "paddingLeft")) || 1) / measurement; /* GET */ 15186 15187 sameRatioIndicators.myParent.removeChild(dummy); 15188 } else { 15189 unitRatios.emToPx = callUnitConversionData.lastEmToPx; 15190 unitRatios.percentToPxWidth = callUnitConversionData.lastPercentToPxWidth; 15191 unitRatios.percentToPxHeight = callUnitConversionData.lastPercentToPxHeight; 15192 } 15193 15194 /*************************** 15195 Element-Agnostic Units 15196 ***************************/ 15197 15198 /* Whereas % and em ratios are determined on a per-element basis, the rem unit only needs to be checked 15199 once per call since it's exclusively dependant upon document.body's fontSize. If this is the first time 15200 that calculateUnitRatios() is being run during this call, remToPx will still be set to its default value of null, 15201 so we calculate it now. */ 15202 if (callUnitConversionData.remToPx === null) { 15203 /* Default to browsers' default fontSize of 16px in the case of 0. */ 15204 callUnitConversionData.remToPx = parseFloat(CSS.getPropertyValue(document.body, "fontSize")) || 16; /* GET */ 15205 } 15206 15207 /* Similarly, viewport units are %-relative to the window's inner dimensions. */ 15208 if (callUnitConversionData.vwToPx === null) { 15209 callUnitConversionData.vwToPx = parseFloat(window.innerWidth) / 100; /* GET */ 15210 callUnitConversionData.vhToPx = parseFloat(window.innerHeight) / 100; /* GET */ 15211 } 15212 15213 unitRatios.remToPx = callUnitConversionData.remToPx; 15214 unitRatios.vwToPx = callUnitConversionData.vwToPx; 15215 unitRatios.vhToPx = callUnitConversionData.vhToPx; 15216 15217 if (Velocity.debug >= 1) { 15218 console.log("Unit ratios: " + JSON.stringify(unitRatios), element); 15219 } 15220 return unitRatios; 15221 }; 15222 15223 /******************** 15224 Unit Conversion 15225 ********************/ 15226 15227 /* The * and / operators, which are not passed in with an associated unit, inherently use startValue's unit. Skip value and unit conversion. */ 15228 if (/[\/*]/.test(operator)) { 15229 endValueUnitType = startValueUnitType; 15230 /* If startValue and endValue differ in unit type, convert startValue into the same unit type as endValue so that if endValueUnitType 15231 is a relative unit (%, em, rem), the values set during tweening will continue to be accurately relative even if the metrics they depend 15232 on are dynamically changing during the course of the animation. Conversely, if we always normalized into px and used px for setting values, the px ratio 15233 would become stale if the original unit being animated toward was relative and the underlying metrics change during the animation. */ 15234 /* Since 0 is 0 in any unit type, no conversion is necessary when startValue is 0 -- we just start at 0 with endValueUnitType. */ 15235 } else if ((startValueUnitType !== endValueUnitType) && startValue !== 0) { 15236 /* Unit conversion is also skipped when endValue is 0, but *startValueUnitType* must be used for tween values to remain accurate. */ 15237 /* Note: Skipping unit conversion here means that if endValueUnitType was originally a relative unit, the animation won't relatively 15238 match the underlying metrics if they change, but this is acceptable since we're animating toward invisibility instead of toward visibility, 15239 which remains past the point of the animation's completion. */ 15240 if (endValue === 0) { 15241 endValueUnitType = startValueUnitType; 15242 } else { 15243 /* By this point, we cannot avoid unit conversion (it's undesirable since it causes layout thrashing). 15244 If we haven't already, we trigger calculateUnitRatios(), which runs once per element per call. */ 15245 elementUnitConversionData = elementUnitConversionData || calculateUnitRatios(); 15246 15247 /* The following RegEx matches CSS properties that have their % values measured relative to the x-axis. */ 15248 /* Note: W3C spec mandates that all of margin and padding's properties (even top and bottom) are %-relative to the *width* of the parent element. */ 15249 var axis = (/margin|padding|left|right|width|text|word|letter/i.test(property) || /X$/.test(property) || property === "x") ? "x" : "y"; 15250 15251 /* In order to avoid generating n^2 bespoke conversion functions, unit conversion is a two-step process: 15252 1) Convert startValue into pixels. 2) Convert this new pixel value into endValue's unit type. */ 15253 switch (startValueUnitType) { 15254 case "%": 15255 /* Note: translateX and translateY are the only properties that are %-relative to an element's own dimensions -- not its parent's dimensions. 15256 Velocity does not include a special conversion process to account for this behavior. Therefore, animating translateX/Y from a % value 15257 to a non-% value will produce an incorrect start value. Fortunately, this sort of cross-unit conversion is rarely done by users in practice. */ 15258 startValue *= (axis === "x" ? elementUnitConversionData.percentToPxWidth : elementUnitConversionData.percentToPxHeight); 15259 break; 15260 15261 case "px": 15262 /* px acts as our midpoint in the unit conversion process; do nothing. */ 15263 break; 15264 15265 default: 15266 startValue *= elementUnitConversionData[startValueUnitType + "ToPx"]; 15267 } 15268 15269 /* Invert the px ratios to convert into to the target unit. */ 15270 switch (endValueUnitType) { 15271 case "%": 15272 startValue *= 1 / (axis === "x" ? elementUnitConversionData.percentToPxWidth : elementUnitConversionData.percentToPxHeight); 15273 break; 15274 15275 case "px": 15276 /* startValue is already in px, do nothing; we're done. */ 15277 break; 15278 15279 default: 15280 startValue *= 1 / elementUnitConversionData[endValueUnitType + "ToPx"]; 15281 } 15282 } 15283 } 15284 15285 /********************* 15286 Relative Values 15287 *********************/ 15288 15289 /* Operator logic must be performed last since it requires unit-normalized start and end values. */ 15290 /* Note: Relative *percent values* do not behave how most people think; while one would expect "+=50%" 15291 to increase the property 1.5x its current value, it in fact increases the percent units in absolute terms: 15292 50 points is added on top of the current % value. */ 15293 switch (operator) { 15294 case "+": 15295 endValue = startValue + endValue; 15296 break; 15297 15298 case "-": 15299 endValue = startValue - endValue; 15300 break; 15301 15302 case "*": 15303 endValue = startValue * endValue; 15304 break; 15305 15306 case "/": 15307 endValue = startValue / endValue; 15308 break; 15309 } 15310 15311 /************************** 15312 tweensContainer Push 15313 **************************/ 15314 15315 /* Construct the per-property tween object, and push it to the element's tweensContainer. */ 15316 tweensContainer[property] = { 15317 rootPropertyValue: rootPropertyValue, 15318 startValue: startValue, 15319 currentValue: startValue, 15320 endValue: endValue, 15321 unitType: endValueUnitType, 15322 easing: easing 15323 }; 15324 if (pattern) { 15325 tweensContainer[property].pattern = pattern; 15326 } 15327 15328 if (Velocity.debug) { 15329 console.log("tweensContainer (" + property + "): " + JSON.stringify(tweensContainer[property]), element); 15330 } 15331 }; 15332 15333 /* Create a tween out of each property, and append its associated data to tweensContainer. */ 15334 for (var property in propertiesMap) { 15335 15336 if (!propertiesMap.hasOwnProperty(property)) { 15337 continue; 15338 } 15339 /* The original property name's format must be used for the parsePropertyValue() lookup, 15340 but we then use its camelCase styling to normalize it for manipulation. */ 15341 var propertyName = CSS.Names.camelCase(property), 15342 valueData = parsePropertyValue(propertiesMap[property]); 15343 15344 /* Find shorthand color properties that have been passed a hex string. */ 15345 /* Would be quicker to use CSS.Lists.colors.includes() if possible */ 15346 if (_inArray(CSS.Lists.colors, propertyName)) { 15347 /* Parse the value data for each shorthand. */ 15348 var endValue = valueData[0], 15349 easing = valueData[1], 15350 startValue = valueData[2]; 15351 15352 if (CSS.RegEx.isHex.test(endValue)) { 15353 /* Convert the hex strings into their RGB component arrays. */ 15354 var colorComponents = ["Red", "Green", "Blue"], 15355 endValueRGB = CSS.Values.hexToRgb(endValue), 15356 startValueRGB = startValue ? CSS.Values.hexToRgb(startValue) : undefined; 15357 15358 /* Inject the RGB component tweens into propertiesMap. */ 15359 for (var i = 0; i < colorComponents.length; i++) { 15360 var dataArray = [endValueRGB[i]]; 15361 15362 if (easing) { 15363 dataArray.push(easing); 15364 } 15365 15366 if (startValueRGB !== undefined) { 15367 dataArray.push(startValueRGB[i]); 15368 } 15369 15370 fixPropertyValue(propertyName + colorComponents[i], dataArray); 15371 } 15372 /* If we have replaced a shortcut color value then don't update the standard property name */ 15373 continue; 15374 } 15375 } 15376 fixPropertyValue(propertyName, valueData); 15377 } 15378 15379 /* Along with its property data, store a reference to the element itself onto tweensContainer. */ 15380 tweensContainer.element = element; 15381 } 15382 15383 /***************** 15384 Call Push 15385 *****************/ 15386 15387 /* Note: tweensContainer can be empty if all of the properties in this call's property map were skipped due to not 15388 being supported by the browser. The element property is used for checking that the tweensContainer has been appended to. */ 15389 if (tweensContainer.element) { 15390 /* Apply the "velocity-animating" indicator class. */ 15391 CSS.Values.addClass(element, "velocity-animating"); 15392 15393 /* The call array houses the tweensContainers for each element being animated in the current call. */ 15394 call.push(tweensContainer); 15395 15396 data = Data(element); 15397 15398 if (data) { 15399 /* Store the tweensContainer and options if we're working on the default effects queue, so that they can be used by the reverse command. */ 15400 if (opts.queue === "") { 15401 15402 data.tweensContainer = tweensContainer; 15403 data.opts = opts; 15404 } 15405 15406 /* Switch on the element's animating flag. */ 15407 data.isAnimating = true; 15408 } 15409 15410 /* Once the final element in this call's element set has been processed, push the call array onto 15411 Velocity.State.calls for the animation tick to immediately begin processing. */ 15412 if (elementsIndex === elementsLength - 1) { 15413 /* Add the current call plus its associated metadata (the element set and the call's options) onto the global call container. 15414 Anything on this call container is subjected to tick() processing. */ 15415 Velocity.State.calls.push([call, elements, opts, null, promiseData.resolver, null, 0]); 15416 15417 /* If the animation tick isn't running, start it. (Velocity shuts it off when there are no active calls to process.) */ 15418 if (Velocity.State.isTicking === false) { 15419 Velocity.State.isTicking = true; 15420 15421 /* Start the tick loop. */ 15422 tick(); 15423 } 15424 } else { 15425 elementsIndex++; 15426 } 15427 } 15428 } 15429 15430 /* When the queue option is set to false, the call skips the element's queue and fires immediately. */ 15431 if (opts.queue === false) { 15432 /* Since this buildQueue call doesn't respect the element's existing queue (which is where a delay option would have been appended), 15433 we manually inject the delay property here with an explicit setTimeout. */ 15434 if (opts.delay) { 15435 15436 /* Temporarily store delayed elements to facilitate access for global pause/resume */ 15437 var callIndex = Velocity.State.delayedElements.count++; 15438 Velocity.State.delayedElements[callIndex] = element; 15439 15440 var delayComplete = (function(index) { 15441 return function() { 15442 /* Clear the temporary element */ 15443 Velocity.State.delayedElements[index] = false; 15444 15445 /* Finally, issue the call */ 15446 buildQueue(); 15447 }; 15448 })(callIndex); 15449 15450 Data(element).delayBegin = (new Date()).getTime(); 15451 Data(element).delay = parseFloat(opts.delay); 15452 Data(element).delayTimer = { 15453 setTimeout: setTimeout(buildQueue, parseFloat(opts.delay)), 15454 next: delayComplete 15455 }; 15456 } else { 15457 buildQueue(); 15458 } 15459 /* Otherwise, the call undergoes element queueing as normal. */ 15460 /* Note: To interoperate with jQuery, Velocity uses jQuery's own $.queue() stack for queuing logic. */ 15461 } else { 15462 $.queue(element, opts.queue, function(next, clearQueue) { 15463 /* If the clearQueue flag was passed in by the stop command, resolve this call's promise. (Promises can only be resolved once, 15464 so it's fine if this is repeatedly triggered for each element in the associated call.) */ 15465 if (clearQueue === true) { 15466 if (promiseData.promise) { 15467 promiseData.resolver(elements); 15468 } 15469 15470 /* Do not continue with animation queueing. */ 15471 return true; 15472 } 15473 15474 /* This flag indicates to the upcoming completeCall() function that this queue entry was initiated by Velocity. 15475 See completeCall() for further details. */ 15476 Velocity.velocityQueueEntryFlag = true; 15477 15478 buildQueue(next); 15479 }); 15480 } 15481 15482 /********************* 15483 Auto-Dequeuing 15484 *********************/ 15485 15486 /* As per jQuery's $.queue() behavior, to fire the first non-custom-queue entry on an element, the element 15487 must be dequeued if its queue stack consists *solely* of the current call. (This can be determined by checking 15488 for the "inprogress" item that jQuery prepends to active queue stack arrays.) Regardless, whenever the element's 15489 queue is further appended with additional items -- including $.delay()'s or even $.animate() calls, the queue's 15490 first entry is automatically fired. This behavior contrasts that of custom queues, which never auto-fire. */ 15491 /* Note: When an element set is being subjected to a non-parallel Velocity call, the animation will not begin until 15492 each one of the elements in the set has reached the end of its individually pre-existing queue chain. */ 15493 /* Note: Unfortunately, most people don't fully grasp jQuery's powerful, yet quirky, $.queue() function. 15494 Lean more here: http://stackoverflow.com/questions/1058158/can-somebody-explain-jquery-queue-to-me */ 15495 if ((opts.queue === "" || opts.queue === "fx") && $.queue(element)[0] !== "inprogress") { 15496 $.dequeue(element); 15497 } 15498 } 15499 15500 /************************** 15501 Element Set Iteration 15502 **************************/ 15503 15504 /* If the "nodeType" property exists on the elements variable, we're animating a single element. 15505 Place it in an array so that $.each() can iterate over it. */ 15506 $.each(elements, function(i, element) { 15507 /* Ensure each element in a set has a nodeType (is a real element) to avoid throwing errors. */ 15508 if (Type.isNode(element)) { 15509 processElement(element, i); 15510 } 15511 }); 15512 15513 /****************** 15514 Option: Loop 15515 ******************/ 15516 15517 /* The loop option accepts an integer indicating how many times the element should loop between the values in the 15518 current call's properties map and the element's property values prior to this call. */ 15519 /* Note: The loop option's logic is performed here -- after element processing -- because the current call needs 15520 to undergo its queue insertion prior to the loop option generating its series of constituent "reverse" calls, 15521 which chain after the current call. Two reverse calls (two "alternations") constitute one loop. */ 15522 opts = $.extend({}, Velocity.defaults, options); 15523 opts.loop = parseInt(opts.loop, 10); 15524 var reverseCallsCount = (opts.loop * 2) - 1; 15525 15526 if (opts.loop) { 15527 /* Double the loop count to convert it into its appropriate number of "reverse" calls. 15528 Subtract 1 from the resulting value since the current call is included in the total alternation count. */ 15529 for (var x = 0; x < reverseCallsCount; x++) { 15530 /* Since the logic for the reverse action occurs inside Queueing and therefore this call's options object 15531 isn't parsed until then as well, the current call's delay option must be explicitly passed into the reverse 15532 call so that the delay logic that occurs inside *Pre-Queueing* can process it. */ 15533 var reverseOptions = { 15534 delay: opts.delay, 15535 progress: opts.progress 15536 }; 15537 15538 /* If a complete callback was passed into this call, transfer it to the loop redirect's final "reverse" call 15539 so that it's triggered when the entire redirect is complete (and not when the very first animation is complete). */ 15540 if (x === reverseCallsCount - 1) { 15541 reverseOptions.display = opts.display; 15542 reverseOptions.visibility = opts.visibility; 15543 reverseOptions.complete = opts.complete; 15544 } 15545 15546 animate(elements, "reverse", reverseOptions); 15547 } 15548 } 15549 15550 /*************** 15551 Chaining 15552 ***************/ 15553 15554 /* Return the elements back to the call chain, with wrapped elements taking precedence in case Velocity was called via the $.fn. extension. */ 15555 return getChain(); 15556 }; 15557 15558 /* Turn Velocity into the animation function, extended with the pre-existing Velocity object. */ 15559 Velocity = $.extend(animate, Velocity); 15560 /* For legacy support, also expose the literal animate method. */ 15561 Velocity.animate = animate; 15562 15563 /************** 15564 Timing 15565 **************/ 15566 15567 /* Ticker function. */ 15568 var ticker = window.requestAnimationFrame || rAFShim; 15569 15570 /* Inactive browser tabs pause rAF, which results in all active animations immediately sprinting to their completion states when the tab refocuses. 15571 To get around this, we dynamically switch rAF to setTimeout (which the browser *doesn't* pause) when the tab loses focus. We skip this for mobile 15572 devices to avoid wasting battery power on inactive tabs. */ 15573 /* Note: Tab focus detection doesn't work on older versions of IE, but that's okay since they don't support rAF to begin with. */ 15574 if (!Velocity.State.isMobile && document.hidden !== undefined) { 15575 var updateTicker = function() { 15576 /* Reassign the rAF function (which the global tick() function uses) based on the tab's focus state. */ 15577 if (document.hidden) { 15578 ticker = function(callback) { 15579 /* The tick function needs a truthy first argument in order to pass its internal timestamp check. */ 15580 return setTimeout(function() { 15581 callback(true); 15582 }, 16); 15583 }; 15584 15585 /* The rAF loop has been paused by the browser, so we manually restart the tick. */ 15586 tick(); 15587 } else { 15588 ticker = window.requestAnimationFrame || rAFShim; 15589 } 15590 }; 15591 15592 /* Page could be sitting in the background at this time (i.e. opened as new tab) so making sure we use correct ticker from the start */ 15593 updateTicker(); 15594 15595 /* And then run check again every time visibility changes */ 15596 document.addEventListener("visibilitychange", updateTicker); 15597 } 15598 15599 /************ 15600 Tick 15601 ************/ 15602 15603 /* Note: All calls to Velocity are pushed to the Velocity.State.calls array, which is fully iterated through upon each tick. */ 15604 function tick(timestamp) { 15605 /* An empty timestamp argument indicates that this is the first tick occurence since ticking was turned on. 15606 We leverage this metadata to fully ignore the first tick pass since RAF's initial pass is fired whenever 15607 the browser's next tick sync time occurs, which results in the first elements subjected to Velocity 15608 calls being animated out of sync with any elements animated immediately thereafter. In short, we ignore 15609 the first RAF tick pass so that elements being immediately consecutively animated -- instead of simultaneously animated 15610 by the same Velocity call -- are properly batched into the same initial RAF tick and consequently remain in sync thereafter. */ 15611 if (timestamp) { 15612 /* We normally use RAF's high resolution timestamp but as it can be significantly offset when the browser is 15613 under high stress we give the option for choppiness over allowing the browser to drop huge chunks of frames. 15614 We use performance.now() and shim it if it doesn't exist for when the tab is hidden. */ 15615 var timeCurrent = Velocity.timestamp && timestamp !== true ? timestamp : performance.now(); 15616 15617 /******************** 15618 Call Iteration 15619 ********************/ 15620 15621 var callsLength = Velocity.State.calls.length; 15622 15623 /* To speed up iterating over this array, it is compacted (falsey items -- calls that have completed -- are removed) 15624 when its length has ballooned to a point that can impact tick performance. This only becomes necessary when animation 15625 has been continuous with many elements over a long period of time; whenever all active calls are completed, completeCall() clears Velocity.State.calls. */ 15626 if (callsLength > 10000) { 15627 Velocity.State.calls = compactSparseArray(Velocity.State.calls); 15628 callsLength = Velocity.State.calls.length; 15629 } 15630 15631 /* Iterate through each active call. */ 15632 for (var i = 0; i < callsLength; i++) { 15633 /* When a Velocity call is completed, its Velocity.State.calls entry is set to false. Continue on to the next call. */ 15634 if (!Velocity.State.calls[i]) { 15635 continue; 15636 } 15637 15638 /************************ 15639 Call-Wide Variables 15640 ************************/ 15641 15642 var callContainer = Velocity.State.calls[i], 15643 call = callContainer[0], 15644 opts = callContainer[2], 15645 timeStart = callContainer[3], 15646 firstTick = !timeStart, 15647 tweenDummyValue = null, 15648 pauseObject = callContainer[5], 15649 millisecondsEllapsed = callContainer[6]; 15650 15651 15652 15653 /* If timeStart is undefined, then this is the first time that this call has been processed by tick(). 15654 We assign timeStart now so that its value is as close to the real animation start time as possible. 15655 (Conversely, had timeStart been defined when this call was added to Velocity.State.calls, the delay 15656 between that time and now would cause the first few frames of the tween to be skipped since 15657 percentComplete is calculated relative to timeStart.) */ 15658 /* Further, subtract 16ms (the approximate resolution of RAF) from the current time value so that the 15659 first tick iteration isn't wasted by animating at 0% tween completion, which would produce the 15660 same style value as the element's current value. */ 15661 if (!timeStart) { 15662 timeStart = Velocity.State.calls[i][3] = timeCurrent - 16; 15663 } 15664 15665 /* If a pause object is present, skip processing unless it has been set to resume */ 15666 if (pauseObject) { 15667 if (pauseObject.resume === true) { 15668 /* Update the time start to accomodate the paused completion amount */ 15669 timeStart = callContainer[3] = Math.round(timeCurrent - millisecondsEllapsed - 16); 15670 15671 /* Remove pause object after processing */ 15672 callContainer[5] = null; 15673 } else { 15674 continue; 15675 } 15676 } 15677 15678 millisecondsEllapsed = callContainer[6] = timeCurrent - timeStart; 15679 15680 /* The tween's completion percentage is relative to the tween's start time, not the tween's start value 15681 (which would result in unpredictable tween durations since JavaScript's timers are not particularly accurate). 15682 Accordingly, we ensure that percentComplete does not exceed 1. */ 15683 var percentComplete = Math.min((millisecondsEllapsed) / opts.duration, 1); 15684 15685 /********************** 15686 Element Iteration 15687 **********************/ 15688 15689 /* For every call, iterate through each of the elements in its set. */ 15690 for (var j = 0, callLength = call.length; j < callLength; j++) { 15691 var tweensContainer = call[j], 15692 element = tweensContainer.element; 15693 15694 /* Check to see if this element has been deleted midway through the animation by checking for the 15695 continued existence of its data cache. If it's gone, or the element is currently paused, skip animating this element. */ 15696 if (!Data(element)) { 15697 continue; 15698 } 15699 15700 var transformPropertyExists = false; 15701 15702 /********************************** 15703 Display & Visibility Toggling 15704 **********************************/ 15705 15706 /* If the display option is set to non-"none", set it upfront so that the element can become visible before tweening begins. 15707 (Otherwise, display's "none" value is set in completeCall() once the animation has completed.) */ 15708 if (opts.display !== undefined && opts.display !== null && opts.display !== "none") { 15709 if (opts.display === "flex") { 15710 var flexValues = ["-webkit-box", "-moz-box", "-ms-flexbox", "-webkit-flex"]; 15711 15712 $.each(flexValues, function(i, flexValue) { 15713 CSS.setPropertyValue(element, "display", flexValue); 15714 }); 15715 } 15716 15717 CSS.setPropertyValue(element, "display", opts.display); 15718 } 15719 15720 /* Same goes with the visibility option, but its "none" equivalent is "hidden". */ 15721 if (opts.visibility !== undefined && opts.visibility !== "hidden") { 15722 CSS.setPropertyValue(element, "visibility", opts.visibility); 15723 } 15724 15725 /************************ 15726 Property Iteration 15727 ************************/ 15728 15729 /* For every element, iterate through each property. */ 15730 for (var property in tweensContainer) { 15731 /* Note: In addition to property tween data, tweensContainer contains a reference to its associated element. */ 15732 if (tweensContainer.hasOwnProperty(property) && property !== "element") { 15733 var tween = tweensContainer[property], 15734 currentValue, 15735 /* Easing can either be a pre-genereated function or a string that references a pre-registered easing 15736 on the Velocity.Easings object. In either case, return the appropriate easing *function*. */ 15737 easing = Type.isString(tween.easing) ? Velocity.Easings[tween.easing] : tween.easing; 15738 15739 /****************************** 15740 Current Value Calculation 15741 ******************************/ 15742 15743 if (Type.isString(tween.pattern)) { 15744 var patternReplace = percentComplete === 1 ? 15745 function($0, index, round) { 15746 var result = tween.endValue[index]; 15747 15748 return round ? Math.round(result) : result; 15749 } : 15750 function($0, index, round) { 15751 var startValue = tween.startValue[index], 15752 tweenDelta = tween.endValue[index] - startValue, 15753 result = startValue + (tweenDelta * easing(percentComplete, opts, tweenDelta)); 15754 15755 return round ? Math.round(result) : result; 15756 }; 15757 15758 currentValue = tween.pattern.replace(/{(\d+)(!)?}/g, patternReplace); 15759 } else if (percentComplete === 1) { 15760 /* If this is the last tick pass (if we've reached 100% completion for this tween), 15761 ensure that currentValue is explicitly set to its target endValue so that it's not subjected to any rounding. */ 15762 currentValue = tween.endValue; 15763 } else { 15764 /* Otherwise, calculate currentValue based on the current delta from startValue. */ 15765 var tweenDelta = tween.endValue - tween.startValue; 15766 15767 currentValue = tween.startValue + (tweenDelta * easing(percentComplete, opts, tweenDelta)); 15768 /* If no value change is occurring, don't proceed with DOM updating. */ 15769 } 15770 if (!firstTick && (currentValue === tween.currentValue)) { 15771 continue; 15772 } 15773 15774 tween.currentValue = currentValue; 15775 15776 /* If we're tweening a fake 'tween' property in order to log transition values, update the one-per-call variable so that 15777 it can be passed into the progress callback. */ 15778 if (property === "tween") { 15779 tweenDummyValue = currentValue; 15780 } else { 15781 /****************** 15782 Hooks: Part I 15783 ******************/ 15784 var hookRoot; 15785 15786 /* For hooked properties, the newly-updated rootPropertyValueCache is cached onto the element so that it can be used 15787 for subsequent hooks in this call that are associated with the same root property. If we didn't cache the updated 15788 rootPropertyValue, each subsequent update to the root property in this tick pass would reset the previous hook's 15789 updates to rootPropertyValue prior to injection. A nice performance byproduct of rootPropertyValue caching is that 15790 subsequently chained animations using the same hookRoot but a different hook can use this cached rootPropertyValue. */ 15791 if (CSS.Hooks.registered[property]) { 15792 hookRoot = CSS.Hooks.getRoot(property); 15793 15794 var rootPropertyValueCache = Data(element).rootPropertyValueCache[hookRoot]; 15795 15796 if (rootPropertyValueCache) { 15797 tween.rootPropertyValue = rootPropertyValueCache; 15798 } 15799 } 15800 15801 /***************** 15802 DOM Update 15803 *****************/ 15804 15805 /* setPropertyValue() returns an array of the property name and property value post any normalization that may have been performed. */ 15806 /* Note: To solve an IE<=8 positioning bug, the unit type is dropped when setting a property value of 0. */ 15807 var adjustedSetData = CSS.setPropertyValue(element, /* SET */ 15808 property, 15809 tween.currentValue + (IE < 9 && parseFloat(currentValue) === 0 ? "" : tween.unitType), 15810 tween.rootPropertyValue, 15811 tween.scrollData); 15812 15813 /******************* 15814 Hooks: Part II 15815 *******************/ 15816 15817 /* Now that we have the hook's updated rootPropertyValue (the post-processed value provided by adjustedSetData), cache it onto the element. */ 15818 if (CSS.Hooks.registered[property]) { 15819 /* Since adjustedSetData contains normalized data ready for DOM updating, the rootPropertyValue needs to be re-extracted from its normalized form. ?? */ 15820 if (CSS.Normalizations.registered[hookRoot]) { 15821 Data(element).rootPropertyValueCache[hookRoot] = CSS.Normalizations.registered[hookRoot]("extract", null, adjustedSetData[1]); 15822 } else { 15823 Data(element).rootPropertyValueCache[hookRoot] = adjustedSetData[1]; 15824 } 15825 } 15826 15827 /*************** 15828 Transforms 15829 ***************/ 15830 15831 /* Flag whether a transform property is being animated so that flushTransformCache() can be triggered once this tick pass is complete. */ 15832 if (adjustedSetData[0] === "transform") { 15833 transformPropertyExists = true; 15834 } 15835 15836 } 15837 } 15838 } 15839 15840 /**************** 15841 mobileHA 15842 ****************/ 15843 15844 /* If mobileHA is enabled, set the translate3d transform to null to force hardware acceleration. 15845 It's safe to override this property since Velocity doesn't actually support its animation (hooks are used in its place). */ 15846 if (opts.mobileHA) { 15847 /* Don't set the null transform hack if we've already done so. */ 15848 if (Data(element).transformCache.translate3d === undefined) { 15849 /* All entries on the transformCache object are later concatenated into a single transform string via flushTransformCache(). */ 15850 Data(element).transformCache.translate3d = "(0px, 0px, 0px)"; 15851 15852 transformPropertyExists = true; 15853 } 15854 } 15855 15856 if (transformPropertyExists) { 15857 CSS.flushTransformCache(element); 15858 } 15859 } 15860 15861 /* The non-"none" display value is only applied to an element once -- when its associated call is first ticked through. 15862 Accordingly, it's set to false so that it isn't re-processed by this call in the next tick. */ 15863 if (opts.display !== undefined && opts.display !== "none") { 15864 Velocity.State.calls[i][2].display = false; 15865 } 15866 if (opts.visibility !== undefined && opts.visibility !== "hidden") { 15867 Velocity.State.calls[i][2].visibility = false; 15868 } 15869 15870 /* Pass the elements and the timing data (percentComplete, msRemaining, timeStart, tweenDummyValue) into the progress callback. */ 15871 if (opts.progress) { 15872 opts.progress.call(callContainer[1], 15873 callContainer[1], 15874 percentComplete, 15875 Math.max(0, (timeStart + opts.duration) - timeCurrent), 15876 timeStart, 15877 tweenDummyValue); 15878 } 15879 15880 /* If this call has finished tweening, pass its index to completeCall() to handle call cleanup. */ 15881 if (percentComplete === 1) { 15882 completeCall(i); 15883 } 15884 } 15885 } 15886 15887 /* Note: completeCall() sets the isTicking flag to false when the last call on Velocity.State.calls has completed. */ 15888 if (Velocity.State.isTicking) { 15889 ticker(tick); 15890 } 15891 } 15892 15893 /********************** 15894 Call Completion 15895 **********************/ 15896 15897 /* Note: Unlike tick(), which processes all active calls at once, call completion is handled on a per-call basis. */ 15898 function completeCall(callIndex, isStopped) { 15899 /* Ensure the call exists. */ 15900 if (!Velocity.State.calls[callIndex]) { 15901 return false; 15902 } 15903 15904 /* Pull the metadata from the call. */ 15905 var call = Velocity.State.calls[callIndex][0], 15906 elements = Velocity.State.calls[callIndex][1], 15907 opts = Velocity.State.calls[callIndex][2], 15908 resolver = Velocity.State.calls[callIndex][4]; 15909 15910 var remainingCallsExist = false; 15911 15912 /************************* 15913 Element Finalization 15914 *************************/ 15915 15916 for (var i = 0, callLength = call.length; i < callLength; i++) { 15917 var element = call[i].element; 15918 15919 /* If the user set display to "none" (intending to hide the element), set it now that the animation has completed. */ 15920 /* Note: display:none isn't set when calls are manually stopped (via Velocity("stop"). */ 15921 /* Note: Display gets ignored with "reverse" calls and infinite loops, since this behavior would be undesirable. */ 15922 if (!isStopped && !opts.loop) { 15923 if (opts.display === "none") { 15924 CSS.setPropertyValue(element, "display", opts.display); 15925 } 15926 15927 if (opts.visibility === "hidden") { 15928 CSS.setPropertyValue(element, "visibility", opts.visibility); 15929 } 15930 } 15931 15932 /* If the element's queue is empty (if only the "inprogress" item is left at position 0) or if its queue is about to run 15933 a non-Velocity-initiated entry, turn off the isAnimating flag. A non-Velocity-initiatied queue entry's logic might alter 15934 an element's CSS values and thereby cause Velocity's cached value data to go stale. To detect if a queue entry was initiated by Velocity, 15935 we check for the existence of our special Velocity.queueEntryFlag declaration, which minifiers won't rename since the flag 15936 is assigned to jQuery's global $ object and thus exists out of Velocity's own scope. */ 15937 var data = Data(element); 15938 15939 if (opts.loop !== true && ($.queue(element)[1] === undefined || !/\.velocityQueueEntryFlag/i.test($.queue(element)[1]))) { 15940 /* The element may have been deleted. Ensure that its data cache still exists before acting on it. */ 15941 if (data) { 15942 data.isAnimating = false; 15943 /* Clear the element's rootPropertyValueCache, which will become stale. */ 15944 data.rootPropertyValueCache = {}; 15945 15946 var transformHAPropertyExists = false; 15947 /* If any 3D transform subproperty is at its default value (regardless of unit type), remove it. */ 15948 $.each(CSS.Lists.transforms3D, function(i, transformName) { 15949 var defaultValue = /^scale/.test(transformName) ? 1 : 0, 15950 currentValue = data.transformCache[transformName]; 15951 15952 if (data.transformCache[transformName] !== undefined && new RegExp("^\\(" + defaultValue + "[^.]").test(currentValue)) { 15953 transformHAPropertyExists = true; 15954 15955 delete data.transformCache[transformName]; 15956 } 15957 }); 15958 15959 /* Mobile devices have hardware acceleration removed at the end of the animation in order to avoid hogging the GPU's memory. */ 15960 if (opts.mobileHA) { 15961 transformHAPropertyExists = true; 15962 delete data.transformCache.translate3d; 15963 } 15964 15965 /* Flush the subproperty removals to the DOM. */ 15966 if (transformHAPropertyExists) { 15967 CSS.flushTransformCache(element); 15968 } 15969 15970 /* Remove the "velocity-animating" indicator class. */ 15971 CSS.Values.removeClass(element, "velocity-animating"); 15972 } 15973 } 15974 15975 /********************* 15976 Option: Complete 15977 *********************/ 15978 15979 /* Complete is fired once per call (not once per element) and is passed the full raw DOM element set as both its context and its first argument. */ 15980 /* Note: Callbacks aren't fired when calls are manually stopped (via Velocity("stop"). */ 15981 if (!isStopped && opts.complete && !opts.loop && (i === callLength - 1)) { 15982 /* We throw callbacks in a setTimeout so that thrown errors don't halt the execution of Velocity itself. */ 15983 try { 15984 opts.complete.call(elements, elements); 15985 } catch (error) { 15986 setTimeout(function() { 15987 throw error; 15988 }, 1); 15989 } 15990 } 15991 15992 /********************** 15993 Promise Resolving 15994 **********************/ 15995 15996 /* Note: Infinite loops don't return promises. */ 15997 if (resolver && opts.loop !== true) { 15998 resolver(elements); 15999 } 16000 16001 /**************************** 16002 Option: Loop (Infinite) 16003 ****************************/ 16004 16005 if (data && opts.loop === true && !isStopped) { 16006 /* If a rotateX/Y/Z property is being animated by 360 deg with loop:true, swap tween start/end values to enable 16007 continuous iterative rotation looping. (Otherise, the element would just rotate back and forth.) */ 16008 $.each(data.tweensContainer, function(propertyName, tweenContainer) { 16009 if (/^rotate/.test(propertyName) && ((parseFloat(tweenContainer.startValue) - parseFloat(tweenContainer.endValue)) % 360 === 0)) { 16010 var oldStartValue = tweenContainer.startValue; 16011 16012 tweenContainer.startValue = tweenContainer.endValue; 16013 tweenContainer.endValue = oldStartValue; 16014 } 16015 16016 if (/^backgroundPosition/.test(propertyName) && parseFloat(tweenContainer.endValue) === 100 && tweenContainer.unitType === "%") { 16017 tweenContainer.endValue = 0; 16018 tweenContainer.startValue = 100; 16019 } 16020 }); 16021 16022 Velocity(element, "reverse", {loop: true, delay: opts.delay}); 16023 } 16024 16025 /*************** 16026 Dequeueing 16027 ***************/ 16028 16029 /* Fire the next call in the queue so long as this call's queue wasn't set to false (to trigger a parallel animation), 16030 which would have already caused the next call to fire. Note: Even if the end of the animation queue has been reached, 16031 $.dequeue() must still be called in order to completely clear jQuery's animation queue. */ 16032 if (opts.queue !== false) { 16033 $.dequeue(element, opts.queue); 16034 } 16035 } 16036 16037 /************************ 16038 Calls Array Cleanup 16039 ************************/ 16040 16041 /* Since this call is complete, set it to false so that the rAF tick skips it. This array is later compacted via compactSparseArray(). 16042 (For performance reasons, the call is set to false instead of being deleted from the array: http://www.html5rocks.com/en/tutorials/speed/v8/) */ 16043 Velocity.State.calls[callIndex] = false; 16044 16045 /* Iterate through the calls array to determine if this was the final in-progress animation. 16046 If so, set a flag to end ticking and clear the calls array. */ 16047 for (var j = 0, callsLength = Velocity.State.calls.length; j < callsLength; j++) { 16048 if (Velocity.State.calls[j] !== false) { 16049 remainingCallsExist = true; 16050 16051 break; 16052 } 16053 } 16054 16055 if (remainingCallsExist === false) { 16056 /* tick() will detect this flag upon its next iteration and subsequently turn itself off. */ 16057 Velocity.State.isTicking = false;
16058 16059 /* Clear the calls array so that its length is reset. */ 16060 delete Velocity.State.calls; 16061 Velocity.State.calls = []; 16062 } 16063 } 16064 16065 /****************** 16066 Frameworks 16067 ******************/ 16068 16069 /* Both jQuery and Zepto allow their $.fn object to be extended to allow wrapped elements to be subjected to plugin calls. 16070 If either framework is loaded, register a "velocity" extension pointing to Velocity's core animate() method. Velocity 16071 also registers itself onto a global container (window.jQuery || window.Zepto || window) so that certain features are 16072 accessible beyond just a per-element scope. This master object contains an .animate() method, which is later assigned to $.fn 16073 (if jQuery or Zepto are present). Accordingly, Velocity can both act on wrapped DOM elements and stand alone for targeting raw DOM elements. */ 16074 global.Velocity = Velocity; 16075 16076 if (global !== window) { 16077 /* Assign the element function to Velocity's core animate() method. */ 16078 global.fn.velocity = animate; 16079 /* Assign the object function's defaults to Velocity's global defaults object. */ 16080 global.fn.velocity.defaults = Velocity.defaults; 16081 } 16082 16083 /*********************** 16084 Packaged Redirects 16085 ***********************/ 16086 16087 /* slideUp, slideDown */ 16088 $.each(["Down", "Up"], function(i, direction) { 16089 Velocity.Redirects["slide" + direction] = function(element, options, elementsIndex, elementsSize, elements, promiseData) { 16090 var opts = $.extend({}, options), 16091 begin = opts.begin, 16092 complete = opts.complete, 16093 inlineValues = {}, 16094 computedValues = {height: "", marginTop: "", marginBottom: "", paddingTop: "", paddingBottom: ""}; 16095 16096 if (opts.display === undefined) { 16097 /* Show the element before slideDown begins and hide the element after slideUp completes. */ 16098 /* Note: Inline elements cannot have dimensions animated, so they're reverted to inline-block. */ 16099 opts.display = (direction === "Down" ? (Velocity.CSS.Values.getDisplayType(element) === "inline" ? "inline-block" : "block") : "none"); 16100 } 16101 16102 opts.begin = function() { 16103 /* If the user passed in a begin callback, fire it now. */ 16104 if (elementsIndex === 0 && begin) { 16105 begin.call(elements, elements); 16106 } 16107 16108 /* Cache the elements' original vertical dimensional property values so that we can animate back to them. */ 16109 for (var property in computedValues) { 16110 if (!computedValues.hasOwnProperty(property)) { 16111 continue; 16112 } 16113 inlineValues[property] = element.style[property]; 16114 16115 /* For slideDown, use forcefeeding to animate all vertical properties from 0. For slideUp, 16116 use forcefeeding to start from computed values and animate down to 0. */ 16117 var propertyValue = CSS.getPropertyValue(element, property); 16118 computedValues[property] = (direction === "Down") ? [propertyValue, 0] : [0, propertyValue]; 16119 } 16120 16121 /* Force vertical overflow content to clip so that sliding works as expected. */ 16122 inlineValues.overflow = element.style.overflow; 16123 element.style.overflow = "hidden"; 16124 }; 16125 16126 opts.complete = function() { 16127 /* Reset element to its pre-slide inline values once its slide animation is complete. */ 16128 for (var property in inlineValues) { 16129 if (inlineValues.hasOwnProperty(property)) { 16130 element.style[property] = inlineValues[property]; 16131 } 16132 } 16133 16134 /* If the user passed in a complete callback, fire it now. */ 16135 if (elementsIndex === elementsSize - 1) { 16136 if (complete) { 16137 complete.call(elements, elements); 16138 } 16139 if (promiseData) { 16140 promiseData.resolver(elements); 16141 } 16142 } 16143 }; 16144 16145 Velocity(element, computedValues, opts); 16146 }; 16147 }); 16148 16149 /* fadeIn, fadeOut */ 16150 $.each(["In", "Out"], function(i, direction) { 16151 Velocity.Redirects["fade" + direction] = function(element, options, elementsIndex, elementsSize, elements, promiseData) { 16152 var opts = $.extend({}, options), 16153 complete = opts.complete, 16154 propertiesMap = {opacity: (direction === "In") ? 1 : 0}; 16155 16156 /* Since redirects are triggered individually for each element in the animated set, avoid repeatedly triggering 16157 callbacks by firing them only when the final element has been reached. */ 16158 if (elementsIndex !== 0) { 16159 opts.begin = null; 16160 } 16161 if (elementsIndex !== elementsSize - 1) { 16162 opts.complete = null; 16163 } else { 16164 opts.complete = function() { 16165 if (complete) { 16166 complete.call(elements, elements); 16167 } 16168 if (promiseData) { 16169 promiseData.resolver(elements); 16170 } 16171 }; 16172 } 16173 16174 /* If a display was passed in, use it. Otherwise, default to "none" for fadeOut or the element-specific default for fadeIn. */ 16175 /* Note: We allow users to pass in "null" to skip display setting altogether. */ 16176 if (opts.display === undefined) { 16177 opts.display = (direction === "In" ? "auto" : "none"); 16178 } 16179 16180 Velocity(this, propertiesMap, opts); 16181 }; 16182 }); 16183 16184 return Velocity; 16185 }((window.jQuery || window.Zepto || window), window, (window ? window.document : undefined)); 16186})); 16187 16188/****************** 16189 Known Issues 16190 ******************/ 16191 16192/* The CSS spec mandates that the translateX/Y/Z transforms are %-relative to the element itself -- not its parent. 16193 Velocity, however, doesn't make this distinction. Thus, converting to or from the % unit with these subproperties 16194 will produce an inaccurate conversion value. The same issue exists with the cx/cy attributes of SVG circles and ellipses. */ 16195 16196},{}],55:[function(require,module,exports){ 16197/********************** 16198 Velocity UI Pack 16199 **********************/ 16200 16201/* VelocityJS.org UI Pack (5.2.0). (C) 2014 Julian Shapiro. MIT @license: en.wikipedia.org/wiki/MIT_License. Portions copyright Daniel Eden, Christian Pucci. */ 16202 16203(function(factory) { 16204 "use strict"; 16205 /* CommonJS module. */ 16206 if (typeof require === "function" && typeof exports === "object") { 16207 module.exports = factory(); 16208 /* AMD module. */ 16209 } else if (typeof define === "function" && define.amd) { 16210 define(["velocity"], factory); 16211 /* Browser globals. */ 16212 } else { 16213 factory(); 16214 } 16215}(function() { 16216 "use strict"; 16217 return function(global, window, document, undefined) { 16218 16219 /************* 16220 Checks 16221 *************/ 16222 var Velocity = global.Velocity; 16223 16224 if (!Velocity || !Velocity.Utilities) { 16225 if (window.console) { 16226 console.log("Velocity UI Pack: Velocity must be loaded first. Aborting."); 16227 } 16228 return; 16229 } 16230 var $ = Velocity.Utilities; 16231 16232 var velocityVersion = Velocity.version, 16233 requiredVersion = {major: 1, minor: 1, patch: 0}; 16234 16235 function greaterSemver(primary, secondary) { 16236 var versionInts = []; 16237 16238 if (!primary || !secondary) { 16239 return false;
vendor: 27,195 bytes, lines 16240-17002
16240 } 16241 16242 $.each([primary, secondary], function(i, versionObject) { 16243 var versionIntsComponents = []; 16244 16245 $.each(versionObject, function(component, value) { 16246 while (value.toString().length < 5) { 16247 value = "0" + value; 16248 } 16249 versionIntsComponents.push(value); 16250 }); 16251 16252 versionInts.push(versionIntsComponents.join("")); 16253 }); 16254 16255 return (parseFloat(versionInts[0]) > parseFloat(versionInts[1])); 16256 } 16257 16258 if (greaterSemver(requiredVersion, velocityVersion)) { 16259 var abortError = "Velocity UI Pack: You need to update Velocity (velocity.js) to a newer version. Visit http://github.com/julianshapiro/velocity."; 16260 alert(abortError); 16261 throw new Error(abortError); 16262 } 16263 16264 /************************ 16265 Effect Registration 16266 ************************/ 16267 16268 /* Note: RegisterUI is a legacy name. */ 16269 Velocity.RegisterEffect = Velocity.RegisterUI = function(effectName, properties) { 16270 /* Animate the expansion/contraction of the elements' parent's height for In/Out effects. */ 16271 function animateParentHeight(elements, direction, totalDuration, stagger) { 16272 var totalHeightDelta = 0, 16273 parentNode; 16274 16275 /* Sum the total height (including padding and margin) of all targeted elements. */ 16276 $.each(elements.nodeType ? [elements] : elements, function(i, element) { 16277 if (stagger) { 16278 /* Increase the totalDuration by the successive delay amounts produced by the stagger option. */ 16279 totalDuration += i * stagger; 16280 } 16281 16282 parentNode = element.parentNode; 16283 16284 var propertiesToSum = ["height", "paddingTop", "paddingBottom", "marginTop", "marginBottom"]; 16285 16286 /* If box-sizing is border-box, the height already includes padding and margin */ 16287 if (Velocity.CSS.getPropertyValue(element, "boxSizing").toString().toLowerCase() === "border-box") { 16288 propertiesToSum = ["height"]; 16289 } 16290 16291 $.each(propertiesToSum, function(i, property) { 16292 totalHeightDelta += parseFloat(Velocity.CSS.getPropertyValue(element, property)); 16293 }); 16294 }); 16295 16296 /* Animate the parent element's height adjustment (with a varying duration multiplier for aesthetic benefits). */ 16297 Velocity.animate( 16298 parentNode, 16299 {height: (direction === "In" ? "+" : "-") + "=" + totalHeightDelta}, 16300 {queue: false, easing: "ease-in-out", duration: totalDuration * (direction === "In" ? 0.6 : 1)} 16301 ); 16302 } 16303 16304 /* Register a custom redirect for each effect. */ 16305 Velocity.Redirects[effectName] = function(element, redirectOptions, elementsIndex, elementsSize, elements, promiseData, loop) { 16306 var finalElement = (elementsIndex === elementsSize - 1), 16307 totalDuration = 0; 16308 16309 loop = loop || properties.loop; 16310 if (typeof properties.defaultDuration === "function") { 16311 properties.defaultDuration = properties.defaultDuration.call(elements, elements); 16312 } else { 16313 properties.defaultDuration = parseFloat(properties.defaultDuration); 16314 } 16315 16316 /* Get the total duration used, so we can share it out with everything that doesn't have a duration */ 16317 for (var callIndex = 0; callIndex < properties.calls.length; callIndex++) { 16318 durationPercentage = properties.calls[callIndex][1]; 16319 if (typeof durationPercentage === "number") { 16320 totalDuration += durationPercentage; 16321 } 16322 } 16323 var shareDuration = totalDuration >= 1 ? 0 : properties.calls.length ? (1 - totalDuration) / properties.calls.length : 1; 16324 16325 /* Iterate through each effect's call array. */ 16326 for (callIndex = 0; callIndex < properties.calls.length; callIndex++) { 16327 var call = properties.calls[callIndex], 16328 propertyMap = call[0], 16329 redirectDuration = 1000, 16330 durationPercentage = call[1], 16331 callOptions = call[2] || {}, 16332 opts = {}; 16333 16334 if (redirectOptions.duration !== undefined) { 16335 redirectDuration = redirectOptions.duration; 16336 } else if (properties.defaultDuration !== undefined) { 16337 redirectDuration = properties.defaultDuration; 16338 } 16339 16340 /* Assign the whitelisted per-call options. */ 16341 opts.duration = redirectDuration * (typeof durationPercentage === "number" ? durationPercentage : shareDuration); 16342 opts.queue = redirectOptions.queue || ""; 16343 opts.easing = callOptions.easing || "ease"; 16344 opts.delay = parseFloat(callOptions.delay) || 0; 16345 opts.loop = !properties.loop && callOptions.loop; 16346 opts._cacheValues = callOptions._cacheValues || true; 16347 16348 /* Special processing for the first effect call. */ 16349 if (callIndex === 0) { 16350 /* If a delay was passed into the redirect, combine it with the first call's delay. */ 16351 opts.delay += (parseFloat(redirectOptions.delay) || 0); 16352 16353 if (elementsIndex === 0) { 16354 opts.begin = function() { 16355 /* Only trigger a begin callback on the first effect call with the first element in the set. */ 16356 if (redirectOptions.begin) { 16357 redirectOptions.begin.call(elements, elements); 16358 } 16359 16360 var direction = effectName.match(/(In|Out)$/); 16361 16362 /* Make "in" transitioning elements invisible immediately so that there's no FOUC between now 16363 and the first RAF tick. */ 16364 if ((direction && direction[0] === "In") && propertyMap.opacity !== undefined) { 16365 $.each(elements.nodeType ? [elements] : elements, function(i, element) { 16366 Velocity.CSS.setPropertyValue(element, "opacity", 0); 16367 }); 16368 } 16369 16370 /* Only trigger animateParentHeight() if we're using an In/Out transition. */ 16371 if (redirectOptions.animateParentHeight && direction) { 16372 animateParentHeight(elements, direction[0], redirectDuration + opts.delay, redirectOptions.stagger); 16373 } 16374 }; 16375 } 16376 16377 /* If the user isn't overriding the display option, default to "auto" for "In"-suffixed transitions. */ 16378 if (redirectOptions.display !== null) { 16379 if (redirectOptions.display !== undefined && redirectOptions.display !== "none") { 16380 opts.display = redirectOptions.display; 16381 } else if (/In$/.test(effectName)) { 16382 /* Inline elements cannot be subjected to transforms, so we switch them to inline-block. */ 16383 var defaultDisplay = Velocity.CSS.Values.getDisplayType(element); 16384 opts.display = (defaultDisplay === "inline") ? "inline-block" : defaultDisplay; 16385 } 16386 } 16387 16388 if (redirectOptions.visibility && redirectOptions.visibility !== "hidden") { 16389 opts.visibility = redirectOptions.visibility; 16390 } 16391 } 16392 16393 /* Special processing for the last effect call. */ 16394 if (callIndex === properties.calls.length - 1) { 16395 /* Append promise resolving onto the user's redirect callback. */ 16396 var injectFinalCallbacks = function() { 16397 if ((redirectOptions.display === undefined || redirectOptions.display === "none") && /Out$/.test(effectName)) { 16398 $.each(elements.nodeType ? [elements] : elements, function(i, element) { 16399 Velocity.CSS.setPropertyValue(element, "display", "none"); 16400 }); 16401 } 16402 if (redirectOptions.complete) { 16403 redirectOptions.complete.call(elements, elements); 16404 } 16405 if (promiseData) { 16406 promiseData.resolver(elements || element); 16407 } 16408 }; 16409 16410 opts.complete = function() { 16411 if (loop) { 16412 Velocity.Redirects[effectName](element, redirectOptions, elementsIndex, elementsSize, elements, promiseData, loop === true ? true : Math.max(0, loop - 1)); 16413 } 16414 if (properties.reset) { 16415 for (var resetProperty in properties.reset) { 16416 if (!properties.reset.hasOwnProperty(resetProperty)) { 16417 continue; 16418 } 16419 var resetValue = properties.reset[resetProperty]; 16420 16421 /* Format each non-array value in the reset property map to [ value, value ] so that changes apply 16422 immediately and DOM querying is avoided (via forcefeeding). */ 16423 /* Note: Don't forcefeed hooks, otherwise their hook roots will be defaulted to their null values. */ 16424 if (Velocity.CSS.Hooks.registered[resetProperty] === undefined && (typeof resetValue === "string" || typeof resetValue === "number")) { 16425 properties.reset[resetProperty] = [properties.reset[resetProperty], properties.reset[resetProperty]]; 16426 } 16427 } 16428 16429 /* So that the reset values are applied instantly upon the next rAF tick, use a zero duration and parallel queueing. */ 16430 var resetOptions = {duration: 0, queue: false}; 16431 16432 /* Since the reset option uses up the complete callback, we trigger the user's complete callback at the end of ours. */ 16433 if (finalElement) { 16434 resetOptions.complete = injectFinalCallbacks; 16435 } 16436 16437 Velocity.animate(element, properties.reset, resetOptions); 16438 /* Only trigger the user's complete callback on the last effect call with the last element in the set. */ 16439 } else if (finalElement) { 16440 injectFinalCallbacks(); 16441 } 16442 }; 16443 16444 if (redirectOptions.visibility === "hidden") { 16445 opts.visibility = redirectOptions.visibility; 16446 } 16447 } 16448 16449 Velocity.animate(element, propertyMap, opts); 16450 } 16451 }; 16452 16453 /* Return the Velocity object so that RegisterUI calls can be chained. */ 16454 return Velocity; 16455 }; 16456 16457 /********************* 16458 Packaged Effects 16459 *********************/ 16460 16461 /* Externalize the packagedEffects data so that they can optionally be modified and re-registered. */ 16462 /* Support: <=IE8: Callouts will have no effect, and transitions will simply fade in/out. IE9/Android 2.3: Most effects are fully supported, the rest fade in/out. All other browsers: full support. */ 16463 Velocity.RegisterEffect.packagedEffects = 16464 { 16465 /* Animate.css */ 16466 "callout.bounce": { 16467 defaultDuration: 550, 16468 calls: [ 16469 [{translateY: -30}, 0.25], 16470 [{translateY: 0}, 0.125], 16471 [{translateY: -15}, 0.125], 16472 [{translateY: 0}, 0.25] 16473 ] 16474 }, 16475 /* Animate.css */ 16476 "callout.shake": { 16477 defaultDuration: 800, 16478 calls: [ 16479 [{translateX: -11}], 16480 [{translateX: 11}], 16481 [{translateX: -11}], 16482 [{translateX: 11}], 16483 [{translateX: -11}], 16484 [{translateX: 11}], 16485 [{translateX: -11}], 16486 [{translateX: 0}] 16487 ] 16488 }, 16489 /* Animate.css */ 16490 "callout.flash": { 16491 defaultDuration: 1100, 16492 calls: [ 16493 [{opacity: [0, "easeInOutQuad", 1]}], 16494 [{opacity: [1, "easeInOutQuad"]}], 16495 [{opacity: [0, "easeInOutQuad"]}], 16496 [{opacity: [1, "easeInOutQuad"]}] 16497 ] 16498 }, 16499 /* Animate.css */ 16500 "callout.pulse": { 16501 defaultDuration: 825, 16502 calls: [ 16503 [{scaleX: 1.1, scaleY: 1.1}, 0.50, {easing: "easeInExpo"}], 16504 [{scaleX: 1, scaleY: 1}, 0.50] 16505 ] 16506 }, 16507 /* Animate.css */ 16508 "callout.swing": { 16509 defaultDuration: 950, 16510 calls: [ 16511 [{rotateZ: 15}], 16512 [{rotateZ: -10}], 16513 [{rotateZ: 5}], 16514 [{rotateZ: -5}], 16515 [{rotateZ: 0}] 16516 ] 16517 }, 16518 /* Animate.css */ 16519 "callout.tada": { 16520 defaultDuration: 1000, 16521 calls: [ 16522 [{scaleX: 0.9, scaleY: 0.9, rotateZ: -3}, 0.10], 16523 [{scaleX: 1.1, scaleY: 1.1, rotateZ: 3}, 0.10], 16524 [{scaleX: 1.1, scaleY: 1.1, rotateZ: -3}, 0.10], 16525 ["reverse", 0.125], 16526 ["reverse", 0.125], 16527 ["reverse", 0.125], 16528 ["reverse", 0.125], 16529 ["reverse", 0.125], 16530 [{scaleX: 1, scaleY: 1, rotateZ: 0}, 0.20] 16531 ] 16532 }, 16533 "transition.fadeIn": { 16534 defaultDuration: 500, 16535 calls: [ 16536 [{opacity: [1, 0]}] 16537 ] 16538 }, 16539 "transition.fadeOut": { 16540 defaultDuration: 500, 16541 calls: [ 16542 [{opacity: [0, 1]}] 16543 ] 16544 }, 16545 /* Support: Loses rotation in IE9/Android 2.3 (fades only). */ 16546 "transition.flipXIn": { 16547 defaultDuration: 700, 16548 calls: [ 16549 [{opacity: [1, 0], transformPerspective: [800, 800], rotateY: [0, -55]}] 16550 ], 16551 reset: {transformPerspective: 0} 16552 }, 16553 /* Support: Loses rotation in IE9/Android 2.3 (fades only). */ 16554 "transition.flipXOut": { 16555 defaultDuration: 700, 16556 calls: [ 16557 [{opacity: [0, 1], transformPerspective: [800, 800], rotateY: 55}] 16558 ], 16559 reset: {transformPerspective: 0, rotateY: 0} 16560 }, 16561 /* Support: Loses rotation in IE9/Android 2.3 (fades only). */ 16562 "transition.flipYIn": { 16563 defaultDuration: 800, 16564 calls: [ 16565 [{opacity: [1, 0], transformPerspective: [800, 800], rotateX: [0, -45]}] 16566 ], 16567 reset: {transformPerspective: 0} 16568 }, 16569 /* Support: Loses rotation in IE9/Android 2.3 (fades only). */ 16570 "transition.flipYOut": { 16571 defaultDuration: 800, 16572 calls: [ 16573 [{opacity: [0, 1], transformPerspective: [800, 800], rotateX: 25}] 16574 ], 16575 reset: {transformPerspective: 0, rotateX: 0} 16576 }, 16577 /* Animate.css */ 16578 /* Support: Loses rotation in IE9/Android 2.3 (fades only). */ 16579 "transition.flipBounceXIn": { 16580 defaultDuration: 900, 16581 calls: [ 16582 [{opacity: [0.725, 0], transformPerspective: [400, 400], rotateY: [-10, 90]}, 0.50], 16583 [{opacity: 0.80, rotateY: 10}, 0.25], 16584 [{opacity: 1, rotateY: 0}, 0.25] 16585 ], 16586 reset: {transformPerspective: 0} 16587 }, 16588 /* Animate.css */ 16589 /* Support: Loses rotation in IE9/Android 2.3 (fades only). */ 16590 "transition.flipBounceXOut": { 16591 defaultDuration: 800, 16592 calls: [ 16593 [{opacity: [0.9, 1], transformPerspective: [400, 400], rotateY: -10}], 16594 [{opacity: 0, rotateY: 90}] 16595 ], 16596 reset: {transformPerspective: 0, rotateY: 0} 16597 }, 16598 /* Animate.css */ 16599 /* Support: Loses rotation in IE9/Android 2.3 (fades only). */ 16600 "transition.flipBounceYIn": { 16601 defaultDuration: 850, 16602 calls: [ 16603 [{opacity: [0.725, 0], transformPerspective: [400, 400], rotateX: [-10, 90]}, 0.50], 16604 [{opacity: 0.80, rotateX: 10}, 0.25], 16605 [{opacity: 1, rotateX: 0}, 0.25] 16606 ], 16607 reset: {transformPerspective: 0} 16608 }, 16609 /* Animate.css */ 16610 /* Support: Loses rotation in IE9/Android 2.3 (fades only). */ 16611 "transition.flipBounceYOut": { 16612 defaultDuration: 800, 16613 calls: [ 16614 [{opacity: [0.9, 1], transformPerspective: [400, 400], rotateX: -15}], 16615 [{opacity: 0, rotateX: 90}] 16616 ], 16617 reset: {transformPerspective: 0, rotateX: 0} 16618 }, 16619 /* Magic.css */ 16620 "transition.swoopIn": { 16621 defaultDuration: 850, 16622 calls: [ 16623 [{opacity: [1, 0], transformOriginX: ["100%", "50%"], transformOriginY: ["100%", "100%"], scaleX: [1, 0], scaleY: [1, 0], translateX: [0, -700], translateZ: 0}] 16624 ], 16625 reset: {transformOriginX: "50%", transformOriginY: "50%"} 16626 }, 16627 /* Magic.css */ 16628 "transition.swoopOut": { 16629 defaultDuration: 850, 16630 calls: [ 16631 [{opacity: [0, 1], transformOriginX: ["50%", "100%"], transformOriginY: ["100%", "100%"], scaleX: 0, scaleY: 0, translateX: -700, translateZ: 0}] 16632 ], 16633 reset: {transformOriginX: "50%", transformOriginY: "50%", scaleX: 1, scaleY: 1, translateX: 0} 16634 }, 16635 /* Magic.css */ 16636 /* Support: Loses rotation in IE9/Android 2.3. (Fades and scales only.) */ 16637 "transition.whirlIn": { 16638 defaultDuration: 850, 16639 calls: [ 16640 [{opacity: [1, 0], transformOriginX: ["50%", "50%"], transformOriginY: ["50%", "50%"], scaleX: [1, 0], scaleY: [1, 0], rotateY: [0, 160]}, 1, {easing: "easeInOutSine"}] 16641 ] 16642 }, 16643 /* Magic.css */ 16644 /* Support: Loses rotation in IE9/Android 2.3. (Fades and scales only.) */ 16645 "transition.whirlOut": { 16646 defaultDuration: 750, 16647 calls: [ 16648 [{opacity: [0, "easeInOutQuint", 1], transformOriginX: ["50%", "50%"], transformOriginY: ["50%", "50%"], scaleX: 0, scaleY: 0, rotateY: 160}, 1, {easing: "swing"}] 16649 ], 16650 reset: {scaleX: 1, scaleY: 1, rotateY: 0} 16651 }, 16652 "transition.shrinkIn": { 16653 defaultDuration: 750, 16654 calls: [ 16655 [{opacity: [1, 0], transformOriginX: ["50%", "50%"], transformOriginY: ["50%", "50%"], scaleX: [1, 1.5], scaleY: [1, 1.5], translateZ: 0}] 16656 ] 16657 }, 16658 "transition.shrinkOut": { 16659 defaultDuration: 600, 16660 calls: [ 16661 [{opacity: [0, 1], transformOriginX: ["50%", "50%"], transformOriginY: ["50%", "50%"], scaleX: 1.3, scaleY: 1.3, translateZ: 0}] 16662 ], 16663 reset: {scaleX: 1, scaleY: 1} 16664 }, 16665 "transition.expandIn": { 16666 defaultDuration: 700, 16667 calls: [ 16668 [{opacity: [1, 0], transformOriginX: ["50%", "50%"], transformOriginY: ["50%", "50%"], scaleX: [1, 0.625], scaleY: [1, 0.625], translateZ: 0}] 16669 ] 16670 }, 16671 "transition.expandOut": { 16672 defaultDuration: 700, 16673 calls: [ 16674 [{opacity: [0, 1], transformOriginX: ["50%", "50%"], transformOriginY: ["50%", "50%"], scaleX: 0.5, scaleY: 0.5, translateZ: 0}] 16675 ], 16676 reset: {scaleX: 1, scaleY: 1} 16677 }, 16678 /* Animate.css */ 16679 "transition.bounceIn": { 16680 defaultDuration: 800, 16681 calls: [ 16682 [{opacity: [1, 0], scaleX: [1.05, 0.3], scaleY: [1.05, 0.3]}, 0.35], 16683 [{scaleX: 0.9, scaleY: 0.9, translateZ: 0}, 0.20], 16684 [{scaleX: 1, scaleY: 1}, 0.45] 16685 ] 16686 }, 16687 /* Animate.css */ 16688 "transition.bounceOut": { 16689 defaultDuration: 800, 16690 calls: [ 16691 [{scaleX: 0.95, scaleY: 0.95}, 0.35], 16692 [{scaleX: 1.1, scaleY: 1.1, translateZ: 0}, 0.35], 16693 [{opacity: [0, 1], scaleX: 0.3, scaleY: 0.3}, 0.30] 16694 ], 16695 reset: {scaleX: 1, scaleY: 1} 16696 }, 16697 /* Animate.css */ 16698 "transition.bounceUpIn": { 16699 defaultDuration: 800, 16700 calls: [ 16701 [{opacity: [1, 0], translateY: [-30, 1000]}, 0.60, {easing: "easeOutCirc"}], 16702 [{translateY: 10}, 0.20], 16703 [{translateY: 0}, 0.20] 16704 ] 16705 }, 16706 /* Animate.css */ 16707 "transition.bounceUpOut": { 16708 defaultDuration: 1000, 16709 calls: [ 16710 [{translateY: 20}, 0.20], 16711 [{opacity: [0, "easeInCirc", 1], translateY: -1000}, 0.80] 16712 ], 16713 reset: {translateY: 0} 16714 }, 16715 /* Animate.css */ 16716 "transition.bounceDownIn": { 16717 defaultDuration: 800, 16718 calls: [ 16719 [{opacity: [1, 0], translateY: [30, -1000]}, 0.60, {easing: "easeOutCirc"}], 16720 [{translateY: -10}, 0.20], 16721 [{translateY: 0}, 0.20] 16722 ] 16723 }, 16724 /* Animate.css */ 16725 "transition.bounceDownOut": { 16726 defaultDuration: 1000, 16727 calls: [ 16728 [{translateY: -20}, 0.20], 16729 [{opacity: [0, "easeInCirc", 1], translateY: 1000}, 0.80] 16730 ], 16731 reset: {translateY: 0} 16732 }, 16733 /* Animate.css */ 16734 "transition.bounceLeftIn": { 16735 defaultDuration: 750, 16736 calls: [ 16737 [{opacity: [1, 0], translateX: [30, -1250]}, 0.60, {easing: "easeOutCirc"}], 16738 [{translateX: -10}, 0.20], 16739 [{translateX: 0}, 0.20] 16740 ] 16741 }, 16742 /* Animate.css */ 16743 "transition.bounceLeftOut": { 16744 defaultDuration: 750, 16745 calls: [ 16746 [{translateX: 30}, 0.20], 16747 [{opacity: [0, "easeInCirc", 1], translateX: -1250}, 0.80] 16748 ], 16749 reset: {translateX: 0} 16750 }, 16751 /* Animate.css */ 16752 "transition.bounceRightIn": { 16753 defaultDuration: 750, 16754 calls: [ 16755 [{opacity: [1, 0], translateX: [-30, 1250]}, 0.60, {easing: "easeOutCirc"}], 16756 [{translateX: 10}, 0.20], 16757 [{translateX: 0}, 0.20] 16758 ] 16759 }, 16760 /* Animate.css */ 16761 "transition.bounceRightOut": { 16762 defaultDuration: 750, 16763 calls: [ 16764 [{translateX: -30}, 0.20], 16765 [{opacity: [0, "easeInCirc", 1], translateX: 1250}, 0.80] 16766 ], 16767 reset: {translateX: 0} 16768 }, 16769 "transition.slideUpIn": { 16770 defaultDuration: 900, 16771 calls: [ 16772 [{opacity: [1, 0], translateY: [0, 20], translateZ: 0}] 16773 ] 16774 }, 16775 "transition.slideUpOut": { 16776 defaultDuration: 900, 16777 calls: [ 16778 [{opacity: [0, 1], translateY: -20, translateZ: 0}] 16779 ], 16780 reset: {translateY: 0} 16781 }, 16782 "transition.slideDownIn": { 16783 defaultDuration: 900, 16784 calls: [ 16785 [{opacity: [1, 0], translateY: [0, -20], translateZ: 0}] 16786 ] 16787 }, 16788 "transition.slideDownOut": { 16789 defaultDuration: 900, 16790 calls: [ 16791 [{opacity: [0, 1], translateY: 20, translateZ: 0}] 16792 ], 16793 reset: {translateY: 0} 16794 }, 16795 "transition.slideLeftIn": { 16796 defaultDuration: 1000, 16797 calls: [ 16798 [{opacity: [1, 0], translateX: [0, -20], translateZ: 0}] 16799 ] 16800 }, 16801 "transition.slideLeftOut": { 16802 defaultDuration: 1050, 16803 calls: [ 16804 [{opacity: [0, 1], translateX: -20, translateZ: 0}] 16805 ], 16806 reset: {translateX: 0} 16807 }, 16808 "transition.slideRightIn": { 16809 defaultDuration: 1000, 16810 calls: [ 16811 [{opacity: [1, 0], translateX: [0, 20], translateZ: 0}] 16812 ] 16813 }, 16814 "transition.slideRightOut": { 16815 defaultDuration: 1050, 16816 calls: [ 16817 [{opacity: [0, 1], translateX: 20, translateZ: 0}] 16818 ], 16819 reset: {translateX: 0} 16820 }, 16821 "transition.slideUpBigIn": { 16822 defaultDuration: 850, 16823 calls: [ 16824 [{opacity: [1, 0], translateY: [0, 75], translateZ: 0}] 16825 ] 16826 }, 16827 "transition.slideUpBigOut": { 16828 defaultDuration: 800, 16829 calls: [ 16830 [{opacity: [0, 1], translateY: -75, translateZ: 0}] 16831 ], 16832 reset: {translateY: 0} 16833 }, 16834 "transition.slideDownBigIn": { 16835 defaultDuration: 850, 16836 calls: [ 16837 [{opacity: [1, 0], translateY: [0, -75], translateZ: 0}] 16838 ] 16839 }, 16840 "transition.slideDownBigOut": { 16841 defaultDuration: 800, 16842 calls: [ 16843 [{opacity: [0, 1], translateY: 75, translateZ: 0}] 16844 ], 16845 reset: {translateY: 0} 16846 }, 16847 "transition.slideLeftBigIn": { 16848 defaultDuration: 800, 16849 calls: [ 16850 [{opacity: [1, 0], translateX: [0, -75], translateZ: 0}] 16851 ] 16852 }, 16853 "transition.slideLeftBigOut": { 16854 defaultDuration: 750, 16855 calls: [ 16856 [{opacity: [0, 1], translateX: -75, translateZ: 0}] 16857 ], 16858 reset: {translateX: 0} 16859 }, 16860 "transition.slideRightBigIn": { 16861 defaultDuration: 800, 16862 calls: [ 16863 [{opacity: [1, 0], translateX: [0, 75], translateZ: 0}] 16864 ] 16865 }, 16866 "transition.slideRightBigOut": { 16867 defaultDuration: 750, 16868 calls: [ 16869 [{opacity: [0, 1], translateX: 75, translateZ: 0}] 16870 ], 16871 reset: {translateX: 0} 16872 }, 16873 /* Magic.css */ 16874 "transition.perspectiveUpIn": { 16875 defaultDuration: 800, 16876 calls: [ 16877 [{opacity: [1, 0], transformPerspective: [800, 800], transformOriginX: [0, 0], transformOriginY: ["100%", "100%"], rotateX: [0, -180]}] 16878 ], 16879 reset: {transformPerspective: 0, transformOriginX: "50%", transformOriginY: "50%"} 16880 }, 16881 /* Magic.css */ 16882 /* Support: Loses rotation in IE9/Android 2.3 (fades only). */ 16883 "transition.perspectiveUpOut": { 16884 defaultDuration: 850, 16885 calls: [ 16886 [{opacity: [0, 1], transformPerspective: [800, 800], transformOriginX: [0, 0], transformOriginY: ["100%", "100%"], rotateX: -180}] 16887 ], 16888 reset: {transformPerspective: 0, transformOriginX: "50%", transformOriginY: "50%", rotateX: 0} 16889 }, 16890 /* Magic.css */ 16891 /* Support: Loses rotation in IE9/Android 2.3 (fades only). */ 16892 "transition.perspectiveDownIn": { 16893 defaultDuration: 800, 16894 calls: [ 16895 [{opacity: [1, 0], transformPerspective: [800, 800], transformOriginX: [0, 0], transformOriginY: [0, 0], rotateX: [0, 180]}] 16896 ], 16897 reset: {transformPerspective: 0, transformOriginX: "50%", transformOriginY: "50%"} 16898 }, 16899 /* Magic.css */ 16900 /* Support: Loses rotation in IE9/Android 2.3 (fades only). */ 16901 "transition.perspectiveDownOut": { 16902 defaultDuration: 850, 16903 calls: [ 16904 [{opacity: [0, 1], transformPerspective: [800, 800], transformOriginX: [0, 0], transformOriginY: [0, 0], rotateX: 180}] 16905 ], 16906 reset: {transformPerspective: 0, transformOriginX: "50%", transformOriginY: "50%", rotateX: 0} 16907 }, 16908 /* Magic.css */ 16909 /* Support: Loses rotation in IE9/Android 2.3 (fades only). */ 16910 "transition.perspectiveLeftIn": { 16911 defaultDuration: 950, 16912 calls: [ 16913 [{opacity: [1, 0], transformPerspective: [2000, 2000], transformOriginX: [0, 0], transformOriginY: [0, 0], rotateY: [0, -180]}] 16914 ], 16915 reset: {transformPerspective: 0, transformOriginX: "50%", transformOriginY: "50%"} 16916 }, 16917 /* Magic.css */ 16918 /* Support: Loses rotation in IE9/Android 2.3 (fades only). */ 16919 "transition.perspectiveLeftOut": { 16920 defaultDuration: 950, 16921 calls: [ 16922 [{opacity: [0, 1], transformPerspective: [2000, 2000], transformOriginX: [0, 0], transformOriginY: [0, 0], rotateY: -180}] 16923 ], 16924 reset: {transformPerspective: 0, transformOriginX: "50%", transformOriginY: "50%", rotateY: 0} 16925 }, 16926 /* Magic.css */ 16927 /* Support: Loses rotation in IE9/Android 2.3 (fades only). */ 16928 "transition.perspectiveRightIn": { 16929 defaultDuration: 950, 16930 calls: [ 16931 [{opacity: [1, 0], transformPerspective: [2000, 2000], transformOriginX: ["100%", "100%"], transformOriginY: [0, 0], rotateY: [0, 180]}] 16932 ], 16933 reset: {transformPerspective: 0, transformOriginX: "50%", transformOriginY: "50%"} 16934 }, 16935 /* Magic.css */ 16936 /* Support: Loses rotation in IE9/Android 2.3 (fades only). */ 16937 "transition.perspectiveRightOut": { 16938 defaultDuration: 950, 16939 calls: [ 16940 [{opacity: [0, 1], transformPerspective: [2000, 2000], transformOriginX: ["100%", "100%"], transformOriginY: [0, 0], rotateY: 180}] 16941 ], 16942 reset: {transformPerspective: 0, transformOriginX: "50%", transformOriginY: "50%", rotateY: 0} 16943 } 16944 }; 16945 16946 /* Register the packaged effects. */ 16947 for (var effectName in Velocity.RegisterEffect.packagedEffects) { 16948 if (Velocity.RegisterEffect.packagedEffects.hasOwnProperty(effectName)) { 16949 Velocity.RegisterEffect(effectName, Velocity.RegisterEffect.packagedEffects[effectName]); 16950 } 16951 } 16952 16953 /********************* 16954 Sequence Running 16955 **********************/ 16956 16957 /* Note: Sequence calls must use Velocity's single-object arguments syntax. */ 16958 Velocity.RunSequence = function(originalSequence) { 16959 var sequence = $.extend(true, [], originalSequence); 16960 16961 if (sequence.length > 1) { 16962 $.each(sequence.reverse(), function(i, currentCall) { 16963 var nextCall = sequence[i + 1]; 16964 16965 if (nextCall) { 16966 /* Parallel sequence calls (indicated via sequenceQueue:false) are triggered 16967 in the previous call's begin callback. Otherwise, chained calls are normally triggered 16968 in the previous call's complete callback. */ 16969 var currentCallOptions = currentCall.o || currentCall.options, 16970 nextCallOptions = nextCall.o || nextCall.options; 16971 16972 var timing = (currentCallOptions && currentCallOptions.sequenceQueue === false) ? "begin" : "complete", 16973 callbackOriginal = nextCallOptions && nextCallOptions[timing], 16974 options = {}; 16975 16976 options[timing] = function() { 16977 var nextCallElements = nextCall.e || nextCall.elements; 16978 var elements = nextCallElements.nodeType ? [nextCallElements] : nextCallElements; 16979 16980 if (callbackOriginal) { 16981 callbackOriginal.call(elements, elements); 16982 } 16983 Velocity(currentCall); 16984 }; 16985 16986 if (nextCall.o) { 16987 nextCall.o = $.extend({}, nextCallOptions, options); 16988 } else { 16989 nextCall.options = $.extend({}, nextCallOptions, options); 16990 } 16991 } 16992 }); 16993 16994 sequence.reverse(); 16995 } 16996 16997 Velocity(sequence[0]); 16998 }; 16999 }((window.jQuery || window.Zepto || window), window, (window ? window.document : undefined)); 17000})); 17001 17002},{}]},{},[40]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.