axQuery.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. $axure = function(query) {
  2. return $axure.query(query);
  3. };
  4. // ******* AxQuery and Page metadata ******** //
  5. (function() {
  6. var $ax = function() {
  7. var returnVal = $axure.apply(this, arguments);
  8. var axFn = $ax.fn;
  9. for (var key in axFn) {
  10. returnVal[key] = axFn[key];
  11. }
  12. return returnVal;
  13. };
  14. $ax.public = $axure;
  15. $ax.fn = {};
  16. $axure.internal = function(initFunction) {
  17. //Attach messagecenter to $ax object so that it can be used in viewer.js, etc in internal scope
  18. if(!$ax.messageCenter) $ax.messageCenter = $axure.messageCenter;
  19. return initFunction($ax);
  20. };
  21. var _lastFiredResize = 0;
  22. var _resizeFunctions = [];
  23. var _lastTimeout;
  24. var _fireResize = function() {
  25. if (_lastTimeout) window.clearTimeout(_lastTimeout);
  26. _lastTimeout = undefined;
  27. _lastFiredResize = new Date().getTime();
  28. for(var i = 0; i < _resizeFunctions.length; i++) _resizeFunctions[i]();
  29. };
  30. $axure.resize = function(fn) {
  31. if(fn) _resizeFunctions[_resizeFunctions.length] = fn;
  32. else $(window).resize();
  33. };
  34. $(window).resize(function() {
  35. var THRESHOLD = 50;
  36. var now = new Date().getTime();
  37. if(now - _lastFiredResize > THRESHOLD) {
  38. _fireResize();
  39. } else if(!_lastTimeout) {
  40. _lastTimeout = window.setTimeout(_fireResize, THRESHOLD);
  41. }
  42. });
  43. window.$obj = function(id) {
  44. return $ax.getObjectFromElementId(id);
  45. };
  46. window.$id = function(obj) {
  47. return obj.scriptIds[0];
  48. };
  49. window.$jobj = function(id) {
  50. return $(document.getElementById(id));
  51. };
  52. window.$jobjAll = function(id) {
  53. return $addAll($jobj(id), id);
  54. };
  55. window.$addAll = function(jobj, id) {
  56. return jobj.add($jobj(id + '_ann')).add($jobj(id + '_ref'));
  57. };
  58. $ax.INPUT = function(id) { return id + "_input"; };
  59. $ax.IsImageFocusable = function (type) { return $ax.public.fn.IsImageBox(type) || $ax.public.fn.IsVector(type) || $ax.public.fn.IsTreeNodeObject(type) || $ax.public.fn.IsTableCell(type); };
  60. $ax.IsTreeNodeObject = function (type) { return $ax.public.fn.IsTreeNodeObject(type); };
  61. $ax.IsSelectionButton = function (type) { return $ax.public.fn.IsCheckBox(type) || $ax.public.fn.IsRadioButton(type); };
  62. var _fn = {};
  63. $axure.fn = _fn;
  64. $axure.fn.jQuery = function() {
  65. var elements = this.getElements();
  66. return $(elements);
  67. };
  68. $axure.fn.$ = $axure.fn.jQuery;
  69. var _query = function(query, queryArg) {
  70. var returnVal = {};
  71. var _axQueryObject = returnVal.query = { };
  72. _axQueryObject.filterFunctions = [];
  73. if (query == '*') {
  74. _axQueryObject.filterFunctions[0] = function() { return true; };
  75. } else if (typeof(query) === 'function') {
  76. _axQueryObject.filterFunctions[0] = query;
  77. } else {
  78. var firstString = $.trim(query.toString());
  79. if (firstString.charAt(0) == '@') {
  80. _axQueryObject.filterFunctions[0] = function(diagramObject) {
  81. return diagramObject.label == firstString.substring(1);
  82. };
  83. } else if (firstString.charAt(0) == '#') {
  84. _axQueryObject.elementId = firstString.substring(1);
  85. } else {
  86. if (firstString == 'label') {
  87. _axQueryObject.filterFunctions[0] = function(diagramObject) {
  88. return queryArg instanceof Array && queryArg.indexOf(diagramObject.label) > 0 ||
  89. queryArg instanceof RegExp && queryArg.test(diagramObject.label) ||
  90. diagramObject.label == queryArg;
  91. };
  92. } else if(firstString == 'elementId') {
  93. _axQueryObject.filterFunctions[0] = function(diagramObject, elementId) {
  94. return queryArg instanceof Array && queryArg.indexOf(elementId) > 0 ||
  95. elementId == queryArg;
  96. };
  97. }
  98. }
  99. }
  100. var axureFn = $axure.fn;
  101. for (var key in axureFn) {
  102. returnVal[key] = axureFn[key];
  103. }
  104. return returnVal;
  105. };
  106. $axure.query = _query;
  107. var _getFilterFnFromQuery = function(query) {
  108. var filter = function(diagramObject, elementId) {
  109. // Non diagram objects are allowed to be queryed, such as text inputs.
  110. if (diagramObject && !$ax.public.fn.IsReferenceDiagramObject(diagramObject.type) && !document.getElementById(elementId)) return false;
  111. var retVal = true;
  112. for(var i = 0; i < query.filterFunctions.length && retVal; i++) {
  113. retVal = query.filterFunctions[i](diagramObject, elementId);
  114. }
  115. return retVal;
  116. };
  117. return filter;
  118. };
  119. $ax.public.fn.filter = function(query, queryArg) {
  120. var returnVal = _query(query, queryArg);
  121. if(this.query.elementId) returnVal.query.elementId = this.query.elementId;
  122. //If there is already a function, offset by 1 when copying other functions over.
  123. var offset = returnVal.query.filterFunctions[0] ? 1 : 0;
  124. //Copy all functions over to new array.
  125. for(var i = 0; i < this.query.filterFunctions.length; i++) returnVal.query.filterFunctions[i+offset] = this.query.filterFunctions[i];
  126. //Functions are in reverse order now
  127. returnVal.query.filterFunctions.reverse();
  128. return returnVal;
  129. };
  130. $ax.public.fn.each = function(fn) {
  131. var filter = _getFilterFnFromQuery(this.query);
  132. var elementIds = this.query.elementId ? [this.query.elementId] : $ax.getAllElementIds();
  133. for (var i = 0; i < elementIds.length; i++) {
  134. var elementId = elementIds[i];
  135. var diagramObject = $ax.getObjectFromElementId(elementId);
  136. if (filter(diagramObject, elementId)) {
  137. fn.apply(diagramObject, [diagramObject, elementId]);
  138. }
  139. }
  140. };
  141. $ax.public.fn.getElements = function() {
  142. var elements = [];
  143. this.each(function(dObj, elementId) {
  144. var elementById = document.getElementById(elementId);
  145. if(elementById) elements[elements.length] = elementById;
  146. });
  147. return elements;
  148. };
  149. $ax.public.fn.getElementIds = function() {
  150. var elementIds = [];
  151. this.each(function(dObj, elementId) { elementIds[elementIds.length] = elementId; });
  152. return elementIds;
  153. };
  154. // Deep means to keep getting parents parent until at the root parent. Parent is then an array instead of an id.
  155. // Filter options: layer, rdo, repeater, item, dynamicPanel, state
  156. $ax.public.fn.getParents = function (deep, filter) {
  157. if(filter == '*') filter = ['layer', 'rdo', 'repeater', 'item', 'dynamicPanel', 'state'];
  158. var elementIds = this.getElementIds();
  159. var parentIds = [];
  160. var getParent = function(elementId) {
  161. var containerIndex = elementId.indexOf('_container');
  162. if(containerIndex != -1) elementId = elementId.substring(0, containerIndex);
  163. // Layer only references it if it is a direct layer to it
  164. var parent = $ax.getLayerParentFromElementId(elementId);
  165. // If layer is allowed we found parent, otherwise ignore and keep climbing
  166. if (parent) return filter.indexOf('layer') != -1 ? parent : getParent(parent);
  167. // if repeater item, then just return repeater
  168. var scriptId = $ax.repeater.getScriptIdFromElementId(elementId);
  169. var itemNum = $ax.repeater.getItemIdFromElementId(elementId);
  170. var parentRepeater = $ax.getParentRepeaterFromScriptId(scriptId);
  171. // scriptId is item or repeater itself
  172. if (parentRepeater == scriptId) {
  173. // If you are repeater item, return your repeater
  174. if(itemNum) return filter.indexOf('repeater') != -1 ? scriptId : getParent(scriptId);
  175. // Otherwise you are actually at repeater, clean parentRepeater, or else you loop
  176. parentRepeater = undefined;
  177. }
  178. // if state, then just return panel
  179. if(scriptId.indexOf('_state') != -1) {
  180. var panelId = $ax.repeater.createElementId(scriptId.split('_')[0], itemNum);
  181. // If dynamic panel is allowed we found parent, otherwise ignore and keep climbing
  182. return filter.indexOf('dynamicPanel') != -1 ? panelId : getParent(panelId);
  183. }
  184. var parentType = '';
  185. if(parentRepeater) {
  186. parentType = 'item';
  187. parent = $ax.repeater.createElementId(parentRepeater, itemNum);
  188. }
  189. var masterPath = $ax.getPathFromScriptId($ax.repeater.getScriptIdFromElementId(elementId));
  190. masterPath.pop();
  191. if(masterPath.length > 0) {
  192. var masterId = $ax.getElementIdFromPath(masterPath, { itemNum: itemNum });
  193. if(!masterId) return undefined;
  194. var masterRepeater = $ax.getParentRepeaterFromElementId($ax.repeater.getScriptIdFromElementId(masterId));
  195. if(!parentRepeater || masterRepeater) {
  196. parentType = 'rdo';
  197. parent = masterId;
  198. }
  199. }
  200. var obj = $obj(elementId);
  201. var parentDynamicPanel = obj.parentDynamicPanel;
  202. if(parentDynamicPanel) {
  203. // Make sure the parent if not parentRepeater, or dynamic panel is also in that repeater
  204. // If there is a parent master, the dynamic panel must be in it, otherwise parentDynamicPanel would be undefined.
  205. var panelPath = masterPath;
  206. panelPath[panelPath.length] = parentDynamicPanel;
  207. panelId = $ax.getElementIdFromPath(panelPath, { itemNum: itemNum });
  208. if(!panelId) return undefined;
  209. var panelRepeater = $ax.getParentRepeaterFromElementId(panelId);
  210. if(!parentRepeater || panelRepeater) {
  211. parentType = 'state';
  212. parent = panelId + '_state' + obj.panelIndex;
  213. }
  214. }
  215. // If at top or parent type is desired, then return parent, otherwise keep climbing
  216. return !parent || filter.indexOf(parentType) != -1 ? parent : getParent(parent);
  217. };
  218. for(var i = 0; i < elementIds.length; i++) {
  219. var parent = getParent(elementIds[i]);
  220. if(deep) {
  221. var parents = [];
  222. while(parent) {
  223. parents[parents.length] = parent;
  224. // If id is not a valid object, you are either repeater item or dynamic panel state
  225. //if(!$obj(parent)) parent = $ax.visibility.getWidgetFromContainer($jobj(parent).parent().attr('id'));
  226. parent = getParent(parent);
  227. }
  228. parent = parents;
  229. }
  230. parentIds[parentIds.length] = parent;
  231. }
  232. return parentIds;
  233. };
  234. // Get the path to the child, where non leaf nodes can be masters, layers, dynamic panels, and repeaters.
  235. $ax.public.fn.getChildren = function(deep) {
  236. var elementIds = this.getElementIds();
  237. var children = [];
  238. var getChildren = function(elementId) {
  239. var obj = $obj(elementId);
  240. if(!obj) return undefined;
  241. var isRepeater = obj.type == $ax.constants.REPEATER_TYPE;
  242. var isDynamicPanel = obj.type == $ax.constants.DYNAMIC_PANEL_TYPE;
  243. var isLayer = obj.type == $ax.constants.LAYER_TYPE;
  244. var isMaster = obj.type == $ax.constants.MASTER_TYPE;
  245. var isMenu = obj.type == $ax.constants.MENU_OBJECT_TYPE;
  246. var isTreeNode = obj.type == $ax.constants.TREE_NODE_OBJECT_TYPE;
  247. var isTable = obj.type == $ax.constants.TABLE_TYPE;
  248. //var isCompoundVector = obj.type == $ax.constants.VECTOR_SHAPE_TYPE && obj.generateCompound;
  249. if (isRepeater || isDynamicPanel || isLayer || isMaster || isMenu || isTreeNode || isTable) {// || isCompoundVector) {
  250. // Find parent that children should be pulled from. Default is just the elementId query (used by table and master)
  251. var parent = $jobj(elementId);
  252. if(isRepeater) {
  253. parent = $();
  254. var itemIds = $ax.getItemIdsForRepeater(elementId);
  255. for(var itemIndex = 0; itemIndex < itemIds.length; itemIndex++) parent = parent.add($jobj($ax.repeater.createElementId(elementId, itemIds[itemIndex])));
  256. } else if(isDynamicPanel) {
  257. // Really only need to do active state probably...
  258. parent = $jobj(elementId).children();
  259. // Get through all containers
  260. while ($(parent[0]).attr('id').indexOf('container') != -1) parent = parent.children();
  261. // Now at states, but want states content
  262. parent = parent.children();
  263. } else if(isTreeNode) parent = $jobj($ax.repeater.applySuffixToElementId(elementId, '_children'));
  264. // Menu doesn't want all children, only tables and menus, so it must be handled specially
  265. var children = isMenu ? parent.children('.ax_table').add(parent.children('.ax_menu')) : parent.children();
  266. children = $ax.visibility.getRealChildren(_fixForBasicLinks(children));
  267. // For tree nodes you want the the button shape contained by the elementQuery too
  268. if(isTreeNode) {
  269. var treeNodeChildren = $jobj(elementId).children();
  270. for(var treeNodeIndex = 0; treeNodeIndex < treeNodeChildren.length; treeNodeIndex++) {
  271. var treeNodeChild = $(treeNodeChildren[treeNodeIndex]);
  272. var childObj = $obj(treeNodeChild.attr('id'));
  273. if (childObj && $ax.public.fn.IsVector(childObj.type)) children = children.add(treeNodeChild);
  274. }
  275. }
  276. var childrenIds = [];
  277. for(var childIndex = 0; childIndex < children.length; childIndex++) {
  278. var childObj = $(children[childIndex]);
  279. var id = childObj.attr('id');
  280. if(typeof(id) == 'undefined' && childObj.is('a')) id = $(childObj.children()[0]).attr('id');
  281. // Ignore annotations and any other children that are not elements
  282. if (id.split('_').length > 1) continue;
  283. childrenIds.push(id);
  284. }
  285. if(deep) {
  286. var childObjs = [];
  287. for(var i = 0; i < childrenIds.length; i++) {
  288. var childId = childrenIds[i];
  289. childObjs[i] = { id: childId, children: getChildren(childId) };
  290. }
  291. childrenIds = childObjs;
  292. }
  293. return childrenIds;
  294. }
  295. return undefined;
  296. };
  297. for(var i = 0; i < elementIds.length; i++) {
  298. children[children.length] = { id : elementIds[i], children : getChildren(elementIds[i])};
  299. }
  300. return children;
  301. };
  302. var _fixForBasicLinks = function(query) {
  303. var retval = $();
  304. for(var i = 0; i < query.length; i++) {
  305. var child = $(query[i]);
  306. if(child.hasClass('basiclink')) retval = retval.add(child.children());
  307. else retval = retval.add(child);
  308. }
  309. return retval;
  310. };
  311. })();