1/** 2 * @license 3 * jquery.socialshareprivacy.js | 2 Klicks fuer mehr Datenschutz 4 * 5 * http://www.heise.de/extras/socialshareprivacy/ 6 * http://www.heise.de/ct/artikel/2-Klicks-fuer-mehr-Datenschutz-1333879.html 7 * 8 * Copyright (c) 2011 Hilko Holweg, Sebastian Hilbig, Nicolas Heiringhoff, Juergen Schmidt, 9 * Heise Zeitschriften Verlag GmbH & Co. KG, http://www.heise.de 10 * 11 * Copyright (c) 2012-2013 Mathias Panzenböck 12 * 13 * is released under the MIT License http://www.opensource.org/licenses/mit-license.php 14 * 15 * Spread the word, link to us if you can. 16 */ 17(function ($, undefined) { 18 "use strict"; 19 20 /* 21 * helper functions 22 */ 23 24 /** 25 * Build an absolute url using a base url. 26 * The provided base url has to be a valid absolute url. It will not be validated! 27 * If no base url is given the document location is used. 28 * Schemes that behave other than http might not work. 29 * This function tries to support file:-urls, but might fail in some cases. 30 * email:-urls aren't supported at all (don't make sense anyway). 31 */ 32 function absurl (url, base) { 33 if (!base) base = document.baseURI || $("html > head > base").last().attr("href") || document.location.href; 34 if (!url) { 35 return base; 36 } 37 else if (/^[a-z][-+\.a-z0-9]*:/i.test(url)) { 38 // The scheme actually could contain any kind of alphanumerical unicode 39 // character, but JavaScript regular expressions don't support unicode 40 // character classes. Maybe /^[^:]+:/ or even /^.*:/ would be sufficient? 41 return url; 42 } 43 else if (url.slice(0,2) === '//') { 44 return /^[^:]+:/.exec(base)[0]+url; 45 } 46 47 var ch = url.charAt(0); 48 if (ch === '/') { 49 if (/^file:/i.test(base)) { 50 // file scheme has no hostname 51 return 'file://'+url; 52 } 53 else { 54 return /^[^:]+:\/*[^\/]+/i.exec(base)[0]+url; 55 } 56 } 57 else if (ch === '#') { 58 // assume "#" only occures at the end indicating the fragment 59 return base.replace(/#.*$/,'')+url; 60 } 61 else if (ch === '?') { 62 // assume "?" and "#" only occure at the end indicating the query 63 // and the fragment 64 return base.replace(/[\?#].*$/,'')+url; 65 } 66 else { 67 var path; 68 if (/^file:/i.test(base)) { 69 path = base.replace(/^file:\/{0,2}/i,''); 70 base = "file://"; 71 } 72 else { 73 var match = /^([^:]+:\/*[^\/]+)(\/.*?)?(\?.*?)?(#.*)?$/.exec(base); 74 base = match[1]; 75 path = match[2]||"/"; 76 } 77 78 path = path.split("/"); 79 path.pop(); 80 if (path.length === 0) { 81 // Ensure leading "/". Of course this is only valid on 82 // unix like filesystems. More magic would be needed to 83 // support other filesystems. 84 path.push(""); 85 } 86 path.push(url); 87 return base+path.join("/"); 88 } 89 } 90 91 function formatNumber (number) { 92 number = Number(number); 93 94 var prefix = ""; 95 var suffix = ""; 96 if (number < 0) { 97 prefix = "-"; 98 number = -number; 99 } 100 101 if (number === Infinity) { 102 return prefix + "Infinity"; 103 } 104 105 if (number > 9999) { 106 number = number / 1000; 107 suffix = "K"; 108 } 109 110 number = Math.round(number); 111 if (number === 0) { 112 return "0"; 113 } 114 115 var buf = []; 116 while (number > 0) { 117 var part = String(number % 1000); 118 119 number = Math.floor(number / 1000); 120 if (number) { 121 while (part.length < 3) { 122 part = "0"+part; 123 } 124 } 125 126 buf.unshift(part); 127 } 128 129 return prefix + buf.join(",") + suffix; 130 } 131 132 // helper function that gets the title of the current page 133 function getTitle (options, uri, settings) { 134 var title = settings && settings.title; 135 if (typeof title === "function") { 136 title = title.call(this, options, uri, settings); 137 } 138 139 if (title) { 140 return title; 141 } 142 143 var title = $('meta[name="DC.title"]').attr('content'); 144 var creator = $('meta[name="DC.creator"]').attr('content'); 145 146 if (title && creator) { 147 return title + ' - ' + creator; 148 } else { 149 return title || $('meta[property="og:title"]').attr('content') || $('title').text(); 150 } 151 } 152 153 function getDescription (options, uri, settings) { 154 var description = settings && settings.description; 155 if (typeof description === "function") { 156 description = description.call(this, options, uri, settings); 157 } 158 159 if (description) { 160 return description; 161 } 162 163 return abbreviateText( 164 $('meta[name="twitter:description"]').attr('content') || 165 $('meta[itemprop="description"]').attr('content') || 166 $('meta[name="description"]').attr('content') || 167 $.trim($('article, p').first().text()) || $.trim($('body').text()), 3500); 168 } 169 170 var IMAGE_ATTR_MAP = { 171 META : 'content', 172 IMG : 'src', 173 A : 'href', 174 IFRAME : 'src', 175 LINK : 'href' 176 }; 177 178 // find the largest image of the website 179 // if no image at all is found use googles favicon service, which 180 // defaults to a small globe (so there is always some image) 181 function getImage (options, uri, settings) { 182 var imgs, img = settings && settings.image; 183 if (typeof img === "function") { 184 img = img.call(this, options, uri, settings); 185 } 186 187 if (!img) { 188 imgs = $('meta[property="image"], meta[property="og:image"], meta[property="og:image:url"], meta[name="twitter:image"], link[rel="image_src"], itemscope *[itemprop="image"]').first(); 189 if (imgs.length > 0) { 190 img = imgs.attr(IMAGE_ATTR_MAP[imgs[0].nodeName]); 191 } 192 } 193 194 if (img) { 195 return absurl(img); 196 } 197 198 imgs = $('img').filter(':visible').filter(function () { 199 return $(this).parents('.social_share_privacy_area').length === 0; 200 }); 201 if (imgs.length === 0) { 202 img = $('link[rel~="shortcut"][rel~="icon"]').attr('href'); 203 if (img) return absurl(img); 204 return 'http://www.google.com/s2/favicons?'+$.param({domain:location.hostname}); 205 } 206 imgs.sort(function (lhs, rhs) { 207 return rhs.offsetWidth * rhs.offsetHeight - lhs.offsetWidth * lhs.offsetHeight; 208 }); 209 // browser makes src absolute: 210 return imgs[0].src; 211 } 212 213 // abbreviate at last blank before length and add "\u2026" (horizontal ellipsis) 214 function abbreviateText (text, length) { 215 // length of UTF-8 encoded string 216 if (unescape(encodeURIComponent(text)).length <= length) { 217 return text; 218 } 219 220 // "\u2026" is actually 3 bytes long in UTF-8 221 // TODO: if any of the last 3 characters is > 1 byte long this truncates too much 222 var abbrev = text.slice(0, length - 3); 223 224 if (!/\W/.test(text.charAt(length - 3))) { 225 var match = /^(.*)\s\S*$/.exec(abbrev); 226 if (match) { 227 abbrev = match[1]; 228 } 229 } 230 return abbrev + "\u2026"; 231 } 232 233 var HTML_CHAR_MAP = { 234 '<': '<', 235 '>': '>', 236 '&': '&', 237 '"': '"', 238 "'": ''' 239 }; 240 241 function escapeHtml (s) { 242 return s.replace(/[<>&"']/g, function (ch) { 243 return HTML_CHAR_MAP[ch]; 244 }); 245 } 246 247 function getEmbed (options, uri, settings) { 248 var embed = settings && settings.embed; 249 if (typeof embed === "function") { 250 embed = embed.call(this, options, uri, settings); 251 } 252 253 if (embed) { 254 return embed; 255 } 256 257 embed = ['<iframe scrolling="no" frameborder="0" style="border:none;" allowtransparency="true"']; 258 var embed_url = $('meta[name="twitter:player"]').attr('content'); 259 260 if (embed_url) { 261 var width = $('meta[name="twitter:player:width"]').attr('content'); 262 var height = $('meta[name="twitter:player:height"]').attr('content'); 263 264 if (width) embed.push(' width="',escapeHtml(width),'"'); 265 if (height) embed.push(' height="',escapeHtml(height),'"'); 266 } 267 else { 268 embed_url = uri + options.referrer_track; 269 } 270 271 embed.push(' src="',escapeHtml(embed_url),'"></iframe>'); 272 return embed.join(''); 273 } 274 275 // build URI from rel="canonical" or document.location 276 function getURI (options) { 277 var uri = document.location.href; 278 var canonical = $("link[rel=canonical]").attr("href") || $('head meta[property="og:url"]').attr("content"); 279 280 if (canonical) { 281 uri = absurl(canonical); 282 } 283 else if (options && options.ignore_fragment) { 284 uri = uri.replace(/#.*$/,''); 285 } 286 287 return uri; 288 } 289 290 function buttonClickHandler (service_name) { 291 function onclick (event) { 292 var $container = $(this).parents('li.help_info').first(); 293 var $share = $container.parents('.social_share_privacy_area').first().parent(); 294 var options = $share.data('social-share-privacy-options'); 295 var service = options.services[service_name]; 296 var button_class = service.button_class || service_name; 297 var uri = options.uri; 298 if (typeof uri === 'function') { 299 uri = uri.call($share[0], options); 300 } 301 var $switch = $container.find('span.switch'); 302 if ($switch.hasClass('off')) { 303 $container.addClass('info_off'); 304 $switch.addClass('on').removeClass('off').html(service.txt_on||'\u00a0'); 305 $container.find('img.privacy_dummy').replaceWith( 306 typeof(service.button) === "function" ? 307 service.button.call($container.parent().parent()[0],service,uri,options) : 308 service.button); 309 $share.trigger({type: 'socialshareprivacy:enable', serviceName: service_name, isClick: !event.isTrigger}); 310 } else { 311 $container.removeClass('info_off'); 312 $switch.addClass('off').removeClass('on').html(service.txt_off||'\u00a0'); 313 $container.find('.dummy_btn').empty(). 314 append($('<img/>').addClass(button_class+'_privacy_dummy privacy_dummy'). 315 attr({ 316 alt: service.dummy_alt, 317 src: service.path_prefix + (options.layout === 'line' ? 318 service.dummy_line_img : service.dummy_box_img) 319 }).click(onclick)); 320 $share.trigger({type: 'socialshareprivacy:disable', serviceName: service_name, isClick: !event.isTrigger}); 321 } 322 }; 323 return onclick; 324 } 325 326 // display info-overlays a tiny bit delayed 327 function enterHelpInfo () { 328 var $info_wrapper = $(this); 329 if ($info_wrapper.hasClass('info_off')) return; 330 var timeout_id = window.setTimeout(function () { 331 $info_wrapper.addClass('display'); 332 $info_wrapper.removeData('timeout_id'); 333 }, 500); 334 $info_wrapper.data('timeout_id', timeout_id); 335 } 336 337 function leaveHelpInfo () { 338 var $info_wrapper = $(this); 339 var timeout_id = $info_wrapper.data('timeout_id'); 340 if (timeout_id !== undefined) { 341 window.clearTimeout(timeout_id); 342 } 343 $info_wrapper.removeClass('display'); 344 } 345 346 function permCheckChangeHandler () { 347 var $input = $(this); 348 var $share = $input.parents('.social_share_privacy_area').first().parent(); 349 var options = $share.data('social-share-privacy-options'); 350 if ($input.is(':checked')) { 351 options.set_perma_option($input.attr('data-service'), options); 352 $input.parent().addClass('checked'); 353 } else { 354 options.del_perma_option($input.attr('data-service'), options); 355 $input.parent().removeClass('checked'); 356 } 357 } 358 359 function enterSettingsInfo () { 360 var $settings = $(this); 361 var timeout_id = window.setTimeout(function () { 362 $settings.find('.settings_info_menu').removeClass('off').addClass('on'); 363 $settings.removeData('timeout_id'); 364 }, 500); 365 $settings.data('timeout_id', timeout_id); 366 } 367 368 function leaveSettingsInfo () { 369 var $settings = $(this); 370 var timeout_id = $settings.data('timeout_id'); 371 if (timeout_id !== undefined) { 372 window.clearTimeout(timeout_id); 373 } 374 $settings.find('.settings_info_menu').removeClass('on').addClass('off'); 375 } 376 377 function setPermaOption (service_name, options) { 378 $.cookie('socialSharePrivacy_'+service_name, 'perma_on', options.cookie_expires, options.cookie_path, options.cookie_domain); 379 } 380 381 function delPermaOption (service_name, options) { 382 $.cookie('socialSharePrivacy_'+service_name, null, -1, options.cookie_path, options.cookie_domain); 383 } 384 385 function getPermaOption (service_name, options) { 386 return !!options.get_perma_options(options)[service_name]; 387 } 388 389 function getPermaOptions (options) { 390 var cookies = $.cookie(); 391 var permas = {}; 392 for (var name in cookies) { 393 var match = /^socialSharePrivacy_(.+)$/.exec(name); 394 if (match) { 395 permas[match[1]] = cookies[name] === 'perma_on'; 396 } 397 } 398 return permas; 399 } 400 401 402 // extend jquery with our plugin function 403 function socialSharePrivacy (options) { 404 405 if (typeof options === "string") { 406 var command = options; 407 if (arguments.length === 1) { 408 switch (command) { 409 case "enable": 410 this.find('.switch.off').click(); 411 break; 412 413 case "disable": 414 this.find('.switch.on').click(); 415 break; 416 417 case "toggle": 418 this.find('.switch').click(); 419 break; 420 421 case "options": 422 return this.data('social-share-privacy-options'); 423 424 case "destroy": 425 this.trigger({type: 'socialshareprivacy:destroy'}); 426 this.children('.social_share_privacy_area').remove(); 427 this.removeData('social-share-privacy-options'); 428 break; 429 430 default: 431 throw new Error("socialSharePrivacy: unknown command: "+command); 432 } 433 } 434 else { 435 var arg = arguments[1]; 436 switch (command) { 437 case "enable": 438 this.each(function () { 439 var $self = $(this); 440 var options = $self.data('social-share-privacy-options'); 441 $self.find('.'+(options.services[arg].class_name||arg)+' .switch.off').click(); 442 }); 443 break; 444 445 case "disable": 446 this.each(function () { 447 var $self = $(this); 448 var options = $self.data('social-share-privacy-options'); 449 $self.find('.'+(options.services[arg].class_name||arg)+' .switch.on').click(); 450 }); 451 break; 452 453 case "toggle": 454 this.each(function () { 455 var $self = $(this); 456 var options = $self.data('social-share-privacy-options'); 457 $self.find('.'+(options.services[arg].class_name||arg)+' .switch').click(); 458 }); 459 break; 460 461 case "option": 462 if (arguments.length > 2) { 463 var value = {}; 464 value[arg] = arguments[2]; 465 this.each(function () { 466 $.extend(true, $(this).data('social-share-privacy-options'), value); 467 }); 468 } 469 else { 470 return this.data('social-share-privacy-options')[arg]; 471 } 472 break; 473 474 case "options": 475 $.extend(true, options, arg); 476 break; 477 478 default: 479 throw new Error("socialSharePrivacy: unknown command: "+command); 480 } 481 } 482 return this; 483 } 484 485 return this.each(function () { 486 // parse options passed via data-* attributes: 487 var data = {}; 488 if (this.lang) data.language = this.lang; 489 for (var i = 0, attrs = this.attributes; i < attrs.length; ++ i) { 490 var attr = attrs[i]; 491 if (/^data-./.test(attr.name)) { 492 var path = attr.name.slice(5).replace(/-/g,"_").split("."); 493 var ctx = data, j = 0; 494 for (; j < path.length-1; ++ j) { 495 var name = path[j]; 496 if (name in ctx) { 497 ctx = ctx[name]; 498 if (typeof ctx === "string") { 499 ctx = (new Function("$", "return ("+ctx+");")).call(this, $); 500 } 501 } 502 else { 503 ctx = ctx[name] = {}; 504 } 505 } 506 var name = path[j]; 507 if (typeof ctx[name] === "object") { 508 ctx[name] = $.extend(true, (new Function("$", "return ("+attr.value+");")).call(this, $), ctx[name]); 509 } 510 else { 511 ctx[name] = attr.value; 512 } 513 } 514 } 515 // parse global option values: 516 if ('cookie_expires' in data) data.cookie_expires = Number(data.cookie_expires); 517 if ('perma_option' in data) data.perma_option = $.trim(data.perma_option).toLowerCase() === "true"; 518 if ('ignore_fragment' in data) data.ignore_fragment = $.trim(data.ignore_fragment).toLowerCase() === "true"; 519 if ('set_perma_option' in data) { 520 data.set_perma_option = new Function("service_name", "options", data.set_perma_option); 521 } 522 if ('del_perma_option' in data) { 523 data.del_perma_option = new Function("service_name", "options", data.del_perma_option); 524 } 525 if ('get_perma_option' in data) { 526 data.get_perma_option = new Function("service_name", "options", data.get_perma_option); 527 } 528 if ('get_perma_options' in data) { 529 data.get_perma_options = new Function("options", data.get_perma_options); 530 } 531 if ('order' in data) { 532 data.order = $.trim(data.order); 533 if (data.order) { 534 data.order = data.order.split(/\s+/g); 535 } 536 else { 537 delete data.order; 538 } 539 } 540 if (typeof data.services === "string") { 541 data.services = (new Function("$", "return ("+data.services+");")).call(this, $); 542 } 543 if ('options' in data) { 544 data = $.extend(data, (new Function("$", "return ("+data.options+");")).call(this, $)); 545 delete data.options; 546 } 547 if ('services' in data) { 548 for (var service_name in data.services) { 549 var service = data.services[service_name]; 550 if (typeof service === "string") { 551 data.services[service_name] = (new Function("$", "return ("+service+");")).call(this, $); 552 } 553 // only values of common options are parsed: 554 if (typeof service.status === "string") { 555 service.status = $.trim(service.status).toLowerCase() === "true"; 556 } 557 if (typeof service.perma_option === "string") { 558 service.perma_option = $.trim(service.perma_option).toLowerCase() === "true"; 559 } 560 } 561 } 562 // overwrite default values with user settings 563 var this_options = $.extend(true,{},socialSharePrivacy.settings,options,data); 564 var order = this_options.order || []; 565 566 var dummy_img = this_options.layout === 'line' ? 'dummy_line_img' : 'dummy_box_img'; 567 var any_on = false; 568 var any_perm = false; 569 var any_unsafe = false; 570 var unordered = []; 571 for (var service_name in this_options.services) { 572 var service = this_options.services[service_name]; 573 if (service.status) { 574 any_on = true; 575 if ($.inArray(service_name, order) === -1) { 576 unordered.push(service_name); 577 } 578 if (service.privacy !== 'safe') { 579 any_unsafe = true; 580 if (service.perma_option) { 581 any_perm = true; 582 } 583 } 584 } 585 if (!('language' in service)) { 586 service.language = this_options.language; 587 } 588 if (!('path_prefix' in service)) { 589 service.path_prefix = this_options.path_prefix; 590 } 591 if (!('referrer_track' in service)) { 592 service.referrer_track = ''; 593 } 594 } 595 unordered.sort(); 596 order = order.concat(unordered); 597 598 // check if at least one service is activated 599 if (!any_on) { 600 return; 601 } 602 603 // insert stylesheet into document and prepend target element 604 if (this_options.css_path) { 605 var css_path = (this_options.path_prefix||"") + this_options.css_path; 606 // IE fix (needed for IE < 9 - but done for all IE versions) 607 if (document.createStyleSheet) { 608 document.createStyleSheet(css_path); 609 } else if ($('link[href="'+css_path+'"]').length === 0) { 610 $('<link/>',{rel:'stylesheet',type:'text/css',href:css_path}).appendTo(document.head); 611 } 612 } 613 614 // get stored perma options 615 var permas; 616 if (this_options.perma_option && any_perm) { 617 if (this_options.get_perma_options) { 618 permas = this_options.get_perma_options(this_options); 619 } 620 else { 621 permas = {}; 622 for (var service_name in this_options.services) { 623 permas[service_name] = this_options.get_perma_option(service_name, this_options); 624 } 625 } 626 } 627 628 // canonical uri that will be shared 629 var uri = this_options.uri; 630 if (typeof uri === 'function') { 631 uri = uri.call(this, this_options); 632 } 633 634 var $context = $('<ul class="social_share_privacy_area"></ul>').addClass(this_options.layout); 635 var $share = $(this); 636 637 $share.prepend($context).data('social-share-privacy-options',this_options); 638 639 for (var i = 0; i < order.length; ++ i) { 640 var service_name = order[i]; 641 var service = this_options.services[service_name]; 642 643 if (service && service.status) { 644 var class_name = service.class_name || service_name; 645 var button_class = service.button_class || service_name; 646 var $help_info; 647 648 if (service.privacy === 'safe') { 649 $help_info = $('<li class="help_info"><div class="info">' + 650 service.txt_info + '</div><div class="dummy_btn"></div></li>').addClass(class_name); 651 $help_info.find('.dummy_btn'). 652 addClass(button_class). 653 append(service.button.call(this,service,uri,this_options)); 654 } 655 else { 656 $help_info = $('<li class="help_info"><div class="info">' + 657 service.txt_info + '</div><span class="switch off">' + (service.txt_off||'\u00a0') + 658 '</span><div class="dummy_btn"></div></li>').addClass(class_name); 659 $help_info.find('.dummy_btn'). 660 addClass(button_class). 661 append($('<img/>').addClass(button_class+'_privacy_dummy privacy_dummy'). 662 attr({ 663 alt: service.dummy_alt, 664 src: service.path_prefix + service[dummy_img] 665 })); 666 667 $help_info.find('.dummy_btn img.privacy_dummy, span.switch').click( 668 buttonClickHandler(service_name)); 669 } 670 $context.append($help_info); 671 } 672 } 673 674 // 675 // append Info/Settings-area 676 // 677 if (any_unsafe) { 678 var $settings_info = $('<li class="settings_info"><div class="settings_info_menu off perma_option_off"><a>' + 679 '<span class="help_info icon"><span class="info">' + this_options.txt_help + '</span></span></a></div></li>'); 680 var $info_link = $settings_info.find('> .settings_info_menu > a').attr('href', this_options.info_link); 681 if (this_options.info_link_target) { 682 $info_link.attr("target",this_options.info_link_target); 683 } 684 $context.append($settings_info); 685 686 $context.find('.help_info').on('mouseenter', enterHelpInfo).on('mouseleave', leaveHelpInfo); 687 688 // menu for permanently enabling of service buttons 689 if (this_options.perma_option && any_perm) { 690 691 // define container 692 var $container_settings_info = $context.find('li.settings_info'); 693 694 // remove class that fomrats the i-icon, because perma-options are shown 695 var $settings_info_menu = $container_settings_info.find('.settings_info_menu'); 696 $settings_info_menu.removeClass('perma_option_off'); 697 698 // append perma-options-icon (.settings) and form (hidden) 699 $settings_info_menu.append( 700 '<span class="settings">' + this_options.txt_settings + '</span><form><fieldset><legend>' + 701 this_options.settings_perma + '</legend></fieldset></form>'); 702 703 // write services with <input> and <label> and checked state from cookie 704 var $fieldset = $settings_info_menu.find('form fieldset'); 705 for (var i = 0; i < order.length; ++ i) { 706 var service_name = order[i]; 707 var service = this_options.services[service_name]; 708 709 if (service && service.status && service.perma_option && service.privacy !== 'safe') { 710 var class_name = service.class_name || service_name; 711 var perma = permas[service_name]; 712 var $field = $('<label><input type="checkbox"' + (perma ? ' checked="checked"/>' : '/>') + 713 service.display_name + '</label>'); 714 $field.find('input').attr('data-service', service_name); 715 $fieldset.append($field); 716 717 // enable services when cookie set and refresh cookie 718 if (perma) { 719 $context.find('li.'+class_name+' span.switch').click(); 720 this_options.set_perma_option(service_name, this_options); 721 } 722 } 723 } 724 725 // indicate clickable setings gear 726 $container_settings_info.find('span.settings').css('cursor', 'pointer'); 727 728 // show settings menu on hover 729 $container_settings_info.on('mouseenter', enterSettingsInfo).on('mouseleave', leaveSettingsInfo); 730 731 // interaction for <input> to enable services permanently 732 $container_settings_info.find('fieldset input').on('change', permCheckChangeHandler); 733 } 734 } 735 $share.trigger({type: 'socialshareprivacy:create', options: this_options}); 736 }); 737 }; 738 739 // expose helper functions: 740 socialSharePrivacy.absurl = absurl; 741 socialSharePrivacy.escapeHtml = escapeHtml; 742 socialSharePrivacy.getTitle = getTitle; 743 socialSharePrivacy.getImage = getImage; 744 socialSharePrivacy.getEmbed = getEmbed; 745 socialSharePrivacy.getDescription = getDescription; 746 socialSharePrivacy.abbreviateText = abbreviateText; 747 socialSharePrivacy.formatNumber = formatNumber; 748 749 socialSharePrivacy.settings = { 750 'services' : {}, 751 'info_link' : 'http://panzi.github.com/SocialSharePrivacy/', 752 'info_link_target' : '', 753 'txt_settings' : 'Settings', 754 'txt_help' : 'If you activate these fields via click, data will be sent to a third party (Facebook, Twitter, Google, ...) and stored there. For more details click <em>i</em>.', 755 'settings_perma' : 'Permanently enable share buttons:', 756 'layout' : 'line', // possible values: 'line' (~120x20) or 'box' (~58x62) 757 'set_perma_option' : setPermaOption, 758 'del_perma_option' : delPermaOption, 759 'get_perma_options' : getPermaOptions, 760 'get_perma_option' : getPermaOption, 761 'perma_option' : !!$.cookie, 762 'cookie_path' : '/', 763 'cookie_domain' : document.location.hostname, 764 'cookie_expires' : 365, 765 'path_prefix' : '', 766 'css_path' : "stylesheets/jquery.socialshareprivacy.css", 767 'uri' : getURI, 768 'language' : 'en', 769 'ignore_fragment' : true 770 }; 771 772 $.fn.socialSharePrivacy = socialSharePrivacy; 773}(jQuery)); 774