1/* 2Last update: 2013-2-17 3*/ 4 5/* 6A shortcut to console.log 7*/ 8function say(input) { 9 console.log(input); 10} 11 12(function(window, jQuery) { 13 var $ = jQuery; 14 15 /* 16 Returns the library with the given selection saved to it, so that we can work with that 17 selection when executing other functions in the Odf library. 18 19 @param string jquery_selector 20 The string that is used by jQuery to create a selection, e.g. "div#container". 21 */ 22 function Odf(jquery_selector) { 23 if(!$(jquery_selector).length) { 24 console.log('Error: target (' + jquery_selector + ') not found.'); 25 return false; 26 } 27 else { 28 return new Odf.prototype.select(jquery_selector); 29 } 30 } 31 32 33 34 // Define the Odf library's functions. 35 Odf.prototype = { 36 37 /* 38 Saves the given selection to the object so that we can work with it later on. This function 39 is executed when the Odf() function is executed and is returned as an object containing 40 the Odf prototype. 41 42 @param string jquery_selector 43 The string that is used by jQuery to create a selection, e.g. "div#container". 44 */ 45 select: function(jquery_selector) { 46 Odf.selection = $(jquery_selector); 47 this.length = Odf.selection.length; 48 }, 49 50 51 settings: { 52 loading_image: 'img/loading.gif', 53 loading_image_big: 'img/loading_big.gif', 54 loading_image_black_bg: 'img/loading_black_bg.gif', 55 loading_image_black_bg_big: 'img/loading_black_bg_big.gif' 56 }, 57 58 59 /* 60 Sets a var in this.settings, which can be retrieved through this.get() in any function 61 you'd like. I'd rather have a function for this than calling this.settings.varname all the 62 time :). 63 64 @param string key 65 The key for which to set the value. 66 @param mixed value 67 The value to store. 68 @return nothing 69 */ 70 set: function(key, value) { 71 Odf.settings[key] = value; 72 }, 73 74 75 /* 76 Returns a var from Odf.settings. 77 78 @param string key 79 The key of which to retrieve the value. 80 @return mixed 81 The value of the requested key. 82 */ 83 get: function(key) { 84 return Odf.settings[key]; 85 }, 86 87 88 /* 89 Initiates the ODF library, enabling stuff like AJAX functionality for forms with the 90 "odf_ajax" class. 91 */ 92 init: function() { 93 // Ready href class elements. 94 $('.odf_href').click(function() { 95 var href = $(this).data('href'); 96 window.location.href = href; 97 }); 98 99 // Ready <tr> hovers. 100 $('.odf_hover').hover(function() { 101 $(this).addClass('hovered'); 102 }, 103 function() { 104 $(this).removeClass('hovered'); 105 }); 106 107 // Ready forms. 108 $('form.odf_ajax').each(function() { 109 $(this).on('submit', function() { 110 Odf.ajax.submit.call(this); 111 return false; 112 }); 113 }); 114 }, 115 116 117 /*********************************************************************** 118 AJAX functionalities 119 */ 120 121 ajax: { 122 123 /* 124 Sets a target to load AJAX results in that are returned by Odf's AJAX functions. 125 126 @param string selector 127 The jQuery selector for the target. E.g. 'div#ajax_target'. 128 @return none 129 */ 130 setTarget: function(selector) { 131 this.selectors.ajax_target = $(selector); 132 }, 133 134 135 /* 136 Returns the target previously set by this.setTarget() as jQuery object. 137 138 @return object 139 The target as jQuery object. 140 */ 141 getTarget: function() { 142 var r = $(this.selectors.ajax_target); 143 return r; 144 }, 145 146 147 /* 148 Sets the HTML to be parsed by other AJAX functions. 149 150 @param object html 151 The object used in jQuery's $.ajax() function, in its. success(html) function. 152 @return none 153 */ 154 setHtml: function(html) { 155 Odf.set('html', html); 156 }, 157 158 159 /* 160 Returns the value of a hidden return <input> from the HTML that was set by this.setHtml(). 161 162 @param string return_name 163 The name of the hidden return input to get the status from. These inputs must be 164 have the "odf_return_" prefix. 165 @return string 166 The value of the targeted hidden <input>. 167 */ 168 getReturn: function(return_name) { 169 html = Odf.get('html'); 170 171 // Parse the HTML. 172 html = $.parseHTML(html); 173 174 // Contain the HTML in an invisible <div> so that we can search through it.
175 var div = $('<div></div>'); 176 div.html(html); 177 178 // Get the return status. 179 var status = div.find('input[name=odf_return_' + return_name + ']').val(); 180 181 return status; 182 }, 183 184 185 /* 186 Removes the hidden return <inputs> in the HTML set by this.setHtml(). 187 188 @return object 189 The HTML object without the hidden return <input>s. 190 */ 191 removeReturns: function() { 192 html = Odf.get('html'); 193 194 // Parse the HTML. 195 // html = $.parseHTML(html); 196 197 // Contain the HTML in an invisible <div> so that we can search through it. 198 var div = $('<div></div>'); 199 div.html(html); 200 201 // Remove the return status from the returned HTML. 202 div.find('input[name^=odf_return_]').remove(); 203 204 // Remove the container <div> as we're done searching the returned HTML. 205 html = div.html(); 206 207 return html; 208 }, 209 210 /* 211 Create a custom XMLHttpRequest object. 212 213 @return object 214 Returns a custom XMLHttpRequest object. 215 */ 216 createXhr: function() { 217 var xhr = new window.XMLHttpRequest(); 218 219 // Upload progress 220 xhr.upload.addEventListener('progress', function(e) { 221 if(e.lengthComputable) { 222 var progress_percentage = Math.ceil((e.loaded / e.total) * 100); 223 $('span#progress_percentage').html(progress_percentage + ' %'); 224 } 225 }, false); 226 227 // Download progress 228 xhr.addEventListener('progress', function(e) { 229 if(e.lengthComputable) { 230 var progress_percentage = Math.ceil((e.loaded / e.total) * 100); 231 } 232 }, false); 233 234 return xhr; 235 }, 236 237 removeLoadingImage: function(loading_image_id) { 238 if(loading_image_id) { 239 $('img#' + loading_image_id).remove(); 240 } 241 else { 242 $('img.odf_loading_image').remove(); 243 } 244 }, 245 246 247 /* 248 Submits a form through AJAX. 249 250 [@param object odf_return_status_functions] 251 Contains a function to execute for each status that is returned in the $.ajax()'s 252 success() function. E.g. { success: function() { ... } } 253 [@param bool use_toggle_instead_of_slide] 254 If set to true, the function will not use an animation to display the results of the 255 action. 256 */ 257 submit: function(odf_return_status_functions, use_toggle_instead_of_slide) { 258 var self = $(this); // The form that was submitted. 259 260 if(self[0].tagName.toLowerCase() != 'form') { 261 console.log('Error: cannot submit a non-form.'); 262 return false; 263 } 264 265 var action = self.attr('action'); 266 var method = self.attr('method'); 267 var target = $('div#' + self.data('target')); 268 269 $.ajax({ 270 url: action, 271 type: method.toUpperCase(), 272 data: self.serialize(), 273 beforeSend: function() { 274 // Remove any existing loading images. 275 Odf.ajax.removeLoadingImage(); 276 277 // # 278 // # Display loading image. 279 // # 280 281 var img = $('<img src="' + Odf.get('loading_image') + '" class="odf_loading_image">'); 282 var submit_button = self.find('input[type=submit]:first'); 283 284 if(!submit_button.length) 285 var submit_button = self.find('button[type=submit]:first'); 286 287 if(!submit_button.length) { 288 if(self.data('submit_button_id')) 289 submit_button = $('input#' + self.data('submit_button_id')); 290 else 291 submit_button = $('input[type=submit]:last'); 292 } 293 294 var offset = submit_button.offset(); 295 296 // Display the loading image. 297 $('body').prepend(img); 298 img = $('img.odf_loading_image:first'); 299 300 301 // Offset top 302 if(submit_button.height() > img.height()) { 303 var additional_offset_top = (submit_button.height() - img.height()) / 2; 304 } 305 else { 306 var additional_offset_top = (img.height() - submit_button.height()) / 2; 307 } 308 309 var offset_top = offset.top + additional_offset_top 310 311 312 // Offset left 313 var additional_offset_left = parseInt(submit_button.css('padding-left')) + parseInt(submit_button.css('padding-right')); 314 315 if(self.hasClass('odf_loading_image_left')) { 316 //* The loading image is to be displayed to the left of the submit button. 317 var offset_left = offset.left - img.width() - 10; 318 } 319 else { 320 //* The loading image is to be displayed to the right of the submit button. 321 var offset_left = offset.left + submit_button.width() + additional_offset_left + 10; 322 } 323 324 img.css({ 325 position: 'absolute', 326 top: offset_top, 327 left: offset_left, 328 'z-index': 100 329 }); 330 331 // # --/ 332 333 }, 334 success: function(html) { 335 Odf.ajax.removeLoadingImage(); 336 Odf.ajax.setHtml(html); 337 var slide_speed = 300; 338 339 340 // Do we have to execute a redirect? 341 var redirect = Odf.ajax.getReturn('redirect'); 342 343 if(redirect) { 344 window.location.href = redirect; 345 console.log('redirect'); 346 return; 347 } 348 349 350 // Have special return status functions been given? E.g. if a "success" return 351 // status should produce a different result as a "error" return status. 352 if(odf_return_status_functions) { 353 var status = Odf.ajax.getReturn('status'); 354 var function_to_execute = odf_return_status_functions[status]; 355 356 // Has a custom function to execute been given? 357 if(function_to_execute) { 358 var r = function_to_execute(html); 359 360 // If the function to execute returns false, this is a special sign 361 // to not execute any more default functionality. 362 if(r === false) 363 return; 364 } 365 366 var html = Odf.ajax.removeReturns(); 367 } 368 369 370 // Display return HTML. 371 if(target && use_toggle_instead_of_slide) { 372 target.html(html).show(); 373 } 374 else if(target) { 375 376 if(target.is(':hidden')) { 377 target.stop().html(html).slideToggle(slide_speed); 378 } 379 else { 380 // Wrap the contents of the target, so that we won't have to change 381 // the target's height during the sliding, so that the page height 382 // will remain unchanged. 383 target.wrapInner('<div id="odf_tmp_ajax_wrapper"></div>'); 384 var fake_target = $('div#odf_tmp_ajax_wrapper'); 385 386 387 // Make sure the container will keep the same height, so that the 388 // sliding won't affect the page's height. 389 var current_height = target.height(); 390 target.height(current_height); 391 392 fake_target.stop().slideToggle(slide_speed, function() { 393 // Set the target's content. 394 $(this).stop().html(html); 395
396 // Get the content's new height witout revealing the element. 397 $(this).show(); 398 var new_height = $(this).height(); 399 $(this).hide(); 400 401 // If there is a height difference, make sure the container 402 // takes on a new height. 403 if(new_height != current_height) { 404 target.animate({ 405 height: new_height 406 }); 407 } 408 409 // Show the content. 410 $(this).slideToggle(slide_speed, function() { 411 fake_target.remove(); 412 var contents = fake_target.html(); 413 target.html(contents); 414 }); 415 }); 416 } 417 418 // Make sure the displayed message is seen by scrolling to it if it is not 419 // in the current view. 420 var message_offset_top = target.offset().top; 421 422 if(message_offset_top < $(window).scrollTop()) { 423 var new_scroll_top = message_offset_top - 10; 424 new_scroll_top = new_scroll_top < 0 ? 0 : new_scroll_top; 425 426 $('html, body').animate({ 427 scrollTop: new_scroll_top 428 }); 429 } 430 } 431 }, 432 error: function(error) { 433 //alert('Ouch, something has gone terribly, terribly wrong.. The requested page could not be found or loaded :\\.'); 434 console.log(error.statusText); 435 } 436 }); 437 438 return false; 439 }, 440 441 442 /* 443 Loads a specific file through AJAX using GET. Creates a neat loading overlay in the 444 process. 445 446 @param str url 447 The URL to load. 448 @param str target_element_selector 449 The selector of the element in which to load the results. E.g. div#div_id. 450 [@param obj data] 451 Data to pass to the file that is loaded. E.g. { name: 'Stephan' }. 452 */ 453 get: function(url, target_element_selector, data) { 454 Odf.ajax.load(url, target_element_selector, data, 'get'); 455 }, 456 457 /* 458 Loads a specific file through AJAX using POST. Creates a neat loading overlay in the 459 process. 460 461 @param str url 462 The URL to load. 463 @param str target_element_selector 464 The selector of the element in which to load the results. E.g. div#div_id. 465 [@param obj data] 466 Data to pass to the file that is loaded. E.g. { name: 'Stephan' }. 467 */ 468 post: function(url, target_element_selector, data) { 469 Odf.ajax.load(url, target_element_selector, data, 'post'); 470 }, 471 472 /* 473 Loads a specific file through AJAX. Creates a neat loading overlay in the process. 474 475 @param str url 476 The URL to load. 477 @param str target_element_selector 478 The selector of the element in which to load the results. E.g. div#div_id. 479 [@param obj data] 480 Data to pass to the file that is loaded. E.g. { name: 'Stephan' }. 481 */ 482 load: function(url, target_element_selector, data, type) { 483 switch(type) { 484 default: 485 console.log('Error: invalid type (' + type + ').'); 486 break; 487 488 case 'post': 489 case 'get': 490 break; 491 } 492 493 var selection = Odf(target_element_selector); 494 if(!selection.length) { 495 console.log('Warning: selection could not be made with ' + target_element_selector); 496 return false; 497 } 498 499 $.ajax({ 500 url: url, 501 type: type, 502 data: data, 503 beforeSend: function() { 504 Odf(target_element_selector).removeLoadingOverlay(); 505 Odf(target_element_selector).createLoadingOverlay(); 506 }, 507 success: function(html) { 508 Odf(target_element_selector).removeLoadingOverlay(); 509 $(target_element_selector).html(html); 510 }, 511 error: function(error) { 512 Odf(target_element_selector).removeLoadingOverlay(); 513 console.log('Error: ' + error.statusText); 514 } 515 }); 516 }, 517 518 /* 519 W.I.P.! 520 521 Calls to the file specified in results_url for search results based on what has been 522 typed in element. This file must return JSON. 523 524 @parameter string|object options 525 If string: 526 The url to the file that will return the search results. This file must return 527 JSON. 528 If object: 529 An object containing the options for this function: 530 @key string results_url 531 The url to the file that will return the search results. This file must return 532 JSON. 533 [@key int min_length] 534 The minimum number of characters that must have been typed before the 535 search is triggered. 536 */ 537 autoComplete: function(options) { 538 var selection = Odf.selection; 539 var min_length = 3; 540 541 console.log(selection); 542 543 if(typeof options == 'string') { 544 var results_url = options; 545 } 546 else if(typeof options == 'object') { 547 var results_url = options.results_url; 548 min_length = options.min_length || min_length; 549 } 550 551 552 // We require a results url. 553 if(!results_url) 554 return false;
555 556 557 selection.each(function() { 558 $(this).blur(function() { 559 // alert('a'); 560 $('div#odf_autocomplete_results').remove(); 561 }); 562 563 $(this).keyup(function() { 564 var self = $(this); 565 var value = $.trim(self.val()); 566 567 if(value.length < min_length) 568 return; 569 570 $.ajax({ 571 type: 'POST', 572 data: { search: value }, 573 url: results_url, 574 beforeSend: function() { 575 // Show loading image next to self. 576 $('body').prepend('<img src="' + Odf.get('loading_image') + '" class="odf_loading_image">'); 577 578 $('body img.odf_loading_image:first').css({ 579 position: 'absolute', 580 top: Math.round( 581 self.offset().top 582 - (self.outerHeight() / 4) 583 ), 584 left: Math.round( 585 self.offset().left 586 + self.outerWidth() 587 + 10 588 ), 589 'z-index': 100 590 }); 591 592 593 }, 594 success: function(html) { 595 Odf.ajax.removeLoadingImage(); 596 597 // Remove any existing results. 598 $('div#odf_autocomplete_results').remove(); 599 600 // Wrap self in a container. 601 self.wrap('<div id="odf_autocomplete_container"></div>'); 602 var container = $('div#odf_autocomplete_container'); 603 604 // Create results <div>. 605 container.append('<div id="odf_autocomplete_results"></div>'); 606 var div = $('div#odf_autocomplete_results'); 607 608 div.css({ 609 width: self.width(), 610 top: self.outerHeight(), 611 'z-index': 100 612 }); 613 614 615 if(!html) { 616 div.html('<p>' + Odf.lang('no_results_found') + '</p>'); 617 } 618 else { 619 // Parse JSON. 620 var json = $.parseJSON(html); 621 console.log(json); 622 } 623 624 // Make sure focus isn't lost, which is/was somehow happening. 625 self.focus(); 626 } 627 }); 628 }); 629 }); 630 } 631 632 }, 633 634 635 /*********************************************************************** 636 Language functions. 637 */ 638 639 /* 640 Returns the translation with the given key. 641 642 @param str key 643 The key for which to return the translation. 644 */ 645 translate: function(key) { 646 var language = Odf.get('language'); 647 648 if(odf_translations[language][key]) { 649 return odf_translations[language][key]; 650 } 651 else { 652 console.log('No translation found for key ' + key + ' in language ' + language + '.'); 653 return false; 654 } 655 }, 656 657 658 /*********************************************************************** 659 Utility functions 660 */ 661 662 utility: {}, 663 664 665 /*********************************************************************** 666 Other/general functionalities 667 */ 668 669 670 /* 671 Creates a loading overlay in the ODF selection (Odf(selector)). 672 */ 673 createLoadingOverlay: function() { 674 var selection = Odf.selection; 675 if(!selection.length) { 676 console.log('Error: no selection.'); 677 return false; 678 } 679 680 selection = selection.first(); 681 682 var div = $('<div></div>'); 683 div.prependTo(selection); 684 div.addClass('odf_loading_overlay'); 685 div.css({ 686 position: 'absolute', 687 width: selection.innerWidth(), 688 height: selection.innerHeight(), 689 'background-color': '#000', 690 opacity: 0.33, 691 '-moz-opacity': 0.33 692 }); 693 694 var loading_image = $('<img src="' + Odf.get('loading_image_black_bg_big') + '" class="odf_loading_image">'); 695 loading_image.prependTo(div); 696 loading_image.css({ 697 position: 'absolute', 698 top: (div.outerHeight() / 2) - (loading_image.height() / 2), 699 left: (div.outerWidth() / 2) - (loading_image.width() / 2) 700 }); 701 }, 702 703 /* 704 Removes the loading overlay from the ODF selection (Odf(selector)). 705 */ 706 removeLoadingOverlay: function() { 707 var selection = Odf.selection; 708 if(!selection.length) { 709 console.log('Error: no selection.'); 710 return false; 711 } 712 713 selection = selection.first(); 714 selection.find('div.odf_loading_overlay').remove(); 715 }, 716 717 /* 718 Sets the text cursor position or creates a selection range. 719 720 @this 721 The element in which the range is to be created. 722 */ 723 setTextCursorPosition: function(start_position, end_position) { 724 self = $(this); 725 726 if(!self) 727 return false;
728 729 if(self.createTextRange) { 730 var textRange = self.createTextRange(); 731 textRange.collapse(true); 732 textRange.moveStart(start_position); 733 textRange.moveEnd(end_position); 734 textRange.select(); 735 return true; 736 } 737 else if(self.setSelectionRange) { 738 self.setSelectionRange(start_position, end_position); 739 return true; 740 } 741 742 return false; 743 }, 744 745 /* 746 Checks if the number of characters that are being typed in an element do not 747 exceed the maximum number of allowed characters. 748 749 @this 750 The element in which is being typed. 751 @param int max_length 752 The maximum number of characters that may be typed in the element. 753 */ 754 checkLength: function(max_length) { 755 var self = $(this), // The textarea that was typed in. 756 length = self.val().length; 757 758 if(length >= max_length) { 759 self.val(self.val().substr(0, max_length)); 760 $('#textarea_length').html('2000 / ' + max_length); 761 return false; 762 } 763 764 $('#textarea_length').html(length + ' / ' + max_length); 765 } 766 }; 767 768 // Make sure the prototype's functions are also directly available. 769 for(var key in Odf.prototype) { 770 Odf[key] = Odf.prototype[key]; 771 } 772 773 // Make sure the Odf prototype's functions are available to the object that is returned when 774 // the Odf() function is called. 775 Odf.prototype.select.prototype = Odf.prototype; 776 777 778 // Make the Odf library globally available. 779 window.Odf = Odf; 780 781})(window, jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.