events.js.orig 63 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379
  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. if(!check && _supports.mobile) {
  19. _supports.touchstart = false;
  20. _supports.touchmove = false;
  21. _supports.touchend = false;
  22. _supports.mobile = false;
  23. }
  24. var _eventNames = _features.eventNames = {};
  25. _eventNames.mouseDownName = _supports.touchstart ? 'touchstart' : 'mousedown';
  26. _eventNames.mouseUpName = _supports.touchend ? 'touchend' : 'mouseup';
  27. _eventNames.mouseMoveName = _supports.touchmove ? 'touchmove' : 'mousemove';
  28. });
  29. // ******* EVENT MANAGER ******** //
  30. $axure.internal(function($ax) {
  31. var _objectIdToEventHandlers = {};
  32. var _jBrowserEvent = undefined;
  33. $ax.setjBrowserEvent = function(event) {
  34. _jBrowserEvent = event;
  35. };
  36. $ax.getjBrowserEvent = function() {
  37. return _jBrowserEvent;
  38. };
  39. var _event = {};
  40. $ax.event = _event;
  41. //initilize state
  42. _event.mouseOverObjectId = '';
  43. _event.mouseDownObjectId = '';
  44. _event.mouseOverIds = [];
  45. var EVENT_NAMES = ['mouseenter', 'mouseleave', 'contextmenu', 'change', 'focus', 'blur'];
  46. // Tap, double tap, and touch move, or synthetic.
  47. if(!$ax.features.supports.mobile) {
  48. EVENT_NAMES[EVENT_NAMES.length] = 'click';
  49. EVENT_NAMES[EVENT_NAMES.length] = 'dblclick';
  50. EVENT_NAMES[EVENT_NAMES.length] = 'mousemove';
  51. }
  52. // add the event names for the touch events
  53. EVENT_NAMES[EVENT_NAMES.length] = $ax.features.eventNames.mouseDownName;
  54. EVENT_NAMES[EVENT_NAMES.length] = $ax.features.eventNames.mouseUpName;
  55. for(var i = 0; i < EVENT_NAMES.length; i++) {
  56. var eventName = EVENT_NAMES[i];
  57. //we need the function here to circumvent closure modifying eventName
  58. _event[eventName] = (function(event_Name) {
  59. return function(elementId, fn) {
  60. var elementIdQuery = $jobj(elementId);
  61. var type = $ax.getTypeFromElementId(elementId);
  62. //we need specially track link events so we can enable and disable them along with
  63. //their parent widgets
  64. if(elementIdQuery.is('a')) _attachCustomObjectEvent(elementId, event_Name, fn);
  65. //see notes below
  66. else if($ax.IsTreeNodeObject(type)) _attachTreeNodeEvent(elementId, event_Name, fn);
  67. else if($ax.IsButtonShape(type) && (event_Name == 'focus' || event_Name == 'blur')) {
  68. _attachDefaultObjectEvent($jobj($ax.repeater.applySuffixToElementId(elementId, '_img')), elementId, event_Name, fn);
  69. } else {
  70. var inputId = $ax.INPUT(elementId);
  71. var isInput = $jobj(inputId).length != 0;
  72. var id = isInput && (event_Name == 'focus' || event_Name == 'blur') ? inputId : elementId;
  73. _attachDefaultObjectEvent($jobj(id), elementId, event_Name, fn);
  74. }
  75. };
  76. })(eventName);
  77. }
  78. var AXURE_TO_JQUERY_EVENT_NAMES = {
  79. 'onMouseOver': 'mouseenter',
  80. 'onMouseOut': 'mouseleave',
  81. 'onContextMenu': 'contextmenu',
  82. 'onChange': 'change',
  83. 'onFocus': 'focus',
  84. 'onLostFocus': 'blur'
  85. };
  86. // Tap, double tap, and touch move, or synthetic.
  87. if(!$ax.features.supports.mobile) {
  88. AXURE_TO_JQUERY_EVENT_NAMES.onClick = 'click';
  89. AXURE_TO_JQUERY_EVENT_NAMES.onDoubleClick = 'dblclick';
  90. AXURE_TO_JQUERY_EVENT_NAMES.onMouseMove = 'mousemove';
  91. }
  92. AXURE_TO_JQUERY_EVENT_NAMES.onMouseDown = $ax.features.eventNames.mouseDownName;
  93. AXURE_TO_JQUERY_EVENT_NAMES.onMouseUp = $ax.features.eventNames.mouseUpName;
  94. var _attachEvents = function(diagramObject, elementId) {
  95. var inputId = $ax.repeater.applySuffixToElementId(elementId, '_input');
  96. var id = $jobj(inputId).length ? inputId : elementId;
  97. for(var eventName in diagramObject.interactionMap) {
  98. var jQueryEventName = AXURE_TO_JQUERY_EVENT_NAMES[eventName];
  99. if(!jQueryEventName) continue;
  100. _event[jQueryEventName](id,
  101. //this is needed to escape closure
  102. (function(axEventObject) {
  103. return function(e) {
  104. $ax.setjBrowserEvent(e);
  105. _handleEvent(elementId, $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), false, elementId), axEventObject);
  106. };
  107. })(diagramObject.interactionMap[eventName])
  108. );
  109. }
  110. };
  111. var _initilizeEventHandlers = function(query) {
  112. query.filter(function(diagramObject) {
  113. return diagramObject.interactionMap;
  114. }).each(_attachEvents);
  115. };
  116. var preventDefaultEvents = ['OnContextMenu', 'OnKeyUp', 'OnKeyDown'];
  117. var allowBubble = ['OnFocus', 'OnResize', 'OnMouseOut', 'OnMouseOver'];
  118. var canClick = true;
  119. var _handleEvent = $ax.event.handleEvent = function(elementId, eventInfo, axEventObject, skipShowDescriptions, synthetic) {
  120. var eventDescription = axEventObject.description;
  121. if(!canClick && eventDescription == 'OnClick') return;
  122. // If you are supposed to suppress, do that right away.
  123. if(suppressedEventStatus[eventDescription]) {
  124. return;
  125. }
  126. var currentEvent = $ax.getjBrowserEvent();
  127. if(!synthetic && currentEvent && currentEvent.originalEvent && currentEvent.originalEvent.handled && !eventInfo.isMasterEvent) return;
  128. if(!synthetic && elementId && !$ax.style.getObjVisible(elementId) && $ax.getTypeFromElementId(elementId) != 'referenceDiagramObject') return;
  129. var bubble = true;
  130. if(skipShowDescriptions || !_shouldShowCaseDescriptions(axEventObject)) {
  131. //handle case descriptions
  132. var caseGroups = [];
  133. var currentCaseGroup = [];
  134. caseGroups[0] = currentCaseGroup;
  135. // Those refreshes not after a wait
  136. var guaranteedRefreshes = {};
  137. for(var i = 0; i < axEventObject.cases.length; i++) {
  138. var currentCase = axEventObject.cases[i];
  139. if(currentCase.isNewIfGroup) {
  140. currentCaseGroup = [];
  141. caseGroups[caseGroups.length] = currentCaseGroup;
  142. }
  143. currentCaseGroup[currentCaseGroup.length] = currentCase;
  144. for(var j = 0; j < currentCase.actions.length; j++) {
  145. var action = currentCase.actions[j];
  146. if(action.action == 'wait') break;
  147. if(action.action != 'refreshRepeater') continue;
  148. for(var k = 0; k < action.repeatersToRefresh.length; k++) {
  149. var id = $ax.getElementIdsFromPath(action.repeatersToRefresh[k], eventInfo)[k];
  150. guaranteedRefreshes[id] = i;
  151. }
  152. }
  153. }
  154. for(var i = 0; i < caseGroups.length; i++) {
  155. var groupRefreshes = [];
  156. for(var key in guaranteedRefreshes) {
  157. if(guaranteedRefreshes[key] == i) groupRefreshes[groupRefreshes.length] = key;
  158. }
  159. bubble = _handleCaseGroup(eventInfo, caseGroups[i], groupRefreshes) && bubble;
  160. }
  161. } else {
  162. _showCaseDescriptions(elementId, eventInfo, axEventObject, synthetic);
  163. bubble = false;
  164. }
  165. // Only trigger a supression if it handled this event
  166. if(!bubble && suppressingEvents[eventDescription]) {
  167. suppressedEventStatus[suppressingEvents[eventDescription]] = true;
  168. }
  169. // This should not be needed anymore. All refreshes should be inserted, or handled earlier.
  170. var repeaters = $ax.deepCopy($ax.action.repeatersToRefresh);
  171. while($ax.action.repeatersToRefresh.length) $ax.action.repeatersToRefresh.pop();
  172. for(i = 0; i < repeaters.length; i++) $ax.repeater.refreshRepeater(repeaters[i], eventInfo);
  173. if(currentEvent && currentEvent.originalEvent) {
  174. currentEvent.originalEvent.handled = !synthetic && !bubble && allowBubble.indexOf(eventDescription) == -1;
  175. currentEvent.originalEvent.donotdrag = currentEvent.donotdrag || (!bubble && eventDescription == 'OnMouseDown');
  176. // Prevent default if necessary
  177. if(currentEvent.originalEvent.handled && preventDefaultEvents.indexOf(eventDescription) != -1) {
  178. currentEvent.preventDefault();
  179. }
  180. }
  181. };
  182. var _showCaseDescriptions = function(elementId, eventInfo, axEventObject, synthetic) {
  183. if(axEventObject.cases.length == 0) return true;
  184. var linksId = elementId + "linkBox";
  185. $('#' + linksId).remove();
  186. var $container = $("<div class='intcases' id='" + linksId + "'></div>");
  187. if(!_isEventSimulating(axEventObject)) {
  188. for(var i = 0; i < axEventObject.cases.length; i++) {
  189. var $link = $("<div class='intcaselink'>" + axEventObject.cases[i].description + "</div>");
  190. $link.click(function(j) {
  191. return function() {
  192. var bubble = $ax.action.dispatchAction(eventInfo, axEventObject.cases[j].actions);
  193. $('#' + linksId).remove();
  194. return bubble;
  195. };
  196. } (i)
  197. );
  198. $container.append($link);
  199. }
  200. } else {
  201. var fullDescription = axEventObject.description + ":<br>";
  202. for(var i = 0; i < axEventObject.cases.length; i++) {
  203. var currentCase = axEventObject.cases[i];
  204. fullDescription += "&nbsp;&nbsp;" + currentCase.description.replace(/<br>/g, '<br>&nbsp;&nbsp;') + ":<br>";
  205. for(var j = 0; j < currentCase.actions.length; j++) {
  206. fullDescription += "&nbsp;&nbsp;&nbsp;&nbsp;" + currentCase.actions[j].description.replace(/<br>/g, '<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;') + "<br>";
  207. }
  208. }
  209. fullDescription = fullDescription.substring(0, fullDescription.length - 4);
  210. var $link = $("<div class='intcaselink'>" + fullDescription + "</div>");
  211. $link.click(function() {
  212. _handleEvent(elementId, eventInfo, axEventObject, true, synthetic);
  213. $('#' + linksId).remove();
  214. return;
  215. });
  216. $container.append($link);
  217. }
  218. $container.mouseleave(function(e) { $ax.legacy.SuppressBubble(e); });
  219. $('body').append($container);
  220. _showCaseLinks(eventInfo, linksId);
  221. };
  222. var _showCaseLinks = function(eventInfo, linksId) {
  223. var links = window.document.getElementById(linksId);
  224. links.style.top = eventInfo.pageY;
  225. var left = eventInfo.pageX;
  226. links.style.left = left;
  227. $ax.visibility.SetVisible(links, true);
  228. $ax.legacy.BringToFront(linksId, true);
  229. $ax.legacy.RefreshScreen();
  230. };
  231. var _shouldShowCaseDescriptions = function(axEventObject) {
  232. if($ax.document.configuration.linkStyle == "alwaysDisplayTargets") return true;
  233. if($ax.document.configuration.linkStyle == "neverDisplayTargets") return false;
  234. if(axEventObject.cases.length == 0) return false;
  235. if(_isEventSimulating(axEventObject)) return false;
  236. if(axEventObject.cases.length >= 2) return true;
  237. return false;
  238. };
  239. var _isEventSimulating = function(axEventObject) {
  240. for(var i = 0; i < axEventObject.cases.length; i++) {
  241. if(axEventObject.cases[i].condition) return true;
  242. }
  243. return false;
  244. };
  245. var _handleCaseGroup = function(eventInfo, caseGroup, groupRefreshes) {
  246. for(var i = 0; i < caseGroup.length; i++) {
  247. var currentCase = caseGroup[i];
  248. if(!currentCase.condition || _processCondition(currentCase.condition, eventInfo)) {
  249. for(var j = 0; j < currentCase.actions.length; j++) {
  250. var action = currentCase.actions[j];
  251. if(action.action == 'wait') break;
  252. if(action.action != 'repeaterRefresh') continue;
  253. for(var k = 0; k < action.repeatersToRefresh.length; k++) {
  254. var id = $ax.getElementIdsFromPath(action.repeatersToRefresh[i], eventInfo)[i];
  255. var index = groupRefreshes.indexOf(id);
  256. if(index != -1) $ax.splice(groupRefreshes);
  257. }
  258. }
  259. // Any guaranteed refreshes that aren't accounted for must be run still.
  260. $ax.repeater.refreshRepeaters(groupRefreshes, eventInfo);
  261. $ax.action.dispatchAction(eventInfo, currentCase.actions);
  262. return false;
  263. }
  264. }
  265. // Any guaranteed refreshes that aren't accounted for must be run still.
  266. $ax.repeater.refreshRepeaters(groupRefreshes, eventInfo);
  267. return true;
  268. };
  269. var _processCondition = function(expr, eventInfo) {
  270. return $ax.expr.evaluateExpr(expr, eventInfo);
  271. };
  272. var _attachTreeNodeEvent = function(elementId, eventName, fn) {
  273. //we need to set the cursor here because we want to make sure that every tree node has the default
  274. //cursor set and then it's overridden if it has a click
  275. if(eventName == 'click') window.document.getElementById(elementId).style.cursor = 'pointer';
  276. _attachCustomObjectEvent(elementId, eventName, fn);
  277. };
  278. var _attachDefaultObjectEvent = function(elementIdQuery, elementId, eventName, fn) {
  279. var func = function() {
  280. if(!$ax.style.IsWidgetDisabled(elementId)) return fn.apply(this, arguments);
  281. return true;
  282. };
  283. var bind = !elementIdQuery[eventName];
  284. if(bind) elementIdQuery.bind(eventName, func);
  285. else elementIdQuery[eventName](func);
  286. };
  287. var _attachCustomObjectEvent = function(elementId, eventName, fn) {
  288. var handlers = _objectIdToEventHandlers[elementId];
  289. if(!handlers) _objectIdToEventHandlers[elementId] = handlers = {};
  290. var fnList = handlers[eventName];
  291. if(!fnList) handlers[eventName] = fnList = [];
  292. fnList[fnList.length] = fn;
  293. };
  294. var _fireObjectEvent = function(elementId, event, originalArgs) {
  295. var element = window.document.getElementById(elementId);
  296. var handlerList = _objectIdToEventHandlers[elementId] && _objectIdToEventHandlers[elementId][event];
  297. if(handlerList) {
  298. for(var i = 0; i < handlerList.length; i++) handlerList[i].apply(element, originalArgs);
  299. }
  300. };
  301. //for button shapes and images the img is focusable instead of the div to get better outlines
  302. $ax.event.getFocusableWidgetOrChildId = function(elementId) {
  303. var imgId = $ax.repeater.applySuffixToElementId(elementId, '_img');
  304. var imgQuery = $jobj(imgId);
  305. var inputId = $ax.repeater.applySuffixToElementId(elementId, '_input');
  306. var inputQuery = $jobj(inputId);
  307. return imgQuery.length > 0 ? imgId : inputQuery.length > 0 ? inputId : elementId;
  308. };
  309. // key is the suppressing event, and the value is the event that is supressed
  310. var suppressingEvents = {};
  311. // key is the event that will cancel the suppression, and value is the event that was being suppressed
  312. var cancelSuppressions = {};
  313. // suppressed event maps to true if it is supressed
  314. var suppressedEventStatus = {};
  315. // Attempt at a generic way to supress events
  316. var initSuppressingEvents = function(query) {
  317. suppressingEvents['OnLongClick'] = 'OnClick';
  318. cancelSuppressions['onMouseDown'] = 'OnClick';
  319. // Have to cancel suppressed event here. Only works for non-synthetic events currently
  320. for(var key in cancelSuppressions) {
  321. var eventName = AXURE_TO_JQUERY_EVENT_NAMES[key];
  322. if(!eventName) continue;
  323. (function(eventName, suppressed) {
  324. query.bind(eventName, function() {
  325. suppressedEventStatus[suppressed] = false;
  326. });
  327. })(eventName, cancelSuppressions[key]);
  328. }
  329. // Otherwise see if you have the chance to cancel a supression
  330. // if(cancelSuppressions[eventDescription]) {
  331. // suppressedEventStatus[cancelSuppressions[eventDescription]] = false;
  332. // }
  333. };
  334. // TODO: It may be a good idea to split this into multiple functions, or at least pull out more similar functions into private methods
  335. var _initializeObjectEvents = function(query) {
  336. // Must init the supressing eventing before the handlers, so that it has the ability to supress those events.
  337. initSuppressingEvents(query);
  338. _initilizeEventHandlers(query);
  339. //attach button shape alternate styles
  340. var mouseFilter = query.filter(function(obj) {
  341. return obj.type != 'hyperlink' && obj.type != 'dynamicPanel' && obj.type != 'richTextPanel' &&
  342. obj.type != 'repeater' && obj.type != 'checkbox' && obj.type != 'radioButton' && obj.type != 'treeNodeObject';
  343. });
  344. mouseFilter.mouseenter(function() {
  345. var elementId = this.id;
  346. var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId);
  347. if(parent) {
  348. dynamicPanelMouseOver(parent.id);
  349. if(parent.direct) return;
  350. }
  351. if($.inArray(elementId, _event.mouseOverIds) != -1) return;
  352. _event.mouseOverIds[_event.mouseOverIds.length] = elementId;
  353. if(elementId == _event.mouseOverObjectId) return;
  354. _event.mouseOverObjectId = elementId;
  355. $ax.style.SetWidgetHover(elementId, true);
  356. var textId = $ax.style.GetTextIdFromShape(elementId);
  357. if(textId) $ax.annotation.updateLinkLocations(textId);
  358. }).mouseleave(function() {
  359. var elementId = this.id;
  360. var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId);
  361. if(parent) {
  362. dynamicPanelMouseLeave(parent.id);
  363. if(parent.direct) return;
  364. }
  365. $ax.splice(_event.mouseOverIds, $.inArray(elementId, _event.mouseOverIds), 1);
  366. if(elementId == _event.mouseOverObjectId) {
  367. _event.mouseOverObjectId = '';
  368. }
  369. $ax.style.SetWidgetHover(elementId, false);
  370. var textId = $ax.style.GetTextIdFromShape(elementId);
  371. if(textId) $ax.annotation.updateLinkLocations(textId);
  372. });
  373. mouseFilter.bind($ax.features.eventNames.mouseDownName, function() {
  374. var elementId = this.id;
  375. var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId);
  376. if(parent) {
  377. dynamicPanelMouseDown(parent.id);
  378. if(parent.direct) return;
  379. }
  380. _event.mouseDownObjectId = elementId;
  381. $ax.style.SetWidgetMouseDown(this.id, true);
  382. $ax.annotation.updateLinkLocations($ax.style.GetTextIdFromShape(elementId));
  383. }).bind($ax.features.eventNames.mouseUpName, function() {
  384. var elementId = this.id;
  385. var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId);
  386. if(parent) {
  387. dynamicPanelMouseUp(parent.id);
  388. if(parent.direct) return;
  389. }
  390. var mouseDownId = _event.mouseDownObjectId;
  391. _event.mouseDownObjectId = '';
  392. if(!$ax.style.ObjHasMouseDown(elementId)) return;
  393. $ax.style.SetWidgetMouseDown(elementId, false);
  394. $ax.annotation.updateLinkLocations($ax.style.GetTextIdFromShape(elementId));
  395. //there used to be something we needed to make images click, because swapping out the images prevents the click
  396. // this is a note that we can eventually delete.
  397. });
  398. // Initialize selected elements
  399. query.filter(function(obj) {
  400. return (obj.type == 'flowShape' || obj.type == 'buttonShape' || obj.type == 'imageBox' || obj.type == 'dynamicPanel') && obj.selected;
  401. }).selected(true);
  402. //initialize disabled elements
  403. query.filter(function(obj) {
  404. return (obj.type == 'flowShape' || obj.type == 'buttonShape' || obj.type == 'imageBox' || obj.type == 'dynamicPanel') && obj.disabled;
  405. }).enabled(false);
  406. // Initialize Placeholders. Right now this is text boxes and text areas.
  407. // Also, the assuption is being made that these widgets with the placeholder, have no other styles (this may change...)
  408. query.filter(function(obj) {
  409. var hasPlaceholder = obj.placeholderText == '' ? true : Boolean(obj.placeholderText);
  410. return (obj.type == 'textArea' || obj.type == 'textBox') && hasPlaceholder;
  411. }).each(function(diagramObject, elementId) {
  412. // This is needed to initialize the placeholder state
  413. $jobj($ax.INPUT(elementId)).bind('keydown', function() {
  414. var id = this.id;
  415. var inputIndex = id.indexOf('_input');
  416. if(inputIndex == -1) return;
  417. var inputId = id.substring(0, inputIndex);
  418. if(!$ax.placeholderManager.isActive(inputId)) return;
  419. $ax.placeholderManager.updatePlaceholder(inputId, false, true);
  420. }).bind('keyup', function() {
  421. var id = this.id;
  422. var inputIndex = id.indexOf('_input');
  423. if(inputIndex == -1) return;
  424. var inputId = id.substring(0, inputIndex);
  425. if($ax.placeholderManager.isActive(inputId)) return;
  426. if(!$jobj(id).val()) {
  427. $ax.placeholderManager.updatePlaceholder(inputId, true);
  428. $ax.placeholderManager.moveCaret(id, 0);
  429. }
  430. }).bind('focus', function() {
  431. $ax.placeholderManager.moveCaret(this.id);
  432. }).bind('mousedown', function() {
  433. $ax.placeholderManager.moveCaret(this.id);
  434. }).bind('mouseup', function() {
  435. $ax.placeholderManager.moveCaret(this.id);
  436. }).bind('blur', function() {
  437. var id = this.id;
  438. var inputIndex = id.indexOf('_input');
  439. if(inputIndex == -1) return;
  440. var inputId = id.substring(0, inputIndex);
  441. if($jobj(id).val()) return;
  442. $ax.placeholderManager.updatePlaceholder(inputId, true);
  443. });
  444. $ax.placeholderManager.registerPlaceholder(elementId, diagramObject.placeholderText, $jobj($ax.INPUT(elementId)).attr('type') == 'password');
  445. $ax.placeholderManager.updatePlaceholder(elementId, !($jobj($ax.repeater.applySuffixToElementId(elementId, '_input')).val()));
  446. });
  447. // Initialize assigned submit buttons
  448. query.filter(function(dObj) { return dObj.submitButton; }).each(function(dObj, elementId) {
  449. $('#' + elementId).keyup(function(e) {
  450. if(e.keyCode == '13') {
  451. var scriptId = $ax.repeater.getScriptIdFromElementId(elementId);
  452. var path = $ax.deepCopy(dObj.submitButton.path);
  453. path[path.length] = dObj.submitButton.id;
  454. var itemNum = $ax.repeater.getItemIdFromElementId(elementId);
  455. var submitId = $ax.getScriptIdFromPath(path, scriptId);
  456. if(itemNum && $ax.getParentRepeaterFromScriptId(submitId) == $ax.getParentRepeaterFromScriptId(scriptId)) {
  457. submitId = $ax.repeater.createElementId(submitId, itemNum);
  458. }
  459. var inputId = $ax.INPUT(submitId);
  460. if($jobj(inputId).length) submitId = inputId;
  461. $ax.setjBrowserEvent(e);
  462. $ax.event.fireClick(submitId);
  463. }
  464. }).keydown(function(e) {
  465. if(e.keyCode == '13') {
  466. e.preventDefault();
  467. }
  468. });
  469. });
  470. // Don't drag after mousing down on a plain text object
  471. query.filter(function(obj) {
  472. return obj.type == 'textArea' || obj.type == 'textBox' || obj.type == 'listBox' || obj.type == 'comboBox' || obj.type == 'checkBox' || obj.type == 'radioButton';
  473. }).bind($ax.features.eventNames.mouseDownName, function(event) {
  474. event.originalEvent.donotdrag = true;
  475. });
  476. if($ax.features.supports.mobile) {
  477. query.bind($ax.features.eventNames.mouseDownName, function(event) { canClick = true; });
  478. query.filter(function(obj) {
  479. return obj.type == 'dynamicPanel';
  480. }).scroll(function() { canClick = false; });
  481. }
  482. //initialize tree node cursors to default so they will override their parent
  483. query.filter(function(obj) {
  484. return obj.type == 'treeNodeObject' && !(obj.interactionMap && obj.interactionMap.onClick);
  485. }).each(function(obj, id) {
  486. $jobj(id).css('cursor', 'default');
  487. });
  488. //initialize widgets that are clickable to have the pointer over them when hovering
  489. query.filter(function(obj) {
  490. return obj.interactionMap && obj.interactionMap.onClick;
  491. }).each(function(obj, id) {
  492. var jobj = $jobj(id);
  493. if(jobj) jobj.css('cursor', 'pointer');
  494. });
  495. // TODO: not sure if we need this. It appears to be working without
  496. //initialize panels for DynamicPanels
  497. query.filter(function(obj) {
  498. return (obj.type == 'dynamicPanel');
  499. }).$().children().each(function() {
  500. var parts = this.id.split('_');
  501. var state = parts[parts.length - 1].substring(5);
  502. if(state != 0) $ax.visibility.SetVisible(this, false);
  503. });
  504. //initialize TreeNodes
  505. query.filter(function(obj) {
  506. return (obj.type == 'treeNodeObject');
  507. }).each(function(otehnutohe, id) {
  508. //var id = ids[index];
  509. var obj = $jobj(id);
  510. if(obj.hasClass('treeroot')) return;
  511. var childrenId = id + '_children';
  512. var children = obj.children('[id="' + childrenId + '"]:first');
  513. if(children.length > 0) {
  514. var plusMinusId = 'u' + (parseInt($ax.repeater.getScriptIdFromElementId(id).substring(1)) + 1);
  515. var itemId = $ax.repeater.getItemIdFromElementId(id);
  516. if(itemId) plusMinusId = $ax.repeater.createElementId(plusMinusId, itemId);
  517. if(!$jobj(plusMinusId).hasClass('ax_image')) plusMinusId = '';
  518. $ax.tree.InitializeTreeNode(id, plusMinusId, childrenId);
  519. }
  520. obj.click(function() { $ax.tree.SelectTreeNode(id, true); });
  521. });
  522. //initialize submenus
  523. query.filter(function(obj) {
  524. return (obj.type == 'menuObject');
  525. }).each(function(obj, elementId) {
  526. var jobj = $jobj(elementId);
  527. if(jobj.hasClass('sub_menu')) {
  528. var tableCellElementId = $ax.getElementIdFromPath([obj.parentCellId], { relativeTo: elementId });
  529. $ax.menu.InitializeSubmenu(elementId, tableCellElementId);
  530. }
  531. });
  532. // Attach handles for dynamic panels that propagate styles to inner items.
  533. query.filter(function(obj) {
  534. return obj.type == 'dynamicPanel' && obj.propagate;
  535. }).mouseenter(function() {
  536. var elementId = this.id;
  537. dynamicPanelMouseOver(elementId);
  538. }).mouseleave(function() {
  539. var elementId = this.id;
  540. dynamicPanelMouseLeave(elementId);
  541. }).bind($ax.features.eventNames.mouseDownName, function() {
  542. var elementId = this.id;
  543. dynamicPanelMouseDown(elementId);
  544. }).bind($ax.features.eventNames.mouseUpName, function() {
  545. var elementId = this.id;
  546. dynamicPanelMouseUp(elementId);
  547. });
  548. // These are the dynamic panel functions for propagating rollover styles and mouse down styles to inner objects
  549. var dynamicPanelMouseOver = function(elementId, fromChild) {
  550. var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId);
  551. if(parent) {
  552. dynamicPanelMouseOver(parent.id, true);
  553. if(parent.direct) return;
  554. }
  555. if($.inArray(elementId, _event.mouseOverIds) != -1) return;
  556. // If this event is coming from a child, don't mark that it's actually entered.
  557. // Only mark that this has been entered if this event has naturally been triggered. (For reason see mouseleave)
  558. if(!fromChild) _event.mouseOverIds[_event.mouseOverIds.length] = elementId;
  559. if(elementId == _event.mouseOverObjectId) return;
  560. _event.mouseOverObjectId = elementId;
  561. $ax.dynamicPanelManager.propagateMouseOver(elementId, true);
  562. };
  563. var dynamicPanelMouseLeave = function(elementId, fromChild) {
  564. var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId);
  565. if(parent) {
  566. dynamicPanelMouseLeave(parent.id, true);
  567. if(parent.direct) return;
  568. }
  569. var index = $.inArray(elementId, _event.mouseOverIds);
  570. // If index != -1, this has been natuarally entered. If naturally entered, then leaving child should not trigger leaving,
  571. // but instead wait for natural mouse leave. If natural mouse enter never triggered, natural mouse leave won't so do this now.
  572. if((index != -1) && fromChild) return;
  573. $ax.splice(_event.mouseOverIds, index, 1);
  574. if(elementId == _event.mouseOverObjectId) {
  575. _event.mouseOverObjectId = '';
  576. }
  577. $ax.dynamicPanelManager.propagateMouseOver(elementId, false);
  578. };
  579. var dynamicPanelMouseDown = function(elementId) {
  580. var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId);
  581. if(parent) {
  582. dynamicPanelMouseDown(parent.id);
  583. if(parent.direct) return;
  584. }
  585. _event.mouseDownObjectId = elementId;
  586. $ax.dynamicPanelManager.propagateMouseDown(elementId, true);
  587. };
  588. var dynamicPanelMouseUp = function(elementId) {
  589. var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId);
  590. if(parent) {
  591. dynamicPanelMouseUp(parent.id);
  592. if(parent.direct) return;
  593. }
  594. _event.mouseDownObjectId = '';
  595. $ax.dynamicPanelManager.propagateMouseDown(elementId, false);
  596. };
  597. //attach handlers for button shape and tree node mouse over styles
  598. // TODO: Can this really be removed? Trees seem to work with out (the generic hover case works for it).
  599. // query.filter(function(obj) {
  600. // return obj.type == 'buttonShape' && obj.parent.type == 'treeNodeObject' &&
  601. // obj.parent.style && obj.parent.style.stateStyles &&
  602. // obj.parent.style.stateStyles.mouseOver;
  603. // }).mouseenter(function() {
  604. // $ax.style.SetWidgetHover(this.id, true);
  605. // }).mouseleave(function() {
  606. // $ax.style.SetWidgetHover(this.id, false);
  607. // });
  608. //handle treeNodeObject events and prevent them from bubbling up. this is necessary because otherwise
  609. //both a sub menu and it's parent would get a click
  610. query.filter(function(obj) {
  611. return obj.type == 'treeNodeObject';
  612. }).click(function() {
  613. //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)
  614. _fireObjectEvent(this.id, 'click', arguments);
  615. return false;
  616. }).$().each(function() {
  617. if(!this.style.cursor) {
  618. this.style.cursor = 'default';
  619. }
  620. });
  621. // Synthetic events
  622. // Attach dynamic panel synthetic drag and swipe events
  623. query.filter(function(diagramObject) {
  624. if(diagramObject.type != "dynamicPanel") return false;
  625. var map = diagramObject.interactionMap;
  626. return map && (
  627. map.onDragStart || map.onDrag ||
  628. map.onDragDrop || map.onSwipeLeft || map.onSwipeRight || map.onSwipeUp || map.onSwipeDown);
  629. }).each(function(diagramObject, elementId) {
  630. $('#' + elementId)
  631. .bind($ax.features.eventNames.mouseDownName, function(e) { $ax.drag.StartDragWidget(e.originalEvent, elementId); });
  632. });
  633. // Attach dynamic panel synthetic scroll event
  634. query.filter(function(diagramObject) {
  635. if(diagramObject.type != 'dynamicPanel') return false;
  636. var map = diagramObject.interactionMap;
  637. return map && map.onScroll;
  638. }).each(function(diagramObject, elementId) {
  639. var diagrams = diagramObject.diagrams;
  640. for(var i = 0; i < diagrams.length; i++) {
  641. var panelId = $ax.repeater.applySuffixToElementId(elementId, '_state' + i);
  642. (function(id) {
  643. _attachDefaultObjectEvent($('#' + id), elementId, 'scroll', function(e) {
  644. $ax.setjBrowserEvent(e);
  645. _handleEvent(elementId, $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), false, elementId), diagramObject.interactionMap.onScroll);
  646. });
  647. })(panelId);
  648. }
  649. });
  650. // Attach synthetic hover event
  651. query.filter(function(diagramObject) {
  652. var map = diagramObject.interactionMap;
  653. return map && map.onMouseHover;
  654. }).each(function(diagramObject, elementId) {
  655. var MIN_HOLD_TIME = 1000;
  656. // So when the timeout fires, you know whether it is the same mouseenter that is active or not.
  657. var mouseCount = 0;
  658. // Update eventInfo regularly, so position is accurate.
  659. var eventInfo;
  660. $('#' + elementId).mouseenter(function(e) {
  661. $ax.setjBrowserEvent(e);
  662. eventInfo = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), false, elementId);
  663. (function(currCount) {
  664. window.setTimeout(function() {
  665. if(currCount == mouseCount) _raiseSyntheticEvent(elementId, 'onMouseHover', false, eventInfo, true);
  666. }, MIN_HOLD_TIME);
  667. })(mouseCount);
  668. }).mouseleave(function(e) {
  669. $ax.setjBrowserEvent(e);
  670. mouseCount++;
  671. }).mousemove(function(e) {
  672. $ax.setjBrowserEvent(e);
  673. eventInfo = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), false, elementId);
  674. });
  675. });
  676. // Attach synthetic tap and hold event.
  677. query.filter(function(diagramObject) {
  678. var map = diagramObject.interactionMap;
  679. return map && map.onLongClick;
  680. }).each(function(diagramObject, elementId) {
  681. var MIN_HOLD_TIME = 750;
  682. // So when the timeout fires, you know whether it is the same mousedown that is active or not.
  683. var mouseCount = 0;
  684. $('#' + elementId).bind($ax.features.eventNames.mouseDownName, function(e) {
  685. (function(currCount) {
  686. $ax.setjBrowserEvent(e);
  687. var eventInfo = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), false, elementId);
  688. window.setTimeout(function() {
  689. if(currCount == mouseCount) _raiseSyntheticEvent(elementId, 'onLongClick', false, eventInfo, true);
  690. }, MIN_HOLD_TIME);
  691. if(e.preventDefault) e.preventDefault();
  692. })(mouseCount);
  693. }).bind($ax.features.eventNames.mouseUpName, function(e) {
  694. $ax.setjBrowserEvent(e);
  695. mouseCount++;
  696. });
  697. });
  698. // Attach synthetic onSelectionChange event to droplist and listbox elements
  699. query.filter(function(diagramObject) {
  700. return $ax.event.HasSelectionChanged(diagramObject);
  701. }).each(function(diagramObject, elementId) {
  702. $('#' + elementId).bind('change', function(e) {
  703. $ax.setjBrowserEvent(e);
  704. _raiseSyntheticEvent(elementId, 'onSelectionChange');
  705. });
  706. });
  707. // Highjack key up and key down to keep track of state of keyboard.
  708. _event.initKeyEvents(function(initKeydown) {
  709. query.filter('*').each(function(diagramObject, elementId) {
  710. initKeydown('#' + elementId, elementId);
  711. });
  712. }, function(initKeyup) {
  713. query.filter('*').each(function(diagramObject, elementId) {
  714. initKeyup('#' + elementId, elementId);
  715. });
  716. });
  717. // Attach synthetic onTextChange event to textbox and textarea elements
  718. query.filter(function(diagramObject) {
  719. return $ax.event.HasTextChanged(diagramObject);
  720. }).each(function(diagramObject, elementId) {
  721. var element = $jobj($ax.INPUT(elementId));
  722. $ax.updateElementText(elementId, element.val());
  723. //Key down needed because when holding a key down, key up only fires once, but keydown fires repeatedly.
  724. //Key up because last mouse down will only show the state before the last character.
  725. element.bind('keydown', function(e) {
  726. $ax.setjBrowserEvent(e);
  727. $ax.event.TryFireTextChanged(elementId);
  728. }).bind('keyup', function(e) {
  729. $ax.setjBrowserEvent(e);
  730. $ax.event.TryFireTextChanged(elementId);
  731. });
  732. //.change(function() { $ax.event.TryFireTextChanged(elementId); });
  733. });
  734. // Attach synthetic onCheckedChange event to radiobutton and checkbox elements
  735. query.filter(function(diagramObject) {
  736. return $ax.event.HasCheckedChanged(diagramObject);
  737. }).each(function(diagramObject, elementId) {
  738. var input = $jobj($ax.INPUT(elementId));
  739. if(diagramObject.type == 'radioButton' && input.prop('checked')) {
  740. $ax.updateRadioButtonSelected(input.attr('name'), elementId);
  741. }
  742. $jobj(elementId).bind('change', function(e) {
  743. $ax.setjBrowserEvent(e);
  744. _tryFireCheckedChanged(elementId, true);
  745. });
  746. });
  747. // Mobile events
  748. _event.initMobileEvents(function(initTap) {
  749. query.filter(function(diagramObject) {
  750. var map = diagramObject.interactionMap;
  751. return map && (map.onClick || map.onDoubleClick);
  752. }).each(function(diagramObject, elementId) {
  753. initTap('#' + elementId, elementId);
  754. });
  755. }, function(initMove) {
  756. query.filter(function(diagramObject) {
  757. var map = diagramObject.interactionMap;
  758. return map && map.onMouseMove;
  759. }).each(function(diagramObject, elementId) {
  760. initMove('#' + elementId, elementId);
  761. });
  762. });
  763. //attach link alternate styles
  764. query.filter(function(obj) {
  765. return obj.type == 'hyperlink';
  766. }).mouseenter(function() {
  767. var elementId = this.id;
  768. if(_event.mouseOverIds.indexOf(elementId) != -1) return true;
  769. _event.mouseOverIds[_event.mouseOverIds.length] = elementId;
  770. var mouseOverObjectId = _event.mouseOverObjectId;
  771. if(mouseOverObjectId && $ax.style.IsWidgetDisabled(mouseOverObjectId)) return true;
  772. $ax.style.SetLinkHover(elementId);
  773. var bubble = _fireObjectEvent(elementId, 'mouseenter', arguments);
  774. $ax.annotation.updateLinkLocations($ax.style.GetTextIdFromLink(elementId));
  775. return bubble;
  776. }).mouseleave(function() {
  777. var elementId = this.id;
  778. $ax.splice(_event.mouseOverIds, _event.mouseOverIds.indexOf(elementId), 1);
  779. var mouseOverObjectId = _event.mouseOverObjectId;
  780. if(mouseOverObjectId && $ax.style.IsWidgetDisabled(mouseOverObjectId)) return true;
  781. $ax.style.SetLinkNotHover(elementId);
  782. var bubble = _fireObjectEvent(elementId, 'mouseleave', arguments);
  783. $ax.annotation.updateLinkLocations($ax.style.GetTextIdFromLink(elementId));
  784. return bubble;
  785. }).bind($ax.features.eventNames.mouseDownName, function() {
  786. var elementId = this.id;
  787. var mouseOverObjectId = _event.mouseOverObjectId;
  788. if($ax.style.IsWidgetDisabled(mouseOverObjectId)) return undefined;
  789. if(mouseOverObjectId) $ax.style.SetWidgetMouseDown(mouseOverObjectId, true);
  790. $ax.style.SetLinkMouseDown(elementId);
  791. $ax.annotation.updateLinkLocations($ax.style.GetTextIdFromLink(elementId));
  792. return false;
  793. }).bind($ax.features.eventNames.mouseUpName, function() {
  794. var elementId = this.id;
  795. var mouseOverObjectId = _event.mouseOverObjectId;
  796. if(mouseOverObjectId && $ax.style.IsWidgetDisabled(mouseOverObjectId)) return;
  797. if(mouseOverObjectId) $ax.style.SetWidgetMouseDown(mouseOverObjectId, false);
  798. $ax.style.SetLinkNotMouseDown(elementId);
  799. $ax.annotation.updateLinkLocations($ax.style.GetTextIdFromLink(elementId));
  800. }).click(function() {
  801. var elementId = this.id;
  802. var mouseOverObjectId = _event.mouseOverObjectId;
  803. if(mouseOverObjectId && $ax.style.IsWidgetDisabled(mouseOverObjectId)) return undefined;
  804. return _fireObjectEvent(elementId, 'click', arguments);
  805. });
  806. // Init inline frames
  807. query.filter(function(obj) {
  808. return obj.type == 'inlineFrame';
  809. }).each(function(obj, elementId) {
  810. var target = obj.target;
  811. var url = '';
  812. if(target.includeVariables && target.url) {
  813. var origSrc = target.url;
  814. url = origSrc.toLowerCase().indexOf('http://') == -1 ? $ax.globalVariableProvider.getLinkUrl(origSrc) : origSrc;
  815. } else if(target.urlLiteral) {
  816. url = $ax.expr.evaluateExpr(target.urlLiteral, $ax.getEventInfoFromEvent(undefined, true, elementId), true);
  817. }
  818. if(url) $jobj(elementId).attr('src', url);
  819. });
  820. };
  821. $ax.initializeObjectEvents = _initializeObjectEvents;
  822. // Handle key up and key down events
  823. (function() {
  824. var _keyState = {};
  825. _keyState.ctrl = false;
  826. _keyState.alt = false;
  827. _keyState.shift = false;
  828. _keyState.keyCode = 0;
  829. $ax.event.keyState = function() {
  830. return $ax.deepCopy(_keyState);
  831. };
  832. var modifierCodes = [16, 17, 18];
  833. $ax.event.initKeyEvents = function(handleKeydown, handleKeyup) {
  834. handleKeydown(function(query, elementId) {
  835. $(query).keydown(function(e) {
  836. _keyState.ctrl = e.ctrlKey;
  837. _keyState.alt = e.altKey;
  838. _keyState.shift = e.shiftKey;
  839. // If a modifier was pressed, then don't set the keyCode;
  840. if(modifierCodes.indexOf(e.keyCode) == -1) _keyState.keyCode = e.keyCode;
  841. $ax.setjBrowserEvent(e);
  842. if(!elementId) fireEventThroughContainers('onKeyDown', undefined, false, ['page', 'referenceDiagramObject', 'dynamicPanel', 'repeater'], ['page', 'referenceDiagramObject']);
  843. else _raiseSyntheticEvent(elementId, 'onKeyDown', false, undefined, true);
  844. });
  845. });
  846. handleKeyup(function(query, elementId) {
  847. $(query).keyup(function(e) {
  848. $ax.setjBrowserEvent(e);
  849. // Fire event before updating modifiers.
  850. if(!elementId) fireEventThroughContainers('onKeyUp', undefined, false, ['page', 'referenceDiagramObject', 'dynamicPanel', 'repeater'], ['page', 'referenceDiagramObject']);
  851. else _raiseSyntheticEvent(elementId, 'onKeyUp', false, undefined, true);
  852. _keyState.ctrl = e.ctrlKey;
  853. _keyState.alt = e.altKey;
  854. _keyState.shift = e.shiftKey;
  855. // If a non-modifier was lifted, clear the keycode
  856. if(modifierCodes.indexOf(e.keyCode) == -1) _keyState.keyCode = 0;
  857. });
  858. });
  859. };
  860. })();
  861. // Handle adding mobile events
  862. (function() {
  863. // NOTE: Multi touch is NOT handled currently.
  864. var CLICK_THRESHOLD_PX = 25;
  865. var CLICK_THRESHOLD_PX_SQ = CLICK_THRESHOLD_PX * CLICK_THRESHOLD_PX;
  866. var DBLCLICK_THRESHOLD_MS = 500;
  867. // Location in page cooridinates
  868. var tapDownLoc;
  869. var lastClickEventTime;
  870. _event.initMobileEvents = function(handleTap, handleMove) {
  871. if(!$ax.features.supports.mobile) return;
  872. // Handle touch start
  873. handleTap(function(query, elementId) {
  874. $(query).bind('touchstart', function(e) {
  875. // We do NOT support multiple touches. This isn't necessarily the touch we want.
  876. var touch = e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0];
  877. if(!touch) return;
  878. tapDownLoc = [touch.pageX, touch.pageY];
  879. var time = (new Date()).getTime();
  880. if(time - lastClickEventTime < DBLCLICK_THRESHOLD_MS) {
  881. var dObj = elementId === '' ? $ax.pageData.page : $ax.getObjectFromElementId(elementId);
  882. var axEventObject = dObj && dObj.interactionMap && dObj.interactionMap['onDoubleClick'];
  883. if(axEventObject) e.preventDefault(); //for Chrome on Android
  884. }
  885. });
  886. $(query).bind('touchend', function(e) {
  887. var touch = e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0];
  888. if(!touch || !tapDownLoc) return;
  889. var tapUpLoc = [touch.pageX, touch.pageY];
  890. var xDiff = tapUpLoc[0] - tapDownLoc[0];
  891. var yDiff = tapUpLoc[1] - tapDownLoc[1];
  892. if((xDiff * xDiff + yDiff * yDiff) < CLICK_THRESHOLD_PX_SQ) {
  893. $ax.setjBrowserEvent(e);
  894. _raiseSyntheticEvent(elementId, 'onClick', false, undefined, true);
  895. var time = (new Date()).getTime();
  896. if(time - lastClickEventTime < DBLCLICK_THRESHOLD_MS) {
  897. _raiseSyntheticEvent(elementId, 'onDoubleClick', false, undefined, true);
  898. if(e.originalEvent && e.originalEvent.handled) e.preventDefault(); //for iOS
  899. }
  900. lastClickEventTime = time;
  901. }
  902. });
  903. });
  904. // Handles touch move
  905. handleMove(function(query, elementId) {
  906. $(query).bind('touchmove', function(e) {
  907. $ax.setjBrowserEvent(e);
  908. _raiseSyntheticEvent(elementId, 'onMouseMove', false, undefined, true);
  909. if(e.originalEvent && e.originalEvent.handled) e.preventDefault();
  910. });
  911. });
  912. };
  913. })();
  914. // Handle adding device independent click events to non-widgets
  915. (function() {
  916. var CLICK_THRESHOLD_PX = 25;
  917. var CLICK_THRESHOLD_PX_SQ = CLICK_THRESHOLD_PX * CLICK_THRESHOLD_PX;
  918. // Location in page cooridinates
  919. var tapDownLoc;
  920. _event.attachClick = function(query, clickHandler) {
  921. if(!$ax.features.supports.mobile) {
  922. query.click(clickHandler);
  923. return;
  924. }
  925. $(query).bind('touchstart', function(e) {
  926. // We do NOT support multiple touches. This isn't necessarily the touch we want.
  927. var touch = e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0];
  928. if(!touch) return;
  929. tapDownLoc = [touch.pageX, touch.pageY];
  930. });
  931. $(query).bind('touchend', function(e) {
  932. var touch = e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0];
  933. if(!touch) return;
  934. var tapUpLoc = [touch.pageX, touch.pageY];
  935. var xDiff = tapUpLoc[0] - tapDownLoc[0];
  936. var yDiff = tapUpLoc[1] - tapDownLoc[1];
  937. if((xDiff * xDiff + yDiff * yDiff) < CLICK_THRESHOLD_PX_SQ) {
  938. clickHandler();
  939. }
  940. });
  941. };
  942. })();
  943. // Handle firing device independent click events on widgets
  944. (function() {
  945. _event.fireClick = function(elementId) {
  946. if(!$ax.features.supports.mobile) {
  947. $('#' + elementId).click();
  948. return;
  949. }
  950. _raiseSyntheticEvent(elementId, 'onClick', false, undefined, true);
  951. };
  952. })();
  953. var _mouseLocation = $ax.mouseLocation = { x: 0, y: 0 };
  954. var _lastmouseLocation = $ax.lastMouseLocation = { x: 0, y: 0 };
  955. var _updateMouseLocation = function(e, end) {
  956. if(!e) return;
  957. if($.browser.msie && typeof (e.type) == 'unknown') return;
  958. if(e.type != 'mousemove' && e.type != 'touchstart' && e.type != 'touchmove' && e.type != 'touchend') return;
  959. var newX;
  960. var newY;
  961. if($.browser.msie) {
  962. newX = e.clientX + $('html').scrollLeft();
  963. newY = e.clientY + $('html').scrollTop();
  964. } else {
  965. newX = e.pageX;
  966. newY = e.pageY;
  967. }
  968. var body = $('body');
  969. if(body.css('position') == 'relative') newX = Math.round(newX - Number(body.css('left').replace('px', '')) - Math.max(0, ($(window).width() - body.width()) / 2));
  970. if(_mouseLocation.x == newX && _mouseLocation.y == newY) return;
  971. _lastmouseLocation.x = _mouseLocation.x;
  972. _lastmouseLocation.y = _mouseLocation.y;
  973. _mouseLocation.x = newX;
  974. _mouseLocation.y = newY;
  975. $ax.geometry.tick(_mouseLocation.x, _mouseLocation.y, end);
  976. };
  977. _event.updateMouseLocation = _updateMouseLocation;
  978. var _leavingState = function(stateId) {
  979. var mouseOverIds = _event.mouseOverIds;
  980. if(mouseOverIds.length == 0) return;
  981. var stateQuery = $jobj(stateId);
  982. for(var i = mouseOverIds.length - 1; i >= 0; i--) {
  983. var id = mouseOverIds[i];
  984. if(stateQuery.find('#' + id).length) {
  985. $ax.splice(mouseOverIds, $.inArray(id, mouseOverIds), 1);
  986. $ax.style.SetWidgetMouseDown(id, false);
  987. $ax.style.SetWidgetHover(id, false);
  988. }
  989. }
  990. };
  991. _event.leavingState = _leavingState;
  992. var _raiseSyntheticEvent = function(elementId, eventName, skipShowDescription, eventInfo, nonSynthetic) {
  993. // Empty string used when this is an event directly on the page.
  994. var dObj = elementId === '' ? $ax.pageData.page : $ax.getObjectFromElementId(elementId);
  995. var axEventObject = dObj && dObj.interactionMap && dObj.interactionMap[eventName];
  996. if(!axEventObject) return;
  997. eventInfo = eventInfo || $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), skipShowDescription, elementId);
  998. _handleEvent(elementId, eventInfo, axEventObject, false, !nonSynthetic);
  999. };
  1000. $ax.event.raiseSyntheticEvent = _raiseSyntheticEvent;
  1001. var _hasSyntheticEvent = function(scriptId, eventName) {
  1002. var dObj = $ax.getObjectFromScriptId(scriptId);
  1003. var axEventObject = dObj && dObj.interactionMap && dObj.interactionMap[eventName];
  1004. return Boolean(axEventObject);
  1005. };
  1006. $ax.event.hasSyntheticEvent = _hasSyntheticEvent;
  1007. var _initialize = function() {
  1008. $ax.repeater.load();
  1009. // Make sure key events for page are initialized first. That way they will update the value of key pressed before any other events occur.
  1010. _event.initKeyEvents(function(initKeydown) { initKeydown(window, ''); }, function(initKeyup) { initKeyup(window, ''); });
  1011. _initializeObjectEvents($ax('*'));
  1012. //finally, process the pageload
  1013. _pageLoad();
  1014. // _loadDynamicPanelsAndMasters();
  1015. // $ax.repeater.init();
  1016. // and wipe out the basic links.
  1017. $('.basiclink').click(function() {
  1018. return false;
  1019. });
  1020. };
  1021. _event.initialize = _initialize;
  1022. $ax.event.HasTextChanged = function(diagramObject) {
  1023. if(diagramObject.type != 'textBox' && diagramObject.type != 'textArea') return false;
  1024. var map = diagramObject.interactionMap;
  1025. return map && map.onTextChange;
  1026. };
  1027. $ax.event.TryFireTextChanged = function(elementId) {
  1028. var query = $jobj($ax.repeater.applySuffixToElementId(elementId, '_input'));
  1029. if(!$ax.hasElementTextChanged(elementId, query.val())) return;
  1030. $ax.updateElementText(elementId, query.val());
  1031. $ax.event.raiseSyntheticEvent(elementId, 'onTextChange');
  1032. };
  1033. $ax.event.HasSelectionChanged = function(diagramObject) {
  1034. if(diagramObject.type != 'listBox' && diagramObject.type != 'comboBox') return false;
  1035. var map = diagramObject.interactionMap;
  1036. return map && map.onSelectionChange;
  1037. };
  1038. $ax.event.HasCheckedChanged = function(diagramObject) {
  1039. if(diagramObject.type != 'checkbox' && diagramObject.type != 'radioButton') return false;
  1040. var map = diagramObject.interactionMap;
  1041. return map && map.onCheckedChange;
  1042. };
  1043. var _tryFireCheckedChanged = $ax.event.TryFireCheckChanged = function(elementId, value) {
  1044. var isRadio = $obj(elementId).type == 'radioButton';
  1045. if(isRadio) {
  1046. if(!value) {
  1047. $ax.updateRadioButtonSelected($jobj($ax.INPUT(elementId)).attr('name'), undefined);
  1048. } else {
  1049. var last = $ax.updateRadioButtonSelected($jobj($ax.INPUT(elementId)).attr('name'), elementId);
  1050. // If no change, this should not fire
  1051. if(last == elementId) return;
  1052. // Initially selecting one, last may be undefined
  1053. if(last) $ax.event.raiseSyntheticEvent(last, 'onCheckedChange');
  1054. }
  1055. }
  1056. $ax.event.raiseSyntheticEvent(elementId, 'onCheckedChange');
  1057. };
  1058. var _loadDynamicPanelsAndMasters = function(objects, path, itemId) {
  1059. fireEventThroughContainers('onLoad', objects, true, ['page', 'referenceDiagramObject', 'dynamicPanel'], ['page', 'referenceDiagramObject', 'dynamicPanel', 'repeater'], path, itemId);
  1060. };
  1061. $ax.loadDynamicPanelsAndMasters = _loadDynamicPanelsAndMasters;
  1062. var _viewChangePageAndMasters = function() {
  1063. fireEventThroughContainers('onAdaptiveViewChange', undefined, true, ['page', 'referenceDiagramObject', 'dynamicPanel'], ['page', 'referenceDiagramObject']);
  1064. _postAdaptiveViewChanged();
  1065. };
  1066. $ax.viewChangePageAndMasters = _viewChangePageAndMasters;
  1067. var _postAdaptiveViewChanged = function() {
  1068. //only trigger adaptive view changed if the window is on the mainframe. Also triggered on init, even if default.
  1069. try {
  1070. if(window.name == 'mainFrame' ||
  1071. (!CHROME_5_LOCAL && window.parent.$ && window.parent.$('#mainFrame').length > 0)) {
  1072. $axure.messageCenter.postMessage('adaptiveViewChange', $ax.adaptive.currentViewId);
  1073. }
  1074. } catch(e) {}
  1075. };
  1076. $ax.postAdaptiveViewChanged = _postAdaptiveViewChanged;
  1077. // Filters include page, referenceDiagramObject, dynamicPanel, and repeater.
  1078. var fireEventThroughContainers = function(eventName, objects, synthetic, searchFilter, callFilter, path, itemId) {
  1079. // 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
  1080. var skipShowDescription = eventName == 'onLoad';
  1081. // If objects undefined, load page
  1082. if(!objects) {
  1083. if(callFilter.indexOf('page') != -1) {
  1084. var map = $ax.pageData.page.interactionMap;
  1085. var pageEventInfo = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), skipShowDescription, '');
  1086. var pageEvent = map && map[eventName];
  1087. if(pageEvent) _handleEvent('', pageEventInfo, pageEvent, skipShowDescription, synthetic);
  1088. }
  1089. if(searchFilter.indexOf('page') != -1) fireEventThroughContainers(eventName, $ax.pageData.page.diagram.objects, synthetic, searchFilter, callFilter);
  1090. return;
  1091. }
  1092. if(!path) path = [];
  1093. var pathCopy = [];
  1094. for(var j = 0; j < path.length; j++) pathCopy[j] = path[j];
  1095. for(var i = 0; i < objects.length; i++) {
  1096. var obj = objects[i];
  1097. if(obj.type != 'referenceDiagramObject' && obj.type != 'dynamicPanel' && obj.type != 'repeater') continue;
  1098. pathCopy[path.length] = obj.id;
  1099. var objId = $ax.getScriptIdFromPath(pathCopy);
  1100. objId = $ax.repeater.createElementId(objId, itemId);
  1101. if(obj.type == 'referenceDiagramObject') {
  1102. if(callFilter.indexOf('referenceDiagramObject') != -1) {
  1103. var eventInfo = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), skipShowDescription, objId);
  1104. eventInfo.isMasterEvent = true;
  1105. var axEvent = $ax.pageData.masters[obj.masterId].interactionMap[eventName];
  1106. if(axEvent) _handleEvent(objId, eventInfo, axEvent, skipShowDescription, synthetic);
  1107. }
  1108. if(searchFilter.indexOf('referenceDiagramObject') != -1) fireEventThroughContainers(eventName, $ax.pageData.masters[obj.masterId].diagram.objects, synthetic, searchFilter, callFilter, pathCopy, itemId);
  1109. } else if(obj.type == 'dynamicPanel') {
  1110. if(callFilter.indexOf('dynamicPanel') != -1) $ax.event.raiseSyntheticEvent(objId, eventName, skipShowDescription, undefined, !synthetic);
  1111. if(searchFilter.indexOf('dynamicPanel') != -1) {
  1112. var diagrams = obj.diagrams;
  1113. for(var j = 0; j < diagrams.length; j++) {
  1114. fireEventThroughContainers(eventName, diagrams[j].objects, synthetic, searchFilter, callFilter, path, itemId);
  1115. }
  1116. }
  1117. } else if(obj.type == 'repeater') {
  1118. // TODO: possible an option for repeater item? Now fires overall for the repeater
  1119. if(callFilter.indexOf('repeater') != -1) $ax.event.raiseSyntheticEvent(objId, eventName, skipShowDescription, undefined, !synthetic);
  1120. if(searchFilter.indexOf('repeater') != -1) {
  1121. var itemIds = $ax.getItemIdsForRepeater(objId);
  1122. for(var j = 0; j < itemIds.length; j++) {
  1123. fireEventThroughContainers(eventName, obj.objects, synthetic, searchFilter, callFilter, path, itemIds[j]);
  1124. }
  1125. }
  1126. }
  1127. }
  1128. };
  1129. // FOCUS stuff
  1130. (function() {
  1131. })();
  1132. var _pageLoad = function() {
  1133. // Map of axure event names to pair of what it should attach to, and what the jquery event name is.
  1134. var PAGE_AXURE_TO_JQUERY_EVENT_NAMES = {
  1135. 'onScroll': [window, 'scroll'],
  1136. //'onResize': [window, 'resize'],
  1137. 'onContextMenu': [window, 'contextmenu']
  1138. };
  1139. if(!$ax.features.supports.mobile) {
  1140. PAGE_AXURE_TO_JQUERY_EVENT_NAMES.onClick = ['html', 'click'];
  1141. PAGE_AXURE_TO_JQUERY_EVENT_NAMES.onDoubleClick = ['html', 'dblclick'];
  1142. PAGE_AXURE_TO_JQUERY_EVENT_NAMES.onMouseMove = ['html', 'mousemove'];
  1143. } else {
  1144. _event.initMobileEvents(function(initTap) { initTap(window, ''); }, function(initMove) { initMove(window, ''); });
  1145. $(window).bind($ax.features.eventNames.mouseDownName, _updateMouseLocation);
  1146. $(window).bind($ax.features.eventNames.mouseUpName, function(e) { _updateMouseLocation(e, true); });
  1147. $(window).scroll(function() { canClick = false; });
  1148. $(window).mousedown(function() { canClick = true; });
  1149. }
  1150. $(window).bind($ax.features.eventNames.mouseMoveName, _updateMouseLocation);
  1151. $(window).scroll($ax.flyoutManager.reregisterAllFlyouts);
  1152. for(key in PAGE_AXURE_TO_JQUERY_EVENT_NAMES) {
  1153. if(!PAGE_AXURE_TO_JQUERY_EVENT_NAMES.hasOwnProperty(key)) continue;
  1154. (function(axureName) {
  1155. var jqueryEventNamePair = PAGE_AXURE_TO_JQUERY_EVENT_NAMES[axureName];
  1156. $(jqueryEventNamePair[0])[jqueryEventNamePair[1]](function(e) {
  1157. $ax.setjBrowserEvent(e);
  1158. return fireEventThroughContainers(axureName, undefined, false, ['page', 'referenceDiagramObject', 'dynamicPanel', 'repeater'], ['page', 'referenceDiagramObject']);
  1159. });
  1160. })(key);
  1161. }
  1162. $axure.resize(function(e) {
  1163. $ax.setjBrowserEvent(e);
  1164. return fireEventThroughContainers('onResize', undefined, false, ['page', 'referenceDiagramObject', 'dynamicPanel', 'repeater'], ['page', 'referenceDiagramObject']);
  1165. });
  1166. };
  1167. _event.pageLoad = _pageLoad;
  1168. });