blob: 120a9530c881f1e635cc12462659299cf3d67f3a [file] [log] [blame]
Nils Diewald0e6992a2015-04-14 20:13:52 +00001// Input field for queries
Akron308db382016-05-30 22:34:07 +02002/*
3 * TODO: Support allert for query problems.
4 */
5
Nils Diewald0e6992a2015-04-14 20:13:52 +00006define({
Nils Diewald7148c6f2015-05-04 15:07:53 +00007
8 /**
9 * Create a new input field.
10 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000011 create : function (element) {
12 return Object.create(this)._init(element);
13 },
Nils Diewald0e6992a2015-04-14 20:13:52 +000014
Nils Diewald0e6992a2015-04-14 20:13:52 +000015
Nils Diewald7148c6f2015-05-04 15:07:53 +000016 /**
17 * Get the mirrored input field.
18 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000019 mirror : function () {
20 return this._mirror;
21 },
22
Nils Diewald7148c6f2015-05-04 15:07:53 +000023
24 /**
25 * Get the container element.
Akron308db382016-05-30 22:34:07 +020026 * This contains the hint helper / menus
27 * and probably an
28 * error message.
Nils Diewald7148c6f2015-05-04 15:07:53 +000029 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000030 container : function () {
31 return this._container;
32 },
33
Nils Diewald7148c6f2015-05-04 15:07:53 +000034
35 /**
36 * Get the input element the
37 * hint helper is attached to.
38 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000039 element : function () {
40 return this._element;
41 },
42
Akron308db382016-05-30 22:34:07 +020043
Nils Diewald7148c6f2015-05-04 15:07:53 +000044 /**
45 * Get the value of the input field
46 * the hint helper is attached to.
47 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000048 value : function () {
49 return this._element.value;
50 },
51
Akronc14cbfc2018-08-31 13:15:55 +020052
Akron00cd4d12016-05-31 21:01:11 +020053 /**
54 * Get the value of the input field mirror.
55 */
56 mirrorValue : function () {
57 return this._mirror.firstChild.textContent;
58 },
59
Nils Diewald7148c6f2015-05-04 15:07:53 +000060
61 /**
Akronc14cbfc2018-08-31 13:15:55 +020062 * Reset the input value
Akron95abaf42018-04-26 15:33:22 +020063 */
64 reset : function () {
65 this._element.value = "";
66 },
67
68
69 /**
Nils Diewald7148c6f2015-05-04 15:07:53 +000070 * Update the mirror content.
71 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000072 update : function () {
Nils Diewald7148c6f2015-05-04 15:07:53 +000073 this._mirror.firstChild.textContent = this._split()[0];
74 this._container.style.left = this._rightPos() + 'px';
Akron308db382016-05-30 22:34:07 +020075 return this;
Nils Diewald0e6992a2015-04-14 20:13:52 +000076 },
77
Akron308db382016-05-30 22:34:07 +020078
Nils Diewald7148c6f2015-05-04 15:07:53 +000079 /**
80 * Insert text into the mirror.
81 * This is a prefix of the input field's
82 * value.
83 */
Nils Diewald0e6992a2015-04-14 20:13:52 +000084 insert : function (text) {
Nils Diewald7148c6f2015-05-04 15:07:53 +000085 var splittedText = this._split();
Nils Diewald0e6992a2015-04-14 20:13:52 +000086 var s = this._element;
87 s.value = splittedText[0] + text + splittedText[1];
88 s.selectionStart = (splittedText[0] + text).length;
89 s.selectionEnd = s.selectionStart;
Akron308db382016-05-30 22:34:07 +020090
91 // Maybe update?
Nils Diewald0e6992a2015-04-14 20:13:52 +000092 this._mirror.firstChild.textContent = splittedText[0] + text;
Akron308db382016-05-30 22:34:07 +020093 return this;
Nils Diewald0e6992a2015-04-14 20:13:52 +000094 },
Akron308db382016-05-30 22:34:07 +020095
96 /**
97 * Move hinthelper to given character position
98 */
99 moveto : function (charpos) {
100 this._element.selectionStart = charpos;
101 this._element.selectionEnd = charpos;
102 this._element.focus();
103 return this.update();
104 },
Nils Diewald0e6992a2015-04-14 20:13:52 +0000105
Nils Diewald7148c6f2015-05-04 15:07:53 +0000106 /**
107 * Reposition the input mirror directly
108 * below the input box.
109 */
Nils Diewald0e6992a2015-04-14 20:13:52 +0000110 reposition : function () {
111 var inputClientRect = this._element.getBoundingClientRect();
112 var inputStyle = window.getComputedStyle(this._element, null);
113
114 var bodyClientRect =
115 document.getElementsByTagName('body')[0].getBoundingClientRect();
116
117 // Reset position
118 var mirrorStyle = this._mirror.style;
Akron5336fd42020-10-09 18:13:51 +0200119 mirrorStyle.left = parseInt(inputClientRect.left) + "px";
120 mirrorStyle.top = parseInt(inputClientRect.bottom - bodyClientRect.top) + "px";
Nils Diewald0e6992a2015-04-14 20:13:52 +0000121 mirrorStyle.width = inputStyle.getPropertyValue("width");
Akron5336fd42020-10-09 18:13:51 +0200122
Nils Diewald0e6992a2015-04-14 20:13:52 +0000123 // These may be relevant in case of media depending css
124 mirrorStyle.paddingLeft = inputStyle.getPropertyValue("padding-left");
125 mirrorStyle.marginLeft = inputStyle.getPropertyValue("margin-left");
126 mirrorStyle.borderLeftWidth = inputStyle.getPropertyValue("border-left-width");
127 mirrorStyle.borderLeftStyle = inputStyle.getPropertyValue("border-left-style");
128 mirrorStyle.fontSize = inputStyle.getPropertyValue("font-size");
129 mirrorStyle.fontFamily = inputStyle.getPropertyValue("font-family");
130 },
Nils Diewald7148c6f2015-05-04 15:07:53 +0000131
Akron308db382016-05-30 22:34:07 +0200132
Nils Diewald7148c6f2015-05-04 15:07:53 +0000133 /**
134 * Get the context, which is the input
135 * field's value bounded to the
136 * cursor position.
137 */
Nils Diewald0e6992a2015-04-14 20:13:52 +0000138 context : function () {
Nils Diewald7148c6f2015-05-04 15:07:53 +0000139 return this._split()[0];
140 },
141
Akronc14cbfc2018-08-31 13:15:55 +0200142
Akron308db382016-05-30 22:34:07 +0200143 // Initialize new input field
144 _init : function (element) {
145 this._element = element;
146
147 // Create mirror for searchField
148 // This is important for positioning
Akron00cd4d12016-05-31 21:01:11 +0200149 // if ((this._mirror = document.getElementById("searchMirror")) === null) {
Akroncae907d2018-08-20 17:22:15 +0200150 this._mirror = document.createElement("div");
151 this._mirror.classList.add('hint', 'mirror');
152 this._mirror.appendChild(document.createElement("span"));
153 this._container = document.createElement("div");
hebasta75cfca52019-02-19 13:15:27 +0100154 this._container.setAttribute('id', 'hint');
155
Akroncae907d2018-08-20 17:22:15 +0200156 this._mirror.appendChild(this._container);
157 this._mirror.style.height = "0px";
158 document.getElementsByTagName("body")[0].appendChild(this._mirror);
159 // };
Akron308db382016-05-30 22:34:07 +0200160
161 // Update position of the mirror
162 window.addEventListener('resize', this.reposition.bind(this));
163 this._element.addEventListener('onfocus', this.reposition.bind(this));
164 this.reposition();
165 return this;
166 },
167
Akronc14cbfc2018-08-31 13:15:55 +0200168
Akron308db382016-05-30 22:34:07 +0200169 // Get the right position
170 _rightPos : function () {
171 var box = this._mirror.firstChild.getBoundingClientRect();
172 return box.right - box.left;
173 },
174
175
Nils Diewald7148c6f2015-05-04 15:07:53 +0000176 /*
177 * Return two substrings,
Akron308db382016-05-30 22:34:07 +0200178 * splitted at a given position
179 * or at the current cursor position.
Nils Diewald7148c6f2015-05-04 15:07:53 +0000180 */
Akron308db382016-05-30 22:34:07 +0200181 _split : function (start) {
Nils Diewald7148c6f2015-05-04 15:07:53 +0000182 var s = this._element;
183 var value = s.value;
Akron308db382016-05-30 22:34:07 +0200184
185 // Get start from cursor position
186 if (arguments.length === 0)
187 start = s.selectionStart;
188
Nils Diewald7148c6f2015-05-04 15:07:53 +0000189 return new Array(
190 value.substring(0, start),
191 value.substring(start, value.length)
192 );
Nils Diewald0e6992a2015-04-14 20:13:52 +0000193 }
194});