root / htmltest / sites / all / modules / flag / theme / flag.js @ a5572547
1 |
(function ($) { |
---|---|
2 |
|
3 |
/**
|
4 |
* Terminology:
|
5 |
*
|
6 |
* "Link" means "Everything which is in flag.tpl.php" --and this may contain
|
7 |
* much more than the <A> element. On the other hand, when we speak
|
8 |
* specifically of the <A> element, we say "element" or "the <A> element".
|
9 |
*/
|
10 |
|
11 |
/**
|
12 |
* The main behavior to perform AJAX toggling of links.
|
13 |
*/
|
14 |
Drupal.flagLink = function(context) { |
15 |
/**
|
16 |
* Helper function. Updates a link's HTML with a new one.
|
17 |
*
|
18 |
* @param element
|
19 |
* The <A> element.
|
20 |
* @return
|
21 |
* The new link.
|
22 |
*/
|
23 |
function updateLink(element, newHtml) { |
24 |
var $newLink = $(newHtml); |
25 |
|
26 |
// Initially hide the message so we can fade it in.
|
27 |
$('.flag-message', $newLink).css('display', 'none'); |
28 |
|
29 |
// Reattach the behavior to the new <A> element. This element
|
30 |
// is either whithin the wrapper or it is the outer element itself.
|
31 |
var $nucleus = $newLink.is('a') ? $newLink : $('a.flag', $newLink); |
32 |
$nucleus.addClass('flag-processed').click(flagClick); |
33 |
|
34 |
// Find the wrapper of the old link.
|
35 |
var $wrapper = $(element).parents('.flag-wrapper:first'); |
36 |
// Replace the old link with the new one.
|
37 |
$wrapper.after($newLink).remove(); |
38 |
Drupal.attachBehaviors($newLink.get(0)); |
39 |
|
40 |
$('.flag-message', $newLink).fadeIn(); |
41 |
setTimeout(function(){ $('.flag-message.flag-auto-remove', $newLink).fadeOut() }, 3000); |
42 |
return $newLink.get(0); |
43 |
} |
44 |
|
45 |
/**
|
46 |
* A click handler that is attached to all <A class="flag"> elements.
|
47 |
*/
|
48 |
function flagClick(event) { |
49 |
// Prevent the default browser click handler
|
50 |
event.preventDefault(); |
51 |
|
52 |
// 'this' won't point to the element when it's inside the ajax closures,
|
53 |
// so we reference it using a variable.
|
54 |
var element = this; |
55 |
|
56 |
// While waiting for a server response, the wrapper will have a
|
57 |
// 'flag-waiting' class. Themers are thus able to style the link
|
58 |
// differently, e.g., by displaying a throbber.
|
59 |
var $wrapper = $(element).parents('.flag-wrapper'); |
60 |
if ($wrapper.is('.flag-waiting')) { |
61 |
// Guard against double-clicks.
|
62 |
return false; |
63 |
} |
64 |
$wrapper.addClass('flag-waiting'); |
65 |
|
66 |
// Hide any other active messages.
|
67 |
$('span.flag-message:visible').fadeOut(); |
68 |
|
69 |
// Send POST request
|
70 |
$.ajax({
|
71 |
type: 'POST', |
72 |
url: element.href,
|
73 |
data: { js: true }, |
74 |
dataType: 'json', |
75 |
success: function (data) { |
76 |
data.link = $wrapper.get(0); |
77 |
$.event.trigger('flagGlobalBeforeLinkUpdate', [data]); |
78 |
if (!data.preventDefault) { // A handler may cancel updating the link. |
79 |
data.link = updateLink(element, data.newLink); |
80 |
} |
81 |
|
82 |
// Find all the link wrappers on the page for this flag, but exclude
|
83 |
// the triggering element because Flag's own javascript updates it.
|
84 |
var $wrappers = $('.flag-wrapper.flag-' + data.flagName.flagNameToCSS() + '-' + data.contentId).not(data.link); |
85 |
var $newLink = $(data.newLink); |
86 |
|
87 |
// Hide message, because we want the message to be shown on the triggering element alone.
|
88 |
$('.flag-message', $newLink).hide(); |
89 |
|
90 |
// Finally, update the page.
|
91 |
$wrappers = $newLink.replaceAll($wrappers); |
92 |
Drupal.attachBehaviors($wrappers.parent());
|
93 |
|
94 |
$.event.trigger('flagGlobalAfterLinkUpdate', [data]); |
95 |
}, |
96 |
error: function (xmlhttp) { |
97 |
alert('An HTTP error '+ xmlhttp.status +' occurred.\n'+ element.href); |
98 |
$wrapper.removeClass('flag-waiting'); |
99 |
} |
100 |
}); |
101 |
} |
102 |
|
103 |
$('a.flag-link-toggle:not(.flag-processed)', context).addClass('flag-processed').click(flagClick); |
104 |
}; |
105 |
|
106 |
/**
|
107 |
* Prevent anonymous flagging unless the user has JavaScript enabled.
|
108 |
*/
|
109 |
Drupal.flagAnonymousLinks = function(context) { |
110 |
$('a.flag:not(.flag-anonymous-processed)', context).each(function() { |
111 |
this.href += (this.href.match(/\?/) ? '&' : '?') + 'has_js=1'; |
112 |
$(this).addClass('flag-anonymous-processed'); |
113 |
}); |
114 |
} |
115 |
|
116 |
String.prototype.flagNameToCSS = function() { |
117 |
return this.replace(/_/g, '-'); |
118 |
} |
119 |
|
120 |
/**
|
121 |
* A behavior specifically for anonymous users. Update links to the proper state.
|
122 |
*/
|
123 |
Drupal.flagAnonymousLinkTemplates = function(context) { |
124 |
// Swap in current links. Cookies are set by PHP's setcookie() upon flagging.
|
125 |
|
126 |
var templates = Drupal.settings.flag.templates;
|
127 |
|
128 |
// Build a list of user-flags.
|
129 |
var userFlags = Drupal.flagCookie('flags'); |
130 |
if (userFlags) {
|
131 |
userFlags = userFlags.split('+');
|
132 |
for (var n in userFlags) { |
133 |
var flagInfo = userFlags[n].match(/(\w+)_(\d+)/); |
134 |
var flagName = flagInfo[1]; |
135 |
var contentId = flagInfo[2]; |
136 |
// User flags always default to off and the JavaScript toggles them on.
|
137 |
if (templates[flagName + '_' + contentId]) { |
138 |
$('.flag-' + flagName.flagNameToCSS() + '-' + contentId, context).after(templates[flagName + '_' + contentId]).remove(); |
139 |
} |
140 |
} |
141 |
} |
142 |
|
143 |
// Build a list of global flags.
|
144 |
var globalFlags = document.cookie.match(/flag_global_(\w+)_(\d+)=([01])/g); |
145 |
if (globalFlags) {
|
146 |
for (var n in globalFlags) { |
147 |
var flagInfo = globalFlags[n].match(/flag_global_(\w+)_(\d+)=([01])/); |
148 |
var flagName = flagInfo[1]; |
149 |
var contentId = flagInfo[2]; |
150 |
var flagState = (flagInfo[3] == '1') ? 'flag' : 'unflag'; |
151 |
// Global flags are tricky, they may or may not be flagged in the page
|
152 |
// cache. The template always contains the opposite of the current state.
|
153 |
// So when checking global flag cookies, we need to make sure that we
|
154 |
// don't swap out the link when it's already in the correct state.
|
155 |
if (templates[flagName + '_' + contentId]) { |
156 |
$('.flag-' + flagName.flagNameToCSS() + '-' + contentId, context).each(function() { |
157 |
if ($(this).find('.' + flagState + '-action').size()) { |
158 |
$(this).after(templates[flagName + '_' + contentId]).remove(); |
159 |
} |
160 |
}); |
161 |
} |
162 |
} |
163 |
} |
164 |
} |
165 |
|
166 |
/**
|
167 |
* Utility function used to set Flag cookies.
|
168 |
*
|
169 |
* Note this is a direct copy of the jQuery cookie library.
|
170 |
* Written by Klaus Hartl.
|
171 |
*/
|
172 |
Drupal.flagCookie = function(name, value, options) { |
173 |
if (typeof value != 'undefined') { // name and value given, set cookie |
174 |
options = options || {}; |
175 |
if (value === null) { |
176 |
value = '';
|
177 |
options = $.extend({}, options); // clone object since it's unexpected behavior if the expired property were changed |
178 |
options.expires = -1;
|
179 |
} |
180 |
var expires = ''; |
181 |
if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { |
182 |
var date;
|
183 |
if (typeof options.expires == 'number') { |
184 |
date = new Date();
|
185 |
date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); |
186 |
} else {
|
187 |
date = options.expires; |
188 |
} |
189 |
expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE |
190 |
} |
191 |
// NOTE Needed to parenthesize options.path and options.domain
|
192 |
// in the following expressions, otherwise they evaluate to undefined
|
193 |
// in the packed version for some reason...
|
194 |
var path = options.path ? '; path=' + (options.path) : ''; |
195 |
var domain = options.domain ? '; domain=' + (options.domain) : ''; |
196 |
var secure = options.secure ? '; secure' : ''; |
197 |
document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); |
198 |
} else { // only name given, get cookie |
199 |
var cookieValue = null; |
200 |
if (document.cookie && document.cookie != '') { |
201 |
var cookies = document.cookie.split(';'); |
202 |
for (var i = 0; i < cookies.length; i++) { |
203 |
var cookie = jQuery.trim(cookies[i]);
|
204 |
// Does this cookie string begin with the name we want?
|
205 |
if (cookie.substring(0, name.length + 1) == (name + '=')) { |
206 |
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
207 |
break;
|
208 |
} |
209 |
} |
210 |
} |
211 |
return cookieValue;
|
212 |
} |
213 |
}; |
214 |
|
215 |
Drupal.behaviors.flagLink = {}; |
216 |
Drupal.behaviors.flagLink.attach = function(context) { |
217 |
// For anonymous users with the page cache enabled, swap out links with their
|
218 |
// current state for the user.
|
219 |
if (Drupal.settings.flag && Drupal.settings.flag.templates) {
|
220 |
Drupal.flagAnonymousLinkTemplates(context); |
221 |
} |
222 |
|
223 |
// For all anonymous users, require JavaScript for flagging to prevent spiders
|
224 |
// from flagging things inadvertently.
|
225 |
if (Drupal.settings.flag && Drupal.settings.flag.anonymous) {
|
226 |
Drupal.flagAnonymousLinks(context); |
227 |
} |
228 |
|
229 |
// On load, bind the click behavior for all links on the page.
|
230 |
Drupal.flagLink(context); |
231 |
}; |
232 |
|
233 |
})(jQuery); |