123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- (function ($) {
- /**
- * Terminology:
- *
- * "Link" means "Everything which is in flag.tpl.php" --and this may contain
- * much more than the <A> element. On the other hand, when we speak
- * specifically of the <A> element, we say "element" or "the <A> element".
- */
- /**
- * The main behavior to perform AJAX toggling of links.
- */
- Drupal.flagLink = function(context) {
- /**
- * Helper function. Updates a link's HTML with a new one.
- *
- * @param element
- * The <A> element.
- * @return
- * The new link.
- */
- function updateLink(element, newHtml) {
- var $newLink = $(newHtml);
- // Initially hide the message so we can fade it in.
- $('.flag-message', $newLink).css('display', 'none');
- // Reattach the behavior to the new <A> element. This element
- // is either whithin the wrapper or it is the outer element itself.
- var $nucleus = $newLink.is('a') ? $newLink : $('a.flag', $newLink);
- $nucleus.addClass('flag-processed').click(flagClick);
- // Find the wrapper of the old link.
- var $wrapper = $(element).parents('.flag-wrapper:first');
- // Replace the old link with the new one.
- $wrapper.after($newLink).remove();
- Drupal.attachBehaviors($newLink.get(0));
- $('.flag-message', $newLink).fadeIn();
- setTimeout(function(){ $('.flag-message.flag-auto-remove', $newLink).fadeOut() }, 3000);
- return $newLink.get(0);
- }
- /**
- * A click handler that is attached to all <A class="flag"> elements.
- */
- function flagClick(event) {
- // Prevent the default browser click handler
- event.preventDefault();
- // 'this' won't point to the element when it's inside the ajax closures,
- // so we reference it using a variable.
- var element = this;
- // While waiting for a server response, the wrapper will have a
- // 'flag-waiting' class. Themers are thus able to style the link
- // differently, e.g., by displaying a throbber.
- var $wrapper = $(element).parents('.flag-wrapper');
- if ($wrapper.is('.flag-waiting')) {
- // Guard against double-clicks.
- return false;
- }
- $wrapper.addClass('flag-waiting');
- // Hide any other active messages.
- $('span.flag-message:visible').fadeOut();
- // Send POST request
- $.ajax({
- type: 'POST',
- url: element.href,
- data: { js: true },
- dataType: 'json',
- success: function (data) {
- data.link = $wrapper.get(0);
- $.event.trigger('flagGlobalBeforeLinkUpdate', [data]);
- if (!data.preventDefault) { // A handler may cancel updating the link.
- data.link = updateLink(element, data.newLink);
- }
- // Find all the link wrappers on the page for this flag, but exclude
- // the triggering element because Flag's own javascript updates it.
- var $wrappers = $('.flag-wrapper.flag-' + data.flagName.flagNameToCSS() + '-' + data.contentId).not(data.link);
- var $newLink = $(data.newLink);
- // Hide message, because we want the message to be shown on the triggering element alone.
- $('.flag-message', $newLink).hide();
- // Finally, update the page.
- $wrappers = $newLink.replaceAll($wrappers);
- Drupal.attachBehaviors($wrappers.parent());
- $.event.trigger('flagGlobalAfterLinkUpdate', [data]);
- },
- error: function (xmlhttp) {
- alert('An HTTP error '+ xmlhttp.status +' occurred.\n'+ element.href);
- $wrapper.removeClass('flag-waiting');
- }
- });
- }
- $('a.flag-link-toggle:not(.flag-processed)', context).addClass('flag-processed').click(flagClick);
- };
- /**
- * Prevent anonymous flagging unless the user has JavaScript enabled.
- */
- Drupal.flagAnonymousLinks = function(context) {
- $('a.flag:not(.flag-anonymous-processed)', context).each(function() {
- this.href += (this.href.match(/\?/) ? '&' : '?') + 'has_js=1';
- $(this).addClass('flag-anonymous-processed');
- });
- }
- String.prototype.flagNameToCSS = function() {
- return this.replace(/_/g, '-');
- }
- /**
- * A behavior specifically for anonymous users. Update links to the proper state.
- */
- Drupal.flagAnonymousLinkTemplates = function(context) {
- // Swap in current links. Cookies are set by PHP's setcookie() upon flagging.
- var templates = Drupal.settings.flag.templates;
- // Build a list of user-flags.
- var userFlags = Drupal.flagCookie('flags');
- if (userFlags) {
- userFlags = userFlags.split('+');
- for (var n in userFlags) {
- var flagInfo = userFlags[n].match(/(\w+)_(\d+)/);
- var flagName = flagInfo[1];
- var contentId = flagInfo[2];
- // User flags always default to off and the JavaScript toggles them on.
- if (templates[flagName + '_' + contentId]) {
- $('.flag-' + flagName.flagNameToCSS() + '-' + contentId, context).after(templates[flagName + '_' + contentId]).remove();
- }
- }
- }
- // Build a list of global flags.
- var globalFlags = document.cookie.match(/flag_global_(\w+)_(\d+)=([01])/g);
- if (globalFlags) {
- for (var n in globalFlags) {
- var flagInfo = globalFlags[n].match(/flag_global_(\w+)_(\d+)=([01])/);
- var flagName = flagInfo[1];
- var contentId = flagInfo[2];
- var flagState = (flagInfo[3] == '1') ? 'flag' : 'unflag';
- // Global flags are tricky, they may or may not be flagged in the page
- // cache. The template always contains the opposite of the current state.
- // So when checking global flag cookies, we need to make sure that we
- // don't swap out the link when it's already in the correct state.
- if (templates[flagName + '_' + contentId]) {
- $('.flag-' + flagName.flagNameToCSS() + '-' + contentId, context).each(function() {
- if ($(this).find('.' + flagState + '-action').size()) {
- $(this).after(templates[flagName + '_' + contentId]).remove();
- }
- });
- }
- }
- }
- }
- /**
- * Utility function used to set Flag cookies.
- *
- * Note this is a direct copy of the jQuery cookie library.
- * Written by Klaus Hartl.
- */
- Drupal.flagCookie = function(name, value, options) {
- if (typeof value != 'undefined') { // name and value given, set cookie
- options = options || {};
- if (value === null) {
- value = '';
- options = $.extend({}, options); // clone object since it's unexpected behavior if the expired property were changed
- options.expires = -1;
- }
- var expires = '';
- if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
- var date;
- if (typeof options.expires == 'number') {
- date = new Date();
- date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
- } else {
- date = options.expires;
- }
- expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
- }
- // NOTE Needed to parenthesize options.path and options.domain
- // in the following expressions, otherwise they evaluate to undefined
- // in the packed version for some reason...
- var path = options.path ? '; path=' + (options.path) : '';
- var domain = options.domain ? '; domain=' + (options.domain) : '';
- var secure = options.secure ? '; secure' : '';
- document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
- } else { // only name given, get cookie
- var cookieValue = null;
- if (document.cookie && document.cookie != '') {
- var cookies = document.cookie.split(';');
- for (var i = 0; i < cookies.length; i++) {
- var cookie = jQuery.trim(cookies[i]);
- // Does this cookie string begin with the name we want?
- if (cookie.substring(0, name.length + 1) == (name + '=')) {
- cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
- break;
- }
- }
- }
- return cookieValue;
- }
- };
- Drupal.behaviors.flagLink = {};
- Drupal.behaviors.flagLink.attach = function(context) {
- // For anonymous users with the page cache enabled, swap out links with their
- // current state for the user.
- if (Drupal.settings.flag && Drupal.settings.flag.templates) {
- Drupal.flagAnonymousLinkTemplates(context);
- }
- // For all anonymous users, require JavaScript for flagging to prevent spiders
- // from flagging things inadvertently.
- if (Drupal.settings.flag && Drupal.settings.flag.anonymous) {
- Drupal.flagAnonymousLinks(context);
- }
- // On load, bind the click behavior for all links on the page.
- Drupal.flagLink(context);
- };
- })(jQuery);
|