// 8.0.0.3338. Generated 4/28/2017 12:22:57 AM UTC //***** messagecenter.js *****// if (typeof console == 'undefined') console = { log: function () { } }; // sniff chrome var CHROME_5_LOCAL = false; var CHROME = false; var SAFARI = false; var FIREFOX = false; var WEBKIT = false; var OS_MAC = false; var IOS = false; var ANDROID = false; var MOBILE_DEVICE = false; var IE = false; var IE_10_AND_BELOW = false; //ie 10 and lower var IE_11_AND_ABOVE = false; //ie 11 and above var BROWSER_VERSION = 5000; (function () { if(!window.$axure) window.$axure = function() {}; var useragent = window.navigator.userAgent; var edgeRegex = /Edge\/([0-9]+)/g; var edgeMatch = edgeRegex.exec(useragent); $axure.browser = { isEdge: Boolean(edgeMatch) }; if(!$axure.browser.isEdge) { var chromeRegex = /Chrome\/([0-9]+).([0-9]+)/g; var chromeMatch = chromeRegex.exec(useragent); CHROME = Boolean(chromeMatch); CHROME_5_LOCAL = chromeMatch && Number(chromeMatch[1]) >= 5 && location.href.indexOf('file://') >= 0; } var safariRegex = /Safari\/([0-9]+)/g; var safariMatch = safariRegex.exec(useragent); SAFARI = Boolean(safariMatch) && !CHROME; //because chrome also inserts safari string into user agent var webkitRegex = /WebKit\//g ; WEBKIT = Boolean(webkitRegex.exec(useragent)); FIREFOX = useragent.toLowerCase().indexOf('firefox') > -1; var macRegex = /Mac/g ; OS_MAC = Boolean(macRegex.exec(window.navigator.platform)); IOS = useragent.match(/iPhone/i) || useragent.match(/iPad/i) || useragent.match(/iPod/i); ANDROID = useragent.match(/Android/i); MOBILE_DEVICE = ANDROID || IOS || navigator.userAgent.match(/webOS/i) || navigator.userAgent.match(/BlackBerry/i) || navigator.userAgent.match(/Tablet PC/i) || navigator.userAgent.match(/Windows Phone/i); if($.browser) { if($.browser.msie) IE_10_AND_BELOW = true; else IE_11_AND_ABOVE = useragent.toLowerCase().indexOf('trident') > -1; BROWSER_VERSION = $.browser.version; } IE = IE_10_AND_BELOW || IE_11_AND_ABOVE; //Used by sitemap and variables.js getLinkUrl functions so that they know //whether to embed global variables in URL as query string or hash string //_shouldSendVars persists the value for sitemap instead of re-checking every time var _shouldSendVars; var _shouldSendVarsToServer = function(url) { if(typeof _shouldSendVars != 'undefined') { return _shouldSendVars; } if(SAFARI || (IE_10_AND_BELOW && BROWSER_VERSION < 10)) { var urlToCheck = typeof url != 'undefined' ? url : window.location.href; var serverRegex = /http:\/\/127\.0\.0\.1:[0-9]{5}/g; var serverMatch = serverRegex.exec(urlToCheck); var previewRegex = /[0-9]{2}\.[0-9]{2}\.[0-9]{2}/g; var previewMatch = previewRegex.exec(urlToCheck); if(Boolean(serverMatch) && Boolean(previewMatch)) { _shouldSendVars = true; return _shouldSendVars; } } _shouldSendVars = false; return _shouldSendVars; }; $axure.shouldSendVarsToServer = _shouldSendVarsToServer; })(); (function() { var _topMessageCenter; var _messageCenter = {}; var _listeners = []; var _stateListeners = []; var _state = {}; var _eventObject = null; var _queuedMessages = []; var _initialized = false; // this is for the non Chrome 5 local scenarios. The "top" message center will dispatch to all the bottom ones var _childrenMessageCenters = []; // create $axure if it hasn't been created if (!window.$axure) window.$axure = function() {}; $axure.messageCenter = _messageCenter; // isolate scope, and initialize _topMessageCenter. (function() { if (!CHROME_5_LOCAL) { var topAxureWindow = window; try { while(topAxureWindow.parent && topAxureWindow.parent !== topAxureWindow && topAxureWindow.parent.$axure) topAxureWindow = topAxureWindow.parent; } catch(e) {} _topMessageCenter = topAxureWindow.$axure.messageCenter; } })(); $(window.document).ready(function() { if (CHROME_5_LOCAL) { $('body').append("" + ""); _eventObject = window.document.createEvent('Event'); _eventObject.initEvent('axureMessageSenderEvent', true, true); $('#axureEventReceiverDiv').bind('axureMessageReceiverEvent', function () { var request = JSON.parse($(this).text()); _handleRequest(request); }); } else { if (_topMessageCenter != _messageCenter) { _topMessageCenter.addChildMessageCenter(_messageCenter); console.log('adding from ' + window.location.toString()); } } }); var _handleRequest = function (request) { // route the request to all the listeners for(var i = 0; i < _listeners.length; i++) _listeners[i](request.message, request.data); // now handle the queued messages if we're initializing if (request.message == 'initialize') { _initialized = true; // send all the queued messages and return for (var i = 0; i < _queuedMessages.length; i++) { var qRequest = _queuedMessages[i]; _messageCenter.postMessage(qRequest.message, qRequest.data); } _queuedMessages = []; } // and then handle the set state messages, if necessary if (request.message == 'setState') { _state[request.data.key] = request.data.value; for (var i = 0; i < _stateListeners.length; i++) { var keyListener = _stateListeners[i]; // if thep passed a null or empty value, always post the message if (!keyListener.key || keyListener.key == request.data.key) { keyListener.listener(request.data.key, request.data.value); } } } }; // ----------------------------------------------------------------------------------------- // This method allows for dispatching messages in the non-chromelocal scenario. // Each child calls this on _topMessageCenter // ----------------------------------------------------------------------------------------- _messageCenter.addChildMessageCenter = function(messageCenter) { _childrenMessageCenters[_childrenMessageCenters.length] = messageCenter; }; // ----------------------------------------------------------------------------------------- // This method allows for dispatching messages in the non-chromelocal scenario. // Each child calls this on _topMessageCenter // ----------------------------------------------------------------------------------------- _messageCenter.dispatchMessage = function(message, data) { _handleRequest({ message: message, data: data }); }; // ----------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------- _messageCenter.dispatchMessageRecursively = function(message, data) { console.log("dispatched to " + window.location.toString()); // dispatch to the top center first _messageCenter.dispatchMessage(message, data); $('iframe').each(function(index, frame) { //try,catch to handle permissions error in FF when loading pages from another domain try { if (frame.contentWindow.$axure && frame.contentWindow.$axure.messageCenter) { frame.contentWindow.$axure.messageCenter.dispatchMessageRecursively(message, data); } }catch(e) {} }); }; var _combineEventMessages = false; var _compositeEventMessageData = []; _messageCenter.startCombineEventMessages = function() { _combineEventMessages = true; } _messageCenter.endCombineEventMessages = function () { _messageCenter.sendCompositeEventMessage(); _combineEventMessages = false; } _messageCenter.sendCompositeEventMessage = function () { _messageCenter.postMessage('axCompositeEventMessage', _compositeEventMessageData); _compositeEventMessageData = []; } _messageCenter.postMessage = function (message, data) { if(_combineEventMessages) { if(message == 'axEvent' || message == 'axCase' || message == 'axAction' || message == 'axEventComplete') { _compositeEventMessageData.push({ 'message': message, 'data': data }); if(_compositeEventMessageData.length >= 10) _messageCenter.sendCompositeEventMessage(); return; } } if(!CHROME_5_LOCAL) { _topMessageCenter.dispatchMessageRecursively(message, data); } else { var request = { message: message, data: data }; if(_initialized) { var senderDiv = window.document.getElementById('axureEventSenderDiv'); var messageText = JSON.stringify(request); // console.log('sending event: ' + messageText); senderDiv.innerText = messageText; senderDiv.dispatchEvent(_eventObject); // console.log('event sent'); } else { _queuedMessages[_queuedMessages.length] = request; } } }; _messageCenter.setState = function(key, value) { var data = { key: key, value: value }; _messageCenter.postMessage('setState', data); }; _messageCenter.getState = function(key) { return _state[key]; }; _messageCenter.addMessageListener = function(listener) { _listeners[_listeners.length] = listener; }; _messageCenter.addStateListener = function(key, listener) { _stateListeners[_stateListeners.length] = { key: key, listener: listener }; }; })(); //***** events.js *****// // ******* Features MANAGER ******** // $axure.internal(function($ax) { var _features = $ax.features = {}; var _supports = _features.supports = {}; _supports.touchstart = typeof window.ontouchstart !== 'undefined'; _supports.touchmove = typeof window.ontouchmove !== 'undefined'; _supports.touchend = typeof window.ontouchend !== 'undefined'; _supports.mobile = _supports.touchstart && _supports.touchend && _supports.touchmove; // Got this from http://stackoverflow.com/questions/11381673/javascript-solution-to-detect-mobile-browser var check = navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/webOS/i) || navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/BlackBerry/i) || navigator.userAgent.match(/Tablet PC/i) || navigator.userAgent.match(/Windows Phone/i); _supports.windowsMobile = navigator.userAgent.match(/Tablet PC/i) || navigator.userAgent.match(/Windows Phone/i); if(!check && _supports.mobile) { _supports.touchstart = false; _supports.touchmove = false; _supports.touchend = false; _supports.mobile = false; } var _eventNames = _features.eventNames = {}; _eventNames.mouseDownName = _supports.touchstart ? 'touchstart' : 'mousedown'; _eventNames.mouseUpName = _supports.touchend ? 'touchend' : 'mouseup'; _eventNames.mouseMoveName = _supports.touchmove ? 'touchmove' : 'mousemove'; }); // ******* EVENT MANAGER ******** // $axure.internal(function($ax) { var _objectIdToEventHandlers = {}; var _jBrowserEvent = undefined; $ax.setjBrowserEvent = function(event) { _jBrowserEvent = event; }; $ax.getjBrowserEvent = function() { return _jBrowserEvent; }; var _event = {}; $ax.event = _event; //initilize state _event.mouseOverObjectId = ''; _event.mouseDownObjectId = ''; _event.mouseOverIds = []; var EVENT_NAMES = ['mouseenter', 'mouseleave', 'contextmenu', 'change', 'focus', 'blur']; // Tap, double tap, and touch move, or synthetic. if(!$ax.features.supports.mobile) { EVENT_NAMES[EVENT_NAMES.length] = 'click'; EVENT_NAMES[EVENT_NAMES.length] = 'dblclick'; EVENT_NAMES[EVENT_NAMES.length] = 'mousemove'; } // add the event names for the touch events EVENT_NAMES[EVENT_NAMES.length] = $ax.features.eventNames.mouseDownName; EVENT_NAMES[EVENT_NAMES.length] = $ax.features.eventNames.mouseUpName; for(var i = 0; i < EVENT_NAMES.length; i++) { var eventName = EVENT_NAMES[i]; //we need the function here to circumvent closure modifying eventName _event[eventName] = (function(event_Name) { return function(elementId, fn) { var elementIdQuery = $jobj(elementId); var type = $ax.getTypeFromElementId(elementId); //we need specially track link events so we can enable and disable them along with //their parent widgets if(elementIdQuery.is('a')) _attachCustomObjectEvent(elementId, event_Name, fn); //see notes below else if($ax.IsTreeNodeObject(type)) _attachTreeNodeEvent(elementId, event_Name, fn); else if ($ax.IsImageFocusable(type) && (event_Name == 'focus' || event_Name == 'blur')) { var suitableChild; var imgChild = $ax.repeater.applySuffixToElementId(elementId, '_img'); var divChild = $ax.repeater.applySuffixToElementId(elementId, '_div'); for (var j = 0; j < elementIdQuery[0].children.length; j++) { if (elementIdQuery[0].children[j].id == imgChild) suitableChild = imgChild; if (!suitableChild && elementIdQuery[0].children[j].id == divChild) suitableChild = divChild; } if(!suitableChild) suitableChild = imgChild; _attachDefaultObjectEvent($jobj(suitableChild), elementId, event_Name, fn); } else { var inputId = $ax.INPUT(elementId); var isInput = $jobj(inputId).length != 0; var id = isInput && (event_Name == 'focus' || event_Name == 'blur') ? inputId : elementId; _attachDefaultObjectEvent($jobj(id), elementId, event_Name, fn); } }; })(eventName); } var AXURE_TO_JQUERY_EVENT_NAMES = { 'onMouseOver': 'mouseenter', 'onMouseOut': 'mouseleave', 'onContextMenu': 'contextmenu', 'onChange': 'change', 'onFocus': 'focus', 'onLostFocus': 'blur' }; // Tap, double tap, and touch move, or synthetic. if(!$ax.features.supports.mobile) { AXURE_TO_JQUERY_EVENT_NAMES.onClick = 'click'; AXURE_TO_JQUERY_EVENT_NAMES.onDoubleClick = 'dblclick'; AXURE_TO_JQUERY_EVENT_NAMES.onMouseMove = 'mousemove'; } AXURE_TO_JQUERY_EVENT_NAMES.onMouseDown = $ax.features.eventNames.mouseDownName; AXURE_TO_JQUERY_EVENT_NAMES.onMouseUp = $ax.features.eventNames.mouseUpName; //for dp, if mouse entered without leaving, don't fire mouse enter again var mouseEnterGuard = {}; var _attachEvents = function (diagramObject, elementId, doMouseEnterGuard) { var inputId = $ax.repeater.applySuffixToElementId(elementId, '_input'); var id = $jobj(inputId).length ? inputId : elementId; for(var eventName in diagramObject.interactionMap) { var jQueryEventName = AXURE_TO_JQUERY_EVENT_NAMES[eventName]; if(!jQueryEventName) continue; _event[jQueryEventName](id, //this is needed to escape closure (function(axEventObject) { return function (e) { if(e.type == 'mouseenter' && doMouseEnterGuard) { if(mouseEnterGuard[elementId]) return; else mouseEnterGuard[elementId] = true; } $ax.setjBrowserEvent(e); // console.log(axEventObject.description); var eventInfo = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), false, elementId); _handleEvent(elementId, eventInfo, axEventObject); }; })(diagramObject.interactionMap[eventName]) ); if(jQueryEventName.toLowerCase() == 'mouseenter' && doMouseEnterGuard) { $jobj(elementId).on('mouseleave touchend', function() { mouseEnterGuard[elementId] = false; }); } } }; var _descriptionToKey = { 'OnFocus': 'onFocus', 'OnLostFocus': 'onLostFocus' }; var _createProxies = function(diagramObject, elementId) { var createFocus = _needsProxy(diagramObject, elementId, 'onFocus'); var createLostFocus = _needsProxy(diagramObject, elementId, 'onLostFocus'); if(!createFocus && !createLostFocus) return; if(!diagramObject.interactionMap) diagramObject.interactionMap = {}; if(createFocus) diagramObject.interactionMap.onFocus = { proxy: true, description: 'OnFocus' }; if(createLostFocus) diagramObject.interactionMap.onLostFocus = { proxy: true, description: 'OnLostFocus' }; } var preventDefaultEvents = ['OnContextMenu', 'OnKeyUp', 'OnKeyDown']; var allowBubble = ['OnFocus', 'OnResize', 'OnMouseOut', 'OnMouseOver']; var _canClick = true; var _startScroll = []; var _setCanClick = function(canClick) { _canClick = canClick; if(_canClick) _startScroll = [$(window).scrollLeft(), $(window).scrollTop()]; }; var _getCanClick = function() { if(!$ax.features.supports.mobile) return true; var endScroll = [$(window).scrollLeft(), $(window).scrollTop()]; return _canClick && _startScroll[0] == endScroll[0] && _startScroll[1] == endScroll[1]; }; //var _notAllowedInvisible = function (type) { // $ax.getTypeFromElementId(elementId); // return !$ax.public.fn.IsReferenceDiagramObject(type) && !$ax.public.fn.IsLayer(type); //} var _notAllowedInvisible = function (id) { var type = $ax.getTypeFromElementId(id); if ($ax.public.fn.IsReferenceDiagramObject(type) || $ax.public.fn.IsLayer(type)) return false; return !($ax.public.fn.IsVector(type) && _hasCompoundImage(id)); } var _hasCompoundImage = function (id) { var query = $jobj(id); return $ax.public.fn.isCompoundVectorHtml(query[0]); } var _suppressedEvents = {}; // Suppressed for next occurance. var _blockedEvents = {}; // Blocked until unblocked. _event.addSuppressedEvent = function(id, event) { if(!_suppressedEvents[id]) _suppressedEvents[id] = []; var events = _suppressedEvents[id]; if(events.indexOf(event) != -1) return; events.push(event); } _event.blockEvent = function(id, event) { if(!_blockedEvents[id]) _blockedEvents[id] = {}; var events = _blockedEvents[id]; if(events[event]) ++events[event]; else events[event] = 1; return function() { _unblockEvent(id, event); }; } var _isSuppressedEvent = function(id, event) { var suppressedEvents = _suppressedEvents[id]; var blockedEvents = _blockedEvents[id]; return (suppressedEvents && suppressedEvents.indexOf(event) != -1) || (blockedEvents && blockedEvents[event]); } var _removeSuppressedEvent = function(id, event) { var events = _suppressedEvents[id]; if(!events) return; if(events.length == 1) { delete _suppressedEvents[id]; } else { var eventIndex = events.indexOf(event); for(var i = eventIndex + 1; i < events.length; i++) events[i - 1] = events[i]; events.pop(); } } var _unblockEvent = function(id, event) { var events = _blockedEvents[id]; if(events) { if(--events[event] > 0) return; } _removeSuppressedEvent(id, event); } var _unblockEvent = function(id, event) { var events = _blockedEvents[id]; if(events) { if(--events[event] > 0) return; } _removeSuppressedEvent(id, event); } var eventNesting = 0; var eventNestingTime = new Date().getTime(); var _handleEvent = $ax.event.handleEvent = function (elementId, eventInfo, axEventObject, skipShowDescriptions, synthetic) { var eventDescription = axEventObject.description; if(_enteredWidgets[elementId] && eventDescription == 'OnMouseEnter') return; // Suppress entering a widget when already in widget (ie only) if(_isSuppressedEvent(elementId, eventDescription)) { _removeSuppressedEvent(elementId, eventDescription); return; } if(axEventObject.proxy) { var firingId = _widgetToFocusParent[elementId]; if(firingId) { var firingObj = $obj(firingId); var nextEventObj = firingObj.interactionMap && firingObj.interactionMap[_descriptionToKey[eventDescription]]; if(!nextEventObj) nextEventObj = axEventObject; _handleEvent(firingId, eventInfo, nextEventObj, skipShowDescriptions, synthetic); } return; } // var x = JSON.stringify(eventInfo); // var y = JSON.stringify(axEventObject); var fireTime = new Date().getTime(); if(fireTime - eventNestingTime > 100) { eventNestingTime = fireTime; eventNesting = 0; } if(eventNesting === 0) { $ax.recording.maybeRecordEvent(elementId, eventInfo, axEventObject, fireTime); } eventNesting += 1; if(!_getCanClick() && (eventDescription == 'OnClick' || eventDescription == 'OnPageClick')) return; // If you are supposed to suppress, do that right away. if(suppressedEventStatus[eventDescription]) { return; } var currentEvent = $ax.getjBrowserEvent(); if(!synthetic && currentEvent && currentEvent.originalEvent && currentEvent.originalEvent.handled && !eventInfo.isMasterEvent) return; if(!synthetic && elementId && !$ax.style.getObjVisible(elementId) && _notAllowedInvisible(elementId)) return; //if debug var axObj = $obj(elementId); var axObjLabel = axObj ? axObj.label : eventInfo.label; var axObjType = axObj ? axObj.friendlyType : eventInfo.friendlyType; if(!skipShowDescriptions || eventDescription == 'OnPageLoad') $ax.messageCenter.postMessage('axEvent', { 'label': axObjLabel, 'type': axObjType, 'event': axEventObject }); var bubble = true; var showCaseDescriptions = !skipShowDescriptions && _shouldShowCaseDescriptions(axEventObject); if(!showCaseDescriptions) { //handle case descriptions var caseGroups = []; var currentCaseGroup = []; caseGroups[0] = currentCaseGroup; // Those refreshes not after a wait var guaranteedRefreshes = {}; var caseGroupIndex = 0; for(var i = 0; i < axEventObject.cases.length; i++) { var currentCase = axEventObject.cases[i]; if(currentCase.isNewIfGroup && i != 0) { caseGroupIndex++; currentCaseGroup = []; caseGroups[caseGroups.length] = currentCaseGroup; // Joon: Isn't caseGroups.length always equal to caseGroupIndex? } currentCaseGroup[currentCaseGroup.length] = currentCase; for(var j = 0; j < currentCase.actions.length; j++) { var action = currentCase.actions[j]; if(action.action == 'wait') break; if(action.action != 'refreshRepeater') continue; for(var k = 0; k < action.repeatersToRefresh.length; k++) { var id = $ax.getElementIdsFromPath(action.repeatersToRefresh[k], eventInfo)[0]; if(id) guaranteedRefreshes[id] = caseGroupIndex; } } } for(var i = 0; i < caseGroups.length; i++) { var groupRefreshes = []; for(var key in guaranteedRefreshes) { if(guaranteedRefreshes[key] == i) groupRefreshes[groupRefreshes.length] = key; } bubble = _handleCaseGroup(eventInfo, caseGroups[i], groupRefreshes) && bubble; } } else { _showCaseDescriptions(elementId, eventInfo, axEventObject, synthetic); bubble = false; } // If not handled, synthetically bubble if you can if(bubble && _widgetToFocusParent[elementId]) { firingId = _widgetToFocusParent[elementId]; if(firingId) { firingObj = $obj(firingId); nextEventObj = firingObj.interactionMap && firingObj.interactionMap[_descriptionToKey[axEventObject.description]]; if(!nextEventObj) nextEventObj = axEventObject; _handleEvent(firingId, eventInfo, nextEventObj, skipShowDescriptions, synthetic); } return; } // Only trigger a supression if it handled this event if(!bubble && suppressingEvents[eventDescription]) { suppressedEventStatus[suppressingEvents[eventDescription]] = true; } $ax.action.flushAllResizeMoveActions(eventInfo); // This should not be needed anymore. All refreshes should be inserted, or handled earlier. var repeaters = $ax.deepCopy($ax.action.repeatersToRefresh); while($ax.action.repeatersToRefresh.length) $ax.action.repeatersToRefresh.pop(); for(i = 0; i < repeaters.length; i++) $ax.repeater.refreshRepeater(repeaters[i], eventInfo); if(currentEvent && currentEvent.originalEvent) { currentEvent.originalEvent.handled = !synthetic && !bubble && allowBubble.indexOf(eventDescription) == -1; //currentEvent.originalEvent.donotdrag = currentEvent.donotdrag || (!bubble && eventDescription == 'OnMouseDown'); // Prevent default if necessary if(currentEvent.originalEvent.handled && preventDefaultEvents.indexOf(eventDescription) != -1) { currentEvent.preventDefault(); } } eventNesting -= 1; if(!showCaseDescriptions) $ax.messageCenter.postMessage('axEventComplete'); }; var _showCaseDescriptions = function(elementId, eventInfo, axEventObject, synthetic) { if(axEventObject.cases.length == 0) return true; var linksId = elementId + "linkBox"; $('#' + linksId).remove(); var $container = $("
"); if(!_isEventSimulating(axEventObject)) { var copy = $ax.eventCopy(eventInfo); for(var i = 0; i < axEventObject.cases.length; i++) { var $link = $(""); $link.click(function(j) { return function () { var currentCase = axEventObject.cases[j]; $ax.messageCenter.postMessage('axCase', { 'description': currentCase.description }); for(var k = 0; k < currentCase.actions.length; k++) { $ax.messageCenter.postMessage('axAction', { 'description': currentCase.actions[k].description }); } $ax.messageCenter.postMessage('axEventComplete'); var bubble = $ax.action.dispatchAction(copy, axEventObject.cases[j].actions); $ax.action.flushAllResizeMoveActions(copy); $('#' + linksId).remove(); return bubble; }; } (i) ); $container.append($link); } } else { var fullDescription = axEventObject.description + ":
"; for(var i = 0; i < axEventObject.cases.length; i++) { var currentCase = axEventObject.cases[i]; fullDescription += "  " + currentCase.description.replace(/
/g, '
  ') + ":
"; for(var j = 0; j < currentCase.actions.length; j++) { fullDescription += "    " + currentCase.actions[j].description.replace(/
/g, '
      ') + "
"; } } fullDescription = fullDescription.substring(0, fullDescription.length - 4); var $link = $(""); $link.click(function() { _handleEvent(elementId, eventInfo, axEventObject, true, synthetic); $ax.messageCenter.postMessage('axEventComplete'); $('#' + linksId).remove(); return; }); $container.append($link); } $container.mouseleave(function(e) { $ax.legacy.SuppressBubble(e); }); $('body').append($container); _showCaseLinks(eventInfo, linksId); }; var _showCaseLinks = function(eventInfo, linksId) { var links = window.document.getElementById(linksId); links.style.top = eventInfo.pageY; var left = eventInfo.pageX; links.style.left = left; $ax.visibility.SetVisible(links, true); $ax.legacy.BringToFront(linksId, true); // Switch to using jquery if this is still needed. Really old legacy code, likely for a browser no longer supported. //$ax.legacy.RefreshScreen(); }; var _shouldShowCaseDescriptions = function(axEventObject) { if($ax.document.configuration.linkStyle == "alwaysDisplayTargets") return true; if($ax.document.configuration.linkStyle == "neverDisplayTargets") return false; if(axEventObject.cases.length == 0) return false; if(_isEventSimulating(axEventObject)) return false; if(axEventObject.cases.length >= 2) return true; return false; }; var _isEventSimulating = function(axEventObject) { for(var i = 0; i < axEventObject.cases.length; i++) { if(axEventObject.cases[i].condition) return true; } return false; }; var _handleCaseGroup = function(eventInfo, caseGroup, groupRefreshes) { for(var i = 0; i < caseGroup.length; i++) { var currentCase = caseGroup[i]; if(!currentCase.condition || _processCondition(currentCase.condition, eventInfo)) { $ax.messageCenter.postMessage('axCase', { 'description': currentCase.description }); for(var j = 0; j < currentCase.actions.length; j++) { if(currentCase.actions[j].action != 'refreshRepeater') $ax.messageCenter.postMessage('axAction', { 'description': currentCase.actions[j].description }); } for(var j = 0; j < currentCase.actions.length; j++) { var action = currentCase.actions[j]; if(action.action == 'wait') break; if(action.action != 'refreshRepeater') continue; for(var k = 0; k < action.repeatersToRefresh.length; k++) { var id = $ax.getElementIdsFromPath(action.repeatersToRefresh[i], eventInfo)[i]; if(id) { var index = groupRefreshes.indexOf(id); if(index != -1) $ax.splice(groupRefreshes, index); } } } // Any guaranteed refreshes that aren't accounted for must be run still. $ax.action.tryRefreshRepeaters(groupRefreshes, eventInfo); $ax.action.dispatchAction(eventInfo, currentCase.actions); return false; } } // Any guaranteed refreshes that aren't accounted for must be run still. $ax.action.tryRefreshRepeaters(groupRefreshes, eventInfo); return true; }; var _processCondition = function(expr, eventInfo) { return $ax.expr.evaluateExpr(expr, eventInfo); }; var _attachTreeNodeEvent = function(elementId, eventName, fn) { //we need to set the cursor here because we want to make sure that every tree node has the default //cursor set and then it's overridden if it has a click if(eventName == 'click') window.document.getElementById(elementId).style.cursor = 'pointer'; _attachCustomObjectEvent(elementId, eventName, fn); }; var _attachDefaultObjectEvent = function(elementIdQuery, elementId, eventName, fn) { var func = function() { if(!$ax.style.IsWidgetDisabled(elementId)) return fn.apply(this, arguments); return true; }; var bind = !elementIdQuery[eventName]; if(bind) elementIdQuery.bind(eventName, func); else elementIdQuery[eventName](func); }; var _attachCustomObjectEvent = function(elementId, eventName, fn) { var handlers = _objectIdToEventHandlers[elementId]; if(!handlers) _objectIdToEventHandlers[elementId] = handlers = {}; var fnList = handlers[eventName]; if(!fnList) handlers[eventName] = fnList = []; fnList[fnList.length] = fn; }; var _fireObjectEvent = function(elementId, event, originalArgs) { var element = window.document.getElementById(elementId); var handlerList = _objectIdToEventHandlers[elementId] && _objectIdToEventHandlers[elementId][event]; if(handlerList) { for(var i = 0; i < handlerList.length; i++) handlerList[i].apply(element, originalArgs); } eventNesting -= 1; }; var _layerToFocusableWidget = {}; var _widgetToFocusParent = {}; _event.layerMapFocus = function(layer, elementId) { var mainObj = layer.objs[0]; // If first child non existant return if (!mainObj) return; var mainId = $ax.getElementIdFromPath([mainObj.id], { relativeTo: elementId }); _widgetToFocusParent[mainId] = elementId; // If first child is a layer, call recursively if ($ax.public.fn.IsLayer(mainObj.type)) { _event.layerMapFocus(mainObj, mainId); var baseId = _layerToFocusableWidget[mainId]; if(baseId) _layerToFocusableWidget[elementId] = baseId; return; } _layerToFocusableWidget[elementId] = mainId; } var _needsProxy = function(obj, id, proxyName) { // layers don't need on focus ever, proxies will handle them if ($ax.public.fn.IsLayer(obj.type)) return false; // If you already focus you don't need to force yourself to proxy. if(obj.interactionMap && obj.interactionMap[proxyName]) return false; var parentId = _widgetToFocusParent[id]; if(parentId) return _needsProxyHelper(parentId, proxyName); return false; } var _needsProxyHelper = function(id, proxyName) { var obj = $obj(id); if(obj.interactionMap && obj.interactionMap[proxyName]) return true; var parentId = _widgetToFocusParent[id]; if(parentId) return _needsProxyHelper(parentId, proxyName); return false; } //for button shapes and images the img is focusable instead of the div to get better outlines // For layers, we remember who their proxy is. $ax.event.getFocusableWidgetOrChildId = function (elementId) { var mappedId = _layerToFocusableWidget[elementId]; if (mappedId) elementId = mappedId; var inputId = $ax.repeater.applySuffixToElementId(elementId, '_input'); var inputQuery = $jobj(inputId); if(inputQuery.length > 0) return inputId; var imgId = $ax.repeater.applySuffixToElementId(elementId, '_img'); var imgQuery = $jobj(imgId); if (imgQuery.length > 0) return imgId; var divId = $ax.repeater.applySuffixToElementId(elementId, '_div'); var divQuery = $jobj(divId); if (divQuery.length > 0) return divId; return elementId; }; var _enteredWidgets = {}; // key is the suppressing event, and the value is the event that is supressed var suppressingEvents = {}; // key is the event that will cancel the suppression, and value is the event that was being suppressed var cancelSuppressions = {}; // suppressed event maps to true if it is supressed var suppressedEventStatus = {}; var initSuppressingEvents = function () { suppressingEvents['OnLongClick'] = 'OnClick'; cancelSuppressions['onMouseDown'] = 'OnClick'; // Have to cancel suppressed event here. Only works for non-synthetic events currently for(var key in cancelSuppressions) { var jEventName = AXURE_TO_JQUERY_EVENT_NAMES[key]; if(!jEventName) continue; $('body').bind(jEventName, function () { suppressedEventStatus[cancelSuppressions[key]] = false; }); } }; // TODO: It may be a good idea to split this into multiple functions, or at least pull out more similar functions into private methods var _initializeObjectEvents = function(query, allowItem) { query.each(function(dObj, elementId) { var $element = $jobj(elementId); var itemId = $ax.repeater.getItemIdFromElementId(elementId); // Focus has to be done before on focus fires // Set up focus 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) || $ax.public.fn.IsListBox(dObj.type) || $ax.public.fn.IsComboBox(dObj.type) || $ax.public.fn.IsButton(dObj.type) || (dObj.tabbable && ($ax.public.fn.IsImageBox(dObj.type) || $ax.public.fn.IsVector(dObj.type) || $ax.IsTreeNodeObject(dObj.type) || $ax.public.fn.IsTableCell(dObj.type)))) { var focusObj = $jobj($ax.event.getFocusableWidgetOrChildId(elementId)); focusObj.focus(function() { window.lastFocusedControl = elementId; }); } // [MAS: Supressing events were here] _createProxies(dObj, elementId); var isDynamicPanel = $ax.public.fn.IsDynamicPanel(dObj.type); if(dObj.interactionMap) { _attachEvents(dObj, elementId, isDynamicPanel); }; if (IE || $axure.browser.isEdge) { $element.mouseenter(function() { _enteredWidgets[elementId] = true; }).mouseleave(function() { _enteredWidgets[elementId] = false; }); } _attachIxStyleEvents(dObj, elementId, $element); var $axElement = undefined; // Unless you are pre eval - don't allow item and have an item id - then set enabled/selected through js as usual if(allowItem || !itemId) { //initialize disabled elements, do this first before selected, cause if a widget is disabled, we don't want to apply selected style anymore if(($ax.public.fn.IsVector(dObj.type) || $ax.public.fn.IsImageBox(dObj.type) || isDynamicPanel || $ax.public.fn.IsLayer(dObj.type)) && dObj.disabled) { if(!$axElement) $axElement = $ax('#' + elementId); $axElement.enabled(false); } // Initialize selected elements if not in repeater if(($ax.public.fn.IsVector(dObj.type) || $ax.public.fn.IsImageBox(dObj.type) || isDynamicPanel || $ax.public.fn.IsLayer(dObj.type)) && dObj.selected) { if(!$axElement) $axElement = $ax('#' + elementId); $axElement.selected(true); } } else { // Otherwise everything should be set up correctly by pre-eval, except disabled is needed if($element.hasClass('disabled')) { $axElement = $ax('#' + elementId); $axElement.enabled(false); } } if(OS_MAC && WEBKIT) { if ($ax.public.fn.IsComboBox(dObj.type) && dObj.disabled) { $jobj($ax.INPUT(elementId)).css('color', 'grayText'); } }; // Initialize Placeholders. Right now this is text boxes and text areas. // Also, the assuption is being made that these widgets with the placeholder, have no other styles (this may change...) var hasPlaceholder = dObj.placeholderText == '' ? true : Boolean(dObj.placeholderText); if(($ax.public.fn.IsTextArea(dObj.type) || $ax.public.fn.IsTextBox(dObj.type)) && hasPlaceholder) { // This is needed to initialize the placeholder state var inputJobj = $jobj($ax.INPUT(elementId)); inputJobj.bind('focus', function () { if(dObj.HideHintOnFocused) { var id = this.id; var inputIndex = id.indexOf('_input'); if (inputIndex == -1) return; var inputId = id.substring(0, inputIndex); if (!$ax.placeholderManager.isActive(inputId)) return; $ax.placeholderManager.updatePlaceholder(inputId, false, true); } $ax.placeholderManager.moveCaret(this.id); }).bind('mouseup', function() { $ax.placeholderManager.moveCaret(this.id); }).bind('blur', function() { var id = this.id; var inputIndex = id.indexOf('_input'); if(inputIndex == -1) return; var inputId = id.substring(0, inputIndex); if($jobj(id).val()) return; $ax.placeholderManager.updatePlaceholder(inputId, true); }); if(ANDROID) { //input fires before keyup, to avoid flicker, supported in ie9 and above inputJobj.bind('input', function() { if(!dObj.HideHintOnFocused) { //hide on type var id = this.id; var inputIndex = id.indexOf('_input'); if(inputIndex == -1) return; var inputId = id.substring(0, inputIndex); if($ax.placeholderManager.isActive(inputId)) { $ax.placeholderManager.updatePlaceholder(inputId, false, true); } else if(!$jobj(id).val()) { $ax.placeholderManager.updatePlaceholder(inputId, true, false); $ax.placeholderManager.moveCaret(id, 0); } } }); } else { inputJobj.bind('keydown', function() { if(!dObj.HideHintOnFocused) { var id = this.id; var inputIndex = id.indexOf('_input'); if(inputIndex == -1) return; var inputId = id.substring(0, inputIndex); if(!$ax.placeholderManager.isActive(inputId)) return; $ax.placeholderManager.updatePlaceholder(inputId, false, true); } }).bind('keyup', function() { var id = this.id; var inputIndex = id.indexOf('_input'); if(inputIndex == -1) return; var inputId = id.substring(0, inputIndex); if($ax.placeholderManager.isActive(inputId)) return; if(!dObj.HideHintOnFocused && !$jobj(id).val()) { $ax.placeholderManager.updatePlaceholder(inputId, true); $ax.placeholderManager.moveCaret(id, 0); } }); } $ax.placeholderManager.registerPlaceholder(elementId, dObj.placeholderText, inputJobj.attr('type') == 'password'); $ax.placeholderManager.updatePlaceholder(elementId, !($jobj($ax.repeater.applySuffixToElementId(elementId, '_input')).val())); } // Initialize assigned submit buttons if(dObj.submitButton) { $element.keyup(function(e) { if(e.keyCode == '13') { var scriptId = $ax.repeater.getScriptIdFromElementId(elementId); var path = $ax.deepCopy(dObj.submitButton.path); path[path.length] = dObj.submitButton.id; var itemNum = $ax.repeater.getItemIdFromElementId(elementId); var submitId = $ax.getScriptIdFromPath(path, scriptId); if(itemNum && $ax.getParentRepeaterFromScriptId(submitId) == $ax.getParentRepeaterFromScriptId(scriptId)) { submitId = $ax.repeater.createElementId(submitId, itemNum); } var inputId = $ax.INPUT(submitId); if($jobj(inputId).length) submitId = inputId; $ax.setjBrowserEvent(e); $ax.event.fireClick(submitId); } }).keydown(function(e) { if(e.keyCode == '13') { e.preventDefault(); } }); } // Don't drag after mousing down on a plain text object if ($ax.public.fn.IsTextArea(dObj.type) || $ax.public.fn.IsTextBox(dObj.type) || $ax.public.fn.IsListBox(dObj.type) || $ax.public.fn.IsComboBox(dObj.type) || $ax.public.fn.IsCheckBox(dObj.type) || $ax.public.fn.IsRadioButton(dObj.type)) { $element.bind($ax.features.eventNames.mouseDownName, function(event) { event.originalEvent.donotdrag = true; }); } if($ax.features.supports.mobile) { $element.bind($ax.features.eventNames.mouseDownName, function() { _setCanClick(true); }); if (isDynamicPanel) { $element.scroll(function() { _setCanClick(false); }); } } //initialize tree node cursors to default so they will override their parent if ($ax.public.fn.IsTreeNodeObject(dObj.type) && !(dObj.interactionMap && dObj.interactionMap.onClick)) { $element.css('cursor', 'default'); } //initialize widgets that are clickable to have the pointer over them when hovering if($ax.event.HasClick(dObj)) { if($element) $element.css('cursor', 'pointer'); } // TODO: not sure if we need this. It appears to be working without //initialize panels for DynamicPanels if (isDynamicPanel) { $element.children().each(function() { var parts = this.id.split('_'); var state = parts[parts.length - 1].substring(5); if(state != 0) $ax.visibility.SetVisible(this, false); }); } //initialize TreeNodes if ($ax.public.fn.IsTreeNodeObject(dObj.type)) { if($element.hasClass('treeroot')) return; var childrenId = elementId + '_children'; var children = $element.children('[id="' + childrenId + '"]:first'); if(children.length > 0) { var plusMinusId = 'u' + (parseInt($ax.repeater.getScriptIdFromElementId(elementId).substring(1)) + 1); if(itemId) plusMinusId = $ax.repeater.createElementId(plusMinusId, itemId); if(!$jobj(plusMinusId).children().first().is('img')) plusMinusId = ''; $ax.tree.InitializeTreeNode(elementId, plusMinusId, childrenId); } $element.click(function() { $ax.tree.SelectTreeNode(elementId, true); }); } //initialize submenus if ($ax.public.fn.IsMenuObject(dObj.type)) { if($element.hasClass('sub_menu')) { var tableCellElementId = $ax.getElementIdFromPath([dObj.parentCellId], { relativeTo: elementId }); $ax.menu.InitializeSubmenu(elementId, tableCellElementId); } } // Attach handles for dynamic panels that propagate styles to inner items. if ((isDynamicPanel || $ax.public.fn.IsLayer(dObj.type)) && dObj.propagate) { $element.mouseenter(function() { dynamicPanelMouseOver(this.id); }).mouseleave(function() { dynamicPanelMouseLeave(this.id); }).bind($ax.features.eventNames.mouseDownName, function() { dynamicPanelMouseDown(this.id); }).bind($ax.features.eventNames.mouseUpName, function() { dynamicPanelMouseUp(this.id); }); } // These are the dynamic panel functions for propagating rollover styles and mouse down styles to inner objects var dynamicPanelMouseOver = function(elementId, fromChild) { var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId); if(parent) { dynamicPanelMouseOver(parent.id, true); if(parent.direct) return; } if($.inArray(elementId, _event.mouseOverIds) != -1) return; // If this event is coming from a child, don't mark that it's actually entered. // Only mark that this has been entered if this event has naturally been triggered. (For reason see mouseleave) if(!fromChild) _event.mouseOverIds[_event.mouseOverIds.length] = elementId; if(elementId == _event.mouseOverObjectId) return; _event.mouseOverObjectId = elementId; $ax.dynamicPanelManager.propagateMouseOver(elementId, true); }; var dynamicPanelMouseLeave = function(elementId, fromChild) { var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId); if(parent) { dynamicPanelMouseLeave(parent.id, true); if(parent.direct) return; } var index = $.inArray(elementId, _event.mouseOverIds); // If index != -1, this has been natuarally entered. If naturally entered, then leaving child should not trigger leaving, // but instead wait for natural mouse leave. If natural mouse enter never triggered, natural mouse leave won't so do this now. if((index != -1) && fromChild) return; $ax.splice(_event.mouseOverIds, index, 1); if(elementId == _event.mouseOverObjectId) { _event.mouseOverObjectId = ''; } $ax.dynamicPanelManager.propagateMouseOver(elementId, false); }; //attach handlers for button shape and tree node mouse over styles // TODO: Can this really be removed? Trees seem to work with out (the generic hover case works for it). // query.filter(function(obj) { // return $ax.public.fn.IsVector(obj.type) && $ax.public.fn.IsTreeNodeObject(obj.parent.type) && // obj.parent.style && obj.parent.style.stateStyles && // obj.parent.style.stateStyles.mouseOver; // }).mouseenter(function() { // $ax.style.SetWidgetHover(this.id, true); // }).mouseleave(function() { // $ax.style.SetWidgetHover(this.id, false); // }); //handle treeNodeObject events and prevent them from bubbling up. this is necessary because otherwise //both a sub menu and it's parent would get a click if ($ax.public.fn.IsTreeNodeObject(dObj.type)) { $element.click(function() { //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) _fireObjectEvent(this.id, 'click', arguments); return false; }).each(function() { if(!this.style.cursor) { this.style.cursor = 'default'; } }); } // Synthetic events var map = dObj.interactionMap; // Attach dynamic panel synthetic drag and swipe events if(dObj.type == "dynamicPanel" && map && ( map.onDragStart || map.onDrag || map.onDragDrop || map.onSwipeLeft || map.onSwipeRight || map.onSwipeUp || map.onSwipeDown)) { $element.bind($ax.features.eventNames.mouseDownName, function(e) { $ax.drag.StartDragWidget(e.originalEvent, elementId); }); } // Attach dynamic panel synthetic scroll event if (isDynamicPanel && map && (map.onScroll || map.onScrollUp || map.onScrollDown)) { var diagrams = dObj.diagrams; for(var i = 0; i < diagrams.length; i++) { var panelId = $ax.repeater.applySuffixToElementId(elementId, '_state' + i); (function(id) { if ($('#' + id).data('lastScrollTop') == undefined) $('#' + id).data('lastScrollTop', '0'); _attachDefaultObjectEvent($('#' + id), elementId, 'scroll', function(e) { $ax.setjBrowserEvent(e); var currentEvent = $ax.getjBrowserEvent(); var eventInfoFromEvent = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), false, elementId); if(map.onScroll) _handleEvent(elementId, eventInfoFromEvent, map.onScroll); var currentTop = $('#' + id).scrollTop(); var wasHandled = currentEvent.originalEvent.handled; if (map.onScrollUp && currentTop < $('#' + id).data('lastScrollTop')) { currentEvent.originalEvent.handled = false; _handleEvent(elementId, eventInfoFromEvent, map.onScrollUp); } else if (map.onScrollDown && currentTop > $('#' + id).data('lastScrollTop')) { currentEvent.originalEvent.handled = false; _handleEvent(elementId, eventInfoFromEvent, map.onScrollDown); } currentEvent.originalEvent.handled |= wasHandled; $('#' + id).data('lastScrollTop', currentTop); }); })(panelId); } } // Attach synthetic hover event if (map && map.onMouseHover) { var MIN_HOVER_HOLD_TIME = 1000; // So when the timeout fires, you know whether it is the same mouseenter that is active or not. var hoverMouseCount = 0; // Update eventInfo regularly, so position is accurate. var hoverEventInfo; $element.mouseenter(function(e) { $ax.setjBrowserEvent(e); hoverEventInfo = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), false, elementId); (function(currCount) { window.setTimeout(function() { if(currCount == hoverMouseCount) _raiseSyntheticEvent(elementId, 'onMouseHover', false, hoverEventInfo, true); }, MIN_HOVER_HOLD_TIME); })(hoverMouseCount); }).mouseleave(function(e) { $ax.setjBrowserEvent(e); hoverMouseCount++; }).mousemove(function(e) { $ax.setjBrowserEvent(e); hoverEventInfo = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), false, elementId); }); } // Attach synthetic tap and hold event. if (map && map.onLongClick) { var MIN_LONG_CLICK_HOLD_TIME = 750; // So when the timeout fires, you know whether it is the same mousedown that is active or not. var longClickMouseCount = 0; $element.bind($ax.features.eventNames.mouseDownName, function(e) { (function(currCount) { $ax.setjBrowserEvent(e); var eventInfo = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), false, elementId); window.setTimeout(function() { if(currCount == longClickMouseCount) _raiseSyntheticEvent(elementId, 'onLongClick', false, eventInfo, true); }, MIN_LONG_CLICK_HOLD_TIME); if(e.preventDefault) e.preventDefault(); })(longClickMouseCount); }).bind($ax.features.eventNames.mouseUpName, function(e) { $ax.setjBrowserEvent(e); longClickMouseCount++; }); }; // Attach synthetic onSelectionChange event to droplist and listbox elements if ($ax.event.HasSelectionChanged(dObj)) { $element.bind('change', function(e) { $ax.setjBrowserEvent(e); _raiseSyntheticEvent(elementId, 'onSelectionChange'); }); }; // Highjack key up and key down to keep track of state of keyboard. if($ax.event.HasKeyUpOrDown(dObj)) _event.initKeyEvents($element); // Attach synthetic onTextChange event to textbox and textarea elements if ($ax.event.HasTextChanged(dObj)) { var element = $jobj($ax.INPUT(elementId)); $ax.updateElementText(elementId, element.val()); //Key down needed because when holding a key down, key up only fires once, but keydown fires repeatedly. //Key up because last mouse down will only show the state before the last character. element.bind('keydown', function(e) { $ax.setjBrowserEvent(e); $ax.event.TryFireTextChanged(elementId); }).bind('keyup', function(e) { $ax.setjBrowserEvent(e); $ax.event.TryFireTextChanged(elementId); }); }; // Attach synthetic onCheckedChange event to radiobutton and checkbox elements if ($ax.public.fn.IsCheckBox(dObj.type) || $ax.public.fn.IsRadioButton(dObj.type)) { var input = $jobj($ax.INPUT(elementId)); if ($ax.public.fn.IsRadioButton(dObj.type) && input.prop('checked')) { $ax.updateRadioButtonSelected(input.attr('name'), elementId); } $element.bind('change', function(e) { $ax.setjBrowserEvent(e); var eTarget = e.target || e.srcElement; _tryFireCheckedChanged(elementId, eTarget.checked); }); }; var hasTap = map && (map.onClick || map.onDoubleClick); var hasMove = map && map.onMouseMove; _event.initMobileEvents(hasTap ? $element : $(), hasMove ? $element : $(), elementId); //attach link alternate styles if(dObj.type == 'hyperlink') { $element.mouseenter(function() { var elementId = this.id; if(_event.mouseOverIds.indexOf(elementId) != -1) return true; _event.mouseOverIds[_event.mouseOverIds.length] = elementId; var mouseOverObjectId = _event.mouseOverObjectId; if(mouseOverObjectId && $ax.style.IsWidgetDisabled(mouseOverObjectId)) return true; $ax.style.SetLinkHover(elementId); var bubble = _fireObjectEvent(elementId, 'mouseenter', arguments); $ax.annotation.updateLinkLocations($ax.style.GetTextIdFromLink(elementId)); return bubble; }).mouseleave(function() { var elementId = this.id; $ax.splice(_event.mouseOverIds, _event.mouseOverIds.indexOf(elementId), 1); var mouseOverObjectId = _event.mouseOverObjectId; if(mouseOverObjectId && $ax.style.IsWidgetDisabled(mouseOverObjectId)) return true; $ax.style.SetLinkNotHover(elementId); var bubble = _fireObjectEvent(elementId, 'mouseleave', arguments); $ax.annotation.updateLinkLocations($ax.style.GetTextIdFromLink(elementId)); return bubble; }).bind($ax.features.eventNames.mouseDownName, function() { var elementId = this.id; var mouseOverObjectId = _event.mouseOverObjectId; if($ax.style.IsWidgetDisabled(mouseOverObjectId)) return undefined; if(mouseOverObjectId) $ax.style.SetWidgetMouseDown(mouseOverObjectId, true); $ax.style.SetLinkMouseDown(elementId); $ax.annotation.updateLinkLocations($ax.style.GetTextIdFromLink(elementId)); return false; }).bind($ax.features.eventNames.mouseUpName, function() { var elementId = this.id; var mouseOverObjectId = _event.mouseOverObjectId; if(mouseOverObjectId && $ax.style.IsWidgetDisabled(mouseOverObjectId)) return; if(mouseOverObjectId) $ax.style.SetWidgetMouseDown(mouseOverObjectId, false); $ax.style.SetLinkNotMouseDown(elementId); $ax.annotation.updateLinkLocations($ax.style.GetTextIdFromLink(elementId)); }).click(function() { var elementId = this.id; var mouseOverObjectId = _event.mouseOverObjectId; if(mouseOverObjectId && $ax.style.IsWidgetDisabled(mouseOverObjectId)) return undefined; return _fireObjectEvent(elementId, 'click', arguments); }); } // Init inline frames if (dObj.type == 'inlineFrame') { var target = dObj.target; var url = ''; if(target.includeVariables && target.url) { var origSrc = target.url; url = origSrc.toLowerCase().indexOf('http://') == -1 ? $ax.globalVariableProvider.getLinkUrl(origSrc) : origSrc; } else if(target.urlLiteral) { url = $ax.expr.evaluateExpr(target.urlLiteral, $ax.getEventInfoFromEvent(undefined, true, elementId), true); } if(url) $jobj($ax.INPUT(elementId)).attr('src', url); }; }); } $ax.initializeObjectEvents = _initializeObjectEvents; $ax.event.updateIxStyleEvents = function(elementId) { _dettachIxStyleEvents(elementId); _attachIxStyleEvents($ax.getObjectFromElementId(elementId), elementId, $jobj(elementId), true); } var _dettachIxStyleEvents = function(elementId) { var $element = $jobj(elementId); $element.off('mouseenter.ixStyle') .off('mouseleave.ixStyle') .off($ax.features.eventNames.mouseDownName + '.ixStyle') .off($ax.features.eventNames.mouseUpName + '.ixStyle'); } var _attachIxStyleEvents = function(dObj, elementId, $element, ignoreHasIxStyles) { //attach button shape alternate styles var isDynamicPanel = $ax.public.fn.IsDynamicPanel(dObj.type); var needsMouseFilter = (ignoreHasIxStyles || $ax.event.HasIxStyles(dObj)) && dObj.type != 'hyperlink' && !$ax.public.fn.IsLayer(dObj.type) && !isDynamicPanel && dObj.type != 'richTextPanel' && !$ax.public.fn.IsRepeater(dObj.type) && !$ax.public.fn.IsCheckBox(dObj.type) && !$ax.public.fn.IsRadioButton(dObj.type) && !$ax.public.fn.IsTreeNodeObject(dObj.type); if(needsMouseFilter) { //$element.mouseenter(function () { $element.on('mouseenter.ixStyle', function () { var elementId = this.id; var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId); if(parent && parent.direct) return; if($.inArray(elementId, _event.mouseOverIds) != -1) return; _event.mouseOverIds[_event.mouseOverIds.length] = elementId; if(elementId == _event.mouseOverObjectId) return; _event.mouseOverObjectId = elementId; $ax.style.SetWidgetHover(elementId, true); var textId = $ax.style.GetTextIdFromShape(elementId); if(textId) $ax.annotation.updateLinkLocations(textId); //}).mouseleave(function () { }).on('mouseleave.ixStyle', function () { var elementId = this.id; var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId); if(parent && parent.direct) return; $ax.splice(_event.mouseOverIds, $.inArray(elementId, _event.mouseOverIds), 1); if(elementId == _event.mouseOverObjectId) { _event.mouseOverObjectId = ''; } $ax.style.SetWidgetHover(elementId, false); var textId = $ax.style.GetTextIdFromShape(elementId); if(textId) $ax.annotation.updateLinkLocations(textId); }); //$element.bind($ax.features.eventNames.mouseDownName, function () { $element.on($ax.features.eventNames.mouseDownName + '.ixStyle', function () { var elementId = this.id; var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId); if(parent) { dynamicPanelMouseDown(parent.id); if(parent.direct) return; } _event.mouseDownObjectId = elementId; $ax.style.SetWidgetMouseDown(this.id, true); $ax.annotation.updateLinkLocations($ax.style.GetTextIdFromShape(elementId)); //}).bind($ax.features.eventNames.mouseUpName, function () { }).on($ax.features.eventNames.mouseUpName + '.ixStyle', function () { var elementId = this.id; var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId); if(parent) { dynamicPanelMouseUp(parent.id); if(parent.direct) return; } _event.mouseDownObjectId = ''; if(!$ax.style.ObjHasMouseDown(elementId)) return; $ax.style.SetWidgetMouseDown(elementId, false); $ax.annotation.updateLinkLocations($ax.style.GetTextIdFromShape(elementId)); //there used to be something we needed to make images click, because swapping out the images prevents the click // this is a note that we can eventually delete. }); } }; var dynamicPanelMouseDown = function (elementId) { var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId); if(parent) { dynamicPanelMouseDown(parent.id); if(parent.direct) return; } _event.mouseDownObjectId = elementId; $ax.dynamicPanelManager.propagateMouseDown(elementId, true); }; var dynamicPanelMouseUp = function (elementId) { var parent = $ax.dynamicPanelManager.parentHandlesStyles(elementId); if(parent) { dynamicPanelMouseUp(parent.id); if(parent.direct) return; } _event.mouseDownObjectId = ''; $ax.dynamicPanelManager.propagateMouseDown(elementId, false); }; // Handle key up and key down events (function() { var _keyState = {}; _keyState.ctrl = false; _keyState.alt = false; _keyState.shift = false; _keyState.keyCode = 0; $ax.event.keyState = function() { return $ax.deepCopy(_keyState); }; var modifierCodes = [16, 17, 18]; var clearKeyCode = false; $ax.event.initKeyEvents = function($query) { $query.keydown(function (e) { if(clearKeyCode) { clearKeyCode = false; _keyState.keyCode = 0; } var elementId = this.id; _keyState.ctrl = e.ctrlKey; _keyState.alt = e.altKey; _keyState.shift = e.shiftKey; // If a modifier was pressed, then don't set the keyCode; if(modifierCodes.indexOf(e.keyCode) == -1) _keyState.keyCode = e.keyCode; $ax.setjBrowserEvent(e); if (!elementId) fireEventThroughContainers('onKeyDown', undefined, false, [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE, $ax.constants.DYNAMIC_PANEL_TYPE, $ax.constants.REPEATER], [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE, $ax.constants.LAYER_TYPE]); else _raiseSyntheticEvent(elementId, 'onKeyDown', false, undefined, true); }); $query.keyup(function(e) { var elementId = this.id; if (modifierCodes.indexOf(e.keyCode) == -1) clearKeyCode = true; else if (clearKeyCode) { clearKeyCode = false; _keyState.keyCode = 0; } $ax.setjBrowserEvent(e); // Fire event before updating modifiers. if (!elementId) fireEventThroughContainers('onKeyUp', undefined, false, [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE, $ax.constants.DYNAMIC_PANEL_TYPE, $ax.constants.REPEATER], [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE, $ax.constants.LAYER_TYPE]); else _raiseSyntheticEvent(elementId, 'onKeyUp', false, undefined, true); //_keyState.ctrl = e.ctrlKey; //_keyState.alt = e.altKey; //_keyState.shift = e.shiftKey; //// If a non-modifier was lifted, clear the keycode ///if(modifierCodes.indexOf(e.keyCode) == -1) _keyState.keyCode = 0; }); }; })(); // Handle adding mobile events (function() { // NOTE: Multi touch is NOT handled currently. var CLICK_THRESHOLD_PX = 25; var CLICK_THRESHOLD_PX_SQ = CLICK_THRESHOLD_PX * CLICK_THRESHOLD_PX; var DBLCLICK_THRESHOLD_MS = 500; // Location in page cooridinates var tapDownLoc; var lastClickEventTime; _event.initMobileEvents = function($tapQuery, $moveQuery, elementId) { if(!$ax.features.supports.mobile) return; // Handle touch start $tapQuery.bind('touchstart', function(e) { // We do NOT support multiple touches. This isn't necessarily the touch we want. var touch = e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0]; if(!touch) return; tapDownLoc = [touch.pageX, touch.pageY]; var time = (new Date()).getTime(); if(time - lastClickEventTime < DBLCLICK_THRESHOLD_MS) { var dObj = elementId === '' ? $ax.pageData.page : $ax.getObjectFromElementId(elementId); var axEventObject = dObj && dObj.interactionMap && dObj.interactionMap['onDoubleClick']; if(axEventObject) e.preventDefault(); //for Chrome on Android } }).bind('touchend', function(e) { var touch = e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0]; if(!touch || !tapDownLoc) return; var tapUpLoc = [touch.pageX, touch.pageY]; var xDiff = tapUpLoc[0] - tapDownLoc[0]; var yDiff = tapUpLoc[1] - tapDownLoc[1]; if((xDiff * xDiff + yDiff * yDiff) < CLICK_THRESHOLD_PX_SQ) { $ax.setjBrowserEvent(e); _raiseSyntheticEvent(elementId, 'onClick', false, undefined, true); var time = (new Date()).getTime(); if(time - lastClickEventTime < DBLCLICK_THRESHOLD_MS) { _raiseSyntheticEvent(elementId, 'onDoubleClick', false, undefined, true); if(e.originalEvent && e.originalEvent.handled) e.preventDefault(); //for iOS } lastClickEventTime = time; } }); // Handles touch move $moveQuery.bind('touchmove', function(e) { $ax.setjBrowserEvent(e); _raiseSyntheticEvent(elementId, 'onMouseMove', false, undefined, true); if(e.originalEvent && e.originalEvent.handled) e.preventDefault(); }); }; })(); // Handle adding device independent click events to non-widgets (function() { var CLICK_THRESHOLD_PX = 25; var CLICK_THRESHOLD_PX_SQ = CLICK_THRESHOLD_PX * CLICK_THRESHOLD_PX; // Location in page cooridinates var tapDownLoc; _event.attachClick = function(query, clickHandler) { if(!$ax.features.supports.mobile) { query.click(clickHandler); return; } $(query).bind('touchstart', function(e) { // We do NOT support multiple touches. This isn't necessarily the touch we want. var touch = e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0]; if(!touch) return; tapDownLoc = [touch.pageX, touch.pageY]; }); $(query).bind('touchend', function(e) { var touch = e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0]; if(!touch) return; var tapUpLoc = [touch.pageX, touch.pageY]; var xDiff = tapUpLoc[0] - tapDownLoc[0]; var yDiff = tapUpLoc[1] - tapDownLoc[1]; if((xDiff * xDiff + yDiff * yDiff) < CLICK_THRESHOLD_PX_SQ) { clickHandler(); } }); }; })(); // Handle firing device independent click events on widgets (function() { _event.fireClick = function(elementId) { if(!$ax.features.supports.mobile) { $('#' + elementId).click(); return; } _raiseSyntheticEvent(elementId, 'onClick', false, undefined, true); }; })(); var _mouseLocation = $ax.mouseLocation = { x: 0, y: 0 }; var _lastmouseLocation = $ax.lastMouseLocation = { x: 0, y: 0 }; var _updateMouseLocation = function(e, end) { if(!e) return; if(IE_10_AND_BELOW && typeof (e.type) == 'unknown') return; if(e.type != 'mousemove' && e.type != 'touchstart' && e.type != 'touchmove' && e.type != 'touchend') return; var newX; var newY; if(IE_10_AND_BELOW) { newX = e.clientX + $('html').scrollLeft(); newY = e.clientY + $('html').scrollTop(); } else { newX = e.pageX; newY = e.pageY; } //var body = $('body'); //if(body.css('position') == 'relative') newX = Math.round(newX - Number(body.css('left').replace('px', '')) - Math.max(0, ($(window).width() - body.width()) / 2)); if(_mouseLocation.x == newX && _mouseLocation.y == newY) return; _lastmouseLocation.x = _mouseLocation.x; _lastmouseLocation.y = _mouseLocation.y; _mouseLocation.x = newX; _mouseLocation.y = newY; $ax.geometry.tick(_mouseLocation.x, _mouseLocation.y, end); }; _event.updateMouseLocation = _updateMouseLocation; var _leavingState = function(stateId) { var mouseOverIds = _event.mouseOverIds; if(mouseOverIds.length == 0) return; var stateQuery = $jobj(stateId); for(var i = mouseOverIds.length - 1; i >= 0; i--) { var id = mouseOverIds[i]; if(stateQuery.find('#' + id).length) { $ax.splice(mouseOverIds, $.inArray(id, mouseOverIds), 1); $ax.style.SetWidgetMouseDown(id, false); $ax.style.SetWidgetHover(id, false); } } }; _event.leavingState = _leavingState; var _raiseSelectedEvents = function(elementId, value) { $ax.event.raiseSyntheticEvent(elementId, 'onSelectedChange'); if(value) $ax.event.raiseSyntheticEvent(elementId, 'onSelect'); else $ax.event.raiseSyntheticEvent(elementId, 'onUnselect'); }; $ax.event.raiseSelectedEvents = _raiseSelectedEvents; var _raiseSyntheticEvent = function(elementId, eventName, skipShowDescription, eventInfo, nonSynthetic) { // Empty string used when this is an event directly on the page. var dObj = elementId === '' ? $ax.pageData.page : $ax.getObjectFromElementId(elementId); var axEventObject = dObj && dObj.interactionMap && dObj.interactionMap[eventName]; if(!axEventObject) return; eventInfo = eventInfo || $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), skipShowDescription, elementId); // $ax.recording.maybeRecordEvent(elementId, eventInfo, axEventObject, new Date().getTime()); _handleEvent(elementId, eventInfo, axEventObject, false, !nonSynthetic); }; $ax.event.raiseSyntheticEvent = _raiseSyntheticEvent; var _hasSyntheticEvent = function(scriptId, eventName) { var dObj = $ax.getObjectFromScriptId(scriptId); var axEventObject = dObj && dObj.interactionMap && dObj.interactionMap[eventName]; return Boolean(axEventObject); }; $ax.event.hasSyntheticEvent = _hasSyntheticEvent; var _addEvent = function (target, eventType, handler, useCapture) { //this return value is only for debug purpose var succeed = undefined; if(target.attachEvent) { if($ax.features.supports.windowsMobile) { succeed = target.attachEvent(eventType, handler); } else { succeed = target.attachEvent('on' + eventType, handler); } } else if(target.addEventListener) { target.addEventListener(eventType, handler, useCapture); succeed = true; } return succeed; } $ax.event.addEvent = _addEvent; var _removeEvent = function(target, eventType, handler, useCapture, skipCheckingWindowsMobile) { //this return value is only for debug purpose var succeed = undefined; if(target.detachEvent) { if(!skipCheckingWindowsMobile && $ax.features.supports.windowsMobile) { succeed = target.detachEvent(eventType, handler); } else { succeed = target.detachEvent('on' + eventType, handler); } } else if(target.removeEventListener) { target.removeEventListener(eventType, handler, useCapture); succeed = true; } return succeed; } $ax.event.removeEvent = _removeEvent; var _initialize = function() { $ax.repeater.load(); // Make sure key events for page are initialized first. That way they will update the value of key pressed before any other events occur. _event.initKeyEvents($(window)); initSuppressingEvents(); // Anything with an item id is in a repeater and should be handled by that repeater. _initializeObjectEvents($ax(function(obj, elementId) { return !$ax.repeater.getItemIdFromElementId(elementId); })); //finally, process the pageload _pageLoad(); // _loadDynamicPanelsAndMasters(); // $ax.repeater.init(); // and wipe out the basic links. $('.basiclink').click(function() { return false; }); }; _event.initialize = _initialize; $ax.event.HasIxStyles = function(diagramObject) { if(diagramObject.style.stateStyles) return true; if(diagramObject.adaptiveStyles) { for(var viewId in diagramObject.adaptiveStyles) { if(diagramObject.adaptiveStyles[viewId].stateStyles) return true; } } return false; }; $ax.event.HasTextChanged = function(diagramObject) { if (!$ax.public.fn.IsTextBox(diagramObject.type) && !$ax.public.fn.IsTextArea(diagramObject.type)) return false; var map = diagramObject.interactionMap; return map && map.onTextChange; }; $ax.event.TryFireTextChanged = function(elementId) { var query = $jobj($ax.repeater.applySuffixToElementId(elementId, '_input')); if(!$ax.hasElementTextChanged(elementId, query.val())) return; $ax.updateElementText(elementId, query.val()); $ax.event.raiseSyntheticEvent(elementId, 'onTextChange'); }; $ax.event.HasSelectionChanged = function(diagramObject) { if (!$ax.public.fn.IsListBox(diagramObject.type) && !$ax.public.fn.IsComboBox(diagramObject.type)) return false; var map = diagramObject.interactionMap; return map && map.onSelectionChange; }; $ax.event.HasKeyUpOrDown = function (diagramObject) { if($ax.public.fn.IsTextBox(diagramObject.type) || $ax.public.fn.IsTextArea(diagramObject.type)) return true; var map = diagramObject.interactionMap; return map && (map.onKeyUp || map.onKeyDown); }; $ax.event.HasCheckedChanged = function(diagramObject) { if (!$ax.public.fn.IsCheckBox(diagramObject.type) && !$ax.public.fn.IsRadioButton(diagramObject.type)) return false; var map = diagramObject.interactionMap; return map && map.onSelectedChange; }; $ax.event.HasClick = function (diagramObject) { var map = diagramObject.interactionMap; return map && map.onClick; }; var _tryFireCheckedChanged = $ax.event.TryFireCheckChanged = function(elementId, value) { var isRadio = $ax.public.fn.IsRadioButton($obj(elementId).type); if(isRadio) { if(!value) { $ax.updateRadioButtonSelected($jobj($ax.INPUT(elementId)).attr('name'), undefined); } else { var last = $ax.updateRadioButtonSelected($jobj($ax.INPUT(elementId)).attr('name'), elementId); // If no change, this should not fire if(last == elementId) return; // Initially selecting one, last may be undefined if(last) { //here last is the previouse selected elementid $ax.event.raiseSelectedEvents(last, false); } } } $ax.event.raiseSelectedEvents(elementId, value); }; //onload everything now, not only dp and master var _loadDynamicPanelsAndMasters = function(objects, path, itemId) { fireEventThroughContainers('onLoad', objects, true, [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE, $ax.constants.DYNAMIC_PANEL_TYPE], [$ax.constants.ALL_TYPE], path, itemId); }; $ax.loadDynamicPanelsAndMasters = _loadDynamicPanelsAndMasters; var _viewChangePageAndMasters = function(forceSwitchTo) { fireEventThroughContainers('onAdaptiveViewChange', undefined, true, [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE, $ax.constants.DYNAMIC_PANEL_TYPE], [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE]); _postAdaptiveViewChanged(forceSwitchTo); }; $ax.viewChangePageAndMasters = _viewChangePageAndMasters; //if forceSwitchTo is true, we will also update the checkmark in sitemap.js var _postAdaptiveViewChanged = function(forceSwitchTo) { //only trigger adaptive view changed if the window is on the mainframe. Also triggered on init, even if default. try { if(window.name == 'mainFrame' || (!CHROME_5_LOCAL && window.parent.$ && window.parent.$('#mainFrame').length > 0)) { var data = { viewId: $ax.adaptive.currentViewId, forceSwitchTo: forceSwitchTo }; $axure.messageCenter.postMessage('adaptiveViewChange', data); } } catch(e) { } }; $ax.postAdaptiveViewChanged = _postAdaptiveViewChanged; var _postResize = $ax.postResize = function(e) { $ax.setjBrowserEvent(e); return fireEventThroughContainers('onResize', undefined, false, [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE, $ax.constants.DYNAMIC_PANEL_TYPE, $ax.constants.REPEATER], [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE]); }; //fire events for table, menu and tree, including its sub items var _fireEventsForTableMenuAndTree = function (object, event, skipShowDescription, eventInfo, path, synthetic) { if (!path) path = []; var pathCopy = path.slice(); pathCopy[path.length] = object.id; var scriptId = $ax.getScriptIdFromPath(pathCopy); $ax.event.raiseSyntheticEvent(scriptId, event, skipShowDescription, eventInfo, !synthetic); if(object.objects) { for(var index = 0; index < object.objects.length; index++) { var subObj = object.objects[index]; if ($ax.public.fn.IsTableCell(subObj.type)) { pathCopy[path.length] = subObj.id; scriptId = $ax.getScriptIdFromPath(pathCopy); $ax.event.raiseSyntheticEvent(scriptId, event, skipShowDescription, eventInfo, !synthetic); } else if ($ax.public.fn.IsTable(object.type) || $ax.public.fn.IsMenuObject(object.type) || $ax.public.fn.IsTreeNodeObject(object.type)) { _fireEventsForTableMenuAndTree(subObj, event, skipShowDescription, eventInfo, path, synthetic); } } } } // if ($('#' + id).data('lastScrollTop') == undefined) $('#' + id).data('lastScrollTop', '0'); // _attachDefaultObjectEvent($('#' + id), elementId, 'scroll', function (e) { // $ax.setjBrowserEvent(e); // var currentEvent = $ax.getjBrowserEvent(); // var eventInfoFromEvent = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), false, elementId); // if (map.onScroll) _handleEvent(elementId, eventInfoFromEvent, map.onScroll); // // var currentTop = $('#' + id).scrollTop(); // var wasHandled = currentEvent.originalEvent.handled; // if (map.onScrollUp && currentTop < $('#' + id).data('lastScrollTop')) { // currentEvent.originalEvent.handled = false; // _handleEvent(elementId, eventInfoFromEvent, map.onScrollUp); // } else if (map.onScrollDown && currentTop > $('#' + id).data('lastScrollTop')) { // currentEvent.originalEvent.handled = false; // _handleEvent(elementId, eventInfoFromEvent, map.onScrollDown); // } // currentEvent.originalEvent.handled |= wasHandled; // $('#' + id).data('lastScrollTop', currentTop); // }); //remember the scroll bar position, so we can detect scroll up/down var lastScrollTop; // Filters include page, referenceDiagramObject, dynamicPanel, and repeater. var fireEventThroughContainers = function(eventName, objects, synthetic, searchFilter, callFilter, path, itemId) { // 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 var skipShowDescription = eventName == 'onLoad'; // If objects undefined, load page if(!objects) { if(_callFilterCheck(callFilter, $ax.constants.PAGE_TYPE)) { var map = $ax.pageData.page.interactionMap; var currentEvent = $ax.getjBrowserEvent(); var pageEvent = map && map[eventName]; var scrolling = currentEvent && currentEvent.type === "scroll"; if (scrolling && !pageEvent && map) pageEvent = map.onScrollUp || map.onScrollDown; if(pageEvent) { var pageEventInfo = $ax.getEventInfoFromEvent(currentEvent, skipShowDescription, ''); pageEventInfo.label = $ax.pageData.page.name; pageEventInfo.friendlyType = 'Page'; if (!scrolling || map.onScroll) _handleEvent('', pageEventInfo, pageEvent, skipShowDescription, synthetic); if (scrolling) { var wasHandled = currentEvent.originalEvent.handled; var currentScrollTop = $(window).scrollTop(); if(map.onScrollUp && currentScrollTop < lastScrollTop) { currentEvent.originalEvent.handled = false; _handleEvent('', pageEventInfo, map.onScrollUp, skipShowDescription, synthetic); } else if (map.onScrollDown && currentScrollTop > lastScrollTop) { currentEvent.originalEvent.handled = false; _handleEvent('', pageEventInfo, map.onScrollDown, skipShowDescription, synthetic); } currentEvent.originalEvent.handled |= wasHandled; lastScrollTop = currentScrollTop; } } } if (searchFilter.indexOf($ax.constants.PAGE_TYPE) != -1) fireEventThroughContainers(eventName, $ax.pageData.page.diagram.objects, synthetic, searchFilter, callFilter); return; } if(!path) path = []; var pathCopy = []; for(var j = 0; j < path.length; j++) pathCopy[j] = path[j]; for(var i = 0; i < objects.length; i++) { var obj = objects[i]; pathCopy[path.length] = obj.id; 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)) { if(_callFilterCheck(callFilter)) { //fire current event for all types if ($ax.public.fn.IsTable(obj.type) || $ax.public.fn.IsMenuObject(obj.type) || $ax.public.fn.IsTreeNodeObject(obj.type)) { _fireEventsForTableMenuAndTree(obj, eventName, skipShowDescription, undefined, path, !synthetic); } else { var scriptId = $ax.getScriptIdFromPath(pathCopy); if(scriptId && itemId) scriptId = $ax.repeater.createElementId(scriptId, itemId); $ax.event.raiseSyntheticEvent(scriptId, eventName, skipShowDescription, undefined, !synthetic); } } continue; } var objId = $ax.getScriptIdFromPath(pathCopy); // If limboed, move on to next item if(!objId) continue; if(itemId) objId = $ax.repeater.createElementId(objId, itemId); if($ax.public.fn.IsReferenceDiagramObject(obj.type)) { if(_callFilterCheck(callFilter, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE)) { var axEvent = $ax.pageData.masters[obj.masterId].interactionMap[eventName]; if(axEvent) { var eventInfo = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), skipShowDescription, objId); eventInfo.isMasterEvent = true; _handleEvent(objId, eventInfo, axEvent, skipShowDescription, synthetic); } } if(searchFilter.indexOf($ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE) != -1) fireEventThroughContainers(eventName, $ax.pageData.masters[obj.masterId].diagram.objects, synthetic, searchFilter, callFilter, pathCopy, itemId); } else if($ax.public.fn.IsDynamicPanel(obj.type)) { if(_callFilterCheck(callFilter, $ax.constants.DYNAMIC_PANEL_TYPE)) $ax.event.raiseSyntheticEvent(objId, eventName, skipShowDescription, undefined, !synthetic); if(searchFilter.indexOf($ax.constants.DYNAMIC_PANEL_TYPE) != -1) { var diagrams = obj.diagrams; for(var j = 0; j < diagrams.length; j++) { fireEventThroughContainers(eventName, diagrams[j].objects, synthetic, searchFilter, callFilter, path, itemId); } } } else if($ax.public.fn.IsRepeater(obj.type)) { // TODO: possible an option for repeater item? Now fires overall for the repeater if(_callFilterCheck(callFilter, $ax.constants.REPEATER)) $ax.event.raiseSyntheticEvent(objId, eventName, skipShowDescription, undefined, !synthetic); if(searchFilter.indexOf($ax.constants.REPEATER) != -1) { var itemIds = $ax.getItemIdsForRepeater(objId); for(var j = 0; j < itemIds.length; j++) { fireEventThroughContainers(eventName, obj.objects, synthetic, searchFilter, callFilter, path, itemIds[j]); } } } else if($ax.public.fn.IsLayer(obj.type)) { if(_callFilterCheck(callFilter, $ax.constants.LAYER_TYPE)) $ax.event.raiseSyntheticEvent(objId, eventName, skipShowDescription, undefined, !synthetic); } } eventNesting -= 1; }; var _callFilterCheck = function(callFilter, type) { for(var index = 0; index < callFilter.length; index++) { var currentType = callFilter[index]; if(currentType === $ax.constants.ALL_TYPE || currentType === type) return true; } return false; }; // FOCUS stuff (function() { })(); var _pageLoad = function() { // Map of axure event names to pair of what it should attach to, and what the jquery event name is. var PAGE_AXURE_TO_JQUERY_EVENT_NAMES = { 'onScroll': [window, 'scroll'], 'onScrollUp': [window, 'scrollup'], 'onScrollDown': [window, 'scrolldown'], //'onResize': [window, 'resize'], 'onContextMenu': [window, 'contextmenu'] }; var $win = $(window); if(!$ax.features.supports.mobile) { PAGE_AXURE_TO_JQUERY_EVENT_NAMES.onClick = ['html', 'click']; PAGE_AXURE_TO_JQUERY_EVENT_NAMES.onDoubleClick = ['html', 'dblclick']; PAGE_AXURE_TO_JQUERY_EVENT_NAMES.onMouseMove = ['html', 'mousemove']; } else { _event.initMobileEvents($win, $win, ''); $win.bind($ax.features.eventNames.mouseDownName, _updateMouseLocation); $win.bind($ax.features.eventNames.mouseUpName, function(e) { _updateMouseLocation(e, true); }); $win.scroll(function() { _setCanClick(false); }); $win.bind($ax.features.eventNames.mouseDownName, (function() { _setCanClick(true); })); } $win.bind($ax.features.eventNames.mouseMoveName, _updateMouseLocation); $win.scroll($ax.flyoutManager.reregisterAllFlyouts); for(key in PAGE_AXURE_TO_JQUERY_EVENT_NAMES) { if(!PAGE_AXURE_TO_JQUERY_EVENT_NAMES.hasOwnProperty(key)) continue; (function(axureName) { var jqueryEventNamePair = PAGE_AXURE_TO_JQUERY_EVENT_NAMES[axureName]; var actionName = jqueryEventNamePair[1]; if(actionName == "scrollup" || actionName == "scrolldown") return; $(jqueryEventNamePair[0])[actionName](function (e) { $ax.setjBrowserEvent(e); return fireEventThroughContainers(axureName, undefined, false, [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE, $ax.constants.DYNAMIC_PANEL_TYPE, $ax.constants.REPEATER], [$ax.constants.PAGE_TYPE, $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE]); }); })(key); } eventNesting -= 1; lastScrollTop = 0; }; _event.pageLoad = _pageLoad; }); //***** recording.js *****// // ******* Recording MANAGER ******** // $axure.internal(function($ax) { var _recording = $ax.recording = {}; $ax.recording.recordEvent = function(element, eventInfo, axEventObject, timeStamp) { var elementHtml = $jobj(element); var className = elementHtml.attr('class'); var inputValue; if(className === 'ax_checkbox') { inputValue = elementHtml.find('#' + element + '_input')[0].checked; eventInfo.inputType = className; eventInfo.inputValue = inputValue; } if(className === 'ax_text_field') { inputValue = elementHtml.find('#' + element + '_input').val(); eventInfo.inputType = className; eventInfo.inputValue = inputValue; } var scriptId = $ax.repeater.getScriptIdFromElementId(element); var diagramObjectPath = $ax.getPathFromScriptId(scriptId); var form = { recordingId: $ax.recording.recordingId, elementID: element, eventType: axEventObject.description, 'eventInfo': eventInfo, // eventObject: axEventObject, 'timeStamp': timeStamp, 'path': diagramObjectPath // , // 'trigger': function() { // $ax.event.handleEvent(element, eventInfo, axEventObject); // return false; // } }; $ax.messageCenter.postMessage('logEvent', form); }; $ax.recording.maybeRecordEvent = function(element, eventInfo, axEventObject, timeStamp) { }; $ax.recording.recordingId = ""; $ax.recording.recordingName = ""; $ax.messageCenter.addMessageListener(function(message, data) { if(message === 'startRecording') { $ax.recording.maybeRecordEvent = $ax.recording.recordEvent; $ax.recording.recordingId = data.recordingId; $ax.recording.recordingName = data.recordingName; } else if(message === 'stopRecording') { $ax.recording.maybeRecordEvent = function(element, eventInfo, axEventObject, timeStamp) { }; } else if(message === 'playEvent') { var eventType = makeFirstLetterLower(data.eventType); var inputElement; var dObj = data.element === '' ? $ax.pageData.page : $ax.getObjectFromElementId(data.element); if(!data.axEventObject) { data.axEventObject = dObj && dObj.interactionMap && dObj.interactionMap[eventType]; } data.eventInfo.thiswidget = $ax.getWidgetInfo(data.element); data.eventInfo.item = $ax.getItemInfo(data.element); if(data.eventInfo.inputType && data.eventInfo.inputType === 'ax_checkbox') { inputElement = $jobj(data.element + '_input'); inputElement[0].checked = data.eventInfo.inputValue; } if(data.eventInfo.inputType && data.eventInfo.inputType === 'ax_text_field') { inputElement = $jobj(data.element + '_input'); inputElement.val(data.eventInfo.inputValue); } $ax.event.handleEvent(data.element, data.eventInfo, data.axEventObject, false, true); } }); var makeFirstLetterLower = function(eventName) { return eventName.substr(0, 1).toLowerCase() + eventName.substr(1); }; }); //***** action.js *****// $axure.internal(function($ax) { var _actionHandlers = {}; var _action = $ax.action = {}; var queueTypes = _action.queueTypes = { none: 0, move: 1, setState: 2, fade: 3, resize: 4, rotate: 5 }; var animationQueue = {}; // using array as the key doesn't play nice var nextAnimationId = 1; var animationsToCount = {}; var actionToActionGroups = {}; var getAnimation = function(id, type) { return animationQueue[id] && animationQueue[id][type] && animationQueue[id][type][0]; }; var _addAnimation = _action.addAnimation = function (id, type, func, suppressFire) { var wasEmpty = !getAnimation(id, type); // Add the func to the queue. Create the queue if necessary. var idQueue = animationQueue[id]; if(!idQueue) animationQueue[id] = idQueue = {}; var queue = idQueue[type]; if(!queue) idQueue[type] = queue = []; queue[queue.length] = func; // If it was empty, there isn't a callback waiting to be called on this. You have to fire it manually. // If this is waiting on something, suppress it, and it will fire when it's ready if(wasEmpty && !suppressFire) func(); }; var _addAnimations = function (animations) { if(animations.length == 1) { _addAnimation(animations[0].id, animations[0].type, animations[0].func); return; } var allReady = true; var readyCount = 0; for(var i = 0; i < animations.length; i++) { var animation = animations[i]; var thisReady = !getAnimation(animation.id, animation.type); allReady = allReady && thisReady; if (thisReady) readyCount++; else { var typeToGroups = actionToActionGroups[animation.id]; if (!typeToGroups) actionToActionGroups[animation.id] = typeToGroups = {}; var groups = typeToGroups[animation.type]; if (!groups) typeToGroups[animation.type] = groups = []; groups[groups.length] = animations; } } for(i = 0; i < animations.length; i++) { animation = animations[i]; _addAnimation(animation.id, animation.type, animation.func, true); } if (allReady) { for (i = 0; i < animations.length; i++) animations[i].func(); } else { animations.id = nextAnimationId++; animationsToCount[animations.id] = readyCount; } } var _fireAnimationFromQueue = _action.fireAnimationFromQueue = function (id, type) { // Remove the function that was just fired if (animationQueue[id] && animationQueue[id][type]) $ax.splice(animationQueue[id][type], 0, 1); // Fire the next func if there is one var func = getAnimation(id, type); if(func && !_checkFireActionGroup(id, type, func)) func(); }; var _checkFireActionGroup = function(id, type, func) { var group = actionToActionGroups[id]; group = group && group[type]; if (!group || group.length == 0) return false; var animations = group[0]; var found = false; for (var i = 0; i < animations.length; i++) { var animation = animations[i]; if (animation.id == id && animation.type == type) { found = func == animation.func; break; } } // if found then update this action group, otherwise, keep waiting for right action to fire if(!found) return false; $ax.splice(group, 0, 1); var count = animationsToCount[animations.id] + 1; if(count != animations.length) { animationsToCount[animations.id] = count; return true; } delete animationsToCount[animations.id]; // Funcs is needed because an earlier func can try to cascade right away (when no animation for example) and will kill this func and move on to the // next one (which may not even exist). If we get all funcs before calling any, then we know they are all the func we want. var funcs = []; for(i = 0; i < animations.length; i++) { animation = animations[i]; funcs.push(getAnimation(animation.id, animation.type)); } for(i = 0; i < funcs.length; i++) { funcs[i](); } return true; } var _refreshing = []; _action.refreshStart = function(repeaterId) { _refreshing.push(repeaterId); }; _action.refreshEnd = function() { _refreshing.pop(); }; // TODO: [ben] Consider moving this to repeater.js var _repeatersToRefresh = _action.repeatersToRefresh = []; var _ignoreAction = function(repeaterId) { for(var i = 0; i < _refreshing.length; i++) if(_refreshing[i] == repeaterId) return true; return false; }; var _addRefresh = function(repeaterId) { if(_repeatersToRefresh.indexOf(repeaterId) == -1) _repeatersToRefresh.push(repeaterId); }; var _getIdToResizeMoveState = function(eventInfo) { if(!eventInfo.idToResizeMoveState) eventInfo.idToResizeMoveState = {}; return eventInfo.idToResizeMoveState; } var _queueResizeMove = function (id, type, eventInfo, actionInfo) { if (type == queueTypes.resize || type == queueTypes.rotate) $ax.public.fn.convertToSingleImage($jobj(id)); var idToResizeMoveState = _getIdToResizeMoveState(eventInfo); if(!idToResizeMoveState[id]) { idToResizeMoveState[id] = {}; idToResizeMoveState[id][queueTypes.move] = { queue: [], used: 0 }; idToResizeMoveState[id][queueTypes.resize] = { queue: [], used: 0 }; idToResizeMoveState[id][queueTypes.rotate] = { queue: [], used: 0 }; } var state = idToResizeMoveState[id]; // If this is not a type being queued (no action of it's type waiting already) then if it is an instant, fire right away. var myOptions = type == queueTypes.resize ? actionInfo : actionInfo.options; if(!state[type].queue.length && (!myOptions.easing || myOptions.easing == 'none' || !myOptions.duration)) { var func = type == queueTypes.resize ? _addResize : type == queueTypes.rotate ? _addRotate : _addMove; func(id, eventInfo, actionInfo, { easing: 'none', duration: 0, stop: { instant: true } }); return; } // Check other 2 types to see if either is empty, if so, we can't do anything, so just queue it up var otherType1 = type == queueTypes.move ? queueTypes.resize : queueTypes.move; var otherType2 = type == queueTypes.rotate ? queueTypes.resize : queueTypes.rotate; if (!state[otherType1].queue.length || !state[otherType2].queue.length) { state[type].queue.push({ eventInfo: eventInfo, actionInfo: actionInfo }); } else { var duration = myOptions.duration; var used1 = state[otherType1].used; var used2 = state[otherType2].used; while(state[otherType1].queue.length && state[otherType2].queue.length && duration != 0) { var other1 = state[otherType1].queue[0]; var otherOptions1 = otherType1 == queueTypes.resize ? other1.actionInfo : other1.actionInfo.options; // If queue up action is a non animation, then don't combo it, just queue it and move on if(!otherOptions1.easing || otherOptions1.easing == 'none' || !otherOptions1.duration) { func = otherType1 == queueTypes.resize ? _addResize : otherType1 == queueTypes.rotate ? _addRotate : _addMove; func(id, eventInfo, actionInfo, { easing: 'none', duration: 0, stop: { instant: true } }); continue; } var other2 = state[otherType2].queue[0]; var otherOptions2 = otherType2 == queueTypes.resize ? other2.actionInfo : other2.actionInfo.options; // If queue up action is a non animation, then don't combo it, just queue it and move on if(!otherOptions2.easing || otherOptions2.easing == 'none' || !otherOptions2.duration) { func = otherType2 == queueTypes.resize ? _addResize : otherType2 == queueTypes.rotate ? _addRotate : _addMove; func(id, eventInfo, actionInfo, { easing: 'none', duration: 0, stop: { instant: true } }); continue; } // Other duration is what is left over. When in queue it may be partly finished already var otherDuration1 = otherOptions1.duration - used1; var otherDuration2 = otherOptions2.duration - used2; var resizeInfo = type == queueTypes.resize ? actionInfo : otherType1 == queueTypes.resize ? other1.actionInfo : other2.actionInfo; var rotateInfo = type == queueTypes.rotate ? actionInfo : otherType1 == queueTypes.rotate ? other1.actionInfo : other2.actionInfo; var moveInfo = type == queueTypes.move ? actionInfo : otherType1 == queueTypes.move ? other1.actionInfo : other2.actionInfo; var options = { easing: moveInfo.options.easing, duration: Math.min(duration, otherDuration1, otherDuration2) }; // Start for self is whole duration - duration left, end is start plus duration of combo to be queued, length is duration var stop = { start: myOptions.duration - duration, len: myOptions.duration }; stop.end = stop.start + options.duration; // Start for other is used (will be 0 after 1st round), end is start plus length is duration of combo to be queued, length is other duration var otherStop1 = { start: used1, end: options.duration + used1, len: otherOptions1.duration }; var otherStop2 = { start: used2, end: options.duration + used2, len: otherOptions2.duration }; options.stop = type == queueTypes.resize ? stop : otherType1 == queueTypes.resize ? otherStop1 : otherStop2; options.moveStop = type == queueTypes.move ? stop : otherType1 == queueTypes.move ? otherStop1 : otherStop2; options.rotateStop = type == queueTypes.rotate ? stop : otherType1 == queueTypes.rotate ? otherStop1 : otherStop2; _addResize(id, eventInfo, resizeInfo, options, moveInfo, rotateInfo); // Update duration for this animation duration -= options.duration; // For others update used and remove from queue if necessary if(otherDuration1 == options.duration) { $ax.splice(state[otherType1].queue, 0, 1); used1 = 0; } else used1 += options.duration; if(otherDuration2 == options.duration) { $ax.splice(state[otherType2].queue, 0, 1); used2 = 0; } else used2 += options.duration; } // Start queue for new type if necessary if(duration) { state[type].queue.push({ eventInfo: eventInfo, actionInfo: actionInfo }); state[type].used = myOptions.duration - duration; } // Update used for others state[otherType1].used = used1; state[otherType2].used = used2; } }; _action.flushAllResizeMoveActions = function (eventInfo) { var idToResizeMoveState = _getIdToResizeMoveState(eventInfo); for(var id in idToResizeMoveState) _flushResizeMoveActions(id, idToResizeMoveState); }; var _flushResizeMoveActions = function(id, idToResizeMoveState) { var state = idToResizeMoveState[id]; var move = state[queueTypes.move]; var moveInfo = move.queue[0]; var resize = state[queueTypes.resize]; var resizeInfo = resize.queue[0]; var rotate = state[queueTypes.rotate]; var rotateInfo = rotate.queue[0]; while (moveInfo || resizeInfo || rotateInfo) { var eventInfo = moveInfo ? moveInfo.eventInfo : resizeInfo ? resizeInfo.eventInfo : rotateInfo.eventInfo; moveInfo = moveInfo && moveInfo.actionInfo; resizeInfo = resizeInfo && resizeInfo.actionInfo; rotateInfo = rotateInfo && rotateInfo.actionInfo; // Resize is used by default, then rotate if(resizeInfo) { // Check for instant resize if(!resizeInfo.duration || resizeInfo.easing == 'none') { _addResize(id, resize.queue[0].eventInfo, resizeInfo, { easing: 'none', duration: 0, stop: { instant: true } }); _updateResizeMoveUsed(id, queueTypes.resize, 0, idToResizeMoveState); resizeInfo = resize.queue[0]; continue; } var duration = resizeInfo.duration - resize.used; if(moveInfo) duration = Math.min(duration, moveInfo.options.duration - move.used); if(rotateInfo) duration = Math.min(duration, rotateInfo.options.duration - rotate.used); var baseOptions = moveInfo ? moveInfo.options : resizeInfo; var options = { easing: baseOptions.easing, duration: duration }; options.stop = { start: resize.used, end: resize.used + duration, len: resizeInfo.duration }; if(moveInfo) options.moveStop = { start: move.used, end: move.used + duration, len: moveInfo.options.duration }; if(rotateInfo) options.rotateStop = { start: rotate.used, end: rotate.used + duration, len: rotateInfo.options.duration }; _addResize(id, eventInfo, resizeInfo, options, moveInfo, rotateInfo); _updateResizeMoveUsed(id, queueTypes.resize, duration, idToResizeMoveState); resizeInfo = resize.queue[0]; if(rotateInfo) { _updateResizeMoveUsed(id, queueTypes.rotate, duration, idToResizeMoveState); rotateInfo = rotate.queue[0]; } if(moveInfo) { _updateResizeMoveUsed(id, queueTypes.move, duration, idToResizeMoveState); moveInfo = move.queue[0]; } } else if (rotateInfo) { // Check for instant rotate if(!rotateInfo.options.duration || rotateInfo.options.easing == 'none') { _addRotate(id, rotate.queue[0].eventInfo, rotateInfo, { easing: 'none', duration: 0, stop: { instant: true } }); _updateResizeMoveUsed(id, queueTypes.rotate, 0, idToResizeMoveState); rotateInfo = rotate.queue[0]; continue; } duration = rotateInfo.options.duration - rotate.used; if(moveInfo) duration = Math.min(duration, moveInfo.options.duration - move.used); baseOptions = moveInfo ? moveInfo.options : rotateInfo.options; options = { easing: baseOptions.easing, duration: duration }; options.stop = { start: rotate.used, end: rotate.used + duration, len: rotateInfo.options.duration }; if(moveInfo) options.moveStop = { start: move.used, end: move.used + duration, len: moveInfo.options.duration }; _addRotate(id, eventInfo, rotateInfo, options, moveInfo); _updateResizeMoveUsed(id, queueTypes.rotate, duration, idToResizeMoveState); rotateInfo = rotate.queue[0]; if(moveInfo) { _updateResizeMoveUsed(id, queueTypes.move, duration, idToResizeMoveState); moveInfo = move.queue[0]; } } else { if(!moveInfo.options.duration || moveInfo.options.easing == 'none') { _addMove(id, eventInfo, moveInfo, { easing: 'none', duration: 0, stop: { instant: true } }); _updateResizeMoveUsed(id, queueTypes.move, 0, idToResizeMoveState); moveInfo = move.queue[0]; continue; } duration = moveInfo.options.duration - move.used; options = { easing: moveInfo.options.easing, duration: duration }; options.stop = { start: move.used, end: moveInfo.options.duration, len: moveInfo.options.duration }; _addMove(id, eventInfo, moveInfo, options); _updateResizeMoveUsed(id, queueTypes.move, duration, idToResizeMoveState); moveInfo = move.queue[0]; } } }; var _updateResizeMoveUsed = function(id, type, duration, idToResizeMoveState) { var state = idToResizeMoveState[id][type]; state.used += duration; var options = state.queue[0].actionInfo; if(options.options) options = options.options; var optionDur = (options.easing && options.easing != 'none' && options.duration) || 0; if(optionDur <= state.used) { $ax.splice(state.queue, 0, 1); state.used = 0; } } var _dispatchAction = $ax.action.dispatchAction = function(eventInfo, actions, currentIndex) { currentIndex = currentIndex || 0; //If no actions, you can bubble if(currentIndex >= actions.length) return; //actions are responsible for doing their own dispatching _actionHandlers[actions[currentIndex].action](eventInfo, actions, currentIndex); }; _actionHandlers.wait = function(eventInfo, actions, index) { var action = actions[index]; var infoCopy = $ax.eventCopy(eventInfo); window.setTimeout(function() { infoCopy.now = new Date(); infoCopy.idToResizeMoveState = undefined; _dispatchAction(infoCopy, actions, index + 1); _action.flushAllResizeMoveActions(infoCopy); }, action.waitTime); }; _actionHandlers.expr = function(eventInfo, actions, index) { var action = actions[index]; $ax.expr.evaluateExpr(action.expr, eventInfo); //this should be a block _dispatchAction(eventInfo, actions, index + 1); }; _actionHandlers.setFunction = _actionHandlers.expr; _actionHandlers.linkWindow = function(eventInfo, actions, index) { linkActionHelper(eventInfo, actions, index); }; _actionHandlers.closeCurrent = function(eventInfo, actions, index) { $ax.closeWindow(); _dispatchAction(eventInfo, actions, index + 1); }; _actionHandlers.linkFrame = function(eventInfo, actions, index) { linkActionHelper(eventInfo, actions, index); }; _actionHandlers.setAdaptiveView = function(eventInfo, actions, index) { var action = actions[index]; var view = action.setAdaptiveViewTo; if(view) $ax.adaptive.setAdaptiveView(view); }; var linkActionHelper = function(eventInfo, actions, index) { var action = actions[index]; eventInfo.link = true; if(action.linkType != 'frame') { var includeVars = _includeVars(action.target, eventInfo); if(action.target.targetType == "reloadPage") { $ax.reload(action.target.includeVariables); } else if(action.target.targetType == "backUrl") { $ax.back(); } var url = action.target.url; if(!url && action.target.urlLiteral) { url = $ax.expr.evaluateExpr(action.target.urlLiteral, eventInfo, true); } if(url) { if(action.linkType == "popup") { $ax.navigate({ url: url, target: action.linkType, includeVariables: includeVars, popupOptions: action.popup }); } else { $ax.navigate({ url: url, target: action.linkType, includeVariables: includeVars }); } } } else linkFrame(eventInfo, action); eventInfo.link = false; _dispatchAction(eventInfo, actions, index + 1); }; var _includeVars = function(target, eventInfo) { if(target.includeVariables) return true; // If it is a url literal, that is a string literal, that has only 1 sto, that is an item that is a page, include vars. if(target.urlLiteral) { var literal = target.urlLiteral; var sto = literal.stos[0]; if(literal.exprType == 'stringLiteral' && literal.value.indexOf('[[') == 0 && literal.value.indexOf(']]' == literal.value.length - 2) && literal.stos.length == 1 && sto.sto == 'item' && eventInfo.item) { var data = $ax.repeater.getData(eventInfo, eventInfo.item.repeater.elementId, eventInfo.item.index, sto.name, 'data'); if (data && $ax.public.fn.IsPage(data.type)) return true; } } return false; }; var linkFrame = function(eventInfo, action) { for(var i = 0; i < action.framesToTargets.length; i++) { var framePath = action.framesToTargets[i].framePath; var target = action.framesToTargets[i].target; var includeVars = _includeVars(target, eventInfo); var url = target.url; if(!url && target.urlLiteral) { url = $ax.expr.evaluateExpr(target.urlLiteral, eventInfo, true); } var id = $ax.getElementIdsFromPath(framePath, eventInfo)[0]; if(id) $ax('#' + $ax.INPUT(id)).openLink(url, includeVars); } }; var _repeatPanelMap = {}; _actionHandlers.setPanelState = function(eventInfo, actions, index) { var action = actions[index]; for(var i = 0; i < action.panelsToStates.length; i++) { var panelToState = action.panelsToStates[i]; var stateInfo = panelToState.stateInfo; var elementIds = $ax.getElementIdsFromPath(panelToState.panelPath, eventInfo); for(var j = 0; j < elementIds.length; j++) { var elementId = elementIds[j]; // Need new scope for elementId and info (function(elementId, stateInfo) { _addAnimation(elementId, queueTypes.setState, function() { var stateNumber = stateInfo.stateNumber; if(stateInfo.setStateType == "value") { var oldTarget = eventInfo.targetElement; eventInfo.targetElement = elementId; var stateName = $ax.expr.evaluateExpr(stateInfo.stateValue, eventInfo); eventInfo.targetElement = oldTarget; // Try for state name first var states = $ax.getObjectFromElementId(elementId).diagrams; var stateNameFound = false; for(var k = 0; k < states.length; k++) { if(states[k].label == stateName) { stateNumber = k + 1; stateNameFound = true; } } // Now check for index if(!stateNameFound) { stateNumber = Number(stateName); var panelCount = $('#' + elementId).children().length; // Make sure number is not NaN, is in range, and is a whole number. // Wasn't a state name or number, so return if(isNaN(stateNumber) || stateNumber <= 0 || stateNumber > panelCount || Math.round(stateNumber) != stateNumber) return _fireAnimationFromQueue(elementId, queueTypes.setState); } } else if(stateInfo.setStateType == 'next' || stateInfo.setStateType == 'previous') { var info = $ax.deepCopy(stateInfo); var repeat = info.repeat; // Only map it, if repeat exists. if(typeof (repeat) == 'number') _repeatPanelMap[elementId] = info; return _progessPanelState(elementId, info, info.repeatSkipFirst); } delete _repeatPanelMap[elementId]; // If setting to current (to stop repeat) break here if(stateInfo.setStateType == 'current') return _fireAnimationFromQueue(elementId, queueTypes.setState); $ax('#' + elementId).SetPanelState(stateNumber, stateInfo.options, stateInfo.showWhenSet); }); })(elementId, stateInfo); } } _dispatchAction(eventInfo, actions, index + 1); }; var _progessPanelState = function(id, info, skipFirst) { var direction = info.setStateType; var loop = info.loop; var repeat = info.repeat; var options = info.options; var hasRepeat = typeof (repeat) == 'number'; var currentStateId = $ax.visibility.GetPanelState(id); var stateNumber = ''; if(currentStateId != '') { currentStateId = $ax.repeater.getScriptIdFromElementId(currentStateId); var currentStateNumber = Number(currentStateId.substr(currentStateId.indexOf('state') + 5)); if(direction == "next") { stateNumber = currentStateNumber + 2; if(stateNumber > $ax.visibility.GetPanelStateCount(id)) { if(loop) stateNumber = 1; else { delete _repeatPanelMap[id]; return _fireAnimationFromQueue(id, queueTypes.setState); } } } else if(direction == "previous") { stateNumber = currentStateNumber; if(stateNumber <= 0) { if(loop) stateNumber = $ax.visibility.GetPanelStateCount(id); else { delete _repeatPanelMap[id]; return _fireAnimationFromQueue(id, queueTypes.setState); } } } if(hasRepeat && _repeatPanelMap[id] != info) return _fireAnimationFromQueue(id, queueTypes.setState); if (!skipFirst) $ax('#' + id).SetPanelState(stateNumber, options, info.showWhenSet); else _fireAnimationFromQueue(id, queueTypes.setState); if(hasRepeat) { var animate = options && options.animateIn; if(animate && animate.easing && animate.easing != 'none' && animate.duration > repeat) repeat = animate.duration; animate = options && options.animateOut; if(animate && animate.easing && animate.easing != 'none' && animate.duration > repeat) repeat = animate.duration; window.setTimeout(function() { // Either new repeat, or no repeat anymore. if(_repeatPanelMap[id] != info) return; _addAnimation(id, queueTypes.setState, function() { _progessPanelState(id, info, false); }); }, repeat); } else delete _repeatPanelMap[id]; } }; _actionHandlers.fadeWidget = function(eventInfo, actions, index) { var action = actions[index]; for(var i = 0; i < action.objectsToFades.length; i++) { var fadeInfo = action.objectsToFades[i].fadeInfo; var elementIds = $ax.getElementIdsFromPath(action.objectsToFades[i].objectPath, eventInfo); for(var j = 0; j < elementIds.length; j++) { var elementId = elementIds[j]; // Need new scope for elementId and info (function(elementId, fadeInfo) { _addAnimation(elementId, queueTypes.fade, function() { if(fadeInfo.fadeType == "hide") { $ax('#' + elementId).hide(fadeInfo.options); } else if(fadeInfo.fadeType == "show") { $ax('#' + elementId).show(fadeInfo.options, eventInfo); } else if(fadeInfo.fadeType == "toggle") { $ax('#' + elementId).toggleVisibility(fadeInfo.options); } }); })(elementId, fadeInfo); } } _dispatchAction(eventInfo, actions, index + 1); }; _actionHandlers.setOpacity = function(eventInfo, actions, index) { var action = actions[index]; for(var i = 0; i < action.objectsToSetOpacity.length; i++) { var opacityInfo = action.objectsToSetOpacity[i].opacityInfo; var elementIds = $ax.getElementIdsFromPath(action.objectsToSetOpacity[i].objectPath, eventInfo); for(var j = 0; j < elementIds.length; j++) { var elementId = elementIds[j]; (function(elementId, opacityInfo) { _addAnimation(elementId, queueTypes.fade, function () { var oldTarget = eventInfo.targetElement; eventInfo.targetElement = elementId; var opacity = $ax.expr.evaluateExpr(opacityInfo.opacity, eventInfo); eventInfo.targetElement = oldTarget; opacity = Math.min(100, Math.max(0, opacity)); $ax('#' + elementId).setOpacity(opacity/100, opacityInfo.easing, opacityInfo.duration); }) })(elementId, opacityInfo); } } _dispatchAction(eventInfo, actions, index + 1); } _actionHandlers.moveWidget = function(eventInfo, actions, index) { var action = actions[index]; for(var i = 0; i < action.objectsToMoves.length; i++) { var moveInfo = action.objectsToMoves[i].moveInfo; var elementIds = $ax.getElementIdsFromPath(action.objectsToMoves[i].objectPath, eventInfo); for(var j = 0; j < elementIds.length; j++) { var elementId = elementIds[j]; _queueResizeMove(elementId, queueTypes.move, eventInfo, moveInfo); //_addMove(eventInfo, elementId, moveInfo, eventInfo.dragInfo); } } _dispatchAction(eventInfo, actions, index + 1); }; var _compoundChildrenShallow = function (id) { var deep = []; var children = $ax('#' + id).getChildren()[0].children; var piecePrefix = id + 'p'; for (var i = 0; i < children.length; i++) { if(children[i].substring(0, id.length + 1) == piecePrefix) { deep.push(children[i]); } } return deep; }; var _addMove = function (elementId, eventInfo, moveInfo, optionsOverride) { var eventInfoCopy = $ax.eventCopy(eventInfo); var idToResizeMoveState = _getIdToResizeMoveState(eventInfoCopy); eventInfoCopy.targetElement = elementId; var options = $ax.deepCopy(moveInfo.options); options.easing = optionsOverride.easing; options.duration = optionsOverride.duration; options.dragInfo = eventInfo.dragInfo; if($ax.public.fn.IsLayer($obj(elementId).type)) { var childrenIds = $ax.public.fn.getLayerChildrenDeep(elementId, true); if(childrenIds.length == 0) return; var animations = []; // Get move delta once, then apply to all children animations.push({ id: elementId, type: queueTypes.move, func: function() { var layerInfo = $ax.public.fn.getWidgetBoundingRect(elementId); var deltaLoc = _getMoveLoc(elementId, moveInfo, eventInfoCopy, optionsOverride.stop, idToResizeMoveState[elementId], options, layerInfo); // $ax.event.raiseSyntheticEvent(elementId, "onMove"); $ax.visibility.pushContainer(elementId, false); options.onComplete = function () { _fireAnimationFromQueue(elementId, queueTypes.move); $ax.visibility.popContainer(elementId, false); }; $ax('#' + elementId).moveBy(deltaLoc.x, deltaLoc.y, options); } }); //for(var i = 0; i < childrenIds.length; i++) { // (function(childId) { // animations.push({ // id: childId, // type: queueTypes.move, // func: function () { // // Nop, while trying to move as container // //$ax.event.raiseSyntheticEvent(childId, "onMove"); // //if($ax.public.fn.IsLayer($obj(childId).type)) _fireAnimationFromQueue(childId, queueTypes.move); // //else $ax('#' + childId).moveBy(deltaLoc.x, deltaLoc.y, moveInfo.options); // } // }); // })(childrenIds[i]); //} _addAnimations(animations); } else { _addAnimation(elementId, queueTypes.move, function() { var loc = _getMoveLoc(elementId, moveInfo, eventInfoCopy, optionsOverride.stop, idToResizeMoveState[elementId], options); // $ax.event.raiseSyntheticEvent(elementId, "onMove"); if(loc.moveTo) $ax('#' + elementId).moveTo(loc.x, loc.y, options); else $ax('#' + elementId).moveBy(loc.x, loc.y, options); }); } }; var _moveSingleWidget = function (elementId, delta, options, onComplete) { var fixedInfo = $ax.dynamicPanelManager.getFixedInfo(elementId); var xProp = 'left'; var xDiff = '+='; if(fixedInfo) { if(fixedInfo.horizontal == 'right') { xProp = 'right'; xDiff = '-='; } else if(fixedInfo.horizontal == 'center') { xProp = 'margin-left'; } } var yProp = 'top'; var yDiff = '+='; if(fixedInfo) { if(fixedInfo.vertical == 'bottom') { yProp = 'bottom'; yDiff = '-='; } else if(fixedInfo.vertical == 'middle') { yProp = 'margin-top'; } } var css = {}; css[xProp] = xDiff + delta.x; css[yProp] = yDiff + delta.y; var moveInfo = $ax.move.PrepareForMove(elementId, delta.x, delta.y,false, options); $jobj(elementId).animate(css, { duration: options.duration, easing: options.easing, queue: false, complete: function () { if(onComplete) onComplete(); if(moveInfo.rootLayer) $ax.visibility.popContainer(moveInfo.rootLayer, false); $ax.action.fireAnimationFromQueue(elementId, $ax.action.queueTypes.move); } }); } var _getMoveLoc = function (elementId, moveInfo, eventInfoCopy, stopInfo, comboState, options, layerInfo) { var moveTo = false; var moveWithThis = false; var xValue = 0; var yValue = 0; var moveResult = comboState.moveResult; var widgetDragInfo = eventInfoCopy.dragInfo; var jobj = $jobj(elementId); var startX; var startY; switch(moveInfo.moveType) { case "location": // toRatio is ignoring anything before start since that has already taken effect we just know whe have from start to len to finish // getting to the location we want to get to. var toRatio = stopInfo.instant ? 1 : (stopInfo.end - stopInfo.start) / (stopInfo.len - stopInfo.start); // If result already caluculated, don't recalculate again, other calculate and save if (moveResult) { xValue = moveResult.x; yValue = moveResult.y; } else { comboState.moveResult = moveResult = { x: $ax.expr.evaluateExpr(moveInfo.xValue, eventInfoCopy), y: $ax.expr.evaluateExpr(moveInfo.yValue, eventInfoCopy) }; xValue = moveResult.x; yValue = moveResult.y; } // If this is final stop for this move, then clear out the result so next move won't use it if(stopInfo.instant || stopInfo.end == stopInfo.len) comboState.moveResult = undefined; if (layerInfo) { startX = layerInfo.left; startY = layerInfo.top; //} else if ($ax.public.fn.isCompoundVectorHtml(jobj[0])) { // var dimensions = $ax.public.fn.compoundWidgetDimensions(jobj); // startX = dimensions.left; // startY = dimensions.top; } else { startX = $ax('#' + elementId).locRelativeIgnoreLayer(false); startY = $ax('#' + elementId).locRelativeIgnoreLayer(true); if(jobj.css('position') == 'fixed') { startX -= $(window).scrollLeft(); startY -= $(window).scrollTop(); } } xValue = xValue == '' ? 0 : (xValue - startX) * toRatio; yValue = yValue == '' ? 0 : (yValue - startY) * toRatio; break; case "delta": var ratio = stopInfo.instant ? 1 : (stopInfo.end - stopInfo.start) / stopInfo.len; // See case location above if(moveResult) { xValue = moveResult.x * ratio; yValue = moveResult.y * ratio; } else { comboState.moveResult = moveResult = { x: $ax.expr.evaluateExpr(moveInfo.xValue, eventInfoCopy), y: $ax.expr.evaluateExpr(moveInfo.yValue, eventInfoCopy) }; xValue = moveResult.x * ratio; yValue = moveResult.y * ratio; } if (stopInfo.instant || stopInfo.end == stopInfo.len) comboState.moveResult = undefined; break; case "drag": xValue = widgetDragInfo.xDelta; yValue = widgetDragInfo.yDelta; break; case "dragX": xValue = widgetDragInfo.xDelta; yValue = 0; break; case "dragY": xValue = 0; yValue = widgetDragInfo.yDelta; break; case "locationBeforeDrag": var location = widgetDragInfo.movedWidgets[eventInfoCopy.targetElement]; if (location) { var axObj = $ax('#' + eventInfoCopy.targetElement); xValue = location.x - axObj.left(); yValue = location.y - axObj.top(); } else { _fireAnimationFromQueue(eventInfoCopy.srcElement, queueTypes.move); return { x: 0, y: 0 }; } //moveTo = true; break; case "withThis": moveWithThis = true; var widgetMoveInfo = $ax.move.GetWidgetMoveInfo(); var srcElementId = $ax.getElementIdsFromEventAndScriptId(eventInfoCopy, eventInfoCopy.srcElement)[0]; var delta = widgetMoveInfo[srcElementId]; options.easing = delta.options.easing; options.duration = delta.options.duration; xValue = delta.x; yValue = delta.y; break; } if (options && options.boundaryExpr) { //$ax.public.fn.removeCompound(jobj); if(jobj.css('position') == 'fixed') { //swap page coordinates with fixed coordinates options.boundaryExpr.leftExpr.value = options.boundaryExpr.leftExpr.value.replace('.top', '.topfixed').replace('.left', '.leftfixed').replace('.bottom', '.bottomfixed').replace('.right', '.rightfixed'); options.boundaryExpr.leftExpr.stos[0].leftSTO.prop = options.boundaryExpr.leftExpr.stos[0].leftSTO.prop + 'fixed'; options.boundaryStos.boundaryScope.direcval0.value = options.boundaryStos.boundaryScope.direcval0.value.replace('.top', '.topfixed').replace('.left', '.leftfixed').replace('.bottom', '.bottomfixed').replace('.right', '.rightfixed'); options.boundaryStos.boundaryScope.direcval0.stos[0].leftSTO.prop = options.boundaryStos.boundaryScope.direcval0.stos[0].leftSTO.prop + 'fixed'; } if(moveWithThis && (xValue || yValue)) { _updateLeftExprVariable(options.boundaryExpr, xValue.toString(), yValue.toString()); } if(!$ax.expr.evaluateExpr(options.boundaryExpr, eventInfoCopy)) { var boundaryStoInfo = options.boundaryStos; if(boundaryStoInfo) { if(moveWithThis) { var stoScopes = boundaryStoInfo.boundaryScope; if(stoScopes) { for(var s in stoScopes) { var boundaryScope = stoScopes[s]; if(!boundaryScope.localVariables) continue; if(boundaryScope.localVariables.withx) boundaryScope.localVariables.withx.value = xValue.toString(); if(boundaryScope.localVariables.withy) boundaryScope.localVariables.withy.value = yValue.toString(); } } } if(layerInfo) { startX = layerInfo.left; startY = layerInfo.top; } else { startX = $ax('#' + elementId).locRelativeIgnoreLayer(false); startY = $ax('#' + elementId).locRelativeIgnoreLayer(true); if(jobj.css('position') == 'fixed') { startX -= $(window).scrollLeft(); startY -= $(window).scrollTop(); } } if(boundaryStoInfo.ySto) { var currentTop = layerInfo ? layerInfo.top : startY; var newTop = $ax.evaluateSTO(boundaryStoInfo.ySto, boundaryStoInfo.boundaryScope, eventInfoCopy); if(moveTo) yValue = newTop; else yValue = newTop - currentTop; } if(boundaryStoInfo.xSto) { var currentLeft = layerInfo ? layerInfo.left : startX; var newLeft = $ax.evaluateSTO(boundaryStoInfo.xSto, boundaryStoInfo.boundaryScope, eventInfoCopy); if(moveTo) xValue = newLeft; else xValue = newLeft - currentLeft; } } } //$ax.public.fn.restoreCompound(jobj); } return { x: Number(xValue), y: Number(yValue), moveTo: moveTo }; }; //we will have something like [[Target.right + withX]] for leftExpr, and this function set the value of withX var _updateLeftExprVariable = function (exprTree, xValue, yValue) { if(exprTree.leftExpr && !exprTree.leftExpr.op) { var localVars = exprTree.leftExpr.localVariables; if(localVars) { if(localVars.withx) localVars.withx.value = xValue; if(localVars.withy) localVars.withy.value = yValue; } } //traversal if(exprTree.op) { if(exprTree.leftExpr) _updateLeftExprVariable(exprTree.leftExpr, xValue, yValue); if(exprTree.rightExpr) _updateLeftExprVariable(exprTree.rightExpr, xValue, yValue); } } var widgetRotationFilter = [ $ax.constants.IMAGE_BOX_TYPE, $ax.constants.IMAGE_MAP_REGION_TYPE, $ax.constants.DYNAMIC_PANEL_TYPE, $ax.constants.VECTOR_SHAPE_TYPE, $ax.constants.VERTICAL_LINE_TYPE, $ax.constants.HORIZONTAL_LINE_TYPE ]; _actionHandlers.rotateWidget = function(eventInfo, actions, index) { var action = actions[index]; for(var i = 0; i < action.objectsToRotate.length; i++) { var rotateInfo = action.objectsToRotate[i].rotateInfo; var elementIds = $ax.getElementIdsFromPath(action.objectsToRotate[i].objectPath, eventInfo); for(var j = 0; j < elementIds.length; j++) { var elementId = elementIds[j]; _queueResizeMove(elementId, queueTypes.rotate, eventInfo, rotateInfo); } } _dispatchAction(eventInfo, actions, index + 1); }; var _addRotate = function (elementId, eventInfo, rotateInfo, options, moveInfo) { var idToResizeMoveState = _getIdToResizeMoveState(eventInfo); rotateInfo = $ax.deepCopy(rotateInfo); rotateInfo.options.easing = options.easing; rotateInfo.options.duration = options.duration; var eventInfoCopy = $ax.eventCopy(eventInfo); eventInfoCopy.targetElement = elementId; //calculate degree value at start of animation var rotateDegree; var offset = {}; var eval = function(boundingRect) { rotateDegree = parseFloat($ax.expr.evaluateExpr(rotateInfo.degree, eventInfoCopy)); offset.x = Number($ax.expr.evaluateExpr(rotateInfo.offsetX, eventInfoCopy)); offset.y = Number($ax.expr.evaluateExpr(rotateInfo.offsetY, eventInfoCopy)); if(!rotateInfo.options.clockwise) rotateDegree = -rotateDegree; _updateOffset(offset, rotateInfo.anchor, boundingRect); } if(moveInfo) { var moveOptions = { dragInfo: eventInfoCopy.dragInfo, duration: options.duration, easing: options.easing, boundaryExpr: moveInfo.options.boundaryExpr, boundaryStos: moveInfo.options.boundaryStos }; } var obj = $obj(elementId); if($ax.public.fn.IsLayer(obj.type)) { var childrenIds = $ax.public.fn.getLayerChildrenDeep(elementId, true, true); if(childrenIds.length == 0) return; var animations = []; //get center point of the group, and degree delta var centerPoint, degreeDelta, moveDelta; animations.push({ id: elementId, type: queueTypes.rotate, func: function () { var boundingRect = $axure.fn.getWidgetBoundingRect(elementId); eval(boundingRect); centerPoint = boundingRect.centerPoint; centerPoint.x += offset.x; centerPoint.y += offset.y; degreeDelta = _initRotateLayer(elementId, rotateInfo, rotateDegree, options, options.stop); _fireAnimationFromQueue(elementId, queueTypes.rotate); moveDelta = { x: 0, y: 0 }; if (moveInfo) { moveDelta = _getMoveLoc(elementId, moveInfo, eventInfoCopy, options.moveStop, idToResizeMoveState[elementId], moveOptions, boundingRect); if (moveDelta.moveTo) { moveDelta.x -= $ax.getNumFromPx($jobj(elementId).css('left')); moveDelta.y -= $ax.getNumFromPx($jobj(elementId).css('top')); } $ax.event.raiseSyntheticEvent(elementId, 'onMove'); } } }); for(var idIndex = 0; idIndex < childrenIds.length; idIndex++) { var childId = childrenIds[idIndex]; (function(id) { var childObj = $obj(id); var rotate = $.inArray(childObj.type, widgetRotationFilter) != -1; var isLayer = $ax.public.fn.IsLayer(childObj.type); animations.push({ id: id, type: queueTypes.rotate, func: function() { $ax.event.raiseSyntheticEvent(id, "onRotate"); if(isLayer) _fireAnimationFromQueue(id, queueTypes.rotate); else $ax('#' + id).circularMoveAndRotate(degreeDelta, options, centerPoint.x, centerPoint.y, rotate, moveDelta); } }); if(!isLayer) animations.push({ id: id, type: queueTypes.move, func: function() {} }); })(childId); } _addAnimations(animations); } else { animations = []; animations.push({ id: elementId, type: queueTypes.rotate, func: function () { var jobj = $jobj(elementId); var unrotatedDim = { width: $ax.getNumFromPx(jobj.css('width')), height: $ax.getNumFromPx(jobj.css('height')) }; eval(unrotatedDim); var delta = { x: 0, y: 0 }; if(moveInfo) { delta = _getMoveLoc(elementId, moveInfo, eventInfoCopy, options.moveStop, idToResizeMoveState[elementId], moveOptions); if(delta.moveTo) { delta.x -= $ax.getNumFromPx($jobj(elementId).css('left')); delta.y -= $ax.getNumFromPx($jobj(elementId).css('top')); } } $ax.event.raiseSyntheticEvent(elementId, 'onRotate'); if(offset.x == 0 && offset.y == 0) { _rotateSingle(elementId, rotateDegree, rotateInfo.rotateType == 'location', delta, options, options.stop); _fireAnimationFromQueue(elementId, queueTypes.move); if(moveInfo) $ax.event.raiseSyntheticEvent(elementId, 'onMove'); return; } _rotateSingleOffset(elementId, rotateDegree, rotateInfo.rotateType == 'location', delta, { x: offset.x, y: offset.y }, options, options.stop); if(moveInfo) $ax.event.raiseSyntheticEvent(elementId, 'onMove'); } }); animations.push({ id: elementId, type: queueTypes.move, func: function () { } }); _addAnimations(animations); } } var _updateOffset = function(offset, anchor, boundingRect) { if (anchor.indexOf('left') != -1) offset.x -= boundingRect.width / 2; if (anchor.indexOf('right') != -1) offset.x += boundingRect.width / 2; if (anchor.indexOf('top') != -1) offset.y -= boundingRect.height / 2; if (anchor.indexOf('bottom') != -1) offset.y += boundingRect.height / 2; } var _rotateSingle = function(elementId, rotateDegree, rotateTo, delta, options, stop) { var degreeDelta = _applyRotateStop(rotateDegree, $ax.move.getRotationDegree(elementId), rotateTo, stop); $ax('#' + elementId).rotate(degreeDelta, options.easing, options.duration, false, true); if(delta.x || delta.y) _moveSingleWidget(elementId, delta, options); }; var _rotateSingleOffset = function (elementId, rotateDegree, rotateTo, delta, offset, options, stop, resizeOffset) { var obj = $obj(elementId); var currRotation = $ax.move.getRotationDegree(elementId); // Need to fix offset. Want to to stay same place on widget after rotation, so need to take the offset and rotate it to where it should be. if(currRotation) { offset = $axure.fn.getPointAfterRotate(currRotation, offset, { x: 0, y: 0 }); } var degreeDelta = _applyRotateStop(rotateDegree, currRotation, rotateTo, stop); var widgetCenter = $axure.fn.getWidgetBoundingRect(elementId).centerPoint; var rotate = $.inArray(obj.type, widgetRotationFilter) != -1; $ax('#' + elementId).circularMoveAndRotate(degreeDelta, options, widgetCenter.x + offset.x, widgetCenter.y + offset.y, rotate, delta, resizeOffset); } var _applyRotateStop = function(rotateDegree, currRotation, to, stop) { var degreeDelta; var ratio; if(to) { degreeDelta = rotateDegree - currRotation; ratio = stop.instant ? 1 : (stop.end - stop.start) / (stop.len - stop.start); } else { degreeDelta = rotateDegree; ratio = stop.instant ? 1 : (stop.end - stop.start) / stop.len; } return degreeDelta * ratio; } var _initRotateLayer = function(elementId, rotateInfo, rotateDegree, options, stop) { var layerDegree = $jobj(elementId).data('layerDegree'); if (layerDegree === undefined) layerDegree = 0; else layerDegree = parseFloat(layerDegree); var to = rotateInfo.rotateType == 'location'; var newDegree = to ? rotateDegree : layerDegree + rotateDegree; var degreeDelta = newDegree - layerDegree; var ratio = stop.instant ? 1 : (stop.end - stop.start) / (stop.len - stop.start); degreeDelta *= ratio; $jobj(elementId).data('layerDegree', newDegree); $ax.event.raiseSyntheticEvent(elementId, "onRotate"); return degreeDelta; } _actionHandlers.setWidgetSize = function(eventInfo, actions, index) { var action = actions[index]; for(var i = 0; i < action.objectsToResize.length; i++) { var resizeInfo = action.objectsToResize[i].sizeInfo; var objPath = action.objectsToResize[i].objectPath; if(objPath == 'thisItem') { var thisId = eventInfo.srcElement; var repeaterId = $ax.getParentRepeaterFromElementId(thisId); var itemId = $ax.repeater.getItemIdFromElementId(thisId); var currSize = $ax.repeater.getItemSize(repeaterId, itemId); var newSize = _getSizeFromInfo(resizeInfo, eventInfo, currSize.width, currSize.height); $ax.repeater.setItemSize(repeaterId, itemId, newSize.width, newSize.height); continue; } var elementIds = $ax.getElementIdsFromPath(objPath, eventInfo); for(var j = 0; j < elementIds.length; j++) { var elementId = elementIds[j]; _queueResizeMove(elementId, queueTypes.resize, eventInfo, resizeInfo); //_addResize(elementId, resizeInfo); } } _dispatchAction(eventInfo, actions, index + 1); }; // Move info undefined unless this move/resize actions are being merged var _addResize = function(elementId, eventInfo, resizeInfo, options, moveInfo, rotateInfo) { var axObject = $obj(elementId); resizeInfo = $ax.deepCopy(resizeInfo); resizeInfo.easing = options.easing; resizeInfo.duration = options.duration; var eventInfoCopy = $ax.eventCopy(eventInfo); eventInfoCopy.targetElement = elementId; var moves = moveInfo || resizeInfo.anchor != "top left" || ($ax.public.fn.IsDynamicPanel(axObject.type) && ((axObject.fixedHorizontal && axObject.fixedHorizontal == 'center') || (axObject.fixedVertical && axObject.fixedVertical == 'middle'))) || (rotateInfo && (rotateInfo.offsetX || rotateInfo.offsetY)); if(moveInfo) { var moveOptions = { dragInfo: eventInfoCopy.dragInfo, duration: options.duration, easing: options.easing, boundaryExpr: moveInfo.options.boundaryExpr, boundaryStos: moveInfo.options.boundaryStos }; } var idToResizeMoveState = _getIdToResizeMoveState(eventInfoCopy); var animations = []; if($ax.public.fn.IsLayer(axObject.type)) { moves = true; // Assume widgets will move will layer, even though not all widgets may move var childrenIds = $ax.public.fn.getLayerChildrenDeep(elementId, true, true); if(childrenIds.length === 0) return; // Need to wait to calculate new size, until time to animate, but animates are in separate queues // best option seems to be to calculate in a "animate" for the layer itself and all children will use that. // May just have to be redundant if this doesn't work well. var boundingRect, widthChangedPercent, heightChangedPercent, unchanged, deltaLoc, degreeDelta, resizeOffset; animations.push({ id: elementId, type: queueTypes.resize, func: function () { $ax.visibility.pushContainer(elementId, false); boundingRect = $ax.public.fn.getWidgetBoundingRect(elementId); var size = _getSizeFromInfo(resizeInfo, eventInfoCopy, boundingRect.width, boundingRect.height, elementId); deltaLoc = { x: 0, y: 0 }; var stop = options.stop; var ratio = stop.instant ? 1 : (stop.end - stop.start) / (stop.len - stop.start); widthChangedPercent = Math.round(size.width - boundingRect.width) / boundingRect.width * ratio; heightChangedPercent = Math.round(size.height - boundingRect.height) / boundingRect.height * ratio; resizeOffset = _applyAnchorToResizeOffset(widthChangedPercent * boundingRect.width, heightChangedPercent * boundingRect.height, resizeInfo.anchor); if(stop.instant || stop.end == stop.len) idToResizeMoveState[elementId].resizeResult = undefined; unchanged = widthChangedPercent === 0 && heightChangedPercent === 0; $ax.event.raiseSyntheticEvent(elementId, 'onResize'); _fireAnimationFromQueue(elementId, queueTypes.resize); } }); if(moveInfo) animations.push({ id: elementId, type: queueTypes.move, func: function() { deltaLoc = _getMoveLoc(elementId, moveInfo, eventInfoCopy, options.moveStop, idToResizeMoveState[elementId], moveOptions, boundingRect); $ax.visibility.pushContainer(elementId, false); _fireAnimationFromQueue(elementId, queueTypes.move); $ax.event.raiseSyntheticEvent(elementId, 'onMove'); } }); if (rotateInfo) animations.push({ id: elementId, type: queueTypes.rotate, func: function () { resizeOffset = _applyAnchorToResizeOffset(widthChangedPercent * boundingRect.width, heightChangedPercent * boundingRect.height, resizeInfo.anchor); var rotateDegree = parseFloat($ax.expr.evaluateExpr(rotateInfo.degree, eventInfoCopy)); degreeDelta = _initRotateLayer(elementId, rotateInfo, rotateDegree, options, options.rotateStop); _fireAnimationFromQueue(elementId, queueTypes.rotate); $ax.event.raiseSyntheticEvent(elementId, 'onRotate'); } }); var completeCount = childrenIds.length*2; // Because there is a resize and move complete, it needs to be doubled for(var idIndex = 0; idIndex < childrenIds.length; idIndex++) { // Need to use scoping trick here to make sure childId doesn't change on next loop (function(childId) { //use ax obj to get width and height, jquery css give us the value without border var isLayer = $ax.public.fn.IsLayer($obj(childId).type); var rotate = $.inArray($obj(childId).type, widgetRotationFilter) != -1; animations.push({ id: childId, type: queueTypes.resize, func: function() { //$ax.event.raiseSyntheticEvent(childId, 'onResize'); if(isLayer) { completeCount -= 2; _fireAnimationFromQueue(childId, queueTypes.resize); $ax.event.raiseSyntheticEvent(childId, 'onResize'); } else { var currDeltaLoc = { x: deltaLoc.x, y: deltaLoc.y }; var resizeDeltaMove = { x: 0, y: 0 }; var css = _getCssForResizingLayerChild(childId, resizeInfo.anchor, boundingRect, widthChangedPercent, heightChangedPercent, resizeDeltaMove); var onComplete = function() { if(--completeCount == 0) $ax.visibility.popContainer(elementId, false); }; $ax('#' + childId).resize(css, resizeInfo, true, moves, onComplete); if(rotateInfo) { var offset = { x: Number($ax.expr.evaluateExpr(rotateInfo.offsetX, eventInfoCopy)), y: Number($ax.expr.evaluateExpr(rotateInfo.offsetY, eventInfo)) }; _updateOffset(offset, resizeInfo.anchor, boundingRect); var centerPoint = { x: boundingRect.centerPoint.x + offset.x, y: boundingRect.centerPoint.y + offset.y }; $ax('#' + childId).circularMoveAndRotate(degreeDelta, options, centerPoint.x, centerPoint.y, rotate, currDeltaLoc, resizeOffset, resizeDeltaMove, onComplete); } else { currDeltaLoc.x += resizeDeltaMove.x; currDeltaLoc.y += resizeDeltaMove.y; _moveSingleWidget(childId, currDeltaLoc, options, onComplete); } } } }); if(!isLayer && moves) animations.push({ id: childId, type: queueTypes.move, func: function () {} }); if(!isLayer && rotateInfo) animations.push({ id: childId, type: queueTypes.rotate, func: function () {} }); })(childrenIds[idIndex]); } } else { // Not func, obj with func animations.push({ id: elementId, type: queueTypes.resize, func: function() { //textarea can be resized manully by the user, but doesn't update div size yet, so doing this for now. //alternatively axquery get for size can account for this var sizeId = $ax.public.fn.IsTextArea(axObject.type) ? $jobj(elementId).children('textarea').attr('id') : elementId; var oldSize = $ax('#' + sizeId).size(); var oldWidth = oldSize.width; var oldHeight = oldSize.height; var stop = options.stop; var ratio = stop.instant ? 1 : (stop.end - stop.start) / (stop.len - stop.start); var size = _getSizeFromInfo(resizeInfo, eventInfoCopy, oldWidth, oldHeight, elementId); var newWidth = size.width; var newHeight = size.height; var deltaWidth = Math.round(newWidth - oldWidth) * ratio; var deltaHeight = Math.round(newHeight - oldHeight) * ratio; newWidth = oldWidth + deltaWidth; newHeight = oldHeight + deltaHeight; var delta = { x: 0, y: 0 }; if(moveInfo) { delta = _getMoveLoc(elementId, moveInfo, eventInfoCopy, options.moveStop, idToResizeMoveState[elementId], moveOptions); if (delta.moveTo) { delta.x -= $ax.getNumFromPx($jobj(elementId).css('left')); delta.y -= $ax.getNumFromPx($jobj(elementId).css('top')); } } var rotateHandlesMove = false; var offset = { x: 0, y: 0 }; if(rotateInfo) { offset.x = Number($ax.expr.evaluateExpr(rotateInfo.offsetX, eventInfoCopy)); offset.y = Number($ax.expr.evaluateExpr(rotateInfo.offsetY, eventInfoCopy)); _updateOffset(offset, rotateInfo.anchor, $axure.fn.getWidgetBoundingRect(elementId)); rotateHandlesMove = Boolean(rotateInfo && (offset.x || offset.y || rotateInfo.anchor != 'center')); $ax.event.raiseSyntheticEvent(elementId, 'onRotate'); } var css = null; var rootLayer = null; if(deltaHeight != 0 || deltaWidth != 0) { rootLayer = $ax.move.getRootLayer(elementId); if(rootLayer) $ax.visibility.pushContainer(rootLayer, false); css = _getCssForResizingWidget(elementId, eventInfoCopy, resizeInfo.anchor, newWidth, newHeight, oldWidth, oldHeight, delta, options.stop, !rotateHandlesMove); idToResizeMoveState[elementId].resizeResult = undefined; } if(rotateInfo) { var rotateDegree = parseFloat($ax.expr.evaluateExpr(rotateInfo.degree, eventInfoCopy)); if(rotateHandlesMove) { var resizeOffset = _applyAnchorToResizeOffset(deltaWidth, deltaHeight, rotateInfo.anchor); _rotateSingleOffset(elementId, rotateDegree, rotateInfo.rotateType == 'location', delta, offset, options, options.rotateStop, resizeOffset); } else { // Not handling move so pass in nop delta _rotateSingle(elementId, rotateDegree, rotateInfo.rotateType == 'location', { x: 0, y: 0 }, options, options.rotateStop); } } else _moveSingleWidget(elementId, delta, options); // Have to do it down here to make sure move info is registered if(moveInfo) $ax.event.raiseSyntheticEvent(elementId, 'onMove'); //$ax.event.raiseSyntheticEvent(elementId, 'onResize'); if (css) { $ax('#' + elementId).resize(css, resizeInfo, true, moves, function () { if(rootLayer) $ax.visibility.popContainer(rootLayer, false); }); } else { _fireAnimationFromQueue(elementId, queueTypes.resize); if(moves && !rotateHandlesMove) _fireAnimationFromQueue(elementId, queueTypes.move); $ax.event.raiseSyntheticEvent(elementId, 'onResize'); } } }); // Nop move (move handled by resize) if(rotateInfo) animations.push({ id: elementId, type: queueTypes.rotate, func: function () { } }); if(moves) animations.push({ id: elementId, type: queueTypes.move, func: function () { } }); } _addAnimations(animations); }; var _applyAnchorToResizeOffset = function (deltaWidth, deltaHeight, anchor) { var offset = {}; if (anchor.indexOf('left') != -1) offset.x = -deltaWidth / 2; else if (anchor.indexOf('right') != -1) offset.x = deltaWidth / 2; if (anchor.indexOf('top') != -1) offset.y = -deltaHeight / 2; else if (anchor.indexOf('bottom') != -1) offset.y = deltaHeight / 2; return offset; } //var _getOldAndNewSize = function (resizeInfo, eventInfo, targetElement) { // var axObject = $obj(targetElement); // var oldWidth, oldHeight; // //textarea can be resized manully by the user, use the textarea child to get the current size // //because this new size may not be reflected on its parents yet // if ($ax.public.fn.IsTextArea(axObject.type)) { // var jObject = $jobj(elementId); // var textObj = $ax('#' + jObject.children('textarea').attr('id')); // //maybe we shouldn't use ax obj to get width and height here anymore... // oldWidth = textObj.width(); // oldHeight = textObj.height(); // } else { // oldWidth = $ax('#' + elementId).width(); // oldHeight = $ax('#' + elementId).height(); // } // var size = _getSizeFromInfo(resizeInfo, eventInfo, oldHeight, oldWidth, elementId); // return { oldWidth: oldWidth, oldHeight: oldHeight, newWidth: size.width, newHeight: size.height, change: oldWidth != size.width || oldHeight != size.height }; //} var _getSizeFromInfo = function(resizeInfo, eventInfo, oldWidth, oldHeight, targetElement) { var oldTarget = eventInfo.targetElement; eventInfo.targetElement = targetElement; var state = _getIdToResizeMoveState(eventInfo)[targetElement]; if(state && state.resizeResult) return state.resizeResult; var width = $ax.expr.evaluateExpr(resizeInfo.width, eventInfo); var height = $ax.expr.evaluateExpr(resizeInfo.height, eventInfo); eventInfo.targetElement = oldTarget; // If either one is not a number, use the old value width = width != "" ? Number(width) : oldWidth; height = height != "" ? Number(height) : oldHeight; width = isNaN(width) ? oldWidth : width; height = isNaN(height) ? oldHeight : height; // can't be negative var result = { width: Math.max(width, 0), height: Math.max(height, 0) }; if(state) state.resizeResult = result; return result; } //var _queueResize = function (elementId, css, resizeInfo) { // var resizeFunc = function() { // $ax('#' + elementId).resize(css, resizeInfo, true); // //$ax.public.fn.resize(elementId, css, resizeInfo, true); // }; // var obj = $obj(elementId); // var moves = resizeInfo.anchor != "top left" || ($ax.public.fn.IsDynamicPanel(obj.type) && ((obj.fixedHorizontal && obj.fixedHorizontal == 'center') || (obj.fixedVertical && obj.fixedVertical == 'middle'))) // if(!moves) { // _addAnimation(elementId, queueTypes.resize, resizeFunc); // } else { // var animations = []; // animations[0] = { id: elementId, type: queueTypes.resize, func: resizeFunc }; // animations[1] = { id: elementId, type: queueTypes.move, func: function() {}}; // Nop func - resize handles move and firing from queue // _addAnimations(animations); // } //}; //should clean this function and var _getCssForResizingWidget = function (elementId, eventInfo, anchor, newWidth, newHeight, oldWidth, oldHeight, delta, stop, handleMove) { var ratio = stop.instant ? 1 : (stop.end - stop.start) / (stop.len - stop.start); var deltaWidth = (newWidth - oldWidth) * ratio; var deltaHeight = (newHeight - oldHeight) * ratio; if(stop.instant || stop.end == stop.len) { var idToResizeMoveState = _getIdToResizeMoveState(eventInfo); if(idToResizeMoveState[elementId]) idToResizeMoveState[elementId].resizeResult = undefined; } var css = {}; css.height = oldHeight + deltaHeight; var obj = $obj(elementId); //if it's 100% width, don't change its width if($ax.dynamicPanelManager.isPercentWidthPanel(obj)) var is100Dp = true; else css.width = oldWidth + deltaWidth; var jobj = $jobj(elementId); //if this is pinned dp, we will mantain the pin, no matter how you resize it; so no need changes left or top //NOTE: currently only pinned DP has position == fixed if(jobj.css('position') == 'fixed') return css; //use position relative to parents //var position = obj.generateCompound ? $ax.public.fn.getWidgetBoundingRect(elementId) : $ax.public.fn.getPositionRelativeToParent(elementId); var locationShift; switch(anchor) { case "top left": locationShift = { x: 0, y: 0 }; break; case "top": locationShift = { x: -deltaWidth / 2.0, y: 0.0 }; break; case "top right": locationShift = { x: -deltaWidth, y: 0.0 }; break; case "left": locationShift = { x: 0.0, y: -deltaHeight / 2.0 }; break; case "center": locationShift = { x: -deltaWidth / 2.0, y: -deltaHeight / 2.0 }; break; case "right": locationShift = { x: -deltaWidth, y: -deltaHeight / 2.0 }; break; case "bottom left": locationShift = { x: 0.0, y: -deltaHeight }; break; case "bottom": locationShift = { x: -deltaWidth/2.0, y: -deltaHeight }; break; case "bottom right": locationShift = { x: -deltaWidth, y: -deltaHeight }; break; } if(handleMove) { if(jobj.css('position') === 'absolute') { css.left = $ax.getNumFromPx(jobj.css('left')) + locationShift.x + delta.x; css.top = $ax.getNumFromPx(jobj.css('top')) + locationShift.y + delta.y; } else { var axQuery = $ax('#' + elementId); css.left = axQuery.left(true) + locationShift.x + delta.x; css.top = axQuery.top(true) + locationShift.y + delta.y; } } else { delta.x += locationShift.x; delta.y += locationShift.y; } return css; }; var _getCssForResizingLayerChild = function (elementId, anchor, layerBoundingRect, widthChangedPercent, heightChangedPercent, deltaLoc) { var boundingRect = $ax.public.fn.getWidgetBoundingRect(elementId); var childCenterPoint = boundingRect.centerPoint; var currentSize = $ax('#' + elementId).size(); var newWidth = currentSize.width + currentSize.width * widthChangedPercent; var newHeight = currentSize.height + currentSize.height * heightChangedPercent; var css = {}; css.height = newHeight; var obj = $obj(elementId); //if it's 100% width, don't change its width and left var changeLeft = true; if($ax.dynamicPanelManager.isPercentWidthPanel(obj)) changeLeft = false; else css.width = newWidth; var jobj = $jobj(elementId); //if this is pinned dp, we will mantain the pin, no matter how you resize it; so no need changes left or top //NOTE: currently only pinned DP has position == fixed if(jobj.css('position') == 'fixed') return css; //use bounding rect position relative to parents to calculate delta var axObj = $ax('#' + elementId); // This will be absolute world coordinates, but we want body coordinates. var currentLeft = axObj.locRelativeIgnoreLayer(false); var currentTop = axObj.locRelativeIgnoreLayer(true); if(anchor.indexOf("center") > -1) { var topDelta = (childCenterPoint.y - layerBoundingRect.centerPoint.y) * heightChangedPercent - currentSize.height * heightChangedPercent / 2; if(changeLeft) var leftDelta = (childCenterPoint.x - layerBoundingRect.centerPoint.x) * widthChangedPercent - currentSize.width * widthChangedPercent / 2; } else { if(anchor.indexOf("top") > -1) { topDelta = (currentTop - layerBoundingRect.top) * heightChangedPercent; } else if(anchor.indexOf("bottom") > -1) { topDelta = (currentTop - layerBoundingRect.bottom) * heightChangedPercent; } else { topDelta = (childCenterPoint.y - layerBoundingRect.centerPoint.y) * heightChangedPercent - currentSize.height * heightChangedPercent / 2; } if(changeLeft) { if(anchor.indexOf("left") > -1) { leftDelta = (currentLeft - layerBoundingRect.left) * widthChangedPercent; } else if(anchor.indexOf("right") > -1) { leftDelta = (currentLeft - layerBoundingRect.right) * widthChangedPercent; } else { leftDelta = (childCenterPoint.x - layerBoundingRect.centerPoint.x) * widthChangedPercent - currentSize.width * widthChangedPercent / 2; } } } if(topDelta) deltaLoc.y += topDelta; if(leftDelta && changeLeft) deltaLoc.x += leftDelta; return css; }; _actionHandlers.setPanelOrder = function(eventInfo, actions, index) { var action = actions[index]; for(var i = 0; i < action.panelPaths.length; i++) { var func = action.panelPaths[i].setOrderInfo.bringToFront ? 'bringToFront' : 'sendToBack'; var elementIds = $ax.getElementIdsFromPath(action.panelPaths[i].panelPath, eventInfo); for(var j = 0; j < elementIds.length; j++) $ax('#' + elementIds[j])[func](); } _dispatchAction(eventInfo, actions, index + 1); }; _actionHandlers.modifyDataSetEditItems = function(eventInfo, actions, index) { var action = actions[index]; var add = action.repeatersToAddTo; var repeaters = add || action.repeatersToRemoveFrom; var itemId; for(var i = 0; i < repeaters.length; i++) { var data = repeaters[i]; // Grab the first one because repeaters must have only element id, as they cannot be inside repeaters // or none if unplaced var id = $ax.getElementIdsFromPath(data.path, eventInfo)[0]; if(!id) continue; if(data.addType == 'this') { var scriptId = $ax.repeater.getScriptIdFromElementId(eventInfo.srcElement); itemId = $ax.repeater.getItemIdFromElementId(eventInfo.srcElement); var repeaterId = $ax.getParentRepeaterFromScriptId(scriptId); if(add) $ax.repeater.addEditItems(repeaterId, [itemId]); else $ax.repeater.removeEditItems(repeaterId, [itemId]); } else if(data.addType == 'all') { var allItems = $ax.repeater.getAllItemIds(id); if(add) $ax.repeater.addEditItems(id, allItems); else $ax.repeater.removeEditItems(id, allItems); } else { var oldTarget = eventInfo.targetElement; var itemIds = $ax.repeater.getAllItemIds(id); var itemIdsToAdd = []; for(var j = 0; j < itemIds.length; j++) { itemId = itemIds[j]; eventInfo.targetElement = $ax.repeater.createElementId(id, itemId); if($ax.expr.evaluateExpr(data.query, eventInfo) == "true") { itemIdsToAdd[itemIdsToAdd.length] = String(itemId); } eventInfo.targetElement = oldTarget; } if(add) $ax.repeater.addEditItems(id, itemIdsToAdd); else $ax.repeater.removeEditItems(id, itemIdsToAdd); } } _dispatchAction(eventInfo, actions, index + 1); }; _action.repeaterInfoNames = { addItemsToDataSet: 'dataSetsToAddTo', deleteItemsFromDataSet: 'dataSetItemsToRemove', updateItemsInDataSet: 'dataSetsToUpdate', addFilterToRepeater: 'repeatersToAddFilter', removeFilterFromRepeater: 'repeatersToRemoveFilter', addSortToRepeater: 'repeaterToAddSort', removeSortFromRepeater: 'repeaterToRemoveSort', setRepeaterToPage: 'repeatersToSetPage', setItemsPerRepeaterPage: 'repeatersToSetItemCount' }; _actionHandlers.addItemsToDataSet = function(eventInfo, actions, index) { var action = actions[index]; for(var i = 0; i < action.dataSetsToAddTo.length; i++) { var datasetInfo = action.dataSetsToAddTo[i]; // Grab the first one because repeaters must have only element id, as they cannot be inside repeaters // or none if unplaced var id = $ax.getElementIdsFromPath(datasetInfo.path, eventInfo)[0]; if(!id || _ignoreAction(id)) continue; var dataset = datasetInfo.data; for(var j = 0; j < dataset.length; j++) $ax.repeater.addItem(id, $ax.deepCopy(dataset[j]), eventInfo); if(dataset.length) _addRefresh(id); } _dispatchAction(eventInfo, actions, index + 1); }; _actionHandlers.deleteItemsFromDataSet = function(eventInfo, actions, index) { var action = actions[index]; for(var i = 0; i < action.dataSetItemsToRemove.length; i++) { // Grab the first one because repeaters must have only element id, as they cannot be inside repeaters // or none if unplaced var deleteInfo = action.dataSetItemsToRemove[i]; var id = $ax.getElementIdsFromPath(deleteInfo.path, eventInfo)[0]; if(!id || _ignoreAction(id)) continue; $ax.repeater.deleteItems(id, eventInfo, deleteInfo.type, deleteInfo.rule); _addRefresh(id); } _dispatchAction(eventInfo, actions, index + 1); }; _actionHandlers.updateItemsInDataSet = function(eventInfo, actions, index) { var action = actions[index]; for(var i = 0; i < action.dataSetsToUpdate.length; i++) { var dataSet = action.dataSetsToUpdate[i]; // Grab the first one because repeaters must have only element id, as they cannot be inside repeaters // or none if unplaced var id = $ax.getElementIdsFromPath(dataSet.path, eventInfo)[0]; if(!id || _ignoreAction(id)) continue; $ax.repeater.updateEditItems(id, dataSet.props, eventInfo, dataSet.type, dataSet.rule); _addRefresh(id); } _dispatchAction(eventInfo, actions, index + 1); }; _actionHandlers.setRepeaterToDataSet = function(eventInfo, actions, index) { var action = actions[index]; for(var i = 0; i < action.repeatersToSet.length; i++) { var setRepeaterInfo = action.repeatersToSet[i]; // Grab the first one because repeaters must have only element id, as they cannot be inside repeaters // or none if unplaced var id = $ax.getElementIdsFromPath(setRepeaterInfo.path, eventInfo)[0]; if(!id) continue; $ax.repeater.setDataSet(id, setRepeaterInfo.localDataSetId); } _dispatchAction(eventInfo, actions, index + 1); }; _actionHandlers.addFilterToRepeater = function(eventInfo, actions, index) { var action = actions[index]; for(var i = 0; i < action.repeatersToAddFilter.length; i++) { var addFilterInfo = action.repeatersToAddFilter[i]; // Grab the first one because repeaters must have only element id, as they cannot be inside repeaters // or none if unplaced var id = $ax.getElementIdsFromPath(addFilterInfo.path, eventInfo)[0]; if(!id || _ignoreAction(id)) continue; $ax.repeater.addFilter(id, addFilterInfo.removeOtherFilters, addFilterInfo.label, addFilterInfo.filter, eventInfo.srcElement); _addRefresh(id); } _dispatchAction(eventInfo, actions, index + 1); }; _actionHandlers.removeFilterFromRepeater = function(eventInfo, actions, index) { var action = actions[index]; for(var i = 0; i < action.repeatersToRemoveFilter.length; i++) { var removeFilterInfo = action.repeatersToRemoveFilter[i]; // Grab the first one because repeaters must have only element id, as they cannot be inside repeaters // or none if unplaced var id = $ax.getElementIdsFromPath(removeFilterInfo.path, eventInfo)[0]; if(!id || _ignoreAction(id)) continue; if(removeFilterInfo.removeAll) $ax.repeater.removeFilter(id); else if(removeFilterInfo.filterName != '') { $ax.repeater.removeFilter(id, removeFilterInfo.filterName); } _addRefresh(id); } _dispatchAction(eventInfo, actions, index + 1); }; _actionHandlers.addSortToRepeater = function(eventInfo, actions, index) { var action = actions[index]; for(var i = 0; i < action.repeatersToAddSort.length; i++) { var addSortInfo = action.repeatersToAddSort[i]; // Grab the first one because repeaters must have only element id, as they cannot be inside repeaters // or none if unplaced var id = $ax.getElementIdsFromPath(addSortInfo.path, eventInfo)[0]; if(!id || _ignoreAction(id)) continue; $ax.repeater.addSort(id, addSortInfo.label, addSortInfo.columnName, addSortInfo.ascending, addSortInfo.toggle, addSortInfo.sortType); _addRefresh(id); } _dispatchAction(eventInfo, actions, index + 1); }; _actionHandlers.removeSortFromRepeater = function(eventInfo, actions, index) { var action = actions[index]; for(var i = 0; i < action.repeatersToRemoveSort.length; i++) { var removeSortInfo = action.repeatersToRemoveSort[i]; // Grab the first one because repeaters must have only element id, as they cannot be inside repeaters // or none if unplaced var id = $ax.getElementIdsFromPath(removeSortInfo.path, eventInfo)[0]; if(!id || _ignoreAction(id)) continue; if(removeSortInfo.removeAll) $ax.repeater.removeSort(id); else if(removeSortInfo.sortName != '') $ax.repeater.removeSort(id, removeSortInfo.sortName); _addRefresh(id); } _dispatchAction(eventInfo, actions, index + 1); }; _actionHandlers.setRepeaterToPage = function(eventInfo, actions, index) { var action = actions[index]; for(var i = 0; i < action.repeatersToSetPage.length; i++) { var setPageInfo = action.repeatersToSetPage[i]; // Grab the first one because repeaters must have only element id, as they cannot be inside repeaters // or none if unplaced var id = $ax.getElementIdsFromPath(setPageInfo.path, eventInfo)[0]; if(!id || _ignoreAction(id)) continue; var oldTarget = eventInfo.targetElement; eventInfo.targetElement = id; $ax.repeater.setRepeaterToPage(id, setPageInfo.pageType, setPageInfo.pageValue, eventInfo); eventInfo.targetElement = oldTarget; _addRefresh(id); } _dispatchAction(eventInfo, actions, index + 1); }; _actionHandlers.setItemsPerRepeaterPage = function(eventInfo, actions, index) { var action = actions[index]; for(var i = 0; i < action.repeatersToSetItemCount.length; i++) { var setItemCountInfo = action.repeatersToSetItemCount[i]; // Grab the first one because repeaters must have only element id, as they cannot be inside repeaters // or none if unplaced var id = $ax.getElementIdsFromPath(setItemCountInfo.path, eventInfo)[0]; if(!id || _ignoreAction(id)) continue; if(setItemCountInfo.noLimit) $ax.repeater.setNoItemLimit(id); else $ax.repeater.setItemLimit(id, setItemCountInfo.itemCountValue, eventInfo); _addRefresh(id); } _dispatchAction(eventInfo, actions, index + 1); }; _actionHandlers.refreshRepeater = function(eventInfo, actions, index) { // We use this as a psudo action now. var action = actions[index]; for (var i = 0; i < action.repeatersToRefresh.length; i++) { // Grab the first one because repeaters must have only element id, as they cannot be inside repeaters // or none if unplaced var id = $ax.getElementIdsFromPath(action.repeatersToRefresh[i], eventInfo)[0]; if(id) _tryRefreshRepeater(id, eventInfo); } _dispatchAction(eventInfo, actions, index + 1); }; var _tryRefreshRepeater = function(id, eventInfo) { var idIndex = _repeatersToRefresh.indexOf(id); if(idIndex == -1) return; $ax.splice(_repeatersToRefresh, idIndex, 1); $ax.repeater.refreshRepeater(id, eventInfo); }; _action.tryRefreshRepeaters = function(ids, eventInfo) { for(var i = 0; i < ids.length; i++) _tryRefreshRepeater(ids[i], eventInfo); }; _actionHandlers.scrollToWidget = function(eventInfo, actions, index) { var action = actions[index]; var elementIds = $ax.getElementIdsFromPath(action.objectPath, eventInfo); if(elementIds.length > 0) $ax('#' + elementIds[0]).scroll(action.options); _dispatchAction(eventInfo, actions, index + 1); }; _actionHandlers.enableDisableWidgets = function(eventInfo, actions, index) { var action = actions[index]; for(var i = 0; i < action.pathToInfo.length; i++) { var elementIds = $ax.getElementIdsFromPath(action.pathToInfo[i].objectPath, eventInfo); var enable = action.pathToInfo[i].enableDisableInfo.enable; for(var j = 0; j < elementIds.length; j++) $ax('#' + elementIds[j]).enabled(enable); } _dispatchAction(eventInfo, actions, index + 1); }; _actionHandlers.setImage = function(eventInfo, actions, index) { var oldTarget = eventInfo.targetElement; var action = actions[index]; var view = $ax.adaptive.currentViewId; eventInfo.image = true; for(var i = 0; i < action.imagesToSet.length; i++) { var imgInfo = action.imagesToSet[i]; imgInfo = view ? imgInfo.adaptive[view] : imgInfo.base; var elementIds = $ax.getElementIdsFromPath(action.imagesToSet[i].objectPath, eventInfo); for(var j = 0; j < elementIds.length; j++) { var elementId = elementIds[j]; eventInfo.targetElement = elementId; var evaluatedImgs = _evaluateImages(imgInfo, eventInfo); var img = evaluatedImgs.normal; if($ax.style.IsWidgetDisabled(elementId)) { if(imgInfo.disabled) img = evaluatedImgs.disabled; } else if($ax.style.IsWidgetSelected(elementId)) { if(imgInfo.selected) img = evaluatedImgs.selected; } else if($ax.event.mouseDownObjectId == elementId && imgInfo.mouseDown) img = evaluatedImgs.mouseDown; else if($ax.event.mouseOverIds.indexOf(elementId) != -1 && imgInfo.mouseOver) { img = evaluatedImgs.mouseOver; //Update mouseOverObjectId var currIndex = $ax.event.mouseOverIds.indexOf($ax.event.mouseOverObjectId); var imgIndex = $ax.event.mouseOverIds.indexOf(elementId); if(currIndex < imgIndex) $ax.event.mouseOverObjectId = elementId; } else if(imgInfo.mouseOver && elementId == eventInfo.srcElement) { img = evaluatedImgs.mouseOver; } // $('#' + $ax.repeater.applySuffixToElementId(elementId, '_img')).attr('src', img); $jobj($ax.style.GetImageIdFromShape(elementId)).attr('src', img); //Set up overrides $ax.style.mapElementIdToImageOverrides(elementId, evaluatedImgs); $ax.style.updateElementIdImageStyle(elementId); if(evaluatedImgs.mouseOver || evaluatedImgs.mouseDown) $ax.event.updateIxStyleEvents(elementId); } } eventInfo.targetElement = oldTarget; eventInfo.image = false; _dispatchAction(eventInfo, actions, index + 1); }; var _evaluateImages = function(imgInfo, eventInfo) { var retVal = {}; for(var state in imgInfo) { if(!imgInfo.hasOwnProperty(state)) continue; var img = imgInfo[state][$ax.adaptive.getSketchKey()] || $ax.expr.evaluateExpr(imgInfo[state].literal, eventInfo); if(!img) img = $axure.utils.getTransparentGifPath(); retVal[state] = img; } return retVal; }; $ax.clearRepeaterImageOverrides = function(repeaterId) { var childIds = $ax.getChildElementIdsForRepeater(repeaterId); for(var i = childIds; i < childIds.length; i++) $ax.style.deleteElementIdToImageOverride(childIds[i]); }; _actionHandlers.setFocusOnWidget = function(eventInfo, actions, index) { var action = actions[index]; if(action.objectPaths.length > 0) { var elementIds = $ax.getElementIdsFromPath(action.objectPaths[0], eventInfo); if(elementIds.length > 0) { $ax('#' + elementIds[0]).focus(); //if select text and not in placeholder mode, then select all text if(action.selectText && !$ax.placeholderManager.isActive(elementIds[0])) { var elementChildren = document.getElementById(elementIds[0]).children; //find the input or textarea element for(var i = 0; i < elementChildren.length; i++) { if (elementChildren[i].id.indexOf('_input') == -1) continue; var elementTagName = elementChildren[i].tagName; if(elementTagName && (elementTagName.toLowerCase() == "input" || elementTagName.toLowerCase() == "textarea")) { elementChildren[i].select(); } } } } } _dispatchAction(eventInfo, actions, index + 1); }; _actionHandlers.expandCollapseTree = function(eventInfo, actions, index) { var action = actions[index]; for(var i = 0; i < action.pathToInfo.length; i++) { var pair = action.pathToInfo[i]; var elementIds = $ax.getElementIdsFromPath(pair.treeNodePath, eventInfo); for(var j = 0; j < elementIds.length; j++) $ax('#' + elementIds[j]).expanded(pair.expandCollapseInfo.expand); } _dispatchAction(eventInfo, actions, index + 1); }; _actionHandlers.other = function(eventInfo, actions, index) { var action = actions[index]; $ax.navigate({ url: $axure.utils.getOtherPath() + "#other=" + encodeURI(action.otherDescription), target: "popup", includeVariables: false, popupOptions: action.popup }); _dispatchAction(eventInfo, actions, index + 1); }; _actionHandlers.fireEvents = function(eventInfo, actions, index) { var action = actions[index]; //look for the nearest element id var objId = eventInfo.srcElement; var thisWidget = eventInfo.thiswidget; var obj = $ax.getObjectFromElementId(objId); var rdoId = obj ? $ax.getRdoParentFromElementId(objId) : ""; var rdo = $ax.getObjectFromElementId(rdoId); var page = rdo ? $ax.pageData.masters[rdo.masterId] : $ax.pageData.page; // Check if rdo should be this var oldIsMasterEvent = eventInfo.isMasterEvent; if (obj && $ax.public.fn.IsReferenceDiagramObject(obj.type) && eventInfo.isMasterEvent) { rdoId = objId; rdo = obj; page = $ax.pageData.masters[rdo.masterId]; } for(var i = 0; i < action.firedEvents.length; i++) { var firedEvent = action.firedEvents[i]; var isPage = firedEvent.objectPath.length == 0; var targetObjIds = isPage ? [rdoId] : $ax.getElementIdsFromPath(firedEvent.objectPath, eventInfo); for (var j = 0; j < targetObjIds.length; j++) { var targetObjId = targetObjIds[j]; var targetObj = isPage ? rdo : $ax.getObjectFromElementId(targetObjId); eventInfo.srcElement = targetObjId || ''; eventInfo.thiswidget = $ax.getWidgetInfo(eventInfo.srcElement); eventInfo.isMasterEvent = false; var raisedEvents = firedEvent.raisedEventIds; if(raisedEvents) { for(var k = 0; k < raisedEvents.length; k++) { var event = targetObj.interactionMap && targetObj.interactionMap.raised && targetObj.interactionMap.raised[raisedEvents[k]]; if(event) $ax.event.handleEvent(targetObjId, eventInfo, event, false, true); } } if(isPage) { eventInfo.isMasterEvent = true; eventInfo.label = $ax.pageData.page.name; eventInfo.friendlyType = 'Page'; } var firedTarget = isPage ? page : targetObj; var firedEventNames = firedEvent.firedEventNames; if(firedEventNames) { for(k = 0; k < firedEventNames.length; k++) { event = firedTarget.interactionMap && firedTarget.interactionMap[firedEventNames[k]]; if(event) $ax.event.handleEvent(isPage ? '' : targetObjId, eventInfo, event, false, true); } } if(isPage) eventInfo.isMasterEvent = oldIsMasterEvent; } eventInfo.srcElement = objId; eventInfo.thiswidget = thisWidget; eventInfo.isMasterEvent = oldIsMasterEvent; } _dispatchAction(eventInfo, actions, index + 1); }; }); //***** expr.js *****// // ******* Expr MANAGER ******** // $axure.internal(function($ax) { var _expr = $ax.expr = {}; var _binOpHandlers = { '&&': function(left, right) { return _binOpOverride(left, right, function(left) { return $ax.getBool(left) && $ax.getBool(right()); }); }, '||': function(left, right) { return _binOpOverride(left, right, function(left) { return $ax.getBool(left) || $ax.getBool(right()); }); }, '==': function(left, right) { return isEqual(left, right, true); }, '!=': function(left, right) { return !isEqual(left, right, true); }, '>': function(left, right) { return _binOpNum(left, right, function(left, right) { return left > right; }); }, '<': function(left, right) { return _binOpNum(left, right, function(left, right) { return left < right; }); }, '>=': function(left, right) { return _binOpNum(left, right, function(left, right) { return left >= right; }); }, '<=': function(left, right) { return _binOpNum(left, right, function(left, right) { return left <= right; }); } }; var checkOps = function(left, right) { return left == undefined || right == undefined; }; var isEqual = function (left, right, isFunction) { if (isFunction) { //if left and right is function, then get the value //otherwise left and right should be already the value we want left = left(); right = right(); } if(checkOps(left, right)) return false; if(left instanceof Date && right instanceof Date) { if(left.getMilliseconds() != right.getMilliseconds()) return false; if(left.getSeconds() != right.getSeconds()) return false; if(left.getMinutes() != right.getMinutes()) return false; if(left.getHours() != right.getHours()) return false; if(left.getDate() != right.getDate()) return false; if(left.getMonth() != right.getMonth()) return false; if(left.getYear() != right.getYear()) return false; return true; } if(left instanceof Object && right instanceof Object) { var prop; // Go through all of lefts properties and compare them to rights. for(prop in left) { if(!left.hasOwnProperty(prop)) continue; // If left has a property that the right doesn't they are not equal. if(!right.hasOwnProperty(prop)) return false; // If any of their properties are not equal, they are not equal. if(!isEqual(left[prop], right[prop], false)) return false; } for(prop in right) { // final check to make sure right doesn't have some extra properties that make them not equal. if(left.hasOwnProperty(prop) != right.hasOwnProperty(prop)) return false; } return true; } return $ax.getBool(left) == $ax.getBool(right); }; var _binOpOverride = function(left, right, func) { left = left(); if(left == undefined) return false; var res = func(left, right); return res == undefined ? false : res; }; var _binOpNum = function(left, right, func) { var left = left(); var right = right(); if(checkOps(left, right)) return false; return func(left, Number(right)); }; var _exprHandlers = {}; _exprHandlers.array = function(expr, eventInfo) { var returnVal = []; for(var i = 0; i < expr.items.length; i++) { returnVal[returnVal.length] = _evaluateExpr(expr.items[i], eventInfo); } return returnVal; }; _exprHandlers.binaryOp = function(expr, eventInfo) { var left = function() { return expr.leftExpr && _evaluateExpr(expr.leftExpr, eventInfo); }; var right = function() { return expr.rightExpr && _evaluateExpr(expr.rightExpr, eventInfo); }; if(left == undefined || right == undefined) return false; return _binOpHandlers[expr.op](left, right); }; _exprHandlers.block = function(expr, eventInfo) { var subExprs = expr.subExprs; for(var i = 0; i < subExprs.length; i++) { _evaluateExpr(subExprs[i], eventInfo); //ignore the result } }; _exprHandlers.booleanLiteral = function(expr) { return expr.value; }; _exprHandlers.nullLiteral = function() { return null; }; _exprHandlers.pathLiteral = function(expr, eventInfo) { if(expr.isThis) return [eventInfo.srcElement]; if(expr.isFocused && window.lastFocusedControl) { $ax('#' + window.lastFocusedControl).focus(); return [window.lastFocusedControl]; } if(expr.isTarget) return [eventInfo.targetElement]; return $ax.getElementIdsFromPath(expr.value, eventInfo); }; _exprHandlers.panelDiagramLiteral = function(expr, eventInfo) { var elementIds = $ax.getElementIdsFromPath(expr.panelPath, eventInfo); var elementIdsWithSuffix = []; var suffix = '_state' + expr.panelIndex; for(var i = 0; i < elementIds.length; i++) { elementIdsWithSuffix[i] = $ax.repeater.applySuffixToElementId(elementIds[i], suffix); } return String($jobj(elementIdsWithSuffix).data('label')); }; _exprHandlers.fcall = function(expr, eventInfo) { var oldTarget = eventInfo.targetElement; var targets = []; var fcallArgs = []; var exprArgs = expr.arguments; for(var i = 0; i < expr.arguments.length; i++) { var exprArg = exprArgs[i]; var fcallArg = ''; if(targets.length) { for(var j = 0; j < targets.length; j++) { if(exprArg == null) { fcallArgs[j][i] = null; continue; } eventInfo.targetElement = targets[j]; fcallArg = _evaluateExpr(exprArg, eventInfo); if(typeof (fcallArg) == 'undefined') return ''; fcallArgs[j][i] = fcallArg; } } else { if(exprArg == null) { fcallArgs[i] = null; continue; } fcallArg = _evaluateExpr(exprArg, eventInfo); if(typeof (fcallArg) == 'undefined') return ''; fcallArgs[i] = fcallArg; } // We do support null exprArgs... // TODO: This makes 2 assumptions that may change in the future. 1. The pathLiteral is the always the first arg. 2. there is always only 1 pathLiteral if(exprArg && exprArg.exprType == 'pathLiteral') { targets = fcallArg; // fcallArgs is now an array of an array of args for(j = 0; j < targets.length; j++) fcallArgs[j] = [[fcallArg[j]]]; } } // we want to preserve the target element from outside this function. eventInfo.targetElement = oldTarget; var retval = ''; if(targets.length) { // Go backwards so retval is the first item. for(i = targets.length - 1; i >= 0; i--) { var args = fcallArgs[i]; // Add event info to the end args[args.length] = eventInfo; retval = _exprFunctions[expr.functionName].apply(this, args); } } else fcallArgs[fcallArgs.length] = eventInfo; return targets.length ? retval : _exprFunctions[expr.functionName].apply(this, fcallArgs); }; _exprHandlers.globalVariableLiteral = function(expr) { return expr.variableName; }; _exprHandlers.keyPressLiteral = function(expr) { var keyInfo = {}; keyInfo.keyCode = expr.keyCode; keyInfo.ctrl = expr.ctrl; keyInfo.alt = expr.alt; keyInfo.shift = expr.shift; return keyInfo; }; _exprHandlers.adaptiveViewLiteral = function(expr) { return expr.id; }; _exprHandlers.optionLiteral = function(expr) { return expr.value; } var _substituteSTOs = function(expr, eventInfo) { //first evaluate the local variables var scope = {}; for(var varName in expr.localVariables) { scope[varName] = $ax.expr.evaluateExpr(expr.localVariables[varName], eventInfo); } // TODO: [ben] Date and data object (obj with info for url or image) both need to return non-strings. var i = 0; var retval; var retvalString = expr.value.replace(/\[\[(?!\[)(.*?)\]\](?=\]*)/g, function(match) { var sto = expr.stos[i++]; if(sto.sto == 'error') return match; try { var result = $ax.evaluateSTO(sto, scope, eventInfo); } catch(e) { return match; } if((result instanceof Object) && i == 1 && expr.value.substring(0, 2) == '[[' && expr.value.substring(expr.value.length - 2) == ']]') { // If the result was an object, this was the first result, and the whole thing was this expresion. retval = result; } return ((result instanceof Object) && (result.label || result.text)) || result; }); // If more than one group returned, the object is not valid if(i != 1) retval = false; return retval || retvalString; }; _exprHandlers.htmlLiteral = function (expr, eventInfo) { eventInfo.htmlLiteral = true; var html = _substituteSTOs(expr, eventInfo); eventInfo.htmlLiteral = false return html; }; _exprHandlers.stringLiteral = function(expr, eventInfo) { return _substituteSTOs(expr, eventInfo); }; var _exprFunctions = {}; _exprFunctions.SetCheckState = function(elementIds, value) { var toggle = value == 'toggle'; var boolValue = Boolean(value) && value != 'false'; for(var i = 0; i < elementIds.length; i++) { var query = $ax('#' + elementIds[i]); query.selected(toggle ? !query.selected() : boolValue); } }; _exprFunctions.SetSelectedOption = function(elementIds, value) { for(var i = 0; i < elementIds.length; i++) { var elementId = elementIds[i]; var obj = $jobj($ax.INPUT(elementId)); if(obj.val() == value) return; obj.val(value); if($ax.event.HasSelectionChanged($ax.getObjectFromElementId(elementId))) $ax.event.raiseSyntheticEvent(elementId, 'onSelectionChange'); } }; _exprFunctions.SetGlobalVariableValue = function(varName, value) { $ax.globalVariableProvider.setVariableValue(varName, value); }; _exprFunctions.SetWidgetFormText = function(elementIds, value) { for(var i = 0; i < elementIds.length; i++) { var elementId = elementIds[i]; var inputId = $ax.repeater.applySuffixToElementId(elementId, '_input'); var obj = $jobj(inputId); if(obj.val() == value || (value == '' && $ax.placeholderManager.isActive(elementId))) return; obj.val(value); $ax.placeholderManager.updatePlaceholder(elementId, !value); if($ax.event.HasTextChanged($ax.getObjectFromElementId(elementId))) $ax.event.TryFireTextChanged(elementId); } }; _exprFunctions.SetFocusedWidgetText = function(elementId, value) { if(window.lastFocusedControl) { var elementId = window.lastFocusedControl; var type = $obj(elementId).type; if ($ax.public.fn.IsTextBox(type) || $ax.public.fn.IsTextArea(type)) _exprFunctions.SetWidgetFormText([elementId], value); else _exprFunctions.SetWidgetRichText([elementId], value, true); } }; _exprFunctions.GetRtfElementHeight = function(rtfElement) { if(rtfElement.innerHTML == '') rtfElement.innerHTML = ' '; return rtfElement.offsetHeight; }; _exprFunctions.SetWidgetRichText = function(ids, value, plain) { // Converts dates, widgetinfo, and the like to strings. value = _exprFunctions.ToString(value); //Replace any newlines with line breaks var finalValue = value.replace(/\r\n/g, '
').replace(/\n/g, '
'); for(var i = 0; i < ids.length; i++) { var id = ids[i]; // If calling this on button shape, get the id of the rich text panel inside instead var type = $obj(id).type; if(type != 'richTextPanel' && type != 'hyperlink') { id = $jobj(id).find('.text')[0].id; } var element = window.document.getElementById(id); $ax.visibility.SetVisible(element, value != ''); $ax.style.transformTextWithVerticalAlignment(id, function() { var spans = $jobj(id).find('span'); if(plain) { // Wrap in span and p, style them accordingly. var span = $(''); if(spans.length > 0) { span.attr('style', $(spans[0]).attr('style')); span.attr('id', $(spans[0]).attr('id')); } // Can't set value as text because '
' doesn't actually do a line break // Can't set vaule as html because it doesn't like '<' and ignores all after it // Create tags yourself var lines = value.split(/\r\n|\n/); if(lines.length == 1) span.text(value); else { for(var i = 0; i < lines.length; i++) { if (i != 0) span.append($('
')); var line = lines[i]; if(line.length == 0) continue; var subSpan = $(''); subSpan.text(line); span.append(subSpan); } } var p = $('

'); var ps = $jobj(id).find('p'); if(ps.length > 0) { p.attr('style', $(ps[0]).attr('style')); p.attr('id', $(ps[0]).attr('id')); } p.append(span); finalValue = $('
').append(p).html(); } element.innerHTML = finalValue; }); if(!plain) $ax.style.CacheOriginalText(id, true); } }; _exprFunctions.GetCheckState = function(ids) { return $ax('#' + ids[0]).selected(); }; _exprFunctions.GetSelectedOption = function (ids) { var inputs = $jobj($ax.INPUT(ids[0])); return inputs.length ? inputs[0].value : ''; }; _exprFunctions.GetNum = function(str) { //Setting a GlobalVariable to some blank text then setting a widget to the value of that variable would result in 0 not "" //I have fixed this another way so commenting this should be fine now //if (!str) return ""; return isNaN(str) ? str : Number(str); }; _exprFunctions.GetGlobalVariableValue = function(id) { return $ax.globalVariableProvider.getVariableValue(id); }; _exprFunctions.GetGlobalVariableLength = function(id) { return _exprFunctions.GetGlobalVariableValue(id).length; }; _exprFunctions.GetWidgetText = function(ids) { if($ax.placeholderManager.isActive(ids[0])) return ''; var input = $ax.INPUT(ids[0]); return $ax('#' + ($jobj(input).length ? input : ids[0])).text(); }; _exprFunctions.GetFocusedWidgetText = function() { if(window.lastFocusedControl) { return $ax('#' + window.lastFocusedControl).text(); } else { return ""; } }; _exprFunctions.GetWidgetValueLength = function(ids) { var id = ids[0]; if(!id) return undefined; if($ax.placeholderManager.isActive(id)) return 0; var obj = $jobj($ax.INPUT(id)); if(!obj.length) obj = $jobj(id); var val = obj[0].value || _exprFunctions.GetWidgetText([id]); return val.length; }; _exprFunctions.GetPanelState = function(ids) { var id = ids[0]; if(!id) return undefined; var stateId = $ax.visibility.GetPanelState(id); return stateId && String($jobj(stateId).data('label')); }; _exprFunctions.GetWidgetVisibility = function(ids) { var id = ids[0]; if(!id) return undefined; return $ax.visibility.IsIdVisible(id); }; // ***************** Validation Functions ***************** // _exprFunctions.IsValueAlpha = function(val) { var isAlphaRegex = new RegExp("^[a-z\\s]+$", "gi"); return isAlphaRegex.test(val); }; _exprFunctions.IsValueNumeric = function(val) { var isNumericRegex = new RegExp("^[0-9,\\.\\s]+$", "gi"); return isNumericRegex.test(val); }; _exprFunctions.IsValueAlphaNumeric = function(val) { var isAlphaNumericRegex = new RegExp("^[0-9a-z\\s]+$", "gi"); return isAlphaNumericRegex.test(val); }; _exprFunctions.IsValueOneOf = function(val, values) { for(var i = 0; i < values.length; i++) { var option = values[i]; if(val == option) return true; } //by default, return false return false; }; _exprFunctions.IsValueNotAlpha = function(val) { return !_exprFunctions.IsValueAlpha(val); }; _exprFunctions.IsValueNotNumeric = function(val) { return !_exprFunctions.IsValueNumeric(val); }; _exprFunctions.IsValueNotAlphaNumeric = function(val) { return !_exprFunctions.IsValueAlphaNumeric(val); }; _exprFunctions.IsValueNotOneOf = function(val, values) { return !_exprFunctions.IsValueOneOf(val, values); }; _exprFunctions.GetKeyPressed = function(eventInfo) { return eventInfo.keyInfo; }; _exprFunctions.GetCursorRectangles = function() { var rects = new Object(); rects.lastRect = new $ax.drag.Rectangle($ax.lastMouseLocation.x, $ax.lastMouseLocation.y, 1, 1); rects.currentRect = new $ax.drag.Rectangle($ax.mouseLocation.x, $ax.mouseLocation.y, 1, 1); return rects; }; _exprFunctions.GetWidgetRectangles = function (elementIds, eventInfo) { var elementId = elementIds[0]; var rects = new Object(); var jObj = $jobj(elementId); var invalid = jObj.length == 0; var parent = jObj; // Or are in valid if no obj can be found, or if it is not visible. while(parent.length != 0 && !parent.is('body')) { if(parent.css('display') == 'none') { invalid = true; break; } parent = parent.parent(); } if(invalid) { rects.lastRect = rects.currentRect = new $ax.drag.Rectangle(-1, -1, -1, -1); return rects; } var axObj = $ax('#' + elementId); rects.lastRect = new $ax.drag.Rectangle( axObj.left(), axObj.top(), axObj.width(), axObj.height()); rects.currentRect = rects.lastRect; return rects; }; _exprFunctions.GetWidget = function(elementId) { return $ax.getWidgetInfo(elementId[0]); }; _exprFunctions.GetAdaptiveView = function() { return $ax.adaptive.currentViewId || ''; }; _exprFunctions.IsEntering = function(movingRects, targetRects) { return !movingRects.lastRect.IntersectsWith(targetRects.currentRect) && movingRects.currentRect.IntersectsWith(targetRects.currentRect); }; _exprFunctions.IsLeaving = function(movingRects, targetRects) { return movingRects.lastRect.IntersectsWith(targetRects.currentRect) && !movingRects.currentRect.IntersectsWith(targetRects.currentRect); }; var _IsOver = _exprFunctions.IsOver = function(movingRects, targetRects) { return movingRects.currentRect.IntersectsWith(targetRects.currentRect); }; _exprFunctions.IsNotOver = function(movingRects, targetRects) { return !_IsOver(movingRects, targetRects); }; _exprFunctions.ValueContains = function(inputString, value) { return inputString.indexOf(value) > -1; }; _exprFunctions.ValueNotContains = function(inputString, value) { return !_exprFunctions.ValueContains(inputString, value); }; _exprFunctions.ToString = function(value) { if(value.isWidget) { return value.text; } return String(value); }; var _evaluateExpr = $ax.expr.evaluateExpr = function(expr, eventInfo, toString) { if(expr === undefined || expr === null) return undefined; var result = _exprHandlers[expr.exprType](expr, eventInfo); return toString ? _exprFunctions.ToString(result) : result; }; }); //***** geometry.js *****// // ******* Region MANAGER ******** // $axure.internal(function($ax) { var _geometry = $ax.geometry = {}; var regionMap = {}; var regionList = []; var _unregister = function(label) { var regionIndex = regionList.indexOf(label); if(regionIndex != -1) { var end = $ax.splice(regionList, regionIndex + 1); $ax.splice(regionList, regionIndex, regionList.length - regionIndex); regionList = regionList.concat(end); } delete regionMap[label]; }; _geometry.unregister = _unregister; var clear = function() { regionMap = {}; regionList = []; }; var _polygonRegistered = function(label) { return Boolean(regionMap[label]); }; _geometry.polygonRegistered = _polygonRegistered; // Must be counterclockwise, or enter/exit will be wrong var _registerPolygon = function(label, points, callback, info) { var regionIndex = regionList.indexOf(label); if(regionIndex == -1) regionList.push(label); regionMap[label] = { points: points, callback: callback, info: info }; }; _geometry.registerPolygon = _registerPolygon; var _getPolygonInfo = function(label) { if(!_polygonRegistered(label)) return undefined; return regionMap[label].info; }; _geometry.getPolygonInfo = _getPolygonInfo; var _genRect = function(info, roundHalfPixel) { var x = info.pagex; var y = info.pagey; var w = info.width; var h = info.height; if(roundHalfPixel) { if(x % 1 != 0) { x = Math.floor(x); w++; } if(y % 1 != 0) { y = Math.floor(y); h++; } } var r = x + w; var b = y + h; var rect = { X: function() { return x; }, Y: function() { return y; }, Wigth: function() { return w; }, Height: function() { return h; }, Left: function() { return x; }, Right: function() { return r; }, Top: function() { return y; }, Bottom: function() { return b; } }; return rect; }; _geometry.genRect = _genRect; var _genPoint = function(x, y) { return { x: x, y: y }; }; _geometry.genPoint = _genPoint; var oldPoint = _genPoint(0, 0); _geometry.tick = function(x, y, end) { var lastPoint = oldPoint; var nextPoint = oldPoint = _genPoint(x, y); var line = { p1: lastPoint, p2: nextPoint }; if(!regionList.length) return; for(var i = 0; i < regionList.length; i++) { var region = regionMap[regionList[i]]; var points = region.points; if(!region.checked) { if(!_checkInside(points, $ax.mouseLocation)) { region.callback({ outside: true }); continue; } region.checked = true; } for(var j = 0; j < points.length; j++) { var startSegment = points[j]; var endSegment = points[(j + 1) % points.length]; var intersectInfo = linesIntersect(line, { p1: startSegment, p2: endSegment }); if(intersectInfo) { region.callback(intersectInfo); break; } } } if(end) clear(); }; // Info if the one line touches the other (even barely), false otherwise // Info includes point, if l1 is entering or exiting l2, and any ties that happened, or parallel info var linesIntersect = function(l1, l2) { var retval = {}; var ties = {}; var l1p1 = l1.p1.x < l1.p2.x || (l1.p1.x == l1.p2.x && l1.p1.y < l1.p2.y) ? l1.p1 : l1.p2; var l1p2 = l1.p1.x < l1.p2.x || (l1.p1.x == l1.p2.x && l1.p1.y < l1.p2.y) ? l1.p2 : l1.p1; var m1 = (l1p2.y - l1p1.y) / (l1p2.x - l1p1.x); var l2p1 = l2.p1.x < l2.p2.x || (l2.p1.x == l2.p2.x && l2.p1.y < l2.p2.y) ? l2.p1 : l2.p2; var l2p2 = l2.p1.x < l2.p2.x || (l2.p1.x == l2.p2.x && l2.p1.y < l2.p2.y) ? l2.p2 : l2.p1; var m2 = (l2p2.y - l2p1.y) / (l2p2.x - l2p1.x); var l1Vert = l1.p1.x == l1.p2.x; var l2Vert = l2.p1.x == l2.p2.x; if(l1Vert || l2Vert) { if(l1Vert && l2Vert) { // If the lines don't follow the same path, return if(l1p1.x != l2p1.x) return false; // if they never meet, return if(l1p2.y < l2p1.y || l1p1.y > l2p2.y) return false; var firstVert = l1p1.y >= l2p1.y ? l1p1 : l2p1; var secondVert = l1p2.y <= l2p2.y ? l1p2 : l2p2; // First is from the perspective of l1 retval.parallel = { first: l1p1 == l1.p1 ? firstVert : secondVert, second: l1p2 == l1.p2 ? secondVert : firstVert, sameDirection: (l1p1 == l1.p1) == (l2p1 == l2.p1) }; return retval; } var x1 = l2Vert ? l1p1.x : l2p1.x; var x2 = l2Vert ? l1p2.x : l2p2.x; var xVert = l2Vert ? l2p1.x : l1p1.x; var y = l2Vert ? l1p1.y + (xVert - x1) * m1 : l2p1.y + (xVert - x1) * m2; var y1 = l2Vert ? l2p1.y : l1p1.y; var y2 = l2Vert ? l2p2.y : l1p2.y; if(xVert >= x1 && xVert <= x2 && y >= y1 && y <= y2) { retval.point = { x: xVert, y: y }; retval.exiting = l2Vert == (y1 == (l2Vert ? l2.p1.y : l1.p1.y)) == (x1 == (l2Vert ? l1.p1.x : l2.p1.x)); retval.entering = !retval.exiting; // Calculate ties if(x1 == xVert) { ties[l2Vert ? 'l1' : 'l2'] = (x1 == (l2Vert ? l1.p1.x : l2.p1.x)) ? 'start' : 'end'; retval.ties = ties; } else if(x2 == xVert) { ties[l2Vert ? 'l1' : 'l2'] = (x2 == (l2Vert ? l1.p2.x : l2.p2.x)) ? 'end' : 'start'; retval.ties = ties; } if(y1 == y) { ties[l2Vert ? 'l2' : 'l1'] = (y1 == (l2Vert ? l2.p1.y : l1.p1.y)) ? 'start' : 'end'; retval.ties = ties; } else if(y2 == y) { ties[l2Vert ? 'l2' : 'l1'] = (y2 == (l2Vert ? l2.p2.y : l1.p2.y)) ? 'end' : 'start'; retval.ties = ties; } return retval; } return false; } // If here, no vertical lines if(m1 == m2) { // If the lines don't follow the same path, return if(l1p1.y != (l2p1.y + (l1p1.x - l2p1.x) * m1)) return false; // if they never meet, return if(l1p2.x < l2p1.x || l1p1.x > l2p2.x) return false; var first = l1p1.x >= l2p1.x ? l1p1 : l2p1; var second = l1p2.x <= l2p2.x ? l1p2 : l2p2; // First is from the perspective of l1 retval.parallel = { first: l1p1 == l1.p1 ? first : second, second: l1p2 == l1.p2 ? second : first, sameDirection: (l1p1 == l1.p1) == (l2p1 == l2.p1) }; return retval; } var x = (l2p1.y - l2p1.x * m2 - l1p1.y + l1p1.x * m1) / (m1 - m2); // Check if x is out of bounds if(x >= l1p1.x && x <= l1p2.x && x >= l2p1.x && x <= l2p2.x) { var y = l1p1.y + (x - l1p1.x) * m1; retval.point = { x: x, y: y }; retval.entering = m1 > m2 == (l1p1 == l1.p1) == (l2p1 == l2.p1); retval.exiting = !retval.entering; // Calculate ties if(l1.p1.x == x) { ties.l1 = 'start'; retval.ties = ties; } else if(l1.p2.x == x) { ties.l1 = 'end'; retval.ties = ties; } if(l2.p1.x == x) { ties.l2 = 'start'; retval.ties = ties; } else if(l2.p2.x == x) { ties.l2 = 'end'; retval.ties = ties; } return retval; } return false; }; var _checkInsideRegion = function(label, point) { if(!_polygonRegistered(label)) return false; return _checkInside(regionMap[label].points, point || $ax.mouseLocation); }; _geometry.checkInsideRegion = _checkInsideRegion; // Returns true if point is inside the polygon, including ties var _checkInside = function(polygon, point) { // Make horizontal line wider than the polygon, with the y of point to test location var firstX = polygon[0].x; var secondX = firstX; var i; for(i = 1; i < polygon.length; i++) { var polyX = polygon[i].x; firstX = Math.min(firstX, polyX); secondX = Math.max(secondX, polyX); } var line = { p1: _genPoint(--firstX, point.y), p2: _genPoint(++secondX, point.y) }; // If entered true, with closest intersection says you are inside the polygon. var entered = false; // Closest is the closest intersection to the left of the point var closest = line.p1.x; // This is for if intersections hit the same point, to find out which is correct var cos = -2; var getCos = function(line) { var x = line.p2.x - line.p1.x; var y = line.p2.y - line.p1.y; return x / Math.sqrt(x * x + y * y); }; for(i = 0; i < polygon.length; i++) { var polyLine = { p1: polygon[i], p2: polygon[(i + 1) % polygon.length] }; var intersectInfo = linesIntersect(line, polyLine); if(!intersectInfo) continue; if(intersectInfo.parallel) { // Only really care about this if it actually touches the point if(intersectInfo.parallel.first.x <= point.x && intersectInfo.parallel.second.x >= point.x) return true; continue; } var intersectionX = intersectInfo.point.x; if(intersectionX > point.x || intersectionX < closest) continue; if(intersectionX == point.x) return true; // If closer than last time, reset cosine. if(intersectionX != closest) cos = -2; // For getting cosine, need to possibly reverse the direction of polyLine. if(intersectInfo.ties) { // Tie must be on l2, if the ties is end, reverse so cosine indicates how close the angle is to that of 'point' from here. if(intersectInfo.ties.l2 == 'end') polyLine = { p1: polyLine.p2, p2: polyLine.p1 }; } else { // It is on both side, so you can take the larger one if(polyLine.p1.x > polyLine.p2.x) polyLine = { p1: polyLine.p2, p2: polyLine.p1 }; } var currCos = getCos(polyLine); if(currCos > cos) { cos = currCos; closest = intersectionX; entered = intersectInfo.entering; } } return entered; }; _geometry.checkInside = _checkInside; }); //***** flyout.js *****// // ******* Flyout MANAGER ******** // $axure.internal(function($ax) { var _flyoutManager = $ax.flyoutManager = {}; var getFlyoutLabel = function(panelId) { return panelId + '_flyout'; }; var _unregisterPanel = function(panelId, keepShown) { $ax.geometry.unregister(getFlyoutLabel(panelId)); if(panelToSrc[panelId]) { $ax.style.RemoveRolloverOverride(panelToSrc[panelId]); delete panelToSrc[panelId]; } if(!keepShown) { $ax.action.addAnimation(panelId, $ax.action.queueTypes.fade, function() { $ax('#' + panelId).hide(); }); } }; _flyoutManager.unregisterPanel = _unregisterPanel; var genPoint = $ax.geometry.genPoint; var _updateFlyout = function(panelId) { var label = getFlyoutLabel(panelId); if(!$ax.geometry.polygonRegistered(label)) return; var info = $ax.geometry.getPolygonInfo(label); var rects = info && info.rects; var targetWidget = $ax.getWidgetInfo(panelId); rects.target = $ax.geometry.genRect(targetWidget); // Src will stay the same, just updating $ax.flyoutManager.registerFlyout(rects, panelId, panelToSrc[panelId]); if(!$ax.geometry.checkInsideRegion(label)) _unregisterPanel(panelId); }; _flyoutManager.updateFlyout = _updateFlyout; var panelToSrc = {}; var _registerFlyout = function(rects, panelId, srcId) { var label = _getFlyoutLabel(panelId); var callback = function(info) { // If leaving object or already outside it, then unregister, otherwise just return if(!info.exiting && !info.outside) return; _unregisterPanel(panelId); }; var points = []; var lastSrcId = panelToSrc[panelId]; if(lastSrcId != srcId) { if(lastSrcId) $ax.style.RemoveRolloverOverride(lastSrcId); if(srcId) { $ax.style.AddRolloverOverride(srcId); panelToSrc[panelId] = srcId; } else delete panelToSrc[panelId]; } // rects should be one or two rectangles if(!rects.src) { var rect = rects.target; points.push(genPoint(rect.Left(), rect.Top())); points.push(genPoint(rect.Right(), rect.Top())); points.push(genPoint(rect.Right(), rect.Bottom())); points.push(genPoint(rect.Left(), rect.Bottom())); } else { var r0 = rects.src; var r1 = rects.target; // Right left of right, left right of left, top below top, bottom above bottom var rlr = r0.Right() <= r1.Right(); var lrl = r0.Left() >= r1.Left(); var tbt = r0.Top() >= r1.Top(); var bab = r0.Bottom() <= r1.Bottom(); var info = { rlr: rlr, lrl: lrl, tbt: tbt, bab: bab }; if((rlr && lrl) || (tbt && bab)) { points = getSmallPolygon(r0, r1, info); } else { points = getLargePolygon(r0, r1, info); } } $ax.geometry.registerPolygon(label, points, callback, { rects: rects }); }; _flyoutManager.registerFlyout = _registerFlyout; var _getFlyoutLabel = function(panelId) { return panelId + '_flyout'; }; var _reregisterAllFlyouts = function() { for(var panelId in panelToSrc) _reregisterFlyout(panelId); }; _flyoutManager.reregisterAllFlyouts = _reregisterAllFlyouts; var _reregisterFlyout = function(panelId) { var rects = $ax.geometry.getPolygonInfo(getFlyoutLabel(panelId)).rects; _registerFlyout(rects, panelId, panelToSrc[panelId]); }; // This is the reduced size polygon connecting r0 to r1 by means of horizontal or vertical lines. var getSmallPolygon = function(r0, r1, info) { var points = []; // NOTE: currently I make the assumption that if horizontal/vertical connecting lines from the src hit the target // Meaning if horizontal, rlr and lrl are true, and if vertical, tbt and bab are true. var r0Left = r0.Left(); var r0Right = r0.Right(); var r0Top = r0.Top(); var r0Bottom = r0.Bottom(); var r1Left = r1.Left(); var r1Right = r1.Right(); var r1Top = r1.Top(); var r1Bottom = r1.Bottom(); points.push(genPoint(r1Left, r1Top)); if(!info.tbt) { points.push(genPoint(r0Left, r1Top)); points.push(genPoint(r0Left, r0Top)); points.push(genPoint(r0Right, r0Top)); points.push(genPoint(r0Right, r1Top)); } points.push(genPoint(r1Right, r1Top)); if(!info.rlr) { points.push(genPoint(r1Right, r0Top)); points.push(genPoint(r0Right, r0Top)); points.push(genPoint(r0Right, r0Bottom)); points.push(genPoint(r1Right, r0Bottom)); } points.push(genPoint(r1Right, r1Bottom)); if(!info.bab) { points.push(genPoint(r0Right, r1Bottom)); points.push(genPoint(r0Right, r0Bottom)); points.push(genPoint(r0Left, r0Bottom)); points.push(genPoint(r0Left, r1Bottom)); } points.push(genPoint(r1Left, r1Bottom)); if(!info.lrl) { points.push(genPoint(r1Left, r0Bottom)); points.push(genPoint(r0Left, r0Bottom)); points.push(genPoint(r0Left, r0Top)); points.push(genPoint(r1Left, r0Top)); } return points; }; // This is the original algorithm that connects the most extream corners to make polygon var getLargePolygon = function(r0, r1, info) { var points = []; var r0Left = r0.Left(); var r0Right = r0.Right(); var r0Top = r0.Top(); var r0Bottom = r0.Bottom(); var r1Left = r1.Left(); var r1Right = r1.Right(); var r1Top = r1.Top(); var r1Bottom = r1.Bottom(); // Top lefts if(info.tbt) { if(!info.lrl) points.push(genPoint(r0Left, r0Top)); points.push(genPoint(r1Left, r1Top)); } else { if(info.lrl) points.push(genPoint(r1Left, r1Top)); points.push(genPoint(r0Left, r0Top)); } // Top rights if(info.tbt) { points.push(genPoint(r1Right, r1Top)); if(!info.rlr) points.push(genPoint(r0Right, r0Top)); } else { points.push(genPoint(r0Right, r0Top)); if(info.rlr) points.push(genPoint(r1Right, r1Top)); } // Bottom rights if(info.bab) { if(!info.rlr) points.push(genPoint(r0Right, r0Bottom)); points.push(genPoint(r1Right, r1Bottom)); } else { if(info.rlr) points.push(genPoint(r1Right, r1Bottom)); points.push(genPoint(r0Right, r0Bottom)); } // Bottom Lefts if(info.bab) { points.push(genPoint(r1Left, r1Bottom)); if(!info.lrl) points.push(genPoint(r0Left, r0Bottom)); } else { points.push(genPoint(r0Left, r0Bottom)); if(info.lrl) points.push(genPoint(r1Left, r1Bottom)); } return points; }; }); // ******* Placeholder Manager ********* // $axure.internal(function($ax) { var _placeholderManager = $ax.placeholderManager = {}; var idToPlaceholderInfo = {}; var _registerPlaceholder = function(elementId, text, password) { idToPlaceholderInfo[elementId] = { text: text, password: password, active: false }; }; _placeholderManager.registerPlaceholder = _registerPlaceholder; _placeholderManager.refreshPlaceholder = function (elementId) { var info = idToPlaceholderInfo[elementId]; if (!info || !info.active) return; $ax.style.SetWidgetPlaceholder(elementId, true, info.text, info.password); } var _updatePlaceholder = function(elementId, active, clearText) { var inputId = $ax.repeater.applySuffixToElementId(elementId, '_input'); var info = idToPlaceholderInfo[elementId]; if(!info || info.active == active) return; info.active = active; if(active) var value = info.text; else if(!ANDROID) value = clearText ? '' : document.getElementById(inputId).value; else { var currentText = document.getElementById(inputId).value; if(!clearText) value = currentText; else if(currentText == info.text) value = ""; else { var lastIndex = currentText.lastIndexOf(info.text); //here i am assuming the text is always inserted in front value = currentText.substring(0, lastIndex); } } $ax.style.SetWidgetPlaceholder(elementId, active, value, info.password); }; _placeholderManager.updatePlaceholder = _updatePlaceholder; var _isActive = function(elementId) { var info = idToPlaceholderInfo[elementId]; return Boolean(info && info.active); }; _placeholderManager.isActive = _isActive; var _selectRange = function(elementId, start, end) { $jobj(elementId).each(function() { if(this.setSelectionRange) { var validTypes = ["text", "search", "url", "tel", "password"]; if(this.tagName.toLowerCase() != "input" || validTypes.indexOf(this.type) > -1) { this.focus(); this.setSelectionRange(start, end); } } else if(this.createTextRange) { var range = this.createTextRange(); range.collapse(true); range.moveEnd('character', end); range.moveStart('character', start); range.select(); } }); }; _placeholderManager.selectRange = _selectRange; var _moveCaret = function(id, index) { var inputIndex = id.indexOf('_input'); if(inputIndex == -1) return; var inputId = id.substring(0, inputIndex); if(!_isActive(inputId)) return; _selectRange(id, index, index); }; _placeholderManager.moveCaret = _moveCaret; }); //***** ie.js *****// // ******* Internet Explorer MANAGER ******** // //this is to handle all the stupid IE Stuff $axure.internal(function($ax) { if(!IE_10_AND_BELOW) return; var _ieColorManager = {}; if(Number(BROWSER_VERSION) < 9) $ax.ieColorManager = _ieColorManager; var _applyIEFixedPosition = function() { if(Number(BROWSER_VERSION) >= 7) return; $axure(function(diagramObject) { return diagramObject.fixedVertical; }).$() .appendTo($('body')) .css('position', 'absolute').css('margin-left', 0 + 'px').css('margin-top', 0 + 'px'); var handleScroll = function() { $axure(function(diagramObject) { return diagramObject.fixedVertical; }) .each(function(diagramObject, elementId) { var win = $(window); var windowWidth = win.width(); var windowHeight = win.height(); var windowScrollLeft = win.scrollLeft(); var windowScrollTop = win.scrollTop(); var newLeft = 0; var newTop = 0; var elementQuery = $('#' + elementId); var elementAxQuery = $ax('#' + elementId); var width = elementAxQuery.width(); var height = elementAxQuery.height(); var horz = diagramObject.fixedHorizontal; if(horz == 'left') { newLeft = windowScrollLeft + diagramObject.fixedMarginHorizontal; } else if(horz == 'center') { newLeft = windowScrollLeft + ((windowWidth - width) / 2) + diagramObject.fixedMarginHorizontal; } else if(horz == 'right') { newLeft = windowScrollLeft + windowWidth - width - diagramObject.fixedMarginHorizontal; } var vert = diagramObject.fixedVertical; if(vert == 'top') { newTop = windowScrollTop + diagramObject.fixedMarginVertical; } else if(vert == 'middle') { newTop = windowScrollTop + ((windowHeight - height) / 2) + diagramObject.fixedMarginVertical; } else if(vert == 'bottom') { newTop = windowScrollTop + windowHeight - height - diagramObject.fixedMarginVertical; } elementQuery.css('top', newTop + 'px').css('left', newLeft + 'px'); }); }; $(window).scroll(handleScroll); $axure.resize(handleScroll); handleScroll(); }; var _applyBackground = function() { if(Number(BROWSER_VERSION) >= 9) return; var styleChain = $ax.adaptive.getAdaptiveIdChain($ax.adaptive.currentViewId); var argb = _getArgb($ax.pageData.page, styleChain); var hexColor = _getHexColor(argb, false); if(hexColor) $('body').css('background-color', hexColor); _applyBackgroundToQuery($ax('*')); }; var _applyBackgroundToQuery = function(query) { if(Number(BROWSER_VERSION) >= 9) return; var styleChain = $ax.adaptive.getAdaptiveIdChain($ax.adaptive.currentViewId); query.each(function(obj, elementId) { if ($ax.public.fn.IsDynamicPanel(obj.type)) { var stateCount = obj.diagrams.length; for(var j = 0; j < stateCount; j++) { var stateId = $ax.repeater.applySuffixToElementId(elementId, '_state' + j); var argb = _getArgb(obj.diagrams[j], styleChain); var hexColor = _getHexColor(argb, true); if(hexColor) $jobj(stateId).css('background-color', hexColor); } } else if ($ax.public.fn.IsRepeater(obj.type)) { } }); }; _ieColorManager.applyBackground = _applyBackgroundToQuery; var _getArgb = function(diagram, styleChain) { var argb = undefined; for(var i = 0; i < styleChain.length && !argb; i++) { var style = diagram.adaptiveStyles[styleChain[i]]; argb = style.fill && style.fill.color; } if(!argb) argb = diagram.style.fill.color; return argb; }; var gMult = 256; var rMult = gMult * 256; var aMult = rMult * 256; var _getHexColor = function(argb, allowWhite) { var a = Math.floor(argb / aMult); argb -= a * aMult; var r = Math.floor(argb / rMult); argb -= r * rMult; var g = Math.floor(argb / gMult); var b = argb - g * gMult; return _getColorFromArgb(a, r, g, b, allowWhite); }; var _getColorFromArgb = function(a, r, g, b, allowWhite) { if(Number(BROWSER_VERSION) >= 9) return undefined; //convert the color with alpha to a color with no alpha (assuming white background) r = Math.min((r * a) / 255 + 255 - a, 255); g = Math.min((g * a) / 255 + 255 - a, 255); b = Math.min((b * a) / 255 + 255 - a, 255); if(a == 0) return undefined; if(!allowWhite && (r == 255 && g == 255 && b == 255)) return undefined; var color = '#'; color += Math.floor(r / 16).toString(16); color += Math.floor(r % 16).toString(16); color += Math.floor(g / 16).toString(16); color += Math.floor(g % 16).toString(16); color += Math.floor(b / 16).toString(16); color += Math.floor(b % 16).toString(16); return color; }; _ieColorManager.getColorFromArgb = _getColorFromArgb; var getIEOffset = function(transform, rect) { var translatedVertexes = [ $axure.utils.Vector2D(0, 0), //we dont translate, so the orgin is fixed transform.mul($axure.utils.Vector2D(0, rect.height)), transform.mul($axure.utils.Vector2D(rect.width, 0)), transform.mul($axure.utils.Vector2D(rect.width, rect.height))]; var minX = 0, minY = 0, maxX = 0, maxY = 0; $.each(translatedVertexes, function(index, p) { minX = Math.min(minX, p.x); minY = Math.min(minY, p.y); maxX = Math.max(maxX, p.x); maxY = Math.max(maxY, p.y); }); return $axure.utils.Vector2D( (maxX - minX - rect.width) / 2, (maxY - minY - rect.height) / 2); }; var _filterFromTransform = function(transform) { return "progid:DXImageTransform.Microsoft.Matrix(M11=" + transform.m11 + ", M12=" + transform.m12 + ", M21=" + transform.m21 + ", M22=" + transform.m22 + ", SizingMethod='auto expand')"; }; var _applyIERotation = function() { if(Number(BROWSER_VERSION) >= 9) return; $axure(function(diagramObject) { return ((diagramObject.style.rotation && Math.abs(diagramObject.style.rotation) > 0.1) || (diagramObject.style.textRotation && Math.abs(diagramObject.style.textRotation) > 0.1)) && !diagramObject.isContained; }).each(function(diagramObject, elementId) { var rotation = diagramObject.style.rotation || 0; var $element = $('#' + elementId); var axElement = $ax('#' + elementId); var width = axElement.width(); var height = axElement.height(); var originX = width / 2; var originY = height / 2; var shapeIeOffset; $element.children().each(function() { var $child = $(this); var axChild = $ax('#' + $child.attr('id')); var childWidth = axChild.width(); var childHeight = axChild.height() + $child.position().top; var centerX = $child.position().left + (childWidth / 2); var centerY = $child.position().top + (childHeight / 2); var deltaX = centerX - originX; var deltaY = centerY - originY; var effectiveRotation = rotation; var textObject = $ax.getObjectFromElementId($child.attr('id')); if(textObject) { if(textObject.style.textRotation) effectiveRotation = textObject.style.textRotation; else return; } var transform = $ax.utils.Matrix2D.identity().rotate(effectiveRotation); var filter = _filterFromTransform(transform); $child.css('filter', filter) .width(childWidth + 1) .height(childHeight + 1); var p = transform.mul($ax.utils.Vector2D(deltaX, deltaY)); var ieOffset = getIEOffset(transform, { width: childWidth, height: childHeight }); if(!textObject) { shapeIeOffset = ieOffset; } else { // This is a close approximation, but not exact if(diagramObject.style.verticalAlignment != 'top') ieOffset.y -= shapeIeOffset.y + Math.abs(shapeIeOffset.x); } $child.css("margin-left", -ieOffset.x - deltaX + p.x).css("margin-top", -ieOffset.y - deltaY + p.y); }); }); }; var _fixIEStretchBackground = function() { if(Number(BROWSER_VERSION) >= 9) return; var pageStyle = $ax.adaptive.getPageStyle(); if(!pageStyle.imageRepeat || pageStyle.imageRepeat == 'auto') return; $('body').css('background-image', 'none'); var viewId = $ax.adaptive.currentViewId; var imageInfo = viewId ? $ax.pageData.viewIdToBackgroundImageInfo && $ax.pageData.viewIdToBackgroundImageInfo[viewId] : $ax.pageData.defaultBackgroundImageInfo; if(imageInfo && imageInfo.path) { if($('#bg_img').length == 0) $('body').append(''); $('#bg_img').attr('src', imageInfo.path).css('position', 'fixed').css('z-index', '-10000'); _resizeIEBackground(); } else $('#bg_img').remove(); }; var _resizeIEBackground = function() { if(Number(BROWSER_VERSION) >= 9) return; //var page = $ax.pageData.page; var viewId = $ax.adaptive.currentViewId; var pageStyle = $ax.adaptive.getPageStyle(); if(!$ax.pageData.defaultBackgroundImageInfo && !$ax.pageData.viewIdToBackgroundImageInfo) return; var imageInfo = viewId ? $ax.pageData.viewIdToBackgroundImageInfo[viewId] : $ax.pageData.defaultBackgroundImageInfo; if(!imageInfo) return; var imageWidth = imageInfo.width; var imageHeight = imageInfo.height; var windowWidth = $(window).width(); var windowHeight = $(window).height(); var isCover = pageStyle.imageRepeat == 'cover'; var wRatio = windowWidth / imageWidth; var hRatio = windowHeight / imageHeight; var ratio = wRatio; if(isCover) { if(hRatio > wRatio) ratio = hRatio; } else { if(hRatio < wRatio) ratio = hRatio; } var width = imageWidth * ratio; var height = imageHeight * ratio; var left = '0px'; if((isCover && width > windowWidth) || (!isCover && width < windowWidth)) { if(pageStyle.imageHorizontalAlignment == 'center') { left = ((windowWidth - width) / 2) + 'px'; } else if(pageStyle.imageHorizontalAlignment == 'far') { left = (windowWidth - width) + 'px'; } } var top = '0px'; if((isCover && height > windowHeight) || (!isCover && height < windowHeight)) { if(pageStyle.imageVerticalAlignment == 'center') { top = ((windowHeight - height) / 2) + 'px'; } else if(pageStyle.imageVerticalAlignment == 'far') { top = (windowHeight - height) + 'px'; } } $('#bg_img').css('top', top).css('left', left).css('width', width).css('height', height); }; var _fixAllPngs = function() { if(!(/MSIE ((5\.5)|6)/.test(window.navigator.userAgent) && window.navigator.platform == "Win32")) return; $('img[src$=".png"]').each(function() { if(!this.complete) { this.onload = function() { $axure.utils.fixPng(this); }; } else { $axure.utils.fixPng(this); } }); }; var _fixInputSize = function() { if(Number(BROWSER_VERSION) >= 8 || window.navigator.userAgent.indexOf("Trident/4.0") > -1) return; var inputs = $('input').not(':input[type=button], :input[type=submit], :input[type=radio], :input[type=checkbox]'); inputs.each(function() { var $input = $(this); var axInput = $ax('#' + $input.attr('id')); $input.css('height', (axInput.height() - 4 + 'px')).css('width', (axInput.width() - 2 + 'px')); }); var textAreas = $($ax.constants.TEXT_AREA_TYPE); textAreas.each(function() { var $textArea = $(this); var axText = $ax('#' + $textArea.attr('id')); $textArea.css('height', (axText.height() - 6 + 'px')).css('width', (axText.width() - 6 + 'px')); }); }; var _fixInputBackground = function() { var inputs = $('input').not(':input[type=button], :input[type=submit], :input[type=radio], :input[type=checkbox]'); inputs = inputs.add($($ax.constants.TEXT_AREA_TYPE)); inputs.each(function() { var $input = $(this); if($input.css('background-color') == 'transparent') { $input.css('background-image', 'url(../../transparent.gif)'); } else { $input.css('background-image', ''); } }); }; $(document).ready(function() { _fixIEStretchBackground(); _applyIEFixedPosition(); $axure.resize(function() { _resizeIEBackground(); }); $ax.adaptive.bind('viewChanged', function() { _fixIEStretchBackground(); _applyBackground(); _fixInputBackground(); }); _fixAllPngs(); _applyIERotation(); _applyBackground(); _fixInputSize(); _fixInputBackground(); }); }); //***** model.js *****// // ******* Object Model ******** // $axure.internal(function($ax) { var _implementations = {}; var _initializeObject = function(type, obj) { $.extend(obj, _implementations[type]); }; $ax.initializeObject = _initializeObject; var _model = $ax.model = {}; _model.idsInRdoToHideOrLimbo = function(rdoId, scriptIds) { var rdoScriptId = $ax.repeater.getScriptIdFromElementId(rdoId); var path = $ax.getPathFromScriptId(rdoScriptId); if(!scriptIds) scriptIds = []; var rdo = $ax.getObjectFromElementId(rdoId); var master = $ax.pageData.masters[rdo.masterId]; var masterChildren = master.diagram.objects; for(var i = 0; i < masterChildren.length; i++) { var obj = masterChildren[i]; var objScriptIds = obj.scriptIds; for(var j = 0; j < objScriptIds.length; j++) { var scriptId = objScriptIds[j]; // Anything in a layer is already handled by the layer if($ax.getLayerParentFromElementId(scriptId)) continue; // Make sure in same rdo var elementPath = $ax.getPathFromScriptId(scriptId); // This is because last part of path is for the obj itself. elementPath.pop(); if(elementPath.length != path.length) continue; var samePath = true; for(var k = 0; k < path.length; k++) { if(elementPath[k] != path[k]) { samePath = false; break; } } if(!samePath) continue; if($ax.public.fn.IsReferenceDiagramObject(obj.type)) _model.idsInRdoToHideOrLimbo(scriptId, scriptIds); else if(scriptIds.indexOf(scriptId) == -1) scriptIds.push(scriptId); break; } } return scriptIds; }; }); //***** repeater.js *****// // ******* Repeater MANAGER ******** // $axure.internal(function($ax) { var _repeaterManager = {}; $ax.repeater = _repeaterManager; //This is a mapping of current editItems var repeaterToEditItems = {}; //This is a mapping of current filters var repeaterToFilters = {}; // This is a mapping of current sorts var repeaterToSorts = {}; // This is a mapping of repeater page info var repeaterToPageInfo = {}; //Hopefully this can be simplified, but for now I think 3 are needed. //This is the data set that is owned by this repeater. The repeater may or may not reference this data set, and others can reference it. var repeaterToLocalDataSet = {}; //This is the data set referenced by the repeater. It is not a copy of the local data set, but a reference to a local data set (or eventually a global data set could be referenced). var repeaterToCurrentDataSet = {}; //This is a copy of the current data set, that is replaced whenever a set or refresh is done. var repeaterToActiveDataSet = {}; var _loadRepeaters = function() { $ax(function(obj) { return $ax.public.fn.IsRepeater(obj.type); }).each(function(obj, repeaterId) { repeaterToLocalDataSet[repeaterId] = $ax.deepCopy(obj.data); repeaterToLocalDataSet[repeaterId].props = obj.dataProps; repeaterToEditItems[repeaterId] = []; _initPageInfo(obj, repeaterId); _setRepeaterDataSet(repeaterId, repeaterId); var initialItemIds = obj.repeaterPropMap.itemIds; for (var i = 0; i < initialItemIds.length; i++) $ax.addItemIdToRepeater(initialItemIds[i], repeaterId); $ax.visibility.initRepeater(repeaterId); }); }; _repeaterManager.load = _loadRepeaters; var _loaded = {}; var _initRepeaters = function() { $ax(function(obj, repeaterId) { return $ax.public.fn.IsRepeater(obj.type) && !_loaded[repeaterId]; }).each(function(obj, repeaterId) { _refreshRepeater(repeaterId, undefined, true); //// Fix selected and default if necessary //var states = obj.evaluatedStates[repeaterId]; //if(!states) return; // If there are no evaluated states the repeater id key could not be mapped to an array of states. //for(var i = 0; i < states.length; i++) { // var state = states[i]; // $ax.style.SetWidgetEnabled(state.id, true); // So selected will take place. If disabled, selected wouldn't happen. // $ax.style.SetWidgetSelected(state.id, state.selected); // $ax.style.SetWidgetEnabled(state.id, !state.disabled); //} }); }; _repeaterManager.initRefresh = _initRepeaters; var repeatersHaveNewDataSet = []; var _setRepeaterDataSet = function(repeaterId, dataSetId) { //TODO: No idea about how global data sets will be handled... repeaterToCurrentDataSet[repeaterId] = repeaterToLocalDataSet[dataSetId]; repeaterToActiveDataSet[repeaterId] = getActiveDataSet(repeaterId); repeaterToFilters[repeaterId] = []; repeaterToSorts[repeaterId] = []; // Not using this currently // if(repeatersHaveNewDataSet.indexOf(repeaterId) == -1) repeatersHaveNewDataSet[repeatersHaveNewDataSet.length] = repeaterId; }; _repeaterManager.setDataSet = _setRepeaterDataSet; var _refreshRepeater = function(repeaterId, eventInfo, itemsPregen) { // Don't show if you have a parent rdos thats limboed. var rdoPath = $ax.getPathFromScriptId(repeaterId); // Check each parent rdo through appropriate views to see if you are limboed while (rdoPath.length > 0) { if(!$ax.getScriptIdFromPath(rdoPath)) { removeItems(repeaterId); return; } $ax.splice(rdoPath, rdoPath.length - 1, 1); } _loaded[repeaterId] = true; $ax.action.refreshStart(repeaterId); $ax.style.ClearCacheForRepeater(repeaterId); if($ax.visibility.limboIds[repeaterId]) { removeItems(repeaterId); $ax.dynamicPanelManager.fitParentPanel(repeaterId); return; } // Remove delete map if there is one at this point if(eventInfo && eventInfo.repeaterDeleteMap) delete eventInfo.repeaterDeleteMap[repeaterId]; var path = $ax.getPathFromScriptId(repeaterId); path.pop(); if(eventInfo) { eventInfo = $ax.eventCopy(eventInfo); } var obj = $ax.getObjectFromScriptId(repeaterId); var propMap = obj.repeaterPropMap; //If there is no wrap, then set it to be above the number of rows var viewId = $ax.adaptive.currentViewId || ''; var wrap = _getAdaptiveProp(propMap, 'wrap', viewId); var vertical = _getAdaptiveProp(propMap, 'vertical', viewId); var offset = propMap[viewId]; // Right now pregen only works for default adaptive view if(viewId) itemsPregen = false; var orderedIds = []; if(itemsPregen) { var repeaterChildren = $jobj(repeaterId).children(); // Start at 1 to skip script div child for(var i = 1; i < repeaterChildren.length; i++) { orderedIds.push(_getItemIdFromElementId($(repeaterChildren[i]).attr('id'))); } } else orderedIds = getOrderedIds(repeaterId, eventInfo); var ids = []; var background = _getAdaptiveProp(propMap, 'backColor', viewId); var hasAltColor = _getAdaptiveProp(propMap, 'hasAltColor', viewId); var altColor = hasAltColor ? _getAdaptiveProp(propMap, 'altColor', viewId) : undefined; var useAlt = false; if(itemsPregen) { var start = 0; var end = orderedIds.length; } else { var bounds = _getVisibleDataBounds(repeaterToPageInfo[repeaterId], itemsPregen ? obj.data.length : orderedIds.length); start = bounds[0]; end = bounds[1]; } var repeaterObj = $jobj(repeaterId); var preevalMap = {}; if(itemsPregen) { var templateIds = [repeaterId]; var processScriptIds = function (full, prop, id) { if(id.indexOf('_') <= 0 && id.indexOf('p') == -1) templateIds.push('u' + id); }; $('#' + repeaterId + '_script').html().replace(/(id|for)="?u([0-9]+(p([0-9]){3})?(_[_a-z0-9]*)?)"?/g, processScriptIds); for(var i = 0; i < templateIds.length; i++) { for(var j = 0; j < orderedIds.length; j++) { ids.push(_createElementId(templateIds[i], orderedIds[j])); } } for(var pos = start; pos < end; pos++) { var itemId = orderedIds[pos]; itemElementId = _createElementId(repeaterId, itemId); var jobj = $jobj(itemElementId); var preeval = jobj.hasClass('preeval'); for(var i = 0; i < templateIds.length; i++) $ax.initializeObjectEvents($ax('#' + _createElementId(templateIds[i], itemId)), !preeval); if(preeval) { preevalMap[itemId] = true; jobj.removeClass('preeval'); } } } else { var html = $('#' + repeaterId + '_script').html(); // var container = $('
'); // container.html(html); // container.attr('id', '' + repeaterId + '_container'); // container.css({ position: 'absolute' }); // container.offset({ left: -obj.x, top: -obj.y }); var div = $('
'); div.html(html); div.find('.' + $ax.visibility.HIDDEN_CLASS).removeClass($ax.visibility.HIDDEN_CLASS); div.find('.' + $ax.visibility.UNPLACED_CLASS).removeClass($ax.visibility.UNPLACED_CLASS); var paddingTop = _getAdaptiveProp(propMap, 'paddingTop', viewId); var paddingLeft = _getAdaptiveProp(propMap, 'paddingLeft', viewId); var paddingY = paddingTop + _getAdaptiveProp(propMap, 'paddingBottom', viewId); var paddingX = paddingLeft + _getAdaptiveProp(propMap, 'paddingRight', viewId); var spacingX = _getAdaptiveProp(propMap, 'horizontalSpacing', viewId); var xOffset = offset.width + spacingX; var spacingY = _getAdaptiveProp(propMap, 'verticalSpacing', viewId); var yOffset = offset.height + spacingY; div.css({ width: offset.width, height: offset.height }); _applyColorCss(background, div); var altDiv = div; if(hasAltColor) altDiv = _applyColorCss(altColor, div.clone()); // Hide repeater, if shown, while updating. var shown = $ax.visibility.IsIdVisible(repeaterId); if(shown) document.getElementById(repeaterId).style.visibility = 'hidden'; //clean up old items as late as possible removeItems(repeaterId); resetItemSizes(repeaterId, offset, bounds, orderedIds, vertical, wrap); var i = 0; var startTop = paddingTop; var startLeft = paddingLeft; if(repeaterObj.css('box-sizing') == 'border-box') { startTop -= $ax.getNumFromPx(repeaterObj.css('border-top-width')) || 0; startLeft -= $ax.getNumFromPx(repeaterObj.css('border-left-width')) || 0; } var top = startTop; var left = startLeft; for(pos = start; pos < end; pos++) { itemId = orderedIds[pos]; var itemElementId = _createElementId(repeaterId, itemId); $ax.addItemIdToRepeater(itemId, repeaterId); ids.push(itemElementId); var processId = function(full, prop, id) { var elementId = _createElementId('u' + id, itemId); //If there is a suffix (ex. _img), then don't push the id. if (id.indexOf('_') <= 0 && id.indexOf('p') == -1) ids.push(elementId); return prop + '="' + elementId + '"'; }; var copy = (useAlt ? altDiv : div).clone(); useAlt = !useAlt; copy.attr('id', itemElementId); copy.html(div.html().replace(/(id|for)="?u([0-9]+(p([0-9]){3})?(_[_a-z0-9]*)?)"?/g, processId)); if(obj.repeaterPropMap.isolateRadio) { var radioButtons = copy.find(':radio'); for(var radioIndex = 0; radioIndex < radioButtons.length; radioIndex++) { var radio = $(radioButtons[radioIndex]); var oldName = radio.attr('name') || ''; // Can't use create element id because there could be an underscore in name if(oldName) radio.attr('name', oldName + '-' + itemId); } } copy.css({ 'position': 'absolute', 'top': top + 'px', 'left': left + 'px', 'width': obj.width + 'px', 'height': obj.height + 'px' }); $('#' + repeaterId).append(copy); i++; if(wrap != -1 && i % wrap == 0) { if(vertical) { top = startTop; left += xOffset; } else { left = startLeft; top += yOffset; } } else if (vertical) top += yOffset; else left += xOffset; } var shownCount = end - start; var repeaterSize = { width: paddingX, height: paddingY}; if(shownCount > 0) { var primaryCount = wrap == -1 ? shownCount : Math.min(shownCount, wrap); var secondaryCount = wrap == -1 ? 1 : Math.ceil(shownCount / wrap); var widthCount = vertical ? secondaryCount : primaryCount; var heightCount = vertical ? primaryCount : secondaryCount; repeaterSize.width += offset.width + (widthCount - 1) * xOffset; repeaterSize.height += offset.height + (heightCount - 1) * yOffset; } repeaterObj.css(repeaterSize); // Had to move this here because it sets up cursor: pointer on inline links, // but must be done before style cached when adaptive view is set. // TODO: Should be able to combine this with initialization done in pregen items. Just need to have ids and template ids be the same. for(var i = 0; i < ids.length; i++) $ax.initializeObjectEvents($ax('#' + ids[i]), true); } var query = _getItemQuery(repeaterId); if(viewId) $ax.adaptive.applyView(viewId, query); else $ax.visibility.resetLimboAndHiddenToDefaults(_getItemQuery(repeaterId, preevalMap)); $ax.annotation.InitializeAnnotations(query); for(var index = 0; index < ids.length; index++) { var id = ids[index]; var childObj = $obj(id); var childJobj = $jobj(id); var childItemId = _getItemIdFromElementId(id); if(obj.repeaterPropMap.isolateSelection && childJobj.attr('selectiongroup')) { childJobj.attr('selectiongroup', _createElementId(childJobj.attr('selectiongroup'), childItemId)); } if ($ax.ieColorManager) $ax.ieColorManager.applyBackground($ax('#' + id)); $ax.style.initializeObjectTextAlignment($ax('#' + id)); $ax.applyHighlight($ax('#' + id), true); } $ax.messageCenter.startCombineEventMessages(); $ax.cacheRepeaterInfo(repeaterId, $ax.getWidgetInfo(repeaterId)); // Now load for(pos = start; pos < end; pos++) { itemId = orderedIds[pos]; itemElementId = _createElementId(repeaterId, itemId); if(!preevalMap[orderedIds[pos]]) $ax.event.raiseSyntheticEvent(itemElementId, 'onItemLoad', true); $ax.loadDynamicPanelsAndMasters(obj.objects, path, itemId); } $ax.removeCachedRepeaterInfo(repeaterId); $ax.messageCenter.endCombineEventMessages(); // Reshow repeater if it was originally shown (load is complete by now) if(shown && !itemsPregen) document.getElementById(repeaterId).style.visibility = 'inherit'; $ax.dynamicPanelManager.fitParentPanel(repeaterId); // Right now we assume only one refresh at a time. If we can manually trigger refreshes, that may possibly change. $ax.action.refreshEnd(); }; _repeaterManager.refreshRepeater = _refreshRepeater; var _getItemQuery = function(repeaterId, preevalMap) { var query = $ax(function (diagramObject, elementId) { // Also need to check that this in not preeval if(preevalMap) { var itemId = _getItemIdFromElementId(elementId); if(preevalMap[itemId]) return false; } // All objects with the repeater as their parent, except the repeater itself. var scriptId = _getScriptIdFromElementId(elementId); return $ax.getParentRepeaterFromScriptId(scriptId) == repeaterId && scriptId != repeaterId; }); return query; } _repeaterManager.refreshAllRepeaters = function() { $ax('*').each(function(diagramObject, elementId) { if(!$ax.public.fn.IsRepeater(diagramObject.type)) return; if($ax.visibility.isElementIdLimboOrInLimboContainer(elementId)) return; _initPageInfo(diagramObject, elementId); _refreshRepeater(elementId, $ax.getEventInfoFromEvent($ax.getjBrowserEvent())); }); }; _repeaterManager.refreshRepeaters = function(ids, eventInfo) { for(var i = 0; i < ids.length; i++) _refreshRepeater(ids[i], eventInfo); }; var _initPageInfo = function(obj, elementId) { var pageInfo = {}; var map = obj.repeaterPropMap; var currentViewId = $ax.adaptive.currentViewId || ''; var itemsPerPage = _getAdaptiveProp(map, 'itemsPerPage', currentViewId); if(itemsPerPage == -1) pageInfo.noLimit = true; else { pageInfo.itemsPerPage = itemsPerPage; pageInfo.currPage = _getAdaptiveProp(map, 'currPage', currentViewId); } repeaterToPageInfo[elementId] = pageInfo; }; _repeaterManager.initialize = function() { $ax(function (obj) { return $ax.public.fn.IsRepeater(obj.type); }).each(function (obj, repeaterId) { _initPregen(repeaterId); }); } var _initPregen = function(repeaterId) { var obj = $ax.getObjectFromScriptId(repeaterId); var propMap = obj.repeaterPropMap; //If there is no wrap, then set it to be above the number of rows var viewId = $ax.adaptive.currentViewId || ''; var wrap = _getAdaptiveProp(propMap, 'wrap', viewId); var vertical = _getAdaptiveProp(propMap, 'vertical', viewId); var orderedIds = []; var ids = []; var background = _getAdaptiveProp(propMap, 'backColor', viewId); var hasAltColor = _getAdaptiveProp(propMap, 'hasAltColor', viewId); var altColor = hasAltColor ? _getAdaptiveProp(propMap, 'altColor', viewId) : undefined; var useAlt = false; var bounds = _getVisibleDataBounds(repeaterToPageInfo[repeaterId], obj.data.length); var start = bounds[0]; var end = bounds[1]; // Starts empty if(start == end) { $ax.action.refreshEnd(repeaterId); return; } var unprocessedBaseIds = $jobj($ax.repeater.createElementId(repeaterId, start + 1)).html().match(/(id|for)="?u([0-9]+)/g); var baseIds = []; if(unprocessedBaseIds) { for(var i = 0; i < unprocessedBaseIds.length; i++) { var val = unprocessedBaseIds[i].split('=')[1].substr(1); if(baseIds.indexOf(val) == -1) baseIds.push(val); } } for(var itemNum = start; itemNum < end; itemNum++) { ids.push($ax.repeater.createElementId(repeaterId, itemNum + 1)); for(i = 0; i < baseIds.length; i++) ids.push($ax.repeater.createElementId(baseIds[i], itemNum + 1)); var itemId = itemNum + 1; orderedIds[itemNum] = itemId; var itemDiv = $jobj($ax.repeater.createElementId(repeaterId, itemNum + 1)); _applyColorCss(useAlt ? altColor : background, itemDiv); if(hasAltColor) useAlt = !useAlt; } resetItemSizes(repeaterId, undefined, bounds, orderedIds, vertical, wrap); }; var _applyColorCss = function(json, div) { var args = json.r + ', ' + json.g + ', ' + json.b; var background = json.a == 0 ? '' : json.a == 1 ? 'rgb(' + args + ')' : 'rgba(' + args + ', ' + json.a + ')'; if($ax.ieColorManager && json.a != 0 && json.a != 1) { var ieColor = $ax.ieColorManager.getColorFromArgb(json.a * 255, json.r, json.g, json.b, true); if(ieColor) background = ieColor; } div.css('background-color', background); return div; }; var _getAdaptiveProp = _repeaterManager.getAdaptiveProp = function(map, prop, viewId) { var viewChain = $ax.adaptive.getAdaptiveIdChain(viewId); for(var i = viewChain.length - 1; i >= 0; i--) { viewId = viewChain[i]; var viewProps = map[viewId]; if(viewProps.hasOwnProperty(prop)) return viewProps[prop]; } var base = map['']; if(base.hasOwnProperty(prop)) return base[prop]; return map['default'][prop]; }; _repeaterManager.getItemCount = function(repeaterId) { var data = repeaterToActiveDataSet[repeaterId].length; var info = repeaterToPageInfo[repeaterId]; if(!info.noLimit) { var start = Math.min(data, info.itemsPerPage * info.currPage); var end = Math.min(data, start + info.itemsPerPage); data = end - start; } return data; }; _repeaterManager.setDisplayProps = function(obj, repeaterId, itemIndex) { var data = repeaterToActiveDataSet[repeaterId]; var info = repeaterToPageInfo[repeaterId]; var start = 0; var end = data.length; if(!info.noLimit) { start = Math.min(end, info.itemsPerPage * (info.currPage - 1)); end = Math.min(end, start + info.itemsPerPage); } var count = end - start; var index = -1; for(var i = 0; i < count; i++) { if(data[start + i].index == itemIndex) index = i + 1; } if(index == -1) return; obj.index = index; obj.isfirst = index == 1; obj.islast = index == end - start; obj.iseven = index % 2 == 0; obj.isodd = index % 2 == 1; }; var _getVisibleDataBounds = function(pageInfo, count) { var retval = [0, count]; if(!pageInfo.noLimit) { var end = pageInfo.itemsPerPage * pageInfo.currPage; var start = end - pageInfo.itemsPerPage; // If past the end, move to last page if(start >= count) { pageInfo.currPage = Math.floor((count - 1) / pageInfo.itemsPerPage) + 1; if(pageInfo.currPage <= 0) pageInfo.currPage = 1; end = pageInfo.itemsPerPage * pageInfo.currPage; start = end - pageInfo.itemsPerPage; } end = Math.min(end, count); retval[0] = start; retval[1] = end; } return retval; }; _repeaterManager.getVisibleDataCount = function(repeaterId) { var bounds = _getVisibleDataBounds(repeaterToPageInfo[repeaterId], repeaterToActiveDataSet[repeaterId].length); return bounds[1] - bounds[0]; }; _repeaterManager.getDataCount = function(repeaterId) { return repeaterToCurrentDataSet[repeaterId].length; }; var _getFilteredDataCount = _repeaterManager.getFilteredDataCount = function(repeaterId) { return repeaterToActiveDataSet[repeaterId].length; }; _repeaterManager.getPageCount = function(repeaterId) { var info = repeaterToPageInfo[repeaterId]; return info.noLimit ? 1 : Math.ceil(_getFilteredDataCount(repeaterId) / info.itemsPerPage); }; _repeaterManager.getPageIndex = function(repeaterId) { var info = repeaterToPageInfo[repeaterId]; return info.noLimit ? 1 : info.currPage; }; var getActiveDataSet = function(repeaterId) { var active = $ax.deepCopy(repeaterToCurrentDataSet[repeaterId]); // Set up 1 indexing each item. for(var i = 0; i < active.length; i++) active[i].index = i + 1; return active; }; var getOrderedIds = function(repeaterId, eventInfo) { var data = repeaterToActiveDataSet[repeaterId] = getActiveDataSet(repeaterId); // Filter first so less to sort applyFilter(repeaterId, data, eventInfo); // Sort next var sorts = repeaterToSorts[repeaterId] || []; if(sorts.length != 0 && data.length > 1) { // TODO: Make this generic and factor out if we want to use it elsewhere... // Compare is a function that takes 2 arguments, and returns a number. A high number means the second should go first // Otherwise the first stays first. var mergesort = function(list, start, end, compare) { var middle = Math.floor((start + end) / 2); if(middle - start > 1) mergesort(list, start, middle, compare); if(end - middle > 1) mergesort(list, middle, end, compare); var index1 = start; var index2 = middle; var tempList = []; while(index1 < middle && index2 < end) { tempList[tempList.length] = list[compare(list[index1], list[index2]) > 0 ? index2++ : index1++]; } while(index1 < middle) tempList[tempList.length] = list[index1++]; while(index2 < end) tempList[tempList.length] = list[index2++]; // transfer from temp list to the real list. for(var i = 0; i < tempList.length; i++) list[start + i] = tempList[i]; }; // Compare is the tie breaking function to us if necessary. var getComparator = function(columnName, ascending, type, compare) { // If this needs to be sped up, break up into several smaller functions conditioned off of type return function(row1, row2) { // If column undefined, no way to measure this, so call it a tie. if(row1[columnName] === undefined || row2[columnName] === undefined) return 0; var text1 = row1[columnName].text; var text2 = row2[columnName].text; // This means we are case insensitive, so lowercase everything to kill casing if(type == 'Text') { text1 = text1.toLowerCase(); text2 = text2.toLowerCase(); } //If tied, go to tie breaker if(text1 == text2) { if(compare) return compare(row1, row2); // Actually a tie. return 0; } if(type == 'Text' || type == 'Text (Case Sensitive)') { if(text1 < text2 ^ ascending) return 1; else return -1; } else if(type == 'Number') { var num1 = Number(text1); var num2 = Number(text2); if(isNaN(num1) && isNaN(num2)) return 0; if(isNaN(num1) || isNaN(num2)) return isNaN(num1) ? 1 : -1; if(num1 < num2 ^ ascending) return 1; else return -1; } else if(type == 'Date - YYYY-MM-DD' || type == 'Date - MM/DD/YYYY') { var func = type == 'Date - YYYY-MM-DD' ? getDate1 : getDate2; var date1 = func(text1); var date2 = func(text2); if(!date1.valid && !date2.valid) return 0; if(!date1.valid || !date2.valid) return date1.valid ? -1 : 1; var diff = date2.year - date1.year; if(diff == 0) diff = date2.month - date1.month; if(diff == 0) diff = date2.day - date1.day; if(diff == 0) return 0; return diff > 0 ^ ascending ? 1 : -1; } console.log('unhandled sort type'); return 0; }; }; var compareFunc = null; for(var i = 0; i < sorts.length; i++) compareFunc = getComparator(sorts[i].columnName, sorts[i].ascending, sorts[i].sortType, compareFunc); mergesort(data, 0, data.length, compareFunc); } var ids = []; for(i = 0; i < data.length; i++) ids[i] = data[i].index; return ids; }; var getDate1 = function(text) { var date = { valid: false }; var sections = text.split('-'); if(sections.length == 1) sections = text.split('/'); if(sections.length != 3) return date; date.year = Number(sections[0]); date.month = Number(sections[1]); date.day = Number(sections[2]); date.valid = !isNaN(date.year); date.valid &= !isNaN(date.month) && date.month > 0 && date.month <= 12; date.valid &= !isNaN(date.day) && date.day > 0 && date.day <= daysPerMonth(date.month, date.year); return date; }; var getDate2 = function(text) { var date = { valid: false }; var sections = text.split('-'); if(sections.length == 1) sections = text.split('/'); if(sections.length != 3) return date; date.month = Number(sections[0]); date.day = Number(sections[1]); date.year = Number(sections[2]); date.valid = !isNaN(date.year); date.valid &= !isNaN(date.month) && date.month > 0 && date.month <= 12; date.valid &= !isNaN(date.day) && date.day > 0 && date.day <= daysPerMonth(date.month, date.year); return date; }; var daysPerMonth = function(month, year) { if(month == 9 || month == 4 || month == 6 || month == 11) return 30; if(month != 2) return 31; if(year % 4 != 0) return 28; if(year % 100 != 0) return 29; return year % 400 == 0 ? 29 : 28; }; var applyFilter = function(repeaterId, data, eventInfo) { var dataFiltered = []; var filters = repeaterToFilters[repeaterId] || []; if (filters.length != 0) { var oldTarget = eventInfo.targetElement; var oldSrc = eventInfo.srcElement; var oldThis = eventInfo.thiswidget; var oldItem = eventInfo.item; var idToWidgetInfo = {}; outer: for(var i = 1; i <= data.length; i++) { for(var j = 0; j < filters.length; j++) { eventInfo.targetElement = _createElementId(repeaterId, i); eventInfo.srcElement = filters[j].thisId; if(!idToWidgetInfo[eventInfo.srcElement]) idToWidgetInfo[eventInfo.srcElement] = $ax.getWidgetInfo(eventInfo.srcElement); eventInfo.thiswidget = idToWidgetInfo[eventInfo.srcElement]; eventInfo.item = $ax.getItemInfo(eventInfo.srcElement); if($ax.expr.evaluateExpr(filters[j].filter, eventInfo) != 'true') continue outer; } dataFiltered[dataFiltered.length] = data[i - 1]; } for(i = 0; i < dataFiltered.length; i++) data[i] = dataFiltered[i]; while(data.length > dataFiltered.length) data.pop(); eventInfo.targetElement = oldTarget; eventInfo.srcElement = oldSrc; eventInfo.thiswidget = oldThis; eventInfo.item = oldItem; } }; var _addFilter = function(repeaterId, removeOtherFilters, label, filter, thisId) { if(removeOtherFilters) _removeFilter(repeaterId); var filterList = repeaterToFilters[repeaterId]; if(!filterList) repeaterToFilters[repeaterId] = filterList = []; var filterObj = { filter: filter, thisId: thisId }; if(label) filterObj.label = label; filterList[filterList.length] = filterObj; }; _repeaterManager.addFilter = _addFilter; var _removeFilter = function(repeaterId, label) { var filterList = repeaterToFilters[repeaterId]; // If no list, nothing to remove if(!filterList) return; // If no label, remove everything if(!label) { repeaterToFilters[repeaterId] = []; return; } for(var i = filterList.length - 1; i >= 0; i--) { var filterObj = filterList[i]; if(filterObj.label && filterObj.label == label) $ax.splice(filterList, i, 1); } }; _repeaterManager.removeFilter = _removeFilter; var _addSort = function(repeaterId, label, columnName, ascending, toggle, sortType) { var sortList = repeaterToSorts[repeaterId]; if(!sortList) repeaterToSorts[repeaterId] = sortList = []; for(var i = 0; i < sortList.length; i++) { if(columnName == sortList[i].columnName) { var lastSortObj = $ax.splice(sortList, i, 1)[0]; if(toggle) ascending = !lastSortObj.ascending; break; } } var sortObj = { columnName: columnName, ascending: ascending, sortType: sortType }; if(label) sortObj.label = label; sortList[sortList.length] = sortObj; }; _repeaterManager.addSort = _addSort; var _removeSort = function(repeaterId, label) { var sortList = repeaterToSorts[repeaterId]; // If no list, nothing to remove if(!sortList) return; // If no label, remove everything if(!label) { repeaterToSorts[repeaterId] = []; return; } for(var i = sortList.length - 1; i >= 0; i--) { var sortObj = sortList[i]; if(sortObj.label && sortObj.label == label) $ax.splice(sortList, i, 1); } }; _repeaterManager.removeSort = _removeSort; var _setRepeaterToPage = function(repeaterId, type, value, eventInfo) { var pageInfo = repeaterToPageInfo[repeaterId]; // page doesn't matter if there is no limit. if(pageInfo.noLimit) return; var dataSet = repeaterToActiveDataSet[repeaterId]; if(!dataSet) dataSet = repeaterToCurrentDataSet[repeaterId]; var lastPage = Math.max(1, Math.ceil(dataSet.length / pageInfo.itemsPerPage)); if(type == 'Value') { var val = Number($ax.expr.evaluateExpr(value, eventInfo)); // if invalid, default to 1, otherwise, clamp the value if(isNaN(val)) val = 1; else if(val < 1) val = 1; else if(val > lastPage) val = lastPage; pageInfo.currPage = val; } else if(type == 'Previous') { if(pageInfo.currPage > 1) pageInfo.currPage--; } else if(type == 'Next') { if(pageInfo.currPage < lastPage) pageInfo.currPage++; } else if(type == 'Last') { pageInfo.currPage = lastPage; } else { console.log('Unknown type'); } }; _repeaterManager.setRepeaterToPage = _setRepeaterToPage; var _setNoItemLimit = function(repeaterId) { var pageInfo = repeaterToPageInfo[repeaterId]; delete pageInfo.currPage; delete pageInfo.itemsPerPage; pageInfo.noLimit = true; }; _repeaterManager.setNoItemLimit = _setNoItemLimit; var _setItemLimit = function(repeaterId, value, eventInfo) { var pageInfo = repeaterToPageInfo[repeaterId]; if(pageInfo.noLimit) { pageInfo.noLimit = false; pageInfo.currPage = 1; } var oldTarget = eventInfo.targetElement; eventInfo.targetElement = repeaterId; var itemLimit = Number($ax.expr.evaluateExpr(value, eventInfo)); eventInfo.targetElement = oldTarget; if(isNaN(itemLimit)) itemLimit = 20; else if(itemLimit < 1) itemLimit = 1; pageInfo.itemsPerPage = itemLimit; }; _repeaterManager.setItemLimit = _setItemLimit; var removeItems = function(repeaterId) { var elementIds = $ax.getChildElementIdsForRepeater(repeaterId); var itemId = $ax.getItemIdsForRepeater(repeaterId); for(var i = 0; i < itemId.length; i++) $jobj(_createElementId(repeaterId, itemId[i])).remove(); $ax.visibility.clearLimboAndHiddenIds(elementIds); $ax.clearItemsForRepeater(repeaterId); }; var repeaterSizes = {}; var resetItemSizes = function (repeaterId, itemSize, bounds, ids, vertical, wrap) { var calcItem = !itemSize; if(calcItem) itemSize = {}; var repeaterMap = {}; repeaterMap.vert = vertical; var sizesMap = {}; var sizes = []; var currSizes = wrap == -1 ? sizes : []; for(var i = 0; i + bounds[0] < bounds[1]; i++) { var itemId = ids[i + bounds[0]]; if(calcItem) { var itemJobj = $jobj(_createElementId(repeaterId, itemId)); itemSize.width = $ax.getNumFromPx(itemJobj.css('width')); itemSize.height = $ax.getNumFromPx(itemJobj.css('height')); } var size = { itemId: itemId, width: itemSize.width, height: itemSize.height }; currSizes.push(size); sizesMap[size.itemId] = size; if(currSizes.length == wrap) { sizes.push(currSizes); currSizes = []; } } if (wrap != -1 && currSizes.length > 0) sizes.push(currSizes); repeaterMap.sizes = sizes; repeaterMap.sizesMap = sizesMap; repeaterSizes[repeaterId] = repeaterMap; }; _repeaterManager.getItemSize = function(repeaterId, itemId) { var repeaterSize = repeaterSizes[repeaterId]; if (!repeaterSize) return false; return repeaterSize.sizesMap[itemId]; } _repeaterManager.setItemSize = function (repeaterId, itemId, width, height) { var repeaterSize = repeaterSizes[repeaterId]; if(!repeaterSize) return false; var size = repeaterSize.sizesMap[itemId]; var deltaX = width - size.width; var deltaY = height - size.height; if(!deltaX && !deltaY) return false; repeaterSize.resized = true; if(deltaX) _pushItems(repeaterId, itemId, deltaX, false, true); if(deltaY) _pushItems(repeaterId, itemId, deltaY, true, true); if(deltaX || deltaY) $ax.event.raiseSyntheticEvent(_createElementId(repeaterId, itemId), 'onItemResize'); return true; } var _pushItems = _repeaterManager.pushItems = function (repeaterId, itemId, delta, vertical, suppressFire) { if(delta == 0) return; // Update repeater item size var prop = vertical ? 'height' : 'width'; var itemObj = $jobj(_createElementId(repeaterId, itemId)); itemObj.css(prop, $ax.getNumFromPx(itemObj.css(prop)) + delta); var repeaterObj = $jobj(repeaterId); var repeaterMap = repeaterSizes[repeaterId]; var sizes = repeaterMap.sizes; var wrap = sizes[0].length != undefined; var vert = repeaterMap.vert; // Not wrapping, has to push in primary direction if (!wrap && vert != vertical) { var before = 0; var after = 0; var limit = 0; for(var i = 0; i < sizes.length; i++) { var size = sizes[i]; if(size.itemId == itemId) { before = size[prop]; size[prop] += delta; after = size[prop]; } else { limit = limit ? Math.max(limit, size[prop]) : size[prop]; } } // Repeater delta is because an item can increase secondary direction, but if another item is already larger, then repeater size isn't effected. var repeaterDelta = delta; if(sizes.length != 1) { if(after >= limit) repeaterDelta = after - Math.max(limit, before); else if(before > limit) repeaterDelta = limit - before; else repeaterDelta = 0; } _updateRepeaterSize(prop, repeaterObj, repeaterDelta, vert); if(!suppressFire) $ax.event.raiseSyntheticEvent(_createElementId(repeaterId, itemId), 'onItemResize'); return; } var index = 0; var index2 = 0; // Get the indices first if(wrap) { outer: for(; index < sizes.length; index++) { var innerSizes = sizes[index]; for(index2 = 0; index2 < innerSizes.length; index2++) if(innerSizes[index2].itemId == itemId) break outer; } } else { for(; index < sizes.length; index++) if(sizes[index].itemId == itemId) break; } // Find out who is being pushed var itemIdsEffected = []; if (vert == vertical) { // To check for repeater resize, non-wrap is easy, for wrap you have to see if your new size is enough to effect the size given other col/row sizes. repeaterDelta = delta; if(wrap && sizes.length > 1) { var viewId = $ax.adaptive.currentViewId || ''; var spacing = _getAdaptiveProp($obj(repeaterId).repeaterPropMap, (vert ? 'vertical' : 'horizontal') + 'Spacing', viewId); for(i = 0; i < sizes.length; i++) { var rowColSize = 0; var rowCol = sizes[i]; for(var j = 0; j < rowCol.length; j++) { if(j != 0) rowColSize += spacing; rowColSize += rowCol[j][prop]; } if(i == index) { before = rowColSize; after = before + delta; } else { limit = limit ? Math.max(limit, rowColSize) : rowColSize; } } if(after >= limit) repeaterDelta = after - Math.max(limit, before); else if (before > limit) repeaterDelta = limit - before; else repeaterDelta = 0; } if (repeaterDelta) { _updateRepeaterSize(prop, repeaterObj, repeaterDelta, vert); } // Done the hard part, calculating/updating new repeater size. Now just resize items and find what to push. var array = wrap ? sizes[index] : sizes; i = wrap ? index2 : index; array[i][prop] += delta; for(i++; i < array.length; i++) itemIdsEffected.push(array[i].itemId); } else { // Secondary push is more interesting. See how much your primary row/column is already pushing, if that changes // then effect all rows/columns after it // Get the biggest one in the current row/column, ignoring the one we're changing var biggest = 0; var currSizes = sizes[index]; for(i = 0; i < currSizes.length; i++) { if (i == index2) continue; biggest = Math.max(biggest, currSizes[i][prop]); } var beforeSize = Math.max(biggest, currSizes[index2][prop]); currSizes[index2][prop] += delta; var afterSize = Math.max(biggest, currSizes[index2][prop]); // Nothing pushed/pulled if (afterSize == beforeSize) return; for(i = index + 1; i < sizes.length; i++) { currSizes = sizes[i]; for(j = 0; j < currSizes.length; j++) itemIdsEffected.push(currSizes[j].itemId); } // Delta is only how much the whole row/column changed delta = afterSize - beforeSize; // Repeater resize secondary is determined by the effective delta. _updateRepeaterSize(prop, repeaterObj, delta, vert); } for(i = 0; i < itemIdsEffected.length; i++) { var currItemId = itemIdsEffected[i]; var elementId = _createElementId(repeaterId, currItemId); var loc = vertical ? 'top' : 'left'; var jobj = $jobj(elementId); var currVal = Number(jobj.css(loc).replace('px', '')); jobj.css(loc, currVal + delta); } if(!suppressFire) $ax.event.raiseSyntheticEvent(_createElementId(repeaterId, itemId), 'onItemResize'); } var _updateRepeaterSize = function(prop, jobj, delta, vert) { if (delta == 0) return; var val = $ax.getNumFromPx(jobj.css(prop)) + delta; var border = 0; if(vert) border += $ax.getNumFromPx(jobj.css('border-top-width')) + $ax.getNumFromPx(jobj.css('border-bottom-width')); else border += $ax.getNumFromPx(jobj.css('border-left-width')) + $ax.getNumFromPx(jobj.css('border-right-width')); val += border; jobj.css(prop, val); $ax.dynamicPanelManager.fitParentPanel(jobj.attr('id')); } var _getDataFromDataSet = function (eventInfo, repeaterId, itemId, propName, type) { var row = undefined; var deleteMap = eventInfo && eventInfo.repeaterDeleteMap && eventInfo.repeaterDeleteMap[repeaterId]; if(deleteMap) row = deleteMap.idToRow[itemId]; if(!row) { var itemNum = _getRealItemId(eventInfo, repeaterId, Number(itemId)); row = repeaterToCurrentDataSet[repeaterId][itemNum]; } // Default to obj with text as empty string, as we don't generate the data for empty props var data = row[propName] || { text: '' }; //For now text is always the default. May change this to depend on context. switch(type) { case 'data': return data.type == 'text' ? data.text : data case 'img': return (data.img && data.img[$ax.adaptive.getSketchKey()]) || data.text; default: return (type && data[type]) || data.text; } //return type == 'data' && data.type != 'text' ? data : (type && data[type]) || data['text']; }; _repeaterManager.getData = _getDataFromDataSet; _repeaterManager.hasData = function(id, propName) { if(!_getItemIdFromElementId(id)) return false; var repeaterId = $ax.getParentRepeaterFromScriptId(_getScriptIdFromElementId(id)); return Boolean(repeaterToCurrentDataSet[repeaterId] && repeaterToCurrentDataSet[repeaterId].props.indexOf(propName) != -1); }; var _getEventDeleteData = function(eventInfo, repeaterId) { var repeaterDeleteMap = eventInfo.repeaterDeleteMap; if(!repeaterDeleteMap) repeaterDeleteMap = eventInfo.repeaterDeleteMap = {}; var myDeleteMap = repeaterDeleteMap[repeaterId]; if(!myDeleteMap) { myDeleteMap = repeaterDeleteMap[repeaterId] = {}; myDeleteMap.deletedIds = []; myDeleteMap.idToRow = {}; } return myDeleteMap; }; var _getRealItemId = function(eventInfo, repeaterId, itemId) { var deletedBefore = 0; var map = eventInfo.repeaterDeleteMap && eventInfo.repeaterDeleteMap[repeaterId]; var deletedIds = map && map.deletedIds; if(!deletedIds) return itemId - 1; for(var i = 0; i < deletedIds.length; i++) if (deletedIds[i] < itemId) deletedBefore++; return itemId - deletedBefore - 1; } var _addItemToDataSet = function(repeaterId, row, itemEventInfo) { itemEventInfo.data = true; var oldTarget = itemEventInfo.targetElement; itemEventInfo.targetElement = repeaterId; var dataSet = repeaterToLocalDataSet[repeaterId]; for(var propName in row) { if(!row.hasOwnProperty(propName)) continue; var prop = row[propName]; if(prop.type == 'literal') { var retval = $ax.expr.evaluateExpr(prop.literal, itemEventInfo); if(typeof (retval) == 'string' || retval instanceof Date) retval = { type: 'text', text: retval }; row[propName] = retval; } } itemEventInfo.targetElement = oldTarget; dataSet[dataSet.length] = row; itemEventInfo.data = false; }; _repeaterManager.addItem = _addItemToDataSet; var _deleteItemsFromDataSet = function(repeaterId, eventInfo, type, rule) { var dataSet = repeaterToCurrentDataSet[repeaterId]; var deleteDataMap = _getEventDeleteData(eventInfo, repeaterId); var items; // Should always be this, marked, or rule. if(type == 'this') items = [_getItemIdFromElementId(eventInfo.srcElement)]; else if(type == 'marked') items = $ax.deepCopy(repeaterToEditItems[repeaterId]); else { // This should be rule var visibleData = repeaterToCurrentDataSet[repeaterId]; items = []; var oldTarget = eventInfo.targetElement; for(var i = 0; i < visibleData.length + deleteDataMap.deletedIds.length; i++) { var index = i + 1; if(deleteDataMap.deletedIds.indexOf(index) != -1) continue; eventInfo.targetElement = _createElementId(repeaterId, index); if($ax.expr.evaluateExpr(rule, eventInfo).toLowerCase() != 'true') continue; items.push(index); } eventInfo.targetElement = oldTarget; } // Want them decending items.sort(function(a, b) { return b - a; }); var editItems = repeaterToEditItems[repeaterId]; for(i = 0; i < items.length; i++) { var itemId = items[i]; // Don't delete already deletedItem if(deleteDataMap.deletedIds.indexOf(itemId) != -1) continue; var deletedRow = $ax.splice(dataSet, _getRealItemId(eventInfo, repeaterId, itemId), 1)[0]; deleteDataMap.deletedIds.push(itemId); deleteDataMap.idToRow[itemId] = deletedRow; for(var j = editItems.length - 1; j >= 0; j--) { var editItem = editItems[j]; if(editItem == itemId) $ax.splice(editItems, j, 1); else if(editItem > itemId) editItems[j] = editItem - 1; } } }; _repeaterManager.deleteItems = _deleteItemsFromDataSet; var _updateEditItemsInDataSet = function(repeaterId, propMap, eventInfo, type, rule) { var oldTarget = eventInfo.targetElement; var dataSet = repeaterToCurrentDataSet[repeaterId]; var items; // Should always be this, marked, or rule. if(type == 'this') items = [_getItemIdFromElementId(eventInfo.srcElement)]; else if(type == 'marked') items = repeaterToEditItems[repeaterId]; else { // This should be rule var currData = repeaterToCurrentDataSet[repeaterId]; items = []; oldTarget = eventInfo.targetElement; for(var i = 0; i < currData.length; i++) { var index = i + 1; eventInfo.targetElement = _createElementId(repeaterId, index); if($ax.expr.evaluateExpr(rule, eventInfo).toLowerCase() != 'true') continue; items.push(index); } eventInfo.targetElement = oldTarget; } eventInfo.data = true; for(var prop in propMap) { if(!propMap.hasOwnProperty(prop)) continue; for(i = 0; i < items.length; i++) { var data = propMap[prop]; var item = items[i]; if(data.type == 'literal') { eventInfo.targetElement = _createElementId(repeaterId, item); data = $ax.expr.evaluateExpr(data.literal, eventInfo); if(typeof (data) == 'object' && data.isWidget) data = data.text; if(typeof (data) == 'string') data = { type: 'text', text: data }; } dataSet[_getRealItemId(eventInfo, repeaterId, item)][prop] = data; } } eventInfo.targetElement = oldTarget; eventInfo.data = false; }; _repeaterManager.updateEditItems = _updateEditItemsInDataSet; var _getAllItemIds = function(repeaterId) { var retval = []; var currDataSet = repeaterToCurrentDataSet[repeaterId]; for(var i = 0; i < currDataSet.length; i++) retval.push(i + 1); return retval; }; _repeaterManager.getAllItemIds = _getAllItemIds; var _addEditItemToRepeater = function(repeaterId, itemIds) { for(var i = 0; i < itemIds.length; i++) { var itemId = Number(itemIds[i]); var items = repeaterToEditItems[repeaterId]; if(items.indexOf(itemId) == -1) items[items.length] = itemId; } }; _repeaterManager.addEditItems = _addEditItemToRepeater; var _removeEditItemFromRepeater = function(repeaterId, itemIds) { for(var i = 0; i < itemIds.length; i++) { var itemId = itemIds[i]; var items = repeaterToEditItems[repeaterId]; var index = items.indexOf(Number(itemId)); if(index != -1) $ax.splice(items, index, 1); } }; _repeaterManager.removeEditItems = _removeEditItemFromRepeater; _repeaterManager.isEditItem = function(repeaterId, itemId) { var items = repeaterToEditItems[repeaterId]; return items.indexOf(Number(itemId)) != -1; }; var _createElementId = function(scriptId, itemId) { if(!itemId) return scriptId; var i = scriptId.indexOf('_'); var sections = i > -1 ? [scriptId.substring(0, i), scriptId.substring(i + 1)] : [scriptId]; var retval = sections[0] + '-' + itemId; return sections.length > 1 ? retval + '_' + sections[1] : retval; }; _repeaterManager.createElementId = _createElementId; var _getElementId = function(scriptId, childId) { var elementId = scriptId; if($ax.getParentRepeaterFromScriptId(scriptId)) { // Must be in the same item as the child var itemId = $ax.repeater.getItemIdFromElementId(childId); elementId = $ax.repeater.createElementId(scriptId, itemId); } return elementId; }; _repeaterManager.getElementId = _getElementId; var _getScriptIdFromElementId = function(elementId) { if(!elementId) return elementId; var sections = elementId.split('-'); var retval = sections[0]; if(sections.length <= 1) return retval; sections = sections[1].split('_'); return sections.length > 1 ? retval + '_' + sections[1] : retval; }; _repeaterManager.getScriptIdFromElementId = _getScriptIdFromElementId; var _getItemIdFromElementId = function(elementId) { var sections = elementId.split('-'); if(sections.length < 2) return ''; sections = sections[1].split('_'); return sections[0]; }; _repeaterManager.getItemIdFromElementId = _getItemIdFromElementId; // TODO: Just inline this if we keep it this way. var _applySuffixToElementId = function(id, suffix) { return id + suffix; // return _createElementId(_getScriptIdFromElementId(id) + suffix, _getItemIdFromElementId(id)); }; _repeaterManager.applySuffixToElementId = _applySuffixToElementId; var _removeSuffixFromElementId = function(id) { if (id.indexOf('_') != -1) return id.split('_', 1)[0]; return id; } _repeaterManager.removeSuffixFromElementId = _removeSuffixFromElementId; // var _getRepeaterSize = function(repeaterId) { // var itemCount = ($ax.getItemIdsForRepeater(repeaterId) || []).length; // if(itemCount == 0) return { width: 0, height: 0 }; // var repeater = $obj(repeaterId); // // Width and height per item; // var width = repeater.width; // var height = repeater.height; // var viewId = $ax.adaptive.currentViewId || ''; // var widthIncrement = width + _getAdaptiveProp(repeater.repeaterPropMap, 'horizontalSpacing', viewId); // var heightIncrement = height + _getAdaptiveProp(repeater.repeaterPropMap, 'verticalSpacing', viewId); // var wrap = _getAdaptiveProp(repeater.repeaterPropMap, 'wrap', viewId); // var vertical = _getAdaptiveProp(repeater.repeaterPropMap, 'vertical', viewId); // if(wrap == -1 || itemCount <= wrap) { // if(vertical) height += heightIncrement * (itemCount - 1); // else width += widthIncrement * (itemCount - 1); // } else { // var primaryDim = wrap; // var secondaryDim = Math.ceil(itemCount / primaryDim); // if(vertical) { // height += heightIncrement * (primaryDim - 1); // width += widthIncrement * (secondaryDim - 1); // } else { // width += widthIncrement * (primaryDim - 1); // height += heightIncrement * (secondaryDim - 1); // } // } // return { width: width, height: height }; // }; // _repeaterManager.getRepeaterSize = _getRepeaterSize; }); // ******* Dynamic Panel Manager ******** // $axure.internal(function($ax) { // TODO: Probably a lot of the dynamic panel functions from pagescript should be moved here at some point... var _dynamicPanelManager = $ax.dynamicPanelManager = {}; var _isIdFitToContent = _dynamicPanelManager.isIdFitToContent = function(id) { var obj = $obj(id); if (!obj || !$ax.public.fn.IsDynamicPanel(obj.type) || !obj.fitToContent) return false; var jpanel = $jobj(id); return !jpanel.attr('data-notfit'); }; //this function fit parent panel, also check for parent layer or repeaters var _fitParentPanel = function (widgetId) { var parentLayer = getParentLayer(widgetId); if(parentLayer) { if(_updateLayerRectCache(parentLayer)) _fitParentPanel(parentLayer); return; } // Find parent panel if there is one. var parentPanelInfo = getParentPanel(widgetId); if(parentPanelInfo) { var parentId = parentPanelInfo.parent; if(_updateFitPanel(parentId, parentPanelInfo.state)) _fitParentPanel(parentId); return; } // Otherwise, try to get parent repeater var parentRepeaterId = $ax.getParentRepeaterFromElementId(widgetId); var repeaterObj = $obj(parentRepeaterId); if(!repeaterObj || widgetId == parentRepeaterId || !repeaterObj.repeaterPropMap.fitToContent) return; var itemId = $ax.repeater.getItemIdFromElementId(widgetId); var size = getContainerSize($ax.repeater.createElementId(parentRepeaterId, itemId)); $ax.repeater.setItemSize(parentRepeaterId, itemId, size.width, size.height); }; _dynamicPanelManager.fitParentPanel = _fitParentPanel; _dynamicPanelManager.initialize = function() { $axure.resize(_handleResize); }; var percentPanelToLeftCache = []; var percentPanelsInitialized = false; var _handleResize = function() { if(percentPanelsInitialized) { for(var key in percentPanelToLeftCache) { //could optimize to only update non-contained panels _updatePanelPercentWidth(key); } } else { $ax('*').each(function(obj, elementId) { if(_isPercentWidthPanel(obj)) _updatePanelPercentWidth(elementId); }); percentPanelsInitialized = true; } }; var _isPercentWidthPanel = _dynamicPanelManager.isPercentWidthPanel = function(obj) { return obj && $ax.public.fn.IsDynamicPanel(obj.type) && obj.percentWidth; }; _dynamicPanelManager.updatePanelContentPercentWidth = function(elementId) { // if(_isPercentWidthPanel($obj(elementId))) return; var stateChildrenQuery = $jobj(elementId).children('.panel_state'); stateChildrenQuery.children('.panel_state_content').each( function() { $(this).children('.ax_dynamic_panel').each( function() { _updatePanelPercentWidth(this.id); } ); } ); }; _dynamicPanelManager.updatePercentPanelCache = function(query) { query.each(function(obj, elementId) { if(_isPercentWidthPanel(obj)) { if(_updatePercentPanelToLeftCache(obj, elementId, true)) { _updatePanelPercentWidth(elementId); } } }); }; _dynamicPanelManager.resetFixedPanel = function(obj, domElement) { if(obj.fixedHorizontal == 'center') domElement.style.marginLeft = ""; if(obj.fixedVertical == 'middle') domElement.style.marginTop = ""; }; _dynamicPanelManager.resetAdaptivePercentPanel = function(obj, domElement) { if(!_isPercentWidthPanel(obj)) return; if(obj.fixedHorizontal == 'center') domElement.style.marginLeft = ""; else if(obj.fixedHorizontal == 'right') domElement.style.width = ""; }; var _updatePercentPanelToLeftCache = function(obj, elementId, overwrite) { var wasUpdated = false; var jObj = $jobj(elementId); var axObj = $ax('#' + elementId); if(percentPanelToLeftCache[elementId] == undefined || overwrite) { if(obj.fixedHorizontal == 'center') percentPanelToLeftCache[elementId] = Number(jObj.css('margin-left').replace("px", "")); else if(obj.fixedHorizontal == 'right') percentPanelToLeftCache[elementId] = axObj.width() + Number(jObj.css('right').replace("px", "")); else percentPanelToLeftCache[elementId] = Number(jObj.css('left').replace("px", "")); wasUpdated = true; } if(obj.fixedHorizontal == 'right' && _isIdFitToContent(elementId)) { var fitWidth = getContainerSize($ax.visibility.GetPanelState(elementId) + '_content').width; percentPanelToLeftCache[elementId] = fitWidth + Number(jObj.css('right').replace("px", "")); wasUpdated = true; } return wasUpdated; }; var _updatePanelPercentWidth = _dynamicPanelManager.updatePanelPercentWidth = function(elementId) { var obj = $obj(elementId); if(!_isPercentWidthPanel(obj)) return; _updatePercentPanelToLeftCache(obj, elementId, false); var width; var x; if(obj.fixedHorizontal) { x = 0; width = $(window).width(); } else { var parentPanelInfo = getParentPanel(elementId); if(parentPanelInfo) { var parentId = parentPanelInfo.parent; width = $ax('#' + parentId).width(); var parentObj = $obj(parentId); if(parentObj.percentWidth) { var stateId = $ax.repeater.applySuffixToElementId(parentId, '_state' + parentPanelInfo.state); var stateContentId = stateId + '_content'; x = -Number($jobj(stateContentId).css('margin-left').replace("px", "")); } else x = 0; } else { var parentRepeater = $ax.getParentRepeaterFromScriptId($ax.repeater.getScriptIdFromElementId(elementId)); if(parentRepeater) { var itemId = $ax.repeater.getItemIdFromElementId(elementId); var itemContainerId = $ax.repeater.createElementId(parentRepeater, itemId); x = 0; width = $ax('#' + itemContainerId).width(); } else { var $window = $(window); width = $window.width(); var bodyLeft = Number($('body').css('left').replace("px", "")); var bodyWidth = Number($('body').css('width').replace("px", "")); var isCenter = $ax.adaptive.getPageStyle().pageAlignment == 'center'; width = Math.max(width, bodyWidth); x = isCenter ? -(width - bodyWidth) / 2 - bodyLeft : 0; } } } var jObj = $jobj(elementId); if(obj.fixedHorizontal == 'left') jObj.css('left', x + 'px'); else if(obj.fixedHorizontal == 'center') { jObj.css('left', x + 'px'); jObj.css('margin-left', 0 + 'px'); } else jObj.css('left', x + 'px'); jObj.css('width', width + 'px'); var panelLeft = percentPanelToLeftCache[elementId]; var stateParent = jObj; while(stateParent.children()[0].id.indexOf($ax.visibility.CONTAINER_SUFFIX) != -1) stateParent = stateParent.children(); var stateChildrenQuery = stateParent.children('.panel_state'); stateChildrenQuery.css('width', width + 'px'); if(obj.fixedHorizontal == 'center') stateChildrenQuery.children('.panel_state_content').css('left', '50%').css('margin-left', panelLeft + 'px'); else if(obj.fixedHorizontal == 'right') stateChildrenQuery.children('.panel_state_content').css('left', width - panelLeft + 'px'); else stateChildrenQuery.children('.panel_state_content').css('margin-left', panelLeft - x + 'px'); }; _dynamicPanelManager.updateParentsOfNonDefaultFitPanels = function () { $ax('*').each(function (diagramObject, elementId) { if(!$ax.public.fn.IsDynamicPanel(diagramObject.type) || !diagramObject.fitToContent) return; if($ax.visibility.isElementIdLimboOrInLimboContainer(elementId)) return; var stateId = $ax.visibility.GetPanelState(elementId); if(stateId != $ax.repeater.applySuffixToElementId(elementId, '_state0')) _fitParentPanel(elementId); }); }; //_dynamicPanelManager.updateAllFitPanelsAndLayerSizeCaches = function() { // var fitToContent = []; // var layers = []; // $ax('*').each(function (obj, elementId) { // var isFitPanel = $ax.public.fn.IsDynamicPanel(obj.type) && obj.fitToContent; // var isLayer = $ax.public.fn.IsLayer(obj.type); // if(!isFitPanel && !isLayer) return; // if($ax.visibility.isElementIdLimboOrInLimboContainer(elementId)) return; // if(isFitPanel) { // fitToContent[fitToContent.length] = elementId; // } else if(isLayer) { // layers[layers.length] = elementId; // } // }); // for(var i = fitToContent.length - 1; i >= 0; i--) { // var panelId = fitToContent[i]; // var stateCount = $obj(panelId).diagrams.length; // for(var j = 0; j < stateCount; j++) { // $ax.dynamicPanelManager.setFitToContentCss(panelId, true); // _updateFitPanel(panelId, j, true); // } // } // for(var i = layers.length - 1; i >= 0; i--) { // var layerId = layers[i]; // _updateLayerSizeCache(layerId); // } //}; var _getCachedLayerRect = function (elementId) { var element = document.getElementById(elementId); var rect = {}; rect.width = Number(element.getAttribute('data-width')); rect.height = Number(element.getAttribute('data-height')); rect.x = Number(element.getAttribute('data-left')); rect.y = Number(element.getAttribute('data-top')); return rect; } var _updateLayerRectCache = function (elementId) { var oldRect = _getCachedLayerRect(elementId); var axObj = $ax('#' + elementId); var size = axObj.size(); var loc = {}; loc.x = axObj.locRelativeIgnoreLayer(false); loc.y = axObj.locRelativeIgnoreLayer(true); var sizeChange = oldRect.width != size.width || oldRect.height != size.height; var locChange = oldRect.x != loc.x || oldRect.y != loc.y; if(sizeChange || locChange) { var element = document.getElementById(elementId); if(sizeChange) { element.setAttribute('data-width', size.width); element.setAttribute('data-height', size.height); $ax.event.raiseSyntheticEvent(elementId, 'onResize'); } if(locChange) { element.setAttribute('data-left', loc.x); element.setAttribute('data-top', loc.y); $ax.event.raiseSyntheticEvent(elementId, 'onMove'); } return true; } return false; } _dynamicPanelManager.setFitToContentCss = function(elementId, fitToContent, oldWidth, oldHeight) { if($ax.dynamicPanelManager.isIdFitToContent(elementId) == fitToContent) return; var panel = $jobj(elementId); var stateCss; var scrollbars = $obj(elementId).scrollbars; if(fitToContent) { panel.attr('style', ''); panel.removeAttr('data-notfit'); stateCss = {}; stateCss.position = 'relative'; if(scrollbars != 'none') { stateCss.overflow = 'visible'; stateCss['-webkit-overflow-scrolling'] = 'visible'; } if(scrollbars == 'verticalAsNeeded') { stateCss['overflow-x'] = 'visible'; stateCss['-ms-overflow-x'] = 'visible'; } else if(scrollbars == 'horizontalAsNeeded') { stateCss['overflow-y'] = 'visible'; stateCss['-ms-overflow-y'] = 'visible'; } panel.children().css(stateCss); } else { panel.attr('data-notfit', 'true'); var panelCss = { width: oldWidth, height: oldHeight }; stateCss = { width: oldWidth, height: oldHeight }; panelCss.overflow = 'hidden'; stateCss.position = 'absolute'; if(scrollbars != 'none') { stateCss.overflow = 'auto'; stateCss['-webkit-overflow-scrolling'] = 'touch'; } if(scrollbars == 'verticalAsNeeded') { stateCss['overflow-x'] = 'hidden'; stateCss['-ms-overflow-x'] = 'hidden'; } else if(scrollbars == 'horizontalAsNeeded') { stateCss['overflow-y'] = 'hidden'; stateCss['-ms-overflow-y'] = 'hidden'; } panel.css(panelCss); panel.children().css(stateCss); } }; var _getShownStateId = function (id) { var obj = $obj(id); if (!obj || !$ax.public.fn.IsDynamicPanel(obj.type)) return id; var children = $ax.visibility.applyWidgetContainer(id, true).children(); for (var i = 0; i < children.length; i++) { var child = children[i]; while ($ax.visibility.isContainer(child.id)) child = $(child).children()[0]; if (child && child.style && child.style.display != 'none') return child.id; } return id; }; var _getShownStateObj = function(id) { return $ax('#' + _getShownStateId(id));} _dynamicPanelManager.getShownState = function (id) { return $jobj(_getShownStateId(id)); }; var _getClamp = function(id) { var obj = $obj(id); if(!obj) return $ax('#' + id); if ($ax.public.fn.IsDynamicPanel(obj.type)) return _getShownStateObj(id); return $ax('#' + id); }; var _updateFitPanel = function(panelId, stateIndex, initializingView) { if(!panelId) return false; // Only fit if fitToContent is true if(!$ax.dynamicPanelManager.isIdFitToContent(panelId)) return false; // Traverse through children to find what size it should be. var stateId = $ax.repeater.applySuffixToElementId(panelId, '_state' + stateIndex); var stateContentId = stateId + '_content'; var stateQuery = $jobj(stateId); var size = getContainerSize(stateContentId); // Skip if size hasn't changed var oldWidth = stateQuery.width(); var oldHeight = stateQuery.height(); if(oldWidth == size.width && oldHeight == size.height) return false; if(!$obj(panelId).percentWidth) stateQuery.width(size.width); stateQuery.height(size.height); //updatePercentWidth on all child panels $jobj(stateContentId).children('.ax_dynamic_panel').each( function() { _updatePanelPercentWidth(this.id); } ); //do the following only if it is the current state if(stateId != $ax.visibility.GetPanelState(panelId)) return false; if(!initializingView) _adjustFixed(panelId, oldWidth, oldHeight, size.width, size.height); else if(stateIndex != 0) { var state0 = $jobj($ax.repeater.applySuffixToElementId(panelId, '_state0')); _adjustFixed(panelId, state0.width(), state0.height(), size.width, size.height); } $ax.event.raiseSyntheticEvent(panelId, 'onResize'); $ax.flyoutManager.updateFlyout(panelId); return true; }; // widgetId is the one that crawls up masters until it finds a parent panel, targetId is the original widgetId (not the crawling master) // finds the immediate parent panel and crawls up through masters but not repeaters var getParentPanel = function(widgetId, path, targetId) { path = path || $ax.getPathFromScriptId($ax.repeater.getScriptIdFromElementId(widgetId)); var obj = $obj(widgetId); if(obj.parentDynamicPanel) { path[path.length - 1] = obj.parentDynamicPanel; var parentId = $ax.getScriptIdFromPath(path); if(!parentId) return undefined; parentId = $ax.repeater.getElementId(parentId, widgetId); var parentObj = $obj(parentId); var retVal = { parent: parentId }; for(var i = 0; i < parentObj.diagrams.length; i++) { var stateId = $ax.repeater.applySuffixToElementId(parentId, '_state' + i); var stateQuery = $jobj(stateId); if(stateQuery.find('#' + (targetId || widgetId)).length != 0) { retVal.state = i; break; } } return retVal; } if(path.length == 1) return undefined; path.pop(); var parentMaster = $ax.getScriptIdFromPath(path); if(!parentMaster) return undefined; parentMaster = $ax.repeater.getElementId(parentMaster, widgetId); //check if the master is in the same repeater as the widgetId widget var parentMasterItemId = $ax.repeater.getItemIdFromElementId(parentMaster); var widgetItemId = $ax.repeater.getItemIdFromElementId(widgetId); if(parentMasterItemId != widgetItemId) return undefined; return getParentPanel(parentMaster, path, targetId || widgetId); }; // finds the immediate parent layer and crawls up through masters but not repeaters or panels var getParentLayer = function (widgetId, path) { path = path || $ax.getPathFromScriptId($ax.repeater.getScriptIdFromElementId(widgetId)); //gets immediate parent layer only var layerId = $ax.getLayerParentFromElementId(widgetId); if(layerId) return layerId; if(path.length == 1) return undefined; path.pop(); var parentMaster = $ax.getScriptIdFromPath(path); if(!parentMaster) return undefined; parentMaster = $ax.repeater.getElementId(parentMaster, widgetId); //check if the master is in the same panel as the widgetId widget var widgetParentPanel = getParentPanel(widgetId); if(widgetParentPanel) { var parentMasterParentPanel = getParentPanel(parentMaster); if(!parentMasterParentPanel || widgetParentPanel.parent != parentMasterParentPanel.parent) return undefined; } //check if the master is in the same repeater as the widgetId widget var parentMasterItemId = $ax.repeater.getItemIdFromElementId(parentMaster); var widgetItemId = $ax.repeater.getItemIdFromElementId(widgetId); if(parentMasterItemId != widgetItemId) return undefined; return getParentLayer(parentMaster, path); }; // TODO: May be a better location for this. Used currently for rdo and panel state containers var getContainerSize = function(containerId) { var containerQuery = containerId ? $jobj(containerId) : $('#base'); var children = containerQuery.children(); // Default size var size = { width: 0, height: 0 }; for(var i = 0; i < children.length; i++) { var child = $(children[i]); var childId = child.attr('id'); //var axChild = $ax('#' + childId).width(); var childObj = $obj(childId); if(!childObj) { // On the body there are some children that should be ignored, as they are not objects. if(!child.hasClass('basiclink') || child.get(0).tagName.toLowerCase() != 'a') continue; // Otherwise it should be a basic link var linkChildren = child.children(); if(!linkChildren.length) continue; child = $(linkChildren[0]); childId = child.attr('id'); childObj = $obj(childId); } // Ignore fixed if(!childId || $ax.visibility.limboIds[childId] || !$ax.visibility.IsIdVisible(childId) || $ax.public.fn.IsDynamicPanel(childObj.type) && childObj.fixedHorizontal) continue; var boundingRect = $ax.public.fn.getWidgetBoundingRect(childId); var position = { left: boundingRect.left, top: boundingRect.top }; var width = boundingRect.width; var height = boundingRect.height; if($ax.public.fn.IsMaster(childObj.type)) { var masterSize = getContainerSize(childId); width = masterSize.width; height = masterSize.height; // } else if($ax.public.fn.IsRepeater(childObj.type)) { // var repeaterSize = $ax.repeater.getRepeaterSize(childId); // width = repeaterSize.width; // height = repeaterSize.height; // if(width == 0 && height == 0) continue; // position.left += childObj.x; // position.top += childObj.y; } else if ($ax.public.fn.IsDynamicPanel(childObj.type)) { if($ax.dynamicPanelManager.isIdFitToContent(childId)) { var stateQuery = $jobj($ax.visibility.GetPanelState(childId)); width = stateQuery.width(); height = stateQuery.height(); } } size.width = Math.max(size.width, position.left + width); size.height = Math.max(size.height, position.top + height); } return size; }; var _adjustFixed = _dynamicPanelManager.adjustFixed = function(panelId, oldWidth, oldHeight, width, height) { var loc = _getFixedPosition(panelId, oldWidth, oldHeight, width, height); if(loc) { $ax.action.addAnimation(panelId, $ax.action.queueTypes.move, function() { $ax.move.MoveWidget(panelId, loc[0], loc[1], { easing: 'none', duration: 0 }, false, null, true); }); } }; var _getFixedPosition = _dynamicPanelManager.getFixedPosition = function(panelId, oldWidth, oldHeight, width, height) { var panelObj = $obj(panelId); var x = 0; var y = 0; if(panelObj.fixedHorizontal == 'center') { x = (oldWidth - width) / 2; } if(panelObj.fixedVertical == 'middle') { y = (oldHeight - height) / 2; } return x == 0 && y == 0 ? undefined : [x, y]; }; _dynamicPanelManager.getFixedInfo = function(panelId) { var panelObj = $obj(panelId); if (!panelObj || !$ax.public.fn.IsDynamicPanel(panelObj.type)) return {}; var jobj = $jobj(panelId); if(jobj.css('position') == 'absolute') return {}; var info = {}; var horizontal = panelObj.fixedHorizontal; if(!horizontal) return info; info.fixed = true; info.horizontal = horizontal; info.vertical = panelObj.fixedVertical; if(info.horizontal == 'left') info.x = Number(jobj.css('left').replace('px', '')); else if(info.horizontal == 'center') info.x = Number(jobj.css('margin-left').replace('px', '')); else if(info.horizontal == 'right') info.x = Number(jobj.css('right').replace('px', '')); if(info.vertical == 'top') info.y = Number(jobj.css('top').replace('px', '')); else if(info.vertical == 'middle') info.y = Number(jobj.css('margin-top').replace('px', '')); else if(info.vertical == 'bottom') info.y = Number(jobj.css('bottom').replace('px', '')); return info; }; // Show isn't necessary if this is always done before toggling (which is currently true), but I don't want that // change (if it happened) to break this. var _compressToggle = function (id, vert, show, easing, duration) { var layer = $ax.getTypeFromElementId(id) == $ax.constants.LAYER_TYPE; var locProp = vert ? 'top' : 'left'; var dimProp = vert ? 'height' : 'width'; var threshold; var delta; threshold = $ax('#' + id)[locProp](true); delta = layer ? $ax('#' + id)[dimProp]() : _getShownStateObj(id)[dimProp](); if(!show) { // Need to make threshold bottom/right threshold += delta; // Delta is in the opposite direction delta *= -1; } _compress(id, vert, threshold, delta, easing, duration); }; _dynamicPanelManager.compressToggle = _compressToggle; // Used when setting state of dynamic panel var _compressDelta = function(id, oldState, newState, vert, easing, duration) { var oldQuery = $jobj(oldState); var newQuery = $jobj(newState); var thresholdProp = vert ? 'top' : 'left'; var thresholdOffset = vert ? 'height' : 'width'; var threshold = $ax('#' + id)[thresholdProp](true); threshold += oldQuery[thresholdOffset](); var delta = newQuery[thresholdOffset]() - oldQuery[thresholdOffset](); var clampOffset = vert ? 'width' : 'height'; var clampWidth = Math.max(oldQuery[clampOffset](), newQuery[clampOffset]()); _compress(id, vert, threshold, delta, easing, duration, clampWidth); }; _dynamicPanelManager.compressDelta = _compressDelta; var _compress = function (id, vert, threshold, delta, easing, duration, clampWidth) { // If below, a horizantal clamp, otherwise a vertical clamp var clamp = { prop: vert ? 'left' : 'top', offset: vert ? 'width' : 'height' }; // Get clamp in coords relative to parent. Account for layers farther down if($ax.getTypeFromElementId(id) == $ax.constants.LAYER_TYPE) { clamp.start = $ax('#' + id)[clamp.prop](true); clamp.end = clamp.start + $ax('#' + id)[clamp.offset](); } else { var clampLoc = $jobj(id); if(typeof clampWidth == 'undefined') clampWidth = _getClamp(id)[clamp.offset](); clamp.start = Number(clampLoc.css(clamp.prop).replace('px', '')); clamp.end = clamp.start + clampWidth; } // If clamps, threshold, or delta is not a number, can't compress. if (isNaN(clamp.start) || isNaN(clamp.end) || isNaN(threshold) || isNaN(delta)) return; // Update clamp if fixed, to account for body position (only necessary when page centered) if($jobj(id).css('position') == 'fixed') { var clampDelta = $('#base').position().left; clamp.start -= clampDelta; clamp.end -= clampDelta; } if(!easing) { easing = 'none'; duration = 0; } var parent = $ax('#' + id).getParents(false, ['item', 'state', 'layer'])[0]; var obj = parent && $ax.getObjectFromElementId($ax.repeater.removeSuffixFromElementId(parent)); // Go until you hit a parent item or state, or a layer that is hidden to use as parent. // Account for layer container positions as you go. while(obj && $ax.public.fn.IsLayer(obj.type) && $ax.visibility.IsIdVisible(parent)) { var container = $ax.visibility.applyWidgetContainer(parent, true, true); // If layer is using container, offset is going to be necessary if(container.length) { var offsetX = $ax.getNumFromPx(container.css('left')); var offsetY = $ax.getNumFromPx(container.css('top')); var clampProp = clamp.prop == 'left' ? offsetX : offsetY; var threshProp = clamp.prop == 'left' ? offsetY : offsetX; threshold += threshProp; clamp.start += clampProp; clamp.end += clampProp; } parent = $ax('#' + parent).getParents(false, ['item', 'state', 'layer'])[0]; obj = parent && $ax.getObjectFromElementId($ax.repeater.removeSuffixFromElementId(parent)); } // Add container mid push causes strange behavior because we take container into account as we go down, but if after we accounted for it, // a container is added, that container is not accounted for with threshold and clamp values. var layer = obj && $ax.public.fn.IsLayer(obj.type) && parent; if(layer) { // If your parent layer is invisible, you want to be relative to it's container. That is true already if it has a container, // but if you are just adding one now, then you need to offset your values var needsOffset = !$jobj(layer + '_container').length && !$ax.visibility.IsIdVisible(layer); $ax.visibility.pushContainer(layer, false); if(needsOffset) { container = $jobj(layer + '_container'); offsetX = $ax.getNumFromPx(container.css('left')); offsetY = $ax.getNumFromPx(container.css('top')); clampProp = clamp.prop == 'left' ? offsetX : offsetY; threshProp = clamp.prop == 'left' ? offsetY : offsetX; threshold -= threshProp; clamp.start -= clampProp; clamp.end -= clampProp; } } // Note: If parent is body, some of these aren't widgets if(parent && $jobj(parent + '_content').length > 0) parent = parent + '_content'; if(parent && $jobj(parent + '_container').length > 0) parent = parent + '_container'; _compressChildrenHelper(id, $(parent ? '#' + parent : '#base').children(), vert, threshold, delta, clamp, easing, duration); if(layer) $ax.visibility.popContainer(layer, false); // Do item push var itemId = $ax.repeater.getItemIdFromElementId(id); if(!itemId) return; var repeaterId = $ax.getParentRepeaterFromElementId(id); // Only need to push when parent is an item directly. if(parent != $ax.repeater.createElementId(repeaterId, itemId)) return; // If repeater is fit to content, then don't worry about it, it'll be handled elsewhere if(!obj.repeaterPropMap.fitToContent) $ax.repeater.pushItems(repeaterId, itemId, delta, vert); }; var _compressChildrenHelper = function (id, children, vert, threshold, delta, clamp, easing, duration, parentLayer) { var toMove = []; var allMove = true; for (var i = 0; i < children.length; i++) { var child = $(children[i]); //don't move fixed if(child.css('position') == 'fixed') continue; // Check for basic links if(child[0] && child[0].tagName == 'A' && child.hasClass('basiclink')) child = child.children(); var childId = child.attr('id'); // Don't move self, and check id to make sure it is a widget. if(childId == id || !childId || childId[0] != 'u') { allMove = false; continue; } if ($ax.getTypeFromElementId(childId) == $ax.constants.LAYER_TYPE) { $ax.visibility.pushContainer(childId, false); var addSelf; var container = $ax.visibility.applyWidgetContainer(childId, true, true); var layerChildren = $ax.visibility.getRealChildren(child.children()); //if(container.length) { var offsetX = -$ax.getNumFromPx(container.css('left')); var offsetY = -$ax.getNumFromPx(container.css('top')); var clampProp = clamp.prop == 'left' ? offsetX : offsetY; var threshProp = clamp.prop == 'left' ? offsetY : offsetX; var layerClamp = { prop: clamp.prop, offset: clamp.offset, start: clamp.start + clampProp, end: clamp.end + clampProp }; addSelf = _compressChildrenHelper(id, layerChildren, vert, threshold + threshProp, delta, layerClamp, easing, duration, childId); //} else addSelf = _compressChildrenHelper(id, layerChildren, vert, threshold, delta, clamp, easing, duration, childId); if(addSelf) toMove.push(childId); else allMove = false; $ax.visibility.popContainer(childId, false); continue; } var numbers = childId.substring(1).split('-'); if(numbers.length < 1 || isNaN(Number(numbers[0])) || (numbers.length == 2 && isNaN(Number(numbers[1]))) || numbers.length > 2) continue; var marker, childClamp; var axChild = $ax('#' + childId); var markerProp = vert ? 'top' : 'left'; marker = Number(axChild[markerProp](true)); childClamp = [Number(axChild[clamp.prop](true))]; // Dynamic panels are not reporting correct size sometimes, so pull it from the state. Get shown state just returns the widget if it is not a dynamic panel. var sizeChild = _getShownStateObj(childId); childClamp[1] = childClamp[0] + sizeChild[clamp.offset](); if(isNaN(marker) || isNaN(childClamp[0]) || isNaN(childClamp[1]) || marker < threshold || childClamp[1] <= clamp.start || childClamp[0] >= clamp.end) { allMove = false; continue; } toMove.push(childId); } if (allMove && parentLayer) { return true; } else { for(var i = 0; i < toMove.length; i++) { $ax('#' + toMove[i]).moveBy(vert ? 0 : delta, vert ? delta : 0, easing == 'none' ? {} : { duration: duration, easing: easing }); } } return false; }; var _parentHandlesStyles = function(id) { var parents = $ax('#' + id).getParents(true, ['dynamicPanel', 'layer'])[0]; if(!parents) return false; var directParent = true; for(var i = 0; i < parents.length; i++) { var parentId = parents[i]; var parentObj = $obj(parentId); if(!parentObj.propagate) { directParent = false; continue; } return { id: parentId, direct: directParent }; } return false; }; _dynamicPanelManager.parentHandlesStyles = _parentHandlesStyles; var _propagateMouseOver = function(id, value) { propagate(id, true, value); }; _dynamicPanelManager.propagateMouseOver = _propagateMouseOver; var _propagateMouseDown = function(id, value) { propagate(id, false, value); }; _dynamicPanelManager.propagateMouseDown = _propagateMouseDown; var propagate = function(id, hover, value) { var hoverChildren = function(children) { if(!children) return; for(var i = 0; i < children.length; i++) { var elementId = children[i].id; var obj = $obj(elementId); if(obj == null) { elementId = elementId.split('_')[0]; obj = $obj(elementId); } if(obj == null) continue; if (($ax.public.fn.IsDynamicPanel(obj.type) || $ax.public.fn.IsLayer(obj.type)) && !obj.propagate) continue; if(hover) $ax.style.SetWidgetHover(elementId, value); else $ax.style.SetWidgetMouseDown(elementId, value); $ax.annotation.updateLinkLocations($ax.style.GetTextIdFromShape(elementId)); hoverChildren(children[i].children); } }; hoverChildren($ax('#' + id).getChildren(true)[0].children); }; }); //***** sto.js *****// $axure.internal(function($ax) { var funcs = {}; var weekday = new Array(7); weekday[0] = "Sunday"; weekday[1] = "Monday"; weekday[2] = "Tuesday"; weekday[3] = "Wednesday"; weekday[4] = "Thursday"; weekday[5] = "Friday"; weekday[6] = "Saturday"; funcs.getDayOfWeek = function() { return _getDayOfWeek(this.getDay()); }; var _getDayOfWeek = $ax.getDayOfWeek = function(day) { return weekday[day]; }; var month = new Array(12); month[0] = "January"; month[1] = "February"; month[2] = "March"; month[3] = "April"; month[4] = "May"; month[5] = "June"; month[6] = "July"; month[7] = "August"; month[8] = "September"; month[9] = "October"; month[10] = "November"; month[11] = "December"; funcs.getMonthName = function() { return _getMonthName(this.getMonth()); }; var _getMonthName = $ax.getMonthName = function(monthNum) { return month[monthNum]; }; funcs.getMonth = function() { return this.getMonth() + 1; }; funcs.addYears = function(years) { var retVal = new Date(this.valueOf()); retVal.setFullYear(this.getFullYear() + Number(years)); return retVal; }; funcs.addMonths = function(months) { var retVal = new Date(this.valueOf()); retVal.setMonth(this.getMonth() + Number(months)); return retVal; }; funcs.addDays = function(days) { var retVal = new Date(this.valueOf()); retVal.setDate(this.getDate() + Number(days)); return retVal; }; funcs.addHours = function(hours) { var retVal = new Date(this.valueOf()); retVal.setHours(this.getHours() + Number(hours)); return retVal; }; funcs.addMinutes = function(minutes) { var retVal = new Date(this.valueOf()); retVal.setMinutes(this.getMinutes() + Number(minutes)); return retVal; }; funcs.addSeconds = function(seconds) { var retVal = new Date(this.valueOf()); retVal.setSeconds(this.getSeconds() + Number(seconds)); return retVal; }; funcs.addMilliseconds = function(milliseconds) { var retVal = new Date(this.valueOf()); retVal.setMilliseconds(this.getMilliseconds() + Number(milliseconds)); return retVal; }; var _stoHandlers = {}; _stoHandlers.literal = function(sto, scope, eventInfo) { return sto.value; }; //need angle bracket syntax because var is a reserved word _stoHandlers['var'] = function(sto, scope, eventInfo) { // Can't us 'A || B' here, because the first value can be false, true, or empty string and still be valid. var retVal = scope.hasOwnProperty(sto.name) ? scope[sto.name] : $ax.globalVariableProvider.getVariableValue(sto.name, eventInfo); // Handle desired type here? if(retVal && retVal.exprType) { retVal = $ax.expr.evaluateExpr(retVal, eventInfo); } if((sto.desiredType == 'int' || sto.desiredType == 'float')) { var num = new Number(retVal); retVal = isNaN(num.valueOf()) ? retVal : num; } return retVal; }; //TODO: Perhaps repeaterId can be detirmined at generation, and stored in the sto info. _stoHandlers.item = function(sto, scope, eventInfo, prop) { prop = prop || (eventInfo.data ? 'data' : eventInfo.link ? 'url' : eventInfo.image ? 'img' : 'text'); var id = sto.isTarget || !$ax.repeater.hasData(eventInfo.srcElement, sto.name) ? eventInfo.targetElement : eventInfo.srcElement; return getData(eventInfo, id, sto.name, prop); }; var getData = function(eventInfo, id, name, prop) { var repeaterId = $ax.getParentRepeaterFromScriptId($ax.repeater.getScriptIdFromElementId(id)); var itemId = $ax.repeater.getItemIdFromElementId(id); return $ax.repeater.getData(eventInfo, repeaterId, itemId, name, prop); }; _stoHandlers.paren = function(sto, scope, eventInfo) { return _evaluateSTO(sto.innerSTO, scope, eventInfo); }; _stoHandlers.fCall = function(sto, scope, eventInfo) { //TODO: [mas] handle required type var thisObj = _evaluateSTO(sto.thisSTO, scope, eventInfo); if(sto.thisSTO.desiredType == 'string' && sto.thisSTO.computedType != 'string') thisObj = thisObj.toString(); var args = []; for(var i = 0; i < sto.arguments.length; i++) { args[i] = _evaluateSTO(sto.arguments[i], scope, eventInfo); } var fn = (funcs.hasOwnProperty(sto.func) && funcs[sto.func]) || thisObj[sto.func]; return fn.apply(thisObj, args); }; _stoHandlers.propCall = function(sto, scope, eventInfo) { //TODO: [mas] handle required type if((sto.prop == 'url' || sto.prop == 'img') && sto.thisSTO.sto == 'item') return _stoHandlers.item(sto.thisSTO, scope, eventInfo, sto.prop); var thisObj = _evaluateSTO(sto.thisSTO, scope, eventInfo); return thisObj[sto.prop]; }; var _binOps = {}; _binOps['+'] = function(left, right) { if(left instanceof Date) return addDayToDate(left, right); if(right instanceof Date) return addDayToDate(right, left); var num = Number(left) + Number(right); return isNaN(num) ? (String(left) + String(right)) : num; }; _binOps['-'] = function(left, right) { if(left instanceof Date) return addDayToDate(left, -right); return left - right; }; _binOps['*'] = function(left, right) { return Number(left) * Number(right); }; _binOps['/'] = function(left, right) { return Number(left) / Number(right); }; _binOps['%'] = function(left, right) { return Number(left) % Number(right); }; _binOps['=='] = function(left, right) { return _getBool(left) == _getBool(right); }; _binOps['!='] = function(left, right) { return _getBool(left) != _getBool(right); }; _binOps['<'] = function(left, right) { return Number(left) < Number(right); }; _binOps['<='] = function(left, right) { return Number(left) <= Number(right); }; _binOps['>'] = function(left, right) { return Number(left) > Number(right); }; _binOps['>='] = function(left, right) { return Number(left) >= Number(right); }; _binOps['&&'] = function(left, right) { return _getBool(left) && _getBool(right); }; _binOps['||'] = function(left, right) { return _getBool(left) || _getBool(right); }; // TODO: Move this to generic place to be used. var addDayToDate = function(date, days) { var retVal = new Date(date.valueOf()); retVal.setDate(date.getDate() + days); return retVal; }; var _unOps = {}; _unOps['+'] = function(arg) { return +arg; }; _unOps['-'] = function(arg) { return -arg; }; _unOps['!'] = function(arg) { return !_getBool(arg); }; _stoHandlers.binOp = function(sto, scope, eventInfo) { var left = _evaluateSTO(sto.leftSTO, scope, eventInfo); var right = _evaluateSTO(sto.rightSTO, scope, eventInfo); return _binOps[sto.op](left, right); }; _stoHandlers.unOp = function(sto, scope, eventInfo) { var input = _evaluateSTO(sto.inputSTO, scope, eventInfo); return _unOps[sto.op](input); }; var _getBool = function(val) { var lowerVal = val.toLowerCase ? val.toLowerCase() : val; return lowerVal == "false" ? false : lowerVal == "true" ? true : val; }; $ax.getBool = _getBool; var _evaluateSTO = function(sto, scope, eventInfo) { if(sto.sto == 'error') return undefined; return _tryEscapeRichText(castSto(_stoHandlers[sto.sto](sto, scope, eventInfo), sto), eventInfo); }; $ax.evaluateSTO = _evaluateSTO; var castSto = function(val, sto) { var type = sto.computedType || sto.desiredType; if(type == 'string') val = String(val); else if(type == 'date' && !(val instanceof Date)) val = new Date(val); else if(type == 'int' || type == 'float') val = Number(val); else if(type == 'bool') val = Boolean(val); return val; }; var _tryEscapeRichText = function(text, eventInfo) { return eventInfo.htmlLiteral ? _escapeRichText(text) : text; }; var _escapeRichText = function(text) { if(typeof (text) != 'string') return text; return text.replace('<', '<'); }; }); //***** utils.temp.js *****// // ******* Deep Copy ******** // $axure.internal(function($ax) { // TODO: [ben] Ah, infinite loops cause major issues here. Tried saving objects we've already hit, but that didn't seem to work (at least at my first shot). var _deepCopy = function(original, trackCopies) { if(trackCopies) { var index = _getCopyIndex(original); if(index != -1) return _originalToCopy[index][1]; } var isArray = original instanceof Array; var isObject = !(original instanceof Function) && !(original instanceof Date) && (original instanceof Object); if(!isArray && !isObject) return original; var copy = isArray ? [] : { }; if(trackCopies) _originalToCopy.push([original, copy]); isArray ? deepCopyArray(original, trackCopies, copy) : deepCopyObject(original, trackCopies, copy); return copy; }; $ax.deepCopy = _deepCopy; // Hacky way to copy event info. Copying dragInfo causes major issues due to infinite loops // Hashmap doesn't map objects well. It just toStrings them, making them all the same key. This has to be slow... var _originalToCopy = []; var _getCopyIndex = function(original) { for(var i = 0; i < _originalToCopy.length; i++) if(original === _originalToCopy[i][0]) return i; return -1; }; $ax.eventCopy = function(eventInfo) { var dragInfo = eventInfo.dragInfo; delete eventInfo.dragInfo; var copy = _deepCopy(eventInfo, true); copy.dragInfo = dragInfo; eventInfo.dragInfo = dragInfo; // reset the map. _originalToCopy = []; return copy; }; var deepCopyArray = function(original, trackCopies, copy) { for(var i = 0; i < original.length; i++) { copy[i] = _deepCopy(original[i], trackCopies); } }; var deepCopyObject = function(original, trackCopies, copy) { for(var key in original) { if(!original.hasOwnProperty(key)) continue; copy[key] = _deepCopy(original[key], trackCopies); } }; // Our implementation of splice because it is broken in IE8... $ax.splice = function(array, startIndex, count) { var retval = []; if(startIndex >= array.length || startIndex < 0 || count == 0) return retval; if(!count || startIndex + count > array.length) count = array.length - startIndex; for(var i = 0; i < count; i++) retval[i] = array[startIndex + i]; for(i = startIndex + count; i < array.length; i++) array[i - count] = array[i]; for(i = 0; i < count; i++) array.pop(); return retval; }; }); // ******* Flow Shape Links ******** // $axure.internal(function($ax) { if(!$ax.document.configuration.linkFlowsToPages && !$ax.document.configuration.linkFlowsToPagesNewWindow) return; $(window.document).ready(function() { $ax(function (dObj) { return ($ax.public.fn.IsVector(dObj.type) || $ax.public.fn.IsSnapshot(dObj.type)) && dObj.referencePageUrl; }).each(function (dObj, elementId) { var elementIdQuery = $('#' + elementId); if($ax.document.configuration.linkFlowsToPages && !$ax.event.HasClick(dObj)) { elementIdQuery.css("cursor", "pointer"); elementIdQuery.click(function() { $ax.navigate({ url: dObj.referencePageUrl, target: "current", includeVariables: true }); }); } if($ax.document.configuration.linkFlowsToPagesNewWindow) { $('#' + elementId + "_ref").append("
"); $('#' + elementId + "PagePopup").click(function() { $ax.navigate({ url: dObj.referencePageUrl, target: "new", includeVariables: true }); }); } }); }); }); //***** variables.js *****// // ******* GLOBAL VARIABLE PROVIDER ******** // $axure.internal(function($ax) { var _globalVariableValues = {}; var _globalVariableProvider = {}; $ax.globalVariableProvider = _globalVariableProvider; var setVariableValue = function(variable, value, suppressBroadcast) { if(!(value instanceof Object)) value = value.toString(); variable = variable.toLowerCase(); _globalVariableValues[variable] = value; if(suppressBroadcast !== true) { var varData = { globalVarName: variable, globalVarValue: value.toString() }; $axure.messageCenter.postMessage('setGlobalVar', varData); } //Post global var values only if pageData is loaded (suppresses exception which occurs when page loads) if($ax.pageData) { _postGlobalVarVals(); } }; _globalVariableProvider.setVariableValue = setVariableValue; var getVariableValue = function(variable, eventInfo, ignoreDefaultsForLinkUrl) { variable = variable.toLowerCase(); if(_globalVariableValues[variable] !== undefined) { //If this is for the GetLinkUrl function and //the current value of the global variable is the same as the default defined in the document, don't return it if(ignoreDefaultsForLinkUrl == true && $ax.document.globalVariables[variable] == _globalVariableValues[variable]) { return null; } return _globalVariableValues[variable]; } if($ax.document.globalVariables[variable] !== undefined) return ignoreDefaultsForLinkUrl == true ? null : $ax.document.globalVariables[variable]; switch(variable) { case "pagename": return $ax.pageData.page.name; case "now": return eventInfo.now; case "gendate": return $ax.pageData.generationDate; case "dragx": return $ax.drag.GetDragX(); case "dragy": return $ax.drag.GetDragY(); case "totaldragx": return $ax.drag.GetTotalDragX(); case "totaldragy": return $ax.drag.GetTotalDragY(); case "dragtime": return $ax.drag.GetDragTime(); case "math": return Math; case "date": return Date; case "window": return eventInfo && eventInfo.window; case "this": return eventInfo && eventInfo.thiswidget && $ax.getWidgetInfo(eventInfo.thiswidget.elementId); case "item": return (eventInfo && eventInfo.item && eventInfo.item.valid && eventInfo.item) || getVariableValue('targetitem', eventInfo, ignoreDefaultsForLinkUrl); case "targetitem": return eventInfo && eventInfo.targetElement && $ax.getItemInfo(eventInfo.targetElement); case "repeater": return eventInfo && eventInfo.repeater; case "target": return eventInfo && eventInfo.targetElement && $ax.getWidgetInfo(eventInfo.targetElement); case "cursor": return eventInfo && eventInfo.cursor; default: var gen = variable.substr(0, 3) == "gen"; var date = gen ? $ax.pageData.generationDate : new Date(); var prop = gen ? variable.substr(3) : variable; switch(prop) { case "day": return date.getDate(); case "month": return date.getMonth() + 1; case "monthname": return $ax.getMonthName(date.getMonth()); case "dayofweek": return $ax.getDayOfWeek(date.getDay()); case "year": return date.getFullYear(); case "time": return date.toLocaleTimeString(); case "hours": return date.getHours(); case "minutes": return date.getMinutes(); case "seconds": return date.getSeconds(); default: return ''; } } }; _globalVariableProvider.getVariableValue = getVariableValue; var load = function() { var csum = false; var query = (window.location.href.split("#")[1] || ''); //hash.substring(1); Firefox decodes this so & in variables breaks if(query.length > 0) { var vars = query.split("&"); for(var i = 0; i < vars.length; i++) { var pair = vars[i].split("="); var varName = pair[0]; var varValue = pair[1]; if(varName) { if(varName == 'CSUM') { csum = true; } else setVariableValue(varName, decodeURIComponent(varValue), true); } } if(!csum && query.length > 250) { window.alert('Axure Warning: The variable values were too long to pass to this page.\n\nIf you are using IE, using Chrome or Firefox will support more data.'); } } }; var getLinkUrl = function(baseUrl) { var toAdd = ''; var definedVariables = _getDefinedVariables(); for(var i = 0; i < definedVariables.length; i++) { var key = definedVariables[i]; var val = getVariableValue(key, undefined, true); if(val != null) { if(toAdd.length > 0) toAdd += '&'; toAdd += key + '=' + encodeURIComponent(val); } } return toAdd.length > 0 ? baseUrl + ($axure.shouldSendVarsToServer() ? '?' : '#') + toAdd + "&CSUM=1" : baseUrl; }; _globalVariableProvider.getLinkUrl = getLinkUrl; var _getDefinedVariables = function() { return $ax.pageData.variables; }; _globalVariableProvider.getDefinedVariables = _getDefinedVariables; var _postGlobalVarVals = function() { var retVal = {}; var definedVariables = _getDefinedVariables(); for(var i = 0; i < definedVariables.length; i++) { var key = definedVariables[i]; var val = getVariableValue(key); if(val != null) { retVal[key] = val; } } $ax.messageCenter.postMessage('globalVariableValues', retVal); }; $ax.messageCenter.addMessageListener(function(message, data) { if(message == 'getGlobalVariables') { _postGlobalVarVals(); } else if(message == 'resetGlobalVariables') { _globalVariableValues = {}; _postGlobalVarVals(); } }); load(); }); //***** drag.js *****// $axure.internal(function($ax) { var widgetDragInfo = new Object(); var _drag = {}; $ax.drag = _drag; $ax.drag.GetWidgetDragInfo = function() { return $.extend({}, widgetDragInfo); }; $ax.drag.StartDragWidget = function(event, id) { $ax.setjBrowserEvent(jQuery.Event(event)); if(event.donotdrag) return; var x, y; var tg; if(IE_10_AND_BELOW) { x = window.event.clientX + window.document.documentElement.scrollLeft + window.document.body.scrollLeft; y = window.event.clientY + window.document.documentElement.scrollTop + window.document.body.scrollTop; tg = window.event.srcElement; } else { if(event.changedTouches) { x = event.changedTouches[0].pageX; y = event.changedTouches[0].pageY; } else { x = event.pageX; y = event.pageY; event.preventDefault(); } tg = event.target; } widgetDragInfo.hasStarted = false; widgetDragInfo.widgetId = id; widgetDragInfo.cursorStartX = x; widgetDragInfo.cursorStartY = y; widgetDragInfo.lastX = x; widgetDragInfo.lastY = y; widgetDragInfo.currentX = x; widgetDragInfo.currentY = y; widgetDragInfo.movedWidgets = new Object(); widgetDragInfo.startTime = (new Date()).getTime(); widgetDragInfo.targetWidget = tg; var movedownName = IE_10_AND_BELOW && $ax.features.supports.windowsMobile ? $ax.features.eventNames.mouseDownName : $ax.features.eventNames.mouseMoveName; $ax.event.addEvent(document, movedownName, _dragWidget, true); $ax.event.addEvent(document, $ax.features.eventNames.mouseUpName, _stopDragWidget, true); // if(IE && BROWSER_VERSION < 9) { // if($ax.features.supports.windowsMobile) { // window.document.attachEvent($ax.features.eventNames.mouseDownName, _dragWidget); // window.document.attachEvent($ax.features.eventNames.mouseUpName, _stopDragWidget); // } else { // window.document.attachEvent('on' + $ax.features.eventNames.mouseMoveName, _dragWidget); // window.document.attachEvent('on' + $ax.features.eventNames.mouseUpName, _stopDragWidget); // } // } else { // window.document.addEventListener($ax.features.eventNames.mouseMoveName, _dragWidget, true); // window.document.addEventListener($ax.features.eventNames.mouseUpName, _stopDragWidget, true); // } $ax.legacy.SuppressBubble(event); }; var _dragWidget = function(event) { $ax.setjBrowserEvent(jQuery.Event(event)); var x, y; if(IE_10_AND_BELOW) { x = window.event.clientX + window.document.documentElement.scrollLeft + window.document.body.scrollLeft; y = window.event.clientY + window.document.documentElement.scrollTop + window.document.body.scrollTop; } else { if(event.changedTouches) { x = event.changedTouches[0].pageX; y = event.changedTouches[0].pageY; //allow scroll (defaults) if only swipe events have cases and delta x is less than 5px and not blocking scrolling var deltaX = x - widgetDragInfo.currentX; var target = window.document.getElementById(widgetDragInfo.widgetId); if($ax.event.hasSyntheticEvent(widgetDragInfo.widgetId, "onDrag") || $ax.event.hasSyntheticEvent(widgetDragInfo.widgetId, "onSwipeUp") || $ax.event.hasSyntheticEvent(widgetDragInfo.widgetId, "onSwipeDown") || (deltaX * deltaX) > 25 || ($ax.document.configuration.preventScroll && $ax.legacy.GetScrollable(target) == window.document.body)) { event.preventDefault(); } } else { x = event.pageX; y = event.pageY; } } widgetDragInfo.xDelta = x - widgetDragInfo.currentX; widgetDragInfo.yDelta = y - widgetDragInfo.currentY; widgetDragInfo.lastX = widgetDragInfo.currentX; widgetDragInfo.lastY = widgetDragInfo.currentY; widgetDragInfo.currentX = x; widgetDragInfo.currentY = y; widgetDragInfo.currentTime = (new Date()).getTime(); $ax.legacy.SuppressBubble(event); if(!widgetDragInfo.hasStarted) { widgetDragInfo.hasStarted = true; $ax.event.raiseSyntheticEvent(widgetDragInfo.widgetId, "onDragStart"); widgetDragInfo.oldBodyCursor = window.document.body.style.cursor; window.document.body.style.cursor = 'move'; var widget = window.document.getElementById(widgetDragInfo.widgetId); widgetDragInfo.oldCursor = widget.style.cursor; widget.style.cursor = 'move'; } $ax.event.raiseSyntheticEvent(widgetDragInfo.widgetId, "onDrag"); }; var _suppressClickAfterDrag = function(event) { _removeSuppressEvents(); $ax.legacy.SuppressBubble(event); }; var _removeSuppressEvents = function () { if(IE_10_AND_BELOW) { $ax.event.removeEvent(event.srcElement, 'click', _suppressClickAfterDrag, undefined, true); $ax.event.removeEvent(widgetDragInfo.targetWidget, 'mousemove', _removeSuppressEvents, undefined, true); } else { $ax.event.removeEvent(document, "click", _suppressClickAfterDrag, true); $ax.event.removeEvent(document, 'mousemove', _removeSuppressEvents, true); } }; var _stopDragWidget = function(event) { $ax.setjBrowserEvent(jQuery.Event(event)); var tg; var movedownName = IE_10_AND_BELOW && $ax.features.supports.windowsMobile ? $ax.features.eventNames.mouseDownName : $ax.features.eventNames.mouseMoveName; $ax.event.removeEvent(document, movedownName, _dragWidget, true); $ax.event.removeEvent(document, $ax.features.eventNames.mouseUpName, _stopDragWidget, true); tg = IE_10_AND_BELOW ? window.event.srcElement : event.target; // // // if(OLD_IE && BROWSER_VERSION < 9) { // if($ax.features.supports.windowsMobile) { // window.document.detachEvent($ax.features.eventNames.mouseDownName, _dragWidget); // window.document.detachEvent($ax.features.eventNames.mouseUpName, _stopDragWidget); // // } else { // window.document.detachEvent('on' + $ax.features.eventNames.mouseMoveName, _dragWidget); // window.document.detachEvent('on' + $ax.features.eventNames.mouseUpName, _stopDragWidget); // } // tg = window.event.srcElement; // } else { // window.document.removeEventListener($ax.features.eventNames.mouseMoveName, _dragWidget, true); // window.document.removeEventListener($ax.features.eventNames.mouseUpName, _stopDragWidget, true); // tg = event.target; // } if(widgetDragInfo.hasStarted) { widgetDragInfo.currentTime = (new Date()).getTime(); $ax.event.raiseSyntheticEvent(widgetDragInfo.widgetId, "onDragDrop"); if($ax.globalVariableProvider.getVariableValue('totaldragx') < -30 && $ax.globalVariableProvider.getVariableValue('dragtime') < 1000) { $ax.event.raiseSyntheticEvent(widgetDragInfo.widgetId, "onSwipeLeft"); } if($ax.globalVariableProvider.getVariableValue('totaldragx') > 30 && $ax.globalVariableProvider.getVariableValue('dragtime') < 1000) { $ax.event.raiseSyntheticEvent(widgetDragInfo.widgetId, "onSwipeRight"); } var totalDragY = $ax.globalVariableProvider.getVariableValue('totaldragy'); if(totalDragY < -30 && $ax.globalVariableProvider.getVariableValue('dragtime') < 1000) { $ax.event.raiseSyntheticEvent(widgetDragInfo.widgetId, "onSwipeUp"); } if(totalDragY > 30 && $ax.globalVariableProvider.getVariableValue('dragtime') < 1000) { $ax.event.raiseSyntheticEvent(widgetDragInfo.widgetId, "onSwipeDown"); } window.document.body.style.cursor = widgetDragInfo.oldBodyCursor; var widget = window.document.getElementById(widgetDragInfo.widgetId); // It may be null if OnDragDrop filtered out the widget if(widget != null) widget.style.cursor = widgetDragInfo.oldCursor; if(widgetDragInfo.targetWidget == tg && !event.changedTouches) { // suppress the click after the drag on desktop browsers if(IE_10_AND_BELOW && widgetDragInfo.targetWidget) { $ax.event.addEvent(widgetDragInfo.targetWidget, 'click', _suppressClickAfterDrag, true, true); $ax.event.addEvent(widgetDragInfo.targetWidget, "onmousemove", _removeSuppressEvents, true, true); } else { $ax.event.addEvent(document, "click", _suppressClickAfterDrag, true); $ax.event.addEvent(document, "mousemove", _removeSuppressEvents, true); } // // // if(IE && BROWSER_VERSION < 9 && widgetDragInfo.targetWidget) { // widgetDragInfo.targetWidget.attachEvent("onclick", _suppressClickAfterDrag); // widgetDragInfo.targetWidget.attachEvent("onmousemove", _removeSuppressEvents); // } else { // window.document.addEventListener("click", _suppressClickAfterDrag, true); // window.document.addEventListener("mousemove", _removeSuppressEvents, true); // } } } widgetDragInfo.hasStarted = false; widgetDragInfo.movedWidgets = new Object(); return false; }; $ax.drag.GetDragX = function() { if(widgetDragInfo.hasStarted) return widgetDragInfo.xDelta; return 0; }; $ax.drag.GetDragY = function() { if(widgetDragInfo.hasStarted) return widgetDragInfo.yDelta; return 0; }; $ax.drag.GetTotalDragX = function() { if(widgetDragInfo.hasStarted) return widgetDragInfo.currentX - widgetDragInfo.cursorStartX; return 0; }; $ax.drag.GetTotalDragY = function() { if(widgetDragInfo.hasStarted) return widgetDragInfo.currentY - widgetDragInfo.cursorStartY; return 0; }; $ax.drag.GetDragTime = function() { if(widgetDragInfo.hasStarted) return widgetDragInfo.currentTime - widgetDragInfo.startTime; return 600000; }; // $ax.drag.GetCursorRectangles = function() { // var rects = new Object(); // rects.lastRect = new rect($ax.lastMouseLocation.x, $ax.lastMouseLocation.y, 1, 1); // rects.currentRect = new rect($ax.mouseLocation.x, $ax.mouseLocation.y, 1, 1); // return rects; // }; // $ax.drag.GetWidgetRectangles = function(id) { // var widget = window.document.getElementById(id); // var rects = new Object(); // rects.lastRect = new rect($ax.legacy.getAbsoluteLeft(widget), $ax.legacy.getAbsoluteTop(widget), Number($('#' + id).css('width').replace("px", "")), Number($('#' + id).css('height').replace("px", ""))); // rects.currentRect = rects.lastRect; // return rects; // }; // $ax.drag.IsEntering = function(movingRects, targetRects) { // return !movingRects.lastRect.IntersectsWith(targetRects.currentRect) && movingRects.currentRect.IntersectsWith(targetRects.currentRect); // }; // $ax.drag.IsLeaving = function(movingRects, targetRects) { // return movingRects.lastRect.IntersectsWith(targetRects.currentRect) && !movingRects.currentRect.IntersectsWith(targetRects.currentRect); // }; // function IsOver(movingRects, targetRects) { // return movingRects.currentRect.IntersectsWith(targetRects.currentRect); // } // function IsNotOver(movingRects, targetRects) { // return !IsOver(movingRects, targetRects); // } $ax.drag.LogMovedWidgetForDrag = function (id, dragInfo) { dragInfo = dragInfo || widgetDragInfo; if(dragInfo.hasStarted) { var containerIndex = id.indexOf('_container'); if(containerIndex != -1) id = id.substring(0, containerIndex); // If state or other non-widget id, this should not be dragged, and should exit out to avoid exceptions. if(!$obj(id)) return; var query = $ax('#' + id); var x = query.left(); var y = query.top(); var movedWidgets = dragInfo.movedWidgets; if(!movedWidgets[id]) { movedWidgets[id] = new Location(x, y); } } }; var Location = function(x, y) { this.x = x; this.y = y; }; $ax.drag.location = Location; var Rectangle = $ax.drag.Rectangle = function(x, y, width, height) { this.x = x; this.y = y; this.width = width; this.height = height; this.right = x + width; this.bottom = y + height; }; Rectangle.prototype.IntersectsWith = function(rect) { if(this.Invalid()) return false; if(rect.length) { for(var i = 0; i < rect.length; i++) if(!rect[i].Invalid && this.IntersectsWith(rect[i])) return true; return false; } if(rect.Invalid()) return false; return this.x < rect.right && this.right > rect.x && this.y < rect.bottom && this.bottom > rect.y; }; Rectangle.prototype.Invalid = function() { return this.x == -1 && this.y == -1 && this.width == -1 && this.height == -1; }; Rectangle.prototype.Move = function(x, y) { return new Rectangle(x, y, this.width, this.height); }; }); //***** move.js *****// $axure.internal(function($ax) { var _move = {}; $ax.move = _move; var widgetMoveInfo = {}; //register and return move info, also create container for rootlayer if needed $ax.move.PrepareForMove = function (id, x, y, to, options, jobj, rootLayer, skipContainerForRootLayer) { var fixedInfo = jobj ? {} : $ax.dynamicPanelManager.getFixedInfo(id); var widget = $jobj(id); var query = $ax('#' + id); var isLayer = $ax.getTypeFromElementId(id) == $ax.constants.LAYER_TYPE; if(!rootLayer) { rootLayer = _move.getRootLayer(id); if (rootLayer && !skipContainerForRootLayer) { $ax.visibility.pushContainer(rootLayer, false); if (isLayer) widget = $ax.visibility.applyWidgetContainer(id, true); } } if (!jobj) jobj = widget; var horzProp = 'left'; var vertProp = 'top'; var horzX = to ? x - query.locRelativeIgnoreLayer(false) : x; var vertY = to ? y - query.locRelativeIgnoreLayer(true) : y; if (fixedInfo.horizontal == 'right') { horzProp = 'right'; horzX = to ? $(window).width() - x - Number(jobj.css('right').replace('px', '')) - query.width() : -x; } else if(fixedInfo.horizontal == 'center') { horzProp = 'margin-left'; if (to) horzX = x - $(window).width() / 2; } if (fixedInfo.vertical == 'bottom') { vertProp = 'bottom'; vertY = to ? $(window).height() - y - Number(jobj.css('bottom').replace('px', '')) - query.height() : -y; } else if (fixedInfo.vertical == 'middle') { vertProp = 'margin-top'; if (to) vertY = y - $(window).height() / 2; } //todo currently this always save the info, which is not needed for compound vector children and maybe some other cases //let's optimize it later, only register if registerid is valid.. widgetMoveInfo[id] = { x: horzX, y: vertY, options: options }; return { horzX: horzX, vertY: vertY, horzProp: horzProp, vertProp: vertProp, rootLayer: rootLayer, jobj: jobj }; }; $ax.move.GetWidgetMoveInfo = function() { return $.extend({}, widgetMoveInfo); }; _move.getRootLayer = function (id) { var isLayer = $ax.getTypeFromElementId(id) == $ax.constants.LAYER_TYPE; var rootLayer = isLayer ? id : ''; var parentIds = $ax('#' + id).getParents(true, '*')[0]; for(var i = 0; i < parentIds.length; i++) { var parentId = parentIds[i]; // Keep climbing up layers until you hit a non-layer. At that point you have your root layer if($ax.public.fn.IsLayer($ax.getTypeFromElementId(parentId))) rootLayer = parentId; else break; } return rootLayer; }; $ax.move.MoveWidget = function (id, x, y, options, to, animationCompleteCallback, shouldFire, jobj, skipOnMoveEvent) { var moveInfo = $ax.move.PrepareForMove(id, x, y, to, options, jobj); $ax.drag.LogMovedWidgetForDrag(id, options.dragInfo); var object = $obj(id); if(object && $ax.public.fn.IsLayer(object.type)) { var childrenIds = $ax.public.fn.getLayerChildrenDeep(id, true); //don't push container when register moveinfo for child if(!skipOnMoveEvent) { for(var i = 0; i < childrenIds.length; i++) $ax.move.PrepareForMove(childrenIds[i], x, y, to, options, null, moveInfo.rootLayer, true); } } //if(!moveInfo) moveInfo = _getMoveInfo(id, x, y, to, options, jobj); jobj = moveInfo.jobj; _moveElement(id, options, animationCompleteCallback, shouldFire, jobj, moveInfo); if(skipOnMoveEvent) return; $ax.event.raiseSyntheticEvent(id, "onMove"); if(childrenIds) { for(var i = 0; i < childrenIds.length; i++) $ax.event.raiseSyntheticEvent(childrenIds[i], 'onMove'); } }; var _moveElement = function (id, options, animationCompleteCallback, shouldFire, jobj, moveInfo){ var cssStyles = {}; if(!$ax.dynamicPanelManager.isPercentWidthPanel($obj(id))) cssStyles[moveInfo.horzProp] = '+=' + moveInfo.horzX; cssStyles[moveInfo.vertProp] = '+=' + moveInfo.vertY; // I don't think root layer is necessary anymore after changes to layer container structure. // Wait to try removing it until more stable. var rootLayer = moveInfo.rootLayer; var query = $addAll(jobj, id); if(options.easing == 'none') { query.animate(cssStyles, { duration: 0, queue: false }); if(rootLayer) $ax.visibility.popContainer(rootLayer, false); if(animationCompleteCallback) animationCompleteCallback(); //if this widget is inside a layer, we should just remove the layer from the queue if(shouldFire) $ax.action.fireAnimationFromQueue(id, $ax.action.queueTypes.move); } else { var completeCount = query.length; query.animate(cssStyles, { duration: options.duration, easing: options.easing, queue: false, complete: function () { if (animationCompleteCallback) animationCompleteCallback(); completeCount--; if(completeCount == 0 && rootLayer) $ax.visibility.popContainer(rootLayer, false); if(shouldFire) $ax.action.fireAnimationFromQueue(id, $ax.action.queueTypes.move); }}); } // //moveinfo is used for moving 'with this' // var moveInfo = new Object(); // moveInfo.x = horzX; // moveInfo.y = vertY; // moveInfo.options = options; // widgetMoveInfo[id] = moveInfo; }; _move.nopMove = function(id, options) { var moveInfo = new Object(); moveInfo.x = 0; moveInfo.y = 0; moveInfo.options = {}; moveInfo.options.easing = 'none'; moveInfo.options.duration = 0; widgetMoveInfo[id] = moveInfo; // Layer move using container now. var obj = $obj(id); if($ax.public.fn.IsLayer(obj.type)) if(options.onComplete) options.onComplete(); $ax.event.raiseSyntheticEvent(id, "onMove"); }; //rotationDegree: total degree to rotate //centerPoint: the center of the circular path var _noRotateOnlyMove = function (id, moveDelta, rotatableMove, fireAnimationQueue, easing, duration, completionCallback) { moveDelta.x += rotatableMove.x; moveDelta.y += rotatableMove.y; if (moveDelta.x == 0 && moveDelta.y == 0) { if(fireAnimationQueue) { $ax.action.fireAnimationFromQueue(id, $ax.action.queueTypes.rotate); $ax.action.fireAnimationFromQueue(id, $ax.action.queueTypes.move); } } else { $jobj(id).animate({ top: '+=' + moveDelta.y, left: '+=' + moveDelta.x }, { duration: duration, easing: easing, queue: false, complete: function () { if(fireAnimationQueue) { $ax.action.fireAnimationFromQueue(id, $ax.action.queueTypes.move); $ax.action.fireAnimationFromQueue(id, $ax.action.queueTypes.rotate); } if (completionCallback) completionCallback(); } }); } } _move.circularMove = function (id, degreeDelta, centerPoint, moveDelta, rotatableMove, resizeOffset, options, fireAnimationQueue, completionCallback) { var elem = $jobj(id); var moveInfo = $ax.move.PrepareForMove(id, moveDelta.x, moveDelta.y, false, options); // If not rotating, still need to check moveDelta and may need to handle that. if (degreeDelta === 0) { _noRotateOnlyMove(id, moveDelta, rotatableMove, fireAnimationQueue, options.easing, options.duration, completionCallback); return; } var stepFunc = function(newDegree) { var deg = newDegree - rotation.degree; var widgetCenter = $ax.public.fn.getWidgetBoundingRect(id).centerPoint; //console.log("widget center of " + id + " x " + widgetCenter.x + " y " + widgetCenter.y); var widgetNewCenter = $axure.fn.getPointAfterRotate(deg, widgetCenter, centerPoint); // Start by getting the move not related to rotation, and make sure to update center point to move with it. var ratio = deg / degreeDelta; var xdelta = (moveDelta.x + rotatableMove.x) * ratio; var ydelta = (moveDelta.y + rotatableMove.y) * ratio; if(resizeOffset) { var resizeShift = {}; resizeShift.x = resizeOffset.x * ratio; resizeShift.y = resizeOffset.y * ratio; $axure.fn.getPointAfterRotate(rotation.degree, resizeShift, { x: 0, y: 0 }); xdelta += resizeShift.x; ydelta += resizeShift.y; } centerPoint.x += xdelta; centerPoint.y += ydelta; // Now for the move that is rotatable, it must be rotated rotatableMove = $axure.fn.getPointAfterRotate(deg, rotatableMove, { x: 0, y: 0 }); // Now add in circular move to the mix. xdelta += widgetNewCenter.x - widgetCenter.x; ydelta += widgetNewCenter.y - widgetCenter.y; if(xdelta < 0) elem.css('left', '-=' + -xdelta); else if(xdelta > 0) elem.css('left', '+=' + xdelta); if(ydelta < 0) elem.css('top', '-=' + -ydelta); else if(ydelta > 0) elem.css('top', '+=' + ydelta); }; var onComplete = function() { if(fireAnimationQueue) $ax.action.fireAnimationFromQueue(id, $ax.action.queueTypes.move); if(completionCallback) completionCallback(); if(moveInfo.rootLayer) $ax.visibility.popContainer(moveInfo.rootLayer, false); var isPercentWidthPanel = $ax.dynamicPanelManager.isPercentWidthPanel($obj(id)); if(isPercentWidthPanel) { $ax.dynamicPanelManager.updatePanelPercentWidth(id); $ax.dynamicPanelManager.updatePanelContentPercentWidth(id); } if(elem.css('position') == 'fixed') { if(!isPercentWidthPanel) elem.css('left', ''); elem.css('top', ''); } }; var rotation = { degree: 0 }; if(!options.easing || options.easing === 'none' || options.duration <= 0) { stepFunc(degreeDelta); onComplete(); } else { $(rotation).animate({ degree: degreeDelta }, { duration: options.duration, easing: options.easing, queue: false, step: stepFunc, complete: onComplete }); } }; //rotate a widget by degree, center is 50% 50% _move.rotate = function (id, degree, easing, duration, to, shouldFire, completionCallback) { var currentDegree = _getRotationDegree(id); if(to) degree = degree - currentDegree; if(degree === 0) { if (shouldFire) $ax.action.fireAnimationFromQueue(id, $ax.action.queueTypes.rotate); return; } var query = $jobj(id).add($jobj(id + '_ann')).add($jobj(id + '_ref')); var stepFunc = function(now) { var degreeDelta = now - rotation.degree; var newDegree = currentDegree + degreeDelta; query.css($ax.public.fn.setTransformHowever("rotate(" + newDegree + "deg)")); currentDegree = newDegree; }; var onComplete = function() { if(shouldFire) { $ax.action.fireAnimationFromQueue($ax.public.fn.compoundIdFromComponent(id), $ax.action.queueTypes.rotate); } if(completionCallback) completionCallback(); }; var rotation = { degree: 0 }; //if no animation, setting duration to 1, to prevent RangeError in rotation loops without animation if(!easing || easing === 'none' || duration <= 0) { stepFunc(degree); onComplete(); } else { $(rotation).animate({ degree: degree }, { duration: duration, easing: easing, queue: false, step: stepFunc, complete: onComplete }); } }; _move.compoundRotateAround = function (id, degreeDelta, centerPoint, moveDelta, rotatableMove, resizeOffset, easing, duration, fireAnimationQueue, completionCallback) { if (degreeDelta === 0) { _noRotateOnlyMove($ax.public.fn.compoundIdFromComponent(id), moveDelta, rotatableMove, fireAnimationQueue, easing, duration, completionCallback, $ax.action.queueTypes.rotate); return; } var elem = $jobj(id); var rotation = { degree: 0 }; if (!easing || easing === 'none' || duration <= 0) { duration = 1; easing = 'linear'; //it doesn't matter anymore here... } var originalWidth = Number(elem.css('width').replace('px', '')); var originalHeight = Number(elem.css('height').replace('px', '')); var originalLeft = Number(elem.css('left').replace('px', '')); var originalTop = Number(elem.css('top').replace('px', '')); $(rotation).animate({ degree: degreeDelta }, { duration: duration, easing: easing, queue: false, step: function (newDegree) { var transform = $ax.public.fn.transformFromElement(elem[0]); var originalCenter = { x: originalLeft + 0.5 * originalWidth, y: originalTop + 0.5 * originalHeight}; var componentCenter = { x: originalCenter.x + transform[4], y: originalCenter.y + transform[5] }; var deg = newDegree - rotation.degree; var ratio = deg / degreeDelta; var xdelta = (moveDelta.x + rotatableMove.x) * ratio; var ydelta = (moveDelta.y + rotatableMove.y) * ratio; if (resizeOffset) { var resizeShift = {}; resizeShift.x = resizeOffset.x * ratio; resizeShift.y = resizeOffset.y * ratio; $axure.fn.getPointAfterRotate(rotation.degree, resizeShift, { x: 0, y: 0 }); xdelta += resizeShift.x; ydelta += resizeShift.y; } var rotationMatrix = $ax.public.fn.rotationMatrix(deg); var compositionTransform = $ax.public.fn.matrixMultiplyMatrix(rotationMatrix, { m11: transform[0], m21: transform[1], m12: transform[2], m22: transform[3] }); //console.log("widget center of " + id + " x " + widgetCenter.x + " y " + widgetCenter.y); var widgetNewCenter = $axure.fn.getPointAfterRotate(deg, componentCenter, centerPoint); var newMatrix = $ax.public.fn.matrixString(compositionTransform.m11, compositionTransform.m21, compositionTransform.m12, compositionTransform.m22, widgetNewCenter.x - originalCenter.x + xdelta, widgetNewCenter.y - originalCenter.y + ydelta); elem.css($ax.public.fn.setTransformHowever(newMatrix)); }, complete: function () { if (fireAnimationQueue) { $ax.action.fireAnimationFromQueue(elem.parent()[0].id, $ax.action.queueTypes.rotate); } if(completionCallback) completionCallback(); } }); }; var _getRotationDegree = _move.getRotationDegree = function(elementId) { if($ax.public.fn.IsLayer($obj(elementId).type)) { return $jobj(elementId).data('layerDegree'); } var element = document.getElementById(elementId); if(element == null) return NaN; //var transformString = element.style.transform || // element.style.OTransform || // element.style.msTransform || // element.style.MozTransform || // element.style.webkitTransform; var transformString = element.style['transform'] || element.style['-o-transform'] || element.style['-ms-transform'] || element.style['-moz-transform'] || element.style['-webkit-transform']; if(transformString) { var rotateRegex = /rotate\(([-?0-9]+)deg\)/; var degreeMatch = rotateRegex.exec(transformString); if(degreeMatch && degreeMatch[1]) return parseFloat(degreeMatch[1]); } if(window.getComputedStyle) { var st = window.getComputedStyle(element, null); } else { console.log('rotation is not supported for ie 8 and below in this version of axure rp'); return 0; } var tr = st.getPropertyValue("transform") || st.getPropertyValue("-o-transform") || st.getPropertyValue("-ms-transform") || st.getPropertyValue("-moz-transform") || st.getPropertyValue("-webkit-transform"); if(!tr || tr === 'none') return 0; var values = tr.split('(')[1]; values = values.split(')')[0], values = values.split(','); var a = values[0]; var b = values[1]; var radians = Math.atan2(b, a); if(radians < 0) { radians += (2 * Math.PI); } var angle = Math.round(radians * (180 / Math.PI)); return angle; }; // var generateFilter = function(deg) { // var rot, cos, sin, matrix; // // rot=deg>=0 ? Math.PI*deg/180 : Math.PI*(360+deg)/180; // cos=Math.cos(rot); // sin=Math.sin(rot); // matrix='M11='+cos+',M12='+(-sin)+',M21='+sin+',M22='+cos+',SizingMethod="auto expand"'; // return 'progid:DXImageTransform.Microsoft.Matrix('+matrix+')'; // } }); //***** visibility.js *****// $axure.internal(function($ax) { var document = window.document; var _visibility = {}; $ax.visibility = _visibility; var _defaultHidden = {}; var _defaultLimbo = {}; // ****************** Visibility and State Functions ****************** // var _isIdVisible = $ax.visibility.IsIdVisible = function(id) { return $ax.visibility.IsVisible(window.document.getElementById(id)); }; $ax.visibility.IsVisible = function(element) { //cannot use css('visibility') because that gets the effective visiblity //e.g. won't be able to set visibility on panels inside hidden panels return element.style.visibility != 'hidden'; }; $ax.visibility.SetIdVisible = function(id, visible) { $ax.visibility.SetVisible(window.document.getElementById(id), visible); // Hide lightbox if necessary if(!visible) { $jobj($ax.repeater.applySuffixToElementId(id, '_lightbox')).remove(); $ax.flyoutManager.unregisterPanel(id, true); } }; var _setAllVisible = function(query, visible) { for(var i = 0; i < query.length; i++) { _visibility.SetVisible(query[i], visible); } } $ax.visibility.SetVisible = function (element, visible) { //not setting display to none to optimize measuring if(visible) { if($(element).hasClass(HIDDEN_CLASS)) $(element).removeClass(HIDDEN_CLASS); if($(element).hasClass(UNPLACED_CLASS)) $(element).removeClass(UNPLACED_CLASS); element.style.display = ''; element.style.visibility = 'inherit'; } else { element.style.display = 'none'; element.style.visibility = 'hidden'; } }; var _setWidgetVisibility = $ax.visibility.SetWidgetVisibility = function (elementId, options) { var visible = $ax.visibility.IsIdVisible(elementId); // If limboed, just fire the next action then leave. if(visible == options.value || _limboIds[elementId]) { if(!_limboIds[elementId]) options.onComplete && options.onComplete(); $ax.action.fireAnimationFromQueue(elementId, $ax.action.queueTypes.fade); return; } options.containInner = true; var query = $jobj(elementId); var parentId = query.parent().attr('id'); var axObj = $obj(elementId); var preserveScroll = false; var isPanel = $ax.public.fn.IsDynamicPanel(axObj.type); var isLayer = $ax.public.fn.IsLayer(axObj.type); if(!options.noContainer && (isPanel || isLayer)) { //if dp has scrollbar, save its scroll position if(isPanel && axObj.scrollbars != 'none') { var shownState = $ax.dynamicPanelManager.getShownState(elementId); preserveScroll = true; //before hiding, try to save scroll location if(!options.value && shownState) { DPStateAndScroll[elementId] = { shownId: shownState.attr('id'), left: shownState.scrollLeft(), top: shownState.scrollTop() } } } _pushContainer(elementId, isPanel); if(isPanel && !options.value) _tryResumeScrollForDP(elementId); var complete = options.onComplete; options.onComplete = function () { if(complete) complete(); _popContainer(elementId, isPanel); //after showing dp, restore the scoll position if(isPanel && options.value) _tryResumeScrollForDP(elementId, true); } options.containerExists = true; } _setVisibility(parentId, elementId, options, preserveScroll); //set the visibility of the annotation box as well if it exists var ann = document.getElementById(elementId + "_ann"); if(ann) _visibility.SetVisible(ann, options.value); //set ref visibility for ref of flow shape, if that exists var ref = document.getElementById(elementId + '_ref'); if(ref) _visibility.SetVisible(ref, options.value); }; var _setVisibility = function(parentId, childId, options, preserveScroll) { var wrapped = $jobj(childId); var completeTotal = 1; var visible = $ax.visibility.IsIdVisible(childId); if(visible == options.value) { options.onComplete && options.onComplete(); $ax.action.fireAnimationFromQueue(childId, $ax.action.queueTypes.fade); return; } var child = $jobj(childId); var size = options.size || (options.containerExists ? $(child.children()[0]) : child); var isIdFitToContent = $ax.dynamicPanelManager.isIdFitToContent(parentId); //fade and resize won't work together when there is a container... but we still needs the container for fit to content DPs var needContainer = options.easing && options.easing != 'none' && (options.easing != 'fade' || isIdFitToContent); var cullPosition = options.cull ? options.cull.css('position') : ''; var containerExists = options.containerExists; var isFullWidth = $ax.dynamicPanelManager.isPercentWidthPanel($obj(childId)); // If fixed fit to content panel, then we must set size on it. It will be size of 0 otherwise, because container in it is absolute position. var needSetSize = false; var sizeObj = {}; if(needContainer) { var sizeId = ''; if($ax.dynamicPanelManager.isIdFitToContent(childId)) sizeId = childId; else { var panelId = $ax.repeater.removeSuffixFromElementId(childId); if($ax.dynamicPanelManager.isIdFitToContent(panelId)) sizeId = panelId; } if(sizeId) { needSetSize = true; sizeObj = $jobj(sizeId); var newSize = options.cull || sizeObj; var newAxSize = $ax('#' + newSize.attr('id')); sizeObj.width(newAxSize.width()); sizeObj.height(newAxSize.height()); } } var wrappedOffset = { left: 0, top: 0 }; var visibleWrapped = wrapped; if(needContainer) { var childObj = $obj(childId); if (options.cull) { var axCull = $ax('#' + options.cull.attr('id')); var containerWidth = axCull.width(); var containerHeight = axCull.height(); } else { if(childObj && ($ax.public.fn.IsLayer(childObj.type))) {// || childObj.generateCompound)) { var boundingRectangle = $ax.public.fn.getWidgetBoundingRect(childId); wrappedOffset.left = boundingRectangle.left; wrappedOffset.top = boundingRectangle.top; containerWidth = boundingRectangle.width; containerHeight = boundingRectangle.height; } else if (childObj && childObj.generateCompound) { var image = $jobj(childId + '_img'); containerWidth = $ax.getNumFromPx(image.css('width')); containerHeight = $ax.getNumFromPx(image.css('height')); wrappedOffset.left = $ax.getNumFromPx(image.css('left')); wrappedOffset.top = $ax.getNumFromPx(image.css('top')); } else { containerWidth = $ax('#' + childId).width(); containerHeight = $ax('#' + childId).height(); } } var containerId = $ax.visibility.applyWidgetContainer(childId); // var container = _makeContainer(containerId, options.cull || boundingRectangle, isFullWidth, options.easing == 'flip', wrappedOffset, options.containerExists); var container = _makeContainer(containerId, containerWidth, containerHeight, isFullWidth, options.easing == 'flip', wrappedOffset, options.containerExists); if(options.containInner) { wrapped = _wrappedChildren(containerExists ? $(child.children()[0]) : child); // Filter for visibile wrapped children visibleWrapped = []; for (var i = 0; i < wrapped.length; i++) if($ax.visibility.IsVisible(wrapped[i])) visibleWrapped.push(wrapped[i]); visibleWrapped = $(visibleWrapped); completeTotal = visibleWrapped.length; if(!containerExists) container.prependTo(child); // Offset items if necessary if(!containerExists && (wrappedOffset.left != 0 || wrappedOffset.top != 0)) { for(var i = 0; i < wrapped.length; i++) { var inner = $(wrapped[i]); inner.css('left', $ax.getNumFromPx(inner.css('left')) - wrappedOffset.left); inner.css('top', $ax.getNumFromPx(inner.css('top')) - wrappedOffset.top); // Parent layer is now size 0, so have to have to use conatiner since it's the real size. // Should we use container all the time? This may make things easier for fit panels too. size = container; } } } else if(!containerExists) container.insertBefore(child); if(!containerExists) wrapped.appendTo(container); if (options.value && options.containInner) { //has to set children first because flip to show needs children invisible _setAllVisible(visibleWrapped, false); _updateChildAlignment(childId); _setAllVisible(child, true); } } var completeCount = 0; var onComplete = function () { completeCount++; if (needContainer && completeCount == completeTotal) { if ($ax.public.fn.isCompoundVectorHtml(container.parent()[0])) { wrappedOffset.left = $ax.getNumFromPx(container.css('left')); wrappedOffset.top = $ax.getNumFromPx(container.css('top')); } if (options.containInner && !containerExists && (wrappedOffset.left != 0 || wrappedOffset.top != 0)) { for (i = 0; i < wrapped.length; i++) { inner = $(wrapped[i]); //if ($ax.public.fn.isCompoundVectorComponentHtml(inner[0])) break; inner.css('left', $ax.getNumFromPx(inner.css('left')) + wrappedOffset.left); inner.css('top', $ax.getNumFromPx(inner.css('top')) + wrappedOffset.top); } } if(options.containInner && !options.value) { _setAllVisible(child, false); _setAllVisible(visibleWrapped, true); } if(containerExists) { if(!options.settingChild) container.css('position', 'relative;'); } else { wrapped.insertBefore(container); container.remove(); } if(childObj && $ax.public.fn.IsDynamicPanel(childObj.type) && window.modifiedDynamicPanleParentOverflowProp) { child.css('overflow', 'hidden'); window.modifiedDynamicPanleParentOverflowProp = false; } } if(options.value) _updateChildAlignment(childId); if(!needContainer || completeTotal == completeCount) { if(options.cull) options.cull.css('position', cullPosition); if(needSetSize) { sizeObj.css('width', 'auto'); sizeObj.css('height', 'auto'); } options.onComplete && options.onComplete(); if(options.fire) { $ax.event.raiseSyntheticEvent(childId, options.value ? 'onShow' : 'onHide'); $ax.action.fireAnimationFromQueue(childId, $ax.action.queueTypes.fade); } } }; // Nothing actually being animated, all wrapped elements invisible if(!visibleWrapped.length) { if(!options.easing || options.easing == 'none') { $ax.visibility.SetIdVisible(childId, options.value); completeTotal = 1; onComplete(); } else { window.setTimeout(function() { completeCount = completeTotal - 1; onComplete(); },options.duration); } return; } if(!options.easing || options.easing == 'none') { $ax.visibility.SetIdVisible(childId, options.value); completeTotal = 1; onComplete(); } else if(options.easing == 'fade') { if(options.value) { if(preserveScroll) { visibleWrapped.css('opacity', 0); visibleWrapped.css('visibility', 'inherit'); visibleWrapped.css('display', 'block'); //was hoping we could just use fadein here, but need to set display before set scroll position _tryResumeScrollForDP(childId); visibleWrapped.animate({ opacity: 1 }, { duration: options.duration, easing: 'swing', queue: false, complete: function() { $ax.visibility.SetIdVisible(childId, true); visibleWrapped.css('opacity', ''); onComplete(); } }); } else { // Can't use $ax.visibility.SetIdVisible, because we only want to set visible, we don't want to set display, fadeIn will handle that. visibleWrapped.css('visibility', 'inherit'); visibleWrapped.fadeIn({ queue: false, duration: options.duration, complete: onComplete }); } } else { // Fading here is being strange... visibleWrapped.animate({ opacity: 0 }, { duration: options.duration, easing: 'swing', queue: false, complete: function() { $ax.visibility.SetIdVisible(childId, false); visibleWrapped.css('opacity', ''); onComplete(); }}); } } else if (options.easing == 'flip') { //this container will hold var innerContainer = $('
'); innerContainer.attr('id', containerId + "_inner"); innerContainer.data('flip', options.direction == 'left' || options.direction == 'right' ? 'y' : 'x'); innerContainer.css({ position: 'relative', 'width': containerWidth, 'height': containerHeight }); innerContainer.appendTo(container); wrapped.appendTo(innerContainer); if(childObj && $ax.public.fn.IsDynamicPanel(childObj.type)) var containerDiv = child; else containerDiv = parentId ? $jobj(parentId) : child.parent(); completeTotal = 1; var flipdegree; var requestAnimFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) { window.setTimeout(callback, 1000 / 60); }; var originForUpOrDown = '100% ' + containerHeight / 2 + 'px'; if(options.value) { //options.value == true means in or show, note to get here, the element must be currently hidden //to show, we need to first flip it 180deg without animation switch(options.direction) { case 'right': case 'left': _setRotateTransformation(innerContainer, 'rotateY(180deg)'); flipdegree = options.direction === 'right' ? 'rotateY(360deg)' : 'rotateY(0deg)'; break; case 'up': case 'down': innerContainer.css({ '-webkit-transform-origin': originForUpOrDown, '-ms-transform-origin': originForUpOrDown, 'transform-origin': originForUpOrDown, }); _setRotateTransformation(innerContainer, 'rotateX(180deg)'); flipdegree = options.direction === 'up' ? 'rotateX(360deg)' : 'rotateX(0deg)'; break; } var onFlipShowComplete = function() { $ax.visibility.SetIdVisible(childId, true); wrapped.insertBefore(innerContainer); innerContainer.remove(); onComplete(); }; innerContainer.css({ '-webkit-backface-visibility': 'hidden', 'backface-visibility': 'hidden' }); child.css({ 'display': '', 'visibility': 'inherit' }); visibleWrapped.css({ 'display': '', 'visibility': 'inherit' }); innerContainer.css({ '-webkit-transition-duration': options.duration + 'ms', 'transition-duration': options.duration + 'ms' }); if(preserveScroll) _tryResumeScrollForDP(childId); requestAnimFrame(function () { _setRotateTransformation(innerContainer, flipdegree, containerDiv, onFlipShowComplete, options.duration); }); } else { //hide or out switch(options.direction) { case 'right': case 'left': flipdegree = options.direction === 'right' ? 'rotateY(180deg)' : 'rotateY(-180deg)'; break; case 'up': case 'down': //_setRotateTransformation(wrapped, 'rotateX(0deg)'); innerContainer.css({ '-webkit-transform-origin': originForUpOrDown, '-ms-transform-origin': originForUpOrDown, 'transform-origin': originForUpOrDown, }); flipdegree = options.direction === 'up' ? 'rotateX(180deg)' : 'rotateX(-180deg)'; break; } var onFlipHideComplete = function() { wrapped.insertBefore(innerContainer); $ax.visibility.SetIdVisible(childId, false); innerContainer.remove(); onComplete(); }; innerContainer.css({ '-webkit-backface-visibility': 'hidden', 'backface-visibility': 'hidden', '-webkit-transition-duration': options.duration + 'ms', 'transition-duration': options.duration + 'ms' }); if(preserveScroll) _tryResumeScrollForDP(childId); requestAnimFrame(function () { _setRotateTransformation(innerContainer, flipdegree, containerDiv, onFlipHideComplete, options.duration); }); } } else { // Because the move is gonna fire on annotation and ref too, need to update complete total completeTotal = $addAll(visibleWrapped, childId).length; if(options.value) { _slideStateIn(childId, childId, options, size, false, onComplete, visibleWrapped, preserveScroll); } else { var tops = []; var lefts = []; for(var i = 0; i < visibleWrapped.length; i++) { var currWrapped = $(visibleWrapped[i]); tops.push(currWrapped.css('top')); lefts.push(currWrapped.css('left')); } var onOutComplete = function () { //bring back SetIdVisible on childId for hiding lightbox $ax.visibility.SetIdVisible(childId, false); for(i = 0; i < visibleWrapped.length; i++) { currWrapped = $(visibleWrapped[i]); $ax.visibility.SetIdVisible(currWrapped.attr('id'), false); currWrapped.css('top', tops[i]); currWrapped.css('left', lefts[i]); } onComplete(); }; _slideStateOut(size, childId, options, onOutComplete, visibleWrapped); } } // If showing, go through all rich text objects inside you, and try to redo alignment of them if(options.value && !options.containInner) { _updateChildAlignment(childId); } }; var _updateChildAlignment = function(childId) { var descendants = $jobj(childId).find('*'); for(var i = 0; i < descendants.length; i++) { var decendantId = descendants[i].id; // This check is probably redundant? UpdateTextAlignment should ignore any text objects that haven't set the vAlign yet. if($ax.getTypeFromElementId(decendantId) != 'richTextPanel') continue; $ax.style.updateTextAlignmentForVisibility(decendantId); } }; var _wrappedChildren = function (child) { return child.children(); //var children = child.children(); //var valid = []; //for(var i = 0; i < children.length; i++) if($ax.visibility.IsVisible(children[i])) valid.push(children[i]); //return $(valid); }; var _setRotateTransformation = function(elementsToSet, transformValue, elementParent, flipCompleteCallback, flipDurationMs) { if(flipCompleteCallback) { //here we didn't use 'transitionend' event to fire callback //when show/hide on one element, changing transition property will stop the event from firing window.setTimeout(flipCompleteCallback, flipDurationMs); } elementsToSet.css({ '-webkit-transform': transformValue, '-moz-transform': transformValue, '-ms-transform': transformValue, '-o-transform': transformValue, 'transform': transformValue }); //when deal with dynamic panel, we need to set it's parent's overflow to visible to have the 3d effect //NOTE: we need to set this back when both flips finishes in DP, to prevents one animation finished first and set this back if(elementParent && elementParent.css('overflow') === 'hidden') { elementParent.css('overflow', 'visible'); window.modifiedDynamicPanleParentOverflowProp = true; } }; $ax.visibility.GetPanelState = function(id) { var children = $ax.visibility.getRealChildren($jobj(id).children()); for(var i = 0; i < children.length; i++) { if(children[i].style && $ax.visibility.IsVisible(children[i])) return children[i].id; } return ''; }; var containerCount = {}; $ax.visibility.SetPanelState = function(id, stateId, easingOut, directionOut, durationOut, easingIn, directionIn, durationIn, showWhenSet) { var show = !$ax.visibility.IsIdVisible(id) && showWhenSet; if(show) $ax.visibility.SetIdVisible(id, true); // Exit here if already at desired state. if($ax.visibility.IsIdVisible(stateId)) { if(show) { $ax.event.raiseSyntheticEvent(id, 'onShow'); // If showing size changes and need to update parent panels $ax.dynamicPanelManager.fitParentPanel(id); } $ax.action.fireAnimationFromQueue(id, $ax.action.queueTypes.setState); return; } _pushContainer(id, true); var state = $jobj(stateId); var oldStateId = $ax.visibility.GetPanelState(id); var oldState = $jobj(oldStateId); //pin to browser $ax.dynamicPanelManager.adjustFixed(id, oldState.width(), oldState.height(), state.width(), state.height()); _bringPanelStateToFront(id, stateId, oldStateId); var fitToContent = $ax.dynamicPanelManager.isIdFitToContent(id); var resized = false; if(fitToContent) { // Set resized resized = state.width() != oldState.width() || state.height() != oldState.height(); } //edge case for sliding var movement = (directionOut == 'left' || directionOut == 'up' || state.children().length == 0) && oldState.children().length != 0 ? oldState : state; var onCompleteCount = 0; var onComplete = function () { //move this call from _setVisibility() for animate out. //Because this will make the order of dp divs consistence: the showing panel is always in front after both animation finished //tested in the cases where one panel is out/show slower/faster/same time/instantly. _bringPanelStateToFront(id, stateId, oldStateId); if (window.modifiedDynamicPanleParentOverflowProp) { var parent = id ? $jobj(id) : child.parent(); parent.css('overflow', 'hidden'); window.modifiedDynamicPanleParentOverflowProp = false; } $ax.dynamicPanelManager.fitParentPanel(id); $ax.dynamicPanelManager.updatePanelPercentWidth(id); $ax.dynamicPanelManager.updatePanelContentPercentWidth(id); $ax.action.fireAnimationFromQueue(id, $ax.action.queueTypes.setState); $ax.event.raiseSyntheticEvent(id, "onPanelStateChange"); $ax.event.leavingState(oldStateId); _popContainer(id, true); }; // Must do state out first, so if we cull by new state, location is correct _setVisibility(id, oldStateId, { value: false, easing: easingOut, direction: directionOut, duration: durationOut, containerExists: true, onComplete: function() { // if(easingIn !== 'flip') _bringPanelStateToFront(id, stateId); if (++onCompleteCount == 2) onComplete(); }, settingChild: true, size: movement, //cull for cull: easingOut == 'none' || state.children().length == 0 ? oldState : state }); _setVisibility(id, stateId, { value: true, easing: easingIn, direction: directionIn, duration: durationIn, containerExists: true, onComplete: function () { // if (easingIn === 'flip') _bringPanelStateToFront(id, stateId); if (++onCompleteCount == 2) onComplete(); }, settingChild: true, //size for offset size: movement }); if(show) $ax.event.raiseSyntheticEvent(id, 'onShow'); if(resized) $ax.event.raiseSyntheticEvent(id, 'onResize'); }; var containedFixed = {}; var _pushContainer = _visibility.pushContainer = function(id, panel) { var count = containerCount[id]; if(count) containerCount[id] = count + 1; else { var trapScroll = _trapScrollLoc(id); var jobj = $jobj(id); var children = jobj.children(); var css = { position: 'relative', top: 0, left: 0 }; if(!panel) { var boundingRect = $axure.fn.getWidgetBoundingRect(id); css.top = boundingRect.top; css.left = boundingRect.left; } var container = $('
'); container.attr('id', $ax.visibility.applyWidgetContainer(id)); container.css(css); //container.append(jobj.children()); jobj.append(container); containerCount[id] = 1; // Panel needs to wrap children if(panel) { for(var i = 0; i < children.length; i++) { var child = $(children[i]); var childContainer = $('
'); childContainer.attr('id', $ax.visibility.applyWidgetContainer(child.attr('id'))); childContainer.css(css); child.after(childContainer); childContainer.append(child); container.append(childContainer); } } else { var focus = _getCurrFocus(); if(focus) $ax.event.addSuppressedEvent($ax.repeater.removeSuffixFromElementId(focus), 'OnLostFocus'); // Layer needs to fix top left var childIds = $ax('#' + id).getChildren()[0].children; for(var i = 0; i < childIds.length; i++) { var childId = childIds[i]; var childObj = $jobj(childId); var fixedInfo = $ax.dynamicPanelManager.getFixedInfo(childId); if(fixedInfo.fixed) { var axObj = $ax('#' + childId); var left = axObj.left(); var top = axObj.top(); containedFixed[childId] = { left: left, top: top, fixed: fixedInfo }; childObj.css('left', left); childObj.css('top', top); childObj.css('margin-left', 0); childObj.css('margin-top', 0); childObj.css('right', 'auto'); childObj.css('bottom', 'auto'); childObj.css('position', 'absolute'); } var cssChange = { left: '-=' + css.left, top: '-=' + css.top }; if($ax.getTypeFromElementId(childId) == $ax.constants.LAYER_TYPE) { _pushContainer(childId, false); $ax.visibility.applyWidgetContainer(childId, true).css(cssChange); } else { //if ($ax.public.fn.isCompoundVectorHtml(jobj[0])) { // var grandChildren = jobj[0].children; // //while (grandChildren.length > 0 && grandChildren[0].id.indexOf('container') >= 0) grandChildren = grandChildren[0].children; // for (var j = 0; j < grandChildren.length; j++) { // var grandChildId = grandChildren[j].id; // if (grandChildId.indexOf(childId + 'p') >= 0 || grandChildId.indexOf('_container') >= 0) $jobj(grandChildId).css(cssChange); // } //} else // Need to include ann and ref in move. childObj = $addAll(childObj, childId); childObj.css(cssChange); } container.append(childObj); } _setCurrFocus(focus); } trapScroll(); } }; var _popContainer = _visibility.popContainer = function (id, panel) { var count = containerCount[id]; if(!count) return; count--; containerCount[id] = count; if(count != 0) return; var trapScroll = _trapScrollLoc(id); var jobj = $jobj(id); var container = $ax.visibility.applyWidgetContainer(id, true); // If layer is at bottom or right of page, unwrapping could change scroll by temporarily reducting page size. // To avoid this, we let container persist on page, with the size it is at this point, and don't remove container completely // until the children are back to their proper locations. var size = $ax('#' + id).size(); container.css('width', size.width); container.css('height', size.height); var focus = _getCurrFocus(); if(focus) $ax.event.addSuppressedEvent($ax.repeater.removeSuffixFromElementId(focus), 'OnLostFocus'); jobj.append(container.children()); _setCurrFocus(focus); $('body').append(container); // Layer doesn't have children containers to clean up if(panel) { var children = jobj.children(); for(var i = 0; i < children.length; i++) { var childContainer = $(children[i]); var child = $(childContainer.children()[0]); childContainer.after(child); childContainer.remove(); } } else { var left = container.css('left'); var top = container.css('top'); var childIds = $ax('#' + id).getChildren()[0].children; for (var i = 0; i < childIds.length; i++) { var childId = childIds[i]; var cssChange = { left: '+=' + left, top: '+=' + top }; if($ax.getTypeFromElementId(childId) == $ax.constants.LAYER_TYPE) { $ax.visibility.applyWidgetContainer(childId, true).css(cssChange); _popContainer(childId, false); } else { var childObj = $jobj(childId); // if ($ax.public.fn.isCompoundVectorHtml(jobj[0])) { // var grandChildren = jobj[0].children; // //while (grandChildren.length > 0 && grandChildren[0].id.indexOf('container') >= 0) grandChildren = grandChildren[0].children; // for (var j = 0; j < grandChildren.length; j++) { // var grandChildId = grandChildren[j].id; // if (grandChildId.indexOf(childId + 'p') >= 0 || grandChildId.indexOf('_container') >= 0) $jobj(grandChildId).css(cssChange); // } //} else var allObjs = $addAll(childObj, childId); // Just include other objects for initial css. Fixed panels need to be dealt with separately. allObjs.css(cssChange); var fixedInfo = containedFixed[childId]; if(fixedInfo) { delete containedFixed[childId]; childObj.css('position', 'fixed'); var deltaX = $ax.getNumFromPx(childObj.css('left')) - fixedInfo.left; var deltaY = $ax.getNumFromPx(childObj.css('top')) - fixedInfo.top; fixedInfo = fixedInfo.fixed; if(fixedInfo.horizontal == 'left') childObj.css('left', fixedInfo.x + deltaX); else if(fixedInfo.horizontal == 'center') { childObj.css('left', '50%'); childObj.css('margin-left', fixedInfo.x + deltaX); } else { childObj.css('left', 'auto'); childObj.css('right', fixedInfo.x - deltaX); } if(fixedInfo.vertical == 'top') childObj.css('top', fixedInfo.y + deltaY); else if(fixedInfo.vertical == 'middle') { childObj.css('top', '50%'); childObj.css('margin-top', fixedInfo.y + deltaY); } else { childObj.css('top', 'auto'); childObj.css('bottom', fixedInfo.y - deltaY); } $ax.dynamicPanelManager.updatePanelPercentWidth(childId); $ax.dynamicPanelManager.updatePanelContentPercentWidth(childId); } } } } container.remove(); trapScroll(); }; var _trapScrollLoc = function(id) { var locs = {}; var states = $jobj(id).find('.panel_state'); for(var i = 0; i < states.length; i++) { var state = $(states[i]); locs[state.attr('id')] = { x: state.scrollLeft(), y: state.scrollTop() }; } return function() { for(var key in locs) { var state = $jobj(key); state.scrollLeft(locs[key].x); state.scrollTop(locs[key].y); } }; } var _getCurrFocus = function () { // Only care about focused a tags and inputs var id = window.lastFocusedClickable && window.lastFocusedClickable.id; if(!id) return id; var jobj = $(window.lastFocusedClickable); return jobj.is('a') || jobj.is('input') ? id : ''; } var _setCurrFocus = function(id) { if(id) { // This is really just needed for IE, so if this causes issues on other browsers, try adding that check here var trap = $ax.event.blockEvent($ax.repeater.removeSuffixFromElementId(id), 'OnFocus'); window.setTimeout(function () { $jobj(id).focus(); trap(); }, 0); } } //use this to save & restore DP's scroll position when show/hide //key => dp's id (not state's id, because it seems we can change state while hiding) //value => first state's id & scroll position //we only need to store one scroll position for one DP, and remove the key after shown. var DPStateAndScroll = {} var _tryResumeScrollForDP = function (dpId, deleteId) { var scrollObj = DPStateAndScroll[dpId]; if(scrollObj) { var shownState = document.getElementById(scrollObj.shownId); if(scrollObj.left) shownState.scrollLeft = scrollObj.left; if(scrollObj.top) shownState.scrollTop = scrollObj.top; if(deleteId) delete DPStateAndScroll[dpId]; } }; // var _makeContainer = function (containerId, rect, isFullWidth, isFlip, offset, containerExists) { var _makeContainer = function (containerId, width, height, isFullWidth, isFlip, offset, containerExists) { if(containerExists) var container = $jobj(containerId); else { container = $('
'); container.attr('id', containerId); } var css = { position: 'absolute', width: width, height: height, }; if(!containerExists) { // If container exists, may be busy updating location. Will init and update it correctly. css.top = offset.top; css.left = offset.left; } if(isFlip) { css.perspective = '800px'; css.webkitPerspective = "800px"; css.mozPerspective = "800px"; } else css.overflow = 'hidden'; //perspective on container will give us 3d effect when flip //if(!isFlip) css.overflow = 'hidden'; // Rect should be a jquery not axquery obj //_getFixedCss(css, rect.$ ? rect.$() : rect, fixedInfo, isFullWidth); container.css(css); return container; }; var CONTAINER_SUFFIX = _visibility.CONTAINER_SUFFIX = '_container'; var CONTAINER_INNER = CONTAINER_SUFFIX + '_inner'; _visibility.getWidgetFromContainer = function(id) { var containerIndex = id.indexOf(CONTAINER_SUFFIX); if(containerIndex == -1) return id; return id.substr(0, containerIndex) + id.substr(containerIndex + CONTAINER_SUFFIX.length); }; // Apply container to widget id if necessary. // returnJobj: True if you want the jquery object rather than id returned // skipCheck: True if you want the query returned reguardless of container existing // checkInner: True if inner container should be checked _visibility.applyWidgetContainer = function (id, returnJobj, skipCheck, checkInner) { // If container exists, just return (return query if requested) if(id.indexOf(CONTAINER_SUFFIX) != -1) return returnJobj ? $jobj(id) : id; // Get desired id, and return it if query is not desired var containerId = $ax.repeater.applySuffixToElementId(id, checkInner ? CONTAINER_INNER : CONTAINER_SUFFIX); if(!returnJobj) return containerId; // If skipping check or container exists, just return innermost container requested var container = $jobj(containerId); if(skipCheck || container.length) return container; // If inner container was not checked, then no more to check, return query for widget if(!checkInner) return $jobj(id); // If inner container was checked, check for regular container still container = $jobj($ax.repeater.applySuffixToElementId(id, CONTAINER_SUFFIX)); return container.length ? container : $jobj(id); }; _visibility.isContainer = function(id) { return id.indexOf(CONTAINER_SUFFIX) != -1; }; _visibility.getRealChildren = function(query) { while(query.length && $(query[0]).attr('id').indexOf(CONTAINER_SUFFIX) != -1) query = query.children(); return query; }; var _getFixedCss = function(css, rect, fixedInfo, isFullWidth) { // todo: **mas** make sure this is ok if(fixedInfo.fixed) { css.position = 'fixed'; if(fixedInfo.horizontal == 'left') css.left = fixedInfo.x; else if(fixedInfo.horizontal == 'center') { css.left = isFullWidth ? '0px' : '50%'; css['margin-left'] = fixedInfo.x; } else if(fixedInfo.horizontal == 'right') { css.left = 'auto'; css.right = fixedInfo.x; } if(fixedInfo.vertical == 'top') css.top = fixedInfo.y; else if(fixedInfo.vertical == 'middle') { css.top = '50%'; css['margin-top'] = fixedInfo.y; } else if(fixedInfo.vertical == 'bottom') { css.top = 'auto'; css.bottom = fixedInfo.y; } } else { css.left = Number(rect.css('left').replace('px', '')) || 0; css.top = Number(rect.css('top').replace('px', '')) || 0; } }; var _slideStateOut = function (container, stateId, options, onComplete, jobj) { var directionOut = options.direction; var axObject = $ax('#' + container.attr('id')); var width = axObject.width(); var height = axObject.height(); if(directionOut == "right") { $ax.move.MoveWidget(stateId, width, 0, options, false, onComplete, false, jobj, true); } else if(directionOut == "left") { $ax.move.MoveWidget(stateId, -width, 0, options, false, onComplete, false, jobj, true); } else if(directionOut == "up") { $ax.move.MoveWidget(stateId, 0, -height, options, false, onComplete, false, jobj, true); } else if(directionOut == "down") { $ax.move.MoveWidget(stateId, 0, height, options, false, onComplete, false, jobj, true); } }; var _slideStateIn = function (id, stateId, options, container, makePanelVisible, onComplete, jobj, preserveScroll) { var directionIn = options.direction; var axObject = $ax('#' +container.attr('id')); var width = axObject.width(); var height = axObject.height(); for(var i = 0; i < jobj.length; i++) { var child = $(jobj[i]); var oldTop = $ax.getNumFromPx(child.css('top')); var oldLeft = $ax.getNumFromPx(child.css('left')); if (directionIn == "right") { child.css('left', oldLeft - width + 'px'); } else if(directionIn == "left") { child.css('left', oldLeft + width + 'px'); } else if(directionIn == "up") { child.css('top', oldTop + height + 'px'); } else if(directionIn == "down") { child.css('top', oldTop - height + 'px'); } } if (makePanelVisible) $ax.visibility.SetIdVisible(id, true); for(i = 0; i < jobj.length; i++) $ax.visibility.SetIdVisible($(jobj[i]).attr('id'), true); if(preserveScroll) _tryResumeScrollForDP(id); if(directionIn == "right") { $ax.move.MoveWidget(stateId, width, 0, options, false, onComplete, false, jobj, true); } else if(directionIn == "left") { $ax.move.MoveWidget(stateId, -width, 0, options, false, onComplete, false, jobj, true); } else if(directionIn == "up") { $ax.move.MoveWidget(stateId, 0, -height, options, false, onComplete, false, jobj, true); } else if(directionIn == "down") { $ax.move.MoveWidget(stateId, 0, height, options, false, onComplete, false, jobj, true); } }; $ax.visibility.GetPanelStateId = function(dpId, index) { var itemNum = $ax.repeater.getItemIdFromElementId(dpId); var panelStateId = $ax.repeater.getScriptIdFromElementId(dpId) + '_state' + index; return $ax.repeater.createElementId(panelStateId, itemNum); }; $ax.visibility.GetPanelStateCount = function(id) { return $ax.visibility.getRealChildren($jobj(id).children()).length; }; var _bringPanelStateToFront = function (dpId, stateid, oldStateId) { var panel = $jobj(dpId); if(containerCount[dpId]) { stateid = $ax.visibility.applyWidgetContainer(stateid); panel = $ax.visibility.applyWidgetContainer(dpId, true, false, true); } $jobj(stateid).appendTo(panel); //when bring a panel to front, it will be focused, and the previous front panel should fire blur event if it's lastFocusedClickableSelector //ie(currently 11) and firefox(currently 34) doesn't fire blur event, this is the hack to fire it manually if((IE || FIREFOX) && window.lastFocusedClickable && $ax.event.getFocusableWidgetOrChildId(window.lastFocusedControl) == window.lastFocusedClickable.id) { // Only need to do this if the currently focused widget is in the panel state that is being hidden. if($jobj(oldStateId).find('#' + window.lastFocusedClickable.id.split('_')[0]).length) $(window.lastFocusedClickable).triggerHandler('blur'); } }; var _limboIds = _visibility.limboIds = {}; // limboId's is a dictionary of id->true, essentially a set. var _addLimboAndHiddenIds = $ax.visibility.addLimboAndHiddenIds = function(newLimboIds, newHiddenIds, query, skipRepeater) { var limboedByMaster = {}; for(var key in newLimboIds) { if (!$ax.public.fn.IsReferenceDiagramObject($ax.getObjectFromElementId(key).type)) continue; var ids = $ax.model.idsInRdoToHideOrLimbo(key); for(var i = 0; i < ids.length; i++) limboedByMaster[ids[i]] = true; } var hiddenByMaster = {}; for(key in newHiddenIds) { if (!$ax.public.fn.IsReferenceDiagramObject($ax.getObjectFromElementId(key).type)) continue; ids = $ax.model.idsInRdoToHideOrLimbo(key); for(i = 0; i < ids.length; i++) hiddenByMaster[ids[i]] = true; } // Extend with children of rdos newLimboIds = $.extend(newLimboIds, limboedByMaster); newHiddenIds = $.extend(newHiddenIds, hiddenByMaster); // something is only visible if it's not hidden and limboed query.each(function(diagramObject, elementId) { // Rdos already handled, contained widgets are limboed by the parent, and sub menus should be ignored if(diagramObject.isContained || $ax.public.fn.IsReferenceDiagramObject(diagramObject.type) || $ax.public.fn.IsTableCell(diagramObject.type) || $jobj(elementId).hasClass('sub_menu')) return; if(diagramObject.type == 'table' && $jobj(elementId).parent().hasClass('ax_menu')) return; if(skipRepeater) { // Any item in a repeater should return if($ax.getParentRepeaterFromElementIdExcludeSelf(elementId)) return; } var scriptId = $ax.repeater.getScriptIdFromElementId(elementId); var shouldBeVisible = Boolean(!newLimboIds[scriptId] && !newHiddenIds[scriptId]); var isVisible = Boolean(_isIdVisible(elementId)); if(shouldBeVisible != isVisible) { _setWidgetVisibility(elementId, { value: shouldBeVisible, noContainer: true }); } }); _limboIds = _visibility.limboIds = $.extend(_limboIds, newLimboIds); }; var _clearLimboAndHidden = $ax.visibility.clearLimboAndHidden = function(ids) { _limboIds = _visibility.limboIds = {}; }; $ax.visibility.clearLimboAndHiddenIds = function(ids) { for(var i = 0; i < ids.length; i++) { var scriptId = $ax.repeater.getScriptIdFromElementId(ids[i]); delete _limboIds[scriptId]; } }; $ax.visibility.resetLimboAndHiddenToDefaults = function (query) { if(!query) query = $ax('*'); _clearLimboAndHidden(); _addLimboAndHiddenIds(_defaultLimbo, _defaultHidden, query); }; $ax.visibility.isScriptIdLimbo = function(scriptId) { if(_limboIds[scriptId]) return true; var repeater = $ax.getParentRepeaterFromScriptId(scriptId); if(!repeater) return false; var itemId = $ax.getItemIdsForRepeater(repeater)[0]; return _limboIds[$ax.repeater.createElementId(scriptId, itemId)]; } $ax.visibility.isElementIdLimboOrInLimboContainer = function (elementId) { var parent = document.getElementById(elementId); while(parent) { var scriptId = $ax.repeater.getScriptIdFromElementId($(parent).attr('id')); if(_limboIds[scriptId]) return true; parent = parent.parentElement; } return false; } $ax.visibility.initialize = function() { // initialize initial visible states $('.' + HIDDEN_CLASS).each(function (index, diagramObject) { _defaultHidden[$ax.repeater.getScriptIdFromElementId(diagramObject.id)] = true; }); $('.' + UNPLACED_CLASS).each(function (index, diagramObject) { _defaultLimbo[$ax.repeater.getScriptIdFromElementId(diagramObject.id)] = true; }); _addLimboAndHiddenIds(_defaultLimbo, _defaultHidden, $ax('*'), true); }; _visibility.initRepeater = function(repeaterId) { var html = $('
'); html.append($jobj(repeaterId + '_script').html()); html.find('.' + HIDDEN_CLASS).each(function (index, element) { _defaultHidden[$ax.repeater.getScriptIdFromElementId(element.id)] = true; }); html.find('.' + UNPLACED_CLASS).each(function (index, element) { _defaultLimbo[$ax.repeater.getScriptIdFromElementId(element.id)] = true; }); } var HIDDEN_CLASS = _visibility.HIDDEN_CLASS = 'ax_default_hidden'; var UNPLACED_CLASS = _visibility.UNPLACED_CLASS = 'ax_default_unplaced'; }); //***** style.js *****// $axure.internal(function($ax) { var _style = {}; $ax.style = _style; var _disabledWidgets = {}; var _selectedWidgets = {}; // A table to cache the outerHTML of the _rtf elements before the rollover state is applied. var _originalTextCache = {}; // A table to exclude the normal style from adaptive overrides var _shapesWithSetRichText = {}; // just a listing of shape ids var _adaptiveStyledWidgets = {}; var _setLinkStyle = function(id, styleName) { var textId = $ax.style.GetTextIdFromLink(id); var style = _computeAllOverrides(id, textId, styleName, $ax.adaptive.currentViewId); if(!_originalTextCache[textId]) { $ax.style.CacheOriginalText(textId); } if($.isEmptyObject(style)) return; var parentObjectCache = _originalTextCache[textId].styleCache; _transformTextWithVerticalAlignment(textId, function() { var cssProps = _getCssStyleProperties(style); $('#' + id).find('*').andSelf().each(function(index, element) { element.setAttribute('style', parentObjectCache[element.id]); _applyCssProps(element, cssProps); }); }); }; var _resetLinkStyle = function(id) { var textId = $ax.style.GetTextIdFromLink(id); var parentObjectCache = _originalTextCache[textId].styleCache; _transformTextWithVerticalAlignment(textId, function() { $('#' + id).find('*').andSelf().each(function(index, element) { element.style.cssText = parentObjectCache[element.id]; }); }); if($ax.event.mouseDownObjectId) { $ax.style.SetWidgetMouseDown($ax.event.mouseDownObjectId, true); } else if($ax.event.mouseOverObjectId) { $ax.style.SetWidgetHover($ax.event.mouseOverObjectId, true); } }; $ax.style.SetLinkHover = function(id) { _setLinkStyle(id, MOUSE_OVER); }; $ax.style.SetLinkNotHover = function(id) { _resetLinkStyle(id); }; $ax.style.SetLinkMouseDown = function(id) { _setLinkStyle(id, MOUSE_DOWN); }; $ax.style.SetLinkNotMouseDown = function(id) { _resetLinkStyle(id); var style = _computeAllOverrides(id, $ax.event.mouseOverObjectId, MOUSE_OVER, $ax.adaptive.currentViewId); if(!$.isEmptyObject(style)) $ax.style.SetLinkHover(id); //we dont do anything here because the widget not mouse down has taken over here }; var _widgetHasState = function(id, state) { if($ax.style.getElementImageOverride(id, state)) return true; var diagramObject = $ax.getObjectFromElementId(id); var adaptiveIdChain = $ax.adaptive.getAdaptiveIdChain($ax.adaptive.currentViewId); for(var i = 0; i < adaptiveIdChain.length; i++) { var viewId = adaptiveIdChain[i]; var adaptiveStyle = diagramObject.adaptiveStyles[viewId]; if(adaptiveStyle && adaptiveStyle.stateStyles && adaptiveStyle.stateStyles[state]) return true; } if(diagramObject.style.stateStyles) return diagramObject.style.stateStyles[state]; return false; }; // Returns what overrides the hover, or false if nothing. var _hoverOverride = function(id) { if($ax.style.IsWidgetDisabled(id)) return DISABLED; if($ax.style.IsWidgetSelected(id)) return SELECTED; var obj = $ax.getObjectFromElementId(id); if(!obj.isContained) return false; var path = $ax.getPathFromScriptId($ax.repeater.getScriptIdFromElementId(id)); path[path.length - 1] = obj.parent.id; var itemId = $ax.repeater.getItemIdFromElementId(id); return _hoverOverride($ax.getElementIdFromPath(path, { itemNum: itemId })); }; $ax.style.SetWidgetHover = function(id, value) { var override = _hoverOverride(id); if(override == DISABLED) return; if(!_widgetHasState(id, MOUSE_OVER)) return; var valToSet = value || _isRolloverOverride(id); var state = _generateMouseState(id, valToSet ? MOUSE_OVER : NORMAL, override == SELECTED); _applyImageAndTextJson(id, state); _updateElementIdImageStyle(id, state); }; var _rolloverOverrides = []; var _isRolloverOverride = function(id) { return _rolloverOverrides.indexOf(id) != -1; }; $ax.style.AddRolloverOverride = function(id) { if(_isRolloverOverride(id)) return; _rolloverOverrides[_rolloverOverrides.length] = id; if($ax.event.mouseOverIds.indexOf(id) == -1) $ax.style.SetWidgetHover(id, true); }; $ax.style.RemoveRolloverOverride = function(id) { var index = _rolloverOverrides.indexOf(id); if(index == -1) return; $ax.splice(_rolloverOverrides, index, 1); if($ax.event.mouseOverIds.indexOf(id) == -1) $ax.style.SetWidgetHover(id, false); }; // function GetWidgetCurrentState(id) { // if($ax.style.IsWidgetDisabled(id)) return "disabled"; // if($ax.style.IsWidgetSelected(id)) return "selected"; // if($ax.event.mouseOverObjectId == id) return "mouseOver"; // if($ax.event.mouseDownObjectId == id) return "mouseDown"; // return "normal"; // } $ax.style.ObjHasMouseDown = function(id) { var obj = $obj(id); if($ax.style.getElementImageOverride(id, 'mouseDown') || obj.style && obj.style.stateStyles && obj.style.stateStyles.mouseDown) return true; var chain = $ax.adaptive.getAdaptiveIdChain($ax.adaptive.currentViewId); for(var i = 0; i < chain.length; i++) { var style = obj.adaptiveStyles[chain[i]]; if(style && style.stateStyles && style.stateStyles.mouseDown) return true; } return false; }; $ax.style.SetWidgetMouseDown = function(id, value) { if($ax.style.IsWidgetDisabled(id)) return; if(!_widgetHasState(id, MOUSE_DOWN)) return; // ApplyImageAndTextJson(id, value ? 'mouseDown' : !$.isEmptyObject(GetStyleForState(id, null, 'mouseOver')) ? 'mouseOver' : 'normal'); var state = _generateMouseState(id, value ? MOUSE_DOWN : MOUSE_OVER, $ax.style.IsWidgetSelected(id)); _applyImageAndTextJson(id, state); _updateElementIdImageStyle(id, state); }; var _generateMouseState = function(id, mouseState, selected) { if (selected) { if (_style.getElementImageOverride(id, SELECTED)) return SELECTED; var viewChain = $ax.adaptive.getAdaptiveIdChain($ax.adaptive.currentViewId); viewChain[viewChain.length] = ''; var obj = $obj(id); if(obj.type == "dynamicPanel") return SELECTED; var any = function(dict) { for(var key in dict) return true; return false; }; for(var i = 0; i < viewChain.length; i++) { var viewId = viewChain[i]; // Need to check seperately for images. if(obj.adaptiveStyles && obj.adaptiveStyles[viewId] && any(obj.adaptiveStyles[viewId]) || obj.images && obj.images['selected~' + viewId]) return SELECTED; } var selectedStyle = obj.style && obj.style.stateStyles && obj.style.stateStyles.selected; if(selectedStyle && any(selectedStyle)) return SELECTED; } // Not using selected return mouseState; }; $ax.style.SetWidgetSelected = function(id, value, alwaysApply) { if(_isWidgetDisabled(id)) return; //NOTE: not firing select events if state didn't change var raiseSelectedEvents = $ax.style.IsWidgetSelected(id) != value; if(value) { var group = $('#' + id).attr('selectiongroup'); if(group) { $("[selectiongroup='" + group + "']").each(function() { var otherId = this.id; if(otherId == id) return; if ($ax.visibility.isScriptIdLimbo($ax.repeater.getScriptIdFromElementId(otherId))) return; $ax.style.SetWidgetSelected(otherId, false); }); } } var obj = $obj(id); if(obj) { var actionId = id; if ($ax.public.fn.IsDynamicPanel(obj.type) || $ax.public.fn.IsLayer(obj.type)) { if(!value) $jobj(id).removeClass('selected'); var children = $axure('#' + id).getChildren()[0].children; for(var i = 0; i < children.length; i++) { var childId = children[i]; // Special case for trees var childObj = $jobj(childId); if(childObj.hasClass('treeroot')) { var treenodes = childObj.find('.treenode'); for(var j = 0; j < treenodes.length; j++) { $axure('#' + treenodes[j].id).selected(value); } } else $axure('#' + childId).selected(value); } } else { var widgetHasSelectedState = _widgetHasState(id, SELECTED); while(obj.isContained && !widgetHasSelectedState) obj = obj.parent; var itemId = $ax.repeater.getItemIdFromElementId(id); var path = $ax.getPathFromScriptId($ax.repeater.getScriptIdFromElementId(id)); path[path.length - 1] = obj.id; actionId = $ax.getElementIdFromPath(path, { itemNum: itemId }); if(alwaysApply || widgetHasSelectedState) { var state = _generateSelectedState(actionId, value); _applyImageAndTextJson(actionId, state); _updateElementIdImageStyle(actionId, state); } //added actionId and this hacky logic because we set style state on child, but interaction on parent //then the id saved in _selectedWidgets would be depended on widgetHasSelectedState... more see case 1818143 while(obj.isContained && !$ax.getObjectFromElementId(id).interactionMap) obj = obj.parent; path = $ax.getPathFromScriptId($ax.repeater.getScriptIdFromElementId(id)); path[path.length - 1] = obj.id; actionId = $ax.getElementIdFromPath(path, { itemNum: itemId }); } } // ApplyImageAndTextJson(id, value ? 'selected' : 'normal'); _selectedWidgets[id] = value; if(raiseSelectedEvents) $ax.event.raiseSelectedEvents(actionId, value); }; var _generateSelectedState = function(id, selected) { var mouseState = $ax.event.mouseDownObjectId == id ? MOUSE_DOWN : $.inArray(id, $ax.event.mouseOverIds) != -1 ? MOUSE_OVER : NORMAL; //var mouseState = $ax.event.mouseDownObjectId == id ? MOUSE_DOWN : $ax.event.mouseOverIds.indexOf(id) != -1 ? MOUSE_OVER : NORMAL; return _generateMouseState(id, mouseState, selected); }; $ax.style.IsWidgetSelected = function(id) { return Boolean(_selectedWidgets[id]) || $('#'+id).hasClass('selected'); }; $ax.style.SetWidgetEnabled = function(id, value) { _disabledWidgets[id] = !value; $('#' + id).find('a').css('cursor', value ? 'pointer' : 'default'); if(!_widgetHasState(id, DISABLED)) return; if(!value) { _applyImageAndTextJson(id, DISABLED); _updateElementIdImageStyle(id, DISABLED); } else $ax.style.SetWidgetSelected(id, $ax.style.IsWidgetSelected(id), true); }; $ax.style.SetWidgetPlaceholder = function(id, value, text, password) { var inputId = $ax.repeater.applySuffixToElementId(id, '_input'); // Right now this is the only style on the widget. If other styles (ex. Rollover), are allowed // on TextBox/TextArea, or Placeholder is applied to more widgets, this may need to do more. var obj = $jobj(inputId); var height = document.getElementById(inputId).style['height']; var width = document.getElementById(inputId).style['width']; obj.attr('style', ''); //removing all styles, but now we can change the size, so we should add them back //this is more like a quick hack if (height) obj.css('height', height); if (width) obj.css('width', width); if(!value) { try { //ie8 and below error if(password) document.getElementById(inputId).type = 'password'; } catch(e) { } } else { var element = $('#' + inputId)[0]; var style = _computeAllOverrides(id, undefined, HINT, $ax.adaptive.currentViewId); var styleProperties = _getCssStyleProperties(style); //moved this out of GetCssStyleProperties for now because it was breaking un/rollovers with gradient fills if(style.fill) styleProperties.allProps.backgroundColor = _getColorFromFill(style.fill); _applyCssProps(element, styleProperties, true); try { //ie8 and below error if(password) document.getElementById(inputId).type = 'text'; } catch(e) { } } obj.val(text); }; var _isWidgetDisabled = $ax.style.IsWidgetDisabled = function(id) { return Boolean(_disabledWidgets[id]); }; var _elementIdsToImageOverrides = {}; $ax.style.mapElementIdToImageOverrides = function (elementId, override) { for(var key in override) _addImageOverride(elementId, key, override[key]); }; var _addImageOverride = function (elementId, state, val) { if (!_elementIdsToImageOverrides[elementId]) _elementIdsToImageOverrides[elementId] = {}; _elementIdsToImageOverrides[elementId][state] = val; } $ax.style.deleteElementIdToImageOverride = function(elementId) { delete _elementIdsToImageOverrides[elementId]; }; $ax.style.getElementImageOverride = function(elementId, state) { var url = _elementIdsToImageOverrides[elementId] && _elementIdsToImageOverrides[elementId][state]; return url; }; $ax.style.elementHasAnyImageOverride = function(elementId) { return Boolean(_elementIdsToImageOverrides[elementId]); }; var NORMAL = 'normal'; var MOUSE_OVER = 'mouseOver'; var MOUSE_DOWN = 'mouseDown'; var SELECTED = 'selected'; var DISABLED = 'disabled'; var HINT = 'hint'; var _generateState = _style.generateState = function(id) { return $ax.placeholderManager.isActive(id) ? HINT : _style.IsWidgetDisabled(id) ? DISABLED : _generateSelectedState(id, _style.IsWidgetSelected(id)); }; var _progressState = _style.progessState = function(state) { if(state == NORMAL) return false; if(state == MOUSE_DOWN) return MOUSE_OVER; return NORMAL; }; var _unprogressState = function(state, goal) { state = state || NORMAL; if(state == goal) return undefined; if(state == NORMAL && goal == MOUSE_DOWN) return MOUSE_OVER; return goal; }; var _updateElementIdImageStyle = _style.updateElementIdImageStyle = function(elementId, state) { if(!_style.elementHasAnyImageOverride(elementId)) return; if(!state) state = _generateState(elementId); var style = _computeFullStyle(elementId, state, $ax.adaptive.currentViewId); var query = $jobj($ax.repeater.applySuffixToElementId(elementId, '_img')); style.size.width = query.width(); style.size.height = query.height(); var borderId = $ax.repeater.applySuffixToElementId(elementId, '_border'); var borderQuery = $jobj(borderId); if(!borderQuery.length) { borderQuery = $('
'); borderQuery.attr('id', borderId); query.after(borderQuery); } borderQuery.attr('style', ''); borderQuery.css('position', 'absolute'); query.attr('style', ''); var borderWidth = Number(style.borderWidth); var hasBorderWidth = borderWidth > 0; if(hasBorderWidth) { borderQuery.css('border-style', 'solid'); borderQuery.css('border-width', borderWidth + 'px'); // If images start being able to turn off borders on specific sides, need to update this. borderQuery.css('width', style.size.width - borderWidth * 2); borderQuery.css('height', style.size.height - borderWidth * 2); } var linePattern = style.linePattern; if(hasBorderWidth && linePattern) borderQuery.css('border-style', linePattern); var borderFill = style.borderFill; if(hasBorderWidth && borderFill) { var color = borderFill.fillType == 'solid' ? borderFill.color : borderFill.fillType == 'linearGradient' ? borderFill.colors[0].color : 0; var alpha = Math.floor(color / 256 / 256 / 256); color -= alpha * 256 * 256 * 256; alpha = alpha / 255; var red = Math.floor(color / 256 / 256); color -= red * 256 * 256; var green = Math.floor(color / 256); var blue = color - green * 256; borderQuery.css('border-color', _rgbaToFunc(red, green, blue, alpha)); } var cornerRadiusTopLeft = style.cornerRadius; if(cornerRadiusTopLeft) { query.css('border-radius', cornerRadiusTopLeft + 'px'); borderQuery.css('border-radius', cornerRadiusTopLeft + 'px'); } var outerShadow = style.outerShadow; if(outerShadow && outerShadow.on) { var arg = ''; arg += outerShadow.offsetX + 'px' + ' ' + outerShadow.offsetY + 'px' + ' '; var rgba = outerShadow.color; arg += outerShadow.blurRadius + 'px' + ' 0px ' + _rgbaToFunc(rgba.r, rgba.g, rgba.b, rgba.a); query.css('-moz-box-shadow', arg); query.css('-wibkit-box-shadow', arg); query.css('box-shadow', arg); query.css('left', '0px'); query.css('top', '0px'); } query.css({ width: style.size.width, height: style.size.height }); }; var _rgbaToFunc = function(red, green, blue, alpha) { return 'rgba(' + red + ',' + green + ',' + blue + ',' + alpha + ')'; }; //function $ax.style.GetTextIdFromShape(id) { // return $.grep( // $('#' + id).children().map(function (i, obj) { return obj.id; }), // all the child ids // function (item) { return item.indexOf(id) < 0; })[0]; // that are not similar to the parent //} var _getButtonShapeId = function(id) { var obj = $obj(id); return $ax.public.fn.IsTreeNodeObject(obj.type) ? $ax.getElementIdFromPath([obj.buttonShapeId], { relativeTo: id }) : id; }; var _getButtonShape = function(id) { var obj = $obj(id); // some treeNodeObjects don't have button shapes return $jobj($ax.public.fn.IsTreeNodeObject(obj.type) && obj.buttonShapeId ? $ax.getElementIdFromPath([obj.buttonShapeId], { relativeTo: id }) : id); }; var _getTextIdFromShape = $ax.style.GetTextIdFromShape = function(id) { return _getButtonShape(id).find('.text').attr('id'); }; $ax.style.GetTextIdFromLink = function(id) { return $jobj(id).parentsUntil('.text').parent().attr('id'); }; var _getShapeIdFromText = $ax.style.GetShapeIdFromText = function(id) { if(!id) return undefined; // this is to prevent an infinite loop. var current = document.getElementById(id); if(!current) return undefined; current = current.parentElement; while(current && current.tagName != 'BODY') { var currentId = current.id; if(currentId && currentId != 'base') return $ax.visibility.getWidgetFromContainer(currentId); current = current.parentElement; } return undefined; }; $ax.style.GetImageIdFromShape = function(id) { var image = _getButtonShape(id).find('img[id$=img]'); if(!image.length) image = $jobj(id).find('img[id$=image_sketch]'); return image.attr('id'); }; var _applyImageAndTextJson = function(id, event) { var textId = $ax.style.GetTextIdFromShape(id); _resetTextJson(id, textId); // This should never be the case //if(event != '') { var imgQuery = $jobj($ax.style.GetImageIdFromShape(id)); var e = imgQuery.data('events'); if(e && e[event]) imgQuery.trigger(event); var imageUrl = $ax.adaptive.getImageForStateAndView(id, event); if(imageUrl) _applyImage(id, imageUrl, event); var style = _computeAllOverrides(id, undefined, event, $ax.adaptive.currentViewId); if(!$.isEmptyObject(style)) _applyTextStyle(textId, style); _updateStateClasses(id, event); _updateStateClasses($ax.repeater.applySuffixToElementId(id, '_div'), event); }; var _updateStateClasses = function(id, event) { var jobj = $jobj(id); //if(jobj[0] && jobj[0].hasAttribute('widgetwidth')) { // for (var x = 0; x < jobj[0].children.length; x++) { // var childId = jobj[0].children[x].id; // if (childId.indexOf('p') < 0) continue; // _updateStateClasses(childId, event) ; // } //} else { for (var i = 0; i < ALL_STATES.length; i++) jobj.removeClass(ALL_STATES[i]); if (event == 'mouseDown') jobj.addClass('mouseOver'); if(event != 'normal') jobj.addClass(event); //} } /* ------------------- here's the algorithm in a nutshell: [DOWN] -- refers to navigation down the view inheritance heirarchy (default to most specific) [UP] -- navigate up the heirarchy ComputeAllOverrides (object): All view styles [DOWN] If hyperlink - DO ComputeStateStyle for parent object - if (MouseOver || MouseDown) - linkMouseOver Style - if (MouseDown) - linkMouseDown style - ComputeStateStyleForViewChain (parent, STATE) if (MouseDown) DO ComputeStateStyleForViewChain for object, mouseOver DO ComputeStateStyleForViewChain for object, style ComputeStateStyleForViewChain (object, STATE) FIRST STATE state style [UP] the chain OR default object STATE style ------------------- */ var FONT_PROPS = { 'typeface': true, 'fontName': true, 'fontWeight': true, 'fontStyle': true, 'fontStretch': true, 'fontSize': true, 'underline': true, 'foreGroundFill': true, 'horizontalAlignment': true }; var _computeAllOverrides = $ax.style.computeAllOverrides = function(id, parentId, state, currentViewId) { var computedStyle = {}; if(parentId) computedStyle = _computeAllOverrides(parentId, null, state, currentViewId); var diagramObject = $ax.getObjectFromElementId(id); var viewIdChain = $ax.adaptive.getAdaptiveIdChain(currentViewId); var excludeFont = _shapesWithSetRichText[id]; for(var i = 0; i < viewIdChain.length; i++) { var viewId = viewIdChain[i]; var style = diagramObject.adaptiveStyles[viewId]; if(style) { // we want to exclude the normal font style for shapes where the rich text has been set with an interaction // so we copy the style so we don't modify the original, then delete all the font props. if(excludeFont) { style = $ax.deepCopy(style); for(var prop in FONT_PROPS) delete style[prop]; } if(style) { var customStyle = style.baseStyle && $ax.document.stylesheet.stylesById[style.baseStyle]; //make sure not to extend the customStyle this can mutate it for future use $.extend(computedStyle, customStyle); } $.extend(computedStyle, style); } } var currState = NORMAL; while(currState) { $.extend(computedStyle, _computeStateStyleForViewChain(diagramObject, currState, viewIdChain, true)); currState = _unprogressState(currState, state); } return _removeUnsupportedProperties(computedStyle, diagramObject.type); }; var _computeStateStyleForViewChain = function(diagramObject, state, viewIdChain, excludeNormal) { var styleObject = diagramObject; while(styleObject.isContained) styleObject = styleObject.parent; var adaptiveStyles = styleObject.adaptiveStyles; for(var i = viewIdChain.length - 1; i >= 0; i--) { var viewId = viewIdChain[i]; var viewStyle = adaptiveStyles[viewId]; var stateStyle = viewStyle && _getFullStateStyle(viewStyle, state, excludeNormal); if(stateStyle) return $.extend({}, stateStyle); } // we dont want to actually include the object style because those are not overrides, hence the true for "excludeNormal" and not passing the val through var stateStyleFromDefault = _getFullStateStyle(styleObject.style, state, true); return $.extend({}, stateStyleFromDefault); }; // returns the full effective style for an object in a state state and view var _computeFullStyle = function(id, state, currentViewId) { var obj = $obj(id); var overrides = _computeAllOverrides(id, undefined, state, currentViewId); // todo: account for image box var objStyle = obj.style; var customStyle = objStyle.baseStyle && $ax.document.stylesheet.stylesById[objStyle.baseStyle]; var returnVal = $.extend({}, $ax.document.stylesheet.defaultStyle, customStyle, objStyle, overrides); return _removeUnsupportedProperties(returnVal, obj.type); }; var _removeUnsupportedProperties = function(style, objectType) { // for now all we need to do is remove padding from checkboxes and radio buttons if ($ax.public.fn.IsRadioButton(objectType) || $ax.public.fn.IsCheckBox(objectType)) { style.paddingTop = 0; style.paddingLeft = 0; style.paddingRight = 0; style.paddingBottom = 0; } return style; }; var _getFullStateStyle = function(style, state, excludeNormal) { //'normal' is needed because now DiagramObjects get their image from the Style and unapplying a rollover needs the image var stateStyle = state == 'normal' && !excludeNormal ? style : style && style.stateStyles && style.stateStyles[state]; if(stateStyle) { var customStyle = stateStyle.baseStyle && $ax.document.stylesheet.stylesById[stateStyle.baseStyle]; //make sure not to extend the customStyle this can mutate it for future use return $.extend({}, customStyle, stateStyle); } return undefined; }; // commented this out for now... we actually will probably need it for ie var _applyOpacityFromStyle = $ax.style.applyOpacityFromStyle = function(id, style) { return; var opacity = style.opacity || ''; $jobj(id).children().css('opacity', opacity); }; var _initialize = function() { //being handled at on window.load //$ax.style.initializeObjectTextAlignment($ax('*')); }; $ax.style.initialize = _initialize; var _initTextAlignment = function(elementId) { var textId = _getTextIdFromShape(elementId); _storeIdToAlignProps(textId); // now handle vertical alignment if(_getObjVisible(textId)) { _setTextAlignment(textId, _idToAlignProps[textId], false); } }; $ax.style.initializeObjectTextAlignment = function(query) { query.filter(function(diagramObject) { return $ax.public.fn.IsVector(diagramObject.type) || $ax.public.fn.IsImageBox(diagramObject.type); }).each(function(diagramObject, elementId) { if($jobj(elementId).length == 0) return; _initTextAlignment(elementId); }); }; var _storeIdToAlignProps = function(textId) { var shapeId = _getShapeIdFromText(textId); var shapeObj = $obj(shapeId); var state = _generateState(shapeId); var style = _computeFullStyle(shapeId, state, $ax.adaptive.currentViewId); var vAlign = style.verticalAlignment || 'middle'; var paddingLeft = Number(style.paddingLeft) || 0; paddingLeft += (Number(shapeObj && shapeObj.extraLeft) || 0); var paddingTop = style.paddingTop || 0; var paddingRight = style.paddingRight || 0; var paddingBottom = style.paddingBottom || 0; _idToAlignProps[textId] = { vAlign: vAlign, paddingLeft: paddingLeft, paddingTop: paddingTop, paddingRight: paddingRight, paddingBottom: paddingBottom }; }; var ALL_STATES = ['mouseOver', 'mouseDown', 'selected', 'disabled']; var _applyImage = $ax.style.applyImage = function (id, imgUrl, state) { var object = $obj(id); if (object.generateCompound) { for (var i = 0; i < object.compoundChildren.length; i++) { var componentId = object.compoundChildren[i]; var childId = $ax.public.fn.getComponentId(id, componentId); var childImgQuery = $jobj(childId + '_img'); var childQuery = $jobj(childId); childImgQuery.attr('src', imgUrl[componentId]); for (var j = 0; j < ALL_STATES.length; j++) { childImgQuery.removeClass(ALL_STATES[j]); childQuery.removeClass(ALL_STATES[j]); } if (state != 'normal') { childImgQuery.addClass(state); childQuery.addClass(state); } } } else { var imgQuery = $jobj($ax.style.GetImageIdFromShape(id)); var idQuery = $jobj(id); //it is hard to tell if setting the image or the class first causing less flashing when adding shadows. imgQuery.attr('src', imgUrl); for (var i = 0; i < ALL_STATES.length; i++) { idQuery.removeClass(ALL_STATES[i]); imgQuery.removeClass(ALL_STATES[i]); } if (state != 'normal') { idQuery.addClass(state); imgQuery.addClass(state); } if (imgQuery.parents('a.basiclink').length > 0) imgQuery.css('border', 'none'); if (imgUrl.indexOf(".png") > -1) $ax.utils.fixPng(imgQuery[0]); } }; $ax.public.fn.getComponentId = function (id, componentId) { var idParts = id.split('-'); idParts[0] = idParts[0] + componentId; return idParts.join('-'); } var _resetTextJson = function(id, textid) { // reset the opacity $jobj(id).children().css('opacity', ''); var cacheObject = _originalTextCache[textid]; if(cacheObject) { _transformTextWithVerticalAlignment(textid, function() { var styleCache = cacheObject.styleCache; var textQuery = $('#' + textid); textQuery.find('*').each(function(index, element) { element.style.cssText = styleCache[element.id]; }); }); } }; // Preserves the alingment for the element textid after executing transformFn var _getRtfElementHeight = function(rtfElement) { if(rtfElement.innerHTML == '') rtfElement.innerHTML = ' '; // To handle render text as image var images = $(rtfElement).children('img'); if(images.length) return images.height(); return rtfElement.offsetHeight; }; // why microsoft decided to default to round to even is beyond me... var _roundToEven = function(number) { var numString = number.toString(); var parts = numString.split('.'); if(parts.length == 1) return number; if(parts[1].length == 1 && parts[1] == '5') { var wholePart = Number(parts[0]); return wholePart % 2 == 0 ? wholePart : wholePart + 1; } else return Math.round(number); }; var _transformTextWithVerticalAlignment = $ax.style.transformTextWithVerticalAlignment = function(textId, transformFn) { if(!_originalTextCache[textId]) { $ax.style.CacheOriginalText(textId); } var rtfElement = window.document.getElementById(textId); if(!rtfElement) return; transformFn(); _storeIdToAlignProps(textId); $ax.style.updateTextAlignmentForVisibility(textId); }; // this is for vertical alignments set on hidden objects var _idToAlignProps = {}; $ax.style.updateTextAlignmentForVisibility = function (textId) { var textObj = $jobj(textId); // must check if parent id exists. Doesn't exist for text objs in check boxes, and potentially elsewhere. var parentId = textObj.parent().attr('id'); if (parentId && $ax.visibility.isContainer(parentId)) return; var alignProps = _idToAlignProps[textId]; if(!alignProps || !_getObjVisible(textId)) return; _setTextAlignment(textId, alignProps); }; var _getObjVisible = _style.getObjVisible = function (id) { var element = document.getElementById(id); return element && (element.offsetWidth || element.offsetHeight); }; var _setTextAlignment = function (textId, alignProps, updateProps) { if(updateProps) { _storeIdToAlignProps(textId); } if(!alignProps) return; var vAlign = alignProps.vAlign; var paddingTop = Number(alignProps.paddingTop); var paddingBottom = Number(alignProps.paddingBottom); var paddingLeft = Number(alignProps.paddingLeft); var paddingRight = Number(alignProps.paddingRight); var topParam = 0.0; var bottomParam = 1.0; var leftParam = 0.0; var rightParam = 1.0; var textObj = $jobj(textId); var textHeight = _getRtfElementHeight(textObj[0]); var textObjParent = textObj.offsetParent(); var parentId = textObjParent.attr('id'); var isConnector = false; if(parentId) { parentId = $ax.visibility.getWidgetFromContainer(textObjParent.attr('id')); textObjParent = $jobj(parentId); var parentObj = $obj(parentId); if (parentObj['bottomTextPadding']) bottomParam = parentObj['bottomTextPadding']; if (parentObj['topTextPadding']) topParam = parentObj['topTextPadding']; if (parentObj['leftTextPadding']) leftParam = parentObj['leftTextPadding']; if (parentObj['rightTextPadding']) rightParam = parentObj['rightTextPadding']; // smart shapes are mutually exclusive from compound vectors. isConnector = parentObj.type == $ax.constants.CONNECTOR_TYPE; } if (isConnector) return; var axTextObjectParent = $ax('#' + textObjParent.attr('id')); var oldWidth = $ax.getNumFromPx(textObj.css('width')); var oldLeft = $ax.getNumFromPx(textObj.css('left')); var oldTop = $ax.getNumFromPx(textObj.css('top')); var newTop = 0; var newLeft = 0.0; var width = axTextObjectParent.width(); var height = axTextObjectParent.height(); // If text rotated need to handle getting the correct width for text based on bounding rect of rotated parent. var boundingRotation = -$ax.move.getRotationDegree(textId); var boundingParent = $axure.fn.getBoundingSizeForRotate(width, height, boundingRotation); var extraLeftPadding = (width - boundingParent.width) / 2; width = boundingParent.width; var relativeTop = 0.0; relativeTop = height * topParam; var containerHeight = height * bottomParam - relativeTop; if (vAlign == "middle") newTop = _roundToEven(relativeTop + (containerHeight - textHeight + paddingTop - paddingBottom) / 2); else if (vAlign == "bottom") newTop = _roundToEven(relativeTop + containerHeight - textHeight - paddingBottom); else newTop = _roundToEven(paddingTop + relativeTop); newLeft = paddingLeft + extraLeftPadding + width * leftParam; var newWidth = width * (rightParam - leftParam) - paddingLeft - paddingRight; var vertChange = oldTop != newTop; if (vertChange) textObj.css('top', newTop + 'px'); var horizChange = newWidth != oldWidth || newLeft != oldLeft; if (horizChange) { textObj.css('left', newLeft); textObj.width(newWidth); } if ((vertChange || horizChange)) _updateTransformOrigin(textId); }; var _updateTransformOrigin = function(textId) { var textObj = $jobj(textId); var transformOrigin = textObj.css('-webkit-transform-origin') || textObj.css('-moz-transform-origin') || textObj.css('-ms-transform-origin') || textObj.css('transform-origin'); if(transformOrigin) { var textObjParent = $ax('#' + textObj.parent().attr('id')); var newX = (textObjParent.width() / 2 - textObj.css('left').replace('px', '')); var newY = (textObjParent.height() / 2 - textObj.css('top').replace('px', '')); var newOrigin = newX + 'px ' + newY + 'px'; textObj.css('-webkit-transform-origin', newOrigin); textObj.css('-moz-transform-origin', newOrigin); textObj.css('-ms-transform-origin', newOrigin); textObj.css('transform-origin', newOrigin); } }; $ax.style.reselectElements = function() { for(var id in _selectedWidgets) { // Only looking for the selected widgets that don't have their class set if(!_selectedWidgets[id] || $jobj(id).hasClass('selected')) continue; $jobj(id).addClass('selected'); _applyImageAndTextJson(id, $ax.style.generateState(id)); } for(id in _disabledWidgets) { // Only looking for the disabled widgets that don't have their class yet if (!_disabledWidgets[id] || $jobj(id).hasClass('disabled')) continue; $jobj(id).addClass('disabled'); _applyImageAndTextJson(id, $ax.style.generateState(id)); } } $ax.style.clearAdaptiveStyles = function() { for(var shapeId in _adaptiveStyledWidgets) { var repeaterId = $ax.getParentRepeaterFromScriptId(shapeId); if(repeaterId) continue; var elementId = _getButtonShapeId(shapeId); if(elementId) { _applyImageAndTextJson(elementId, $ax.style.generateState(elementId)); } } _adaptiveStyledWidgets = {}; }; $ax.style.setAdaptiveStyle = function(shapeId, style) { _adaptiveStyledWidgets[$ax.repeater.getScriptIdFromElementId(shapeId)] = style; var textId = $ax.style.GetTextIdFromShape(shapeId); if(textId) _applyTextStyle(textId, style); $ax.placeholderManager.refreshPlaceholder(shapeId); // removing this for now // if(style.location) { // $jobj(shapeId).css('top', style.location.x + "px") // .css('left', style.location.y + "px"); // } }; //------------------------------------------------------------------------- // _applyTextStyle // // Applies a rollover style to a text element. // id : the id of the text object to set. // styleProperties : an object mapping style properties to values. eg: // { 'fontWeight' : 'bold', // 'fontStyle' : 'italic' } //------------------------------------------------------------------------- var _applyTextStyle = function(id, style) { _transformTextWithVerticalAlignment(id, function() { var styleProperties = _getCssStyleProperties(style); $('#' + id).find('*').each(function(index, element) { _applyCssProps(element, styleProperties); }); }); }; var _applyCssProps = function(element, styleProperties, applyAllStyle) { if(applyAllStyle) { var allProps = styleProperties.allProps; for(var prop in allProps) element.style[prop] = allProps[prop]; } else { var nodeName = element.nodeName.toLowerCase(); if(nodeName == 'p') { var parProps = styleProperties.parProps; for(prop in parProps) element.style[prop] = parProps[prop]; } else if(nodeName != 'a') { var runProps = styleProperties.runProps; for(prop in runProps) element.style[prop] = runProps[prop]; } } }; var _getCssShadow = function(shadow) { return !shadow.on ? "none" : shadow.offsetX + "px " + shadow.offsetY + "px " + shadow.blurRadius + "px " + _getCssColor(shadow.color); }; var _getCssStyleProperties = function(style) { var toApply = {}; toApply.runProps = {}; toApply.parProps = {}; toApply.allProps = {}; if(style.fontName) toApply.allProps.fontFamily = toApply.runProps.fontFamily = style.fontName; // we need to set font size on both runs and pars because otherwise it well mess up the measure and thereby vertical alignment if(style.fontSize) toApply.allProps.fontSize = toApply.runProps.fontSize = toApply.parProps.fontSize = style.fontSize; if(style.fontWeight !== undefined) toApply.allProps.fontWeight = toApply.runProps.fontWeight = style.fontWeight; if(style.fontStyle !== undefined) toApply.allProps.fontStyle = toApply.runProps.fontStyle = style.fontStyle; if(style.underline !== undefined) toApply.allProps.textDecoration = toApply.runProps.textDecoration = style.underline ? 'underline' : 'none'; if(style.foreGroundFill) { toApply.allProps.color = toApply.runProps.color = _getColorFromFill(style.foreGroundFill); //if(style.foreGroundFill.opacity) toApply.allProps.opacity = toApply.runProps.opacity = style.foreGroundFill.opacity; } if(style.horizontalAlignment) toApply.allProps.textAlign = toApply.parProps.textAlign = toApply.runProps.textAlign = style.horizontalAlignment; if(style.lineSpacing) toApply.allProps.lineHeight = toApply.parProps.lineHeight = style.lineSpacing; if(style.textShadow) toApply.allProps.textShadow = toApply.parProps.textShadow = _getCssShadow(style.textShadow); return toApply; }; var _getColorFromFill = function(fill) { //var fillString = '00000' + fill.color.toString(16); //return '#' + fillString.substring(fillString.length - 6); var val = fill.color; var color = {}; color.b = val % 256; val = Math.floor(val / 256); color.g = val % 256; val = Math.floor(val / 256); color.r = val % 256; color.a = typeof (fill.opacity) == 'number' ? fill.opacity : 1; return _getCssColor(color); }; var _getCssColor = function(rgbaObj) { return "rgba(" + rgbaObj.r + ", " + rgbaObj.g + ", " + rgbaObj.b + ", " + rgbaObj.a + ")"; }; // //-------------------------------------------------------------------------- // // ApplyStyleRecursive // // // // Applies a style recursively to all span and div tags including elementNode // // and all of its children. // // // // element : the element to apply the style to // // styleName : the name of the style property to set (eg. 'font-weight') // // styleValue : the value of the style to set (eg. 'bold') // //-------------------------------------------------------------------------- // function ApplyStyleRecursive(element, styleName, styleValue) { // var nodeName = element.nodeName.toLowerCase(); // if (nodeName == 'div' || nodeName == 'span' || nodeName == 'p') { // element.style[styleName] = styleValue; // } // for (var i = 0; i < element.childNodes.length; i++) { // ApplyStyleRecursive(element.childNodes[i], styleName, styleValue); // } // } // //--------------------------------------------------------------------------- // // ApplyTextProperty // // // // Applies a text property to rtfElement. // // // // rtfElement : the the root text element of the rtf object (this is the // // element named _rtf // // prop : the style property to set. // // value : the style value to set. // //--------------------------------------------------------------------------- // function ApplyTextProperty(rtfElement, prop, value) { // /* // var oldHtml = rtfElement.innerHTML; // if (prop == 'fontWeight') { // rtfElement.innerHTML = oldHtml.replace(/< *b *\/?>/gi, ""); // } else if (prop == 'fontStyle') { // rtfElement.innerHTML = oldHtml.replace(/< *i *\/?>/gi, ""); // } else if (prop == 'textDecoration') { // rtfElement.innerHTML = oldHtml.replace(/< *u *\/?>/gi, ""); // } // */ // for (var i = 0; i < rtfElement.childNodes.length; i++) { // ApplyStyleRecursive(rtfElement.childNodes[i], prop, value); // } // } //} //--------------------------------------------------------------------------- // GetAndCacheOriginalText // // Gets the html for the pre-rollover state and returns the Html representing // the Rich text. //--------------------------------------------------------------------------- var CACHE_COUNTER = 0; $ax.style.CacheOriginalText = function(textId, hasRichTextBeenSet) { var rtfQuery = $('#' + textId); if(rtfQuery.length > 0) { var styleCache = {}; rtfQuery.find('*').each(function(index, element) { var elementId = element.id; if(!elementId) element.id = elementId = 'cache' + CACHE_COUNTER++; styleCache[elementId] = element.style.cssText; }); _originalTextCache[textId] = { styleCache: styleCache }; if(hasRichTextBeenSet) { var shapeId = _getShapeIdFromText(textId); _shapesWithSetRichText[shapeId] = true; } } }; $ax.style.ClearCacheForRepeater = function(repeaterId) { for(var elementId in _originalTextCache) { var scriptId = $ax.repeater.getScriptIdFromElementId(elementId); if($ax.getParentRepeaterFromScriptId(scriptId) == repeaterId) delete _originalTextCache[elementId]; } }; $ax.style.prefetch = function() { var scriptIds = $ax.getAllScriptIds(); var image = new Image(); for(var i = 0; i < scriptIds.length; i++) { var obj = $obj(scriptIds[i]); if (!$ax.public.fn.IsImageBox(obj.type)) continue; var images = obj.images; for (var key in images) image.src = images[key]; var imageOverrides = obj.imageOverrides; for(var elementId in imageOverrides) { var override = imageOverrides[elementId]; for (var state in override) { _addImageOverride(elementId, state, override[state]); image.src = override[state]; } } } }; }); //***** adaptive.js *****// $axure.internal(function($ax) { $ax.adaptive = {}; $axure.utils.makeBindable($ax.adaptive, ["viewChanged"]); var _auto = true; var _autoIsHandledBySidebar = false; var _views; var _idToView; var _enabledViews = []; var _initialViewToLoad; var _initialViewSizeToLoad; var _loadFinished = false; $ax.adaptive.loadFinished = function() { if(_loadFinished) return; _loadFinished = true; if($ax.adaptive.currentViewId) $ax.viewChangePageAndMasters(); else $ax.postAdaptiveViewChanged(); }; var _handleResize = function(forceSwitchTo) { if(!_auto) return; if(_auto && _autoIsHandledBySidebar && !forceSwitchTo) return; var $window = $(window); var height = $window.height(); var width = $window.width(); var toView = _getAdaptiveView(width, height); var toViewId = toView && toView.id; _switchView(toViewId, forceSwitchTo); }; var _setAuto = $ax.adaptive.setAuto = function(val) { if(_auto != val) { _auto = Boolean(val); } }; var _setLineImage = function(id, imageUrl) { var imageQuery = $jobj(id).attr('src', imageUrl); if(imageUrl.indexOf(".png") > -1) $ax.utils.fixPng(imageQuery[0]); }; var _switchView = function (viewId, forceSwitchTo) { if(!$ax.pageData.isAdaptiveEnabled) return; var previousViewId = $ax.adaptive.currentViewId; if(typeof previousViewId == 'undefined') previousViewId = ''; if(typeof viewId == 'undefined') viewId = ''; if (viewId == previousViewId) { if(forceSwitchTo) $ax.postAdaptiveViewChanged(forceSwitchTo); return; } $ax('*').each(function(obj, elementId) { if (!$ax.public.fn.IsTreeNodeObject(obj.type)) return; if(!obj.hasOwnProperty('isExpanded')) return; var query = $ax('#' + elementId); var defaultExpanded = obj.isExpanded; query.expanded(defaultExpanded); }); // reset all the inline positioning from move and rotate actions including size and transformation $axure('*').each(function (diagramObject, elementId) { if(diagramObject.isContained) return; if($ax.getParentRepeaterFromElementIdExcludeSelf(elementId)) return; var element = document.getElementById(elementId); if(element) { var resetCss = { top: "", left: "", width: "", height: "", opacity: "", transform: "", webkitTransform: "", MozTransform: "", msTransform: "", OTransform: "" }; var query = $(element); query.css(resetCss); var isPanel = $ax.public.fn.IsDynamicPanel(diagramObject.type); if(!isPanel || diagramObject.fitToContent) { //keeps size on the panel states when switching adaptive views to optimize fit to panel if(diagramObject.fitToContent) $ax.dynamicPanelManager.setFitToContentCss(elementId, true); var children = query.children(); if(children.length) children.css(resetCss); } $ax.dynamicPanelManager.resetFixedPanel(diagramObject, element); $ax.dynamicPanelManager.resetAdaptivePercentPanel(diagramObject, element); } }); $ax.adaptive.currentViewId = viewId; // we need to set this so the enabled and selected styles will apply properly if(previousViewId) { $ax.style.clearAdaptiveStyles(); $('*').removeClass(previousViewId); } else { $ax.style.reselectElements(); } $axure('*').each(function (obj, elementId) { if($ax.getParentRepeaterFromElementIdExcludeSelf(elementId)) return; $ax.style.updateElementIdImageStyle(elementId); // When image override exists, fix styling/borders }); // reset all the images only if we're going back to the default view if(!viewId) { _updateInputVisibility('', $axure('*')); $axure('*').each(function (diagramObject, elementId) { if($ax.getParentRepeaterFromElementIdExcludeSelf(elementId)) return; $ax.placeholderManager.refreshPlaceholder(elementId); var images = diagramObject.images; if(diagramObject.type == 'horizontalLine' || diagramObject.type == 'verticalLine') { var startImg = images['start~']; _setLineImage(elementId + "_start", startImg); var endImg = images['end~']; _setLineImage(elementId + "_end", endImg); var lineImg = images['line~']; _setLineImage(elementId + "_line", lineImg); } else if(diagramObject.type == $ax.constants.CONNECTOR_TYPE) { _setAdaptiveConnectorImages(elementId, images, ''); } else if(images) { if (diagramObject.generateCompound) { if($ax.style.IsWidgetDisabled(elementId)) { disabledImage = _getImageWithTag(images, 'disabled~'); if(disabledImage) $ax.style.applyImage(elementId, disabledImage, 'disabled'); return; } if($ax.style.IsWidgetSelected(elementId)) { selectedImage = _getImageWithTag(images, 'selected~'); if(selectedImage) $ax.style.applyImage(elementId, selectedImage, 'selected'); return; } $ax.style.applyImage(elementId, _getImageWithTag(images, 'normal~')); } else { if ($ax.style.IsWidgetDisabled(elementId)) { var disabledImage = $ax.style.getElementImageOverride(elementId, 'disabled') || images['disabled~']; if (disabledImage) $ax.style.applyImage(elementId, disabledImage, 'disabled'); return; } if ($ax.style.IsWidgetSelected(elementId)) { var selectedImage = $ax.style.getElementImageOverride(elementId, 'selected') || images['selected~']; if (selectedImage) $ax.style.applyImage(elementId, selectedImage, 'selected'); return; } $ax.style.applyImage(elementId, $ax.style.getElementImageOverride(elementId, 'normal') || images['normal~']); } } //align all text var child = $jobj(elementId).children('.text'); if(child.length) $ax.style.transformTextWithVerticalAlignment(child[0].id, function() { }); }); // we have to reset visibility if we aren't applying a new view $ax.visibility.resetLimboAndHiddenToDefaults(); $ax.repeater.refreshAllRepeaters(); $ax.dynamicPanelManager.updateParentsOfNonDefaultFitPanels(); $ax.dynamicPanelManager.updatePercentPanelCache($ax('*')); } else { $ax.visibility.clearLimboAndHidden(); _applyView(viewId); $ax.repeater.refreshAllRepeaters(); $ax.dynamicPanelManager.updateParentsOfNonDefaultFitPanels(); } $ax.adaptive.triggerEvent('viewChanged', {}); if(_loadFinished) $ax.viewChangePageAndMasters(forceSwitchTo); }; var _getImageWithTag = function(image, tag) { var flattened = {}; for (var component in image) { var componentImage = image[component][tag]; if(componentImage) flattened[component] = componentImage; } return flattened; } // gets if input is hidden due to sketch var BORDER_WIDTH = "borderWidth"; var COLOR_STYLE = "colorStyle"; var SKETCH_FACTOR = "sketchFactor"; var _areInputsHidden = function(viewId) { var chain = _getAdaptiveIdChain(viewId); var page = $ax.pageData.page; var adaptiveStyles = page.adaptiveStyles; // keep track of props that are not sketchy, as you continue to climb up your parents; var notSketch = []; for(var i = chain.length - 1; i >= -1; i--) { var style = i == -1 ? page.style : adaptiveStyles[chain[i]]; if(notSketch.indexOf(BORDER_WIDTH) == -1 && style.hasOwnProperty(BORDER_WIDTH)) { if(style[BORDER_WIDTH] != 0) return true; notSketch.push(BORDER_WIDTH); } if(notSketch.indexOf(COLOR_STYLE) == -1 && style.hasOwnProperty(COLOR_STYLE)) { if(style[COLOR_STYLE] != 'appliedColor') return true; notSketch.push(COLOR_STYLE); } if(notSketch.indexOf(SKETCH_FACTOR) == -1 && style.hasOwnProperty(SKETCH_FACTOR)) { if(style[SKETCH_FACTOR] != 0) return true; notSketch.push(SKETCH_FACTOR); } } return false; }; var _updateInputVisibility = function(viewId, query) { var func = _areInputsHidden(viewId) ? 'addClass' : 'removeClass'; query.each(function(obj, elementId) { var input = $jobj($ax.repeater.applySuffixToElementId(elementId, '_input')); if(input.length == 0) return; input[func]('form_sketch'); }); }; // gets the inheritance chain of a particular view. var _getAdaptiveIdChain = $ax.adaptive.getAdaptiveIdChain = function(viewId) { if(!viewId) return []; var view = _idToView[viewId]; var chain = []; var current = view; while(current) { chain[chain.length] = current.id; current = _idToView[current.baseViewId]; } return chain.reverse(); }; var _getPageStyle = $ax.adaptive.getPageStyle = function() { var currentViewId = $ax.adaptive.currentViewId; var adaptiveChain = _getAdaptiveIdChain(currentViewId); var currentStyle = $.extend({}, $ax.pageData.page.style); for(var i = 0; i < adaptiveChain.length; i++) { var viewId = adaptiveChain[i]; $.extend(currentStyle, $ax.pageData.page.adaptiveStyles[viewId]); } return currentStyle; }; var _setAdaptiveLineImages = function(elementId, images, viewIdChain) { for(var i = viewIdChain.length - 1; i >= 0; i--) { var viewId = viewIdChain[i]; var startImg = images['start~' + viewId]; if(startImg) { _setLineImage(elementId + "_start", startImg); var endImg = images['end~' + viewId]; _setLineImage(elementId + "_end", endImg); var lineImg = images['line~' + viewId]; _setLineImage(elementId + "_line", lineImg); break; } } }; var _setAdaptiveConnectorImages = function (elementId, images, view) { var conn = $jobj(elementId); var count = conn.children().length-1; // -1 for rich text panel for(var i = 0; i < count; i++) { var img = images['' + i + '~' + view]; $jobj(elementId + '_seg' + i).attr('src', img); } }; var _applyView = $ax.adaptive.applyView = function(viewId, query) { var limboIds = {}; var hiddenIds = {}; var jquery; if(query) { jquery = query.jQuery(); jquery = jquery.add(jquery.find('*')); var jqueryAnn = $ax.annotation.jQueryAnn(query); jquery = jquery.add(jqueryAnn); } else { jquery = $('*'); query = $ax('*'); } jquery.addClass(viewId); _updateInputVisibility(viewId, query); var viewIdChain = _getAdaptiveIdChain(viewId); // this could be made more efficient by computing it only once per object query.each(function(diagramObject, elementId) { _applyAdaptiveViewOnObject(diagramObject, elementId, viewIdChain, viewId, limboIds, hiddenIds); }); $ax.visibility.addLimboAndHiddenIds(limboIds, hiddenIds, query); //$ax.dynamicPanelManager.updateAllFitPanelsAndLayerSizeCaches(); $ax.dynamicPanelManager.updatePercentPanelCache(query); }; var _applyAdaptiveViewOnObject = function(diagramObject, elementId, viewIdChain, viewId, limboIds, hiddenIds) { var adaptiveChain = []; for(var i = 0; i < viewIdChain.length; i++) { var viewId = viewIdChain[i]; var viewStyle = diagramObject.adaptiveStyles[viewId]; if(viewStyle) { adaptiveChain[adaptiveChain.length] = viewStyle; if (viewStyle.size) $ax.public.fn.convertToSingleImage($jobj(elementId)); } } var state = $ax.style.generateState(elementId); // set the image var images = diagramObject.images; if(images) { if(diagramObject.type == 'horizontalLine' || diagramObject.type == 'verticalLine') { _setAdaptiveLineImages(elementId, images, viewIdChain); } else if (diagramObject.type == $ax.constants.CONNECTOR_TYPE) { _setAdaptiveConnectorImages(elementId, images, viewId); } else if (diagramObject.generateCompound) { var compoundUrl = _matchImageCompound(diagramObject, elementId, viewIdChain, state); if (compoundUrl) $ax.style.applyImage(elementId, compoundUrl, state); }else { var imgUrl = _matchImage(elementId, images, viewIdChain, state); if(imgUrl) $ax.style.applyImage(elementId, imgUrl, state); } // for(var i = viewIdChain.length - 1; i >= 0; i--) { // var viewId = viewIdChain[i]; // var imgUrl = $ax.style.getElementImageOverride(elementId, state) || images[state + '~' + viewId] || images['normal~' + viewId]; // if(imgUrl) { // $ax.style.applyImage(elementId, imgUrl, state); // break; // } // } // } } // addaptive override style (not including default style props) var adaptiveStyle = $ax.style.computeAllOverrides(elementId, undefined, state, viewId); // this style INCLUDES the object's my style var compoundStyle = $.extend({}, diagramObject.style, adaptiveStyle); //$ax.style.setAdaptiveStyle(elementId, adaptiveStyle); if(!diagramObject.isContained) { $ax.style.setAdaptiveStyle(elementId, adaptiveStyle); } var scriptId = $ax.repeater.getScriptIdFromElementId(elementId); if(compoundStyle.limbo && !diagramObject.isContained) limboIds[scriptId] = true; // sigh, javascript. we need the === here because undefined means not overriden if(compoundStyle.visible === false) hiddenIds[scriptId] = true; }; var _matchImage = function(id, images, viewIdChain, state) { var override = $ax.style.getElementImageOverride(id, state); if(override) return override; if(!images) return undefined; // first check all the images for this state for(var i = viewIdChain.length - 1; i >= 0; i--) { var viewId = viewIdChain[i]; var img = images[state + "~" + viewId]; if(img) return img; } // check for the default state style var defaultStateImage = images[state + '~']; if(defaultStateImage) return defaultStateImage; state = $ax.style.progessState(state); if(state) return _matchImage(id, images, viewIdChain, state); // SHOULD NOT REACH HERE! NORMAL SHOULD ALWAYS CATCH AT THE DEFAULT! return images['normal~']; // this is the default }; var _matchImageCompound = function(diagramObject, id, viewIdChain, state) { var images = []; for(var i = 0; i < diagramObject.compoundChildren.length; i++) { var component = diagramObject.compoundChildren[i]; images[component] = _matchImage(id, diagramObject.images[component], viewIdChain, state); } return images; }; $ax.adaptive.getImageForStateAndView = function(id, state) { var viewIdChain = _getAdaptiveIdChain($ax.adaptive.currentViewId); var diagramObject = $ax.getObjectFromElementId(id); if (diagramObject.generateCompound) return _matchImageCompound(diagramObject, id, viewIdChain, state); else return _matchImage(id, diagramObject.images, viewIdChain, state); }; var _getAdaptiveView = function(winWidth, winHeight) { var _isViewOneGreaterThanTwo = function(view1, view2) { return view1.size.width > view2.size.width || (view1.size.width == view2.size.width && view1.size.height > view2.size.height); }; var _isViewOneLessThanTwo = function(view1, view2) { var width2 = view2.size.width || 1000000; // artificially large number var height2 = view2.size.height || 1000000; var width1 = view1.size.width || 1000000; var height1 = view1.size.height || 1000000; return width1 < width2 || (width1 == width2 && height1 < height2); }; var _isWindowGreaterThanView = function(view, width, height) { return width >= view.size.width && height >= view.size.height; }; var _isWindowLessThanView = function(view1, width, height) { var viewWidth = view1.size.width || 1000000; var viewHeight = view1.size.height || 1000000; return width <= viewWidth && height <= viewHeight; }; var greater = undefined; var less = undefined; for(var i = 0; i < _enabledViews.length; i++) { var view = _enabledViews[i]; if(view.condition == ">=") { if(_isWindowGreaterThanView(view, winWidth, winHeight)) { if(!greater || _isViewOneGreaterThanTwo(view, greater)) greater = view; } } else { if(_isWindowLessThanView(view, winWidth, winHeight)) { if(!less || _isViewOneLessThanTwo(view, less)) less = view; } } } return less || greater; }; var _isAdaptiveInitialized = function() { return typeof _idToView != 'undefined'; }; $ax.messageCenter.addMessageListener(function(message, data) { //If the adaptive plugin hasn't been initialized yet then //save the view to load so that it can get set when initialize occurs if(message == 'switchAdaptiveView') { var href = window.location.href.split('#')[0]; var lastSlash = href.lastIndexOf('/'); href = href.substring(lastSlash + 1); if(href != data.src) return; var view = data.view == 'auto' ? undefined : (data.view == 'default' ? '' : data.view); if(!_isAdaptiveInitialized()) { _initialViewToLoad = view; } else _handleLoadViewId(view); } else if(message == 'setAdaptiveViewForSize') { _autoIsHandledBySidebar = true; if(!_isAdaptiveInitialized()) { _initialViewSizeToLoad = data; } else _handleSetViewForSize(data.width, data.height); } }); $ax.adaptive.setAdaptiveView = function(view) { var viewIdForSitemapToUnderstand = view == 'auto' ? undefined : (view == 'default' ? '' : view); if(!_isAdaptiveInitialized()) { _initialViewToLoad = viewIdForSitemapToUnderstand; } else _handleLoadViewId(viewIdForSitemapToUnderstand); }; $ax.adaptive.initialize = function() { _views = $ax.document.adaptiveViews; _idToView = {}; if(_views && _views.length > 0) { for(var i = 0; i < _views.length; i++) { var view = _views[i]; _idToView[view.id] = view; } var enabledViewIds = $ax.document.configuration.enabledViewIds; for(var i = 0; i < enabledViewIds.length; i++) { _enabledViews[_enabledViews.length] = _idToView[enabledViewIds[i]]; } if(_autoIsHandledBySidebar && _initialViewSizeToLoad) _handleSetViewForSize(_initialViewSizeToLoad.width, _initialViewSizeToLoad.height); else _handleLoadViewId(_initialViewToLoad); } $axure.resize(function(e) { _handleResize(); $ax.postResize(e); //window resize fires after view changed }); }; var _handleLoadViewId = function (loadViewId, forceSwitchTo) { if(typeof loadViewId != 'undefined') { _setAuto(false); _switchView(loadViewId != 'default' ? loadViewId : '', forceSwitchTo); } else { _setAuto(true); _handleResize(forceSwitchTo); } }; var _handleSetViewForSize = function (width, height) { if(!_auto) return; var toView = _getAdaptiveView(width, height); var toViewId = toView && toView.id; _switchView(toViewId); }; $ax.adaptive.getSketchKey = function() { return $ax.pageData.sketchKeys[$ax.adaptive.currentViewId || '']; } }); //***** tree.js *****// // This is actually for BOTH trees and menus $axure.internal(function($ax) { var _tree = $ax.tree = {}; var _menu = $ax.menu = {}; $ax.menu.InitializeSubmenu = function(subMenuId, cellId) { var $submenudiv = $('#' + subMenuId); //mouseenter and leave for parent table cell $('#' + cellId).mouseenter(function(e) { //show current submenu // var submenuElement = document.getElementById(subMenuId); // if($ax.visibility.IsVisible(submenuElement) && submenuElement.style.display !== 'none') return; $ax.visibility.SetIdVisible(subMenuId, true); $ax.legacy.BringToFront(subMenuId); _fireEventForSubmenu(subMenuId, "onShow"); }).mouseleave(function (e) { var offset = $submenudiv.offset(); var subcontwidth = $submenudiv.width(); var subcontheight = $submenudiv.height(); //If mouse is not within the submenu (added 3 pixel margin to top and left calculations), then close the submenu... if(e.pageX + 3 < offset.left || e.pageX > offset.left + subcontwidth || e.pageY + 3 < offset.top || e.pageY > offset.top + subcontheight) { $submenudiv.find('.sub_menu').andSelf().each(function () { // if(!$ax.visibility.IsVisible(this)) return; $ax.visibility.SetVisible(this, false); _fireEventForSubmenu(subMenuId, "onHide"); }); $ax.style.SetWidgetHover(cellId, false); } }); $submenudiv.css('display', 'none'); //mouseleave for submenu $submenudiv.mouseleave(function(e) { //close this menu and all menus below it $(this).find('.sub_menu').andSelf().css({ 'visibility': 'hidden', 'display': 'none' }).each(function () { // if(!$ax.visibility.IsVisible(this)) return; _fireEventForSubmenu(this.id, "onHide"); }); $ax.style.SetWidgetHover(cellId, false); }); }; var _fireEventForSubmenu = function(targetId, eventName) { var diagramObject = $ax.getObjectFromElementId(targetId); var event = diagramObject.interactionMap && diagramObject.interactionMap[eventName]; if(event) { var eventInfo = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), false, targetId); $ax.event.handleEvent(targetId, eventInfo, event, false, true); } } function IsNodeVisible(nodeId) { var current = window.document.getElementById(nodeId); var parent = current.parentNode; //move all the parent's children that are below the node and their annotations while(!$(current).hasClass("treeroot")) { if(!$ax.visibility.IsVisible(parent)) return false; current = parent; parent = parent.parentNode; } return true; } $ax.tree.ExpandNode = function(nodeId, childContainerId, plusMinusId) { var container = window.document.getElementById(childContainerId); if(!container || $ax.visibility.IsVisible(container)) return; $ax.visibility.SetVisible(container, true); if(plusMinusId != '') $ax.style.SetWidgetSelected(plusMinusId, true); var delta = _getExpandCollapseDelta(nodeId, childContainerId); var isVisible = IsNodeVisible(nodeId); var current = window.document.getElementById(nodeId); var parent = current.parentNode; //move all the parent's children that are below the node and their annotations while(!$(current).hasClass("treeroot")) { var after = false; var i = 0; for(i = 0; i < parent.childNodes.length; i++) { var child = parent.childNodes[i]; if(after && child.id && $(child).hasClass("treenode")) { var elementId = child.id; child.style.top = Number($(child).css('top').replace("px", "")) + delta + 'px'; var ann = window.document.getElementById(elementId + "_ann"); if(ann) ann.style.top = Number($(ann).css('top').replace("px", "")) + delta + 'px'; } if(child == current) after = true; } current = parent; parent = parent.parentNode; if(!isVisible && $ax.visibility.IsVisible(parent)) break; } }; $ax.tree.CollapseNode = function(nodeId, childContainerId, plusMinusId) { var container = window.document.getElementById(childContainerId); if(!container || !$ax.visibility.IsVisible(container)) return; if(plusMinusId != '') $ax.style.SetWidgetSelected(plusMinusId, false); var delta = _getExpandCollapseDelta(nodeId, childContainerId); //hide it after getting the delta, otherwise the delta can't be calculated (offsetParent is null) $ax.visibility.SetVisible(container, false); var isVisible = IsNodeVisible(nodeId); var current = window.document.getElementById(nodeId); var parent = current.parentNode; //move all the parent's children that are below the node and their annotations while(!$(current).hasClass("treeroot")) { var after = false; var i = 0; for(i = 0; i < parent.childNodes.length; i++) { var child = parent.childNodes[i]; if(after && child.id && $(child).hasClass("treenode")) { var elementId = child.id; child.style.top = Number($(child).css('top').replace("px", "")) - delta + 'px'; var ann = window.document.getElementById(elementId + "_ann"); if(ann) ann.style.top = Number($(ann).css('top').replace("px", "")) - delta + 'px'; } if(child == current) after = true; } current = parent; parent = current.parentNode; if(!isVisible && $ax.visibility.IsVisible(parent)) break; } }; var _getExpandCollapseDelta = function(nodeId, childContainerId) { return _getChildContainerHeightHelper(childContainerId); }; var _getChildContainerHeightHelper = function(childContainerId) { var height = 0; $('#' + childContainerId).children().each(function() { if($(this).hasClass("treenode")) { height += $(this).height(); var subContainer = window.document.getElementById(this.id + '_children'); if(subContainer && $ax.visibility.IsVisible(subContainer)) { height += _getChildContainerHeightHelper(subContainer.id); } } }); return height; }; $ax.tree.InitializeTreeNode = function(nodeId, plusminusid, childContainerId, selectText) { var childContainer = window.document.getElementById(childContainerId); if(childContainer) { //relying on the html generator to put this inline so we know to collapse by default var isCollapsed = childContainer.style.visibility == "hidden"; if(isCollapsed) $ax.visibility.SetVisible(childContainer, false); if(!isCollapsed && plusminusid != '') $ax.style.SetWidgetSelected(plusminusid, true); } if(plusminusid != '') { $jobj(plusminusid).click(function() { var visibleSet = $ax.visibility.IsIdVisible(childContainerId); if(visibleSet) $ax.tree.CollapseNode(nodeId, childContainerId, plusminusid); else $ax.tree.ExpandNode(nodeId, childContainerId, plusminusid); $ax.tree.SelectTreeNode(nodeId, true); return false; }).css('cursor', 'default'); } }; var _getButtonShapeId = function(id) { var obj = $obj(id); return $ax.public.fn.IsTreeNodeObject(obj.type) ? $ax.getElementIdFromPath([obj.buttonShapeId], { relativeTo: id }) : id; }; $ax.tree.SelectTreeNode = function(id, selected) { $ax.style.SetWidgetSelected(_getButtonShapeId(id), selected); }; }); //***** init.temp.js *****// $axure.internal(function($ax) { $(window.document).ready(function() { var readyStart = (new Date()).getTime(); //this is because the page id is not formatted as a guid var pageId = $ax.pageData.page.packageId; var pageData = { id: pageId, pageName: $ax.pageData.page.name, location: window.location.toString(), notes: $ax.pageData.page.notes }; var anns = []; $ax('*').each(function (dObj, elementId) { pushAnnotation(dObj, elementId); }); function pushAnnotation(dObj, elementId) { var ann = dObj.annotation; if(ann) { ann["id"] = elementId; ann["label"] = dObj.label + " (" + dObj.friendlyType + ")"; anns.push(ann); } if(dObj.type == 'repeater') { if(dObj.objects) { for(var i = 0, len = dObj.objects.length; i < len; i++) { pushAnnotation(dObj.objects[i]); } } } } pageData.widgetNotes = anns; //only trigger the page.data setting if the window is on the mainframe var isMainFrame = false; try { if(window.name == 'mainFrame' || (!CHROME_5_LOCAL && window.parent.$ && window.parent.$('#mainFrame').length > 0)) { isMainFrame = true; $ax.messageCenter.addMessageListener(function(message, data) { if(message == 'finishInit') { _processTempInit(); } }); $axure.messageCenter.setState('page.data', pageData); window.focus(); } } catch(e) { } //attach here for chrome local $(window).load(function() { $ax.style.initializeObjectTextAlignment($ax('*')); }); if(!isMainFrame) _processTempInit(); }); var _processTempInit = function() { //var start = (new Date()).getTime(); //var end = (new Date()).getTime(); //window.alert('elapsed ' + (end - start)); $('iframe').each(function() { var origSrc = $(this).attr('basesrc'); var $this = $(this); if(origSrc) { var newSrcUrl = origSrc.toLowerCase().indexOf('http://') == -1 ? $ax.globalVariableProvider.getLinkUrl(origSrc) : origSrc; $this.attr('src', newSrcUrl); } if(IOS) { $this.parent().css('overflow', 'auto').css('-webkit-overflow-scrolling', 'touch').css('-ms-overflow-x', 'hidden').css('overflow-x', 'hidden'); } }); $axure.messageCenter.addMessageListener(function(message, data) { if(message == 'setGlobalVar') { $ax.globalVariableProvider.setVariableValue(data.globalVarName, data.globalVarValue, true); } }); window.lastFocusedClickable = null; var _lastFocusedClickableSelector = 'input, a'; var shouldOutline = true; $ax(function (dObj) { return dObj.tabbable; }).each(function (dObj, elementId) { if ($ax.public.fn.IsLayer(dObj.type)) $ax.event.layerMapFocus(dObj, elementId); var focusableId = $ax.event.getFocusableWidgetOrChildId(elementId); var $focusable = $('#' + focusableId); $focusable.attr("tabIndex", 0); if($focusable.is('div') || $focusable.is('img')) { $focusable.bind($ax.features.eventNames.mouseDownName, function() { shouldOutline = false; }); attachFocusAndBlur($focusable); } }); $(window.document).bind($ax.features.eventNames.mouseUpName, function() { shouldOutline = true; }); attachFocusAndBlur($(_lastFocusedClickableSelector)); function attachFocusAndBlur($query) { $query.focus(function () { if(shouldOutline) { $(this).css('outline', ''); } else { $(this).css('outline', 'none'); } window.lastFocusedClickable = this; }).blur(function () { if(window.lastFocusedClickable == this) window.lastFocusedClickable = null; }); } $(window.document).bind('keyup', function(e) { if(e.keyCode == '13' || e.keyCode == '32') { if(window.lastFocusedClickable) $(window.lastFocusedClickable).click(); } }); if($ax.document.configuration.hideAddress) { $(window).load(function() { window.setTimeout(function() { window.scrollTo(0, 0.9); }, 0); }); } if($ax.document.configuration.preventScroll) { $(window.document).bind('touchmove', function(e) { var inScrollable = $ax.legacy.GetScrollable(e.target) != window.document.body; if(!inScrollable) { e.preventDefault(); } }); $ax(function(diagramObject) { return $ax.public.fn.IsDynamicPanel(diagramObject.type) && diagramObject.scrollbars != 'none'; }).$().children().bind('touchstart', function() { var target = this; var top = target.scrollTop; if(top <= 0) target.scrollTop = 1; if(top + target.offsetHeight >= target.scrollHeight) target.scrollTop = target.scrollHeight - target.offsetHeight - 1; }); } if(OS_MAC && WEBKIT) { $ax(function(diagramObject) { return $ax.public.fn.IsComboBox(diagramObject.type); }).each(function(obj, id) { $jobj($ax.INPUT(id)).css('-webkit-appearance', 'menulist-button'); }); } $ax.legacy.BringFixedToFront(); $ax.event.initialize(); $ax.style.initialize(); $ax.visibility.initialize(); $ax.repeater.initialize(); $ax.dynamicPanelManager.initialize(); //needs to be called after visibility is initialized $ax.adaptive.initialize(); $ax.loadDynamicPanelsAndMasters(); $ax.adaptive.loadFinished(); var start = (new Date()).getTime(); $ax.repeater.initRefresh(); var end = (new Date()).getTime(); console.log('loadTime: ' + (end - start) / 1000); $ax.style.prefetch(); $(window).resize(); //var readyEnd = (new Date()).getTime(); //window.alert('elapsed ' + (readyEnd - readyStart)); }; }); /* extend canvas */ var gv_hasCanvas = false; (function() { var _canvas = document.createElement('canvas'), proto, abbrev; if(gv_hasCanvas = !!(_canvas.getContext && _canvas.getContext('2d')) && typeof (CanvasGradient) !== 'undefined') { function chain(func) { return function() { return func.apply(this, arguments) || this; }; } with(proto = CanvasRenderingContext2D.prototype) for(var func in abbrev = { a: arc, b: beginPath, n: clearRect, c: clip, p: closePath, g: createLinearGradient, f: fill, j: fillRect, z: function(s) { this.fillStyle = s; }, l: lineTo, w: function(w) { this.lineWidth = w; }, m: moveTo, q: quadraticCurveTo, h: rect, r: restore, o: rotate, s: save, x: scale, y: function(s) { this.strokeStyle = s; }, u: setTransform, k: stroke, i: strokeRect, t: translate }) proto[func] = chain(abbrev[func]); CanvasGradient.prototype.a = chain(CanvasGradient.prototype.addColorStop); } })(); //***** legacy.js *****// //stored on each browser event var windowEvent; $axure.internal(function($ax) { var _legacy = {}; $ax.legacy = _legacy; // ************************** GLOBAL VARS *********************************// // ************************************************************************// //Check if IE //var bIE = false; //if ((index = navigator.userAgent.indexOf("MSIE")) >= 0) { // bIE = true; //} var Forms = window.document.getElementsByTagName("FORM"); for(var i = 0; i < Forms.length; i++) { var Form = Forms[i]; Form.onclick = $ax.legacy.SuppressBubble; } $ax.legacy.SuppressBubble = function(event) { if(IE_10_AND_BELOW) { window.event.cancelBubble = true; window.event.returnValue = false; } else { if(event) { event.stopPropagation(); } } }; // function InsertAfterBegin(dom, html) { // if(!IE) { // var phtml; // var range = dom.ownerDocument.createRange(); // range.selectNodeContents(dom); // range.collapse(true); // phtml = range.createContextualFragment(html); // dom.insertBefore(phtml, dom.firstChild); // } else { // dom.insertAdjacentHTML("afterBegin", html); // } // } // function InsertBeforeEnd(dom, html) { // if(!IE) { // var phtml; // var range = dom.ownerDocument.createRange(); // range.selectNodeContents(dom); // range.collapse(dom); // phtml = range.createContextualFragment(html); // dom.appendChild(phtml); // } else { // dom.insertAdjacentHTML("beforeEnd", html); // } // } //Get the id of the Workflow Dialog belonging to element with id = id // function Workflow(id) { // return id + 'WF'; // } $ax.legacy.BringToFront = function(id, skipFixed) { _bringToFrontHelper(id); if(!skipFixed) $ax.legacy.BringFixedToFront(); }; var _bringToFrontHelper = function(id) { var target = window.document.getElementById(id); if(target == null) return; $ax.globals.MaxZIndex = $ax.globals.MaxZIndex + 1; target.style.zIndex = $ax.globals.MaxZIndex; }; $ax.legacy.BringFixedToFront = function() { $ax(function(diagramObject) { return diagramObject.fixedKeepInFront; }).each(function(diagramObject, scriptId) { _bringToFrontHelper(scriptId); }); }; $ax.legacy.SendToBack = function(id) { var target = window.document.getElementById(id); if(target == null) return; target.style.zIndex = $ax.globals.MinZIndex = $ax.globals.MinZIndex - 1; }; $ax.legacy.RefreshScreen = function() { var oldColor = window.document.body.style.backgroundColor; var setColor = (oldColor == "rgb(0,0,0)") ? "#FFFFFF" : "#000000"; window.document.body.style.backgroundColor = setColor; window.document.body.style.backgroundColor = oldColor; }; $ax.legacy.getAbsoluteLeft = function(currentNode, elementId) { var oldDisplay = currentNode.css('display'); var displaySet = false; if(oldDisplay == 'none') { currentNode.css('display', ''); displaySet = true; } var left = currentNode.offset().left; // Special Layer code if($ax.getTypeFromElementId(elementId) == 'layer') { var first = true; var children = currentNode.children(); for(var i = 0; i < children.length; i++) { var child = $(children[i]); var subDisplaySet = false; if(child.css('display') == 'none') { child.css('display', ''); subDisplaySet = true; } if(first) left = child.offset().left; else left = Math.min(child.offset().left, left); first = false; if(subDisplaySet) child.css('display', 'none'); } } if (displaySet) currentNode.css('display', oldDisplay); return $axure.fn.bodyToWorld(left, true); }; $ax.legacy.getAbsoluteTop = function(currentNode, elementId) { var oldDisplay = currentNode.css('display'); var displaySet = false; if(oldDisplay == 'none') { currentNode.css('display', ''); displaySet = true; } var top = currentNode.offset().top; // Special Layer code if ($ax.getTypeFromElementId(elementId) == 'layer') { var first = true; var children = currentNode.children(); for (var i = 0; i < children.length; i++) { var child = $(children[i]); var subDisplaySet = false; if (child.css('display') == 'none') { child.css('display', ''); subDisplaySet = true; } if (first) top = child.offset().top; else top = Math.min(child.offset().top, top); first = false; if (subDisplaySet) child.css('display', 'none'); } } if(displaySet) currentNode.css('display', oldDisplay); return top; }; // ****************** Annotation and Link Functions ****************** // $ax.legacy.GetAnnotationHtml = function(annJson) { var retVal = ""; for(var noteName in annJson) { if(noteName != "label" && noteName != "id") { retVal += "
" + noteName + "
"; retVal += "
" + linkify(annJson[noteName]) + "
"; } } return retVal; function linkify(text) { var urlRegex = /(\b(((https?|ftp|file):\/\/)|(www\.))[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; return text.replace(urlRegex, function (url, b, c) { var url2 = (c == 'www.') ? 'http://' + url : url; return '' + url + ''; }); } }; $ax.legacy.GetScrollable = function(target) { var $target = $(target); var last = $target; // Start past inital target. Can't scroll to target in itself, must be some ancestor. var current = last.parent(); while(!current.is('body') && !current.is('html')) { var elementId = current.attr('id'); var diagramObject = elementId && $ax.getObjectFromElementId(elementId); if(diagramObject && $ax.public.fn.IsDynamicPanel(diagramObject.type) && diagramObject.scrollbars != 'none') { //returns the panel diagram div which handles scrolling return $ax.dynamicPanelManager.getShownState(current.attr('id'))[0]; } last = current; current = current.parent(); } // Need to do this because of ie if(IE_10_AND_BELOW) return window.document.documentElement; else return window.document.body; }; }); //***** viewer.js *****// // ******* SITEMAP TOOLBAR VIEWER ACTIONS ******** // $axure.internal(function ($ax) { var userTriggeredEventNames = ['onClick', 'onDoubleClick', 'onMouseOver', 'onMouseMove', 'onMouseOut', 'onMouseDown', 'onMouseUp', 'onKeyDown', 'onKeyUp', 'onFocus', 'onLostFocus', 'onTextChange', 'onSelectionChange', 'onSelectedChange', 'onSelect', 'onUnselect', 'onSwipeLeft', 'onSwipeRight', 'onSwipeUp', 'onSwipeDown', 'onDragStart', 'onDrag', 'onDragDrop', 'onScroll', 'onContextMenu', 'onMouseHover', 'onLongClick']; $ax.messageCenter.addMessageListener(function(message, data) { //If annotation toggle message received from sitemap, toggle footnotes if(message == 'annotationToggle') { if(data == true) { $('div.annotation').show(); $('div.annnotelabel').show(); $('div.annnoteimage').show(); } else { $('div.annotation').hide(); $('div.annnotelabel').hide(); $('div.annnoteimage').hide(); } } }); var lastSelectedWidgetNote; $ax.messageCenter.addMessageListener(function (message, data) { //If annotation toggle message received from sitemap, toggle footnotes if(message == 'toggleSelectWidgetNote') { if(lastSelectedWidgetNote == data) { $('#' + lastSelectedWidgetNote).removeClass('widgetNoteSelected'); lastSelectedWidgetNote = null; return; } if(lastSelectedWidgetNote) $('#' + lastSelectedWidgetNote).removeClass('widgetNoteSelected'); $('#' + data).addClass('widgetNoteSelected'); lastSelectedWidgetNote = data; } }); var highlightEnabled = false; $ax.messageCenter.addMessageListener(function(message, data) { if(message == 'highlightInteractive') { highlightEnabled = data == true; _applyHighlight($ax('*')); } }); var _applyHighlight = $ax.applyHighlight = function(query, ignoreUnset) { if(ignoreUnset && !highlightEnabled) return; var pulsateClassName = 'legacyPulsateBorder'; //Find all widgets with a defined userTriggeredEventName specified in the array above var $matchingElements = query.filter(function(obj) { if(obj.interactionMap) { for(var index in userTriggeredEventNames) { if(obj.interactionMap[userTriggeredEventNames[index]]) return true; } } else if ($ax.public.fn.IsVector(obj.type) && obj.referencePageUrl) { return true; } return false; }).$(); var isHighlighted = $matchingElements.is('.' + pulsateClassName); //Toggle the pulsate class on the matched elements if(highlightEnabled && !isHighlighted) { $matchingElements.addClass(pulsateClassName); } else if(!highlightEnabled && isHighlighted) { $matchingElements.removeClass(pulsateClassName); } }; }); //***** math.js *****// $axure.internal(function($ax) { $ax.public.fn.matrixMultiply = function(matrix, vector) { if(!matrix.tx) matrix.tx = 0; if(!matrix.ty) matrix.ty = 0; var outX = matrix.m11 * vector.x + matrix.m12 * vector.y + matrix.tx; var outY = matrix.m21 * vector.x + matrix.m22 * vector.y + matrix.ty; return { x: outX, y: outY }; } $ax.public.fn.matrixInverse = function(matrix) { if(!matrix.tx) matrix.tx = 0; if(!matrix.ty) matrix.ty = 0; var determinant = matrix.m11*matrix.m22 - matrix.m12*matrix.m21; //var threshold = (M11 * M11 + M22 *M22 + M12 *M12+ M21 *M21) / 100000; //if(determinant.DeltaEquals(0, threshold) && determinant < 0.01) { // return Invalid; //} return { m11 : matrix.m22/determinant, m12 : -matrix.m12/determinant, tx : (matrix.ty*matrix.m12 - matrix.tx*matrix.m22)/determinant, m21: -matrix.m21 / determinant, m22: matrix.m11 / determinant, ty: (matrix.tx * matrix.m21 - matrix.ty * matrix.m11) / determinant }; } $ax.public.fn.matrixMultiplyMatrix = function (matrix1, matrix2) { if (!matrix1.tx) matrix1.tx = 0; if (!matrix1.ty) matrix1.ty = 0; if (!matrix2.tx) matrix2.tx = 0; if (!matrix2.ty) matrix2.ty = 0; return { m11: matrix1.m12*matrix2.m21 + matrix1.m11*matrix2.m11, m12: matrix1.m12*matrix2.m22 + matrix1.m11*matrix2.m12, tx: matrix1.m12 * matrix2.ty + matrix1.m11 * matrix2.tx + matrix1.tx, m21: matrix1.m22 * matrix2.m21 + matrix1.m21 * matrix2.m11, m22: matrix1.m22 * matrix2.m22 + matrix1.m21 * matrix2.m12, ty: matrix1.m22 * matrix2.ty + matrix1.m21 * matrix2.tx + matrix1.ty, }; } $ax.public.fn.transformFromElement = function (element) { var st = window.getComputedStyle(element, null); var tr = st.getPropertyValue("-webkit-transform") || st.getPropertyValue("-moz-transform") || st.getPropertyValue("-ms-transform") || st.getPropertyValue("-o-transform") || st.getPropertyValue("transform"); if (tr.indexOf('none') < 0) { var matrix = tr.split('(')[1]; matrix = matrix.split(')')[0]; matrix = matrix.split(','); for (var l = 0; l < matrix.length; l++) { matrix[l] = Number(matrix[l]); } } else { matrix = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]; } return matrix; // matrix[0] = cosine, matrix[1] = sine. // Assuming the element is still orthogonal. } $ax.public.fn.vectorMinus = function(vector1, vector2) { return { x: vector1.x - vector2.x, y: vector1.y - vector2.y }; } $ax.public.fn.vectorPlus = function (vector1, vector2) { return { x: vector1.x + vector2.x, y: vector1.y + vector2.y }; } $ax.public.fn.vectorMidpoint = function (vector1, vector2) { return { x: (vector1.x + vector2.x) / 2.0, y: (vector1.y + vector2.y) / 2.0 }; } $ax.public.fn.fourCornersToBasis = function (fourCorners) { return { widthVector: $ax.public.fn.vectorMinus(fourCorners.widgetTopRight, fourCorners.widgetTopLeft), heightVector: $ax.public.fn.vectorMinus(fourCorners.widgetBottomLeft, fourCorners.widgetTopLeft) }; } $ax.public.fn.matrixString = function(m11, m21, m12, m22, tx, ty) { return "Matrix(" + m11 + "," + m21 + "," + m12 + "," + m22 + ", " + tx + ", " + ty + ")"; } $ax.public.fn.getWidgetBoundingRect = function (widgetId) { var emptyRect = { left: 0, top: 0, centerPoint: { x: 0, y: 0 }, width: 0, height: 0 }; var element = document.getElementById(widgetId); if (!element) return emptyRect; var object = $obj(widgetId); if (object && object.type && $ax.public.fn.IsLayer(object.type)) { var layerChildren = _getLayerChildrenDeep(widgetId); if (!layerChildren) return emptyRect; else return _getBoundingRectForMultipleWidgets(layerChildren); } return _getBoundingRectForSingleWidget(widgetId); }; var _getLayerChildrenDeep = $ax.public.fn.getLayerChildrenDeep = function (layerId, includeLayers, includeHidden) { var deep = []; var children = $ax('#' + layerId).getChildren()[0].children; for (var index = 0; index < children.length; index++) { var childId = children[index]; if(!includeHidden && !$ax.visibility.IsIdVisible(childId)) continue; if ($ax.public.fn.IsLayer($obj(childId).type)) { if (includeLayers) deep.push(childId); var recursiveChildren = _getLayerChildrenDeep(childId, includeLayers, includeHidden); for (var j = 0; j < recursiveChildren.length; j++) deep.push(recursiveChildren[j]); } else deep.push(childId); } return deep; }; var _getBoundingRectForMultipleWidgets = function (widgetsIdArray, relativeToPage) { if (!widgetsIdArray || widgetsIdArray.constructor !== Array) return undefined; if (widgetsIdArray.length == 0) return { left: 0, top: 0, centerPoint: { x: 0, y: 0 }, width: 0, height: 0 }; var widgetRect = _getBoundingRectForSingleWidget(widgetsIdArray[0], relativeToPage, true); var boundingRect = { left: widgetRect.left, right: widgetRect.right, top: widgetRect.top, bottom: widgetRect.bottom }; for (var index = 1; index < widgetsIdArray.length; index++) { widgetRect = _getBoundingRectForSingleWidget(widgetsIdArray[index], relativeToPage); boundingRect.left = Math.min(boundingRect.left, widgetRect.left); boundingRect.top = Math.min(boundingRect.top, widgetRect.top); boundingRect.right = Math.max(boundingRect.right, widgetRect.right); boundingRect.bottom = Math.max(boundingRect.bottom, widgetRect.bottom); } boundingRect.centerPoint = { x: (boundingRect.right + boundingRect.left) / 2.0, y: (boundingRect.bottom + boundingRect.top) / 2.0 }; boundingRect.width = boundingRect.right - boundingRect.left; boundingRect.height = boundingRect.bottom - boundingRect.top; return boundingRect; }; var _getBoundingRectForSingleWidget = function (widgetId, relativeToPage, justSides) { var element = document.getElementById(widgetId); var boundingRect, tempBoundingRect, position; var displayChanged = _displayHackStart(element); if (_isCompoundVectorHtml(element)) { //tempBoundingRect = _getCompoundImageBoundingClientSize(widgetId); //position = { left: tempBoundingRect.left, top: tempBoundingRect.top }; position = $(element).position(); tempBoundingRect = {}; tempBoundingRect.left = position.left; //= _getCompoundImageBoundingClientSize(widgetId); tempBoundingRect.top = position.top; tempBoundingRect.width = Number(element.getAttribute('WidgetWidth')); tempBoundingRect.height = Number(element.getAttribute('WidgetHeight')); } else { tempBoundingRect = element.getBoundingClientRect(); var jElement = $(element); position = jElement.position(); if(jElement.css('position') == 'fixed') { position.left += Number(jElement.css('margin-left').replace("px", "")); position.top += Number(jElement.css('margin-top').replace("px", "")); } } var layers = $ax('#' + widgetId).getParents(true, ['layer'])[0]; var flip = ''; var mirrorWidth = 0; var mirrorHeight = 0; for (var i = 0; i < layers.length; i++) { //should always be 0,0 var layerPos = $jobj(layers[i]).position(); position.left += layerPos.left; position.top += layerPos.top; var outer = $ax.visibility.applyWidgetContainer(layers[i], true, true); if (outer.length) { var outerPos = outer.position(); position.left += outerPos.left; position.top += outerPos.top; } //when a group is flipped we find the unflipped position var inner = $jobj(layers[i] + '_container_inner'); var taggedFlip = inner.data('flip'); if (inner.length && taggedFlip) { //only account for flip if transform is applied var matrix = taggedFlip && (inner.css("-webkit-transform") || inner.css("-moz-transform") || inner.css("-ms-transform") || inner.css("-o-transform") || inner.css("transform")); if (matrix !== 'none') { flip = taggedFlip; mirrorWidth = $ax.getNumFromPx(inner.css('width')); mirrorHeight = $ax.getNumFromPx(inner.css('height')); } } } //Now account for flip if (flip == 'x') position.top = mirrorHeight - position.top - element.getBoundingClientRect().height; else if (flip == 'y') position.left = mirrorWidth - position.left - element.getBoundingClientRect().width; boundingRect = { left: position.left, right: position.left + tempBoundingRect.width, top: position.top, bottom: position.top + tempBoundingRect.height }; _displayHackEnd(displayChanged); if (justSides) return boundingRect; boundingRect.width = boundingRect.right - boundingRect.left; boundingRect.height = boundingRect.bottom - boundingRect.top; boundingRect.centerPoint = { x: boundingRect.width / 2 + boundingRect.left, y: boundingRect.height / 2 + boundingRect.top }; return boundingRect; }; var _getPointAfterRotate = $ax.public.fn.getPointAfterRotate = function (angleInDegrees, pointToRotate, centerPoint) { var displacement = $ax.public.fn.vectorMinus(pointToRotate, centerPoint); var rotationMatrix = $ax.public.fn.rotationMatrix(angleInDegrees); rotationMatrix.tx = centerPoint.x; rotationMatrix.ty = centerPoint.y; return $ax.public.fn.matrixMultiply(rotationMatrix, displacement); }; $ax.public.fn.getBoundingSizeForRotate = function(width, height, rotation) { // point to rotate around doesn't matter since we just care about size, if location matter we need more args and location matters. var origin = { x: 0, y: 0 }; var corner1 = { x: width, y: 0 }; var corner2 = { x: 0, y: height }; var corner3 = { x: width, y: height }; corner1 = _getPointAfterRotate(rotation, corner1, origin); corner2 = _getPointAfterRotate(rotation, corner2, origin); corner3 = _getPointAfterRotate(rotation, corner3, origin); var left = Math.min(0, corner1.x, corner2.x, corner3.x); var right = Math.max(0, corner1.x, corner2.x, corner3.x); var top = Math.min(0, corner1.y, corner2.y, corner3.y); var bottom = Math.max(0, corner1.y, corner2.y, corner3.y); return { width: right - left, height: bottom - top }; } $ax.public.fn.getPositionRelativeToParent = function (elementId) { var element = document.getElementById(elementId); var list = _displayHackStart(element); var position = $(element).position(); _displayHackEnd(list); return position; }; var _displayHackStart = $ax.public.fn.displayHackStart = function (element) { // TODO: Options: 1) stop setting display none. Big change for this late in the game. 2) Implement our own bounding. // TODO: 3) Current method is look for any parents that are set to none, and and temporarily unblock. Don't like it, but it works. var parent = element; var displays = []; while (parent) { if (parent.style.display == 'none') { displays.push(parent); //use block to overwrites default hidden objects' display parent.style.display = 'block'; } parent = parent.parentElement; } return displays; }; var _displayHackEnd = $ax.public.fn.displayHackEnd = function (displayChangedList) { for (var i = 0; i < displayChangedList.length; i++) displayChangedList[i].style.display = 'none'; }; var _isCompoundVectorHtml = $ax.public.fn.isCompoundVectorHtml = function(hElement) { return hElement.hasAttribute('compoundmode') && hElement.getAttribute('compoundmode') == "true"; } $ax.public.fn.removeCompound = function (jobj) { if(_isCompoundVectorHtml(jobj[0])) jobj.removeClass('compound'); } $ax.public.fn.restoreCompound = function (jobj) { if (_isCompoundVectorHtml(jobj[0])) jobj.addClass('compound'); } $ax.public.fn.compoundIdFromComponent = function(id) { var pPos = id.indexOf('p'); var dashPos = id.indexOf('-'); if (pPos < 1) return id; else if (dashPos < 0) return id.substring(0, pPos); else return id.substring(0, pPos) + id.substring(dashPos); } $ax.public.fn.l2 = function (x, y) { return Math.sqrt(x * x + y * y); } $ax.public.fn.convertToSingleImage = function (jobj) { if(!jobj[0]) return; var widgetId = jobj[0].id; var object = $obj(widgetId); if ($ax.public.fn.IsLayer(object.type)) { var recursiveChildren = _getLayerChildrenDeep(widgetId, true); for (var j = 0; j < recursiveChildren.length; j++) $ax.public.fn.convertToSingleImage($jobj(recursiveChildren[j])); return; } //var layer = if(!_isCompoundVectorHtml(jobj[0])) return; $('#' + widgetId).removeClass("compound"); $('#' + widgetId + '_img').removeClass("singleImg"); jobj[0].setAttribute('compoundmode', 'false'); var components = object.compoundChildren; delete object.generateCompound; for (var i = 0; i < components.length; i++) { var componentJobj = $jobj($ax.public.fn.getComponentId(widgetId, components[i])); componentJobj.css('display', 'none'); componentJobj.css('visibility', 'hidden'); } } $ax.public.fn.getContainerDimensions = function(query) { // returns undefined if no containers found. var containerDimensions; for (var i = 0; i < query[0].children.length; i++) { var node = query[0].children[i]; if (node.id.indexOf(query[0].id) >= 0 && node.id.indexOf('container') >= 0) { containerDimensions = node.style; } } return containerDimensions; } $ax.public.fn.rotationMatrix = function (angleInDegrees) { var angleInRadians = angleInDegrees * (Math.PI / 180); var cosTheta = Math.cos(angleInRadians); var sinTheta = Math.sin(angleInRadians); return { m11: cosTheta, m12: -sinTheta, m21: sinTheta, m22: cosTheta, tx: 0.0, ty: 0.0 }; } $ax.public.fn.GetFieldFromStyle = function (query, field) { var raw = query[0].style[field]; if (!raw) raw = query.css(field); return Number(raw.replace('px', '')); } $ax.public.fn.setTransformHowever = function (transformString) { return { '-webkit-transform': transformString, '-moz-transform': transformString, '-ms-transform': transformString, '-o-transform': transformString, 'transform': transformString }; } });