socialshareprivacy.js 25 KB

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