expr.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. // ******* Expr MANAGER ******** //
  2. $axure.internal(function($ax) {
  3. var _expr = $ax.expr = {};
  4. var _binOpHandlers = {
  5. '&&': function(left, right) { return $ax.getBool(left) && $ax.getBool(right); },
  6. '||': function(left, right) { return $ax.getBool(left) || $ax.getBool(right); },
  7. '==': function(left, right) { return isEqual(left, right); },
  8. '!=': function(left, right) { return !isEqual(left, right); },
  9. '>': function(left, right) { return left > Number(right); },
  10. '<': function(left, right) { return left < Number(right); },
  11. '>=': function(left, right) { return left >= Number(right); },
  12. '<=': function(left, right) { return left <= Number(right); }
  13. };
  14. var isEqual = function(left, right) {
  15. if(left instanceof Date && right instanceof Date) {
  16. if(left.getMilliseconds() != right.getMilliseconds()) return false;
  17. if(left.getSeconds() != right.getSeconds()) return false;
  18. if(left.getMinutes() != right.getMinutes()) return false;
  19. if(left.getHours() != right.getHours()) return false;
  20. if(left.getDate() != right.getDate()) return false;
  21. if(left.getMonth() != right.getMonth()) return false;
  22. if(left.getYear() != right.getYear()) return false;
  23. return true;
  24. }
  25. if(left instanceof Object && right instanceof Object) {
  26. var prop;
  27. // Go through all of lefts properties and compare them to rights.
  28. for(prop in left) {
  29. if(!left.hasOwnProperty(prop)) continue;
  30. // If left has a property that the right doesn't they are not equal.
  31. if(!right.hasOwnProperty(prop)) return false;
  32. // If any of their properties are not equal, they are not equal.
  33. if(!isEqual(left[prop], right[prop])) return false;
  34. }
  35. for(prop in right) {
  36. // final check to make sure right doesn't have some extra properties that make them not equal.
  37. if(left.hasOwnProperty(prop) != right.hasOwnProperty(prop)) return false;
  38. }
  39. return true;
  40. }
  41. return $ax.getBool(left) == $ax.getBool(right);
  42. };
  43. var _exprHandlers = {};
  44. _exprHandlers.array = function(expr, eventInfo) {
  45. var returnVal = [];
  46. for(var i = 0; i < expr.items.length; i++) {
  47. returnVal[returnVal.length] = _evaluateExpr(expr.items[i], eventInfo);
  48. }
  49. return returnVal;
  50. };
  51. _exprHandlers.binaryOp = function(expr, eventInfo) {
  52. var left = expr.leftExpr && _evaluateExpr(expr.leftExpr, eventInfo);
  53. var right = expr.rightExpr && _evaluateExpr(expr.rightExpr, eventInfo);
  54. if(left == undefined || right == undefined) return false;
  55. return _binOpHandlers[expr.op](left, right);
  56. };
  57. _exprHandlers.block = function(expr, eventInfo) {
  58. var subExprs = expr.subExprs;
  59. for(var i = 0; i < subExprs.length; i++) {
  60. _evaluateExpr(subExprs[i], eventInfo); //ignore the result
  61. }
  62. };
  63. _exprHandlers.booleanLiteral = function(expr) {
  64. return expr.value;
  65. };
  66. _exprHandlers.nullLiteral = function() { return null; };
  67. _exprHandlers.pathLiteral = function(expr, eventInfo) {
  68. if(expr.isThis) return [eventInfo.srcElement];
  69. if(expr.isFocused && window.lastFocusedControl) {
  70. $ax('#' + window.lastFocusedControl).focus();
  71. return [window.lastFocusedControl];
  72. }
  73. if(expr.isTarget) return [eventInfo.targetElement];
  74. return $ax.getElementIdsFromPath(expr.value, eventInfo);
  75. };
  76. _exprHandlers.panelDiagramLiteral = function(expr, eventInfo) {
  77. var elementIds = $ax.getElementIdsFromPath(expr.panelPath, eventInfo);
  78. var elementIdsWithSuffix = [];
  79. var suffix = '_state' + expr.panelIndex;
  80. for(var i = 0; i < elementIds.length; i++) {
  81. elementIdsWithSuffix[i] = $ax.repeater.applySuffixToElementId(elementIds[i], suffix);
  82. }
  83. return String($jobj(elementIdsWithSuffix).data('label'));
  84. };
  85. _exprHandlers.fcall = function(expr, eventInfo) {
  86. var oldTarget = eventInfo.targetElement;
  87. var targets = [];
  88. var fcallArgs = [];
  89. var exprArgs = expr.arguments;
  90. for(var i = 0; i < expr.arguments.length; i++) {
  91. var exprArg = exprArgs[i];
  92. var fcallArg = '';
  93. if(targets.length) {
  94. for(var j = 0; j < targets.length; j++) {
  95. if(exprArg == null) {
  96. fcallArgs[j][i] = null;
  97. continue;
  98. }
  99. eventInfo.targetElement = targets[j];
  100. fcallArg = _evaluateExpr(exprArg, eventInfo);
  101. if(typeof (fcallArg) == 'undefined') return '';
  102. fcallArgs[j][i] = fcallArg;
  103. }
  104. } else {
  105. if(exprArg == null) {
  106. fcallArgs[i] = null;
  107. continue;
  108. }
  109. fcallArg = _evaluateExpr(exprArg, eventInfo);
  110. if(typeof (fcallArg) == 'undefined') return '';
  111. fcallArgs[i] = fcallArg;
  112. }
  113. // We do support null exprArgs...
  114. // TODO: This makes 2 assumptions that may change in the future. 1. The pathLiteral is the always the first arg. 2. there is always only 1 pathLiteral
  115. if(exprArg && exprArg.exprType == 'pathLiteral') {
  116. targets = fcallArg;
  117. // fcallArgs is now an array of an array of args
  118. for(j = 0; j < targets.length; j++) fcallArgs[j] = [[fcallArg[j]]];
  119. }
  120. }
  121. // we want to preserve the target element from outside this function.
  122. eventInfo.targetElement = oldTarget;
  123. var retval = '';
  124. if(targets.length) {
  125. // Go backwards so retval is the first item.
  126. for(i = targets.length - 1; i >= 0; i--) {
  127. var args = fcallArgs[i];
  128. // Add event info to the end
  129. args[args.length] = eventInfo;
  130. retval = _exprFunctions[expr.functionName].apply(this, args);
  131. }
  132. } else fcallArgs[fcallArgs.length] = eventInfo;
  133. return targets.length ? retval : _exprFunctions[expr.functionName].apply(this, fcallArgs);
  134. };
  135. _exprHandlers.globalVariableLiteral = function(expr) {
  136. return expr.variableName;
  137. };
  138. _exprHandlers.keyPressLiteral = function(expr) {
  139. var keyInfo = {};
  140. keyInfo.keyCode = expr.keyCode;
  141. keyInfo.ctrl = expr.ctrl;
  142. keyInfo.alt = expr.alt;
  143. keyInfo.shift = expr.shift;
  144. return keyInfo;
  145. };
  146. _exprHandlers.adaptiveViewLiteral = function(expr) {
  147. return expr.id;
  148. };
  149. var _substituteSTOs = function(expr, eventInfo) {
  150. //first evaluate the local variables
  151. var scope = {};
  152. for(var varName in expr.localVariables) {
  153. scope[varName] = $ax.expr.evaluateExpr(expr.localVariables[varName], eventInfo);
  154. }
  155. // TODO: [ben] Date and data object (obj with info for url or image) both need to return non-strings.
  156. var i = 0;
  157. var retval;
  158. var retvalString = expr.value.replace(/\[\[(?!\[)(.*?)\]\](?=\]*)/g, function(match) {
  159. var sto = expr.stos[i++];
  160. if(sto.sto == 'error') return match;
  161. try {
  162. var result = $ax.evaluateSTO(sto, scope, eventInfo);
  163. } catch(e) {
  164. return match;
  165. }
  166. if((result instanceof Object) && i == 1 && expr.value.substring(0, 2) == '[[' &&
  167. expr.value.substring(expr.value.length - 2) == ']]') {
  168. // If the result was an object, this was the first result, and the whole thing was this expresion.
  169. retval = result;
  170. }
  171. return ((result instanceof Object) && (result.label || result.text)) || result;
  172. });
  173. // If more than one group returned, the object is not valid
  174. if(i != 1) retval = false;
  175. return retval || retvalString;
  176. };
  177. _exprHandlers.htmlLiteral = function(expr, eventInfo) {
  178. return _substituteSTOs(expr, eventInfo);
  179. };
  180. _exprHandlers.stringLiteral = function(expr, eventInfo) {
  181. return _substituteSTOs(expr, eventInfo);
  182. };
  183. var _exprFunctions = {};
  184. _exprFunctions.SetCheckState = function(elementIds, value) {
  185. var toggle = value == 'toggle';
  186. var boolValue = Boolean(value) && value != 'false';
  187. for(var i = 0; i < elementIds.length; i++) {
  188. var query = $ax('#' + elementIds[i]);
  189. query.selected(toggle ? !query.selected() : boolValue);
  190. }
  191. };
  192. _exprFunctions.SetSelectedOption = function(elementIds, value) {
  193. for(var i = 0; i < elementIds.length; i++) {
  194. var elementId = elementIds[i];
  195. var obj = $jobj($ax.INPUT(elementId));
  196. if(obj.val() == value) return;
  197. obj.val(value);
  198. if($ax.event.HasSelectionChanged($ax.getObjectFromElementId(elementId))) $ax.event.raiseSyntheticEvent(elementId, 'onSelectionChange');
  199. }
  200. };
  201. _exprFunctions.SetGlobalVariableValue = function(varName, value) {
  202. $ax.globalVariableProvider.setVariableValue(varName, value);
  203. };
  204. _exprFunctions.SetWidgetFormText = function(elementIds, value) {
  205. for(var i = 0; i < elementIds.length; i++) {
  206. var elementId = elementIds[i];
  207. var inputId = $ax.repeater.applySuffixToElementId(elementId, '_input');
  208. var obj = $jobj(inputId);
  209. if(obj.val() == value || (value == '' && $ax.placeholderManager.isActive(elementId))) return;
  210. obj.val(value);
  211. $ax.placeholderManager.updatePlaceholder(elementId, !value);
  212. if($ax.event.HasTextChanged($ax.getObjectFromElementId(elementId))) $ax.event.TryFireTextChanged(elementId);
  213. }
  214. };
  215. _exprFunctions.SetFocusedWidgetText = function(elementId, value) {
  216. if(window.lastFocusedControl) {
  217. var elementId = window.lastFocusedControl;
  218. var type = $obj(elementId).type;
  219. if(type == 'textBox' || type == 'textArea') _exprFunctions.SetWidgetFormText([elementId], value);
  220. else _exprFunctions.SetWidgetRichText([elementId], value, true);
  221. }
  222. };
  223. _exprFunctions.GetRtfElementHeight = function(rtfElement) {
  224. if(rtfElement.innerHTML == '') rtfElement.innerHTML = '&nbsp;';
  225. return rtfElement.offsetHeight;
  226. };
  227. _exprFunctions.SetWidgetRichText = function(ids, value, plain) {
  228. // Converts dates, widgetinfo, and the like to strings.
  229. value = _exprFunctions.ToString(value);
  230. //Replace any newlines with line breaks
  231. value = value.replace(/\r\n/g, '<br>').replace(/\n/g, '<br>');
  232. for(var i = 0; i < ids.length; i++) {
  233. var id = ids[i];
  234. // If calling this on button shape, get the id of the rich text panel inside instead
  235. var type = $obj(id).type;
  236. if(type != 'richTextPanel' && type != 'hyperlink') {
  237. id = $jobj(id).find('.text')[0].id;
  238. }
  239. var element = window.document.getElementById(id);
  240. $ax.visibility.SetVisible(element, true);
  241. $ax.style.transformTextWithVerticalAlignment(id, function() {
  242. var spans = $jobj(id).find('span');
  243. if(plain) {
  244. // Wrap in span and p, style them accordingly.
  245. var span = $('<span></span>');
  246. if(spans.length > 0) {
  247. span.attr('style', $(spans[0]).attr('style'));
  248. span.attr('id', $(spans[0]).attr('id'));
  249. }
  250. span.html(value);
  251. var p = $('<p></p>');
  252. var ps = $jobj(id).find('p');
  253. if(ps.length > 0) {
  254. p.attr('style', $(ps[0]).attr('style'));
  255. p.attr('id', $(ps[0]).attr('id'));
  256. }
  257. p.append(span);
  258. value = $('<div></div>').append(p).html();
  259. }
  260. element.innerHTML = value;
  261. });
  262. if(!plain) $ax.style.CacheOriginalText(id, true);
  263. }
  264. };
  265. _exprFunctions.GetCheckState = function(ids) {
  266. return $ax('#' + ids[0]).selected();
  267. };
  268. _exprFunctions.GetSelectedOption = function(ids) {
  269. return $jobj($ax.INPUT(ids[0]))[0].value;
  270. };
  271. _exprFunctions.GetNum = function(str) {
  272. //Setting a GlobalVariable to some blank text then setting a widget to the value of that variable would result in 0 not ""
  273. //I have fixed this another way so commenting this should be fine now
  274. //if (!str) return "";
  275. return isNaN(str) ? str : Number(str);
  276. };
  277. _exprFunctions.GetGlobalVariableValue = function(id) {
  278. return $ax.globalVariableProvider.getVariableValue(id);
  279. };
  280. _exprFunctions.GetGlobalVariableLength = function(id) {
  281. return _exprFunctions.GetGlobalVariableValue(id).length;
  282. };
  283. _exprFunctions.GetWidgetText = function(ids) {
  284. if($ax.placeholderManager.isActive(ids[0])) return '';
  285. var input = $ax.INPUT(ids[0]);
  286. return $ax('#' + ($jobj(input).length ? input : ids[0])).text();
  287. };
  288. _exprFunctions.GetFocusedWidgetText = function() {
  289. if(window.lastFocusedControl) {
  290. return $ax('#' + window.lastFocusedControl).text();
  291. } else {
  292. return "";
  293. }
  294. };
  295. _exprFunctions.GetWidgetValueLength = function(ids) {
  296. var id = ids[0];
  297. if(!id) return undefined;
  298. if($ax.placeholderManager.isActive(id)) return 0;
  299. var obj = $jobj($ax.INPUT(id));
  300. if(!obj.length) obj = $jobj(id);
  301. var val = obj[0].value || _exprFunctions.GetWidgetText([id]);
  302. return val.length;
  303. };
  304. _exprFunctions.GetPanelState = function(ids) {
  305. var id = ids[0];
  306. if(!id) return undefined;
  307. var stateId = $ax.visibility.GetPanelState(id);
  308. return stateId && String($jobj(stateId).data('label'));
  309. };
  310. _exprFunctions.GetWidgetVisibility = function(ids) {
  311. var id = ids[0];
  312. if(!id) return undefined;
  313. return $ax.visibility.IsIdVisible(id);
  314. };
  315. // ***************** Validation Functions ***************** //
  316. _exprFunctions.IsValueAlpha = function(val) {
  317. var isAlphaRegex = new RegExp("^[a-z\\s]+$", "gi");
  318. return isAlphaRegex.test(val);
  319. };
  320. _exprFunctions.IsValueNumeric = function(val) {
  321. var isNumericRegex = new RegExp("^[0-9,\\.\\s]+$", "gi");
  322. return isNumericRegex.test(val);
  323. };
  324. _exprFunctions.IsValueAlphaNumeric = function(val) {
  325. var isAlphaNumericRegex = new RegExp("^[0-9a-z\\s]+$", "gi");
  326. return isAlphaNumericRegex.test(val);
  327. };
  328. _exprFunctions.IsValueOneOf = function(val, values) {
  329. for(var i = 0; i < values.length; i++) {
  330. var option = values[i];
  331. if(val == option) return true;
  332. }
  333. //by default, return false
  334. return false;
  335. };
  336. _exprFunctions.IsValueNotAlpha = function(val) {
  337. return !_exprFunctions.IsValueAlpha(val);
  338. };
  339. _exprFunctions.IsValueNotNumeric = function(val) {
  340. return !_exprFunctions.IsValueNumeric(val);
  341. };
  342. _exprFunctions.IsValueNotAlphaNumeric = function(val) {
  343. return !_exprFunctions.IsValueAlphaNumeric(val);
  344. };
  345. _exprFunctions.IsValueNotOneOf = function(val, values) {
  346. return !_exprFunctions.IsValueOneOf(val, values);
  347. };
  348. _exprFunctions.GetKeyPressed = function(eventInfo) {
  349. return eventInfo.keyInfo;
  350. };
  351. _exprFunctions.GetCursorRectangles = function() {
  352. var rects = new Object();
  353. rects.lastRect = new $ax.drag.Rectangle($ax.lastMouseLocation.x, $ax.lastMouseLocation.y, 1, 1);
  354. rects.currentRect = new $ax.drag.Rectangle($ax.mouseLocation.x, $ax.mouseLocation.y, 1, 1);
  355. return rects;
  356. };
  357. _exprFunctions.GetWidgetRectangles = function(elementId, eventInfo) {
  358. var rects = new Object();
  359. var jObj = $jobj(elementId);
  360. var invalid = jObj.length == 0;
  361. var parent = jObj;
  362. // Or are in valid if no obj can be found, or if it is not visible.
  363. while(parent.length != 0 && !parent.is('body')) {
  364. if(parent.css('display') == 'none') {
  365. invalid = true;
  366. break;
  367. }
  368. parent = parent.parent();
  369. }
  370. if(invalid) {
  371. rects.lastRect = rects.currentRect = new $ax.drag.Rectangle(-1, -1, -1, -1);
  372. return rects;
  373. }
  374. rects.lastRect = new $ax.drag.Rectangle(
  375. $ax.legacy.getAbsoluteLeft(jObj),
  376. $ax.legacy.getAbsoluteTop(jObj),
  377. jObj.width(),
  378. jObj.height());
  379. rects.currentRect = rects.lastRect;
  380. return rects;
  381. };
  382. _exprFunctions.GetWidget = function(elementId) {
  383. return $ax.getWidgetInfo(elementId[0]);
  384. };
  385. _exprFunctions.GetAdaptiveView = function() {
  386. return $ax.adaptive.currentViewId || '';
  387. };
  388. _exprFunctions.IsEntering = function(movingRects, targetRects) {
  389. return !movingRects.lastRect.IntersectsWith(targetRects.currentRect) && movingRects.currentRect.IntersectsWith(targetRects.currentRect);
  390. };
  391. _exprFunctions.IsLeaving = function(movingRects, targetRects) {
  392. return movingRects.lastRect.IntersectsWith(targetRects.currentRect) && !movingRects.currentRect.IntersectsWith(targetRects.currentRect);
  393. };
  394. var _IsOver = _exprFunctions.IsOver = function(movingRects, targetRects) {
  395. return movingRects.currentRect.IntersectsWith(targetRects.currentRect);
  396. };
  397. _exprFunctions.IsNotOver = function(movingRects, targetRects) {
  398. return !_IsOver(movingRects, targetRects);
  399. };
  400. _exprFunctions.ValueContains = function(inputString, value) {
  401. return inputString.indexOf(value) > -1;
  402. };
  403. _exprFunctions.ValueNotContains = function(inputString, value) {
  404. return !_exprFunctions.ValueContains(inputString, value);
  405. };
  406. _exprFunctions.ToString = function(value) {
  407. if(value.isWidget) {
  408. return value.text;
  409. }
  410. return String(value);
  411. };
  412. var _evaluateExpr = $ax.expr.evaluateExpr = function(expr, eventInfo, toString) {
  413. if(expr === undefined || expr === null) return undefined;
  414. var result = _exprHandlers[expr.exprType](expr, eventInfo);
  415. return toString ? _exprFunctions.ToString(result) : result;
  416. };
  417. });