events.js 83 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736
  1. // ******* Features MANAGER ******** //
  2. $axure.internal(function($ax) {
  3. var _features = $ax.features = {};
  4. var _supports = _features.supports = {};
  5. _supports.touchstart = typeof window.ontouchstart !== 'undefined';
  6. _supports.touchmove = typeof window.ontouchmove !== 'undefined';
  7. _supports.touchend = typeof window.ontouchend !== 'undefined';
  8. _supports.mobile = _supports.touchstart && _supports.touchend && _supports.touchmove;
  9. // Got this from http://stackoverflow.com/questions/11381673/javascript-solution-to-detect-mobile-browser
  10. var check = navigator.userAgent.match(/Android/i)
  11. || navigator.userAgent.match(/webOS/i)
  12. || navigator.userAgent.match(/iPhone/i)
  13. || navigator.userAgent.match(/iPad/i)
  14. || navigator.userAgent.match(/iPod/i)
  15. || navigator.userAgent.match(/BlackBerry/i)
  16. || navigator.userAgent.match(/Tablet PC/i)
  17. || navigator.userAgent.match(/Windows Phone/i);
  18. _supports.windowsMobile = navigator.userAgent.match(/Tablet PC/i) || navigator.userAgent.match(/Windows Phone/i);
  19. if(!check && _supports.mobile) {
  20. _supports.touchstart = false;
  21. _supports.touchmove = false;
  22. _supports.touchend = false;
  23. _supports.mobile = false;
  24. }
  25. var _eventNames = _features.eventNames = {};
  26. _eventNames.mouseDownName = _supports.touchstart ? 'touchstart' : 'mousedown';
  27. _eventNames.mouseUpName = _supports.touchend ? 'touchend' : 'mouseup';
  28. _eventNames.mouseMoveName = _supports.touchmove ? 'touchmove' : 'mousemove';
  29. });
  30. // ******* EVENT MANAGER ******** //
  31. $axure.internal(function($ax) {
  32. var _objectIdToEventHandlers = {};
  33. var _jBrowserEvent = undefined;
  34. $ax.setjBrowserEvent = function(event) {
  35. _jBrowserEvent = event;
  36. };
  37. $ax.getjBrowserEvent = function() {
  38. return _jBrowserEvent;
  39. };
  40. var _event = {};
  41. $ax.event = _event;
  42. //initilize state
  43. _event.mouseOverObjectId = '';
  44. _event.mouseDownObjectId = '';
  45. _event.mouseOverIds = [];
  46. var EVENT_NAMES = ['mouseenter', 'mouseleave', 'contextmenu', 'change', 'focus', 'blur'];
  47. // Tap, double tap, and touch move, or synthetic.
  48. if(!$ax.features.supports.mobile) {
  49. EVENT_NAMES[EVENT_NAMES.length] = 'click';
  50. EVENT_NAMES[EVENT_NAMES.length] = 'dblclick';
  51. EVENT_NAMES[EVENT_NAMES.length] = 'mousemove';
  52. }
  53. // add the event names for the touch events
  54. EVENT_NAMES[EVENT_NAMES.length] = $ax.features.eventNames.mouseDownName;
  55. EVENT_NAMES[EVENT_NAMES.length] = $ax.features.eventNames.mouseUpName;
  56. for(var i = 0; i < EVENT_NAMES.length; i++) {
  57. var eventName = EVENT_NAMES[i];
  58. //we need the function here to circumvent closure modifying eventName
  59. _event[eventName] = (function(event_Name) {
  60. return function(elementId, fn) {
  61. var elementIdQuery = $jobj(elementId);
  62. var type = $ax.getTypeFromElementId(elementId);
  63. //we need specially track link events so we can enable and disable them along with
  64. //their parent widgets
  65. if(elementIdQuery.is('a')) _attachCustomObjectEvent(elementId, event_Name, fn);
  66. //see notes below
  67. else if($ax.IsTreeNodeObject(type)) _attachTreeNodeEvent(elementId, event_Name, fn);
  68. else if ($ax.IsImageFocusable(type) && (event_Name == 'focus' || event_Name == 'blur')) {
  69. var suitableChild;
  70. var imgChild = $ax.repeater.applySuffixToElementId(elementId, '_img');
  71. var divChild = $ax.repeater.applySuffixToElementId(elementId, '_div');
  72. for (var j = 0; j < elementIdQuery[0].children.length; j++) {
  73. if (elementIdQuery[0].children[j].id == imgChild) suitableChild = imgChild;
  74. if (!suitableChild && elementIdQuery[0].children[j].id == divChild) suitableChild = divChild;
  75. }
  76. if(!suitableChild) suitableChild = imgChild;
  77. _attachDefaultObjectEvent($jobj(suitableChild), elementId, event_Name, fn);
  78. } else {
  79. var inputId = $ax.INPUT(elementId);
  80. var isInput = $jobj(inputId).length != 0;
  81. var id = isInput && (event_Name == 'focus' || event_Name == 'blur') ? inputId : elementId;
  82. _attachDefaultObjectEvent($jobj(id), elementId, event_Name, fn);
  83. }
  84. };
  85. })(eventName);
  86. }
  87. var AXURE_TO_JQUERY_EVENT_NAMES = {
  88. 'onMouseOver': 'mouseenter',
  89. 'onMouseOut': 'mouseleave',
  90. 'onContextMenu': 'contextmenu',
  91. 'onChange': 'change',
  92. 'onFocus': 'focus',
  93. 'onLostFocus': 'blur'
  94. };
  95. // Tap, double tap, and touch move, or synthetic.
  96. if(!$ax.features.supports.mobile) {
  97. AXURE_TO_JQUERY_EVENT_NAMES.onClick = 'click';
  98. AXURE_TO_JQUERY_EVENT_NAMES.onDoubleClick = 'dblclick';
  99. AXURE_TO_JQUERY_EVENT_NAMES.onMouseMove = 'mousemove';
  100. }
  101. AXURE_TO_JQUERY_EVENT_NAMES.onMouseDown = $ax.features.eventNames.mouseDownName;
  102. AXURE_TO_JQUERY_EVENT_NAMES.onMouseUp = $ax.features.eventNames.mouseUpName;
  103. var _attachEvents = function (diagramObject, elementId) {
  104. var inputId = $ax.repeater.applySuffixToElementId(elementId, '_input');
  105. var id = $jobj(inputId).length ? inputId : elementId;
  106. for(var eventName in diagramObject.interactionMap) {
  107. var jQueryEventName = AXURE_TO_JQUERY_EVENT_NAMES[eventName];
  108. if(!jQueryEventName) continue;
  109. _event[jQueryEventName](id,
  110. //this is needed to escape closure
  111. (function(axEventObject) {
  112. return function(e) {
  113. $ax.setjBrowserEvent(e);
  114. // console.log(axEventObject.description);
  115. var eventInfo = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), false, elementId);
  116. _handleEvent(elementId, eventInfo, axEventObject);
  117. };
  118. })(diagramObject.interactionMap[eventName])
  119. );
  120. }
  121. };
  122. var _descriptionToKey = { 'OnFocus': 'onFocus', 'OnLostFocus': 'onLostFocus' };
  123. var _createProxies = function(diagramObject, elementId) {
  124. var createFocus = _needsProxy(elementId, 'onFocus');
  125. var createLostFocus = _needsProxy(elementId, 'onLostFocus');
  126. if(!createFocus && !createLostFocus) return;
  127. if(!diagramObject.interactionMap) diagramObject.interactionMap = {};
  128. if(createFocus) diagramObject.interactionMap.onFocus = { proxy: true, description: 'OnFocus' };
  129. if(createLostFocus) diagramObject.interactionMap.onLostFocus = { proxy: true, description: 'OnLostFocus' };
  130. }
  131. var preventDefaultEvents = ['OnContextMenu', 'OnKeyUp', 'OnKeyDown'];
  132. var allowBubble = ['OnFocus', 'OnResize', 'OnMouseOut', 'OnMouseOver'];
  133. var _canClick = true;
  134. var _startScroll = [];
  135. var _setCanClick = function(canClick) {
  136. _canClick = canClick;
  137. if(_canClick) _startScroll = [$(window).scrollLeft(), $(window).scrollTop()];
  138. };
  139. var _getCanClick = function() {
  140. if(!$ax.features.supports.mobile) return true;
  141. var endScroll = [$(window).scrollLeft(), $(window).scrollTop()];
  142. return _canClick && _startScroll[0] == endScroll[0] && _startScroll[1] == endScroll[1];
  143. };
  144. //var _notAllowedInvisible = function (type) {
  145. // $ax.getTypeFromElementId(elementId);
  146. // return !$ax.public.fn.IsReferenceDiagramObject(type) && !$ax.public.fn.IsLayer(type);
  147. //}
  148. var _notAllowedInvisible = function (id) {
  149. var type = $ax.getTypeFromElementId(id);
  150. if ($ax.public.fn.IsReferenceDiagramObject(type) || $ax.public.fn.IsLayer(type)) return false;
  151. return !($ax.public.fn.IsVector(type) && _hasCompoundImage(id));
  152. }
  153. var _hasCompoundImage = function (id) {
  154. var query = $jobj(id);
  155. return $ax.public.fn.isCompoundVectorHtml(query[0]);
  156. }
  157. var eventNesting = 0;
  158. var eventNestingTime = new Date().getTime();
  159. var _handleEvent = $ax.event.handleEvent = function(elementId, eventInfo, axEventObject, skipShowDescriptions, synthetic) {
  160. if(axEventObject.proxy) {
  161. var firingId = _widgetToFocusParent[elementId];
  162. if(firingId) {
  163. var firingObj = $obj(firingId);
  164. var nextEventObj = firingObj.interactionMap && firingObj.interactionMap[_descriptionToKey[axEventObject.description]];
  165. if(!nextEventObj) nextEventObj = axEventObject;
  166. _handleEvent(firingId, eventInfo, nextEventObj, skipShowDescriptions, synthetic);
  167. }
  168. return;
  169. }
  170. // var x = JSON.stringify(eventInfo);
  171. // var y = JSON.stringify(axEventObject);
  172. var fireTime = new Date().getTime();
  173. if(fireTime - eventNestingTime > 100) {
  174. eventNestingTime = fireTime;
  175. eventNesting = 0;
  176. }
  177. if(eventNesting === 0) {
  178. $ax.recording.maybeRecordEvent(elementId, eventInfo, axEventObject, fireTime);
  179. }
  180. eventNesting += 1;
  181. var eventDescription = axEventObject.description;
  182. if(!_getCanClick() && (eventDescription == 'OnClick' || eventDescription == 'OnPageClick')) return;
  183. // If you are supposed to suppress, do that right away.
  184. if(suppressedEventStatus[eventDescription]) {
  185. return;
  186. }
  187. var currentEvent = $ax.getjBrowserEvent();
  188. if(!synthetic && currentEvent && currentEvent.originalEvent && currentEvent.originalEvent.handled && !eventInfo.isMasterEvent) return;
  189. if(!synthetic && elementId && !$ax.style.getObjVisible(elementId) && _notAllowedInvisible(elementId)) return;
  190. //if debug
  191. var axObj = $obj(elementId);
  192. var axObjLabel = axObj ? axObj.label : eventInfo.label;
  193. var axObjType = axObj ? axObj.friendlyType : eventInfo.friendlyType;
  194. if(!skipShowDescriptions || eventDescription == 'OnPageLoad') $ax.messageCenter.postMessage('axEvent', { 'label': axObjLabel, 'type': axObjType, 'event': axEventObject });
  195. var bubble = true;
  196. var showCaseDescriptions = !skipShowDescriptions && _shouldShowCaseDescriptions(axEventObject);
  197. if(!showCaseDescriptions) {
  198. //handle case descriptions
  199. var caseGroups = [];
  200. var currentCaseGroup = [];
  201. caseGroups[0] = currentCaseGroup;
  202. // Those refreshes not after a wait
  203. var guaranteedRefreshes = {};
  204. var caseGroupIndex = 0;
  205. for(var i = 0; i < axEventObject.cases.length; i++) {
  206. var currentCase = axEventObject.cases[i];
  207. if(currentCase.isNewIfGroup && i != 0) {
  208. caseGroupIndex++;
  209. currentCaseGroup = [];
  210. caseGroups[caseGroups.length] = currentCaseGroup;
  211. // Joon: Isn't caseGroups.length always equal to caseGroupIndex?
  212. }
  213. currentCaseGroup[currentCaseGroup.length] = currentCase;
  214. for(var j = 0; j < currentCase.actions.length; j++) {
  215. var action = currentCase.actions[j];
  216. if(action.action == 'wait') break;
  217. if(action.action != 'refreshRepeater') continue;
  218. for(var k = 0; k < action.repeatersToRefresh.length; k++) {
  219. var id = $ax.getElementIdsFromPath(action.repeatersToRefresh[k], eventInfo)[0];
  220. if(id) guaranteedRefreshes[id] = caseGroupIndex;
  221. }
  222. }
  223. }
  224. for(var i = 0; i < caseGroups.length; i++) {
  225. var groupRefreshes = [];
  226. for(var key in guaranteedRefreshes) {
  227. if(guaranteedRefreshes[key] == i) groupRefreshes[groupRefreshes.length] = key;
  228. }
  229. bubble = _handleCaseGroup(eventInfo, caseGroups[i], groupRefreshes) && bubble;
  230. }
  231. } else {
  232. _showCaseDescriptions(elementId, eventInfo, axEventObject, synthetic);
  233. bubble = false;
  234. }
  235. // If not handled, synthetically bubble if you can
  236. if(bubble && _widgetToFocusParent[elementId]) {
  237. firingId = _widgetToFocusParent[elementId];
  238. if(firingId) {
  239. firingObj = $obj(firingId);
  240. nextEventObj = firingObj.interactionMap && firingObj.interactionMap[_descriptionToKey[axEventObject.description]];
  241. if(!nextEventObj) nextEventObj = axEventObject;
  242. _handleEvent(firingId, eventInfo, nextEventObj, skipShowDescriptions, synthetic);
  243. }
  244. return;
  245. }
  246. // Only trigger a supression if it handled this event
  247. if(!bubble && suppressingEvents[eventDescription]) {
  248. suppressedEventStatus[suppressingEvents[eventDescription]] = true;
  249. }
  250. $ax.action.flushAllResizeMoveActions(eventInfo);
  251. // This should not be needed anymore. All refreshes should be inserted, or handled earlier.
  252. var repeaters = $ax.deepCopy($ax.action.repeatersToRefresh);
  253. while($ax.action.repeatersToRefresh.length) $ax.action.repeatersToRefresh.pop();
  254. for(i = 0; i < repeaters.length; i++) $ax.repeater.refreshRepeater(repeaters[i], eventInfo);
  255. if(currentEvent && currentEvent.originalEvent) {
  256. currentEvent.originalEvent.handled = !synthetic && !bubble && allowBubble.indexOf(eventDescription) == -1;
  257. //currentEvent.originalEvent.donotdrag = currentEvent.donotdrag || (!bubble && eventDescription == 'OnMouseDown');
  258. // Prevent default if necessary
  259. if(currentEvent.originalEvent.handled && preventDefaultEvents.indexOf(eventDescription) != -1) {
  260. currentEvent.preventDefault();
  261. }
  262. }
  263. eventNesting -= 1;
  264. if(!showCaseDescriptions) $ax.messageCenter.postMessage('axEventComplete');
  265. };
  266. var _showCaseDescriptions = function(elementId, eventInfo, axEventObject, synthetic) {
  267. if(axEventObject.cases.length == 0) return true;
  268. var linksId = elementId + "linkBox";
  269. $('#' + linksId).remove();
  270. var $container = $("<div class='intcases' id='" + linksId + "'></div>");
  271. if(!_isEventSimulating(axEventObject)) {
  272. var copy = $ax.eventCopy(eventInfo);
  273. for(var i = 0; i < axEventObject.cases.length; i++) {
  274. var $link = $("<div class='intcaselink'>" + axEventObject.cases[i].description + "</div>");
  275. $link.click(function(j) {
  276. return function () {
  277. var currentCase = axEventObject.cases[j];
  278. $ax.messageCenter.postMessage('axCase', { 'description': currentCase.description });
  279. for(var k = 0; k < currentCase.actions.length; k++) {
  280. $ax.messageCenter.postMessage('axAction', { 'description': currentCase.actions[k].description });
  281. }
  282. $ax.messageCenter.postMessage('axEventComplete');
  283. var bubble = $ax.action.dispatchAction(copy, axEventObject.cases[j].actions);
  284. $('#' + linksId).remove();
  285. return bubble;
  286. };
  287. } (i)
  288. );
  289. $container.append($link);
  290. }
  291. } else {
  292. var fullDescription = axEventObject.description + ":<br>";
  293. for(var i = 0; i < axEventObject.cases.length; i++) {
  294. var currentCase = axEventObject.cases[i];
  295. fullDescription += "&nbsp;&nbsp;" + currentCase.description.replace(/<br>/g, '<br>&nbsp;&nbsp;') + ":<br>";
  296. for(var j = 0; j < currentCase.actions.length; j++) {
  297. fullDescription += "&nbsp;&nbsp;&nbsp;&nbsp;" + currentCase.actions[j].description.replace(/<br>/g, '<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;') + "<br>";
  298. }
  299. }
  300. fullDescription = fullDescription.substring(0, fullDescription.length - 4);
  301. var $link = $("<div class='intcaselink'>" + fullDescription + "</div>");
  302. $link.click(function() {
  303. _handleEvent(elementId, eventInfo, axEventObject, true, synthetic);
  304. $ax.messageCenter.postMessage('axEventComplete');
  305. $('#' + linksId).remove();
  306. return;
  307. });
  308. $container.append($link);
  309. }
  310. $container.mouseleave(function(e) { $ax.legacy.SuppressBubble(e); });
  311. $('body').append($container);
  312. _showCaseLinks(eventInfo, linksId);
  313. };
  314. var _showCaseLinks = function(eventInfo, linksId) {
  315. var links = window.document.getElementById(linksId);
  316. links.style.top = eventInfo.pageY;
  317. var left = eventInfo.pageX;
  318. links.style.left = left;
  319. $ax.visibility.SetVisible(links, true);
  320. $ax.legacy.BringToFront(linksId, true);
  321. // Switch to using jquery if this is still needed. Really old legacy code, likely for a browser no longer supported.
  322. //$ax.legacy.RefreshScreen();
  323. };
  324. var _shouldShowCaseDescriptions = function(axEventObject) {
  325. if($ax.document.configuration.linkStyle == "alwaysDisplayTargets") return true;
  326. if($ax.document.configuration.linkStyle == "neverDisplayTargets") return false;
  327. if(axEventObject.cases.length == 0) return false;
  328. if(_isEventSimulating(axEventObject)) return false;
  329. if(axEventObject.cases.length >= 2) return true;
  330. return false;
  331. };
  332. var _isEventSimulating = function(axEventObject) {
  333. for(var i = 0; i < axEventObject.cases.length; i++) {
  334. if(axEventObject.cases[i].condition) return true;
  335. }
  336. return false;
  337. };
  338. var _handleCaseGroup = function(eventInfo, caseGroup, groupRefreshes) {
  339. for(var i = 0; i < caseGroup.length; i++) {
  340. var currentCase = caseGroup[i];
  341. if(!currentCase.condition || _processCondition(currentCase.condition, eventInfo)) {
  342. $ax.messageCenter.postMessage('axCase', { 'description': currentCase.description });
  343. for(var j = 0; j < currentCase.actions.length; j++) {
  344. if(currentCase.actions[j].action != 'refreshRepeater') $ax.messageCenter.postMessage('axAction', { 'description': currentCase.actions[j].description });
  345. }
  346. for(var j = 0; j < currentCase.actions.length; j++) {
  347. var action = currentCase.actions[j];
  348. if(action.action == 'wait') break;
  349. if(action.action != 'refreshRepeater') continue;
  350. for(var k = 0; k < action.repeatersToRefresh.length; k++) {
  351. var id = $ax.getElementIdsFromPath(action.repeatersToRefresh[i], eventInfo)[i];
  352. if(id) {
  353. var index = groupRefreshes.indexOf(id);
  354. if(index != -1) $ax.splice(groupRefreshes, index);
  355. }
  356. }
  357. }
  358. // Any guaranteed refreshes that aren't accounted for must be run still.
  359. $ax.action.tryRefreshRepeaters(groupRefreshes, eventInfo);
  360. $ax.action.dispatchAction(eventInfo, currentCase.actions);
  361. return false;
  362. }
  363. }
  364. // Any guaranteed refreshes that aren't accounted for must be run still.
  365. $ax.action.tryRefreshRepeaters(groupRefreshes, eventInfo);
  366. return true;
  367. };
  368. var _processCondition = function(expr, eventInfo) {
  369. return $ax.expr.evaluateExpr(expr, eventInfo);
  370. };
  371. var _attachTreeNodeEvent = function(elementId, eventName, fn) {
  372. //we need to set the cursor here because we want to make sure that every tree node has the default
  373. //cursor set and then it's overridden if it has a click
  374. if(eventName == 'click') window.document.getElementById(elementId).style.cursor = 'pointer';
  375. _attachCustomObjectEvent(elementId, eventName, fn);
  376. };
  377. var _attachDefaultObjectEvent = function(elementIdQuery, elementId, eventName, fn) {
  378. var func = function() {
  379. if(!$ax.style.IsWidgetDisabled(elementId)) return fn.apply(this, arguments);
  380. return true;
  381. };
  382. var bind = !elementIdQuery[eventName];
  383. if(bind) elementIdQuery.bind(eventName, func);
  384. else elementIdQuery[eventName](func);
  385. };
  386. var _attachCustomObjectEvent = function(elementId, eventName, fn) {
  387. var handlers = _objectIdToEventHandlers[elementId];
  388. if(!handlers) _objectIdToEventHandlers[elementId] = handlers = {};
  389. var fnList = handlers[eventName];
  390. if(!fnList) handlers[eventName] = fnList = [];
  391. fnList[fnList.length] = fn;
  392. };
  393. var _fireObjectEvent = function(elementId, event, originalArgs) {
  394. var element = window.document.getElementById(elementId);
  395. var handlerList = _objectIdToEventHandlers[elementId] && _objectIdToEventHandlers[elementId][event];
  396. if(handlerList) {
  397. for(var i = 0; i < handlerList.length; i++) handlerList[i].apply(element, originalArgs);
  398. }
  399. eventNesting -= 1;
  400. };
  401. var _layerToFocusableWidget = {};
  402. var _widgetToFocusParent = {};
  403. _event.layerMapFocus = function(layer, elementId) {
  404. var mainObj = layer.objs[0];
  405. // If first child non existant return
  406. if (!mainObj) return;
  407. var mainId = $ax.getElementIdFromPath([mainObj.id], { relativeTo: elementId });
  408. _widgetToFocusParent[mainId] = elementId;
  409. // If first child is a layer, call recursively
  410. if ($ax.public.fn.IsLayer(mainObj.type)) {
  411. _event.layerMapFocus(mainObj, mainId);
  412. var baseId = _layerToFocusableWidget[mainId];
  413. if(baseId) _layerToFocusableWidget[elementId] = baseId;
  414. return;
  415. }
  416. _layerToFocusableWidget[elementId] = mainId;
  417. }
  418. var _needsProxy = function(id, proxyName) {
  419. var obj = $obj(id);
  420. // layers don't need on focus ever, proxies will handle them
  421. if ($ax.public.fn.IsLayer(obj.type)) return false;
  422. // If you already focus you don't need to force yourself to proxy.
  423. if(obj.interactionMap && obj.interactionMap[proxyName]) return false;
  424. var parentId = _widgetToFocusParent[id];
  425. if(parentId) return _needsProxyHelper(parentId, proxyName);
  426. return false;
  427. }
  428. var _needsProxyHelper = function(id, proxyName) {
  429. var obj = $obj(id);
  430. if(obj.interactionMap && obj.interactionMap[proxyName]) return true;
  431. var parentId = _widgetToFocusParent[id];
  432. if(parentId) return _needsProxyHelper(parentId, proxyName);
  433. return false;
  434. }
  435. //for button shapes and images the img is focusable instead of the div to get better outlines
  436. // For layers, we remember who their proxy is.
  437. $ax.event.getFocusableWidgetOrChildId = function (elementId) {
  438. var mappedId = _layerToFocusableWidget[elementId];
  439. if (mappedId) elementId = mappedId;
  440. var inputId = $ax.repeater.applySuffixToElementId(elementId, '_input');
  441. var inputQuery = $jobj(inputId);
  442. if(inputQuery.length > 0) return inputId;
  443. var imgId = $ax.repeater.applySuffixToElementId(elementId, '_img');
  444. var imgQuery = $jobj(imgId);
  445. if (imgQuery.length > 0) return imgId;
  446. var divId = $ax.repeater.applySuffixToElementId(elementId, '_div');
  447. var divQuery = $jobj(divId);
  448. if (divQuery.length > 0) return divId;
  449. return elementId;
  450. };
  451. // key is the suppressing event, and the value is the event that is supressed
  452. var suppressingEvents = {};
  453. // key is the event that will cancel the suppression, and value is the event that was being suppressed
  454. var cancelSuppressions = {};
  455. // suppressed event maps to true if it is supressed
  456. var suppressedEventStatus = {};
  457. // Attempt at a generic way to supress events
  458. var initSuppressingEvents = function(query) {
  459. suppressingEvents['OnLongClick'] = 'OnClick';
  460. cancelSuppressions['onMouseDown'] = 'OnClick';
  461. // Have to cancel suppressed event here. Only works for non-synthetic events currently
  462. for(var key in cancelSuppressions) {
  463. var eventName = AXURE_TO_JQUERY_EVENT_NAMES[key];
  464. if(!eventName) continue;
  465. (function(eventName, suppressed) {
  466. query.bind(eventName, function() {
  467. suppressedEventStatus[suppressed] = false;
  468. });
  469. })(eventName, cancelSuppressions[key]);
  470. }
  471. // Otherwise see if you have the chance to cancel a supression
  472. // if(cancelSuppressions[eventDescription]) {
  473. // suppressedEventStatus[cancelSuppressions[eventDescription]] = false;
  474. // }
  475. };
  476. // TODO: It may be a good idea to split this into multiple functions, or at least pull out more similar functions into private methods
  477. var _initializeObjectEvents = function(query, allowItem) {
  478. // Must init the supressing eventing before the handlers, so that it has the ability to supress those events.
  479. initSuppressingEvents(query);
  480. query.each(function(dObj, elementId) {
  481. var $element = $jobj(elementId);
  482. var itemId = $ax.repeater.getItemIdFromElementId(elementId);
  483. // Focus has to be done before on focus fires
  484. // Set up focus
  485. if ($ax.public.fn.IsTextArea(dObj.type) || $ax.public.fn.IsTextBox(dObj.type) || $ax.public.fn.IsCheckBox(dObj.type) || $ax.public.fn.IsRadioButton(dObj.type) ||
  486. $ax.public.fn.IsListBox(dObj.type) || $ax.public.fn.IsComboBox(dObj.type) || $ax.public.fn.IsButton(dObj.type) || $ax.public.fn.IsImageBox(dObj.type) ||
  487. $ax.public.fn.IsVector(dObj.type) || $ax.IsTreeNodeObject(dObj.type) || $ax.public.fn.IsTableCell(dObj.type)) {
  488. var focusObj = $jobj($ax.event.getFocusableWidgetOrChildId(elementId));
  489. focusObj.focus(function() {
  490. window.lastFocusedControl = elementId;
  491. });
  492. }
  493. // [MAS: Supressing events were here]
  494. _createProxies(dObj, elementId);
  495. if(dObj.interactionMap) {
  496. _attachEvents(dObj, elementId);
  497. };
  498. //attach button shape alternate styles
  499. var needsMouseFilter = dObj.type != 'hyperlink' && !$ax.public.fn.IsLayer(dObj.type) && !$ax.public.fn.IsDynamicPanel(dObj.type) && dObj.type != 'richTextPanel' &&
  500. !$ax.public.fn.IsRepeater(dObj.type) && !$ax.public.fn.IsCheckBox(dObj.type) && !$ax.public.fn.IsRadioButton(dObj.type) && !$ax.public.fn.IsTreeNodeObject(dObj.type);
  501. if(needsMouseFilter) {
  502. $element.mouseenter(function() {
  503. var elementId = this.id;
  504. var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId);
  505. if(parent && parent.direct) return;
  506. if($.inArray(elementId, _event.mouseOverIds) != -1) return;
  507. _event.mouseOverIds[_event.mouseOverIds.length] = elementId;
  508. if(elementId == _event.mouseOverObjectId) return;
  509. _event.mouseOverObjectId = elementId;
  510. $ax.style.SetWidgetHover(elementId, true);
  511. var textId = $ax.style.GetTextIdFromShape(elementId);
  512. if(textId) $ax.annotation.updateLinkLocations(textId);
  513. }).mouseleave(function() {
  514. var elementId = this.id;
  515. var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId);
  516. if(parent && parent.direct) return;
  517. $ax.splice(_event.mouseOverIds, $.inArray(elementId, _event.mouseOverIds), 1);
  518. if(elementId == _event.mouseOverObjectId) {
  519. _event.mouseOverObjectId = '';
  520. }
  521. $ax.style.SetWidgetHover(elementId, false);
  522. var textId = $ax.style.GetTextIdFromShape(elementId);
  523. if(textId) $ax.annotation.updateLinkLocations(textId);
  524. });
  525. $element.bind($ax.features.eventNames.mouseDownName, function() {
  526. var elementId = this.id;
  527. var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId);
  528. if(parent) {
  529. dynamicPanelMouseDown(parent.id);
  530. if(parent.direct) return;
  531. }
  532. _event.mouseDownObjectId = elementId;
  533. $ax.style.SetWidgetMouseDown(this.id, true);
  534. $ax.annotation.updateLinkLocations($ax.style.GetTextIdFromShape(elementId));
  535. }).bind($ax.features.eventNames.mouseUpName, function() {
  536. var elementId = this.id;
  537. var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId);
  538. if(parent) {
  539. dynamicPanelMouseUp(parent.id);
  540. if(parent.direct) return;
  541. }
  542. _event.mouseDownObjectId = '';
  543. if(!$ax.style.ObjHasMouseDown(elementId)) return;
  544. $ax.style.SetWidgetMouseDown(elementId, false);
  545. $ax.annotation.updateLinkLocations($ax.style.GetTextIdFromShape(elementId));
  546. //there used to be something we needed to make images click, because swapping out the images prevents the click
  547. // this is a note that we can eventually delete.
  548. });
  549. }
  550. var $axElement = undefined;
  551. var preeval = itemId && !allowItem;
  552. //initialize disabled elements, do this first before selected, cause if a widget is disabled, we don't want to apply selected style anymore
  553. if (($ax.public.fn.IsVector(dObj.type) || $ax.public.fn.IsImageBox(dObj.type) || $ax.public.fn.IsDynamicPanel(dObj.type) || $ax.public.fn.IsLayer(dObj.type))
  554. && dObj.disabled && !preeval) {
  555. if (!$axElement) $axElement = $ax('#' + elementId);
  556. $axElement.enabled(false);
  557. }
  558. // Initialize selected elements if not in repeater
  559. if(($ax.public.fn.IsVector(dObj.type) || $ax.public.fn.IsImageBox(dObj.type) || $ax.public.fn.IsDynamicPanel(dObj.type) || $ax.public.fn.IsLayer(dObj.type))
  560. && dObj.selected && !preeval) {
  561. if(!$axElement) $axElement = $ax('#' + elementId);
  562. $axElement.selected(true);
  563. }
  564. if(OS_MAC && WEBKIT) {
  565. if ($ax.public.fn.IsComboBox(dObj.type) && dObj.disabled) {
  566. $jobj($ax.INPUT(elementId)).css('color', 'grayText');
  567. }
  568. };
  569. // Initialize Placeholders. Right now this is text boxes and text areas.
  570. // Also, the assuption is being made that these widgets with the placeholder, have no other styles (this may change...)
  571. var hasPlaceholder = dObj.placeholderText == '' ? true : Boolean(dObj.placeholderText);
  572. if (($ax.public.fn.IsTextArea(dObj.type) || $ax.public.fn.IsTextBox(dObj.type)) && hasPlaceholder) {
  573. // This is needed to initialize the placeholder state
  574. $jobj($ax.INPUT(elementId)).bind('keydown', function () {
  575. if(!dObj.HideHintOnFocused) {
  576. var id = this.id;
  577. var inputIndex = id.indexOf('_input');
  578. if(inputIndex == -1) return;
  579. var inputId = id.substring(0, inputIndex);
  580. if(!$ax.placeholderManager.isActive(inputId)) return;
  581. $ax.placeholderManager.updatePlaceholder(inputId, false, true);
  582. }
  583. }).bind('keyup', function() {
  584. var id = this.id;
  585. var inputIndex = id.indexOf('_input');
  586. if(inputIndex == -1) return;
  587. var inputId = id.substring(0, inputIndex);
  588. if($ax.placeholderManager.isActive(inputId)) return;
  589. if(!dObj.HideHintOnFocused && !$jobj(id).val()) {
  590. $ax.placeholderManager.updatePlaceholder(inputId, true);
  591. $ax.placeholderManager.moveCaret(id, 0);
  592. }
  593. }).bind('focus', function () {
  594. if(dObj.HideHintOnFocused) {
  595. var id = this.id;
  596. var inputIndex = id.indexOf('_input');
  597. if (inputIndex == -1) return;
  598. var inputId = id.substring(0, inputIndex);
  599. if (!$ax.placeholderManager.isActive(inputId)) return;
  600. $ax.placeholderManager.updatePlaceholder(inputId, false, true);
  601. }
  602. $ax.placeholderManager.moveCaret(this.id);
  603. }).bind('mouseup', function() {
  604. $ax.placeholderManager.moveCaret(this.id);
  605. }).bind('blur', function() {
  606. var id = this.id;
  607. var inputIndex = id.indexOf('_input');
  608. if(inputIndex == -1) return;
  609. var inputId = id.substring(0, inputIndex);
  610. if($jobj(id).val()) return;
  611. $ax.placeholderManager.updatePlaceholder(inputId, true);
  612. });
  613. $ax.placeholderManager.registerPlaceholder(elementId, dObj.placeholderText, $jobj($ax.INPUT(elementId)).attr('type') == 'password');
  614. $ax.placeholderManager.updatePlaceholder(elementId, !($jobj($ax.repeater.applySuffixToElementId(elementId, '_input')).val()));
  615. }
  616. // Initialize assigned submit buttons
  617. if(dObj.submitButton) {
  618. $element.keyup(function(e) {
  619. if(e.keyCode == '13') {
  620. var scriptId = $ax.repeater.getScriptIdFromElementId(elementId);
  621. var path = $ax.deepCopy(dObj.submitButton.path);
  622. path[path.length] = dObj.submitButton.id;
  623. var itemNum = $ax.repeater.getItemIdFromElementId(elementId);
  624. var submitId = $ax.getScriptIdFromPath(path, scriptId);
  625. if(itemNum && $ax.getParentRepeaterFromScriptId(submitId) == $ax.getParentRepeaterFromScriptId(scriptId)) {
  626. submitId = $ax.repeater.createElementId(submitId, itemNum);
  627. }
  628. var inputId = $ax.INPUT(submitId);
  629. if($jobj(inputId).length) submitId = inputId;
  630. $ax.setjBrowserEvent(e);
  631. $ax.event.fireClick(submitId);
  632. }
  633. }).keydown(function(e) {
  634. if(e.keyCode == '13') {
  635. e.preventDefault();
  636. }
  637. });
  638. }
  639. // Don't drag after mousing down on a plain text object
  640. if ($ax.public.fn.IsTextArea(dObj.type) || $ax.public.fn.IsTextBox(dObj.type) || $ax.public.fn.IsListBox(dObj.type) ||
  641. $ax.public.fn.IsComboBox(dObj.type) || $ax.public.fn.IsCheckBox(dObj.type) || $ax.public.fn.IsRadioButton(dObj.type)) {
  642. $element.bind($ax.features.eventNames.mouseDownName, function(event) {
  643. event.originalEvent.donotdrag = true;
  644. });
  645. }
  646. if($ax.features.supports.mobile) {
  647. $element.bind($ax.features.eventNames.mouseDownName, function() { _setCanClick(true); });
  648. if ($ax.public.fn.IsDynamicPanel(dObj.type)) {
  649. $element.scroll(function() { _setCanClick(false); });
  650. }
  651. }
  652. //initialize tree node cursors to default so they will override their parent
  653. if ($ax.public.fn.IsTreeNodeObject(dObj.type) && !(dObj.interactionMap && dObj.interactionMap.onClick)) {
  654. $element.css('cursor', 'default');
  655. }
  656. //initialize widgets that are clickable to have the pointer over them when hovering
  657. if($ax.event.HasClick(dObj)) {
  658. if($element) $element.css('cursor', 'pointer');
  659. }
  660. // TODO: not sure if we need this. It appears to be working without
  661. //initialize panels for DynamicPanels
  662. if ($ax.public.fn.IsDynamicPanel(dObj.type)) {
  663. $element.children().each(function() {
  664. var parts = this.id.split('_');
  665. var state = parts[parts.length - 1].substring(5);
  666. if(state != 0) $ax.visibility.SetVisible(this, false);
  667. });
  668. }
  669. //initialize TreeNodes
  670. if ($ax.public.fn.IsTreeNodeObject(dObj.type)) {
  671. if($element.hasClass('treeroot')) return;
  672. var childrenId = elementId + '_children';
  673. var children = $element.children('[id="' + childrenId + '"]:first');
  674. if(children.length > 0) {
  675. var plusMinusId = 'u' + (parseInt($ax.repeater.getScriptIdFromElementId(elementId).substring(1)) + 1);
  676. if(itemId) plusMinusId = $ax.repeater.createElementId(plusMinusId, itemId);
  677. if(!$jobj(plusMinusId).children().first().is('img')) plusMinusId = '';
  678. $ax.tree.InitializeTreeNode(elementId, plusMinusId, childrenId);
  679. }
  680. $element.click(function() { $ax.tree.SelectTreeNode(elementId, true); });
  681. }
  682. //initialize submenus
  683. if ($ax.public.fn.IsMenuObject(dObj.type)) {
  684. if($element.hasClass('sub_menu')) {
  685. var tableCellElementId = $ax.getElementIdFromPath([dObj.parentCellId], { relativeTo: elementId });
  686. $ax.menu.InitializeSubmenu(elementId, tableCellElementId);
  687. }
  688. }
  689. // Attach handles for dynamic panels that propagate styles to inner items.
  690. if (($ax.public.fn.IsDynamicPanel(dObj.type) || $ax.public.fn.IsLayer(dObj.type)) && dObj.propagate) {
  691. $element.mouseenter(function() {
  692. dynamicPanelMouseOver(this.id);
  693. }).mouseleave(function() {
  694. dynamicPanelMouseLeave(this.id);
  695. }).bind($ax.features.eventNames.mouseDownName, function() {
  696. dynamicPanelMouseDown(this.id);
  697. }).bind($ax.features.eventNames.mouseUpName, function() {
  698. dynamicPanelMouseUp(this.id);
  699. });
  700. }
  701. // These are the dynamic panel functions for propagating rollover styles and mouse down styles to inner objects
  702. var dynamicPanelMouseOver = function(elementId, fromChild) {
  703. var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId);
  704. if(parent) {
  705. dynamicPanelMouseOver(parent.id, true);
  706. if(parent.direct) return;
  707. }
  708. if($.inArray(elementId, _event.mouseOverIds) != -1) return;
  709. // If this event is coming from a child, don't mark that it's actually entered.
  710. // Only mark that this has been entered if this event has naturally been triggered. (For reason see mouseleave)
  711. if(!fromChild) _event.mouseOverIds[_event.mouseOverIds.length] = elementId;
  712. if(elementId == _event.mouseOverObjectId) return;
  713. _event.mouseOverObjectId = elementId;
  714. $ax.dynamicPanelManager.propagateMouseOver(elementId, true);
  715. };
  716. var dynamicPanelMouseLeave = function(elementId, fromChild) {
  717. var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId);
  718. if(parent) {
  719. dynamicPanelMouseLeave(parent.id, true);
  720. if(parent.direct) return;
  721. }
  722. var index = $.inArray(elementId, _event.mouseOverIds);
  723. // If index != -1, this has been natuarally entered. If naturally entered, then leaving child should not trigger leaving,
  724. // but instead wait for natural mouse leave. If natural mouse enter never triggered, natural mouse leave won't so do this now.
  725. if((index != -1) && fromChild) return;
  726. $ax.splice(_event.mouseOverIds, index, 1);
  727. if(elementId == _event.mouseOverObjectId) {
  728. _event.mouseOverObjectId = '';
  729. }
  730. $ax.dynamicPanelManager.propagateMouseOver(elementId, false);
  731. };
  732. var dynamicPanelMouseDown = function(elementId) {
  733. var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId);
  734. if(parent) {
  735. dynamicPanelMouseDown(parent.id);
  736. if(parent.direct) return;
  737. }
  738. _event.mouseDownObjectId = elementId;
  739. $ax.dynamicPanelManager.propagateMouseDown(elementId, true);
  740. };
  741. var dynamicPanelMouseUp = function(elementId) {
  742. var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId);
  743. if(parent) {
  744. dynamicPanelMouseUp(parent.id);
  745. if(parent.direct) return;
  746. }
  747. _event.mouseDownObjectId = '';
  748. $ax.dynamicPanelManager.propagateMouseDown(elementId, false);
  749. };
  750. //attach handlers for button shape and tree node mouse over styles
  751. // TODO: Can this really be removed? Trees seem to work with out (the generic hover case works for it).
  752. // query.filter(function(obj) {
  753. // return $ax.public.fn.IsVector(obj.type) && $ax.public.fn.IsTreeNodeObject(obj.parent.type) &&
  754. // obj.parent.style && obj.parent.style.stateStyles &&
  755. // obj.parent.style.stateStyles.mouseOver;
  756. // }).mouseenter(function() {
  757. // $ax.style.SetWidgetHover(this.id, true);
  758. // }).mouseleave(function() {
  759. // $ax.style.SetWidgetHover(this.id, false);
  760. // });
  761. //handle treeNodeObject events and prevent them from bubbling up. this is necessary because otherwise
  762. //both a sub menu and it's parent would get a click
  763. if ($ax.public.fn.IsTreeNodeObject(dObj.type)) {
  764. $element.click(function() {
  765. //todo -- this was bubbling, but then selecting a child tree node would bubble and select the parent (don't know if there is a better way)
  766. _fireObjectEvent(this.id, 'click', arguments);
  767. return false;
  768. }).each(function() {
  769. if(!this.style.cursor) {
  770. this.style.cursor = 'default';
  771. }
  772. });
  773. }
  774. // Synthetic events
  775. var map = dObj.interactionMap;
  776. // Attach dynamic panel synthetic drag and swipe events
  777. if(dObj.type == "dynamicPanel" && map && (
  778. map.onDragStart || map.onDrag ||
  779. map.onDragDrop || map.onSwipeLeft || map.onSwipeRight || map.onSwipeUp || map.onSwipeDown)) {
  780. $element.bind($ax.features.eventNames.mouseDownName, function(e) { $ax.drag.StartDragWidget(e.originalEvent, elementId); });
  781. }
  782. // Attach dynamic panel synthetic scroll event
  783. if ($ax.public.fn.IsDynamicPanel(dObj.type) && map && (map.onScroll || map.onScrollUp || map.onScrollDown)) {
  784. var diagrams = dObj.diagrams;
  785. for(var i = 0; i < diagrams.length; i++) {
  786. var panelId = $ax.repeater.applySuffixToElementId(elementId, '_state' + i);
  787. (function(id) {
  788. if ($('#' + id).data('lastScrollTop') == undefined) $('#' + id).data('lastScrollTop', '0');
  789. _attachDefaultObjectEvent($('#' + id), elementId, 'scroll', function(e) {
  790. $ax.setjBrowserEvent(e);
  791. var currentEvent = $ax.getjBrowserEvent();
  792. var eventInfoFromEvent = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), false, elementId);
  793. if(map.onScroll) _handleEvent(elementId, eventInfoFromEvent, map.onScroll);
  794. var currentTop = $('#' + id).scrollTop();
  795. var wasHandled = currentEvent.originalEvent.handled;
  796. if (map.onScrollUp && currentTop < $('#' + id).data('lastScrollTop')) {
  797. currentEvent.originalEvent.handled = false;
  798. _handleEvent(elementId, eventInfoFromEvent, map.onScrollUp);
  799. } else if (map.onScrollDown && currentTop > $('#' + id).data('lastScrollTop')) {
  800. currentEvent.originalEvent.handled = false;
  801. _handleEvent(elementId, eventInfoFromEvent, map.onScrollDown);
  802. }
  803. currentEvent.originalEvent.handled |= wasHandled;
  804. $('#' + id).data('lastScrollTop', currentTop);
  805. });
  806. })(panelId);
  807. }
  808. }
  809. // Attach synthetic hover event
  810. if (map && map.onMouseHover) {
  811. var MIN_HOVER_HOLD_TIME = 1000;
  812. // So when the timeout fires, you know whether it is the same mouseenter that is active or not.
  813. var hoverMouseCount = 0;
  814. // Update eventInfo regularly, so position is accurate.
  815. var hoverEventInfo;
  816. $element.mouseenter(function(e) {
  817. $ax.setjBrowserEvent(e);
  818. hoverEventInfo = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), false, elementId);
  819. (function(currCount) {
  820. window.setTimeout(function() {
  821. if(currCount == hoverMouseCount) _raiseSyntheticEvent(elementId, 'onMouseHover', false, hoverEventInfo, true);
  822. }, MIN_HOVER_HOLD_TIME);
  823. })(hoverMouseCount);
  824. }).mouseleave(function(e) {
  825. $ax.setjBrowserEvent(e);
  826. hoverMouseCount++;
  827. }).mousemove(function(e) {
  828. $ax.setjBrowserEvent(e);
  829. hoverEventInfo = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), false, elementId);
  830. });
  831. }
  832. // Attach synthetic tap and hold event.
  833. if (map && map.onLongClick) {
  834. var MIN_LONG_CLICK_HOLD_TIME = 750;
  835. // So when the timeout fires, you know whether it is the same mousedown that is active or not.
  836. var longClickMouseCount = 0;
  837. $element.bind($ax.features.eventNames.mouseDownName, function(e) {
  838. (function(currCount) {
  839. $ax.setjBrowserEvent(e);
  840. var eventInfo = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), false, elementId);
  841. window.setTimeout(function() {
  842. if(currCount == longClickMouseCount) _raiseSyntheticEvent(elementId, 'onLongClick', false, eventInfo, true);
  843. }, MIN_LONG_CLICK_HOLD_TIME);
  844. if(e.preventDefault) e.preventDefault();
  845. })(longClickMouseCount);
  846. }).bind($ax.features.eventNames.mouseUpName, function(e) {
  847. $ax.setjBrowserEvent(e);
  848. longClickMouseCount++;
  849. });
  850. };
  851. // Attach synthetic onSelectionChange event to droplist and listbox elements
  852. if ($ax.event.HasSelectionChanged(dObj)) {
  853. $element.bind('change', function(e) {
  854. $ax.setjBrowserEvent(e);
  855. _raiseSyntheticEvent(elementId, 'onSelectionChange');
  856. });
  857. };
  858. // Highjack key up and key down to keep track of state of keyboard.
  859. _event.initKeyEvents($element);
  860. // Attach synthetic onTextChange event to textbox and textarea elements
  861. if ($ax.event.HasTextChanged(dObj)) {
  862. var element = $jobj($ax.INPUT(elementId));
  863. $ax.updateElementText(elementId, element.val());
  864. //Key down needed because when holding a key down, key up only fires once, but keydown fires repeatedly.
  865. //Key up because last mouse down will only show the state before the last character.
  866. element.bind('keydown', function(e) {
  867. $ax.setjBrowserEvent(e);
  868. $ax.event.TryFireTextChanged(elementId);
  869. }).bind('keyup', function(e) {
  870. $ax.setjBrowserEvent(e);
  871. $ax.event.TryFireTextChanged(elementId);
  872. });
  873. };
  874. // Attach synthetic onCheckedChange event to radiobutton and checkbox elements
  875. if ($ax.public.fn.IsCheckBox(dObj.type) || $ax.public.fn.IsRadioButton(dObj.type)) {
  876. var input = $jobj($ax.INPUT(elementId));
  877. if ($ax.public.fn.IsRadioButton(dObj.type) && input.prop('checked')) {
  878. $ax.updateRadioButtonSelected(input.attr('name'), elementId);
  879. }
  880. $element.bind('change', function(e) {
  881. $ax.setjBrowserEvent(e);
  882. var eTarget = e.target || e.srcElement;
  883. _tryFireCheckedChanged(elementId, eTarget.checked);
  884. });
  885. };
  886. var hasTap = map && (map.onClick || map.onDoubleClick);
  887. var hasMove = map && map.onMouseMove;
  888. _event.initMobileEvents(hasTap ? $element : $(),
  889. hasMove ? $element : $(), elementId);
  890. //attach link alternate styles
  891. if(dObj.type == 'hyperlink') {
  892. $element.mouseenter(function() {
  893. var elementId = this.id;
  894. if(_event.mouseOverIds.indexOf(elementId) != -1) return true;
  895. _event.mouseOverIds[_event.mouseOverIds.length] = elementId;
  896. var mouseOverObjectId = _event.mouseOverObjectId;
  897. if(mouseOverObjectId && $ax.style.IsWidgetDisabled(mouseOverObjectId)) return true;
  898. $ax.style.SetLinkHover(elementId);
  899. var bubble = _fireObjectEvent(elementId, 'mouseenter', arguments);
  900. $ax.annotation.updateLinkLocations($ax.style.GetTextIdFromLink(elementId));
  901. return bubble;
  902. }).mouseleave(function() {
  903. var elementId = this.id;
  904. $ax.splice(_event.mouseOverIds, _event.mouseOverIds.indexOf(elementId), 1);
  905. var mouseOverObjectId = _event.mouseOverObjectId;
  906. if(mouseOverObjectId && $ax.style.IsWidgetDisabled(mouseOverObjectId)) return true;
  907. $ax.style.SetLinkNotHover(elementId);
  908. var bubble = _fireObjectEvent(elementId, 'mouseleave', arguments);
  909. $ax.annotation.updateLinkLocations($ax.style.GetTextIdFromLink(elementId));
  910. return bubble;
  911. }).bind($ax.features.eventNames.mouseDownName, function() {
  912. var elementId = this.id;
  913. var mouseOverObjectId = _event.mouseOverObjectId;
  914. if($ax.style.IsWidgetDisabled(mouseOverObjectId)) return undefined;
  915. if(mouseOverObjectId) $ax.style.SetWidgetMouseDown(mouseOverObjectId, true);
  916. $ax.style.SetLinkMouseDown(elementId);
  917. $ax.annotation.updateLinkLocations($ax.style.GetTextIdFromLink(elementId));
  918. return false;
  919. }).bind($ax.features.eventNames.mouseUpName, function() {
  920. var elementId = this.id;
  921. var mouseOverObjectId = _event.mouseOverObjectId;
  922. if(mouseOverObjectId && $ax.style.IsWidgetDisabled(mouseOverObjectId)) return;
  923. if(mouseOverObjectId) $ax.style.SetWidgetMouseDown(mouseOverObjectId, false);
  924. $ax.style.SetLinkNotMouseDown(elementId);
  925. $ax.annotation.updateLinkLocations($ax.style.GetTextIdFromLink(elementId));
  926. }).click(function() {
  927. var elementId = this.id;
  928. var mouseOverObjectId = _event.mouseOverObjectId;
  929. if(mouseOverObjectId && $ax.style.IsWidgetDisabled(mouseOverObjectId)) return undefined;
  930. return _fireObjectEvent(elementId, 'click', arguments);
  931. });
  932. }
  933. // Init inline frames
  934. if (dObj.type == 'inlineFrame') {
  935. var target = dObj.target;
  936. var url = '';
  937. if(target.includeVariables && target.url) {
  938. var origSrc = target.url;
  939. url = origSrc.toLowerCase().indexOf('http://') == -1 ? $ax.globalVariableProvider.getLinkUrl(origSrc) : origSrc;
  940. } else if(target.urlLiteral) {
  941. url = $ax.expr.evaluateExpr(target.urlLiteral, $ax.getEventInfoFromEvent(undefined, true, elementId), true);
  942. }
  943. if(url) $jobj($ax.INPUT(elementId)).attr('src', url);
  944. };
  945. });
  946. }
  947. $ax.initializeObjectEvents = _initializeObjectEvents;
  948. // Handle key up and key down events
  949. (function() {
  950. var _keyState = {};
  951. _keyState.ctrl = false;
  952. _keyState.alt = false;
  953. _keyState.shift = false;
  954. _keyState.keyCode = 0;
  955. $ax.event.keyState = function() {
  956. return $ax.deepCopy(_keyState);
  957. };
  958. var modifierCodes = [16, 17, 18];
  959. var clearKeyCode = false;
  960. $ax.event.initKeyEvents = function($query) {
  961. $query.keydown(function (e) {
  962. if(clearKeyCode) {
  963. clearKeyCode = false;
  964. _keyState.keyCode = 0;
  965. }
  966. var elementId = this.id;
  967. _keyState.ctrl = e.ctrlKey;
  968. _keyState.alt = e.altKey;
  969. _keyState.shift = e.shiftKey;
  970. // If a modifier was pressed, then don't set the keyCode;
  971. if(modifierCodes.indexOf(e.keyCode) == -1) _keyState.keyCode = e.keyCode;
  972. $ax.setjBrowserEvent(e);
  973. if (!elementId) fireEventThroughContainers('onKeyDown', undefined, false, [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE, $ax.constants.DYNAMIC_PANEL_TYPE, $ax.constants.REPEATER],
  974. [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE, $ax.constants.LAYER_TYPE]);
  975. else _raiseSyntheticEvent(elementId, 'onKeyDown', false, undefined, true);
  976. });
  977. $query.keyup(function(e) {
  978. var elementId = this.id;
  979. if (modifierCodes.indexOf(e.keyCode) == -1) clearKeyCode = true;
  980. else if (clearKeyCode) {
  981. clearKeyCode = false;
  982. _keyState.keyCode = 0;
  983. }
  984. $ax.setjBrowserEvent(e);
  985. // Fire event before updating modifiers.
  986. if (!elementId) fireEventThroughContainers('onKeyUp', undefined, false, [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE, $ax.constants.DYNAMIC_PANEL_TYPE, $ax.constants.REPEATER],
  987. [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE, $ax.constants.LAYER_TYPE]);
  988. else _raiseSyntheticEvent(elementId, 'onKeyUp', false, undefined, true);
  989. //_keyState.ctrl = e.ctrlKey;
  990. //_keyState.alt = e.altKey;
  991. //_keyState.shift = e.shiftKey;
  992. //// If a non-modifier was lifted, clear the keycode
  993. ///if(modifierCodes.indexOf(e.keyCode) == -1) _keyState.keyCode = 0;
  994. });
  995. };
  996. })();
  997. // Handle adding mobile events
  998. (function() {
  999. // NOTE: Multi touch is NOT handled currently.
  1000. var CLICK_THRESHOLD_PX = 25;
  1001. var CLICK_THRESHOLD_PX_SQ = CLICK_THRESHOLD_PX * CLICK_THRESHOLD_PX;
  1002. var DBLCLICK_THRESHOLD_MS = 500;
  1003. // Location in page cooridinates
  1004. var tapDownLoc;
  1005. var lastClickEventTime;
  1006. _event.initMobileEvents = function($tapQuery, $moveQuery, elementId) {
  1007. if(!$ax.features.supports.mobile) return;
  1008. // Handle touch start
  1009. $tapQuery.bind('touchstart', function(e) {
  1010. // We do NOT support multiple touches. This isn't necessarily the touch we want.
  1011. var touch = e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0];
  1012. if(!touch) return;
  1013. tapDownLoc = [touch.pageX, touch.pageY];
  1014. var time = (new Date()).getTime();
  1015. if(time - lastClickEventTime < DBLCLICK_THRESHOLD_MS) {
  1016. var dObj = elementId === '' ? $ax.pageData.page : $ax.getObjectFromElementId(elementId);
  1017. var axEventObject = dObj && dObj.interactionMap && dObj.interactionMap['onDoubleClick'];
  1018. if(axEventObject) e.preventDefault(); //for Chrome on Android
  1019. }
  1020. }).bind('touchend', function(e) {
  1021. var touch = e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0];
  1022. if(!touch || !tapDownLoc) return;
  1023. var tapUpLoc = [touch.pageX, touch.pageY];
  1024. var xDiff = tapUpLoc[0] - tapDownLoc[0];
  1025. var yDiff = tapUpLoc[1] - tapDownLoc[1];
  1026. if((xDiff * xDiff + yDiff * yDiff) < CLICK_THRESHOLD_PX_SQ) {
  1027. $ax.setjBrowserEvent(e);
  1028. _raiseSyntheticEvent(elementId, 'onClick', false, undefined, true);
  1029. var time = (new Date()).getTime();
  1030. if(time - lastClickEventTime < DBLCLICK_THRESHOLD_MS) {
  1031. _raiseSyntheticEvent(elementId, 'onDoubleClick', false, undefined, true);
  1032. if(e.originalEvent && e.originalEvent.handled) e.preventDefault(); //for iOS
  1033. }
  1034. lastClickEventTime = time;
  1035. }
  1036. });
  1037. // Handles touch move
  1038. $moveQuery.bind('touchmove', function(e) {
  1039. $ax.setjBrowserEvent(e);
  1040. _raiseSyntheticEvent(elementId, 'onMouseMove', false, undefined, true);
  1041. if(e.originalEvent && e.originalEvent.handled) e.preventDefault();
  1042. });
  1043. };
  1044. })();
  1045. // Handle adding device independent click events to non-widgets
  1046. (function() {
  1047. var CLICK_THRESHOLD_PX = 25;
  1048. var CLICK_THRESHOLD_PX_SQ = CLICK_THRESHOLD_PX * CLICK_THRESHOLD_PX;
  1049. // Location in page cooridinates
  1050. var tapDownLoc;
  1051. _event.attachClick = function(query, clickHandler) {
  1052. if(!$ax.features.supports.mobile) {
  1053. query.click(clickHandler);
  1054. return;
  1055. }
  1056. $(query).bind('touchstart', function(e) {
  1057. // We do NOT support multiple touches. This isn't necessarily the touch we want.
  1058. var touch = e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0];
  1059. if(!touch) return;
  1060. tapDownLoc = [touch.pageX, touch.pageY];
  1061. });
  1062. $(query).bind('touchend', function(e) {
  1063. var touch = e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0];
  1064. if(!touch) return;
  1065. var tapUpLoc = [touch.pageX, touch.pageY];
  1066. var xDiff = tapUpLoc[0] - tapDownLoc[0];
  1067. var yDiff = tapUpLoc[1] - tapDownLoc[1];
  1068. if((xDiff * xDiff + yDiff * yDiff) < CLICK_THRESHOLD_PX_SQ) {
  1069. clickHandler();
  1070. }
  1071. });
  1072. };
  1073. })();
  1074. // Handle firing device independent click events on widgets
  1075. (function() {
  1076. _event.fireClick = function(elementId) {
  1077. if(!$ax.features.supports.mobile) {
  1078. $('#' + elementId).click();
  1079. return;
  1080. }
  1081. _raiseSyntheticEvent(elementId, 'onClick', false, undefined, true);
  1082. };
  1083. })();
  1084. var _mouseLocation = $ax.mouseLocation = { x: 0, y: 0 };
  1085. var _lastmouseLocation = $ax.lastMouseLocation = { x: 0, y: 0 };
  1086. var _updateMouseLocation = function(e, end) {
  1087. if(!e) return;
  1088. if(IE_10_AND_BELOW && typeof (e.type) == 'unknown') return;
  1089. if(e.type != 'mousemove' && e.type != 'touchstart' && e.type != 'touchmove' && e.type != 'touchend') return;
  1090. var newX;
  1091. var newY;
  1092. if(IE_10_AND_BELOW) {
  1093. newX = e.clientX + $('html').scrollLeft();
  1094. newY = e.clientY + $('html').scrollTop();
  1095. } else {
  1096. newX = e.pageX;
  1097. newY = e.pageY;
  1098. }
  1099. //var body = $('body');
  1100. //if(body.css('position') == 'relative') newX = Math.round(newX - Number(body.css('left').replace('px', '')) - Math.max(0, ($(window).width() - body.width()) / 2));
  1101. if(_mouseLocation.x == newX && _mouseLocation.y == newY) return;
  1102. _lastmouseLocation.x = _mouseLocation.x;
  1103. _lastmouseLocation.y = _mouseLocation.y;
  1104. _mouseLocation.x = newX;
  1105. _mouseLocation.y = newY;
  1106. $ax.geometry.tick(_mouseLocation.x, _mouseLocation.y, end);
  1107. };
  1108. _event.updateMouseLocation = _updateMouseLocation;
  1109. var _leavingState = function(stateId) {
  1110. var mouseOverIds = _event.mouseOverIds;
  1111. if(mouseOverIds.length == 0) return;
  1112. var stateQuery = $jobj(stateId);
  1113. for(var i = mouseOverIds.length - 1; i >= 0; i--) {
  1114. var id = mouseOverIds[i];
  1115. if(stateQuery.find('#' + id).length) {
  1116. $ax.splice(mouseOverIds, $.inArray(id, mouseOverIds), 1);
  1117. $ax.style.SetWidgetMouseDown(id, false);
  1118. $ax.style.SetWidgetHover(id, false);
  1119. }
  1120. }
  1121. };
  1122. _event.leavingState = _leavingState;
  1123. var _raiseSelectedEvents = function(elementId, value) {
  1124. $ax.event.raiseSyntheticEvent(elementId, 'onSelectedChange');
  1125. if(value) $ax.event.raiseSyntheticEvent(elementId, 'onSelect');
  1126. else $ax.event.raiseSyntheticEvent(elementId, 'onUnselect');
  1127. };
  1128. $ax.event.raiseSelectedEvents = _raiseSelectedEvents;
  1129. var _raiseSyntheticEvent = function(elementId, eventName, skipShowDescription, eventInfo, nonSynthetic) {
  1130. // Empty string used when this is an event directly on the page.
  1131. var dObj = elementId === '' ? $ax.pageData.page : $ax.getObjectFromElementId(elementId);
  1132. var axEventObject = dObj && dObj.interactionMap && dObj.interactionMap[eventName];
  1133. if(!axEventObject) return;
  1134. eventInfo = eventInfo || $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), skipShowDescription, elementId);
  1135. // $ax.recording.maybeRecordEvent(elementId, eventInfo, axEventObject, new Date().getTime());
  1136. _handleEvent(elementId, eventInfo, axEventObject, false, !nonSynthetic);
  1137. };
  1138. $ax.event.raiseSyntheticEvent = _raiseSyntheticEvent;
  1139. var _hasSyntheticEvent = function(scriptId, eventName) {
  1140. var dObj = $ax.getObjectFromScriptId(scriptId);
  1141. var axEventObject = dObj && dObj.interactionMap && dObj.interactionMap[eventName];
  1142. return Boolean(axEventObject);
  1143. };
  1144. $ax.event.hasSyntheticEvent = _hasSyntheticEvent;
  1145. var _addEvent = function (target, eventType, handler, useCapture) {
  1146. //this return value is only for debug purpose
  1147. var succeed = undefined;
  1148. if(target.attachEvent) {
  1149. if($ax.features.supports.windowsMobile) {
  1150. succeed = target.attachEvent(eventType, handler);
  1151. } else {
  1152. succeed = target.attachEvent('on' + eventType, handler);
  1153. }
  1154. } else if(target.addEventListener) {
  1155. target.addEventListener(eventType, handler, useCapture);
  1156. succeed = true;
  1157. }
  1158. return succeed;
  1159. }
  1160. $ax.event.addEvent = _addEvent;
  1161. var _removeEvent = function(target, eventType, handler, useCapture, skipCheckingWindowsMobile) {
  1162. //this return value is only for debug purpose
  1163. var succeed = undefined;
  1164. if(target.detachEvent) {
  1165. if(!skipCheckingWindowsMobile && $ax.features.supports.windowsMobile) {
  1166. succeed = target.detachEvent(eventType, handler);
  1167. } else {
  1168. succeed = target.detachEvent('on' + eventType, handler);
  1169. }
  1170. } else if(target.removeEventListener) {
  1171. target.removeEventListener(eventType, handler, useCapture);
  1172. succeed = true;
  1173. }
  1174. return succeed;
  1175. }
  1176. $ax.event.removeEvent = _removeEvent;
  1177. var _initialize = function() {
  1178. $ax.repeater.load();
  1179. // Make sure key events for page are initialized first. That way they will update the value of key pressed before any other events occur.
  1180. _event.initKeyEvents($(window));
  1181. // Anything with an item id is in a repeater and should be handled by that repeater.
  1182. _initializeObjectEvents($ax(function(obj, elementId) { return !$ax.repeater.getItemIdFromElementId(elementId); }));
  1183. //finally, process the pageload
  1184. _pageLoad();
  1185. // _loadDynamicPanelsAndMasters();
  1186. // $ax.repeater.init();
  1187. // and wipe out the basic links.
  1188. $('.basiclink').click(function() {
  1189. return false;
  1190. });
  1191. };
  1192. _event.initialize = _initialize;
  1193. $ax.event.HasTextChanged = function(diagramObject) {
  1194. if (!$ax.public.fn.IsTextBox(diagramObject.type) && !$ax.public.fn.IsTextArea(diagramObject.type)) return false;
  1195. var map = diagramObject.interactionMap;
  1196. return map && map.onTextChange;
  1197. };
  1198. $ax.event.TryFireTextChanged = function(elementId) {
  1199. var query = $jobj($ax.repeater.applySuffixToElementId(elementId, '_input'));
  1200. if(!$ax.hasElementTextChanged(elementId, query.val())) return;
  1201. $ax.updateElementText(elementId, query.val());
  1202. $ax.event.raiseSyntheticEvent(elementId, 'onTextChange');
  1203. };
  1204. $ax.event.HasSelectionChanged = function(diagramObject) {
  1205. if (!$ax.public.fn.IsListBox(diagramObject.type) && !$ax.public.fn.IsComboBox(diagramObject.type)) return false;
  1206. var map = diagramObject.interactionMap;
  1207. return map && map.onSelectionChange;
  1208. };
  1209. $ax.event.HasCheckedChanged = function(diagramObject) {
  1210. if (!$ax.public.fn.IsCheckBox(diagramObject.type) && !$ax.public.fn.IsRadioButton(diagramObject.type)) return false;
  1211. var map = diagramObject.interactionMap;
  1212. return map && map.onSelectedChange;
  1213. };
  1214. $ax.event.HasClick = function (diagramObject) {
  1215. var map = diagramObject.interactionMap;
  1216. return map && map.onClick;
  1217. };
  1218. var _tryFireCheckedChanged = $ax.event.TryFireCheckChanged = function(elementId, value) {
  1219. var isRadio = $ax.public.fn.IsRadioButton($obj(elementId).type);
  1220. if(isRadio) {
  1221. if(!value) {
  1222. $ax.updateRadioButtonSelected($jobj($ax.INPUT(elementId)).attr('name'), undefined);
  1223. } else {
  1224. var last = $ax.updateRadioButtonSelected($jobj($ax.INPUT(elementId)).attr('name'), elementId);
  1225. // If no change, this should not fire
  1226. if(last == elementId) return;
  1227. // Initially selecting one, last may be undefined
  1228. if(last) {
  1229. //here last is the previouse selected elementid
  1230. $ax.event.raiseSelectedEvents(last, false);
  1231. }
  1232. }
  1233. }
  1234. $ax.event.raiseSelectedEvents(elementId, value);
  1235. };
  1236. //onload everything now, not only dp and master
  1237. var _loadDynamicPanelsAndMasters = function(objects, path, itemId) {
  1238. fireEventThroughContainers('onLoad', objects, true, [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE, $ax.constants.DYNAMIC_PANEL_TYPE],
  1239. [$ax.constants.ALL_TYPE], path, itemId);
  1240. };
  1241. $ax.loadDynamicPanelsAndMasters = _loadDynamicPanelsAndMasters;
  1242. var _viewChangePageAndMasters = function(forceSwitchTo) {
  1243. fireEventThroughContainers('onAdaptiveViewChange', undefined, true, [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE, $ax.constants.DYNAMIC_PANEL_TYPE],
  1244. [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE]);
  1245. _postAdaptiveViewChanged(forceSwitchTo);
  1246. };
  1247. $ax.viewChangePageAndMasters = _viewChangePageAndMasters;
  1248. //if forceSwitchTo is true, we will also update the checkmark in sitemap.js
  1249. var _postAdaptiveViewChanged = function(forceSwitchTo) {
  1250. //only trigger adaptive view changed if the window is on the mainframe. Also triggered on init, even if default.
  1251. try {
  1252. if(window.name == 'mainFrame' ||
  1253. (!CHROME_5_LOCAL && window.parent.$ && window.parent.$('#mainFrame').length > 0)) {
  1254. var data = {
  1255. viewId: $ax.adaptive.currentViewId,
  1256. forceSwitchTo: forceSwitchTo
  1257. };
  1258. $axure.messageCenter.postMessage('adaptiveViewChange', data);
  1259. }
  1260. } catch(e) { }
  1261. };
  1262. $ax.postAdaptiveViewChanged = _postAdaptiveViewChanged;
  1263. var _postResize = $ax.postResize = function(e) {
  1264. $ax.setjBrowserEvent(e);
  1265. return fireEventThroughContainers('onResize', undefined, false, [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE, $ax.constants.DYNAMIC_PANEL_TYPE, $ax.constants.REPEATER],
  1266. [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE]);
  1267. };
  1268. //fire events for table, menu and tree, including its sub items
  1269. var _fireEventsForTableMenuAndTree = function (object, event, skipShowDescription, eventInfo, path, synthetic) {
  1270. if (!path) path = [];
  1271. var pathCopy = path.slice();
  1272. pathCopy[path.length] = object.id;
  1273. var scriptId = $ax.getScriptIdFromPath(pathCopy);
  1274. $ax.event.raiseSyntheticEvent(scriptId, event, skipShowDescription, eventInfo, !synthetic);
  1275. if(object.objects) {
  1276. for(var index = 0; index < object.objects.length; index++) {
  1277. var subObj = object.objects[index];
  1278. if ($ax.public.fn.IsTableCell(subObj.type)) {
  1279. pathCopy[path.length] = subObj.id;
  1280. scriptId = $ax.getScriptIdFromPath(pathCopy);
  1281. $ax.event.raiseSyntheticEvent(scriptId, event, skipShowDescription, eventInfo, !synthetic);
  1282. } else if ($ax.public.fn.IsTable(object.type) || $ax.public.fn.IsMenuObject(object.type) || $ax.public.fn.IsTreeNodeObject(object.type)) {
  1283. _fireEventsForTableMenuAndTree(subObj, event, skipShowDescription, eventInfo, path, synthetic);
  1284. }
  1285. }
  1286. }
  1287. }
  1288. // if ($('#' + id).data('lastScrollTop') == undefined) $('#' + id).data('lastScrollTop', '0');
  1289. // _attachDefaultObjectEvent($('#' + id), elementId, 'scroll', function (e) {
  1290. // $ax.setjBrowserEvent(e);
  1291. // var currentEvent = $ax.getjBrowserEvent();
  1292. // var eventInfoFromEvent = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), false, elementId);
  1293. // if (map.onScroll) _handleEvent(elementId, eventInfoFromEvent, map.onScroll);
  1294. //
  1295. // var currentTop = $('#' + id).scrollTop();
  1296. // var wasHandled = currentEvent.originalEvent.handled;
  1297. // if (map.onScrollUp && currentTop < $('#' + id).data('lastScrollTop')) {
  1298. // currentEvent.originalEvent.handled = false;
  1299. // _handleEvent(elementId, eventInfoFromEvent, map.onScrollUp);
  1300. // } else if (map.onScrollDown && currentTop > $('#' + id).data('lastScrollTop')) {
  1301. // currentEvent.originalEvent.handled = false;
  1302. // _handleEvent(elementId, eventInfoFromEvent, map.onScrollDown);
  1303. // }
  1304. // currentEvent.originalEvent.handled |= wasHandled;
  1305. // $('#' + id).data('lastScrollTop', currentTop);
  1306. // });
  1307. //remember the scroll bar position, so we can detect scroll up/down
  1308. var lastScrollTop;
  1309. // Filters include page, referenceDiagramObject, dynamicPanel, and repeater.
  1310. var fireEventThroughContainers = function(eventName, objects, synthetic, searchFilter, callFilter, path, itemId) {
  1311. // TODO: may want to pass in this as a parameter. At that point, may want to convert some of them to an option parameter. For now this is the only case
  1312. var skipShowDescription = eventName == 'onLoad';
  1313. // If objects undefined, load page
  1314. if(!objects) {
  1315. if(_callFilterCheck(callFilter, $ax.constants.PAGE_TYPE)) {
  1316. var map = $ax.pageData.page.interactionMap;
  1317. var currentEvent = $ax.getjBrowserEvent();
  1318. var pageEventInfo = $ax.getEventInfoFromEvent(currentEvent, skipShowDescription, '');
  1319. pageEventInfo.label = $ax.pageData.page.name;
  1320. pageEventInfo.friendlyType = 'Page';
  1321. var pageEvent = map && map[eventName];
  1322. var scrolling = currentEvent && currentEvent.type === "scroll";
  1323. if (scrolling && !pageEvent && map) pageEvent = map.onScrollUp || map.onScrollDown;
  1324. if (pageEvent) {
  1325. if (!scrolling || map.onScroll) _handleEvent('', pageEventInfo, pageEvent, skipShowDescription, synthetic);
  1326. if (scrolling) {
  1327. var wasHandled = currentEvent.originalEvent.handled;
  1328. var currentScrollTop = $(window).scrollTop();
  1329. if(map.onScrollUp && currentScrollTop < lastScrollTop) {
  1330. currentEvent.originalEvent.handled = false;
  1331. _handleEvent('', pageEventInfo, map.onScrollUp, skipShowDescription, synthetic);
  1332. } else if (map.onScrollDown && currentScrollTop > lastScrollTop) {
  1333. currentEvent.originalEvent.handled = false;
  1334. _handleEvent('', pageEventInfo, map.onScrollDown, skipShowDescription, synthetic);
  1335. }
  1336. currentEvent.originalEvent.handled |= wasHandled;
  1337. lastScrollTop = currentScrollTop;
  1338. }
  1339. }
  1340. }
  1341. if (searchFilter.indexOf($ax.constants.PAGE_TYPE) != -1) fireEventThroughContainers(eventName, $ax.pageData.page.diagram.objects, synthetic, searchFilter, callFilter);
  1342. return;
  1343. }
  1344. if(!path) path = [];
  1345. var pathCopy = [];
  1346. for(var j = 0; j < path.length; j++) pathCopy[j] = path[j];
  1347. for(var i = 0; i < objects.length; i++) {
  1348. var obj = objects[i];
  1349. pathCopy[path.length] = obj.id;
  1350. if (!$ax.public.fn.IsReferenceDiagramObject(obj.type) && !$ax.public.fn.IsDynamicPanel(obj.type) && !$ax.public.fn.IsRepeater(obj.type) && !$ax.public.fn.IsLayer(obj.type)) {
  1351. if(_callFilterCheck(callFilter)) { //fire current event for all types
  1352. if ($ax.public.fn.IsTable(obj.type) || $ax.public.fn.IsMenuObject(obj.type) || $ax.public.fn.IsTreeNodeObject(obj.type)) {
  1353. _fireEventsForTableMenuAndTree(obj, eventName, skipShowDescription, undefined, path, !synthetic);
  1354. } else {
  1355. var scriptId = $ax.getScriptIdFromPath(pathCopy);
  1356. if(scriptId && itemId) scriptId = $ax.repeater.createElementId(scriptId, itemId);
  1357. $ax.event.raiseSyntheticEvent(scriptId, eventName, skipShowDescription, undefined, !synthetic);
  1358. }
  1359. }
  1360. continue;
  1361. }
  1362. var objId = $ax.getScriptIdFromPath(pathCopy);
  1363. // If limboed, move on to next item
  1364. if(!objId) continue;
  1365. if(itemId) objId = $ax.repeater.createElementId(objId, itemId);
  1366. if($ax.public.fn.IsReferenceDiagramObject(obj.type)) {
  1367. if(_callFilterCheck(callFilter, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE)) {
  1368. var axEvent = $ax.pageData.masters[obj.masterId].interactionMap[eventName];
  1369. if(axEvent) {
  1370. var eventInfo = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), skipShowDescription, objId);
  1371. eventInfo.isMasterEvent = true;
  1372. _handleEvent(objId, eventInfo, axEvent, skipShowDescription, synthetic);
  1373. }
  1374. }
  1375. if(searchFilter.indexOf($ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE) != -1) fireEventThroughContainers(eventName, $ax.pageData.masters[obj.masterId].diagram.objects, synthetic, searchFilter, callFilter, pathCopy, itemId);
  1376. } else if($ax.public.fn.IsDynamicPanel(obj.type)) {
  1377. if(_callFilterCheck(callFilter, $ax.constants.DYNAMIC_PANEL_TYPE)) $ax.event.raiseSyntheticEvent(objId, eventName, skipShowDescription, undefined, !synthetic);
  1378. if(searchFilter.indexOf($ax.constants.DYNAMIC_PANEL_TYPE) != -1) {
  1379. var diagrams = obj.diagrams;
  1380. for(var j = 0; j < diagrams.length; j++) {
  1381. fireEventThroughContainers(eventName, diagrams[j].objects, synthetic, searchFilter, callFilter, path, itemId);
  1382. }
  1383. }
  1384. } else if($ax.public.fn.IsRepeater(obj.type)) {
  1385. // TODO: possible an option for repeater item? Now fires overall for the repeater
  1386. if(_callFilterCheck(callFilter, $ax.constants.REPEATER)) $ax.event.raiseSyntheticEvent(objId, eventName, skipShowDescription, undefined, !synthetic);
  1387. if(searchFilter.indexOf($ax.constants.REPEATER) != -1) {
  1388. var itemIds = $ax.getItemIdsForRepeater(objId);
  1389. for(var j = 0; j < itemIds.length; j++) {
  1390. fireEventThroughContainers(eventName, obj.objects, synthetic, searchFilter, callFilter, path, itemIds[j]);
  1391. }
  1392. }
  1393. } else if($ax.public.fn.IsLayer(obj.type)) {
  1394. if(_callFilterCheck(callFilter, $ax.constants.LAYER_TYPE)) $ax.event.raiseSyntheticEvent(objId, eventName, skipShowDescription, undefined, !synthetic);
  1395. }
  1396. }
  1397. eventNesting -= 1;
  1398. };
  1399. var _callFilterCheck = function(callFilter, type) {
  1400. for(var index = 0; index < callFilter.length; index++) {
  1401. var currentType = callFilter[index];
  1402. if(currentType === $ax.constants.ALL_TYPE || currentType === type) return true;
  1403. }
  1404. return false;
  1405. };
  1406. // FOCUS stuff
  1407. (function() {
  1408. })();
  1409. var _pageLoad = function() {
  1410. // Map of axure event names to pair of what it should attach to, and what the jquery event name is.
  1411. var PAGE_AXURE_TO_JQUERY_EVENT_NAMES = {
  1412. 'onScroll': [window, 'scroll'],
  1413. 'onScrollUp': [window, 'scrollup'],
  1414. 'onScrollDown': [window, 'scrolldown'],
  1415. //'onResize': [window, 'resize'],
  1416. 'onContextMenu': [window, 'contextmenu']
  1417. };
  1418. var $win = $(window);
  1419. if(!$ax.features.supports.mobile) {
  1420. PAGE_AXURE_TO_JQUERY_EVENT_NAMES.onClick = ['html', 'click'];
  1421. PAGE_AXURE_TO_JQUERY_EVENT_NAMES.onDoubleClick = ['html', 'dblclick'];
  1422. PAGE_AXURE_TO_JQUERY_EVENT_NAMES.onMouseMove = ['html', 'mousemove'];
  1423. } else {
  1424. _event.initMobileEvents($win, $win, '');
  1425. $win.bind($ax.features.eventNames.mouseDownName, _updateMouseLocation);
  1426. $win.bind($ax.features.eventNames.mouseUpName, function(e) { _updateMouseLocation(e, true); });
  1427. $win.scroll(function() { _setCanClick(false); });
  1428. $win.bind($ax.features.eventNames.mouseDownName, (function() {
  1429. _setCanClick(true);
  1430. }));
  1431. }
  1432. $win.bind($ax.features.eventNames.mouseMoveName, _updateMouseLocation);
  1433. $win.scroll($ax.flyoutManager.reregisterAllFlyouts);
  1434. for(key in PAGE_AXURE_TO_JQUERY_EVENT_NAMES) {
  1435. if(!PAGE_AXURE_TO_JQUERY_EVENT_NAMES.hasOwnProperty(key)) continue;
  1436. (function(axureName) {
  1437. var jqueryEventNamePair = PAGE_AXURE_TO_JQUERY_EVENT_NAMES[axureName];
  1438. var actionName = jqueryEventNamePair[1];
  1439. if(actionName == "scrollup" || actionName == "scrolldown") return;
  1440. $(jqueryEventNamePair[0])[actionName](function (e) {
  1441. $ax.setjBrowserEvent(e);
  1442. return fireEventThroughContainers(axureName, undefined, false, [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE, $ax.constants.DYNAMIC_PANEL_TYPE, $ax.constants.REPEATER],
  1443. [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE]);
  1444. });
  1445. })(key);
  1446. }
  1447. eventNesting -= 1;
  1448. lastScrollTop = 0;
  1449. };
  1450. _event.pageLoad = _pageLoad;
  1451. });