SHARE
TWEET

Untitled

a guest Jun 25th, 2014 13 Never
  1. /**
  2.  * jQuery plugin for getting position of cursor in textarea
  3.  
  4.  * @license under Apache license
  5.  * @author Bevis Zhao (i@bevis.me, http://bevis.me)
  6.  */
  7.  
  8. (function($, window, document, undefined) {
  9.         $(function() {
  10.                 var calculator = {
  11.                         // key styles
  12.                         primaryStyles: ['fontFamily', 'fontSize', 'fontWeight', 'fontVariant', 'fontStyle',
  13.                                 'paddingLeft', 'paddingTop', 'paddingBottom', 'paddingRight',
  14.                                 'marginLeft', 'marginTop', 'marginBottom', 'marginRight',
  15.                                 'borderLeftColor', 'borderTopColor', 'borderBottomColor', 'borderRightColor',
  16.                                 'borderLeftStyle', 'borderTopStyle', 'borderBottomStyle', 'borderRightStyle',
  17.                                 'borderLeftWidth', 'borderTopWidth', 'borderBottomWidth', 'borderRightWidth',
  18.                                 'line-height', 'outline'],
  19.  
  20.                         specificStyle: {
  21.                                 'word-wrap': 'break-word',
  22.                                 'overflow-x': 'hidden',
  23.                                 'overflow-y': 'auto'
  24.                         },
  25.  
  26.                         simulator : $('<div id="textarea_simulator" contenteditable="true"/>').css({
  27.                                 position: 'absolute',
  28.                                 top: 0,
  29.                                 left: 0,
  30.                                 visibility: 'hidden'
  31.                         }).appendTo(document.body),
  32.  
  33.                         toHtml : function(text) {
  34.                                 return text.replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\n/g, '<br>')
  35.                                         .replace(/(\s)/g,'<span style="white-space:pre-wrap;">$1</span>');
  36.                         },
  37.                         // calculate position
  38.                         getCaretPosition: function() {
  39.                                 var cal = calculator, self = this, element = self[0], elementOffset = self.offset();
  40.  
  41.                                 // IE has easy way to get caret offset position
  42.                                 if ($.browser.msie) {
  43.                                         // must get focus first
  44.                                         element.focus();
  45.                                         var range = document.selection.createRange();
  46.                                         return {
  47.                                                 left: range.boundingLeft - elementOffset.left,
  48.                                                 top: parseInt(range.boundingTop) - elementOffset.top + element.scrollTop
  49.                                                         + document.documentElement.scrollTop + parseInt(self.getComputedStyle("fontSize"))
  50.                                         };
  51.                                 }
  52.                                 cal.simulator.empty();
  53.                                 // clone primary styles to imitate textarea
  54.                                 $.each(cal.primaryStyles, function(index, styleName) {
  55.                                         self.cloneStyle(cal.simulator, styleName);
  56.                                 });
  57.  
  58.                                 // caculate width and height
  59.                                 cal.simulator.css($.extend({
  60.                                         'width': self.width(),
  61.                                         'height': self.height()
  62.                                 }, cal.specificStyle));
  63.  
  64.                                 var value = self.val(), cursorPosition = self.getCursorPosition();
  65.                                 var beforeText = value.substring(0, cursorPosition),
  66.                                         afterText = value.substring(cursorPosition);
  67.  
  68.                                 var before = $('<span class="before"/>').html(cal.toHtml(beforeText)),
  69.                                         focus = $('<span class="focus"/>'),
  70.                                         after = $('<span class="after"/>').html(cal.toHtml(afterText));
  71.  
  72.                                 cal.simulator.append(before).append(focus).append(after);
  73.                                 var focusOffset = focus.offset(), simulatorOffset = cal.simulator.offset();
  74.                                 // alert(focusOffset.left  + ',' +  simulatorOffset.left + ',' + element.scrollLeft);
  75.                                 return {
  76.                                         top: focusOffset.top - simulatorOffset.top - element.scrollTop
  77.                                                 // calculate and add the font height except Firefox
  78.                                                 + ($.browser.mozilla ? 0 : parseInt(self.getComputedStyle("fontSize"))),
  79.                                         left: focus[0].offsetLeft -  cal.simulator[0].offsetLeft - element.scrollLeft
  80.                                 };
  81.                         }
  82.                 };
  83.  
  84.                 $.fn.extend({
  85.                         getComputedStyle: function(styleName) {
  86.                                 if (this.length == 0) return;
  87.                                 var thiz = this[0];
  88.                                 var result = this.css(styleName);
  89.                                 result = result || ($.browser.msie ?
  90.                                         thiz.currentStyle[styleName]:
  91.                                         document.defaultView.getComputedStyle(thiz, null)[styleName]);
  92.                                 return result;
  93.                         },
  94.                         // easy clone method
  95.                         cloneStyle: function(target, styleName) {
  96.                                 var styleVal = this.getComputedStyle(styleName);
  97.                                 if (!!styleVal) {
  98.                                         $(target).css(styleName, styleVal);
  99.                                 }
  100.                         },
  101.                         cloneAllStyle: function(target, style) {
  102.                                 var thiz = this[0];
  103.                                 for (var styleName in thiz.style) {
  104.                                         var val = thiz.style[styleName];
  105.                                         typeof val == 'string' || typeof val == 'number'
  106.                                                 ? this.cloneStyle(target, styleName)
  107.                                                 : NaN;
  108.                                 }
  109.                         },
  110.                         getCursorPosition : function() {
  111.                                 var thiz = this[0], result = 0;
  112.                                 if ('selectionStart' in thiz) {
  113.                                         result = thiz.selectionStart;
  114.                                 } else if('selection' in document) {
  115.                                         var range = document.selection.createRange();
  116.                                         if (parseInt($.browser.version) > 6) {
  117.                                                 thiz.focus();
  118.                                                 var length = document.selection.createRange().text.length;
  119.                                                 range.moveStart('character', - thiz.value.length);
  120.                                                 result = range.text.length - length;
  121.                                         } else {
  122.                                                 var bodyRange = document.body.createTextRange();
  123.                                                 bodyRange.moveToElementText(thiz);
  124.                                                 for (; bodyRange.compareEndPoints("StartToStart", range) < 0; result++)
  125.                                                         bodyRange.moveStart('character', 1);
  126.                                                 for (var i = 0; i <= result; i ++){
  127.                                                         if (thiz.value.charAt(i) == '\n')
  128.                                                                 result++;
  129.                                                 }
  130.                                                 var enterCount = thiz.value.split('\n').length - 1;
  131.                                                 result -= enterCount;
  132.                                                 return result;
  133.                                         }
  134.                                 }
  135.                                 return result;
  136.                         },
  137.                         getCaretPosition: calculator.getCaretPosition
  138.                 });
  139.         });
  140. })(jQuery, window, document);
  141.  
  142. /*
  143.  * AUTOSUGGEST 2.0
  144.  */
  145. AutoSuggest = {
  146.         timerId: 0,
  147.         ul: undefined,
  148.         cachedString: '', // if last string is the same string as the word to match
  149.         cachedField: '', // if last field is the same as current field, e.g. only caretmovement
  150.         locale: '', // language for Ajax
  151.        
  152.         init: function(){
  153.                 // Get current language from the page
  154.                 var ej = jQuery(".lang-select").find("a");
  155.                 if(ej.eq(0).hasClass("active")){ // if english
  156.                         AutoSuggest.locale = "en";
  157.                 }
  158.                 else{
  159.                         AutoSuggest.locale = "ja";
  160.                 }
  161.        
  162.                 // Create hidden suggestion ul box and append it to the body
  163.                 jQuery(document.body).append('<ul id="autosuggest"></ul>');
  164.                 AutoSuggest.ul = jQuery("#autosuggest");
  165.                 AutoSuggest.ul.mouseover(function(e){
  166.                         if($('focussedLi')){
  167.                                 $(focussedLi).removeAttribute('id');
  168.                         }
  169.                 });
  170.                
  171.                 // Get all Elements where it should be applied on
  172.                 var tagfields = jQuery(".autosuggest, #post_tags, #tags");
  173.                
  174.                 tagfields.each(function(index, tagfield){ // for all tagfields
  175.                         AutoSuggest.add(tagfield);
  176.                 });
  177.         },
  178.        
  179.         add: function(tagfield){
  180.                 tagfield = jQuery(tagfield);
  181.                 tagfield.blur(function(){
  182.                         setTimeout(function(){
  183.                                 AutoSuggest.ul.hide()
  184.                         }, 500);
  185.                 });
  186.                 tagfield.attr("autocomplete", "off");
  187.                
  188.                 tagfield.keyup(function(e){
  189.                         var tagfield = this;
  190.                         var tf = false;
  191.                         if(tagfield.tagName === 'INPUT'){
  192.                                 tf = e.keyCode !== Event.KEY_UP && e.keyCode !== Event.KEY_DOWN && e.keyCode !== Event.KEY_PAGEUP && e.keyCode !== Event.KEY_PAGEDOWN;
  193.                         }
  194.                         else if(tagfield.tagName === 'TEXTAREA'){
  195.                                 tf = e.keyCode !== Event.KEY_PAGEUP && e.keyCode !== Event.KEY_PAGEDOWN;
  196.                         }
  197.                
  198.                         if(tf){ // if not up or down key and or not pagedown or pageup
  199.                                 var pos = AutoSuggest.getWordStartAndEnd(this);
  200.                                 var wordToMatch = this.value.substring(pos['start'], pos['end']);
  201.                                 var cachedString = AutoSuggest.cachedString;
  202.                                 var cachedField = AutoSuggest.cachedField;
  203.                                 if(wordToMatch !== cachedString && tagfield.value !== cachedField && wordToMatch !== ''){
  204.                                         clearTimeout(AutoSuggest.timerId);
  205.                                         timerId = setTimeout(function(){
  206.                                                 AutoSuggest.sendTagSuggestRequest(wordToMatch, tagfield);
  207.                                         }, 380);
  208.                                 }
  209.                                 else{
  210.                                         AutoSuggest.ul.html('').hide();
  211.                                 }
  212.                                 AutoSuggest.cachedString = wordToMatch;
  213.                                 AutoSuggest.cachedField = tagfield.value;
  214.                                 console.log(cachedString + " !== " + wordToMatch);
  215.                         }
  216.                 });
  217.                
  218.                 tagfield.keydown(function(e){
  219.                         var tagfield = this;
  220.                         if(e.keyCode === Event.KEY_RETURN && AutoSuggest.ul.children().length > 0){
  221.                                 AutoSuggest.addLiAsText($('focussedLi'), tagfield);
  222.                                 e.preventDefault();
  223.                         }
  224.                         if(AutoSuggest.ul.is(":visible")){
  225.                                 var lis = AutoSuggest.ul.find("li");
  226.                                 var cur = -1;
  227.                                 for(var i = 0; i < lis.length; i++){
  228.                                         if(lis[i].id && lis[i].id === 'focussedLi'){
  229.                                                 cur = i;
  230.                                                 lis[i].removeAttribute('id');
  231.                                                 break;
  232.                                         }
  233.                                 }
  234.                                
  235.                                 if(e.keyCode === Event.KEY_PAGEUP || (e.keyCode === Event.KEY_UP && tagfield.tagName === 'INPUT')){
  236.                                         if(cur > 0){
  237.                                                 lis[cur-1].id = 'focussedLi';
  238.                                         }
  239.                                         else{
  240.                                                 lis[lis.length-1].id = 'focussedLi';
  241.                                         }
  242.                                         e.preventDefault();
  243.                                 }
  244.                                 else if(e.keyCode === Event.KEY_PAGEDOWN || (e.keyCode === Event.KEY_DOWN && tagfield.tagName === 'INPUT')){
  245.                                         if(cur < lis.length - 1 && cur >= 0){
  246.                                                 lis[cur+1].id = 'focussedLi';
  247.                                         }
  248.                                         else{
  249.                                                 lis[0].id = 'focussedLi';
  250.                                         }
  251.                                         e.preventDefault();
  252.                                 }
  253.                         }
  254.                 });
  255.         },
  256.        
  257.         getWordStartAndEnd: function(inp){
  258.                 var rtrn = {
  259.                         'start': 0,
  260.                         'end': 0,
  261.                 };
  262.                 offsetStart = false;
  263.                 orStart = AutoSuggest.doGetCaretPosition(inp);
  264.                 while(orStart > 0 && inp.value[orStart - 1] !== ' '){
  265.                         orStart--;
  266.                 }
  267.                 rtrn['start'] = orStart;
  268.                 rtrn['end'] = rtrn['start'];
  269.                 while(inp.value[rtrn['end']] !== ' ' && rtrn['end'] <= inp.value.length){
  270.                         rtrn['end']++;
  271.                 }
  272.                 return rtrn;
  273.         },
  274.        
  275.         doGetCaretPosition: function(oField){
  276.                 var iCaretPos = 0;
  277.                 if(document.selection){
  278.                         oField.focus();
  279.                         var oSel = document.selection.createRange();
  280.                         oSel.moveStart('character', - oField.value.length);
  281.                         iCaretPos = oSel.text.length;
  282.                 }
  283.                 else if(oField.selectionStart || oField.selectionStart === '0'){
  284.                         iCaretPos = oField.selectionStart;
  285.                 }
  286.                 return iCaretPos;
  287.         },
  288.        
  289.         sendTagSuggestRequest: function(wordToMatch, tagfield){
  290.                 var locale;
  291.                 if($('locale')){ // if undefined
  292.                         $('locale').readAttribute('rel');
  293.                 }
  294.                 else{
  295.                         locale = AutoSuggest.locale;
  296.                 }
  297.                 new Ajax.Request('http://chan.sankakucomplex.com/tag/autosuggest?tag=' + wordToMatch + '&locale=' + locale, {
  298.                         method: 'get',
  299.                         onSuccess: function(transport){
  300.                                 AutoSuggest.displayResults(transport.responseText || "{}", tagfield);
  301.                         },
  302.                         onFailure: function() {
  303.                                 console.log("Ajax tag-suggest failure");
  304.                         }
  305.                 });
  306.         },
  307.        
  308.         displayResults: function(results, tagfield){
  309.                 // Get tagfield position + caret position if Textarea
  310.                 var left = 0;
  311.                 var top = 0;
  312.                 var offset = 10;
  313.                 var jtagfield = jQuery(tagfield);
  314.                 if(tagfield.tagName === 'INPUT'){
  315.                         top = jtagfield.offset().top + jtagfield.height() + offset;
  316.                         left = jtagfield.offset().left;
  317.                 }
  318.                 else if(tagfield.tagName === 'TEXTAREA'){
  319.                         var caret = jtagfield.getCaretPosition();
  320.                         top = jtagfield.offset().top + caret.top + offset;
  321.                         left = jtagfield.offset().left + caret.left;
  322.                 }
  323.                 AutoSuggest.ul.html('').css({
  324.                         "top": top + "px",
  325.                         "left": left + "px",
  326.                 });
  327.                
  328.                 var res = eval('(' + results + ')');
  329.                 var pos = AutoSuggest.getWordStartAndEnd(tagfield);
  330.                 var wordToMatch = tagfield.value.substring(pos['start'], pos['end']);
  331.                 if(res[1] && res[0] === wordToMatch){
  332.                         if(res[1].length > 0) {
  333.                                 for(var i = 0; i < res[1].length; i++){
  334.                                         var li = new Element('li');
  335.                                         li.appendChild(new Element('span').update(res[1][i]));
  336.                                         if(res[i+2]){
  337.                                                 li.appendChild(new Element('span').update(res[i+2]));
  338.                                         }
  339.                                         li.appendChild(document.createElement('br'));
  340.                                         li.observe('click', function(e){
  341.                                                 AutoSuggest.addLiAsText(this, tagfield);
  342.                                                 e.preventDefault();
  343.                                         });
  344.                                         AutoSuggest.ul.append(jQuery(li));
  345.                                 }
  346.                                 AutoSuggest.ul.show();
  347.                                
  348.                                 // add PUPD note
  349.                                 if(tagfield.tagName === 'TEXTAREA'){
  350.                                         AutoSuggest.ul.append('<div id="autosuggestPUPD">^ Pg Up / Pg Down v</div>');
  351.                                 }
  352.                         }
  353.                         else{
  354.                                 AutoSuggest.ul.hide();
  355.                         }
  356.                 }
  357.         },
  358.        
  359.         addLiAsText: function(li, srch){
  360.                 var str = li.firstDescendant().firstChild.nodeValue;
  361.                 var pos = AutoSuggest.getWordStartAndEnd(srch);
  362.                 var prefix = srch.value.substring(0, pos['start']);
  363.                 var postfix = srch.value.substring(pos['end']);
  364.                 srch.value = prefix + str + postfix;
  365.                 srch.focus();
  366.                 AutoSuggest.cachedString = str;
  367.                 AutoSuggest.setCaretToPos(srch, prefix.length+str.length);
  368.                
  369.                 if(srch.createTextRange){
  370.                         var range = srch.createTextRange();
  371.                         range.collapse(true);
  372.                         range.moveEnd('character', srch.value.length);
  373.                         range.moveStart('character', srch.value.length);
  374.                         range.select();
  375.                 }
  376.                 AutoSuggest.ul.html('').hide();
  377.         },
  378.        
  379.         setCaretToPos:function(input, pos) {
  380.           AutoSuggest.setSelectionRange(input, pos, pos);
  381.         },
  382.        
  383.         setSelectionRange: function(input, selectionStart, selectionEnd) {
  384.           if (input.setSelectionRange) {
  385.                 input.focus();
  386.                 input.setSelectionRange(selectionStart, selectionEnd);
  387.           }
  388.           else if (input.createTextRange) {
  389.                 var range = input.createTextRange();
  390.                 range.collapse(true);
  391.                 range.moveEnd('character', selectionEnd);
  392.                 range.moveStart('character', selectionStart);
  393.                 range.select();
  394.           }
  395.         },
  396.  
  397. };
  398.  
  399. jQuery(document).ready(function(){
  400.         AutoSuggest.init();
  401. });
RAW Paste Data
Top