extensions-jQuery.js (10040B)
1 // Extensions de String 2 3 String.prototype.escapeXML = function() { 4 return this 5 .replace(/&/g, "&") 6 .replace(/</g, "<") 7 .replace(/>/g, ">") 8 .replace(/"/g, """) 9 .replace(/'/g, "'"); 10 } 11 12 /* "<div>foo</div>".toDom() ⇔ $("<div>foo</div>") */ 13 String.prototype.toDom = function() { 14 return $("" + this); 15 } 16 17 String.prototype.appendTo = function() { 18 var d = this.toDom(); 19 return d.appendTo.apply(d, arguments); 20 } 21 22 // Extensions de jQuery 23 24 jQuery.fn.extend({ 25 /* Mathias Bynens - http://stackoverflow.com/questions/2059743/detect-elements-overflow-using-jquery */ 26 overflows: function() { 27 return ($(this).width() !== this.clientWidth || $(this).height() !== this.clientHeight); 28 }, 29 scrollToLast: function(speed) { 30 return this.scrollTo(this.children().last(), speed); 31 }, 32 addTo: function(collection) { 33 $.merge(collection, this); 34 return collection; 35 }, 36 remap: function(fn) { 37 var a = $.makeArray(arguments); 38 a.shift(); 39 40 var r = $(); 41 this.each(function(i, e) { 42 var aa = $.makeArray(a); 43 aa.push(e); 44 r = r.add(fn.apply(this, aa)); 45 }); 46 return r; 47 }, 48 // Sérialise le DOM de l'élément sous forme de HTML. 49 serializeDOM: function(value) { 50 /* get the DOM of this node, serialized as HTML. 51 * with value, set the DOM of this node to the 52 * serialized HTML value (Not Implemented Yet) */ 53 if ( value === undefined ) { 54 return this.html().escapeXML(); 55 } 56 }, 57 // renvoie le map de attr sur chaque élément (lecture seule). 58 attrs: function(value) { 59 return this.map(function(idx, elem) { 60 return $([elem]).attr(value); 61 }); 62 }, 63 // Active ou désactive resizable(), et rend la hauteur libre. 64 toggleResizable: function() { 65 // TODO : devrait enregistrer les options. 66 67 if (this.data('notResizable')) { 68 this.resizable(); 69 this.height(this.data('oldHeight')); 70 } else { 71 this.resizable('destroy'); 72 this.data('oldHeight', this.height()); 73 this.height('auto'); 74 } 75 76 this.data('notResizable', ! this.data('notResizable')) 77 78 return this; 79 }, 80 81 // Alias pour des accesseurs courants sur les positions des éléments 82 // Top, left, center, bottom, right, en X et en Y. 83 offX: function(value) { 84 if (value === undefined) { 85 return this.offset().left; 86 } else { 87 return this.offset({left: value}); 88 } 89 }, 90 offY: function(value) { 91 if (value === undefined) { 92 return this.offset().top; 93 } else { 94 return this.offset({top: value}); 95 } 96 }, 97 leftX: function() { 98 return this.offX.apply(this, arguments); 99 }, 100 topY: function() { 101 return this.offY.apply(this, arguments); 102 }, 103 centerX: function() { 104 return this.offX() + (this.width() / 2); 105 }, 106 centerY: function() { 107 return this.offY() + (this.height() / 2); 108 }, 109 rightX: function() { 110 return this.offX() + this.width(); 111 }, 112 bottomY: function() { 113 return this.offY() + this.height(); 114 } 115 }); 116 117 // Fonction utilitaire permettant de facilement surcharger un 118 // accesseur pour un certain type d'éléments. 119 function surchargeAccesseur(nom, type, get, set) { 120 var _old = $.fn[nom]; 121 $.fn[nom] = function(options) { 122 var args = arguments; 123 if (options !== undefined) { 124 var that = this; 125 var ret = $(this).map(function (i) { 126 if (that[i] instanceof type) { 127 return set(that[i], options); 128 } else { 129 return _old.apply($(that[i]), args); 130 } 131 }); 132 return ret[0]; 133 } else { 134 if (this[0] instanceof type) { 135 return get(this); 136 } else { 137 return _old.call(this); 138 } 139 } 140 }; 141 142 } 143 144 function surchargeAccesseurSimple(nom, defaut, type) { 145 surchargeAccesseur( 146 nom, 147 type, 148 function (obj) { ret = obj[0][nom]; return (ret !== undefined) ? ret : defaut; }, 149 function (obj, val) { obj[nom] = val; } 150 ); 151 } 152 153 // Permet d'utiliser un évènement comme si c'était un élément du DOM. 154 155 // This is the beauty of JavaScript ♥. 156 surchargeAccesseurSimple('height', 0, $.Event); 157 surchargeAccesseurSimple('width', 0, $.Event); 158 surchargeAccesseurSimple('scrollLeft', 0, $.Event); 159 surchargeAccesseurSimple('scrollTop', 0, $.Event); 160 surchargeAccesseurSimple('outerWidth', 0, $.Event); 161 surchargeAccesseurSimple('outerHeight', 0, $.Event); 162 surchargeAccesseur( 163 'offset', 164 $.Event, 165 function (obj) { 166 return { 167 left: obj[0].pageX, 168 top: obj[0].pageY 169 }; 170 }, 171 function (obj, val) { 172 if ('left' in val) { that[i].pageX = val.left; } 173 if ('top' in val) { that[i].pageY = val.top; } 174 } 175 ); 176 177 // Fix firefox bug : when top or left are set to a non-integer value, flicker occurs. 178 (function ($) { 179 var _offset = $.fn.offset; 180 181 $.fn.offset = function(options) { 182 var args = arguments; 183 if (options !== undefined) { 184 if ('left' in options) { args[0].left = Math.floor(options.left); } 185 if ('top' in options) { args[0].top = Math.floor(options.top); } 186 } 187 188 return _offset.apply(this, args); 189 } 190 }(jQuery)); 191 192 193 getRectangle = function(x1,y1,x2,y2) { 194 if (y1 === undefined) { 195 var o = $(x1).offset(); 196 return getRectangle(o.left, o.top, o.left + $(x1).width(), o.top + $(x1).height()); 197 } 198 if (x2 === undefined) { 199 var oa = $(x1).offset(); 200 var ob = $(y1).offset(); 201 return getRectangle(oa.left, oa.top, ob.left, ob.top); 202 } 203 return { 204 x1: Math.min(x1,x2), 205 y1: Math.min(y1,y2), 206 x2: Math.max(x1,x2), 207 y2: Math.max(y1,y2), 208 width: Math.abs(x1 - x2), 209 height: Math.abs(y1 - y2) 210 }; 211 }; 212 213 jQuery.fn.corners = function(x1,y1,x2,y2) { 214 var rect = getRectangle(x1,y1,x2,y2); 215 this.offset({left: rect.x1, top: rect.y1}); 216 this.width(rect.width); 217 this.height(rect.height); 218 } 219 220 jQuery.fn.zonable = function(start, zone, end) { 221 var opts = { 222 start: function() {return true;}, 223 zone: function() {return true;}, 224 end: function() {return true;} 225 }; 226 if (typeof start == "function") { 227 if (start) opts.start = start; 228 if (zone) opts.start = start; 229 if (end) opts.start = start; 230 } else { 231 if (start) $.extend(opts, start); 232 } 233 234 var z = {}; 235 z.vZone = $('#vue-zone').jqote({}).appendTo(this); 236 z.vZone.hide(); 237 z.zoning = false; 238 z.start = null; 239 240 z.manageDown = function(e) { 241 if (e.target != this || opts.start(e) === false) { 242 return true; 243 } 244 z.start = $(e); 245 z.zoning = true; 246 z.vZone.show(); 247 z.manageMove(e); 248 return false; 249 }; 250 z.manageMove = function(e) { 251 if (z.zoning) { 252 if (opts.zone(z.start, e) === false) { 253 return true; 254 } 255 z.vZone.corners(z.start, e); 256 return false; 257 } 258 }; 259 z.manageUp = function(e) { 260 if (z.zoning) { 261 z.manageMove(e); 262 if (opts.end(z.start, e, getRectangle(z.start, e)) === false) { 263 return true; 264 } 265 z.vZone.hide(); 266 z.zoning = false; 267 return false; 268 } 269 } 270 271 var that = this; 272 this.mousedown(z.manageDown); 273 this.mousemove(z.manageMove); 274 this.mouseup(z.manageUp); 275 } 276 277 278 /* Fioritures graphique */ 279 jQuery.fn.extend({ 280 blink: function (count, speed) { 281 elem = this; 282 count = count || 10; 283 speed = speed || 1000; 284 285 // Mouseover 286 // Todo : il y a des bugs graphiques ici, 287 // et il faudrait enlever ce hook "mouseover" 288 // après la première fois. 289 elem.mouseover(function () { 290 elem.clearQueue("blink"); 291 elem.queue("blink", function() { 292 elem.removeClass('boutonHover', 1000); 293 }); 294 }); 295 296 // Enqueue blinks 297 for (; count > 0; count--) { 298 elem.queue("blink", function () { 299 elem.toggleClass('boutonHover', 1000, function() { elem.dequeue("blink"); }); 300 }); 301 } 302 elem.queue("blink", function() { 303 elem.removeClass('boutonHover', 1000); 304 }); 305 306 // Start first blink 307 elem.dequeue("blink"); 308 }, 309 stepAnimateClass: function(from, to) { 310 var el = $(this[0]); // TODO : faire un foreach. 311 var actions = {}; 312 var props = ['backgroundColor', 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'color', 'outlineColor']; 313 314 // Get the end 315 var end = {}; 316 var oldstyle = el.attr('style'); 317 var oldclasses = el.attr('className'); 318 el.addClass(to); 319 $.each(props, function(i, attr) { 320 end[attr] = el.css(attr); 321 }); 322 el.attr('className', oldclasses); 323 el.addClass(from); 324 325 // Prepare animations 326 $.each(props, function(i, attr) { 327 actions[attr] = { 328 elem: el[0], 329 end: end[attr], 330 pos: 0 331 }; 332 $.fx.step[attr](actions[attr]); 333 }); 334 el.attr('style', ''); 335 el.attr('style', oldstyle); 336 el.attr('className', oldclasses); 337 338 return function(pos) { 339 if (pos === undefined) { 340 el.attr('style', ''); 341 el.attr('style', oldstyle); 342 } 343 for (i in actions) { 344 actions[i].pos = pos; 345 $.fx.step[i](actions[i]); 346 } 347 } 348 } 349 });