Pastebin launched a little side project called VERYVIRAL.com, check it out ;-) Want more features on Pastebin? Sign Up, it's FREE!
Guest

pinmarklet-special.js

By: a guest on May 7th, 2012  |  syntax: JavaScript  |  size: 20.31 KB  |  views: 417  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. // pinmarketl-special.js
  2. //
  3. // Special handling for pinmarklet.
  4. //
  5. // The pinmarklet was
  6. //   (a) kludgy. It defined an anonymous script, and a page would need to
  7. //       re-request the JS every time it needed to popup the pinterest
  8. //       interaction form.
  9. //   (b) broken.  There were several bugs, including a race condition
  10. //       in the code that tries to determine the natural size of an image.
  11. //       Because of that bug, the pinmarklet form would not show, sometimes.
  12. //       Lame!
  13. //
  14. // To fix these things, I modified the code and use it instead.  This
  15. // modified code works for img tags.  It does not work with these tags:
  16. // video embed object.
  17. //
  18. // ========================================================
  19. // Usage:
  20. //
  21. // in the html, include the script just once:
  22. //    <script type="text/javascript" src="js/pinmarklet-special.js"></script>
  23. //
  24. // also in html, include a pin button:
  25. //   <div id='pagePin'>
  26. //     <img src='http://assets.pinterest.com/images/PinExt.png'/>
  27. //   </div>
  28. //
  29. // attach a click event handler to the button, and use this as the handler logic:
  30. //
  31. //     function pinClick(ev, ix) {
  32. //         PinterestSpecial.popupPinItForm();
  33. //         return false;
  34. //     }
  35. //
  36. // ========================================================
  37. //
  38. // Dino Chiesa
  39. //
  40. // This code is in the Public Domain.
  41. //
  42. // Thu, 22 Mar 2012  22:06
  43. //
  44.  
  45. (function(){
  46.   var pinmarkletConfig = {
  47.     idroot: "PIN_" + (new Date()).getTime(),
  48.     checkpoint: {
  49.       url: "//api.pinterest.com/v2/domains/info/"
  50.     },
  51.     pin: "//pinterest.com/pin/create/bookmarklet/",
  52.     minImgSize: 80,
  53.     thumbCellSize: 200,
  54.     check: ["meta", "img"],
  55.     //check: ["meta", "iframe", "embed", "object", "img", "video"],
  56.     urlRegexi: {
  57.       vimeo: /^https?:\/\/.*?\.?vimeo\.com\//,
  58.       facebook: /^https?:\/\/.*?\.?facebook\.com\//,
  59.       googleReader: /^https?:\/\/.*?\.?google\.com\/reader\//,
  60.       pinterest: /^https?:\/\/.*?\.?pinterest\.com\//,
  61.       stumbleUpon: /^https?:\/\/.*?\.?stumbleupon\.com\//
  62.     },
  63.     stumbleFrame: ["tb-stumble-frame", "stumbleFrame"],
  64.     tag: {
  65.       video: {
  66.         youtube: {
  67.           att: "src",
  68.           match: [/videoplayback/]
  69.         }
  70.       },
  71.       embed: {
  72.         youtube: {
  73.           att: "src",
  74.           match: [/^http:\/\/s\.ytimg\.com\/yt/, /^http:\/\/.*?\.?youtube-nocookie\.com\/v/]
  75.         }
  76.       },
  77.       iframe: {
  78.         youtube: {
  79.           att: "src",
  80.           match: [/^http:\/\/www\.youtube\.com\/embed\/([a-zA-Z0-9\-_]+)/]
  81.         },
  82.         vimeo: {
  83.           att: "src",
  84.           match: [/^http?s:\/\/vimeo.com\/(\d+)/, /^http:\/\/player\.vimeo\.com\/video\/(\d+)/]
  85.         }
  86.       },
  87.       object: {
  88.         youtube: {
  89.           att: "data",
  90.           match: [/^http:\/\/.*?\.?youtube-nocookie\.com\/v/]
  91.         }
  92.       }
  93.     },
  94.     msg: {
  95.       check: "",
  96.       cancelTitle: "Cancel Pin",
  97.       bustFrame: "We need to remove the StumbleUpon toolbar before you can pin anything. Click OK to do this or Cancel to stay here.",
  98.       noPin: "This site doesn't allow pinning to Pinterest. Please contact the owner with any questions. Thanks for visiting!",
  99.       privateDomain: "Sorry, can't pin directly from %privateDomain%.",
  100.       notFound: "Sorry, couldn't find any large images or video on this page.",
  101.       installed: "The bookmarklet is installed! Now you can click your Pin It button to pin images as you browse sites around the web."
  102.     },
  103.     pop: "status=no,resizable=no,scrollbars=yes,personalbar=no,directories=no,location=no,toolbar=no,menubar=no,width=632,height=270,left=0,top=0",
  104.     rules: ["#_bg {position:fixed;z-index:8675309; top:0; right:0; bottom:0; left:0; background-color:#f2f2f2; opacity:.95; }", "#_shim {position:fixed; background: transparent; z-index:8675308; top:0; right:0; bottom:0; left:0; }", "#_bd {position: absolute; text-align: left; padding-top: 36px; top: 0; left: 0; right: 0; z-index:8675320; font:16px hevetica neue,arial,san-serif; }", "#_bd span { zoom:1; display: inline-block; background: #fff; height:200px; width:200px; border: 1px solid #ddd; border-top: none; border-left:none; text-decoration: none;  text-shadow: 0 1px #fff; position: relative; cursor: pointer; vertical-align:middle;  }", "#_bd span#_logo {background: #FCF9F9 url(http://d3io1k5o0zdpqr.cloudfront.net/images/about/LogoAbout.png) 50% 50% no-repeat; box-shadow: none; }", '#_bd a#_x {height: 36px; line-height: 36px; position: fixed; font-size: 14px; font-weight: bold; display: block; width:auto; top: 0; left: 0; right: 0; margin: 0; background: url("http://d3io1k5o0zdpqr.cloudfront.net/images/fullGradient07Normal.png") repeat-x scroll 0 0 #FFFFFF; border-bottom: 1px solid #CCCCCC; color: #211922; text-align: center; z-index:8675321; }', '#_bd a#_x:active {background-color: #211922; background-image: url("http://d3io1k5o0zdpqr.cloudfront.net/images/fullGradient07Inverted.png"); border-color: #211922; text-shadow: 0 -1px #211922; }', "#_bd a#_x:hover {color: #fff; text-decoration: none; background-color: #1389e5; border-color: #1389e5; text-shadow: 0 -1px #46A0E6;}", "#_bd a img {max-height:200px; max-width:200px; top: 50%; left: 50%; position: absolute; z-index:8675312; }", "#_bd a b { z-index: 8675315; position: absolute; top: 50%; left: 50%; height: 50px; width: 50px; background: transparent url(http://d3io1k5o0zdpqr.cloudfront.net/images/VideoIndicator.png) 0 0 no-repeat; margin-top: -25px; margin-left: -25px; }", "#_bd a cite {z-index: 8675316; position: absolute; font-size: 10px; font-style: normal; bottom: 5px; width: 100px; left: 50%; margin-left: -50px; text-align: center; color: #000; background: #fff; padding: 3px;}", "#_bd span._pinContainer {z-index: 8675320; height: 200px; width: 200px; background: #fff; }", "#_bd span._pinButton {z-index: 8675320; height: 200px; width: 200px; background: transparent; }", "#_bd span._pinButton:hover {height: 200px; width: 200px; background: transparent url(http://d3io1k5o0zdpqr.cloudfront.net/images/PinThis.png) 50% 50% no-repeat; }"]
  105.   };
  106.  
  107.  
  108.   function pinmarkletPrep(win, doc, nav, config) {
  109.     var scriptTagIndex = 0,
  110.       a = win[config.idroot] = {
  111.         win: win,
  112.         doc: doc,
  113.         nav: nav,
  114.         config: config,
  115.         structure: {},
  116.         fns: {
  117.           callback: [],
  118.           removeNode: function(nodeId) {
  119.             var node = a.doc.getElementById(nodeId);
  120.             node && node.parentNode && node.parentNode.removeChild(node);
  121.           },
  122.           get: function(node, attrName) {
  123.             var a = node[attrName];
  124.             a = a || node.getAttribute(attrName);
  125.             return a;
  126.           },
  127.           make: function(b) {
  128.             var c = false, e, d;
  129.             for (e in b) {
  130.               if (b[e].hasOwnProperty) {
  131.                 c = a.doc.createElement(e);
  132.                 for (d in b[e]) {
  133.                   if (b[e][d].hasOwnProperty)
  134.                     if (typeof b[e][d] === "string")
  135.                       c[d] = b[e][d];
  136.                 }
  137.                 break;
  138.               }
  139.             }
  140.             return c;
  141.           },
  142.           listen: function(b, c, e) {
  143.             if (typeof a.win.addEventListener !== "undefined") b.addEventListener(c, e, false);
  144.             else typeof a.win.attachEvent !== "undefined" && b.attachEvent("on" + c, e)
  145.           },
  146.           getSelection: function() {
  147.             return ("" + (a.win.getSelection ? a.win.getSelection() : a.doc.getSelection ? a.doc.getSelection() : a.doc.selection.createRange().text)).replace(/(^\s+|\s+$)/g, "")
  148.           },
  149.           pin: function(b) {
  150.             var c = b.getElementsByTagName("IMG")[0],
  151.               e = "false",
  152.               d = a.config.pin + "?",
  153.               f = (new Date).getTime();
  154.             if (b.rel === "video") e = "true";
  155.             d = d + "media=" + encodeURIComponent(c.src);
  156.             d = d + "&url=" + encodeURIComponent(c.getAttribute("url") || a.doc.URL);
  157.             d = d + "&title=" + encodeURIComponent(a.doc.title);
  158.             d = d + "&is_video=" + e;
  159.             d = d + "&description=" + encodeURIComponent(a.values.selectedText || c.title || c.alt);
  160.             a.values.hazIOS && a.win.setTimeout(function() {
  161.               a.win.location = "pinit12:" + d
  162.             }, 25);
  163.             a.win.open(d, "pin" + f, a.config.pop)
  164.           },
  165.           close: function(b) {
  166.             if (a.structure.bg) {
  167.               a.doc.body.removeChild(a.structure.shim);
  168.               a.doc.body.removeChild(a.structure.bg);
  169.               a.doc.body.removeChild(a.structure.bd)
  170.             }
  171.             win.hazPinningNow = false;
  172.             b && a.win.alert(b);
  173.             a.values.hazGoodUrl = false;
  174.             a.win.scroll(0, a.values.saveScrollTop)
  175.           },
  176.           click: function(b) {
  177.             b = b || a.win.event;
  178.             var c = null;
  179.             if (c = b.target ? b.target.nodeType === 3 ? b.target.parentNode : b.target : b.srcElement) if (c === a.structure.x) a.fns.close();
  180.             else if (c.parentNode.className === a.config.idroot + "_pinContainer" || c.className === a.config.idroot + "_pinButton") {
  181.               a.fns.pin(c.parentNode.getElementsByTagName("A")[0]);
  182.               a.win.setTimeout(function() {
  183.                 a.fns.close()
  184.               }, 10)
  185.             }
  186.           },
  187.           behavior: function() {
  188.             a.fns.listen(a.structure.bd, "click", a.fns.click)
  189.           },
  190.           presentation: function() {
  191.             var b = a.fns.make({
  192.               STYLE: {
  193.                 type: "text/css"
  194.               }
  195.             }),
  196.               c = a.config.rules.join("\n").replace(/#_/g, "#" + config.idroot + "_").replace(/\._/g, "." + config.idroot + "_");
  197.             if (b.styleSheet) b.styleSheet.cssText = c;
  198.             else b.appendChild(a.doc.createTextNode(c));
  199.             a.doc.head.appendChild(b)
  200.           },
  201.           thumb: function(b, c, e, d, f, g) {
  202.             if (a.values.hazSrc[b] !== true) a.values.hazSrc[b] = true;
  203.             else if (!a.values.hazIE) return;
  204.             a.values.hazAtLeastOneGoodThumb = true;
  205.             d || (d = "image");
  206.             var h = a.fns.make({
  207.               SPAN: {
  208.                 className: a.config.idroot + "_pinContainer"
  209.               }
  210.             }),
  211.               j = a.fns.make({
  212.                 A: {
  213.                   rel: d
  214.                 }
  215.               }),
  216.               i = new Image,
  217.               m, n;
  218.             i.setAttribute("nopin", "nopin");
  219.             i.style.visibility = "hidden";
  220.             if (f) i.title = f;
  221.             g && i.setAttribute("url", g);
  222.             i.onload = function() {
  223.               m = this.width;
  224.               n = this.height;
  225.               this.style.marginTop = n < a.config.thumbCellSize ? -n / 2 + "px" : "-" + a.config.thumbCellSize / 2 + "px";
  226.               this.style.marginLeft = m < a.config.thumbCellSize ? -m / 2 + "px" : "-" + a.config.thumbCellSize / 2 + "px";
  227.               this.style.visibility = ""
  228.             };
  229.             i.src = b;
  230.             j.appendChild(i);
  231.             if (d !== "image") {
  232.               b = a.fns.make({
  233.                 B: {}
  234.               });
  235.               j.appendChild(b);
  236.             }
  237.             c = a.fns.make({
  238.               CITE: {
  239.                 innerHTML: c + " x " + e
  240.               }
  241.             });
  242.             j.appendChild(c);
  243.             h.appendChild(j);
  244.             h.appendChild(a.fns.make({
  245.               SPAN: {
  246.                 className: a.config.idroot + "_pinButton"
  247.               }
  248.             }));
  249.             if (d !== "image")(d = a.structure.bd.getElementsByTagName("SPAN")[1]) ? d.parentNode.insertBefore(h, d) : a.structure.bd.appendChild(h);
  250.             else a.structure.bd.appendChild(h)
  251.           },
  252.           invokeJsonp: function(urlStub, callback) {
  253.             var scriptId = 'pint-jsonp-script-' + (new Date()).valueOf() + '-' + scriptTagIndex++,
  254.               cbName = "window['" + a.config.idroot + "'].fns.callback[" + a.fns.callback.length + "]",
  255.               scriptElt = a.doc.createElement("SCRIPT");
  256.             a.fns.callback.push(function(f) {
  257.               callback(f);
  258.               a.fns.removeNode(id);
  259.             });
  260.             scriptElt.id = scriptId;
  261.             scriptElt.src = urlStub + cbName;
  262.             scriptElt.type = "text/javascript";
  263.             scriptElt.charset = "utf-8";
  264.             a.values.firstScript.parentNode.insertBefore(scriptElt, a.values.firstScript);
  265.           },
  266.           ping: {
  267.             vimeo: function(b) {
  268.               var c;
  269.               if (b[0] && b[0].thumbnail_large && b[0].embed_privacy === "anywhere") {
  270.                 c = "";
  271.                 if (b[0].title) c += b[0].title;
  272.                 if (b[0].user_name) c = c + ". Video by " + b[0].user_name;
  273.                 if (b[0].user_description) c = c + ". " + b[0].user_description;
  274.                 c += ".";
  275.                 a.fns.thumb(b[0].thumbnail_large, 150, 200, "video", c, b[0].url)
  276.               }
  277.             }
  278.           },
  279.           hazSite: {
  280.             youtube: {
  281.               iframe: function(b) {
  282.                 b = b.src.split("?")[0].split("&")[0].split("/");
  283.                 a.fns.thumb("http://img.youtube.com/vi/" + b.pop() + "/0.jpg", 360, 480, "video")
  284.               },
  285.               video: function(b) {
  286.                 b.getAttribute("data-youtube-id") && a.fns.thumb("http://img.youtube.com/vi/" + b.getAttribute("data-youtube-id") + "/0.jpg", 360, 480, "video")
  287.               },
  288.               embed: function(b) {
  289.                 var c = b.getAttribute("flashvars"),
  290.                   e = "";
  291.                 (e = c ? c.split("video_id=")[1].split("&")[0] : b.src.split("?")[0].split("&")[0].split("/").pop()) && a.fns.thumb("http://img.youtube.com/vi/" + e + "/0.jpg", 360, 480, "video")
  292.               },
  293.               object: function(b) {
  294.                 b = b.getAttribute("data");
  295.                 var c = "";
  296.                 if (b) c = b.split("?")[0].split("&")[0].split("/").pop();
  297.                 c && a.fns.thumb("http://img.youtube.com/vi/" + c + "/0.jpg", 360, 480, "video")
  298.               }
  299.             },
  300.             vimeo: {
  301.               iframe: function(b) {
  302.                 a.fns.invokeJsonp("http://vimeo.com/api/v2/video/" + b.src.split("/").pop() + ".json?callback=", a.fns.ping.vimeo)
  303.               }
  304.             }
  305.           },
  306.           insureNoPinterestBlock:function(b) {
  307.             if (b.name && b.name.toUpperCase() === "PINTEREST") {
  308.               if (b.content && b.content.toUpperCase() === "NOPIN") {
  309.                 //a.fns.close(a.config.msg.noPin);
  310.                 a.values.noPin = true;
  311.               }
  312.             }
  313.           },
  314.           validateNaturalImgSize: function(b, callback) {
  315.             var c;
  316.             if (!b.src.match(/^data/)) {
  317.               // get the natural dimensions of the image
  318.               c = new Image();
  319.               c.onload = function() {
  320.                 if (c.height > a.config.minImgSize && c.width > a.config.minImgSize) {
  321.                   a.fns.thumb(c.src, c.height, c.width);
  322.                 }
  323.                 callback();
  324.               };
  325.               c.src = b.src;
  326.             }
  327.             else {
  328.               callback(); // done
  329.             }
  330.           },
  331.  
  332.           checkTags: function(callback) {
  333.             var b, c, e, d, f, g, h, j, i,
  334.               imgChecksComplete = 0,
  335.               imgChecksRequested = 0,
  336.               oneImageCheckComplete = function() {
  337.                 imgChecksComplete++;
  338.                 if (imgChecksComplete == imgChecksRequested) {
  339.                   callback();
  340.                 }
  341.               };
  342.  
  343.             a.values.tag = [];
  344.             b = 0;
  345.             for (c = a.config.check.length; b < c; b += 1) {
  346.               f = a.doc.getElementsByTagName(a.config.check[b]);
  347.               e = 0;
  348.               for (d = f.length; e < d; e += 1) {
  349.                 g = f[e];
  350.                 if (!g.getAttribute("nopin") &&
  351.                     g.style.display !== "none" &&
  352.                     g.style.visibility !== "hidden") {
  353.                       a.values.tag.push(g);
  354.                 }
  355.               }
  356.             }
  357.  
  358.             // pass 1: count the img checks, and do the meta checks
  359.             b = 0;
  360.             for (c = a.values.tag.length; b < c; b += 1) {
  361.               f = a.values.tag[b]; // an element
  362.               g = f.tagName.toLowerCase();
  363.               if (g == 'img') {
  364.                 imgChecksRequested++;
  365.               }
  366.               else if (g ==  "meta") {
  367.                 a.fns.insureNoPinterestBlock(f);
  368.               }
  369.             }
  370.  
  371.             // pass 2: do the img checks
  372.             for (b = 0; b < c; b += 1) {
  373.               f = a.values.tag[b]; // an element
  374.               g = f.tagName.toLowerCase();
  375.               if (g == 'img') {
  376.                 a.fns.validateNaturalImgSize(f, oneImageCheckComplete);
  377.               }
  378.             }
  379.  
  380.             // edge case: nothing to check, so exhibit synchronous behavior
  381.             if (imgChecksRequested === 0) {
  382.               callback();
  383.             }
  384.           },
  385.  
  386.           structure: function() {
  387.             a.structure.shim = a.fns.make({
  388.               IFRAME: {
  389.                 height: "100%",
  390.                 width: "100%",
  391.                 allowTransparency: true,
  392.                 id: a.config.idroot + "_shim"
  393.               }
  394.             });
  395.             a.structure.shim.setAttribute("nopin", "nopin");
  396.             a.doc.body.appendChild(a.structure.shim);
  397.             a.structure.bg = a.fns.make({
  398.               DIV: {
  399.                 id: a.config.idroot + "_bg"
  400.               }
  401.             });
  402.             a.doc.body.appendChild(a.structure.bg);
  403.             a.structure.bd = a.fns.make({
  404.               DIV: {
  405.                 id: a.config.idroot + "_bd"
  406.               }
  407.             });
  408.             a.structure.x = a.fns.make({
  409.               A: {
  410.                 id: a.config.idroot + "_x",
  411.                 innerHTML: a.config.msg.cancelTitle
  412.               }
  413.             });
  414.             a.structure.bd.appendChild(a.structure.x);
  415.             a.structure.bd.appendChild(a.fns.make({
  416.               SPAN: {
  417.                 id: a.config.idroot + "_logo"
  418.               }
  419.             }));
  420.             a.doc.body.appendChild(a.structure.bd);
  421.             a.win.scroll(0, 0);
  422.           },
  423.  
  424.           checkPage: function(callback) {
  425.             a.fns.checkTags(callback);
  426.           },
  427.  
  428.           init: function() {
  429.             a.doc.body = a.doc.getElementsByTagName("BODY")[0];
  430.             a.doc.head = a.doc.getElementsByTagName("HEAD")[0];
  431.             if (!(!a.doc.body || !a.doc.head || win.hazPinningNow === true)) {
  432.               var b, c = a.nav.userAgent;
  433.               a.values = {
  434.                 saveScrollTop: a.win.pageYOffset,
  435.                 hazAtLeastOneGoodThumb: false,
  436.                 hazSrc: {},
  437.                 hazCalledForThumb: {},
  438.                 hazIE: function() {
  439.                   return /msie/i.test(c) && !/opera/i.test(c);
  440.                 }(),
  441.                 hazIOS: function() {
  442.                   return c.match(/iP/) !== null;
  443.                 }(),
  444.                 firstScript: a.doc.getElementsByTagName("SCRIPT")[0],
  445.                 selectedText: a.fns.getSelection()
  446.               };
  447.               b = a.config.checkpoint.url + "?url=" + encodeURIComponent(a.doc.URL) + "&callback=";
  448.               a.fns.invokeJsonp(b, function(b) {
  449.                 if (b && b.ok === false) {
  450.                   a.fns.close(a.config.msg.noPin);
  451.                   return;
  452.                 }
  453.  
  454.                 a.fns.structure();
  455.                 a.fns.presentation();
  456.  
  457.                 a.fns.checkPage(function() {
  458.                   if (a.values.noPin) {
  459.                     a.fns.close(a.config.msg.noPin);
  460.                     return;
  461.                   }
  462.                   if ( ! a.values.hazAtLeastOneGoodThumb || a.values.tag.length === 0) {
  463.                     a.fns.close(a.config.msg.notFound);
  464.                     return;
  465.                   }
  466.                   a.fns.behavior();
  467.                   win.hazPinningNow = true;
  468.                 });
  469.  
  470.               });
  471.             }
  472.           }
  473.         }
  474.       };
  475.  
  476.     // export one function. It pops up the pinterest form.
  477.       win.PinterestSpecial = {popupPinItForm: a.fns.init};
  478.   }
  479.  
  480.   // this is a one-time thing
  481.   pinmarkletPrep(window, document, navigator, pinmarkletConfig);
  482.  
  483. }());