164 |
165 |
166 |
167 |
178 |
179 |
180 |
--------------------------------------------------------------------------------
/indextest.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
54 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
*চা Script is totally depended on the grammar of ECMA Script which is parsed using Jison
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
Easy to Learn
104 |
চা Script was designed as a learning platform for computer programming. It can be a stepping stone for people to learn how to code but thinks language can be a barrier for them to learn something new and that is why we developed চা Script, a বাংলা scripting language with well documentation and tutorials.
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
Easy to Code
113 |
চা Script contains primitive and easy syntax definitions. No need for type declaration. No need for semicolons. An integrated coding enviroment is provided with keyword buttons for the ease of writing codes.
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
No Installation Required
122 |
চা Script do not need any kind of installation process. It is a fully web based scripting language which can also be used in offline mode if the files are downloaded in the local server/pc.However, we encourage users to download Avro Keyboard to write বাংলা.
123 |
124 |
125 |
126 |
127 |
144 |
145 |
146 |
147 |
148 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
--------------------------------------------------------------------------------
/jquery-linedtextarea.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
JQuery LinedTextArea Demo
4 |
5 |
6 |
7 |
8 |
9 |
10 |
JQuery LinedTextArea Demo
11 |
12 |
Add a scrollable lined area to a standard TextArea control.
13 |
14 |
34 |
35 |
42 |
43 |
Visit http://alan.blog-city.com/jquerylinedtextarea.htm for details and download
44 |
45 |
46 |
--------------------------------------------------------------------------------
/js/base64.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * Base64 encode / decode
4 | * http://www.webtoolkit.info/
5 | *
6 | **/
7 |
8 | var Base64 = {
9 |
10 | // private property
11 | _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
12 |
13 | // public method for encoding
14 | encode : function (input) {
15 | var output = "";
16 | var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
17 | var i = 0;
18 |
19 | input = Base64._utf8_encode(input);
20 |
21 | while (i < input.length) {
22 |
23 | chr1 = input.charCodeAt(i++);
24 | chr2 = input.charCodeAt(i++);
25 | chr3 = input.charCodeAt(i++);
26 |
27 | enc1 = chr1 >> 2;
28 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
29 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
30 | enc4 = chr3 & 63;
31 |
32 | if (isNaN(chr2)) {
33 | enc3 = enc4 = 64;
34 | } else if (isNaN(chr3)) {
35 | enc4 = 64;
36 | }
37 |
38 | output = output +
39 | this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
40 | this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
41 |
42 | }
43 |
44 | return output;
45 | },
46 |
47 | // public method for decoding
48 | decode : function (input) {
49 | var output = "";
50 | var chr1, chr2, chr3;
51 | var enc1, enc2, enc3, enc4;
52 | var i = 0;
53 |
54 | input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
55 |
56 | while (i < input.length) {
57 |
58 | enc1 = this._keyStr.indexOf(input.charAt(i++));
59 | enc2 = this._keyStr.indexOf(input.charAt(i++));
60 | enc3 = this._keyStr.indexOf(input.charAt(i++));
61 | enc4 = this._keyStr.indexOf(input.charAt(i++));
62 |
63 | chr1 = (enc1 << 2) | (enc2 >> 4);
64 | chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
65 | chr3 = ((enc3 & 3) << 6) | enc4;
66 |
67 | output = output + String.fromCharCode(chr1);
68 |
69 | if (enc3 != 64) {
70 | output = output + String.fromCharCode(chr2);
71 | }
72 | if (enc4 != 64) {
73 | output = output + String.fromCharCode(chr3);
74 | }
75 |
76 | }
77 |
78 | output = Base64._utf8_decode(output);
79 |
80 | return output;
81 |
82 | },
83 |
84 | // private method for UTF-8 encoding
85 | _utf8_encode : function (string) {
86 | string = string.replace(/\r\n/g,"\n");
87 | var utftext = "";
88 |
89 | for (var n = 0; n < string.length; n++) {
90 |
91 | var c = string.charCodeAt(n);
92 |
93 | if (c < 128) {
94 | utftext += String.fromCharCode(c);
95 | }
96 | else if((c > 127) && (c < 2048)) {
97 | utftext += String.fromCharCode((c >> 6) | 192);
98 | utftext += String.fromCharCode((c & 63) | 128);
99 | }
100 | else {
101 | utftext += String.fromCharCode((c >> 12) | 224);
102 | utftext += String.fromCharCode(((c >> 6) & 63) | 128);
103 | utftext += String.fromCharCode((c & 63) | 128);
104 | }
105 |
106 | }
107 |
108 | return utftext;
109 | },
110 |
111 | // private method for UTF-8 decoding
112 | _utf8_decode : function (utftext) {
113 | var string = "";
114 | var i = 0;
115 | var c = c1 = c2 = 0;
116 |
117 | while ( i < utftext.length ) {
118 |
119 | c = utftext.charCodeAt(i);
120 |
121 | if (c < 128) {
122 | string += String.fromCharCode(c);
123 | i++;
124 | }
125 | else if((c > 191) && (c < 224)) {
126 | c2 = utftext.charCodeAt(i+1);
127 | string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
128 | i += 2;
129 | }
130 | else {
131 | c2 = utftext.charCodeAt(i+1);
132 | c3 = utftext.charCodeAt(i+2);
133 | string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
134 | i += 3;
135 | }
136 |
137 | }
138 |
139 | return string;
140 | }
141 |
142 | }
--------------------------------------------------------------------------------
/js/formState.js:
--------------------------------------------------------------------------------
1 | /*
2 | Form State v 1.2
3 | copyright 2007 Thomas Frank
4 |
5 | This program is free software under the terms of the
6 | GNU General Public License version 2 as published by the Free
7 | Software Foundation. It is distributed without any warranty.
8 | */
9 | formState={
10 | eventsBeforeStore:true,
11 | onStateChange:false,
12 | init:function(){
13 | // add to onload
14 | if(!formState.onloadAdded){
15 | formState.onloadAdded=true;
16 | (function(){var ol=onload;onload=function(){if(ol){ol()};formState.init()}})();
17 | return
18 | };
19 | // modify/create event handlers on all form elements
20 | var f=document.forms
21 | for(var i=0;i
=0;
24 | f[i].id=f[i].id.replace(/_undoable/,'').replace(/_keystroke/,'');
25 | var e=f[i].elements;
26 | for(var j=0;jf.formStateCo){f.formStateMem.pop()};
60 | f.formStateMem[f.formStateCo]=a;
61 | this.checkQueue(f)
62 | },
63 | readBack:function(f,a){
64 | // read back values to form and check if different
65 | var fe=f.elements, ae=a.elements, d=false;
66 | for(var i=0;i1;
81 | var redoable=f.formStateMem.length-f.formStateCo>1;
82 | if(f.elements.Undo){f.elements.Undo.disabled=!undoable};
83 | if(f.elements.Redo){f.elements.Redo.disabled=!redoable};
84 | if(this.onStateChange){this.onStateChange(f,undoable,redoable)}
85 | },
86 | undo:function(a,r){
87 | if(!r){r=-1};
88 | var tN=a.tagName.toLowerCase()||"";
89 | if(a.parentNode && tN!="form"){a=a.parentNode;return this.undo(a,r)};
90 | if(!a.formStateMem){return false};
91 | var f=a.formStateMem[a.formStateCo+r];
92 | if(!f){return false};
93 | a.formStateCo+=r;
94 | if(!this.readBack(f,a)){return this.undo(a,r)};
95 | this.checkQueue(a);
96 | return true
97 | },
98 | redo:function(a){return this.undo(a,1)}
99 | };
100 | formState.init();
--------------------------------------------------------------------------------
/js/jquery-linedtextarea.js:
--------------------------------------------------------------------------------
1 | /**
2 | * jQuery Lined Textarea Plugin
3 | * http://alan.blog-city.com/jquerylinedtextarea.htm
4 | *
5 | * Copyright (c) 2010 Alan Williamson
6 | *
7 | * Version:
8 | * $Id: jquery-linedtextarea.js 464 2010-01-08 10:36:33Z alan $
9 | *
10 | * Released under the MIT License:
11 | * http://www.opensource.org/licenses/mit-license.php
12 | *
13 | * Usage:
14 | * Displays a line number count column to the left of the textarea
15 | *
16 | * Class up your textarea with a given class, or target it directly
17 | * with JQuery Selectors
18 | *
19 | * $(".lined").linedtextarea({
20 | * selectedLine: 10,
21 | * selectedClass: 'lineselect'
22 | * });
23 | *
24 | * History:
25 | * - 2010.01.08: Fixed a Google Chrome layout problem
26 | * - 2010.01.07: Refactored code for speed/readability; Fixed horizontal sizing
27 | * - 2010.01.06: Initial Release
28 | *
29 | */
30 | (function($) {
31 |
32 | $.fn.linedtextarea = function(options) {
33 |
34 | // Get the Options
35 | var opts = $.extend({}, $.fn.linedtextarea.defaults, options);
36 |
37 |
38 | /*
39 | * Helper function to make sure the line numbers are always
40 | * kept up to the current system
41 | */
42 | var fillOutLines = function(codeLines, h, lineNo){
43 | while ( (codeLines.height() - h ) <= 0 ){
44 | if ( lineNo == opts.selectedLine )
45 | codeLines.append("" + lineNo + "
");
46 | else
47 | codeLines.append("" + lineNo + "
");
48 |
49 | lineNo++;
50 | }
51 | return lineNo;
52 | };
53 |
54 |
55 | /*
56 | * Iterate through each of the elements are to be applied to
57 | */
58 | return this.each(function() {
59 | var lineNo = 1;
60 | var textarea = $(this);
61 |
62 | /* Turn off the wrapping of as we don't want to screw up the line numbers */
63 | textarea.attr("wrap", "off");
64 | textarea.css({resize:'none'});
65 | var originalTextAreaWidth = textarea.outerWidth();
66 |
67 | /* Wrap the text area in the elements we need */
68 | textarea.wrap("
");
69 | var linedTextAreaDiv = textarea.parent().wrap("
");
70 | var linedWrapDiv = linedTextAreaDiv.parent();
71 |
72 | linedWrapDiv.prepend("
");
73 |
74 | var linesDiv = linedWrapDiv.find(".lines");
75 | linesDiv.height( textarea.height() + 6 );
76 |
77 |
78 | /* Draw the number bar; filling it out where necessary */
79 | linesDiv.append( "
" );
80 | var codeLinesDiv = linesDiv.find(".codelines");
81 | lineNo = fillOutLines( codeLinesDiv, linesDiv.height(), 1 );
82 |
83 | /* Move the textarea to the selected line */
84 | if ( opts.selectedLine != -1 && !isNaN(opts.selectedLine) ){
85 | var fontSize = parseInt( textarea.height() / (lineNo-2) );
86 | var position = parseInt( fontSize * opts.selectedLine ) - (textarea.height()/2);
87 | textarea[0].scrollTop = position;
88 | }
89 |
90 |
91 | /* Set the width */
92 | var sidebarWidth = linesDiv.outerWidth();
93 | var paddingHorizontal = parseInt( linedWrapDiv.css("border-left-width") ) + parseInt( linedWrapDiv.css("border-right-width") ) + parseInt( linedWrapDiv.css("padding-left") ) + parseInt( linedWrapDiv.css("padding-right") );
94 | var linedWrapDivNewWidth = originalTextAreaWidth - paddingHorizontal;
95 | var textareaNewWidth = originalTextAreaWidth - sidebarWidth - paddingHorizontal - 20;
96 |
97 | textarea.width( textareaNewWidth );
98 | linedWrapDiv.width( linedWrapDivNewWidth );
99 |
100 |
101 |
102 | /* React to the scroll event */
103 | textarea.scroll( function(tn){
104 | var domTextArea = $(this)[0];
105 | var scrollTop = domTextArea.scrollTop;
106 | var clientHeight = domTextArea.clientHeight;
107 | codeLinesDiv.css( {'margin-top': (-1*scrollTop) + "px"} );
108 | lineNo = fillOutLines( codeLinesDiv, scrollTop + clientHeight, lineNo );
109 | });
110 |
111 |
112 | /* Should the textarea get resized outside of our control */
113 | textarea.resize( function(tn){
114 | var domTextArea = $(this)[0];
115 | linesDiv.height( domTextArea.clientHeight + 6 );
116 | });
117 |
118 | });
119 | };
120 |
121 | // default options
122 | $.fn.linedtextarea.defaults = {
123 | selectedLine: -1,
124 | selectedClass: 'lineselect'
125 | };
126 | })(jQuery);
--------------------------------------------------------------------------------
/js/jquery.a-tools-1.4.1.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * a-tools 1.4.1
3 | *
4 | * Copyright (c) 2009 Andrey Kramarev(andrey.kramarev[at]ampparit.com), Ampparit Inc. (www.ampparit.com)
5 | * Licensed under the MIT license.
6 | * http://www.ampparit.fi/a-tools/license.txt
7 | *
8 | * Basic usage:
9 |
10 |
11 |
12 |
13 | // Get current selection
14 | var sel = $("textarea").getSelection()
15 |
16 | // Replace current selection
17 | $("input").replaceSelection("foo");
18 |
19 | // Count characters
20 | alert($("textarea").countCharacters());
21 |
22 | // Set max length without callback function
23 | $("textarea").setMaxLength(7);
24 |
25 | // Set max length with callback function which will be called when limit is exceeded
26 | $("textarea").setMaxLength(10, function() {
27 | alert("hello")
28 | });
29 |
30 | // Removing limit:
31 | $("textarea").setMaxLength(-1);
32 |
33 | // Insert text at current caret position
34 | $("#textarea").insertAtCaretPos("hello");
35 |
36 | // Set caret position (1 = beginning, -1 = end)
37 | $("#textArea").setCaretPos(10);
38 |
39 | // Set Selection
40 | $("#textArea").setSelection(10,15);
41 |
42 | */
43 | var caretPositionAmp;
44 |
45 | jQuery.fn.extend({
46 | getSelection: function() { // function for getting selection, and position of the selected text
47 | var input = this.jquery ? this[0] : this;
48 | var start;
49 | var end;
50 | var part;
51 | var number = 0;
52 | input.onmousedown = function() { // for IE because it loses caret position when focus changed
53 | if (document.selection && typeof(input.selectionStart) != "number") {
54 | document.selection.empty();
55 | } else {
56 | window.getSelection().removeAllRanges();
57 | }
58 | }
59 | if (document.selection) {
60 | // part for IE and Opera
61 | var s = document.selection.createRange();
62 | var minus = 0;
63 | var position = 0;
64 | var minusEnd = 0;
65 | var re;
66 | var rc;
67 | if (input.value.match(/\n/g) != null) {
68 | number = input.value.match(/\n/g).length;// number of EOL simbols
69 | }
70 | if (s.text) {
71 | part = s.text;
72 | // OPERA support
73 | if (typeof(input.selectionStart) == "number") {
74 | start = input.selectionStart;
75 | end = input.selectionEnd;
76 | // return null if the selected text not from the needed area
77 | if (start == end) {
78 | return { start: start, end: end, text: s.text, length: end - start };
79 | }
80 | } else {
81 | // IE support
82 | var firstRe;
83 | var secondRe;
84 | re = input.createTextRange();
85 | rc = re.duplicate();
86 | firstRe = re.text;
87 | re.moveToBookmark(s.getBookmark());
88 | secondRe = re.text;
89 | rc.setEndPoint("EndToStart", re);
90 | // return null if the selectyed text not from the needed area
91 | if (firstRe == secondRe && firstRe != s.text) {
92 | return this;
93 | }
94 | start = rc.text.length;
95 | end = rc.text.length + s.text.length;
96 | }
97 | // remove all EOL to have the same start and end positons as in MOZILLA
98 | if (number > 0) {
99 | for (var i = 0; i <= number; i++) {
100 | var w = input.value.indexOf("\n", position);
101 | if (w != -1 && w < start) {
102 | position = w + 1;
103 | minus++;
104 | minusEnd = minus;
105 | } else if (w != -1 && w >= start && w <= end) {
106 | if (w == start + 1) {
107 | minus--;
108 | minusEnd--;
109 | position = w + 1;
110 | continue;
111 | }
112 | position = w + 1;
113 | minusEnd++;
114 | } else {
115 | i = number;
116 | }
117 | }
118 | }
119 | if (s.text.indexOf("\n", 0) == 1) {
120 | minusEnd = minusEnd + 2;
121 | }
122 | start = start - minus;
123 | end = end - minusEnd;
124 |
125 | return { start: start, end: end, text: s.text, length: end - start };
126 | }
127 | input.focus ();
128 | if (typeof(input.selectionStart) == "number") {
129 | start = input.selectionStart;
130 | } else {
131 | s = document.selection.createRange();
132 | re = input.createTextRange();
133 | rc = re.duplicate();
134 | re.moveToBookmark(s.getBookmark());
135 | rc.setEndPoint("EndToStart", re);
136 | start = rc.text.length;
137 | }
138 | if (number > 0) {
139 | for (var i = 0; i <= number; i++) {
140 | var w = input.value.indexOf("\n", position);
141 | if (w != -1 && w < start) {
142 | position = w + 1;
143 | minus++;
144 | } else {
145 | i = number;
146 | }
147 | }
148 | }
149 | start = start - minus;
150 | return { start: start, end: start, text: s.text, length: 0 };
151 | } else if (typeof(input.selectionStart) == "number" ) {
152 | start = input.selectionStart;
153 | end = input.selectionEnd;
154 | part = input.value.substring(input.selectionStart, input.selectionEnd);
155 | return { start: start, end: end, text: part, length: end - start };
156 | } else { return { start: undefined, end: undefined, text: undefined, length: undefined }; }
157 | },
158 |
159 | // function for the replacement of the selected text
160 | replaceSelection: function(inputStr) {
161 | var input = this.jquery ? this[0] : this;
162 | //part for IE and Opera
163 | var start;
164 | var end;
165 | var position = 0;
166 | var rc;
167 | var re;
168 | var number = 0;
169 | var minus = 0;
170 | var mozScrollFix = ( input.scrollTop == undefined ) ? 0 : input.scrollTop;
171 | if (document.selection && typeof(input.selectionStart) != "number") {
172 | var s = document.selection.createRange();
173 |
174 | // IE support
175 | if (typeof(input.selectionStart) != "number") { // return null if the selected text not from the needed area
176 | var firstRe;
177 | var secondRe;
178 | re = input.createTextRange();
179 | rc = re.duplicate();
180 | firstRe = re.text;
181 | re.moveToBookmark(s.getBookmark());
182 | secondRe = re.text;
183 | rc.setEndPoint("EndToStart", re);
184 | if (firstRe == secondRe && firstRe != s.text) {
185 | return this;
186 | }
187 | }
188 | if (s.text) {
189 | part = s.text;
190 | if (input.value.match(/\n/g) != null) {
191 | number = input.value.match(/\n/g).length;// number of EOL simbols
192 | }
193 | // IE support
194 | start = rc.text.length;
195 | // remove all EOL to have the same start and end positons as in MOZILLA
196 | if (number > 0) {
197 | for (var i = 0; i <= number; i++) {
198 | var w = input.value.indexOf("\n", position);
199 | if (w != -1 && w < start) {
200 | position = w + 1;
201 | minus++;
202 |
203 | } else {
204 | i = number;
205 | }
206 | }
207 | }
208 | s.text = inputStr;
209 | caretPositionAmp = rc.text.length + inputStr.length;
210 | re.move("character", caretPositionAmp);
211 | document.selection.empty();
212 | input.blur();
213 | }
214 | return this;
215 | } else if (typeof(input.selectionStart) == "number" && // MOZILLA support
216 | input.selectionStart != input.selectionEnd) {
217 |
218 | start = input.selectionStart;
219 | end = input.selectionEnd;
220 | input.value = input.value.substr(0, start) + inputStr + input.value.substr(end);
221 | position = start + inputStr.length;
222 | input.setSelectionRange(position, position);
223 | input.scrollTop = mozScrollFix;
224 | return this;
225 | }
226 | return this;
227 | },
228 |
229 | //Set Selection in text
230 | setSelection: function(startPosition, endPosition) {
231 | startPosition = parseInt(startPosition);
232 | endPosition = parseInt(endPosition);
233 |
234 | var input = this.jquery ? this[0] : this;
235 | input.focus ();
236 | if (typeof(input.selectionStart) != "number") {
237 | re = input.createTextRange();
238 | if (re.text.length < endPosition) {
239 | endPosition = re.text.length+1;
240 | }
241 | }
242 | if (endPosition < startPosition) {
243 | return this;
244 | }
245 | if (document.selection) {
246 | var number = 0;
247 | var plus = 0;
248 | var position = 0;
249 | var plusEnd = 0;
250 | if (typeof(input.selectionStart) != "number") { // IE
251 | re.collapse(true);
252 | re.moveEnd('character', endPosition);
253 | re.moveStart('character', startPosition);
254 | re.select();
255 | return this;
256 | } else if (typeof(input.selectionStart) == "number") { // Opera
257 | if (input.value.match(/\n/g) != null) {
258 | number = input.value.match(/\n/g).length;// number of EOL simbols
259 | }
260 | if (number > 0) {
261 | for (var i = 0; i <= number; i++) {
262 | var w = input.value.indexOf("\n", position);
263 | if (w != -1 && w < startPosition) {
264 | position = w + 1;
265 | plus++;
266 | plusEnd = plus;
267 | } else if (w != -1 && w >= startPosition && w <= endPosition) {
268 | if (w == startPosition + 1) {
269 | plus--;
270 | plusEnd--;
271 | position = w + 1;
272 | continue;
273 | }
274 | position = w + 1;
275 | plusEnd++;
276 | } else {
277 | i = number;
278 | }
279 | }
280 | }
281 | startPosition = startPosition +plus;
282 | endPosition = endPosition + plusEnd;
283 | input.selectionStart = startPosition;
284 | input.selectionEnd = endPosition;
285 | return this;
286 | } else {
287 | return this;
288 | }
289 | }
290 | else if (input.selectionStart) { // MOZILLA support
291 | input.focus ();
292 | input.selectionStart = startPosition;
293 | input.selectionEnd = endPosition;
294 | return this;
295 | }
296 | },
297 |
298 | // insert text at current caret position
299 | insertAtCaretPos: function(inputStr) {
300 | var input = this.jquery ? this[0] : this;
301 | var start;
302 | var end;
303 | var position;
304 | var s;
305 | var re;
306 | var rc;
307 | var point;
308 | var minus = 0;
309 | var number = 0;
310 | var mozScrollFix = ( input.scrollTop == undefined ) ? 0 : input.scrollTop;
311 | input.focus();
312 | if (document.selection && typeof(input.selectionStart) != "number") {
313 | if (input.value.match(/\n/g) != null) {
314 | number = input.value.match(/\n/g).length;// number of EOL simbols
315 | }
316 | point = parseInt(caretPositionAmp);
317 | if (number > 0) {
318 | for (var i = 0; i <= number; i++) {
319 | var w = input.value.indexOf("\n", position);
320 | if (w != -1 && w <= point) {
321 | position = w + 1;
322 | point = point - 1;
323 | minus++;
324 | }
325 | }
326 | }
327 | }
328 | caretPositionAmp = parseInt(caretPositionAmp);
329 | // IE
330 | input.onmouseup = function() { // for IE because it loses caret position when focus changed
331 | if (document.selection && typeof(input.selectionStart) != "number") {
332 | input.focus();
333 | s = document.selection.createRange();
334 | re = input.createTextRange();
335 | rc = re.duplicate();
336 | re.moveToBookmark(s.getBookmark());
337 | rc.setEndPoint("EndToStart", re);
338 | caretPositionAmp = rc.text.length;
339 | }
340 | }
341 |
342 | if (document.selection && typeof(input.selectionStart) != "number") {
343 | s = document.selection.createRange();
344 | if (s.text.length != 0) {
345 | return this;
346 | }
347 | re = input.createTextRange();
348 | textLength = re.text.length;
349 | rc = re.duplicate();
350 | re.moveToBookmark(s.getBookmark());
351 | rc.setEndPoint("EndToStart", re);
352 | start = rc.text.length;
353 | if (caretPositionAmp > 0 && start ==0) {
354 | minus = caretPositionAmp - minus;
355 | re.move("character", minus);
356 | re.select();
357 | s = document.selection.createRange();
358 | caretPositionAmp += inputStr.length;
359 | } else if (!(caretPositionAmp >= 0) && textLength ==0) {
360 | s = document.selection.createRange();
361 | caretPositionAmp = inputStr.length + textLength;
362 | } else if (!(caretPositionAmp >= 0) && start ==0) {
363 | re.move("character", textLength);
364 | re.select();
365 | s = document.selection.createRange();
366 | caretPositionAmp = inputStr.length + textLength;
367 | } else if (!(caretPositionAmp >= 0) && start > 0) {
368 | re.move("character", 0);
369 | document.selection.empty();
370 | re.select();
371 | s = document.selection.createRange();
372 | caretPositionAmp = start + inputStr.length;
373 | } else if (caretPositionAmp >= 0 && caretPositionAmp == textLength) {
374 | if (textLength != 0) {
375 | re.move("character", textLength);
376 | re.select();
377 | } else {
378 | re.move("character", 0);
379 | }
380 | s = document.selection.createRange();
381 | caretPositionAmp = inputStr.length + textLength;
382 | } else if (caretPositionAmp >= 0 && start != 0 && caretPositionAmp >= start) {
383 | minus = caretPositionAmp - start;
384 | re.move("character", minus);
385 | document.selection.empty();
386 | re.select();
387 | s = document.selection.createRange();
388 | caretPositionAmp = caretPositionAmp + inputStr.length;
389 | } else if (caretPositionAmp >= 0 && start != 0 && caretPositionAmp < start) {
390 | re.move("character", 0);
391 | document.selection.empty();
392 | re.select();
393 | s = document.selection.createRange();
394 | caretPositionAmp = caretPositionAmp + inputStr.length;
395 | } else {
396 | document.selection.empty();
397 | re.select();
398 | s = document.selection.createRange();
399 | caretPositionAmp = caretPositionAmp + inputStr.length;
400 | }
401 | s.text = inputStr;
402 | input.focus();
403 |
404 | return this;
405 | } else if (typeof(input.selectionStart) == "number" && // MOZILLA support
406 | input.selectionStart == input.selectionEnd) {
407 | position = input.selectionStart + inputStr.length;
408 | start = input.selectionStart;
409 | end = input.selectionEnd;
410 | input.value = input.value.substr(0, start) + inputStr + input.value.substr(end);
411 | input.setSelectionRange(position, position);
412 | input.scrollTop = mozScrollFix;
413 | return this;
414 | }
415 | return this;
416 | },
417 |
418 |
419 | // Set caret position
420 | setCaretPos: function(inputStr) {
421 |
422 | var input = this.jquery ? this[0] : this;
423 | var s;
424 | var re;
425 | var position;
426 | var number = 0;
427 | var minus = 0;
428 | var w;
429 | input.focus();
430 | if (parseInt(inputStr) == 0) {
431 | return this;
432 | }
433 | //if (document.selection && typeof(input.selectionStart) == "number") {
434 | if (parseInt(inputStr) > 0) {
435 | inputStr = parseInt(inputStr) - 1;
436 | if (document.selection && typeof(input.selectionStart) == "number" && input.selectionStart == input.selectionEnd) {
437 | if (input.value.match(/\n/g) != null) {
438 | number = input.value.match(/\n/g).length;// number of EOL simbols
439 | }
440 | if (number > 0) {
441 | for (var i = 0; i <= number; i++) {
442 | w = input.value.indexOf("\n", position);
443 | if (w != -1 && w <= inputStr) {
444 | position = w + 1;
445 | inputStr = parseInt(inputStr) + 1;
446 | }
447 | }
448 | }
449 | }
450 | }
451 | else if (parseInt(inputStr) < 0) {
452 | inputStr = parseInt(inputStr) + 1;
453 | if (document.selection && typeof(input.selectionStart) != "number") {
454 | inputStr = input.value.length + parseInt(inputStr);
455 | if (input.value.match(/\n/g) != null) {
456 | number = input.value.match(/\n/g).length;// number of EOL simbols
457 | }
458 | if (number > 0) {
459 | for (var i = 0; i <= number; i++) {
460 | w = input.value.indexOf("\n", position);
461 | if (w != -1 && w <= inputStr) {
462 | position = w + 1;
463 | inputStr = parseInt(inputStr) - 1;
464 | minus += 1;
465 | }
466 | }
467 | inputStr = inputStr + minus - number;
468 | }
469 | } else if (document.selection && typeof(input.selectionStart) == "number") {
470 | inputStr = input.value.length + parseInt(inputStr);
471 | if (input.value.match(/\n/g) != null) {
472 | number = input.value.match(/\n/g).length;// number of EOL simbols
473 | }
474 | if (number > 0) {
475 | inputStr = parseInt(inputStr) - number;
476 | for (var i = 0; i <= number; i++) {
477 | w = input.value.indexOf("\n", position);
478 | if (w != -1 && w <= (inputStr)) {
479 | position = w + 1;
480 | inputStr = parseInt(inputStr) + 1;
481 | minus += 1;
482 | }
483 | }
484 | }
485 | } else { inputStr = input.value.length + parseInt(inputStr); }
486 | } else { return this; }
487 | // IE
488 | if (document.selection && typeof(input.selectionStart) != "number") {
489 | s = document.selection.createRange();
490 | if (s.text != 0) {
491 | return this;
492 | }
493 | re = input.createTextRange();
494 | re.collapse(true);
495 | re.moveEnd('character', inputStr);
496 | re.moveStart('character', inputStr);
497 | re.select();
498 | caretPositionAmp = inputStr;
499 |
500 | return this;
501 | } else if (typeof(input.selectionStart) == "number" && // MOZILLA support
502 | input.selectionStart == input.selectionEnd) {
503 | input.setSelectionRange(inputStr, inputStr);
504 | return this;
505 | }
506 | return this;
507 |
508 | },
509 |
510 | countCharacters: function(str) {
511 | var input = this.jquery ? this[0] : this;
512 | if (input.value.match(/\r/g) != null) {
513 | return input.value.length - input.value.match(/\r/g).length;
514 | }
515 | return input.value.length;
516 | },
517 |
518 | setMaxLength: function(max, f) {
519 | this.each(function() {
520 | var input = this.jquery ? this[0] : this;
521 | var type = input.type;
522 | var isSelected;
523 | var maxCharacters;
524 | // remove limit if input is a negative number
525 | if (parseInt(max) < 0) {
526 | max=100000000;
527 | }
528 | if (type == "text") {
529 | input.maxLength = max;
530 | }
531 | if (type == "textarea" || type == "text") {
532 | input.onkeypress = function(e) {
533 | var spacesR = input.value.match(/\r/g);
534 | maxCharacters = max;
535 | if (spacesR != null) {
536 | maxCharacters = parseInt(maxCharacters) + spacesR.length;
537 | }
538 | // get event
539 | var key = e || event;
540 | var keyCode = key.keyCode;
541 | // check if any part of text is selected
542 | if (document.selection) {
543 | isSelected = document.selection.createRange().text.length > 0;
544 | } else {
545 | isSelected = input.selectionStart != input.selectionEnd;
546 | }
547 | if (input.value.length >= maxCharacters && (keyCode > 47 || keyCode == 32 ||
548 | keyCode == 0 || keyCode == 13) && !key.ctrlKey && !key.altKey && !isSelected) {
549 | input.value = input.value.substring(0,maxCharacters);
550 | if (typeof(f) == "function") { f() } //callback function
551 | return false;
552 | }
553 | }
554 | input.onkeyup = function() {
555 | var spacesR = input.value.match(/\r/g);
556 | var plus = 0;
557 | var position = 0;
558 | maxCharacters = max;
559 | if (spacesR != null) {
560 | for (var i = 0; i <= spacesR.length; i++) {
561 | if (input.value.indexOf("\n", position) <= parseInt(max)) {
562 | plus++;
563 | position = input.value.indexOf("\n", position) + 1;
564 | }
565 | }
566 | maxCharacters = parseInt(max) + plus;
567 | }
568 | if (input.value.length > maxCharacters) {
569 | input.value = input.value.substring(0, maxCharacters);
570 | if (typeof(f) == "function") { f() }
571 | return this;
572 | }
573 | }
574 | } else { return this; }
575 | })
576 | return this;
577 | }
578 | });
579 |
--------------------------------------------------------------------------------
/js/jquery.asuggest.js:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery textarea suggest plugin
3 | *
4 | * Copyright (c) 2009-2010 Roman Imankulov
5 | *
6 | * Dual licensed under the MIT and GPL licenses:
7 | * http://www.opensource.org/licenses/mit-license.php
8 | * http://www.gnu.org/licenses/gpl.html
9 | *
10 | * Requires:
11 | * - jQuery (tested with 1.3.x and 1.4.x)
12 | * - jquery.a-tools >= 1.4.1 (http://plugins.jquery.com/project/a-tools)
13 | */
14 |
15 | /*globals jQuery,document */
16 |
17 | (function ($) {
18 | // workaround for Opera browser
19 | if (navigator.userAgent.match(/opera/i)) {
20 | $(document).keypress(function (e) {
21 | if ($.asuggestFocused) {
22 | $.asuggestFocused.focus();
23 | $.asuggestFocused = null;
24 | e.preventDefault();
25 | e.stopPropagation();
26 | }
27 | });
28 | }
29 |
30 | $.asuggestKeys = {
31 | UNKNOWN: 0,
32 | SHIFT: 16,
33 | CTRL: 17,
34 | ALT: 18,
35 | LEFT: 37,
36 | UP: 38,
37 | RIGHT: 39,
38 | DOWN: 40,
39 | DEL: 46,
40 | TAB: 9,
41 | RETURN: 13,
42 | ESC: 27,
43 | COMMA: 188,
44 | PAGEUP: 33,
45 | PAGEDOWN: 34,
46 | BACKSPACE: 8,
47 | SPACE: 32
48 | };
49 | $.asuggestFocused = null;
50 |
51 | $.fn.asuggest = function (suggests, options) {
52 | return this.each(function () {
53 | $.makeSuggest(this, suggests, options);
54 | });
55 | };
56 |
57 | $.fn.asuggest.defaults = {
58 | 'delimiters': '\n ',
59 | 'minChunkSize': 1,
60 | 'cycleOnTab': true,
61 | 'autoComplete': true,
62 | 'endingSymbols': ' ',
63 | 'stopSuggestionKeys': [$.asuggestKeys.RETURN, $.asuggestKeys.SPACE],
64 | 'ignoreCase': false
65 | };
66 |
67 | /* Make suggest:
68 | *
69 | * create and return jQuery object on the top of DOM object
70 | * and store suggests as part of this object
71 | *
72 | * @param area: HTML DOM element to add suggests to
73 | * @param suggests: The array of suggest strings
74 | * @param options: The options object
75 | */
76 | $.makeSuggest = function (area, suggests, options) {
77 | options = $.extend({}, $.fn.asuggest.defaults, options);
78 |
79 | var KEY = $.asuggestKeys,
80 | $area = $(area);
81 | $area.suggests = suggests;
82 | $area.options = options;
83 |
84 | /* Internal method: get the chunk of text before the cursor */
85 | $area.getChunk = function () {
86 | var delimiters = this.options.delimiters.split(''), // array of chars
87 | textBeforeCursor = this.val().substr(0, this.getSelection().start),
88 | indexOfDelimiter = -1,
89 | i,
90 | d,
91 | idx;
92 | for (i = 0; i < delimiters.length; i++) {
93 | d = delimiters[i];
94 | idx = textBeforeCursor.lastIndexOf(d);
95 | if (idx > indexOfDelimiter) {
96 | indexOfDelimiter = idx;
97 | }
98 | }
99 | if (indexOfDelimiter < 0) {
100 | return textBeforeCursor;
101 | } else {
102 | return textBeforeCursor.substr(indexOfDelimiter + 1);
103 | }
104 | };
105 |
106 | /* Internal method: get completion.
107 | * If performCycle is true then analyze getChunk() and and getSelection()
108 | */
109 | $area.getCompletion = function (performCycle) {
110 | var text = this.getChunk(),
111 | selectionText = this.getSelection().text,
112 | suggests = this.suggests,
113 | foundAlreadySelectedValue = false,
114 | firstMatchedValue = null,
115 | i,
116 | suggest;
117 | // search the variant
118 | for (i = 0; i < suggests.length; i++) {
119 | suggest = suggests[i];
120 | if ($area.options.ignoreCase) {
121 | suggest = suggest.toLowerCase();
122 | text = text.toLowerCase();
123 | }
124 | // some variant is found
125 | if (suggest.indexOf(text) === 0) {
126 | if (performCycle) {
127 | if (text + selectionText === suggest) {
128 | foundAlreadySelectedValue = true;
129 | } else if (foundAlreadySelectedValue) {
130 | return suggest.substr(text.length);
131 | } else if (firstMatchedValue === null) {
132 | firstMatchedValue = suggest;
133 | }
134 | } else {
135 | return suggest.substr(text.length);
136 | }
137 | }
138 | }
139 | if (performCycle && firstMatchedValue) {
140 | return firstMatchedValue.substr(text.length);
141 | } else {
142 | return null;
143 | }
144 | };
145 |
146 | $area.updateSelection = function (completion) {
147 | if (completion) {
148 | var _selectionStart = $area.getSelection().start,
149 | _selectionEnd = _selectionStart + completion.length;
150 | if ($area.getSelection().text === "") {
151 | if ($area.val().length === _selectionStart) { // Weird IE workaround, I really have no idea why it works
152 | $area.setCaretPos(_selectionStart + 10000);
153 | }
154 | $area.insertAtCaretPos(completion);
155 | } else {
156 | $area.replaceSelection(completion);
157 | }
158 | $area.setSelection(_selectionStart, _selectionEnd);
159 | }
160 | };
161 |
162 | $area.unbind('keydown.asuggest').bind('keydown.asuggest', function (e) {
163 | if (e.keyCode === KEY.TAB) {
164 | if ($area.options.cycleOnTab) {
165 | var chunk = $area.getChunk();
166 | if (chunk.length >= $area.options.minChunkSize) {
167 | $area.updateSelection($area.getCompletion(true));
168 | }
169 | e.preventDefault();
170 | e.stopPropagation();
171 | $area.focus();
172 | $.asuggestFocused = this;
173 | return false;
174 | }
175 | }
176 | // Check for conditions to stop suggestion
177 | if ($area.getSelection().length &&
178 | $.inArray(e.keyCode, $area.options.stopSuggestionKeys) !== -1) {
179 | // apply suggestion. Clean up selection and insert a space
180 | var _selectionEnd = $area.getSelection().end +
181 | $area.options.endingSymbols.length;
182 | var _text = $area.getSelection().text +
183 | $area.options.endingSymbols;
184 | $area.replaceSelection(_text);
185 | $area.setSelection(_selectionEnd, _selectionEnd);
186 | e.preventDefault();
187 | e.stopPropagation();
188 | this.focus();
189 | $.asuggestFocused = this;
190 | return false;
191 | }
192 | });
193 |
194 | $area.unbind('keyup.asuggest').bind('keyup.asuggest', function (e) {
195 | var hasSpecialKeys = e.altKey || e.metaKey || e.ctrlKey,
196 | hasSpecialKeysOrShift = hasSpecialKeys || e.shiftKey;
197 | switch (e.keyCode) {
198 | case KEY.UNKNOWN: // Special key released
199 | case KEY.SHIFT:
200 | case KEY.CTRL:
201 | case KEY.ALT:
202 | case KEY.RETURN: // we don't want to suggest when RETURN key has pressed (another IE workaround)
203 | break;
204 | case KEY.TAB:
205 | if (!hasSpecialKeysOrShift && $area.options.cycleOnTab) {
206 | break;
207 | }
208 | case KEY.ESC:
209 | case KEY.BACKSPACE:
210 | case KEY.DEL:
211 | case KEY.UP:
212 | case KEY.DOWN:
213 | case KEY.LEFT:
214 | case KEY.RIGHT:
215 | if (!hasSpecialKeysOrShift && $area.options.autoComplete) {
216 | $area.replaceSelection("");
217 | }
218 | break;
219 | default:
220 | if (!hasSpecialKeys && $area.options.autoComplete) {
221 | var chunk = $area.getChunk();
222 | if (chunk.length >= $area.options.minChunkSize) {
223 | $area.updateSelection($area.getCompletion(false));
224 | }
225 | }
226 | break;
227 | }
228 | });
229 | return $area;
230 | };
231 | }(jQuery));
232 |
--------------------------------------------------------------------------------
/js/jquery.sticky.js:
--------------------------------------------------------------------------------
1 | // Sticky Plugin v1.0.0 for jQuery
2 | // =============
3 | // Author: Anthony Garand
4 | // Improvements by German M. Bravo (Kronuz) and Ruud Kamphuis (ruudk)
5 | // Improvements by Leonardo C. Daronco (daronco)
6 | // Created: 2/14/2011
7 | // Date: 2/12/2012
8 | // Website: http://labs.anthonygarand.com/sticky
9 | // Description: Makes an element on the page stick on the screen as you scroll
10 | // It will only set the 'top' and 'position' of your element, you
11 | // might need to adjust the width in some cases.
12 |
13 | (function($) {
14 | var defaults = {
15 | topSpacing: 0,
16 | bottomSpacing: 0,
17 | className: 'is-sticky',
18 | wrapperClassName: 'sticky-wrapper',
19 | center: false,
20 | getWidthFrom: ''
21 | },
22 | $window = $(window),
23 | $document = $(document),
24 | sticked = [],
25 | windowHeight = $window.height(),
26 | scroller = function() {
27 | var scrollTop = $window.scrollTop(),
28 | documentHeight = $document.height(),
29 | dwh = documentHeight - windowHeight,
30 | extra = (scrollTop > dwh) ? dwh - scrollTop : 0;
31 |
32 | for (var i = 0; i < sticked.length; i++) {
33 | var s = sticked[i],
34 | elementTop = s.stickyWrapper.offset().top,
35 | etse = elementTop - s.topSpacing - extra;
36 |
37 | if (scrollTop <= etse) {
38 | if (s.currentTop !== null) {
39 | s.stickyElement
40 | .css('position', '')
41 | .css('top', '');
42 | s.stickyElement.parent().removeClass(s.className);
43 | s.currentTop = null;
44 | }
45 | }
46 | else {
47 | var newTop = documentHeight - s.stickyElement.outerHeight()
48 | - s.topSpacing - s.bottomSpacing - scrollTop - extra;
49 | if (newTop < 0) {
50 | newTop = newTop + s.topSpacing;
51 | } else {
52 | newTop = s.topSpacing;
53 | }
54 | if (s.currentTop != newTop) {
55 | s.stickyElement
56 | .css('position', 'fixed')
57 | .css('top', newTop);
58 |
59 | if (typeof s.getWidthFrom !== 'undefined') {
60 | s.stickyElement.css('width', $(s.getWidthFrom).width());
61 | }
62 |
63 | s.stickyElement.parent().addClass(s.className);
64 | s.currentTop = newTop;
65 | }
66 | }
67 | }
68 | },
69 | resizer = function() {
70 | windowHeight = $window.height();
71 | },
72 | methods = {
73 | init: function(options) {
74 | var o = $.extend(defaults, options);
75 | return this.each(function() {
76 | var stickyElement = $(this);
77 |
78 | var stickyId = stickyElement.attr('id');
79 | var wrapper = $('
')
80 | .attr('id', stickyId + '-sticky-wrapper')
81 | .addClass(o.wrapperClassName);
82 | stickyElement.wrapAll(wrapper);
83 |
84 | if (o.center) {
85 | stickyElement.parent().css({width:stickyElement.outerWidth(),marginLeft:"auto",marginRight:"auto"});
86 | }
87 |
88 | if (stickyElement.css("float") == "right") {
89 | stickyElement.css({"float":"none"}).parent().css({"float":"right"});
90 | }
91 |
92 | var stickyWrapper = stickyElement.parent();
93 | stickyWrapper.css('height', stickyElement.outerHeight());
94 | sticked.push({
95 | topSpacing: o.topSpacing,
96 | bottomSpacing: o.bottomSpacing,
97 | stickyElement: stickyElement,
98 | currentTop: null,
99 | stickyWrapper: stickyWrapper,
100 | className: o.className,
101 | getWidthFrom: o.getWidthFrom
102 | });
103 | });
104 | },
105 | update: scroller,
106 | unstick: function(options) {
107 | return this.each(function() {
108 | var unstickyElement = $(this);
109 |
110 | removeIdx = -1;
111 | for (var i = 0; i < sticked.length; i++)
112 | {
113 | if (sticked[i].stickyElement.get(0) == unstickyElement.get(0))
114 | {
115 | removeIdx = i;
116 | }
117 | }
118 | if(removeIdx != -1)
119 | {
120 | sticked.splice(removeIdx,1);
121 | unstickyElement.unwrap();
122 | unstickyElement.removeAttr('style');
123 | }
124 | });
125 | }
126 | };
127 |
128 | // should be more efficient than using $window.scroll(scroller) and $window.resize(resizer):
129 | if (window.addEventListener) {
130 | window.addEventListener('scroll', scroller, false);
131 | window.addEventListener('resize', resizer, false);
132 | } else if (window.attachEvent) {
133 | window.attachEvent('onscroll', scroller);
134 | window.attachEvent('onresize', resizer);
135 | }
136 |
137 | $.fn.sticky = function(method) {
138 | if (methods[method]) {
139 | return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
140 | } else if (typeof method === 'object' || !method ) {
141 | return methods.init.apply( this, arguments );
142 | } else {
143 | $.error('Method ' + method + ' does not exist on jQuery.sticky');
144 | }
145 | };
146 |
147 | $.fn.unstick = function(method) {
148 | if (methods[method]) {
149 | return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
150 | } else if (typeof method === 'object' || !method ) {
151 | return methods.unstick.apply( this, arguments );
152 | } else {
153 | $.error('Method ' + method + ' does not exist on jQuery.sticky');
154 | }
155 |
156 | };
157 | $(function() {
158 | setTimeout(scroller, 0);
159 | });
160 | })(jQuery);
161 |
--------------------------------------------------------------------------------
/js/jquery.tooltipster.js:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Tooltipster 3.2.2 | 2014-04-07
4 | A rockin' custom tooltip jQuery plugin
5 |
6 | Developed by Caleb Jacob under the MIT license http://opensource.org/licenses/MIT
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 |
10 | */
11 |
12 | ;(function ($, window, document) {
13 |
14 | var pluginName = "tooltipster",
15 | defaults = {
16 | animation: 'fade',
17 | arrow: true,
18 | arrowColor: '',
19 | autoClose: true,
20 | content: null,
21 | contentAsHTML: false,
22 | contentCloning: true,
23 | delay: 200,
24 | fixedWidth: 0,
25 | maxWidth: 0,
26 | functionInit: function(origin, content) {},
27 | functionBefore: function(origin, continueTooltip) {
28 | continueTooltip();
29 | },
30 | functionReady: function(origin, tooltip) {},
31 | functionAfter: function(origin) {},
32 | icon: '(?)',
33 | iconCloning: true,
34 | iconDesktop: false,
35 | iconTouch: false,
36 | iconTheme: 'tooltipster-icon',
37 | interactive: false,
38 | interactiveTolerance: 350,
39 | multiple: false,
40 | offsetX: 0,
41 | offsetY: 0,
42 | onlyOne: false,
43 | position: 'top',
44 | positionTracker: false,
45 | speed: 350,
46 | timer: 0,
47 | theme: 'tooltipster-default',
48 | touchDevices: true,
49 | trigger: 'hover',
50 | updateAnimation: true
51 | };
52 |
53 | function Plugin(element, options) {
54 |
55 | // list of instance variables
56 |
57 | this.bodyOverflowX;
58 | // stack of custom callbacks provided as parameters to API methods
59 | this.callbacks = {
60 | hide: [],
61 | show: []
62 | };
63 | this.checkInterval = null;
64 | // this will be the user content shown in the tooltip. A capital "C" is used because there is also a method called content()
65 | this.Content;
66 | // this is the original element which is being applied the tooltipster plugin
67 | this.$el = $(element);
68 | // this will be the element which triggers the appearance of the tooltip on hover/click/custom events.
69 | // it will be the same as this.$el if icons are not used (see in the options), otherwise it will correspond to the created icon
70 | this.$elProxy;
71 | this.elProxyPosition;
72 | this.enabled = true;
73 | this.options = $.extend({}, defaults, options);
74 | this.mouseIsOverProxy = false;
75 | // a unique namespace per instance, for easy selective unbinding
76 | this.namespace = 'tooltipster-'+ Math.round(Math.random()*100000);
77 | // Status (capital S) can be either : appearing, shown, disappearing, hidden
78 | this.Status = 'hidden';
79 | this.timerHide = null;
80 | this.timerShow = null;
81 | // this will be the tooltip element (jQuery wrapped HTML element)
82 | this.$tooltip;
83 |
84 | // for backward compatibility
85 | this.options.iconTheme = this.options.iconTheme.replace('.', '');
86 | this.options.theme = this.options.theme.replace('.', '');
87 |
88 | // launch
89 |
90 | this._init();
91 | }
92 |
93 | Plugin.prototype = {
94 |
95 | _init: function() {
96 |
97 | var self = this;
98 |
99 | // disable the plugin on old browsers (including IE7 and lower)
100 | if (document.querySelector) {
101 |
102 | // note : the content is null (empty) by default and can stay that way if the plugin remains initialized but not fed any content. The tooltip will just not appear.
103 |
104 | // if content is provided in the options, its has precedence over the title attribute. Remark : an empty string is considered content, only 'null' represents the absence of content.
105 | if (self.options.content !== null){
106 | self._content_set(self.options.content);
107 | }
108 | else {
109 | // the same remark as above applies : empty strings (like title="") are considered content and will be shown. Do not define any attribute at all if you want to initialize the plugin without content at start.
110 | var t = self.$el.attr('title');
111 | if(typeof t === 'undefined') t = null;
112 |
113 | self._content_set(t);
114 | }
115 |
116 | var c = self.options.functionInit.call(self.$el, self.$el, self.Content);
117 | if(typeof c !== 'undefined') self._content_set(c);
118 |
119 | self.$el
120 | // strip the title off of the element to prevent the default tooltips from popping up
121 | .removeAttr('title')
122 | // to be able to find all instances on the page later (upon window events in particular)
123 | .addClass('tooltipstered');
124 |
125 | // detect if we're changing the tooltip origin to an icon
126 | // note about this condition : if the device has touch capability and self.options.iconTouch is false, you'll have no icons event though you may consider your device as a desktop if it also has a mouse. Not sure why someone would have this use case though.
127 | if ((!deviceHasTouchCapability && self.options.iconDesktop) || (deviceHasTouchCapability && self.options.iconTouch)) {
128 |
129 | // TODO : the tooltip should be automatically be given an absolute position to be near the origin. Otherwise, when the origin is floating or what, it's going to be nowhere near it and disturb the position flow of the page elements. It will imply that the icon also detects when its origin moves, to follow it : not trivial.
130 | // Until it's done, the icon feature does not really make sense since the user still has most of the work to do by himself
131 |
132 | // if the icon provided is in the form of a string
133 | if(typeof self.options.icon === 'string'){
134 | // wrap it in a span with the icon class
135 | self.$elProxy = $(' ');
136 | self.$elProxy.text(self.options.icon);
137 | }
138 | // if it is an object (sensible choice)
139 | else {
140 | // (deep) clone the object if iconCloning == true, to make sure every instance has its own proxy. We use the icon without wrapping, no need to. We do not give it a class either, as the user will undoubtedly style the object on his own and since our css properties may conflict with his own
141 | if (self.options.iconCloning) self.$elProxy = self.options.icon.clone(true);
142 | else self.$elProxy = self.options.icon;
143 | }
144 |
145 | self.$elProxy.insertAfter(self.$el);
146 | }
147 | else {
148 | self.$elProxy = self.$el;
149 | }
150 |
151 | // for 'click' and 'hover' triggers : bind on events to open the tooltip. Closing is now handled in _showNow() because of its bindings.
152 | // Notes about touch events :
153 | // - mouseenter, mouseleave and clicks happen even on pure touch devices because they are emulated. deviceIsPureTouch() is a simple attempt to detect them.
154 | // - on hybrid devices, we do not prevent touch gesture from opening tooltips. It would be too complex to differentiate real mouse events from emulated ones.
155 | // - we check deviceIsPureTouch() at each event rather than prior to binding because the situation may change during browsing
156 | if (self.options.trigger == 'hover') {
157 |
158 | // these binding are for mouse interaction only
159 | self.$elProxy
160 | .on('mouseenter.'+ self.namespace, function() {
161 | if (!deviceIsPureTouch() || self.options.touchDevices) {
162 | self.mouseIsOverProxy = true;
163 | self._show();
164 | }
165 | })
166 | .on('mouseleave.'+ self.namespace, function() {
167 | if (!deviceIsPureTouch() || self.options.touchDevices) {
168 | self.mouseIsOverProxy = false;
169 | }
170 | });
171 |
172 | // for touch interaction only
173 | if (deviceHasTouchCapability && self.options.touchDevices) {
174 |
175 | // for touch devices, we immediately display the tooltip because we cannot rely on mouseleave to handle the delay
176 | self.$elProxy.on('touchstart.'+ self.namespace, function() {
177 | self._showNow();
178 | });
179 | }
180 | }
181 | else if (self.options.trigger == 'click') {
182 |
183 | // note : for touch devices, we do not bind on touchstart, we only rely on the emulated clicks (triggered by taps)
184 | self.$elProxy.on('click.'+ self.namespace, function() {
185 | if (!deviceIsPureTouch() || self.options.touchDevices) {
186 | self._show();
187 | }
188 | });
189 | }
190 | }
191 | },
192 |
193 | // this function will schedule the opening of the tooltip after the delay, if there is one
194 | _show: function() {
195 |
196 | var self = this;
197 |
198 | if (self.Status != 'shown' && self.Status != 'appearing') {
199 |
200 | if (self.options.delay) {
201 | self.timerShow = setTimeout(function(){
202 |
203 | // for hover trigger, we check if the mouse is still over the proxy, otherwise we do not show anything
204 | if (self.options.trigger == 'click' || (self.options.trigger == 'hover' && self.mouseIsOverProxy)) {
205 | self._showNow();
206 | }
207 | }, self.options.delay);
208 | }
209 | else self._showNow();
210 | }
211 | },
212 |
213 | // this function will open the tooltip right away
214 | _showNow: function(callback) {
215 |
216 | var self = this;
217 |
218 | // call our constructor custom function before continuing
219 | self.options.functionBefore.call(self.$el, self.$el, function() {
220 |
221 | // continue only if the tooltip is enabled and has any content
222 | if (self.enabled && self.Content !== null) {
223 |
224 | // save the method callback and cancel hide method callbacks
225 | if (callback) self.callbacks.show.push(callback);
226 | self.callbacks.hide = [];
227 |
228 | //get rid of any appearance timer
229 | clearTimeout(self.timerShow);
230 | self.timerShow = null;
231 | clearTimeout(self.timerHide);
232 | self.timerHide = null;
233 |
234 | // if we only want one tooltip open at a time, close all auto-closing tooltips currently open and not already disappearing
235 | if (self.options.onlyOne) {
236 | $('.tooltipstered').not(self.$el).each(function(i,el) {
237 |
238 | var $el = $(el),
239 | nss = $el.data('tooltipster-ns');
240 |
241 | // iterate on all tooltips of the element
242 | $.each(nss, function(i, ns){
243 | var instance = $el.data(ns),
244 | // we have to use the public methods here
245 | s = instance.status(),
246 | ac = instance.option('autoClose');
247 |
248 | if (s !== 'hidden' && s !== 'disappearing' && ac) {
249 | instance.hide();
250 | }
251 | });
252 | });
253 | }
254 |
255 | var finish = function() {
256 | self.Status = 'shown';
257 |
258 | // trigger any show method custom callbacks and reset them
259 | $.each(self.callbacks.show, function(i,c) { c.call(self.$el); });
260 | self.callbacks.show = [];
261 | };
262 |
263 | // if this origin already has its tooltip open
264 | if (self.Status !== 'hidden') {
265 |
266 | // the timer (if any) will start (or restart) right now
267 | var extraTime = 0;
268 |
269 | // if it was disappearing, cancel that
270 | if (self.Status === 'disappearing') {
271 |
272 | self.Status = 'appearing';
273 |
274 | if (supportsTransitions()) {
275 |
276 | self.$tooltip
277 | .clearQueue()
278 | .removeClass('tooltipster-dying')
279 | .addClass('tooltipster-'+ self.options.animation +'-show');
280 |
281 | if (self.options.speed > 0) self.$tooltip.delay(self.options.speed);
282 |
283 | self.$tooltip.queue(finish);
284 | }
285 | else {
286 | // in case the tooltip was currently fading out, bring it back to life
287 | self.$tooltip
288 | .stop()
289 | .fadeIn(finish);
290 | }
291 | }
292 | // if the tooltip is already open, we still need to trigger the method custom callback
293 | else if(self.Status === 'shown') {
294 | finish();
295 | }
296 | }
297 | // if the tooltip isn't already open, open that sucker up!
298 | else {
299 |
300 | self.Status = 'appearing';
301 |
302 | // the timer (if any) will start when the tooltip has fully appeared after its transition
303 | var extraTime = self.options.speed;
304 |
305 | // disable horizontal scrollbar to keep overflowing tooltips from jacking with it and then restore it to its previous value
306 | self.bodyOverflowX = $('body').css('overflow-x');
307 | $('body').css('overflow-x', 'hidden');
308 |
309 | // get some other settings related to building the tooltip
310 | var animation = 'tooltipster-' + self.options.animation,
311 | animationSpeed = '-webkit-transition-duration: '+ self.options.speed +'ms; -webkit-animation-duration: '+ self.options.speed +'ms; -moz-transition-duration: '+ self.options.speed +'ms; -moz-animation-duration: '+ self.options.speed +'ms; -o-transition-duration: '+ self.options.speed +'ms; -o-animation-duration: '+ self.options.speed +'ms; -ms-transition-duration: '+ self.options.speed +'ms; -ms-animation-duration: '+ self.options.speed +'ms; transition-duration: '+ self.options.speed +'ms; animation-duration: '+ self.options.speed +'ms;',
312 | fixedWidth = self.options.fixedWidth > 0 ? 'width:'+ Math.round(self.options.fixedWidth) +'px;' : '',
313 | maxWidth = self.options.maxWidth > 0 ? 'max-width:'+ Math.round(self.options.maxWidth) +'px;' : '',
314 | pointerEvents = self.options.interactive ? 'pointer-events: auto;' : '';
315 |
316 | // build the base of our tooltip
317 | self.$tooltip = $('');
318 |
319 | // only add the animation class if the user has a browser that supports animations
320 | if (supportsTransitions()) self.$tooltip.addClass(animation);
321 |
322 | // insert the content
323 | self._content_insert();
324 |
325 | // attach
326 | self.$tooltip.appendTo('body');
327 |
328 | // do all the crazy calculations and positioning
329 | self.reposition();
330 |
331 | // call our custom callback since the content of the tooltip is now part of the DOM
332 | self.options.functionReady.call(self.$el, self.$el, self.$tooltip);
333 |
334 | // animate in the tooltip
335 | if (supportsTransitions()) {
336 |
337 | self.$tooltip.addClass(animation + '-show');
338 |
339 | if(self.options.speed > 0) self.$tooltip.delay(self.options.speed);
340 |
341 | self.$tooltip.queue(finish);
342 | }
343 | else {
344 | self.$tooltip.css('display', 'none').fadeIn(self.options.speed, finish);
345 | }
346 |
347 | // will check if our tooltip origin is removed while the tooltip is shown
348 | self._interval_set();
349 |
350 | // reposition on scroll (otherwise position:fixed element's tooltips will move away form their origin) and on resize (in case position can/has to be changed)
351 | $(window).on('scroll.'+ self.namespace +' resize.'+ self.namespace, function() {
352 | self.reposition();
353 | });
354 |
355 | // auto-close bindings
356 | if (self.options.autoClose) {
357 |
358 | // in case a listener is already bound for autoclosing (mouse or touch, hover or click), unbind it first
359 | $('body').off('.'+ self.namespace);
360 |
361 | // here we'll have to set different sets of bindings for both touch and mouse
362 | if (self.options.trigger == 'hover') {
363 |
364 | // if the user touches the body, hide
365 | if (deviceHasTouchCapability) {
366 | // timeout 0 : explanation below in click section
367 | setTimeout(function() {
368 | // we don't want to bind on click here because the initial touchstart event has not yet triggered its click event, which is thus about to happen
369 | $('body').on('touchstart.'+ self.namespace, function() {
370 | self.hide();
371 | });
372 | }, 0);
373 | }
374 |
375 | // if we have to allow interaction
376 | if (self.options.interactive) {
377 |
378 | // touch events inside the tooltip must not close it
379 | if (deviceHasTouchCapability) {
380 | self.$tooltip.on('touchstart.'+ self.namespace, function(event) {
381 | event.stopPropagation();
382 | });
383 | }
384 |
385 | // as for mouse interaction, we get rid of the tooltip only after the mouse has spent some time out of it
386 | var tolerance = null;
387 |
388 | self.$elProxy.add(self.$tooltip)
389 | // hide after some time out of the proxy and the tooltip
390 | .on('mouseleave.'+ self.namespace + '-autoClose', function() {
391 | clearTimeout(tolerance);
392 | tolerance = setTimeout(function(){
393 | self.hide();
394 | }, self.options.interactiveTolerance);
395 | })
396 | // suspend timeout when the mouse is over the proxy or the tooltip
397 | .on('mouseenter.'+ self.namespace + '-autoClose', function() {
398 | clearTimeout(tolerance);
399 | });
400 | }
401 | // if this is a non-interactive tooltip, get rid of it if the mouse leaves
402 | else {
403 | self.$elProxy.on('mouseleave.'+ self.namespace + '-autoClose', function() {
404 | self.hide();
405 | });
406 | }
407 | }
408 | // here we'll set the same bindings for both clicks and touch on the body to hide the tooltip
409 | else if(self.options.trigger == 'click'){
410 |
411 | // use a timeout to prevent immediate closing if the method was called on a click event and if options.delay == 0 (because of bubbling)
412 | setTimeout(function() {
413 | $('body').on('click.'+ self.namespace +' touchstart.'+ self.namespace, function() {
414 | self.hide();
415 | });
416 | }, 0);
417 |
418 | // if interactive, we'll stop the events that were emitted from inside the tooltip to stop autoClosing
419 | if (self.options.interactive) {
420 |
421 | // note : the touch events will just not be used if the plugin is not enabled on touch devices
422 | self.$tooltip.on('click.'+ self.namespace +' touchstart.'+ self.namespace, function(event) {
423 | event.stopPropagation();
424 | });
425 | }
426 | }
427 | }
428 | }
429 |
430 | // if we have a timer set, let the countdown begin
431 | if (self.options.timer > 0) {
432 |
433 | self.timerHide = setTimeout(function() {
434 | self.timerHide = null;
435 | self.hide();
436 | }, self.options.timer + extraTime);
437 | }
438 | }
439 | });
440 | },
441 |
442 | _interval_set: function() {
443 |
444 | var self = this;
445 |
446 | self.checkInterval = setInterval(function() {
447 |
448 | // if the tooltip and/or its interval should be stopped
449 | if (
450 | // if the origin has been removed
451 | $('body').find(self.$el).length === 0
452 | // if the elProxy has been removed
453 | || $('body').find(self.$elProxy).length === 0
454 | // if the tooltip has been closed
455 | || self.Status == 'hidden'
456 | // if the tooltip has somehow been removed
457 | || $('body').find(self.$tooltip).length === 0
458 | ) {
459 | // remove the tooltip if it's still here
460 | if (self.Status == 'shown' || self.Status == 'appearing') self.hide();
461 |
462 | // clear this interval as it is no longer necessary
463 | self._interval_cancel();
464 | }
465 | // if everything is alright
466 | else {
467 | // compare the former and current positions of the elProxy to reposition the tooltip if need be
468 | if(self.options.positionTracker){
469 |
470 | var p = self._repositionInfo(self.$elProxy),
471 | identical = false;
472 |
473 | // compare size first (a change requires repositioning too)
474 | if(areEqual(p.dimension, self.elProxyPosition.dimension)){
475 |
476 | // for elements with a fixed position, we track the top and left properties (relative to window)
477 | if(self.$elProxy.css('position') === 'fixed'){
478 | if(areEqual(p.position, self.elProxyPosition.position)) identical = true;
479 | }
480 | // otherwise, track total offset (relative to document)
481 | else {
482 | if(areEqual(p.offset, self.elProxyPosition.offset)) identical = true;
483 | }
484 | }
485 |
486 | if(!identical){
487 | self.reposition();
488 | }
489 | }
490 | }
491 | }, 200);
492 | },
493 |
494 | _interval_cancel: function() {
495 | clearInterval(this.checkInterval);
496 | // clean delete
497 | this.checkInterval = null;
498 | },
499 |
500 | _content_set: function(content) {
501 | // clone if asked. Cloning the object makes sure that each instance has its own version of the content (in case a same object were provided for several instances)
502 | // reminder : typeof null === object
503 | if (typeof content === 'object' && content !== null && this.options.contentCloning) {
504 | content = content.clone(true);
505 | }
506 | this.Content = content;
507 | },
508 |
509 | _content_insert: function() {
510 |
511 | var self = this,
512 | $d = this.$tooltip.find('.tooltipster-content');
513 |
514 | if (typeof self.Content === 'string' && !self.options.contentAsHTML) {
515 | $d.text(self.Content);
516 | }
517 | else {
518 | $d
519 | .empty()
520 | .append(self.Content);
521 | }
522 | },
523 |
524 | _update: function(content) {
525 |
526 | var self = this;
527 |
528 | // change the content
529 | self._content_set(content);
530 |
531 | if (self.Content !== null) {
532 |
533 | // update the tooltip if it is open
534 | if (self.Status !== 'hidden') {
535 |
536 | // reset the content in the tooltip
537 | self._content_insert();
538 |
539 | // reposition and resize the tooltip
540 | self.reposition();
541 |
542 | // if we want to play a little animation showing the content changed
543 | if (self.options.updateAnimation) {
544 |
545 | if (supportsTransitions()) {
546 |
547 | self.$tooltip.css({
548 | 'width': '',
549 | '-webkit-transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms',
550 | '-moz-transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms',
551 | '-o-transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms',
552 | '-ms-transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms',
553 | 'transition': 'all ' + self.options.speed + 'ms, width 0ms, height 0ms, left 0ms, top 0ms'
554 | }).addClass('tooltipster-content-changing');
555 |
556 | // reset the CSS transitions and finish the change animation
557 | setTimeout(function() {
558 |
559 | if(self.Status != 'hidden'){
560 |
561 | self.$tooltip.removeClass('tooltipster-content-changing');
562 |
563 | // after the changing animation has completed, reset the CSS transitions
564 | setTimeout(function() {
565 |
566 | if(self.Status !== 'hidden'){
567 | self.$tooltip.css({
568 | '-webkit-transition': self.options.speed + 'ms',
569 | '-moz-transition': self.options.speed + 'ms',
570 | '-o-transition': self.options.speed + 'ms',
571 | '-ms-transition': self.options.speed + 'ms',
572 | 'transition': self.options.speed + 'ms'
573 | });
574 | }
575 | }, self.options.speed);
576 | }
577 | }, self.options.speed);
578 | }
579 | else {
580 | self.$tooltip.fadeTo(self.options.speed, 0.5, function() {
581 | if(self.Status != 'hidden'){
582 | self.$tooltip.fadeTo(self.options.speed, 1);
583 | }
584 | });
585 | }
586 | }
587 | }
588 | }
589 | else {
590 | self.hide();
591 | }
592 | },
593 |
594 | _repositionInfo: function($el) {
595 | return {
596 | dimension: {
597 | height: $el.outerHeight(false),
598 | width: $el.outerWidth(false)
599 | },
600 | offset: $el.offset(),
601 | position: {
602 | left: parseInt($el.css('left')),
603 | top: parseInt($el.css('top'))
604 | }
605 | };
606 | },
607 |
608 | hide: function(callback) {
609 |
610 | var self = this;
611 |
612 | // save the method custom callback and cancel any show method custom callbacks
613 | if (callback) self.callbacks.hide.push(callback);
614 | self.callbacks.show = [];
615 |
616 | // get rid of any appearance timeout
617 | clearTimeout(self.timerShow);
618 | self.timerShow = null;
619 | clearTimeout(self.timerHide);
620 | self.timerHide = null;
621 |
622 | var finishCallbacks = function() {
623 | // trigger any hide method custom callbacks and reset them
624 | $.each(self.callbacks.hide, function(i,c) { c.call(self.$el); });
625 | self.callbacks.hide = [];
626 | };
627 |
628 | // hide
629 | if (self.Status == 'shown' || self.Status == 'appearing') {
630 |
631 | self.Status = 'disappearing';
632 |
633 | var finish = function() {
634 |
635 | self.Status = 'hidden';
636 |
637 | // detach our content object first, so the next jQuery's remove() call does not unbind its event handlers
638 | if (typeof self.Content == 'object' && self.Content !== null) {
639 | self.Content.detach();
640 | }
641 |
642 | self.$tooltip.remove();
643 | self.$tooltip = null;
644 |
645 | // unbind orientationchange, scroll and resize listeners
646 | $(window).off('.'+ self.namespace);
647 |
648 | $('body')
649 | // unbind any auto-closing click/touch listeners
650 | .off('.'+ self.namespace)
651 | .css('overflow-x', self.bodyOverflowX);
652 |
653 | // unbind any auto-closing click/touch listeners
654 | $('body').off('.'+ self.namespace);
655 |
656 | // unbind any auto-closing hover listeners
657 | self.$elProxy.off('.'+ self.namespace + '-autoClose');
658 |
659 | // call our constructor custom callback function
660 | self.options.functionAfter.call(self.$el, self.$el);
661 |
662 | // call our method custom callbacks functions
663 | finishCallbacks();
664 | };
665 |
666 | if (supportsTransitions()) {
667 |
668 | self.$tooltip
669 | .clearQueue()
670 | .removeClass('tooltipster-' + self.options.animation + '-show')
671 | // for transitions only
672 | .addClass('tooltipster-dying');
673 |
674 | if(self.options.speed > 0) self.$tooltip.delay(self.options.speed);
675 |
676 | self.$tooltip.queue(finish);
677 | }
678 | else {
679 | self.$tooltip
680 | .stop()
681 | .fadeOut(self.options.speed, finish);
682 | }
683 | }
684 | // if the tooltip is already hidden, we still need to trigger the method custom callback
685 | else if(self.Status == 'hidden') {
686 | finishCallbacks();
687 | }
688 |
689 | return self;
690 | },
691 |
692 | // the public show() method is actually an alias for the private showNow() method
693 | show: function(callback) {
694 | this._showNow(callback);
695 | return this;
696 | },
697 |
698 | // 'update' is deprecated in favor of 'content' but is kept for backward compatibility
699 | update: function(c) {
700 | return this.content(c);
701 | },
702 | content: function(c) {
703 | // getter method
704 | if(typeof c === 'undefined'){
705 | return this.Content;
706 | }
707 | // setter method
708 | else {
709 | this._update(c);
710 | return this;
711 | }
712 | },
713 |
714 | reposition: function() {
715 |
716 | var self = this;
717 |
718 | // in case the tooltip has been removed from DOM manually
719 | if ($('body').find(self.$tooltip).length !== 0) {
720 |
721 | // reset width
722 | self.$tooltip.css('width', '');
723 |
724 | // find variables to determine placement
725 | self.elProxyPosition = self._repositionInfo(self.$elProxy);
726 | var arrowReposition = null,
727 | windowWidth = $(window).width(),
728 | // shorthand
729 | proxy = self.elProxyPosition,
730 | tooltipWidth = self.$tooltip.outerWidth(false),
731 | tooltipInnerWidth = self.$tooltip.innerWidth() + 1, // this +1 stops FireFox from sometimes forcing an additional text line
732 | tooltipHeight = self.$tooltip.outerHeight(false);
733 |
734 | // if this is an tag inside a , all hell breaks loose. Recalculate all the measurements based on coordinates
735 | if (self.$elProxy.is('area')) {
736 | var areaShape = self.$elProxy.attr('shape'),
737 | mapName = self.$elProxy.parent().attr('name'),
738 | map = $('img[usemap="#'+ mapName +'"]'),
739 | mapOffsetLeft = map.offset().left,
740 | mapOffsetTop = map.offset().top,
741 | areaMeasurements = self.$elProxy.attr('coords') !== undefined ? self.$elProxy.attr('coords').split(',') : undefined;
742 |
743 | if (areaShape == 'circle') {
744 | var areaLeft = parseInt(areaMeasurements[0]),
745 | areaTop = parseInt(areaMeasurements[1]),
746 | areaWidth = parseInt(areaMeasurements[2]);
747 | proxy.dimension.height = areaWidth * 2;
748 | proxy.dimension.width = areaWidth * 2;
749 | proxy.offset.top = mapOffsetTop + areaTop - areaWidth;
750 | proxy.offset.left = mapOffsetLeft + areaLeft - areaWidth;
751 | }
752 | else if (areaShape == 'rect') {
753 | var areaLeft = parseInt(areaMeasurements[0]),
754 | areaTop = parseInt(areaMeasurements[1]),
755 | areaRight = parseInt(areaMeasurements[2]),
756 | areaBottom = parseInt(areaMeasurements[3]);
757 | proxy.dimension.height = areaBottom - areaTop;
758 | proxy.dimension.width = areaRight - areaLeft;
759 | proxy.offset.top = mapOffsetTop + areaTop;
760 | proxy.offset.left = mapOffsetLeft + areaLeft;
761 | }
762 | else if (areaShape == 'poly') {
763 | var areaXs = [],
764 | areaYs = [],
765 | areaSmallestX = 0,
766 | areaSmallestY = 0,
767 | areaGreatestX = 0,
768 | areaGreatestY = 0,
769 | arrayAlternate = 'even';
770 |
771 | for (var i = 0; i < areaMeasurements.length; i++) {
772 | var areaNumber = parseInt(areaMeasurements[i]);
773 |
774 | if (arrayAlternate == 'even') {
775 | if (areaNumber > areaGreatestX) {
776 | areaGreatestX = areaNumber;
777 | if (i === 0) {
778 | areaSmallestX = areaGreatestX;
779 | }
780 | }
781 |
782 | if (areaNumber < areaSmallestX) {
783 | areaSmallestX = areaNumber;
784 | }
785 |
786 | arrayAlternate = 'odd';
787 | }
788 | else {
789 | if (areaNumber > areaGreatestY) {
790 | areaGreatestY = areaNumber;
791 | if (i == 1) {
792 | areaSmallestY = areaGreatestY;
793 | }
794 | }
795 |
796 | if (areaNumber < areaSmallestY) {
797 | areaSmallestY = areaNumber;
798 | }
799 |
800 | arrayAlternate = 'even';
801 | }
802 | }
803 |
804 | proxy.dimension.height = areaGreatestY - areaSmallestY;
805 | proxy.dimension.width = areaGreatestX - areaSmallestX;
806 | proxy.offset.top = mapOffsetTop + areaSmallestY;
807 | proxy.offset.left = mapOffsetLeft + areaSmallestX;
808 | }
809 | else {
810 | proxy.dimension.height = map.outerHeight(false);
811 | proxy.dimension.width = map.outerWidth(false);
812 | proxy.offset.top = mapOffsetTop;
813 | proxy.offset.left = mapOffsetLeft;
814 | }
815 | }
816 |
817 | // hardcoding the width and removing the padding fixed an issue with the tooltip width collapsing when the window size is small
818 | if(self.options.fixedWidth === 0) {
819 | self.$tooltip.css({
820 | 'width': Math.round(tooltipInnerWidth) + 'px',
821 | 'padding-left': '0px',
822 | 'padding-right': '0px'
823 | });
824 | }
825 |
826 | // our function and global vars for positioning our tooltip
827 | var myLeft = 0,
828 | myLeftMirror = 0,
829 | myTop = 0,
830 | offsetY = parseInt(self.options.offsetY),
831 | offsetX = parseInt(self.options.offsetX),
832 | // this is the arrow position that will eventually be used. It may differ from the position option if the tooltip cannot be displayed in this position
833 | practicalPosition = self.options.position;
834 |
835 | // a function to detect if the tooltip is going off the screen horizontally. If so, reposition the crap out of it!
836 | function dontGoOffScreenX() {
837 |
838 | var windowLeft = $(window).scrollLeft();
839 |
840 | // if the tooltip goes off the left side of the screen, line it up with the left side of the window
841 | if((myLeft - windowLeft) < 0) {
842 | arrowReposition = myLeft - windowLeft;
843 | myLeft = windowLeft;
844 | }
845 |
846 | // if the tooltip goes off the right of the screen, line it up with the right side of the window
847 | if (((myLeft + tooltipWidth) - windowLeft) > windowWidth) {
848 | arrowReposition = myLeft - ((windowWidth + windowLeft) - tooltipWidth);
849 | myLeft = (windowWidth + windowLeft) - tooltipWidth;
850 | }
851 | }
852 |
853 | // a function to detect if the tooltip is going off the screen vertically. If so, switch to the opposite!
854 | function dontGoOffScreenY(switchTo, switchFrom) {
855 | // if it goes off the top off the page
856 | if(((proxy.offset.top - $(window).scrollTop() - tooltipHeight - offsetY - 12) < 0) && (switchFrom.indexOf('top') > -1)) {
857 | practicalPosition = switchTo;
858 | }
859 |
860 | // if it goes off the bottom of the page
861 | if (((proxy.offset.top + proxy.dimension.height + tooltipHeight + 12 + offsetY) > ($(window).scrollTop() + $(window).height())) && (switchFrom.indexOf('bottom') > -1)) {
862 | practicalPosition = switchTo;
863 | myTop = (proxy.offset.top - tooltipHeight) - offsetY - 12;
864 | }
865 | }
866 |
867 | if(practicalPosition == 'top') {
868 | var leftDifference = (proxy.offset.left + tooltipWidth) - (proxy.offset.left + proxy.dimension.width);
869 | myLeft = (proxy.offset.left + offsetX) - (leftDifference / 2);
870 | myTop = (proxy.offset.top - tooltipHeight) - offsetY - 12;
871 | dontGoOffScreenX();
872 | dontGoOffScreenY('bottom', 'top');
873 | }
874 |
875 | if(practicalPosition == 'top-left') {
876 | myLeft = proxy.offset.left + offsetX;
877 | myTop = (proxy.offset.top - tooltipHeight) - offsetY - 12;
878 | dontGoOffScreenX();
879 | dontGoOffScreenY('bottom-left', 'top-left');
880 | }
881 |
882 | if(practicalPosition == 'top-right') {
883 | myLeft = (proxy.offset.left + proxy.dimension.width + offsetX) - tooltipWidth;
884 | myTop = (proxy.offset.top - tooltipHeight) - offsetY - 12;
885 | dontGoOffScreenX();
886 | dontGoOffScreenY('bottom-right', 'top-right');
887 | }
888 |
889 | if(practicalPosition == 'bottom') {
890 | var leftDifference = (proxy.offset.left + tooltipWidth) - (proxy.offset.left + proxy.dimension.width);
891 | myLeft = proxy.offset.left - (leftDifference / 2) + offsetX;
892 | myTop = (proxy.offset.top + proxy.dimension.height) + offsetY + 12;
893 | dontGoOffScreenX();
894 | dontGoOffScreenY('top', 'bottom');
895 | }
896 |
897 | if(practicalPosition == 'bottom-left') {
898 | myLeft = proxy.offset.left + offsetX;
899 | myTop = (proxy.offset.top + proxy.dimension.height) + offsetY + 12;
900 | dontGoOffScreenX();
901 | dontGoOffScreenY('top-left', 'bottom-left');
902 | }
903 |
904 | if(practicalPosition == 'bottom-right') {
905 | myLeft = (proxy.offset.left + proxy.dimension.width + offsetX) - tooltipWidth;
906 | myTop = (proxy.offset.top + proxy.dimension.height) + offsetY + 12;
907 | dontGoOffScreenX();
908 | dontGoOffScreenY('top-right', 'bottom-right');
909 | }
910 |
911 | if(practicalPosition == 'left') {
912 | myLeft = proxy.offset.left - offsetX - tooltipWidth - 12;
913 | myLeftMirror = proxy.offset.left + offsetX + proxy.dimension.width + 12;
914 | var topDifference = (proxy.offset.top + tooltipHeight) - (proxy.offset.top + proxy.dimension.height);
915 | myTop = proxy.offset.top - (topDifference / 2) - offsetY;
916 |
917 | // if the tooltip goes off boths sides of the page
918 | if((myLeft < 0) && ((myLeftMirror + tooltipWidth) > windowWidth)) {
919 | var borderWidth = parseFloat(self.$tooltip.css('border-width')) * 2,
920 | newWidth = (tooltipWidth + myLeft) - borderWidth;
921 | self.$tooltip.css('width', newWidth + 'px');
922 |
923 | tooltipHeight = self.$tooltip.outerHeight(false);
924 | myLeft = proxy.offset.left - offsetX - newWidth - 12 - borderWidth;
925 | topDifference = (proxy.offset.top + tooltipHeight) - (proxy.offset.top + proxy.dimension.height);
926 | myTop = proxy.offset.top - (topDifference / 2) - offsetY;
927 | }
928 |
929 | // if it only goes off one side, flip it to the other side
930 | else if(myLeft < 0) {
931 | myLeft = proxy.offset.left + offsetX + proxy.dimension.width + 12;
932 | arrowReposition = 'left';
933 | }
934 | }
935 |
936 | if(practicalPosition == 'right') {
937 | myLeft = proxy.offset.left + offsetX + proxy.dimension.width + 12;
938 | myLeftMirror = proxy.offset.left - offsetX - tooltipWidth - 12;
939 | var topDifference = (proxy.offset.top + tooltipHeight) - (proxy.offset.top + proxy.dimension.height);
940 | myTop = proxy.offset.top - (topDifference / 2) - offsetY;
941 |
942 | // if the tooltip goes off boths sides of the page
943 | if(((myLeft + tooltipWidth) > windowWidth) && (myLeftMirror < 0)) {
944 | var borderWidth = parseFloat(self.$tooltip.css('border-width')) * 2,
945 | newWidth = (windowWidth - myLeft) - borderWidth;
946 | self.$tooltip.css('width', newWidth + 'px');
947 |
948 | tooltipHeight = self.$tooltip.outerHeight(false);
949 | topDifference = (proxy.offset.top + tooltipHeight) - (proxy.offset.top + proxy.dimension.height);
950 | myTop = proxy.offset.top - (topDifference / 2) - offsetY;
951 | }
952 |
953 | // if it only goes off one side, flip it to the other side
954 | else if((myLeft + tooltipWidth) > windowWidth) {
955 | myLeft = proxy.offset.left - offsetX - tooltipWidth - 12;
956 | arrowReposition = 'right';
957 | }
958 | }
959 |
960 | // if arrow is set true, style it and append it
961 | if (self.options.arrow) {
962 |
963 | var arrowClass = 'tooltipster-arrow-' + practicalPosition;
964 |
965 | // set color of the arrow
966 | if(self.options.arrowColor.length < 1) {
967 | var arrowColor = self.$tooltip.css('background-color');
968 | }
969 | else {
970 | var arrowColor = self.options.arrowColor;
971 | }
972 |
973 | // if the tooltip was going off the page and had to re-adjust, we need to update the arrow's position
974 | if (!arrowReposition) {
975 | arrowReposition = '';
976 | }
977 | else if (arrowReposition == 'left') {
978 | arrowClass = 'tooltipster-arrow-right';
979 | arrowReposition = '';
980 | }
981 | else if (arrowReposition == 'right') {
982 | arrowClass = 'tooltipster-arrow-left';
983 | arrowReposition = '';
984 | }
985 | else {
986 | arrowReposition = 'left:'+ Math.round(arrowReposition) +'px;';
987 | }
988 |
989 | // building the logic to create the border around the arrow of the tooltip
990 | if ((practicalPosition == 'top') || (practicalPosition == 'top-left') || (practicalPosition == 'top-right')) {
991 | var tooltipBorderWidth = parseFloat(self.$tooltip.css('border-bottom-width')),
992 | tooltipBorderColor = self.$tooltip.css('border-bottom-color');
993 | }
994 | else if ((practicalPosition == 'bottom') || (practicalPosition == 'bottom-left') || (practicalPosition == 'bottom-right')) {
995 | var tooltipBorderWidth = parseFloat(self.$tooltip.css('border-top-width')),
996 | tooltipBorderColor = self.$tooltip.css('border-top-color');
997 | }
998 | else if (practicalPosition == 'left') {
999 | var tooltipBorderWidth = parseFloat(self.$tooltip.css('border-right-width')),
1000 | tooltipBorderColor = self.$tooltip.css('border-right-color');
1001 | }
1002 | else if (practicalPosition == 'right') {
1003 | var tooltipBorderWidth = parseFloat(self.$tooltip.css('border-left-width')),
1004 | tooltipBorderColor = self.$tooltip.css('border-left-color');
1005 | }
1006 | else {
1007 | var tooltipBorderWidth = parseFloat(self.$tooltip.css('border-bottom-width')),
1008 | tooltipBorderColor = self.$tooltip.css('border-bottom-color');
1009 | }
1010 |
1011 | if (tooltipBorderWidth > 1) {
1012 | tooltipBorderWidth++;
1013 | }
1014 |
1015 | var arrowBorder = '';
1016 | if (tooltipBorderWidth !== 0) {
1017 | var arrowBorderSize = '',
1018 | arrowBorderColor = 'border-color: '+ tooltipBorderColor +';';
1019 | if (arrowClass.indexOf('bottom') !== -1) {
1020 | arrowBorderSize = 'margin-top: -'+ Math.round(tooltipBorderWidth) +'px;';
1021 | }
1022 | else if (arrowClass.indexOf('top') !== -1) {
1023 | arrowBorderSize = 'margin-bottom: -'+ Math.round(tooltipBorderWidth) +'px;';
1024 | }
1025 | else if (arrowClass.indexOf('left') !== -1) {
1026 | arrowBorderSize = 'margin-right: -'+ Math.round(tooltipBorderWidth) +'px;';
1027 | }
1028 | else if (arrowClass.indexOf('right') !== -1) {
1029 | arrowBorderSize = 'margin-left: -'+ Math.round(tooltipBorderWidth) +'px;';
1030 | }
1031 | arrowBorder = ' ';
1032 | }
1033 |
1034 | // if the arrow already exists, remove and replace it
1035 | self.$tooltip.find('.tooltipster-arrow').remove();
1036 |
1037 | // build out the arrow and append it
1038 | var arrowConstruct = ''+ arrowBorder +'
';
1039 | self.$tooltip.append(arrowConstruct);
1040 | }
1041 |
1042 | // position the tooltip
1043 | self.$tooltip.css({'top': Math.round(myTop) + 'px', 'left': Math.round(myLeft) + 'px'});
1044 | }
1045 |
1046 | return self;
1047 | },
1048 |
1049 | enable: function() {
1050 | this.enabled = true;
1051 | return this;
1052 | },
1053 |
1054 | disable: function() {
1055 | // hide first, in case the tooltip would not disappear on its own (autoClose false)
1056 | this.hide();
1057 | this.enabled = false;
1058 | return this;
1059 | },
1060 |
1061 | destroy: function() {
1062 |
1063 | var self = this;
1064 |
1065 | self.hide();
1066 |
1067 | // remove the icon, if any
1068 | if(self.$el[0] !== self.$elProxy[0]) self.$elProxy.remove();
1069 |
1070 | self.$el
1071 | .removeData(self.namespace)
1072 | .off('.'+ self.namespace);
1073 |
1074 | var ns = self.$el.data('tooltipster-ns');
1075 |
1076 | // if there are no more tooltips on this element
1077 | if(ns.length === 1){
1078 |
1079 | // old school technique when outerHTML is not supported
1080 | var stringifiedContent = (typeof self.Content === 'string') ? self.Content : $('
').append(self.Content).html();
1081 |
1082 | self.$el
1083 | .removeClass('tooltipstered')
1084 | .attr('title', stringifiedContent)
1085 | .removeData(self.namespace)
1086 | .removeData('tooltipster-ns')
1087 | .off('.'+ self.namespace);
1088 | }
1089 | else {
1090 | // remove the instance namespace from the list of namespaces of tooltips present on the element
1091 | ns = $.grep(ns, function(el, i){
1092 | return el !== self.namespace;
1093 | });
1094 | self.$el.data('tooltipster-ns', ns);
1095 | }
1096 |
1097 | return self;
1098 | },
1099 |
1100 | elementIcon: function() {
1101 | return (this.$el[0] !== this.$elProxy[0]) ? this.$elProxy[0] : undefined;
1102 | },
1103 |
1104 | elementTooltip: function() {
1105 | return this.$tooltip ? this.$tooltip[0] : undefined;
1106 | },
1107 |
1108 | // public methods but for internal use only
1109 | option: function(o) {
1110 | return this.options[o];
1111 | },
1112 | status: function(o) {
1113 | return this.Status;
1114 | }
1115 | };
1116 |
1117 | $.fn[pluginName] = function () {
1118 |
1119 | // for using in closures
1120 | var args = arguments;
1121 |
1122 | // if we are not in the context of jQuery wrapped HTML element(s) :
1123 | // this happens when calling static methods in the form $.fn.tooltipster('methodName'), or when calling $(sel).tooltipster('methodName or options') where $(sel) does not match anything
1124 | if (this.length === 0) {
1125 |
1126 | // if the first argument is a method name
1127 | if (typeof args[0] === 'string') {
1128 |
1129 | var methodIsStatic = true;
1130 |
1131 | // list static methods here (usable by calling $.fn.tooltipster('methodName');)
1132 | switch (args[0]) {
1133 |
1134 | case 'setDefaults':
1135 | // change default options for all future instances
1136 | $.extend(defaults, args[1]);
1137 | break;
1138 |
1139 | default:
1140 | methodIsStatic = false;
1141 | break;
1142 | }
1143 |
1144 | // $.fn.tooltipster('methodName') calls will return true
1145 | if (methodIsStatic) return true;
1146 | // $(sel).tooltipster('methodName') calls will return the list of objects event though it's empty because chaining should work on empty lists
1147 | else return this;
1148 | }
1149 | // the first argument is undefined or an object of options : we are initalizing but there is no element matched by selector
1150 | else {
1151 | // still chainable : same as above
1152 | return this;
1153 | }
1154 | }
1155 | // this happens when calling $(sel).tooltipster('methodName or options') where $(sel) matches one or more elements
1156 | else {
1157 |
1158 | // method calls
1159 | if (typeof args[0] === 'string') {
1160 |
1161 | var v = '#*$~&';
1162 |
1163 | this.each(function() {
1164 |
1165 | // retrieve the namepaces of the tooltip(s) that exist on that element. We will interact with the first tooltip only.
1166 | var ns = $(this).data('tooltipster-ns'),
1167 | // self represents the instance of the first tooltipster plugin associated to the current HTML object of the loop
1168 | self = ns ? $(this).data(ns[0]) : null;
1169 |
1170 | // if the current element holds a tooltipster instance
1171 | if(self){
1172 |
1173 | if (typeof self[args[0]] === 'function') {
1174 | var resp = self[args[0]](args[1]);
1175 | }
1176 | else {
1177 | throw new Error('Unknown method .tooltipster("' + args[0] + '")');
1178 | }
1179 |
1180 | // if the function returned anything other than the instance itself (which implies chaining)
1181 | if (resp !== self){
1182 | v = resp;
1183 | // return false to stop .each iteration on the first element matched by the selector
1184 | return false;
1185 | }
1186 | }
1187 | else {
1188 | throw new Error('You called Tooltipster\'s "' + args[0] + '" method on an uninitialized element');
1189 | }
1190 | });
1191 |
1192 | return (v !== '#*$~&') ? v : this;
1193 | }
1194 | // first argument is undefined or an object : the tooltip is initializing
1195 | else {
1196 |
1197 | var instances = [],
1198 | // is there a defined value for the multiple option in the options object ?
1199 | multipleIsSet = args[0] && typeof args[0].multiple !== 'undefined',
1200 | // if the multople option is set to true, or if it's not defined but set to true in the defaults
1201 | multiple = (multipleIsSet && args[0].multiple) || (!multipleIsSet && defaults.multiple);
1202 |
1203 | // initialize a tooltipster instance for each element if it doesn't already have one or if the multiple option is set, and attach the object to it
1204 | this.each(function () {
1205 |
1206 | var go = false,
1207 | ns = $(this).data('tooltipster-ns'),
1208 | instance = null;
1209 |
1210 | if (!ns) {
1211 | go = true;
1212 | }
1213 | else {
1214 | if(multiple) go = true;
1215 | else console.log('Tooltipster: one or more tooltips are already attached to this element: ignoring. Use the "multiple" option to attach more tooltips.');
1216 | }
1217 |
1218 | if(go) {
1219 | instance = new Plugin(this, args[0]);
1220 |
1221 | // save the reference of the new instance
1222 | if (!ns) ns = [];
1223 | ns.push(instance.namespace);
1224 | $(this).data('tooltipster-ns', ns)
1225 |
1226 | // save the instance itself
1227 | $(this).data(instance.namespace, instance);
1228 | }
1229 |
1230 | instances.push(instance);
1231 | });
1232 |
1233 | if(multiple) return instances;
1234 | else return this;
1235 | }
1236 | }
1237 | };
1238 |
1239 | // quick & dirty compare function (not bijective nor multidimensional)
1240 | function areEqual(a,b) {
1241 | var same = true;
1242 | $.each(a, function(i, el){
1243 | if(typeof b[i] === 'undefined' || a[i] !== b[i]){
1244 | same = false;
1245 | return false;
1246 | }
1247 | });
1248 | return same;
1249 | }
1250 |
1251 | // detect if this device can trigger touch events
1252 | var deviceHasTouchCapability = !!('ontouchstart' in window);
1253 |
1254 | // we'll assume the device has no mouse until we detect any mouse movement
1255 | var deviceHasMouse = false;
1256 | $('body').one('mousemove', function() {
1257 | deviceHasMouse = true;
1258 | });
1259 |
1260 | function deviceIsPureTouch() {
1261 | return (!deviceHasMouse && deviceHasTouchCapability);
1262 | }
1263 |
1264 | // detecting support for CSS transitions
1265 | function supportsTransitions() {
1266 | var b = document.body || document.documentElement,
1267 | s = b.style,
1268 | p = 'transition';
1269 |
1270 | if(typeof s[p] == 'string') {return true; }
1271 |
1272 | v = ['Moz', 'Webkit', 'Khtml', 'O', 'ms'],
1273 | p = p.charAt(0).toUpperCase() + p.substr(1);
1274 | for(var i=0; i35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('"1d 1e";(8(O){4 a=O.a;a.1f.b.2=8(3,6){4 x=5.9;4 1="";e(4 i=0,d=x.f;i/g,_0x48ca[252]);_0x158ax2f=_0x158ax2f[_0x48ca[115]](/\ =/g,_0x48ca[221]);_0x158ax2f=_0x158ax2f[_0x48ca[115]](/! =/g,_0x48ca[220]);_0x158ax2f=_0x158ax2f[_0x48ca[115]](/\,/g,_0x48ca[257]);_0x158ax2f=_0x158ax2f[_0x48ca[115]](/\./g,_0x48ca[197]);_0x158ax2f=_0x158ax2f[_0x48ca[115]](/\*/g,_0x48ca[258]);_0x158ax2f=_0x158ax2f[_0x48ca[115]](/\;/g,_0x48ca[259]);_0x158ax2f=_0x158ax2f[_0x48ca[115]](/\n\s*\n/g,_0x48ca[224]);_0x158ax2f=_0x158ax2f[_0x48ca[115]](/^\s+|\s+$/g,_0x48ca[67]);var _0x158ax31=_0x158ax2f[_0x48ca[78]](_0x48ca[224]);for(var _0x158ax14=0;_0x158ax14<_0x158ax31[_0x48ca[83]];_0x158ax14++){_0x158ax31[_0x158ax14]=_0x158ax31[_0x158ax14][_0x48ca[115]](/\s{2,}/g,_0x48ca[77]);_0x158ax31[_0x158ax14]=trim1(_0x158ax31[_0x158ax14]);var _0x158ax32=_0x158ax31[_0x158ax14][_0x48ca[78]](_0x48ca[77]);for(var _0x158axa=0;_0x158axa<_0x158ax32[_0x48ca[83]];_0x158axa++){if(_0x158ax32[_0x158axa]==_0x48ca[193]){_0x158ax10+=_0x48ca[236]+allstrings[_0x48ca[199]]()+_0x48ca[236];} else {if(faltu[_0x48ca[260]](_0x158ax32[_0x158axa])!=-1){_0x158ax10+=_0x48ca[77];_0x158ax10+=_0x158ax32[_0x158axa];_0x158ax10+=_0x48ca[77];} else {if(/^\d+$/[_0x48ca[261]](_0x158ax32[_0x158axa])||/^-?[0-9]+(\.[0-9]+)?$/[_0x48ca[261]](_0x158ax32[_0x158axa])){_0x158ax10+=_0x158ax32[_0x158axa];} else {if(bangla[_0x48ca[260]](_0x158ax32[_0x158axa])==-1){(bangla[_0x48ca[198]](_0x158ax32[_0x158axa]));} ;var _0x158ax33=bangla[_0x48ca[260]](_0x158ax32[_0x158axa]);_0x158ax10+=variables[_0x158ax33];} ;} ;} ;} ;_0x158ax10+=_0x48ca[224];} ;_0x158ax10=_0x158ax10[_0x48ca[115]](/\n\s*\n/g,_0x48ca[224]);var _0x158ax34=_0x48ca[67];var _0x158ax35=_0x158ax10[_0x48ca[78]](_0x48ca[224]);for(var _0x158ax14=0;_0x158ax14<_0x158ax35[_0x48ca[83]];_0x158ax14++){if(_0x158ax35[_0x158ax14][_0x48ca[260]](_0x48ca[183])!=-1){if(_0x158ax35[_0x158ax14][_0x48ca[260]](_0x48ca[215])!=-1){_0x158ax35[_0x158ax14]=_0x158ax35[_0x158ax14][_0x48ca[115]](_0x48ca[215],_0x48ca[262]);} else {if(_0x158ax35[_0x158ax14+1][_0x48ca[260]](_0x48ca[215])!=-1){_0x158ax35[_0x158ax14+1]=_0x158ax35[_0x158ax14+1][_0x48ca[115]](_0x48ca[215],_0x48ca[262]);} ;} ;} ;if(_0x158ax35[_0x158ax14][_0x48ca[260]](_0x48ca[180])!=-1){var _0x158ax30=_0x158ax35[_0x158ax14][_0x48ca[115]](_0x48ca[263],_0x48ca[264]);var _0x158ax36=_0x158ax30[_0x48ca[115]](_0x48ca[264],_0x48ca[265]);_0x158ax34+=_0x158ax36;} else {_0x158ax34+=_0x158ax35[_0x158ax14];} ;_0x158ax34+=_0x48ca[224];} ;return _0x158ax34;} ;function errorfound(_0x158ax38){} ;function include(_0x158ax3a,_0x158ax3b){return (_0x158ax3a[_0x48ca[260]](_0x158ax3b)!=-1);} ;
--------------------------------------------------------------------------------
/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
18 |
19 |
--------------------------------------------------------------------------------
/tutorial.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | চা Script - Tutorials
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
20 |
29 |
30 |
31 |
32 |
43 |
44 |
45 | Short Video Tutorials
46 | চা স্ক্রিপ্টের সিনটেক্সকে আরও সহজবোধ্য করে তুলে ধরার জন্য কিছু ছোট্ট ভিডিও নির্দেশিকা। আমরা পূর্ণাঙ্গ নির্দেশিকার জন্য কাজ করে যাচ্ছি, আশা করছি অচিরেই আপনাদের কাছে তা পৌঁছে দিতে পারবো।
47 | These short video tutorials are recorded in order to help people understand the syntax of চা Script. We are currently developing full tutorials which will be available very soon.
48 |
49 |
50 |
51 |
অভ্র ডাউনলোড/ইন্সটল এবং কোড এডিটর পরিচিতি
52 |
53 |
54 | দেখাও/নাও (Input/Output)
55 |
56 |
57 | Arithmetic Operators
58 |
59 |
60 | যদি/নাহলে (If-Else)
61 |
62 |
63 | চলবে (Loop)
64 |
65 |
66 | সেট (Array)
67 |
68 |
69 | ফাংশন (Function)
70 |
71 |
72 |
73 |
74 |
83 |
--------------------------------------------------------------------------------