Show:
  1. /**
  2. * The ACE Editor TemplateProcessor base
  3. *
  4. * @module aui-ace-editor
  5. * @submodule aui-ace-autocomplete-templateprocessor
  6. */
  7. var Lang = A.Lang,
  8. AArray = A.Array,
  9. AObject = A.Object,
  10. Base = A.AceEditor.AutoCompleteBase,
  11. MATCH_DIRECTIVES = 0,
  12. MATCH_VARIABLES = 1,
  13. TOKEN_PUNCTUATOR_DOT = 1,
  14. TOKEN_UNRECOGNIZED = -1,
  15. TOKEN_VARIABLE = 0,
  16. /**
  17. * A base class for TemplateProcessor.
  18. *
  19. * @class A.AceEditor.TemplateProcessor
  20. * @extends Base
  21. * @param {Object} config Object literal specifying widget configuration
  22. * properties.
  23. * @constructor
  24. */
  25. TemplateProcessor = A.Base.create('aui-ace-autocomplete-templateprocessor', A.Base, [
  26. ], {
  27. /**
  28. * Accepts match and depending on its type processes directives or
  29. * variables. In case of success, calls the provided success callback,
  30. * or the error callback otherwise.
  31. *
  32. * @method getResults
  33. * @param {Object} match The provided match. It should contain at least
  34. * type and content properties
  35. * @param {Function} callbackSuccess The function to be called in case
  36. * of success
  37. * @param {Function} callbackError The function to be called in case of
  38. * error
  39. */
  40. getResults: function(match, callbackSuccess, callbackError) {
  41. var instance = this,
  42. content,
  43. host,
  44. matchDirectives,
  45. matches,
  46. type;
  47. type = match.type;
  48. if (type === MATCH_DIRECTIVES) {
  49. matchDirectives = instance.get('directives');
  50. content = match.content.toLowerCase();
  51. if (content.length) {
  52. host = instance.get('host');
  53. matchDirectives = host._filterResults(content, matchDirectives);
  54. }
  55. callbackSuccess(matchDirectives);
  56. }
  57. else if (type === MATCH_VARIABLES) {
  58. matches = instance._getVariableMatches(match.content);
  59. callbackSuccess(matches);
  60. }
  61. else {
  62. callbackError();
  63. }
  64. },
  65. /**
  66. * Formats the selected suggestion depending on the match type and
  67. * currently selected editor mode. The match type can be one of:
  68. * MATCH_DIRECTOVES or MATCH_VARIABLES. The selected editor mode can be
  69. * one of the following: INSERT or OVERWRITE. See {{#crossLink
  70. * "AceEditor.AutoCompleteBase/fillMode:attribute"}}{{/crossLink}}
  71. *
  72. * @method getSuggestion
  73. * @param {Object} match The provided match. It should contain at least
  74. * type and content properties
  75. * @param {String} selectedSuggestion The selected suggestion from the
  76. * list with suggestions
  77. * @return {String} The final suggestion which should be inserted to the
  78. * editor
  79. */
  80. getSuggestion: function(match, selectedSuggestion) {
  81. var instance = this,
  82. fillMode,
  83. lastEntry,
  84. result,
  85. type,
  86. variables;
  87. result = selectedSuggestion || '';
  88. if (selectedSuggestion) {
  89. fillMode = instance.get('host').get('fillMode');
  90. type = match.type;
  91. if (fillMode === Base.FILL_MODE_INSERT) {
  92. if (type === MATCH_DIRECTIVES) {
  93. if (match.content && selectedSuggestion.indexOf(match.content) === 0) {
  94. result = selectedSuggestion.substring(match.content.length);
  95. }
  96. }
  97. else if (type === MATCH_VARIABLES) {
  98. variables = match.content.split('.');
  99. lastEntry = variables[variables.length - 1];
  100. if (lastEntry && selectedSuggestion.indexOf(lastEntry) === 0) {
  101. result = selectedSuggestion.substring(lastEntry.length);
  102. }
  103. }
  104. }
  105. else if (type === MATCH_VARIABLES) {
  106. variables = match.content.split('.');
  107. variables[variables.length - 1] = selectedSuggestion;
  108. result = variables.join('.');
  109. }
  110. }
  111. return result;
  112. },
  113. /**
  114. * Checks if the the provided index is the last token in the list of
  115. * tokens.
  116. *
  117. * @method _isLastToken
  118. * @param {Number} index The index which should be checked
  119. * @param {Array} tokens The array with tokens
  120. * @protected
  121. * @return {Boolean} True if the provided index is the last token in the
  122. * list
  123. */
  124. _isLastToken: function(index, tokens) {
  125. return index === tokens.length - 1;
  126. },
  127. /**
  128. * Retrieves the type of a token. It can be one of these:
  129. * TOKEN_PUNCTUATOR_DOT = 1
  130. * TOKEN_UNRECOGNIZED = -1
  131. * TOKEN_VARIABLE = 0
  132. *
  133. * @method _getTokenType
  134. * @param {Number} token The type of the token
  135. * @protected
  136. * @return {Number} The token type
  137. */
  138. _getTokenType: function(token) {
  139. var tokenType = TOKEN_UNRECOGNIZED;
  140. if (Lang.isString(token)) {
  141. if (token.length) {
  142. tokenType = TOKEN_VARIABLE;
  143. }
  144. else {
  145. tokenType = TOKEN_PUNCTUATOR_DOT;
  146. }
  147. }
  148. return tokenType;
  149. },
  150. /**
  151. * Scans the content and extracts variables.
  152. *
  153. * @method _getVariableMatches
  154. * @param {String} content The content from which variable matches will
  155. * be extracted
  156. * @protected
  157. * @return {Array} List with variable matches
  158. */
  159. _getVariableMatches: function(content) {
  160. var instance = this,
  161. curVariableData,
  162. data,
  163. host,
  164. i,
  165. isLastToken,
  166. lastEntry,
  167. leftPartheseIndex,
  168. matches,
  169. results,
  170. resultsData,
  171. token,
  172. tokens,
  173. tokenType,
  174. variableData,
  175. variableType;
  176. results = [];
  177. data = instance.get('variables');
  178. resultsData = {};
  179. curVariableData = data.variables;
  180. if (content) {
  181. tokens = content.split('.');
  182. lastEntry = tokens[tokens.length - 1];
  183. for (i = 0; i < tokens.length; i++) {
  184. token = tokens[i];
  185. tokenType = instance._getTokenType(token);
  186. if (tokenType === TOKEN_PUNCTUATOR_DOT) {
  187. if (i === 0) {
  188. curVariableData = {};
  189. }
  190. else {
  191. resultsData = curVariableData;
  192. }
  193. }
  194. else if (tokenType === TOKEN_VARIABLE) {
  195. isLastToken = instance._isLastToken(i, tokens);
  196. if (isLastToken) {
  197. resultsData = curVariableData;
  198. break;
  199. }
  200. leftPartheseIndex = token.indexOf('(');
  201. if (leftPartheseIndex !== -1) {
  202. token = token.substring(0, leftPartheseIndex);
  203. }
  204. variableData = curVariableData[token];
  205. if (variableData) {
  206. if (i === 0) {
  207. variableType = variableData.type;
  208. }
  209. else {
  210. variableType = variableData.returnType;
  211. }
  212. curVariableData = data.types[variableType] || {};
  213. }
  214. else if (isLastToken) {
  215. resultsData = curVariableData;
  216. break;
  217. }
  218. else {
  219. resultsData = {};
  220. break;
  221. }
  222. }
  223. }
  224. }
  225. else {
  226. resultsData = data.variables;
  227. }
  228. results = AObject.keys(resultsData);
  229. matches = results.sort();
  230. if (lastEntry) {
  231. host = instance.get('host');
  232. matches = host._filterResults(lastEntry, matches);
  233. }
  234. if (matches.length) {
  235. matches = AArray.map(
  236. matches,
  237. function(item) {
  238. var args,
  239. data;
  240. data = resultsData[item];
  241. if (data.type === 'Method') {
  242. args = AArray.map(
  243. data.argumentTypes,
  244. function(item) {
  245. var parts = item.split('.');
  246. return parts[parts.length - 1];
  247. }
  248. );
  249. return item + '(' + args.join(', ') + ')';
  250. }
  251. else {
  252. return item;
  253. }
  254. }
  255. );
  256. }
  257. return matches;
  258. },
  259. /**
  260. * Normalizes a regualr expression value. If the value is String, it
  261. * will be converted to an RegExp.
  262. *
  263. * @method _setRegexValue
  264. * @param {String|RegExp} value The provided regualr expression value
  265. * @protected
  266. * @return {RegExp} The final instance of RegExp object
  267. */
  268. _setRegexValue: function(value) {
  269. var result = A.AttributeCore.INVALID_VALUE;
  270. if (Lang.isString(value)) {
  271. result = new RegExp(value);
  272. }
  273. else if (value instanceof RegExp) {
  274. result = value;
  275. }
  276. return result;
  277. }
  278. }, {
  279. /**
  280. * Static property which provides a string to identify the class.
  281. *
  282. * @property NAME
  283. * @type String
  284. * @static
  285. */
  286. NAME: 'aui-ace-autocomplete-templateprocessor',
  287. /**
  288. * Static property provides a string to identify the namespace.
  289. *
  290. * @property NS
  291. * @type String
  292. * @static
  293. */
  294. NS: 'aui-ace-autocomplete-templateprocessor',
  295. /**
  296. * Static property used to define the default attribute
  297. * configuration for the TemplateProcessor.
  298. *
  299. * @property ATTRS
  300. * @type Object
  301. * @static
  302. */
  303. ATTRS: {
  304. /**
  305. * Contains an array of all possible directives for the
  306. * corresponding language.
  307. *
  308. * @attribute directives
  309. * @type Array
  310. */
  311. directives: {
  312. validator: Lang.isArray
  313. },
  314. /**
  315. * The Editor in which the current instance is plugged.
  316. *
  317. * @attribute host
  318. * @type Object
  319. */
  320. host: {
  321. validator: Lang.isObject
  322. },
  323. /**
  324. * Contains the supported variables for the corresponding language.
  325. *
  326. * @attribute variables
  327. * @type Object
  328. */
  329. variables: {
  330. validator: Lang.isObject
  331. }
  332. }
  333. });
  334. A.AceEditor.TemplateProcessor = TemplateProcessor;