/js/jquery.ceebox.js

http://github.com/catcubed/CeeBox · JavaScript · 724 lines · 529 code · 80 blank · 115 comment · 136 complexity · 13a3a3e87d370a45c5c5571493154882 MD5 · raw file

  1. //ceebox
  2. /*
  3. * CeeBox 2.1.5.1 jQuery Plugin
  4. * Requires jQuery 1.3.2 and swfobject.jquery.js plugin to work
  5. * Code hosted on GitHub (http://github.com/catcubed/ceebox) Please visit there for version history information
  6. * By Colin Fahrion (http://www.catcubed.com)
  7. * Inspiration for ceebox comes from Thickbox (http://jquery.com/demo/thickbox/) and Videobox (http://videobox-lb.sourceforge.net/)
  8. * However, along the upgrade path ceebox has morphed a long way from those roots.
  9. * Copyright (c) 2009 Colin Fahrion
  10. * Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php
  11. */
  12. // To make ceebox work add $(".ceebox").ceebox(); to your global js file or if you don't have one just uncomment the following...
  13. //$(document).ready(function(){ $(".ceebox").ceebox();});
  14. /* OPTIONAL DEFAULT opts
  15. * You can change many of the default options
  16. * $(".ceebox").ceebox({vidWidth:600,vidHeight:400,htmlWidth:600,htmlHeight:400,animSpeed:"fast",overlayColor:"#f00",overlayOpacity:0.8});
  17. */
  18. (function($) {
  19. $.ceebox = {version:"2.1.5.1"};
  20. //--------------------------- CEEBOX FUNCTION -------------------------------------
  21. $.fn.ceebox = function(opts){
  22. opts = $.extend({selector: $(this).selector},$.fn.ceebox.defaults, opts);
  23. //initilize some global private functions and variables
  24. var elem = this;
  25. var selector = $(this).selector;
  26. if (opts.videoJSON) {
  27. $.getJSON(opts.videoJSON, function(json){//loads optional JSON file
  28. $.extend($.fn.ceebox.videos,json);
  29. init(elem,opts,selector);
  30. });
  31. } else {init(elem,opts,selector);}
  32. return this;
  33. };
  34. //--------------------------- PUBLIC GLOBAL VARIABLES -------------------------------------------
  35. $.fn.ceebox.defaults = {
  36. // all types of links are activated by default. You can turn them off separately by setting to false
  37. html:true,
  38. image:true,
  39. video:true,
  40. modal:false, //if set to true all ceebox links are modal (unless you set modal:false in the rel);
  41. // Default size opts
  42. // false = autosize to browser window
  43. // Numerical sizes are uses for maximums; if the browser is smaller it will scale to match the browser. You can set any or all of the opts.
  44. // common ratios are included "4:3", "3:2", "16:9" (as set in $.fn.ceebox.ratios), or ratio can also be set to a decimal amount (i.e., "3:2" is the same as 1.5)
  45. titles: true, //set to false if you don't want titles/captions§
  46. htmlGallery:true,
  47. imageGallery:true,
  48. videoGallery:true,
  49. videoWidth: false, //set max size for all video links
  50. videoHeight: false,
  51. videoRatio: "16:9",
  52. htmlWidth: false, //set max size for all html links
  53. htmlHeight: false,
  54. htmlRatio: false,
  55. imageWidth: false, //set max size for all image links (image ratio is determined by the image itself)
  56. imageHeight: false,
  57. //ceebox display settings
  58. animSpeed: "normal", // animation resize transition speed (can be set to "slow","normal","fast", or in milliseconds like 1000)
  59. easing: "swing", // supports use of the easing plugin for resize anim (http://gsgd.co.uk/sandbox/jquery/easing/)
  60. fadeOut: 400, //speed that ceebox fades out when closed or advancing through galleries
  61. fadeIn: 400, //speed that ceebox fades in when opened or advancing through galleries
  62. overlayColor:"#000",
  63. overlayOpacity:0.8,
  64. // color settings for background, text, and border. If these are set to blank then it uses css colors. If set here it overrides css. This becomes useful with metadata and color animations which allows you to change colors from link to link.
  65. boxColor:"", //background color for ceebox.
  66. textColor:"", //color for text in ceebox.
  67. borderColor:"", //outside border color.
  68. borderWidth: "3px", //the border on ceebox. Can be used like css ie,"4px 2px 4px 2px"
  69. padding: 15, //ceebox padding
  70. margin: 150, //minimum margin between ceebox inside content and browser frame (this does not count the padding and border; I know it's odd. I'll likely change how it works at some point)
  71. //misc settings
  72. onload:null, //callback function once ceebox popup is loaded. MUST BE A FUNCTION!
  73. unload:null, //callback function once ceebox popup is unloaded. MUST BE A FUNCTION!
  74. videoJSON:null, //allows addition of seperate json file with more video support.
  75. iPhoneRedirect:true //set to automatically redirect iPhone users for video links (youtube will launch video player)
  76. };
  77. // ratio shortcuts
  78. $.fn.ceebox.ratios = {"4:3": 1.333, "3:2": 1.5, "16:9": 1.778,"1:1":1,"square":1};
  79. // set up modal regex expressions for testing rel attribute; publically accessable so that ceebox can adjust to suit your needs.
  80. // regex for width/height captures the last value if result of regex is an array
  81. // Can be set to Thickbox way {width: /[0-9]+/, height: /[0-9]+/g}; With this width only captures first value and height captures both but uses only the second
  82. $.fn.ceebox.relMatch = {
  83. width: /(?:width:)([0-9]+)/i, // force a max width
  84. height: /(?:height:)([0-9]+)/i, // force a max height
  85. ratio: /(?:ratio:)([0-9\.:]+)/i, // force a ratio
  86. modal: /modal:true/i, // set as modal
  87. nonmodal: /modal:false/i, // set as nonmodal (only useful if modal is the default)
  88. videoSrc:/(?:videoSrc:)(http:[\/\-\._0-9a-zA-Z:]+)/i, // add a different src url for a video this is for help supporting sites that use annoying src urls, which is any site that uses media.mtvnservices.com. Also as bonus, with a bit of ingenuity this can be used to RickRoll people.
  89. videoId:/(?:videoId:)([\-\._0-9a-zA-Z:]+)/i, //add an id which is useful for Daily Show and other sites like the above.
  90. start: /(?:start:)([0-9]+)/i // add a start time
  91. };
  92. // html for loader anim div
  93. $.fn.ceebox.loader = "<div id='cee_load' style='z-index:105;top:50%;left:50%;position:fixed'></div>";
  94. // video players public variables - *optional
  95. // siteRgx: Regular Expression used to test which site it is. Make sure that you include subfolders! ie, google.com/video so that it doesn't force a video player for the entire site.
  96. // idRgx: Regular Expression used to grab id. Note use of non-capturing variables
  97. // src: the src id style. Add [id] and ceebox will grab replace with the id from the link
  98. // *flashvars: additional flashvars if you add an id it will replace it
  99. // *param: additional parameters if you add an id it will replace it
  100. // *width: force a set width
  101. // *height: force a set height
  102. $.fn.ceebox.videos = {
  103. base : { //base variables that are added to every player
  104. param: {wmode: "transparent",allowFullScreen: "true",allowScriptAccess: "always"},
  105. flashvars: {autoplay: true}
  106. },
  107. facebook: {
  108. siteRgx: /facebook\.com\/video/i,
  109. idRgx: /(?:v=)([a-zA-Z0-9_]+)/i,
  110. src: "http://www.facebook.com/v/[id]"
  111. },
  112. youtube: {
  113. siteRgx : /youtube\.com\/watch/i,
  114. idRgx: /(?:v=)([a-zA-Z0-9_\-]+)/i,
  115. src : "http://www.youtube.com/v/[id]&hl=en&fs=1&autoplay=1"
  116. },
  117. metacafe: {
  118. siteRgx : /metacafe\.com\/watch/i,
  119. idRgx: /(?:watch\/)([a-zA-Z0-9_]+)/i,
  120. src: "http://www.metacafe.com/fplayer/[id]/.swf"
  121. },
  122. google: {
  123. siteRgx : /google\.com\/videoplay/i,
  124. idRgx: /(?:id=)([a-zA-Z0-9_\-]+)/i,
  125. src : "http://video.google.com/googleplayer.swf?docId=[id]&hl=en&fs=true",
  126. flashvars: {playerMode: "normal",fs: true}
  127. },
  128. spike: { //also detects ifilm which was spike's old name
  129. siteRgx : /spike\.com\/video|ifilm\.com\/video/i,
  130. idRgx: /(?:\/)([0-9]+)/i,
  131. src : "http://www.spike.com/efp",
  132. flashvars : {flvbaseclip:"[id]"}
  133. },
  134. vimeo: {
  135. siteRgx : /vimeo\.com\/[0-9]+/i,
  136. idRgx: /(?:\.com\/)([a-zA-Z0-9_]+)/i,
  137. src : "http://www.vimeo.com/moogaloop.swf?clip_id=[id]&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1"
  138. },
  139. dailymotion: {
  140. siteRgx : /dailymotion\.com\/video/i, //one issue is that some dailymotion vids are really atom films
  141. idRgx: /(?:video\/)([a-zA-Z0-9_]+)/i,
  142. src : "http://www.dailymotion.com/swf/[id]&related=0&autoplay=1"
  143. },
  144. cnn: {
  145. siteRgx : /cnn\.com\/video/i,
  146. idRgx: /(?:\?\/video\/)([a-zA-Z0-9_\/\.]+)/i,
  147. src : "http://i.cdn.turner.com/cnn/.element/apps/cvp/3.0/swf/cnn_416x234_embed.swf?context=embed&videoId=[id]",
  148. width:416,
  149. height:374
  150. }
  151. };
  152. //--------------------------- PUBLIC FUNCTIONS ---------------------------------------------------------------
  153. //--------------------------- Overlay function (makes the blank popup and loader) -------------------------------
  154. // this function is called ahead of time so the loader is there, but it does not have to be called as the ceebox.popup script also calls this
  155. $.fn.ceebox.overlay = function(opts) {
  156. opts = $.extend({//adds a few basic opts then merges in the defaults
  157. width: 60,
  158. height: 30,
  159. type: "html"
  160. }, $.fn.ceebox.defaults, opts);
  161. // 1. Creates overlay unless one already exists
  162. if ($("#cee_overlay").size() === 0){
  163. $("<div id='cee_overlay'></div>").css({
  164. opacity : opts.overlayOpacity,
  165. position: "absolute",
  166. top: 0,
  167. left: 0,
  168. backgroundColor: opts.overlayColor,
  169. width: "100%",
  170. height: $(document).height(),
  171. zIndex: 100
  172. }).appendTo($("body"));
  173. }
  174. // 2. Creates popup box unless one already exists
  175. if ($("#cee_box").size() === 0){
  176. var pos = boxPos(opts); //set up margin and position
  177. // 2a. set up css
  178. var boxCSS = {
  179. position: pos.position,
  180. zIndex: 102,
  181. top: "50%",
  182. left: "50%",
  183. height: opts.height + "px",
  184. width: opts.width + "px",
  185. marginLeft: pos.mleft + 'px',
  186. marginTop: pos.mtop + 'px',
  187. opacity:0,
  188. borderWidth:opts.borderWidth,
  189. borderColor:opts.borderColor,
  190. backgroundColor:opts.boxColor,
  191. color:opts.textColor
  192. };
  193. // 2b. add ceebox popup
  194. $("<div id='cee_box'></div>").css(boxCSS).appendTo("body").animate({opacity:1},opts.animSpeed,function(){
  195. $("#cee_overlay").addClass("cee_close");
  196. });
  197. }
  198. // 3. adds current type as class to ceebox
  199. $("#cee_box").removeClass().addClass("cee_" + opts.type);
  200. // 4. appends loading anim if not present
  201. if ($("#cee_load").size() === 0) {$($.fn.ceebox.loader).appendTo("body");}
  202. // 5. show loading animation
  203. $("#cee_load").show("fast").animate({opacity:1},"fast");
  204. };
  205. //------------------------Popup function (adds content to popup and animates) -------------------------------
  206. // if the content is a link it sets up as a ceebox content
  207. // otherwise it can be used to add any html content to a ceebox style popup
  208. $.fn.ceebox.popup = function(content,opts) {
  209. var page = pageSize(opts.margin);
  210. opts = $.extend({
  211. //used as base only if non-link html content is sent.
  212. //if a the content is a link than the ceebox build function sets these
  213. width: page.width,
  214. height: page.height,
  215. modal:false,
  216. type: "html",
  217. onload:null
  218. }, $.fn.ceebox.defaults, opts);
  219. // private variables and functions
  220. var gallery,family;
  221. // 1. if content is link, set up ceebox content based on link info
  222. if ($(content).is("a,area,input") && (opts.type == "html" || opts.type == "image" || opts.type == "video")) { //
  223. // 1a. grab gallery data, if it's there
  224. if (opts.gallery) {family = $(opts.selector).eq(opts.gallery.parentId).find("a[href],area[href],input[href]");}
  225. // 1b. build ceebox content using constructors (this is where the heavy lifting happens)
  226. Build[opts.type].prototype = new BoxAttr(content,opts);
  227. var cb = new Build[opts.type]();
  228. content = cb.content;
  229. // 1c. modify options based on properties of constructed ceebox content
  230. opts.action = cb.action;
  231. opts.modal = cb.modal;
  232. // 1d. get computed height of title text area
  233. if (opts.titles) {
  234. opts.titleHeight = $(cb.titlebox).contents().contents().wrap("<div></div>").parent().attr("id","ceetitletest").css({position:"absolute",top:"-300px",width:cb.width + "px"}).appendTo("body").height();
  235. $("#ceetitletest").remove();
  236. opts.titleHeight = (opts.titleHeight >= 10) ? opts.titleHeight + 20 : 30;
  237. } else {opts.titleHeight = 0;}
  238. // 1e. sets final width and height of ceebox popup
  239. opts.width = cb.width + 2*opts.padding;
  240. opts.height = cb.height + opts.titleHeight + 2*opts.padding;
  241. }
  242. // 2. Creates overlay and empty ceebox to page if one does not already exist; also adds loader
  243. $.fn.ceebox.overlay(opts);
  244. // attach action,onload, and unload functions to global variable to be called by $.fn.ceebox.onload() and $.fn.ceebox.closebox()
  245. base.action = opts.action;
  246. base.onload = opts.onload;
  247. base.unload = opts.unload;
  248. // 3. setup animation based on opts
  249. var pos = boxPos(opts);//grab margins
  250. var animOpts = {
  251. marginLeft: pos.mleft,
  252. marginTop: pos.mtop,
  253. width: opts.width + "px",
  254. height: opts.height + "px",
  255. borderWidth:opts.borderWidth
  256. };
  257. if (opts.borderColor) {
  258. var reg = /#[1-90a-f]+/gi;
  259. var borderColor = cssParse(opts.borderColor,reg);
  260. animOpts = $.extend(animOpts,{
  261. borderTopColor:borderColor[0],
  262. borderRightColor:borderColor[1],
  263. borderBottomColor:borderColor[2],
  264. borderLeftColor:borderColor[3]
  265. });
  266. }
  267. animOpts = (opts.textColor) ? $.extend(animOpts,{color:opts.textColor}): animOpts;
  268. animOpts = (opts.boxColor) ? $.extend(animOpts,{backgroundColor:opts.boxColor}): animOpts;
  269. // 4. animate ceebox
  270. $("#cee_box").animate(animOpts,opts.animSpeed,opts.easing,function(){
  271. // 5. append content once animation finishes
  272. var children = $(this).append(content).children().hide();
  273. var len = children.length;
  274. var onloadcall = true;
  275. // 6. fade content in
  276. children.fadeIn(opts.fadeIn,function(){
  277. if ($(this).is("#cee_iframeContent")) {onloadcall = false;} //cancel onload function call if cee_iframe is loaded as it has on onload attached to it.
  278. // Call onload on last item loaded.
  279. if (onloadcall && this == children[len-1]) {$.fn.ceebox.onload();}
  280. });
  281. // 7. check to see if it's modal
  282. if (opts.modal===true) {
  283. $("#cee_overlay").removeClass("cee_close"); //remove close function on overlay
  284. } else {
  285. // 7a. add closebtn
  286. $("<a href='#' id='cee_closeBtn' class='cee_close' title='Close'>close</a>").prependTo("#cee_box");
  287. // 7b. add gallery next/prev nav if there is a gallery group
  288. if (opts.gallery) {addGallery(opts.gallery,family,opts);}
  289. // 7c. add key events
  290. keyEvents(gallery,family,opts.fadeOut);
  291. }
  292. });
  293. };
  294. //--------------------------- ceebox close function ----------------------------------
  295. $.fn.ceebox.closebox = function(fade,unload) { //removes ceebox popup
  296. fade = fade || 400;
  297. $("#cee_box").fadeOut(fade);
  298. $("#cee_overlay").fadeOut((typeof fade == 'number') ? fade*2 : "slow",function(){
  299. $('#cee_box,#cee_overlay,#cee_HideSelect,#cee_load').unbind().trigger("unload").remove();
  300. if (isFunction(unload)) { unload(); } else if (isFunction(base.unload)) {base.unload();}
  301. base.unload = null; //call optional unload callback, then empty function
  302. });
  303. document.onkeydown = null;
  304. };
  305. //--------------------------- ceebox onload function ----------------------------------
  306. // made a public function mainly for cee_iframe to call. $.fn.ceebox.popup calls this automatically once all children objects of the popup are loaded
  307. $.fn.ceebox.onload = function(opts){
  308. $("#cee_load").hide(300).fadeOut(600,function(){$(this).remove();}); // remove loading anim
  309. if (isFunction(base.action)) {base.action(); base.action = null;} // call ceebox specific functions (ie, add flash player or ajax), then empty function
  310. if (isFunction(base.onload)) {base.onload(); base.onload = null;}// call optional onload callback, then empty function
  311. };
  312. //--------------------------- PRIVATE FUNCTIONS ---------------------------------------------------
  313. //--------------------------- Init function which sets up global variables ----------------------------------
  314. var base = {}; //global private variable holder
  315. function init(elem,opts,selector) {
  316. base.vidRegex = function(){ //builds single regex object from the every siteRgx in the ceebox.videos public variable
  317. var regStr = "";
  318. $.each($.fn.ceebox.videos,function(i,v){
  319. if (v.siteRgx !== null && typeof v.siteRgx !== 'string') {
  320. var tmp = String(v.siteRgx);
  321. regStr = regStr + tmp.slice(1,tmp.length-2) + "|";
  322. }
  323. });
  324. return new RegExp(regStr + "\\.swf$","i");
  325. }();
  326. base.userAgent = navigator.userAgent;
  327. $(".cee_close").die().live("click",function(){$.fn.ceebox.closebox();return false;}); //adds close button functionality
  328. if (selector != false) {$(elem).each(function(i){ceeboxLinkSort(this,i,opts,selector);});} //as long as a selector was passed, this sets up all the links
  329. //adds click functionality via jquery live event bubbling
  330. $(elem).live("click", function(e){
  331. var tgt = $(e.target).closest("[href]");
  332. var tgtData = tgt.data("ceebox");
  333. if (tgtData) {
  334. var linkOpts = (tgtData.opts) ? $.extend({}, opts, tgtData.opts) : opts; // metadata plugin support (applied on link element)
  335. $.fn.ceebox.overlay(linkOpts);
  336. if (tgtData.type == "image") {
  337. var imgPreload = new Image();
  338. imgPreload.onload = function(){
  339. var w = imgPreload.width,h=imgPreload.height;
  340. //set image max sizes to so that image doesn't scale larger
  341. linkOpts.imageWidth = getSmlr(w,$.fn.ceebox.defaults.imageWidth);
  342. linkOpts.imageHeight = getSmlr(h,$.fn.ceebox.defaults.imageHeight);
  343. linkOpts.imageRatio = w/h;
  344. $.fn.ceebox.popup(tgt,$.extend(linkOpts,{type:tgtData.type},{gallery:tgtData.gallery})); //build popup
  345. };
  346. imgPreload.src = $(tgt).attr("href");
  347. } else {$.fn.ceebox.popup(tgt,$.extend(linkOpts,{type:tgtData.type},{gallery:tgtData.gallery}));} //build popup
  348. return false;
  349. }
  350. });
  351. }
  352. //--------------------------- MAIN CEEBOX LINK SORTING AND EVENT ATTACHMENT FUNCTION ----------------------------------------------
  353. var ceeboxLinkSort = function(parent,parentId,opts,selector) {
  354. // private function variables
  355. var family,cbLinks = [],galleryLinks = [],gNum = 0;
  356. // 1. if dom element is a link use that otherwise find any and all links under selected dom element
  357. ($(parent).is("[href]")) ? family = $(parent) : family = $(parent).find("[href]");
  358. // 2. url match functions
  359. var urlMatch = {
  360. image: function(h,r) {if (r && r.match(/\bimage\b/i)) { return true; } else { return h.match(/\.jpg$|\.jpeg$|\.png$|\.gif$|\.bmp$/i) || false;}},
  361. video: function(h,r) {if (r && r.match(/\bvideo\b/i)) { return true; } else { return h.match(base.vidRegex) || false; }},
  362. html: function(h) {return true;}
  363. };
  364. var familyLen = family.length;
  365. // 3. sort links by type
  366. family.each(function(i){
  367. var alink = this;
  368. var metadata = $.metadata ? $(alink).metadata() : false;
  369. var linkOpts = metadata ? $.extend({}, opts, metadata) : opts; // metadata plugin support (applied on link element)
  370. $.each(urlMatch, function(type) {
  371. if (urlMatch[type]($(alink).attr("href"),$(alink).attr("rel")) && linkOpts[type]) {
  372. var gallery = false;
  373. // 2. set up array of gallery links
  374. if (linkOpts[type + "Gallery"] === true) {
  375. galleryLinks[galleryLinks.length] = i;
  376. gallery = true;
  377. }
  378. cbLinks[cbLinks.length] = {linkObj:alink,type:type,gallery:gallery,linkOpts:linkOpts};
  379. return false;
  380. }
  381. });
  382. });
  383. var gLen = galleryLinks.length;
  384. $.each(cbLinks,function(i){
  385. if (cbLinks[i].gallery) {
  386. var gallery = {parentId:parentId,gNum:gNum,gLen:gLen};
  387. if (gNum > 0) {gallery.prevId = galleryLinks[gNum-1];}
  388. if (gNum < gLen - 1) {gallery.nextId = galleryLinks[gNum+1];}
  389. gNum++;
  390. }
  391. if (!$.support.opacity && $(parent).is("map")) {$(cbLinks[i].linkObj).click(function(e){e.preventDefault();});} //IE falls to return false if using image map with ceebox gallery
  392. $.data(cbLinks[i].linkObj,"ceebox",{type:cbLinks[i].type,opts:cbLinks[i].linkOpts,gallery:gallery});
  393. });
  394. };
  395. //--------------------------- ceebox builder constructor objects ----------------------------------
  396. // 1. sets up base attr based on default options and link options
  397. var BoxAttr = function(cblink,o) {
  398. var w = o[o.type + "Width"]; //width
  399. var h = o[o.type + "Height"]; //height
  400. var r = o[o.type + "Ratio"] || w/h; //ratio
  401. //grab options form rel
  402. var rel = $(cblink).attr("rel");
  403. if (rel && rel!== "") {
  404. var m = {};
  405. //sort out relMatch regex expressions and exec them to the rel
  406. $.each($.fn.ceebox.relMatch,function(i,v){m[i] = v.exec(rel);});
  407. //check for modal option and overwrite if present
  408. if (m.modal) {o.modal = true;}
  409. if (m.nonmodal) {o.modal = false;}
  410. //check for size option (overwrites the base size)
  411. if (m.width) {w = Number(lastItem(m.width));}
  412. if (m.height) {h = Number(lastItem(m.height));}
  413. if (m.ratio) {r = lastItem(m.ratio); r = (Number(r)) ? Number(r) : String(r);}
  414. // grabs optional video src or id
  415. if (m.videoSrc) {this.videoSrc = String(lastItem(m.videoSrc));}
  416. if (m.videoId) {this.videoId = String(lastItem(m.videoId));}
  417. if (m.start) {this.startTime = Number(lastItem(m.start));}
  418. }
  419. // compare vs page size
  420. var p = pageSize(o.margin);
  421. w = getSmlr(w,p.width);
  422. h = getSmlr(h,p.height);
  423. if (r) { //if ratio value has been passed, adjust size to the ratio
  424. // test if it's a ratio name shortcut
  425. if (!Number(r)) {r = ($.fn.ceebox.ratios[r]) ? Number($.fn.ceebox.ratios[r]) : 1;}
  426. //makes sure that it's smaller than the max width and height
  427. if (w/h > r) {w = parseInt(h * r,10);}
  428. if (w/h < r) {h = parseInt(w / r,10);}
  429. }
  430. // set all important values to this
  431. this.modal = o.modal;
  432. this.href = $(cblink).attr("href");
  433. this.title = $(cblink).attr("title") || cblink.t || ""; //.t is used for ceetip
  434. this.titlebox = (o.titles) ? "<div id='cee_title'><h2>"+this.title+"</h2></div>" : "";
  435. this.width = w;
  436. this.height = h;
  437. this.rel = rel;
  438. this.iPhoneRedirect = o.iPhoneRedirect;
  439. };
  440. // 2. builds content based on type
  441. var Build = {
  442. image: function() {
  443. this.content = "<img id='cee_img' src='"+this.href+"' width='"+this.width+"' height='"+this.height+"' alt='"+this.title+"'/>" + this.titlebox;
  444. },
  445. video: function() {
  446. //sort through list of supported video players and get src,ids,params,etc.
  447. var content = "",cb = this;
  448. var vid = function(){
  449. var rtn = this,id = cb.videoId;
  450. rtn.flashvars = rtn.param = {};
  451. rtn.src = cb.videoSrc || cb.href;
  452. rtn.width = cb.width;
  453. rtn.height = cb.height;
  454. $.each($.fn.ceebox.videos,function(i,v){
  455. if (v.siteRgx && typeof v.siteRgx != 'string' && v.siteRgx.test(cb.href)) {
  456. if (v.idRgx) {
  457. v.idRgx = new RegExp(v.idRgx);
  458. id = String(lastItem(v.idRgx.exec(cb.href)));
  459. }
  460. rtn.src = (v.src) ? v.src.replace("[id]",id) : rtn.src;
  461. var startTimeMinReg = new RegExp(/(?:t=)*([0-9]+)m/i);
  462. var startTimeSecReg = new RegExp(/(?:t=)*([0-9]+)s/i);
  463. var startTimeMin = startTimeMinReg.exec(cb.href);
  464. var startTimeSec = startTimeSecReg.exec(cb.href);
  465. var startTime = 0;
  466. if (startTimeMin) { startTime = Number(startTimeMin[1]) * 60}
  467. if (startTimeSec) { startTime = startTime + Number(startTimeSec[1])}
  468. //check for [id] in flashvars
  469. if (v.flashvars) {$.each(v.flashvars, function(ii,vv){
  470. if (typeof vv =='string') {rtn.flashvars[ii] = vv.replace("[id]",id);}
  471. });}
  472. //check for [id] in params
  473. if (v.param) {$.each(v.param, function(ii,vv){
  474. if (typeof vv =='string') {rtn.param[ii] = vv.replace("[id]",id);}
  475. });}
  476. if (cb.startTime || startTime) {rtn.param["start"] = startTime || cb.startTime}
  477. rtn.width = v.width || rtn.width;
  478. rtn.height = v.height || rtn.height;
  479. rtn.site = i;
  480. return;
  481. }
  482. });
  483. return rtn;
  484. }();
  485. if ($.flash.hasVersion(8)) {
  486. //setup final attributes
  487. this.width = vid.width;
  488. this.height = vid.height;
  489. // add action to embed object once ceebox is loaded
  490. this.action = function() {
  491. $('#cee_vid').flash({
  492. swf: vid.src,
  493. params: $.extend($.fn.ceebox.videos.base.param,vid.param),
  494. flashvars: $.extend($.fn.ceebox.videos.base.flashvars,vid.flashvars),
  495. width: vid.width,
  496. height: vid.height
  497. });
  498. };
  499. } else {
  500. this.width = 400; this.height = 200;
  501. if( ((base.userAgent.match(/iPhone/i)) && this.iPhoneRedirect) || ((base.userAgent.match(/iPod/i)) && this.iPhoneRedirect)) {
  502. var redirect = this.href;
  503. this.action = function(){$.fn.ceebox.closebox(400,function(){window.location = redirect;});};
  504. } else {
  505. vid.site = vid.site || "SWF file";
  506. content = "<p style='margin:20px'>Adobe Flash 8 or higher is required to view this movie. You can either:</p><ul><li>Follow link to <a href='"+ this.href +"'>" + vid.site + " </a></li><li>or <a href='http://www.adobe.com/products/flashplayer/'>Install Flash</a></li><li> or <a href='#' class='cee_close'>Close This Popup</a></li></ul>";
  507. }
  508. }
  509. this.content = "<div id='cee_vid' style='width:"+this.width+"px;height:"+this.height+"px;'>" + content + "</div>" + this.titlebox;
  510. },
  511. html: function() {
  512. //test whether or not content is iframe or ajax
  513. var h = this.href,r = this.rel;
  514. var m = [h.match(/[a-zA-Z0-9_\.]+\.[a-zA-Z]{2,4}/i),h.match(/^http:+/),(r) ? r.match(/^iframe/) : false];
  515. if ((document.domain == m[0] && m[1] && !m[2]) || (!m[1] && !m[2])) { //if linked to same domain and not iframe than it's an ajax link
  516. var id, ajx = (id = h.match(/#[a-zA-Z0-9_\-]+/)) ? String(h.split("#")[0] + " " + id) : h;
  517. this.action = function(){ $("#cee_ajax").load(ajx);};
  518. this.content = this.titlebox + "<div id='cee_ajax' style='width:"+(this.width-30)+"px;height:"+(this.height-20)+"px'></div>";
  519. } else {
  520. $("#cee_iframe").remove();
  521. this.content = this.titlebox + "<iframe frameborder='0' hspace='0' src='"+h+"' id='cee_iframeContent' name='cee_iframeContent"+Math.round(Math.random()*1000)+"' onload='jQuery.fn.ceebox.onload()' style='width:"+(this.width)+"px;height:"+(this.height)+"px;' > </iframe>";
  522. }
  523. }
  524. };
  525. //--------------------------- specific single purpose private functions ----------------------------------
  526. // pageSize function used in box and overlay function (not a constructor)
  527. function pageSize(margin){
  528. var de = document.documentElement;
  529. margin = margin || 100;
  530. this.width = (window.innerWidth || self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth) - margin;
  531. this.height = (window.innerHeight || self.innerHeight || (de&&de.clientHeight) || document.body.clientHeight) - margin;
  532. return this;
  533. }
  534. function boxPos(opts){ //returns margin and positioning
  535. // 1. set up base sizes and positions
  536. var pos = "fixed",scroll = 0, reg = /[0-9]+/g, b = cssParse(opts.borderWidth,reg);
  537. // 2. IE 6 Browser fixes
  538. if (!window.XMLHttpRequest) {
  539. if ($("#cee_HideSelect") === null) {$("body").append("<iframe id='cee_HideSelect'></iframe>");} //fixes IE6's form select z-index issue
  540. pos = "absolute"; //IE 6 positioning is special... and I mean that in the most demeaning way possible
  541. scroll = parseInt((document.documentElement && document.documentElement.scrollTop || document.body.scrollTop),10);
  542. }
  543. this.mleft = parseInt(-1*((opts.width) / 2 + Number(b[3])),10);
  544. this.mtop = parseInt(-1*((opts.height) / 2 + Number(b[0])),10) + scroll;
  545. this.position = pos;
  546. return this;
  547. }
  548. function cssParse(css,reg){ //parses string into separate values for each side which is required for color anim and other uses
  549. var temp = css.match(reg),rtn = [],l = temp.length;
  550. if (l > 1) {
  551. rtn[0] = temp[0];
  552. rtn[1] = temp[1];
  553. rtn[2] = (l == 2) ? temp[0] : temp[2];
  554. rtn[3] = (l == 4) ? temp[3] : temp[1];
  555. } else {rtn = [temp,temp,temp,temp];}
  556. return rtn;
  557. }
  558. function keyEvents() { //adds key events for close/next/prev
  559. document.onkeydown = function(e){
  560. e = e || window.event;
  561. var kc = e.keyCode || e.which;
  562. switch (kc) {
  563. case 13:
  564. return false;
  565. case 27:
  566. $.fn.ceebox.closebox();
  567. document.onkeydown = null;
  568. break;
  569. case 188:
  570. case 37:
  571. $("#cee_prev").trigger("click");
  572. break;
  573. case 190:
  574. case 39:
  575. $("#cee_next").trigger("click");
  576. break;
  577. default:
  578. break;
  579. }
  580. return true;
  581. };
  582. }
  583. function addGallery(g,family,opts){ // adds gallery next/prev functionality
  584. //set up base sizing and positioning for image gallery
  585. var h = opts.height, w = opts.width, th = opts.titleHeight, p = opts.padding;
  586. var nav = {
  587. image : {
  588. w: parseInt(w / 2,10),
  589. h: h-th-2*p,
  590. top: p,
  591. bgtop: (h-th-2*p)/2
  592. },
  593. video : {
  594. w: 60,
  595. h: 80,
  596. top: parseInt(((h-th-10)-2*p) / 2,10),
  597. bgtop: 24
  598. }
  599. };
  600. nav.html = nav.video;
  601. // function for creating prev/next buttons
  602. function navLink(btn,id) {
  603. var s, on = nav[opts.type].bgtop, off = (on-2000), px = "px";
  604. (btn == "prev") ? s = [{left:0},"left"] : s = [{right:0}, x = "right"];
  605. var style = function(y) {return $.extend({zIndex:105,width:nav[opts.type].w + px, height:nav[opts.type].h + px,position:"absolute",top:nav[opts.type].top,backgroundPosition:s[1] + " " + y + px},s[0]);};
  606. $("<a href='#'></a>").text(btn).attr({id:"cee_" + btn}).css(style(off)).hover(
  607. function(){$(this).css(style(on));},
  608. function(){$(this).css(style(off));}
  609. ).one("click",function(e){
  610. e.preventDefault();
  611. (function(f,id,fade){ //click functionality for next/prev links
  612. $("#cee_prev,#cee_next").unbind().click(function(){return false;}); //removes any functionality from next/prev which stops this from being triggered twice
  613. document.onkeydown = null; //removes key events
  614. var content = $("#cee_box").children(), len = content.length;
  615. content.fadeOut(fade,function(){
  616. $(this).remove();
  617. if (this == content[len-1]) {f.eq(id).trigger("click");} //triggers next gallery item once all content is gone
  618. });
  619. })(family,id,opts.fadeOut);
  620. }).appendTo("#cee_box");
  621. }
  622. // add prev/next buttons
  623. if (g.prevId >= 0) {navLink("prev",g.prevId);}
  624. if (g.nextId) {navLink("next",g.nextId);}
  625. $("#cee_title").append("<div id='cee_count'>Item " + (g.gNum+1) +" of "+ g.gLen + "</div>");
  626. }
  627. //------------------------------ Generic helper functions ------------------------------------
  628. function getSmlr(a,b) {return ((a && a < b) || !b) ? a : b;}
  629. function isFunction(a) {return typeof a == 'function';}
  630. function lastItem(a) {var l = a.length;return (l > 1) ? a[l-1] : a;}
  631. //------------------------------ Debug function ----------------------------------------------
  632. function debug(a,tag,opts) {
  633. //must turn on by setting debugging to true as a global variable
  634. if (debugging === true) {var bugs="", header = "[ceebox](" + (tag||"") + ")";
  635. ($.isArray(a) || typeof a == 'object' || typeof a == 'function') ? $.each(a, function(i, val) { bugs = bugs +i + ":" + val + ", ";}) : bugs = a;
  636. if (window.console && window.console.log) {
  637. window.console.log(header + bugs);
  638. } else {
  639. if ($("#debug").size() === 0) {$("<ul id='debug'></ul>").appendTo("body").css({border:"1px solid #ccf",position:"fixed",top:"10px",right:"10px",width:"300px",padding:"10px",listStyle:"square"});
  640. $("<li>").css({margin:"0 0 5px"}).appendTo("#debug").append(header).wrapInner("<b></b>").append(" " + bugs);}
  641. }
  642. }
  643. }
  644. })(jQuery);