input.plugin.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /**
  2. * Input(TODO resize)
  3. * @param {type} $
  4. * @param {type} window
  5. * @param {type} document
  6. * @returns {undefined}
  7. */
  8. (function($, window, document) {
  9. var CLASS_ICON = $.className('icon');
  10. var CLASS_ICON_CLEAR = $.className('icon-clear');
  11. var CLASS_ICON_SPEECH = $.className('icon-speech');
  12. var CLASS_ICON_SEARCH = $.className('icon-search');
  13. var CLASS_ICON_PASSWORD = $.className('icon-eye');
  14. var CLASS_INPUT_ROW = $.className('input-row');
  15. var CLASS_PLACEHOLDER = $.className('placeholder');
  16. var CLASS_TOOLTIP = $.className('tooltip');
  17. var CLASS_HIDDEN = $.className('hidden');
  18. var CLASS_FOCUSIN = $.className('focusin');
  19. var SELECTOR_ICON_CLOSE = '.' + CLASS_ICON_CLEAR;
  20. var SELECTOR_ICON_SPEECH = '.' + CLASS_ICON_SPEECH;
  21. var SELECTOR_ICON_PASSWORD = '.' + CLASS_ICON_PASSWORD;
  22. var SELECTOR_PLACEHOLDER = '.' + CLASS_PLACEHOLDER;
  23. var SELECTOR_TOOLTIP = '.' + CLASS_TOOLTIP;
  24. var findRow = function(target) {
  25. for (; target && target !== document; target = target.parentNode) {
  26. if (target.classList && target.classList.contains(CLASS_INPUT_ROW)) {
  27. return target;
  28. }
  29. }
  30. return null;
  31. };
  32. var Input = function(element, options) {
  33. this.element = element;
  34. this.options = options || {
  35. actions: 'clear'
  36. };
  37. if (~this.options.actions.indexOf('slider')) { //slider
  38. this.sliderActionClass = CLASS_TOOLTIP + ' ' + CLASS_HIDDEN;
  39. this.sliderActionSelector = SELECTOR_TOOLTIP;
  40. } else { //clear,speech,search
  41. if (~this.options.actions.indexOf('clear')) {
  42. this.clearActionClass = CLASS_ICON + ' ' + CLASS_ICON_CLEAR + ' ' + CLASS_HIDDEN;
  43. this.clearActionSelector = SELECTOR_ICON_CLOSE;
  44. }
  45. if (~this.options.actions.indexOf('speech')) { //only for 5+
  46. this.speechActionClass = CLASS_ICON + ' ' + CLASS_ICON_SPEECH;
  47. this.speechActionSelector = SELECTOR_ICON_SPEECH;
  48. }
  49. if (~this.options.actions.indexOf('search')) {
  50. this.searchActionClass = CLASS_PLACEHOLDER;
  51. this.searchActionSelector = SELECTOR_PLACEHOLDER;
  52. }
  53. if (~this.options.actions.indexOf('password')) {
  54. this.passwordActionClass = CLASS_ICON + ' ' + CLASS_ICON_PASSWORD;
  55. this.passwordActionSelector = SELECTOR_ICON_PASSWORD;
  56. }
  57. }
  58. this.init();
  59. };
  60. Input.prototype.init = function() {
  61. this.initAction();
  62. this.initElementEvent();
  63. };
  64. Input.prototype.initAction = function() {
  65. var self = this;
  66. var row = self.element.parentNode;
  67. if (row) {
  68. if (self.sliderActionClass) {
  69. self.sliderAction = self.createAction(row, self.sliderActionClass, self.sliderActionSelector);
  70. } else {
  71. if (self.searchActionClass) {
  72. self.searchAction = self.createAction(row, self.searchActionClass, self.searchActionSelector);
  73. self.searchAction.addEventListener('tap', function(e) {
  74. $.focus(self.element);
  75. e.stopPropagation();
  76. });
  77. }
  78. if (self.speechActionClass) {
  79. self.speechAction = self.createAction(row, self.speechActionClass, self.speechActionSelector);
  80. self.speechAction.addEventListener('click', $.stopPropagation);
  81. self.speechAction.addEventListener('tap', function(event) {
  82. self.speechActionClick(event);
  83. });
  84. }
  85. if (self.clearActionClass) {
  86. self.clearAction = self.createAction(row, self.clearActionClass, self.clearActionSelector);
  87. self.clearAction.addEventListener('tap', function(event) {
  88. self.clearActionClick(event);
  89. });
  90. }
  91. if (self.passwordActionClass) {
  92. self.passwordAction = self.createAction(row, self.passwordActionClass, self.passwordActionSelector);
  93. self.passwordAction.addEventListener('tap', function(event) {
  94. self.passwordActionClick(event);
  95. });
  96. }
  97. }
  98. }
  99. };
  100. Input.prototype.createAction = function(row, actionClass, actionSelector) {
  101. var action = row.querySelector(actionSelector);
  102. if (!action) {
  103. var action = document.createElement('span');
  104. action.className = actionClass;
  105. if (actionClass === this.searchActionClass) {
  106. action.innerHTML = '<span class="' + CLASS_ICON + ' ' + CLASS_ICON_SEARCH + '"></span><span>' + this.element.getAttribute('placeholder') + '</span>';
  107. this.element.setAttribute('placeholder', '');
  108. if (this.element.value.trim()) {
  109. row.classList.add($.className('active'));
  110. }
  111. }
  112. row.insertBefore(action, this.element.nextSibling);
  113. }
  114. return action;
  115. };
  116. Input.prototype.initElementEvent = function() {
  117. var element = this.element;
  118. if (this.sliderActionClass) {
  119. var tooltip = this.sliderAction;
  120. var timer = null;
  121. var showTip = function() { //每次重新计算是因为控件可能被隐藏,初始化时计算是不正确的
  122. tooltip.classList.remove(CLASS_HIDDEN);
  123. var offsetLeft = element.offsetLeft;
  124. var width = element.offsetWidth - 28;
  125. var tooltipWidth = tooltip.offsetWidth;
  126. var distince = Math.abs(element.max - element.min);
  127. var scaleWidth = (width / distince) * Math.abs(element.value - element.min);
  128. tooltip.style.left = (14 + offsetLeft + scaleWidth - tooltipWidth / 2) + 'px';
  129. tooltip.innerText = element.value;
  130. if (timer) {
  131. clearTimeout(timer);
  132. }
  133. timer = setTimeout(function() {
  134. tooltip.classList.add(CLASS_HIDDEN);
  135. }, 1000);
  136. };
  137. element.addEventListener('input', showTip);
  138. element.addEventListener('tap', showTip);
  139. element.addEventListener($.EVENT_MOVE, function(e) {
  140. e.stopPropagation();
  141. });
  142. } else {
  143. if (this.clearActionClass) {
  144. var action = this.clearAction;
  145. if (!action) {
  146. return;
  147. }
  148. $.each(['keyup', 'change', 'input', 'focus', 'cut', 'paste'], function(index, type) {
  149. (function(type) {
  150. element.addEventListener(type, function() {
  151. action.classList[element.value.trim() ? 'remove' : 'add'](CLASS_HIDDEN);
  152. });
  153. })(type);
  154. });
  155. element.addEventListener('blur', function() {
  156. action.classList.add(CLASS_HIDDEN);
  157. });
  158. }
  159. if (this.searchActionClass) {
  160. element.addEventListener('focus', function() {
  161. element.parentNode.classList.add($.className('active'));
  162. });
  163. element.addEventListener('blur', function() {
  164. if (!element.value.trim()) {
  165. element.parentNode.classList.remove($.className('active'));
  166. }
  167. });
  168. }
  169. }
  170. };
  171. Input.prototype.setPlaceholder = function(text) {
  172. if (this.searchActionClass) {
  173. var placeholder = this.element.parentNode.querySelector(SELECTOR_PLACEHOLDER);
  174. placeholder && (placeholder.getElementsByTagName('span')[1].innerText = text);
  175. } else {
  176. this.element.setAttribute('placeholder', text);
  177. }
  178. };
  179. Input.prototype.passwordActionClick = function(event) {
  180. if (this.element.type === 'text') {
  181. this.element.type = 'password';
  182. } else {
  183. this.element.type = 'text';
  184. }
  185. this.passwordAction.classList.toggle($.className('active'));
  186. event.preventDefault();
  187. };
  188. Input.prototype.clearActionClick = function(event) {
  189. var self = this;
  190. self.element.value = '';
  191. $.focus(self.element);
  192. self.clearAction.classList.add(CLASS_HIDDEN);
  193. event.preventDefault();
  194. };
  195. Input.prototype.speechActionClick = function(event) {
  196. if (window.plus) {
  197. var self = this;
  198. var oldValue = self.element.value;
  199. self.element.value = '';
  200. document.body.classList.add(CLASS_FOCUSIN);
  201. plus.speech.startRecognize({
  202. engine: 'iFly'
  203. }, function(s) {
  204. self.element.value += s;
  205. $.focus(self.element);
  206. plus.speech.stopRecognize();
  207. $.trigger(self.element, 'recognized', {
  208. value: self.element.value
  209. });
  210. if (oldValue !== self.element.value) {
  211. $.trigger(self.element, 'change');
  212. $.trigger(self.element, 'input');
  213. }
  214. // document.body.classList.remove(CLASS_FOCUSIN);
  215. }, function(e) {
  216. document.body.classList.remove(CLASS_FOCUSIN);
  217. });
  218. } else {
  219. alert('only for 5+');
  220. }
  221. event.preventDefault();
  222. };
  223. $.fn.input = function(options) {
  224. var inputApis = [];
  225. this.each(function() {
  226. var inputApi = null;
  227. var actions = [];
  228. var row = findRow(this.parentNode);
  229. if (this.type === 'range' && row.classList.contains($.className('input-range'))) {
  230. actions.push('slider');
  231. } else {
  232. var classList = this.classList;
  233. if (classList.contains($.className('input-clear'))) {
  234. actions.push('clear');
  235. }
  236. if (!($.os.android && $.os.stream) && classList.contains($.className('input-speech'))) {
  237. actions.push('speech');
  238. }
  239. if (classList.contains($.className('input-password'))) {
  240. actions.push('password');
  241. }
  242. if (this.type === 'search' && row.classList.contains($.className('search'))) {
  243. actions.push('search');
  244. }
  245. }
  246. var id = this.getAttribute('data-input-' + actions[0]);
  247. if (!id) {
  248. id = ++$.uuid;
  249. inputApi = $.data[id] = new Input(this, {
  250. actions: actions.join(',')
  251. });
  252. for (var i = 0, len = actions.length; i < len; i++) {
  253. this.setAttribute('data-input-' + actions[i], id);
  254. }
  255. } else {
  256. inputApi = $.data[id];
  257. }
  258. inputApis.push(inputApi);
  259. });
  260. return inputApis.length === 1 ? inputApis[0] : inputApis;
  261. };
  262. $.ready(function() {
  263. $($.classSelector('.input-row input')).input();
  264. });
  265. })(mui, window, document);