axplayer.js 142 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419
  1. var PLUGIN_VAR_NAME = 'g';
  2. var FOOTNOTES_VAR_NAME = 'fn';
  3. var ADAPTIVE_VIEW_VAR_NAME = 'view';
  4. var SCALE_VAR_NAME = 'sc';
  5. var DIM_VAR_NAME = 'dm';
  6. var ROT_VAR_NAME = 'r';
  7. var CLOUD_VAR_NAME = 'cl';
  8. var TRACE_VAR_NAME = 'tr';
  9. var RP_VERSION = 9;
  10. var lastLeftPanelWidth = 220;
  11. var lastRightPanelWidth = 290;
  12. var lastLeftPanelWidthDefault = 220;
  13. var lastRightPanelWidthDefault = 290;
  14. var toolBarOnly = true;
  15. // isolate scope
  16. (function () {
  17. // replace hash to query
  18. if (window.location.hash) {
  19. replaceHashToQuery();
  20. }
  21. if (!window.$axure) window.$axure = function () { };
  22. if (typeof console == 'undefined') console = {
  23. log: function () { }
  24. };
  25. if (window._axUtils) $axure.utils = _axUtils;
  26. setUpController();
  27. var getHashStringVar = $axure.player.getHashStringVar = function (query) {
  28. var qstring = self.location.href.split("?");
  29. if (qstring.length < 2) return "";
  30. return GetParameter(qstring, query);
  31. }
  32. var isCloud = $axure.player.isCloud = getHashStringVar(CLOUD_VAR_NAME);
  33. if (isCloud) {
  34. $("#topPanel").css('display', 'none');
  35. }else {
  36. $("#topPanel").css('display', '');
  37. }
  38. $axure.loadDocument = function (document) {
  39. $axure.document = document;
  40. var configuration = $axure.document.configuration;
  41. var _settings = {};
  42. _settings.projectId = configuration.prototypeId;
  43. _settings.projectName = configuration.projectName;
  44. _settings.isAxshare = configuration.isAxshare;
  45. _settings.isExpo = configuration.isExpo == null ? false : configuration.isExpo;
  46. _settings.loadSitemap = configuration.loadSitemap;
  47. _settings.loadFeedbackPlugin = configuration.loadFeedbackPlugin;
  48. var cHash = getHashStringVar(SITEMAP_COLLAPSE_VAR_NAME);
  49. _settings.startCollapsed = cHash == SITEMAP_COLLAPSE_VALUE;
  50. if (cHash == SITEMAP_CLOSE_VALUE) closePlayer();
  51. var gHash = getHashStringVar(PLUGIN_VAR_NAME);
  52. _settings.startPluginGid = gHash;
  53. $axure.player.settings = _settings;
  54. var additionalJs = $axure.document.additionalJs;
  55. if (additionalJs != null) {
  56. var total = additionalJs.length;
  57. if (total > 0) $.holdReady(true);
  58. $.each(additionalJs, function (index, value) {
  59. var script = window.document.createElement("script");
  60. script.type = "text/javascript";
  61. script.src = value;
  62. script.async = false;
  63. script.onload = script.onreadystatechange = function (e) {
  64. if (!script.readyState || /loaded|complete/.test(script.readyState)) {
  65. script.onload = script.onreadystatechange = null;
  66. script = undefined;
  67. }
  68. if (--total == 0) $.holdReady(false);
  69. }
  70. window.document.head.appendChild(script);
  71. });
  72. }
  73. var additionalCss = $axure.document.additionalCss;
  74. if(additionalCss != null) {
  75. $.each(additionalCss, function(index, value) {
  76. var style = window.document.createElement('link');
  77. style.type = "text/css";
  78. style.rel = "stylesheet";
  79. style.href = value;
  80. window.document.head.appendChild(style);
  81. });
  82. }
  83. if(_settings.isExpo && configuration.isMobile) {
  84. initializeDeviceFrame();
  85. }
  86. // Pseudo-indicator that the document has been loaded
  87. $axure.document.isLoaded = true;
  88. };
  89. $(window).bind('load', function () {
  90. if ((CHROME && BROWSER_VERSION < 64) || // First 2018 release
  91. (SAFARI && BROWSER_VERSION < 602) || // Minor version 10
  92. (FIREFOX && BROWSER_VERSION < 57) || // Support Quantum
  93. ($axure.browser.isEdge && BROWSER_VERSION < 15) || // 15 for mobile devices (else could go 16, possibly 17)
  94. (!$axure.browser.isEdge && IE)) {
  95. if (!QQ && !UC) appendOutOfDateNotification();
  96. }
  97. if (CHROME_5_LOCAL && !$('body').attr('pluginDetected')) {
  98. window.location = 'resources/chrome/chrome.html';
  99. }
  100. if (FIREFOX && BROWSER_VERSION >= 68 && document.location.href.indexOf('file://') >= 0) { //detecting firefox and local
  101. window.location = 'resources/chrome/firefox.html';
  102. }
  103. });
  104. $(window).on('hashchange', function() {
  105. window.location.reload();
  106. });
  107. function replaceHashToQuery() {
  108. var urlObj = new URL(window.location.href);
  109. // add parameters from hash to query
  110. const vars = urlObj.hash.substring(1).split("&");
  111. for (let i = 0; i < vars.length; i++) {
  112. const pair = vars[i].split("=");
  113. urlObj.searchParams.set(pair[0], pair[1]);
  114. }
  115. // remove hash from url
  116. urlObj.hash = "";
  117. if (typeof window.history.replaceState != 'undefined') {
  118. try {
  119. window.history.replaceState("", "", urlObj.href);
  120. } catch (ex) { }
  121. } else {
  122. window.location.replace(urlObj.href);
  123. }
  124. }
  125. function appendOutOfDateNotification() {
  126. var toAppend = '';
  127. toAppend += '<div id="browserOutOfDateNotification">';
  128. toAppend += ' <div style="font-size: 24px; text-align: center; color: #FFFFFF;">LOOKS LIKE YOUR BROWSER IS OUT OF DATE</div>';
  129. toAppend += ' <div style="font-size: 14px; text-align: center; color: #FFFFFF; margin-bottom: 16px;">This prototype may not look or function correctly until you update your browser</div>';
  130. toAppend += ' <div id="supportedBrowsersListContainer">';
  131. toAppend += ' <div class="browserContainer">';
  132. toAppend += ' <div class="browserName">Google Chrome</div><div class="browserSupportedVersion">v64 and later</div>';
  133. toAppend += ' </div>';
  134. toAppend += ' <div class="browserContainer">';
  135. toAppend += ' <div class="browserName">Mozilla Firefox</div><div class="browserSupportedVersion">v57 and later</div>';
  136. toAppend += ' </div>';
  137. toAppend += ' <div class="browserContainer">';
  138. toAppend += ' <div class="browserName">Microsoft Edge</div><div class="browserSupportedVersion">v15 and later</div>';
  139. toAppend += ' </div>';
  140. toAppend += ' <div class="browserContainer">';
  141. toAppend += ' <div class="browserName">Apple Safari</div><div class="browserSupportedVersion">v10 and later</div>';
  142. toAppend += ' </div>';
  143. toAppend += ' </div>';
  144. toAppend += ' <div id="browserOutOfDateNotificationButtons">'
  145. if (!MOBILE_DEVICE) {
  146. toAppend += ' <div style="margin-right: 36px"><a href="http://outdatedbrowser.com/en" id="updateBrowserButton">UPDATE BROWSER</a></div>';
  147. toAppend += ' <div style="flex: 0 1 45%;"><a id="continueToPrototypeButton">Continue viewing prototype anyway</a></div>';
  148. } else {
  149. toAppend += ' <div style="width: 100%; text-align:center"><a id="continueToPrototypeButton">Continue viewing prototype anyway</a></div>';
  150. }
  151. toAppend += ' </div>';
  152. toAppend += '</div>';
  153. $('body').prepend(toAppend);
  154. $('#continueToPrototypeButton').on('click', function () {
  155. var $message = $('#browserOutOfDateNotification');
  156. $message.children().hide();
  157. $message.css('padding-top', '0px');
  158. $message.animate({ 'height': '0px' }, { duration: 400, complete: function () { $message.hide(); } });
  159. });
  160. }
  161. $axure.page.bind('load.start', mainFrame_onload);
  162. $axure.messageCenter.addMessageListener(messageCenter_message);
  163. var suppressPluginVarUpdate = false;
  164. $(document).on('pluginShown', function (event, data) {
  165. if (!suppressPluginVarUpdate) $axure.player.setVarInCurrentUrlHash(PLUGIN_VAR_NAME, data ? data : '');
  166. });
  167. $(document).on('pluginCreated', function (event, data) {
  168. if (!$axure.player.isMobileMode() && $axure.player.settings.startPluginGid.indexOf(data) > -1) {
  169. suppressPluginVarUpdate = true;
  170. $axure.player.showPlugin(data);
  171. suppressPluginVarUpdate = false;
  172. }
  173. if (data == '1') {
  174. $('#interfaceControlFrame').animate({ opacity: 1 }, 200);
  175. }
  176. if ($axure.player.settings.isExpo) {
  177. // TODO: Do this only if expo is a mobile device
  178. // TODO: Figure out better way to deal with this issue
  179. $axure.messageCenter.postMessage('setDeviceMode', { device: false });
  180. $axure.messageCenter.postMessage('setDeviceMode', { device: true });
  181. //$axure.player.refreshViewPort();
  182. }
  183. });
  184. function initializeEvents() {
  185. $('#interfaceControlFrameMinimizeContainer').on('click', collapse);
  186. $('#interfaceControlFrameCloseButton').on('click', closePlayer);
  187. $('#interfacePageNameContainer').on($axure.eventNames.mouseDownName, toggleSitemap);
  188. $('#interfaceAdaptiveViewsContainer').on($axure.eventNames.mouseDownName, toggleAdaptiveViewsPopup);
  189. $('#overflowMenuButton').on($axure.eventNames.mouseDownName, toggleOverflowMenuPopup);
  190. $('#scaleMenuButton').on($axure.eventNames.mouseDownName, toggleScaleMenuPopup);
  191. if (!MOBILE_DEVICE) {
  192. $('#maximizePanel').mouseenter(function () {
  193. $(this).addClass('maximizePanelOver');
  194. });
  195. $('#maximizePanel').mouseleave(function () {
  196. if ($(this).hasClass('maximizePanelOver')) {
  197. $(this).animate(isMobileMode() ? {
  198. top: '-' + $('#maximizePanel').height() + 'px'
  199. } : {
  200. left: '-' + $('#maximizePanel').width() + 'px'
  201. }, 300);
  202. }
  203. $(this).removeClass('maximizePanelOver');
  204. });
  205. $('#maximizePanelOver').mouseenter(function () {
  206. $('#maximizePanel').animate(isMobileMode() ? {
  207. top: '0px'
  208. } : {
  209. left: '0px'
  210. }, 100);
  211. });
  212. }
  213. $minimizeContainer = $('#interfaceControlFrameMinimizeContainer');
  214. $minimizeContainer.mouseenter(function () { $minimizeContainer.addClass('collapseHovered') });
  215. $minimizeContainer.mouseleave(function () { $minimizeContainer.removeClass('collapseHovered') });
  216. $maximizeContainer = $('#maximizePanelContainer');
  217. $maximizeContainer.mouseenter(function () { if(!MOBILE_DEVICE) $minimizeContainer.addClass('expandHovered') });
  218. $maximizeContainer.mouseleave(function () { if(!MOBILE_DEVICE) $minimizeContainer.removeClass('expandHovered') });
  219. $('#maximizePanel').click(function () {
  220. $(this).removeClass('maximizePanelOver');
  221. $('#maximizePanelContainer').hide();
  222. $axure.messageCenter.postMessage('expandFrame');
  223. });
  224. $('#mHideSidebar').on($axure.eventNames.mouseDownName, function (e) { startM(e); });
  225. $('#lsplitbar').on($axure.eventNames.mouseDownName, startLeftSplit);
  226. $('#rsplitbar').on($axure.eventNames.mouseDownName, startRightSplit);
  227. if ($axure.mobileSupport.mobile) {
  228. var touchCount = 0;
  229. var lastTouch = Date.now();
  230. $('#mainPanel').on('touchstart',
  231. (function (e) {
  232. var now = Date.now();
  233. if (now - lastTouch < 375) {
  234. if (++touchCount === 3) {
  235. if ($axure.player.isMobileMode() || MOBILE_DEVICE) expand();
  236. touchCount = 0;
  237. e.preventDefault();
  238. };
  239. } else {
  240. touchCount = 1;
  241. }
  242. lastTouch = now;
  243. }));
  244. }
  245. $(window).resize(function () {
  246. $axure.player.resizeContent();
  247. });
  248. $(window).on("orientationchange", function () {
  249. // IOS often does not complete updating innerHeight and innerWidth
  250. // until after calling orientation changed and resized window
  251. // Also, cannot use $(window).height() call since iOS11 needs padding amount
  252. if (IOS && isMobileMode()) setTimeout(function () { $axure.player.resizeContent(true); }, 250);
  253. });
  254. $('#mainPanel').scroll(function () {
  255. repositionClippingBoundsScroll();
  256. });
  257. }
  258. function initializeMainFrame() {
  259. var legacyQString = getQueryString("Page");
  260. if (legacyQString.length > 0) {
  261. location.href = location.href.substring(0, location.href.indexOf("?")) + "?" + PAGE_URL_NAME + "=" + legacyQString;
  262. return;
  263. }
  264. var mainFrame = document.getElementById("mainFrame");
  265. //if it's local file on safari, test if we can access mainframe after its loaded
  266. if (SAFARI && document.location.href.indexOf('file://') >= 0) {
  267. $(mainFrame).on('load', function () {
  268. var canAccess;
  269. try {
  270. var mainFrameWindow = mainFrame.contentWindow || mainFrame.contentDocument;
  271. mainFrameWindow['safari_file_CORS'] = 'Y';
  272. canAccess = mainFrameWindow['safari_file_CORS'] === 'Y';
  273. } catch (err) {
  274. canAccess = false;
  275. }
  276. if (!canAccess) window.location = 'resources/chrome/safari.html';
  277. });
  278. }
  279. if($axure.player.settings != null && !$axure.player.settings.isExpo) {
  280. const linkUrlWithVars = $axure.getLinkUrlWithVars(getInitialUrl());
  281. mainFrame.contentWindow.location.href = linkUrlWithVars;
  282. }
  283. }
  284. function initializeDeviceFrame() {
  285. // TODO: Load device bezel and necessary overlays if applicable
  286. // - Need to determine if device has a frame/overlay
  287. // - Determine where to store said assets
  288. // - Determine sizing, positioning, orientation, and styling for HTML containers
  289. // - Verify that it stays consistent for every state (expo)
  290. var expo = $axure.expo;
  291. var project = expo.project;
  292. var device = project.Platform.Device;
  293. // in expo.ts, Web is 12
  294. if (device === 12) {
  295. // Hide containers
  296. $('#deviceFrameContainer').hide();
  297. $('#bezelOverlay').hide();
  298. return;
  299. }
  300. // map devices to their corresponding frame/bezel/overlays
  301. }
  302. var wasMobile = false;
  303. var isMobileMode = $axure.player.isMobileMode = function () { return $axure.utils.isShareApp() || (MOBILE_DEVICE && $(window).width() < 420); }
  304. var isMobileTextEntry = false;
  305. var isViewOverridden = $axure.player.isViewOverridden = function() {
  306. return getHashStringVar(ADAPTIVE_VIEW_VAR_NAME).length > 0;
  307. }
  308. function toggleSitemapMobileMode() {
  309. var $container = $('#sitemapHost');
  310. if (!$container.length) return;
  311. var $header = $container.find('.pluginNameHeader');
  312. var projectName = $axure.player.getProjectName();
  313. if (isMobileMode()) {
  314. $header.text('PROJECT PAGES');
  315. $container.addClass('mobileMode');
  316. $container.find('.sitemapPageName').addClass('mobileText');
  317. // Give sitemapHost left-margin so it does not collide with projectOptionsHost
  318. if (MOBILE_DEVICE) $container.css('margin-left', '13px');
  319. } else {
  320. $container.removeClass('mobileMode');
  321. $header.text(projectName ? projectName : 'Pages');
  322. $container.find('.sitemapPageName').removeClass('mobileText');
  323. if (MOBILE_DEVICE) $container.css('margin-left', '');
  324. }
  325. }
  326. function togglePageNotesMobileMode() {
  327. var $container = $('#pageNotesHost');
  328. if (!$container.length) return;
  329. if (isMobileMode()) {
  330. $container.addClass('mobileMode');
  331. $('#pageNotesSectionHeader').text('PAGE NOTES');
  332. $('#widgetNotesSectionHeader').text('WIDGET NOTES');
  333. $container.find('.notesPageNameHeader').addClass('mobileSubHeader');
  334. $container.find('.pageNote').addClass('mobileText');
  335. $container.find('.emptyStateTitle').addClass('mobileSubHeader');
  336. $container.find('.emptyStateContent').addClass('mobileText');
  337. } else {
  338. $container.removeClass('mobileMode');
  339. $('#pageNotesSectionHeader').text('Page Notes');
  340. $('#widgetNotesSectionHeader').text('Widget Notes');
  341. $container.find('.notesPageNameHeader').removeClass('mobileSubHeader');
  342. $container.find('.pageNote').removeClass('mobileText');
  343. $container.find('.emptyStateTitle').removeClass('mobileSubHeader');
  344. $container.find('.emptyStateContent').removeClass('mobileText');
  345. }
  346. }
  347. function toggleFeedbackMobileMode() {
  348. var $container = $('#feedbackHost');
  349. if (!$container.length) return;
  350. if (isMobileMode()) {
  351. $container.addClass('mobileMode');
  352. } else {
  353. $container.removeClass('mobileMode');
  354. }
  355. }
  356. $axure.player.updatePlugins = function updatePlugins() {
  357. if (MOBILE_DEVICE && !$axure.utils.isShareApp()) {
  358. var hostPanelPadding = isMobileMode() ? '8px 15px 0px 15px' : '';
  359. $('.rightPanel .leftPanel .mobileOnlyPanel').css('padding', hostPanelPadding);
  360. }
  361. if (isMobileMode()) {
  362. $('body').addClass('mobileMode');
  363. if ($('#debugHost').length) $('#debugHost').hide();
  364. if ($('#handoffHost').length) $('#handoffHost').hide();
  365. } else $('body').removeClass('mobileMode');
  366. toggleSitemapMobileMode();
  367. togglePageNotesMobileMode();
  368. toggleFeedbackMobileMode();
  369. }
  370. // TODO: this is done for IOS and Android (check what can be done for Pixel, etc)
  371. $axure.player.setIsMobileModeTextEntry = function (isTextEntry) {
  372. isMobileTextEntry = isTextEntry;
  373. if (IOS && isTextEntry) {
  374. activateMobileTextEntry()
  375. } else if (IOS) {
  376. setTimeout(deactivateMobileTextEntry, 150);
  377. }
  378. }
  379. function deactivateMobileTextEntry() {
  380. newHeight = window.innerHeight;
  381. var newControlHeight = newHeight - (!$axure.utils.isShareApp() ? 140 : IOS ? 157 : 138);
  382. if (!$('.leftPanel').hasClass('popup')) {
  383. $('.leftPanel').height(newControlHeight);
  384. }
  385. $('.rightPanel').height(newControlHeight);
  386. $('.mobileOnlyPanel').height(newControlHeight);
  387. $('#mobileControlFrameContainer').show();
  388. }
  389. function activateMobileTextEntry() {
  390. $('#mobileControlFrameContainer').hide();
  391. newHeight = window.innerHeight;
  392. var newControlHeight = newHeight - (!$axure.utils.isShareApp() ? 140 : IOS ? 157 : 138);
  393. newControlHeight = newControlHeight + (!$axure.utils.isShareApp() ? 61 : IOS ? 72 : 60);
  394. if (!$('.leftPanel').hasClass('popup')) {
  395. $('.leftPanel').height(newControlHeight);
  396. }
  397. $('.rightPanel').height(newControlHeight);
  398. $('.mobileOnlyPanel').height(newControlHeight);
  399. }
  400. function setAdaptiveView() {
  401. if (typeof noViewport == 'undefined') {
  402. // Block during animation -- end of animation will call resizeContent once completed with isAnimating equal to false
  403. if (!isViewOverridden() && !isAnimating) $axure.messageCenter.postMessage('setAdaptiveViewForSize', { 'width': $('#mainPanel').width(), 'height': $('#mainPanel').height() });
  404. //if (!isViewOverridden()) $axure.messageCenter.postMessage('setAdaptiveViewForSize', { 'width': $('#mainPanel').width(), 'height': $('#mainPanel').height() });
  405. $axure.player.refreshViewPort();
  406. if ($axure.player.updateAdaptiveViewHeader != null) $axure.player.updateAdaptiveViewHeader();
  407. }
  408. }
  409. $axure.player.resizeContent = function (noViewport) {
  410. var isMobile = isMobileMode();
  411. if (wasMobile && !isMobile) {
  412. $('#clippingBoundsScrollContainer').show();
  413. $('#outerContainer').prepend($('.leftPanel'));
  414. $('#outerContainer').append($('.rightPanel'));
  415. $axure.player.updatePlugins();
  416. $('#mHideSidebar').hide();
  417. $('#mobileBrowserControlFrame').hide();
  418. $('#nativeAppControlFrame').hide();
  419. if ($('#topPanel').is(':visible')) {
  420. $('#maximizePanelContainer').hide();
  421. $axure.player.restorePlugins();
  422. } else {
  423. $('.leftPanel').hide();
  424. $('.rightPanel').hide();
  425. if (!MOBILE_DEVICE) $('#maximizePanelContainer').show();
  426. }
  427. $('.leftPanel').css({ 'top': '', 'left': '' });
  428. $('.rightPanel').css({ 'top': '', 'left': '' });
  429. } else if (!wasMobile && isMobile) {
  430. $('#clippingBoundsScrollContainer').hide();
  431. $axure.player.closePopup();
  432. $('#lsplitbar').hide();
  433. $('#rsplitbar').hide();
  434. $('.leftPanel').show();
  435. $('.rightPanel').show();
  436. $axure.player.updatePlugins();
  437. $('#mHideSidebar').append($('.leftPanel'));
  438. $('#mHideSidebar').append($('.rightPanel'));
  439. if (MOBILE_DEVICE) $('#maximizePanelContainer').hide();
  440. $axure.messageCenter.postMessage('collapseFrameOnLoad');
  441. }
  442. var newHeight = 0;
  443. var newWidth = 0;
  444. if (IOS && $axure.utils.isShareApp()) {
  445. // Hack for Iphone X
  446. newHeight = iosInnerHeight();
  447. newWidth = $(window).width();
  448. } else {
  449. // innerHeight includes padding for window -- needed in iOS 11 to have prototype stretch to bottom of screen (could put in -- if (iOS) -- block if needed)
  450. //var newHeight = $(window).height() - ((!isMobile && $('#topPanel').is(':visible'))? $('#topPanel').height() : 0);
  451. newHeight = window.innerHeight - ((!isMobile && $('#topPanel').is(':visible')) ? $('#topPanel').height() : 0);
  452. newWidth = $(window).width();
  453. }
  454. $('#outerContainer').height(newHeight).width(newWidth);
  455. $('#mainPanel').height(newHeight);
  456. $('#clippingBounds').height(newHeight);
  457. if (isMobile) {
  458. $('#mobileControlFrameContainer').height(newHeight);
  459. $('#mobileControlFrameContainer').width(newWidth);
  460. var newControlHeight = newHeight - (!MOBILE_DEVICE ? 112 : !$axure.utils.isShareApp() ? 140 : IOS ? 157 : 138);
  461. // Screen resize is only way through browser to catch mobile device keyboard expand and collapse
  462. if ($('#mHideSidebar').is(':visible') && !$('#mobileControlFrameContainer').is(':visible')) {
  463. $('#mobileControlFrameContainer').delay(150).show();
  464. } else if (isMobileTextEntry) {
  465. newControlHeight = newControlHeight + (!$axure.utils.isShareApp() ? 61 : IOS ? 72 : 60);
  466. $('#mobileControlFrameContainer').hide();
  467. }
  468. if(!$('.leftPanel').hasClass('popup')) {
  469. $('.leftPanel').height(newControlHeight);
  470. }
  471. $('.rightPanel').height(newControlHeight);
  472. $('.mobileOnlyPanel').height(newControlHeight);
  473. } else {
  474. if (!$('.leftPanel').hasClass('popup')) {
  475. $('.leftPanel').css('height','');
  476. }
  477. $('.rightPanel').css('height', '');
  478. if ($('.rightPanel').is(':visible')) {
  479. var lastRightPanelWidthDefaultSub = ($(window).width() - lastRightPanelWidthDefault || 0);
  480. var rightPanelWidth = ($('.rightPanel').width() || 0);
  481. var leftPanelPanelWidthSub = ($(window).width() - $('.leftPanel').width()) || 0;
  482. var newWidth = Math.min(lastRightPanelWidthDefaultSub, rightPanelWidth, leftPanelPanelWidthSub);
  483. lastRightPanelWidth = Math.max(lastRightPanelWidthDefault, newWidth);
  484. $('.rightPanel').width(lastRightPanelWidth ? lastRightPanelWidth : lastRightPanelWidthDefault);
  485. $('#rsplitbar').css('left', $(window).width() - $('.rightPanel').width());
  486. }
  487. if ($('.leftPanel').is(':visible')) {
  488. var lastLeftPanelWidthSub = ($(window).width() - lastLeftPanelWidthDefault || 0);
  489. var leftPanelWidth = ($('.leftPanel').width() || 0);
  490. var rightPanelWidthSub = ($(window).width() - $('.rightPanel').width()) || 0;
  491. var newWidth = Math.min(lastLeftPanelWidthSub, leftPanelWidth, rightPanelWidthSub);
  492. lastLeftPanelWidth = Math.max(lastLeftPanelWidthDefault, newWidth);
  493. $('.leftPanel').width(lastLeftPanelWidth ? lastLeftPanelWidth : lastLeftPanelWidthDefault);
  494. $('#lsplitbar').css('left', $('.leftPanel').width() - 4);
  495. }
  496. }
  497. if (isMobile) {
  498. var newControlWidth = newWidth - 80;
  499. $('.leftPanel').css({ 'width': newControlWidth + 'px' });
  500. $('.rightPanel').css({ 'width': newControlWidth + 'px' });
  501. $('.mobileOnlyPanel').css({ 'width': newControlWidth + 'px' });
  502. adjustM('left');
  503. }
  504. updateClippingBoundsWidth();
  505. repositionClippingBoundsScroll();
  506. setAdaptiveView();
  507. wasMobile = isMobile;
  508. }
  509. function contentDocument_onload() {
  510. (function setRepositionWhenReady() {
  511. var $iframe = $('#mainFrame')[0];
  512. if ($($iframe.contentWindow.document.body).length === 0 || $iframe.contentWindow.document.URL === "about:blank") {
  513. setTimeout(setRepositionWhenReady, 50);
  514. } else {
  515. var $iframe = $($('#mainFrame')[0].contentWindow.document);
  516. $iframe.scroll(function () {
  517. repositionClippingBoundsScroll();
  518. });
  519. }
  520. common_contentDocument_onload();
  521. })();
  522. }
  523. // self-destruction timeouts
  524. var dragOverlayTimeout;
  525. var zoomOverlayTimeout;
  526. var selfDestructionTimeoutDuration = 1000; // ms
  527. var forcePanZoomDisabled = false;
  528. function disablePanZoomFeature() {
  529. forcePanZoomDisabled = true;
  530. $('.vpZoomValue').remove();
  531. $('#scaleValue').text('Scale');
  532. }
  533. function panAndZoomKeydownHandler(e) {
  534. // if space key down
  535. if (e.key == " ") {
  536. var $iframe = $('#mainFrame')[0];
  537. var iframeBody = $iframe.contentWindow.document.body;
  538. var dimStr = $('.currentAdaptiveView').attr('data-dim');
  539. var dim = dimStr ? dimStr.split('x') : { w: '0', h: '0' };
  540. var isDevice = dim[1] != '0' ? true : false;
  541. var focusableElements = ["textarea", "input", "button", "select"];
  542. if ((e.target !== iframeBody
  543. && (iframeBody.contains(e.target) || tabbableElements.lastIndexOf(e.target.tagName.toLowerCase()) !== -1))
  544. || isDevice
  545. ) {
  546. return;
  547. }
  548. e.preventDefault();
  549. // clear self-destruction timeout if exist
  550. if (dragOverlayTimeout) {
  551. clearTimeout(dragOverlayTimeout);
  552. }
  553. toggleDragMode(true);
  554. // self-destruction
  555. dragOverlayTimeout = setTimeout(function() {toggleDragMode(false)}, selfDestructionTimeoutDuration);
  556. }
  557. // if hotkey zooming
  558. if (e.ctrlKey || e.metaKey) {
  559. if (e.key == "+" || e.key == "=") {
  560. e.preventDefault();
  561. zoomIn();
  562. }
  563. if (e.key == "-") {
  564. e.preventDefault();
  565. zoomOut();
  566. }
  567. if (e.key == "0") {
  568. e.preventDefault();
  569. dropScaleAndZoomPage(100);
  570. }
  571. }
  572. // if ctrl key down
  573. if (e.key == "Control" || e.key == "Meta") {
  574. // clear self-destruction timeout if exist
  575. if (zoomOverlayTimeout) {
  576. clearTimeout(zoomOverlayTimeout);
  577. }
  578. toggleZoomOverlay(true);
  579. // self-destruction
  580. zoomOverlayTimeout = setTimeout(function() {toggleZoomOverlay(false)}, selfDestructionTimeoutDuration);
  581. }
  582. };
  583. function panAndZoomKeyupHandler(e) {
  584. // if space key up
  585. if (e.key == " ") {
  586. // clear self-destruction timeout if exist
  587. if (dragOverlayTimeout) {
  588. clearTimeout(dragOverlayTimeout);
  589. }
  590. toggleDragMode(false);
  591. }
  592. // if ctrl key up
  593. if (e.key == "Control" || e.key == "Meta") {
  594. // clear self-destruction timeout if exist
  595. if (zoomOverlayTimeout) {
  596. clearTimeout(zoomOverlayTimeout);
  597. }
  598. toggleZoomOverlay(false);
  599. }
  600. };
  601. var zoomLastTimestamp = 0;
  602. var zoomLastDirection = 0;
  603. var disableChunkedZoomEvents = false;
  604. function zoomWheelHandler(event) {
  605. if (event.ctrlKey || event.metaKey) {
  606. event.stopPropagation();
  607. event.preventDefault();
  608. const wheelEvent = event.originalEvent ? event.originalEvent : event;
  609. if (wheelEvent) {
  610. const { deltaY } = normalizeZoomWheelEvent(wheelEvent);
  611. let timestamp = wheelEvent.timeStamp / 1e3;
  612. const direction = Math.sign(deltaY);
  613. if (disableChunkedZoomEvents && timestamp - zoomLastTimestamp < .4 && direction == zoomLastDirection) {
  614. // ignore chunked events
  615. return;
  616. } else {
  617. // disable stickiness
  618. disableChunkedZoomEvents = false;
  619. }
  620. zoomLastTimestamp = timestamp;
  621. zoomLastDirection = direction;
  622. const zoom = getCurrentZoom();
  623. const zoomStep = deltaY < 0 ? zoom * 0.0409 + 0.0415 : zoom * 0.0394 + 0.0367;
  624. let newZoom = roundZoomValue(zoom + zoomStep * -deltaY);
  625. if ((zoom > 100 && newZoom <= 100) || (zoom < 100 && newZoom >= 100)) {
  626. // enable stickiness
  627. newZoom = 100;
  628. disableChunkedZoomEvents = true;
  629. }
  630. const zoomPositionX = wheelEvent.clientX * zoom / 100 - zoom / 100;
  631. const zoomPositionY = wheelEvent.clientY * zoom / 100 - zoom / 100;
  632. const zoomPosition = { x: zoomPositionX, y: zoomPositionY };
  633. dropScaleAndZoomPage(newZoom, zoomPosition);
  634. }
  635. }
  636. }
  637. var gestureStartZoom = 0;
  638. var gesturePrevZoom = 0;
  639. var gestureRaf;
  640. function zoomGestureStart(e) {
  641. e.preventDefault();
  642. gestureStartZoom = gesturePrevZoom = getCurrentZoom();
  643. };
  644. function zoomGestureChange(e) {
  645. e.preventDefault();
  646. if (gestureRaf !== undefined) {
  647. cancelAnimationFrame(gestureRaf)
  648. }
  649. gestureRaf = requestAnimationFrame(function () {
  650. let timestamp = e.timeStamp / 1e3;
  651. const direction = Math.sign(e.scale - 1);
  652. if (disableChunkedZoomEvents && timestamp - zoomLastTimestamp < .5 && direction == zoomLastDirection) {
  653. // ignore chunked events
  654. return;
  655. } else {
  656. // disable stickiness
  657. disableChunkedZoomEvents = false;
  658. }
  659. zoomLastTimestamp = timestamp;
  660. zoomLastDirection = direction;
  661. var zoom = roundZoomValue(gestureStartZoom * e.scale);
  662. if ((gesturePrevZoom > 100 && zoom <= 100) || (gesturePrevZoom < 100 && zoom >= 100)) {
  663. // enable stickiness
  664. zoom = 100;
  665. disableChunkedZoomEvents = true;
  666. }
  667. gesturePrevZoom = zoom;
  668. var zoomPosition = { x: e.pageX, y: e.pageY };
  669. dropScaleAndZoomPage(zoom, zoomPosition);
  670. });
  671. }
  672. var zoomGestureEnd = function (e) {
  673. e.preventDefault();
  674. }
  675. function scrollWheelHandler(event) {
  676. if (!event.ctrlKey && !event.metaKey) {
  677. var dimStr = $('.currentAdaptiveView').attr('data-dim');
  678. var dim = dimStr ? dimStr.split('x') : { w: '0', h: '0' };
  679. var isDevice = dim[1] != '0' ? true : false;
  680. if (!isDevice) return;
  681. // we should scroll iframe programmatically for custom devices
  682. // if wheel event fires outside of the iframe
  683. const wheelEvent = event.originalEvent ? event.originalEvent : event;
  684. if (wheelEvent) {
  685. event.preventDefault();
  686. const scrollStep = isTrackPadDetected(event) ? 13 : 100;
  687. const deltaFactor = getDeltaWheelFactor();
  688. let deltaY = wheelEvent.deltaY ? -wheelEvent.deltaY * deltaFactor * scrollStep : 0;
  689. let deltaX = wheelEvent.deltaX ? -wheelEvent.deltaX * deltaFactor * scrollStep : 0;
  690. if (wheelEvent.shiftKey) {
  691. const temp = deltaX;
  692. deltaX = deltaY;
  693. deltaY = temp;
  694. }
  695. let pagePosition = getPagePosition();
  696. pagePosition.x += deltaX;
  697. pagePosition.y += deltaY;
  698. setPagePosition({ x: pagePosition.x, y: pagePosition.y });
  699. }
  700. }
  701. }
  702. function panAndZoomMouseUpHandler() {
  703. stopDrag();
  704. };
  705. function common_contentDocument_onload() {
  706. (function bindHandlersWhenReady() {
  707. var $iframe = $('#mainFrame')[0];
  708. currentIframeHtml = null;
  709. // Intentionally disable pan/zoom for mobile mode.
  710. // That's to not interfere with native gesture interactions.
  711. if (isMobileMode()) {
  712. disablePanZoomFeature();
  713. return;
  714. }
  715. // Check for locally running prototype.
  716. // Disable pan and zoom feature if not supported.
  717. try {
  718. var _iframeDocument = $iframe.contentWindow.document;
  719. }
  720. catch(ex) {
  721. disablePanZoomFeature();
  722. return;
  723. }
  724. if ($($iframe.contentWindow.document.body).length === 0 || $iframe.contentWindow.document.URL === "about:blank") {
  725. setTimeout(bindHandlersWhenReady, 50);
  726. } else {
  727. const mainPanel = $('#mainPanel')[0];
  728. const iframeWindow = $('#mainFrame')[0].contentWindow;
  729. // remove already added listeners
  730. window.removeEventListener("mouseup", panAndZoomMouseUpHandler);
  731. window.removeEventListener("keydown", panAndZoomKeydownHandler);
  732. window.removeEventListener("keyup", panAndZoomKeyupHandler);
  733. mainPanel.removeEventListener("keydown", panAndZoomKeydownHandler);
  734. mainPanel.removeEventListener("keyup", panAndZoomKeyupHandler);
  735. mainPanel.removeEventListener("wheel", zoomWheelHandler, { passive: false });
  736. mainPanel.removeEventListener("wheel", scrollWheelHandler, { passive: false });
  737. // add pan and zoom listeners
  738. window.addEventListener("mouseup", panAndZoomMouseUpHandler);
  739. window.addEventListener("keydown", panAndZoomKeydownHandler);
  740. window.addEventListener("keyup", panAndZoomKeyupHandler);
  741. mainPanel.addEventListener("keydown", panAndZoomKeydownHandler);
  742. mainPanel.addEventListener("keyup", panAndZoomKeyupHandler);
  743. mainPanel.addEventListener("wheel", zoomWheelHandler, { passive: false });
  744. mainPanel.addEventListener("wheel", scrollWheelHandler, { passive: false });
  745. iframeWindow.addEventListener("keydown", panAndZoomKeydownHandler);
  746. iframeWindow.addEventListener("keyup", panAndZoomKeyupHandler);
  747. iframeWindow.addEventListener("wheel", zoomWheelHandler, { passive: false, capture: true });
  748. if (iframeWindow) {
  749. // Safari specific
  750. // Safari emit gesture event instead of wheel event if touchpad used.
  751. // remove already added listeners
  752. window.removeEventListener("gesturestart", zoomGestureStart, { capture: true });
  753. window.removeEventListener("gesturechange", zoomGestureChange, { capture: true });
  754. window.removeEventListener("gestureend", zoomGestureEnd, { capture: true });
  755. // attaching to both window and iframeWindow as sometimes events
  756. // this is because how weirdly iframe is positioned in Safari
  757. // and doesn't occupy the full space, thus gesture events trigger only on parent window
  758. window.addEventListener("gesturestart", zoomGestureStart, { capture: true });
  759. window.addEventListener("gesturechange", zoomGestureChange, { capture: true });
  760. window.addEventListener("gestureend", zoomGestureEnd, { capture: true });
  761. iframeWindow.addEventListener("gesturestart", zoomGestureStart, { capture: true });
  762. iframeWindow.addEventListener("gesturechange", zoomGestureChange, { capture: true });
  763. iframeWindow.addEventListener("gestureend", zoomGestureEnd, { capture: true });
  764. }
  765. }
  766. })();
  767. }
  768. var zoomValues = $axure.player.zoomValues = [25, 50, 75, 100, 150, 200, 250, 300, 400];
  769. var roundZoomValue = function(value) {
  770. let zoom = Math.round(value);
  771. if (zoom < zoomValues[0]) {
  772. [zoom] = zoomValues;
  773. } else if (zoom > zoomValues[zoomValues.length - 1]) {
  774. zoom = zoomValues[zoomValues.length - 1];
  775. }
  776. return zoom;
  777. }
  778. var getPageSize = function () {
  779. const currentZoom = getCurrentZoom() / 100;
  780. var documentContainer = $($('#mainFrame')[0].contentDocument);
  781. return {
  782. height: (documentContainer.height() || 0) * currentZoom,
  783. width: ($($('#mainFrame')[0].contentDocument).find("body").width() || 0) * currentZoom,
  784. }
  785. }
  786. var getPagePosition = $axure.player.getPagePosition = function() {
  787. const currentZoom = getCurrentZoom() / 100;
  788. var viewerContainer = $('#mainPanel');
  789. const viewerSize = {
  790. height: viewerContainer.height() || 0,
  791. width: viewerContainer.width() || 0,
  792. };
  793. const pageSize = getPageSize();
  794. var screenContainerPosition = getPageScrollPosition();
  795. var pageX = -screenContainerPosition.x * currentZoom - (viewerSize.width > pageSize.width ? pageSize.width / 2 : viewerSize.width / 2);
  796. var pageY = -screenContainerPosition.y * currentZoom - viewerSize.height / 2;
  797. return { x: pageX, y: pageY };
  798. }
  799. var setPagePosition = $axure.player.setPagePosition = function (position) {
  800. const currentZoom = getCurrentZoom() / 100;
  801. var viewerContainer = $('#mainPanel');
  802. const viewerSize = {
  803. height: viewerContainer.height() || 0,
  804. width: viewerContainer.width() || 0,
  805. };
  806. const screenContainerLeft = (viewerSize.width / 2 > Math.abs(position.x) ? 0 : -position.x - viewerSize.width / 2);
  807. const screenContainerTop = -position.y - viewerSize.height / 2;
  808. setPageScrollPosition({ x: screenContainerLeft / currentZoom, y: screenContainerTop / currentZoom } );
  809. }
  810. var roundValueByArrayOfSteps = function(value, array, toSmaller) {
  811. let resultIndex = 0;
  812. for (let i = 0; i < array.length; i++) {
  813. if (array[i] < value) {
  814. const nextValue = array[i + 1];
  815. if (!nextValue) {
  816. resultIndex = i;
  817. break;
  818. } else if (nextValue < value) {
  819. continue;
  820. } else if (nextValue === value) {
  821. resultIndex = i + 1;
  822. break;
  823. } else if (toSmaller) {
  824. resultIndex = i;
  825. break;
  826. } else {
  827. resultIndex = i + 1;
  828. }
  829. } else if (i === 0) {
  830. break;
  831. }
  832. }
  833. return array[resultIndex];
  834. }
  835. // point on page for zooming
  836. var zoomIn = function (position) {
  837. const nextZoom = getNextStepOfZoom(1);
  838. dropScaleAndZoomPage(nextZoom, position);
  839. }
  840. // point on page for zooming
  841. var zoomOut = function (position) {
  842. const nextZoom = getNextStepOfZoom(-1);
  843. dropScaleAndZoomPage(nextZoom, position);
  844. }
  845. var getNextStepOfZoom = function (offset) {
  846. var zoom = getCurrentZoom();
  847. const nearZoom = roundValueByArrayOfSteps(zoom, zoomValues, offset < 0);
  848. let nextZoomOffset = offset;
  849. if (zoom !== nearZoom) {
  850. nextZoomOffset += nextZoomOffset > 0 ? -1 : 1;
  851. }
  852. const currentZoomIndex = zoomValues.findIndex(function(value) { return value === nearZoom }) || 0;
  853. const nextZoomIndex = currentZoomIndex + nextZoomOffset;
  854. let nextZoom = zoom;
  855. if (zoomValues[nextZoomIndex]) {
  856. nextZoom = zoomValues[nextZoomIndex];
  857. }
  858. return nextZoom;
  859. }
  860. var getCurrentZoom = function () {
  861. var zoomValue = getIframeHtml().attr("zoom");
  862. if (zoomValue) {
  863. return parseInt(zoomValue, 10);
  864. }
  865. return 100;
  866. }
  867. var currentIframeHtml = null;
  868. function getIframeHtml() {
  869. if (currentIframeHtml) return currentIframeHtml;
  870. currentIframeHtml = $($('#mainFrame')[0].contentDocument).find("html");
  871. return currentIframeHtml;
  872. }
  873. // zoom value
  874. // point on page for zooming
  875. var zoomPage = $axure.player.zoomPage = function(zoom, position) {
  876. if (forcePanZoomDisabled) return;
  877. getIframeHtml().toggleClass("hideScroll", zoom != 100);
  878. const currentZoom = getCurrentZoom();
  879. const nextZoom = zoom;
  880. var viewerContainer = $('#mainPanel');
  881. const containerSize = {
  882. height: viewerContainer.height() || 0,
  883. width: viewerContainer.width() || 0,
  884. };
  885. const pageSize = getPageSize();
  886. let newPageX = 0;
  887. let newPageY = 0;
  888. if (
  889. containerSize.width <= (pageSize.width * nextZoom) / currentZoom ||
  890. containerSize.height <= (pageSize.height * nextZoom) / currentZoom
  891. ) {
  892. const mouseX = position ? position.x : containerSize.width / 2;
  893. const mouseY = position ? position.y : containerSize.height / 2;
  894. // get current page position
  895. const pagePosition = getPagePosition();
  896. // calculate new page position after zoom
  897. let mousePageX = mouseX - containerSize.width / 2 - pagePosition.x;
  898. let mousePageY = mouseY - containerSize.height / 2 - pagePosition.y;
  899. const newMousePageX = (mousePageX * nextZoom) / currentZoom;
  900. const newMousePageY = (mousePageY * nextZoom) / currentZoom;
  901. newPageX = pagePosition.x - (newMousePageX - mousePageX);
  902. newPageY = pagePosition.y - (newMousePageY - mousePageY);
  903. }
  904. // resize page
  905. // set zoom
  906. getIframeHtml().attr("zoom", zoom);
  907. $axure.player.refreshViewPort();
  908. // set new page position
  909. setPagePosition({ x: newPageX, y: newPageY });
  910. repositionClippingBoundsScroll();
  911. }
  912. var dropScaleAndZoomPage = function (zoom, position) {
  913. var selectedScale = $('.vpScaleOption').find('.selectedRadioButton');
  914. var scaleVal = $(selectedScale).parent().attr('val');
  915. if (scaleVal != 3) {
  916. $axure.player.selectScaleOption(3);
  917. }
  918. zoomPage(zoom, position);
  919. }
  920. var didInitPlatformInfo = false;
  921. var isMacFlag = false;
  922. var isWindowsFlag = false;
  923. function initPlatformInfo() {
  924. if (didInitPlatformInfo) {
  925. return;
  926. }
  927. var platform = self.navigator.platform;
  928. isMacFlag = /Mac/.test(platform);
  929. if (!isMacFlag) {
  930. isWindowsFlag = /Win/.test(platform);
  931. }
  932. didInitPlatformInfo = true;
  933. }
  934. function isWindows() {
  935. initPlatformInfo();
  936. return isWindowsFlag
  937. }
  938. function isMac() {
  939. initPlatformInfo();
  940. return isMacFlag;
  941. }
  942. var lastMultiplier = 0;
  943. var lastTimestamp = 0;
  944. var lastDirectionX = 0;
  945. var lastDirectionY = 0;
  946. function normalizeZoomWheelEvent(e) {
  947. const DOM_DELTA_PIXELS = 0;
  948. const DOM_DELTA_LINES = 1;
  949. const DOM_DELTA_PAGES = 2;
  950. let deltaMode = e.deltaMode;
  951. let deltaX = e.deltaX;
  952. let deltaY = e.deltaY;
  953. let wheelDeltaX = 0;
  954. let wheelDeltaY = 0;
  955. var isWheelDeltaSupported = e.wheelDeltaY != undefined;
  956. if (isWheelDeltaSupported) {
  957. wheelDeltaX = e.wheelDeltaX;
  958. wheelDeltaY = e.wheelDeltaY;
  959. }
  960. const devicePixelRatio = window.devicePixelRatio;
  961. if (CHROME) {
  962. deltaX /= devicePixelRatio;
  963. deltaY /= devicePixelRatio;
  964. wheelDeltaX /= devicePixelRatio;
  965. wheelDeltaY /= devicePixelRatio
  966. }
  967. if (isMac()) {
  968. if (CHROME) {
  969. // check for speed-wheeling
  970. // trackpad wheelDelta == 120 independent of speed
  971. if (Math.abs(wheelDeltaX) > 120 || Math.abs(wheelDeltaY) > 120) {
  972. // decrease lowres mouse speed-wheeling
  973. deltaX /= 80;
  974. deltaY /= 80;
  975. } else {
  976. // decrease trackpad speed
  977. deltaX /= 4;
  978. deltaY /= 4;
  979. }
  980. } else if (FIREFOX) {
  981. deltaX /= 3;
  982. deltaY /= 3;
  983. } else if (SAFARI) {
  984. // check for speed-wheeling
  985. if (Math.abs(wheelDeltaX) > 12 || Math.abs(wheelDeltaY) > 12) {
  986. // decrease lowres mouse speed-wheeling
  987. deltaX /= 80;
  988. deltaY /= 80;
  989. } else {
  990. // single wheel event
  991. deltaX /= 4;
  992. deltaY /= 4;
  993. }
  994. }
  995. } else if (isWindows()) {
  996. let lowResMouse = false;
  997. let lowResCutoff = 120 - 1;
  998. if (CHROME || $axure.browser.isEdge) {
  999. deltaX = -wheelDeltaX;
  1000. deltaY = -wheelDeltaY;
  1001. lowResMouse = Math.abs(deltaX) >= lowResCutoff || Math.abs(deltaY) >= lowResCutoff;
  1002. if (lowResMouse) {
  1003. deltaX /= 120;
  1004. deltaY /= 120
  1005. }
  1006. } else if (FIREFOX) {
  1007. if (deltaMode === DOM_DELTA_LINES || deltaMode === DOM_DELTA_PAGES) {
  1008. deltaX *= 40;
  1009. deltaY *= 40
  1010. }
  1011. lowResCutoff = 100 - 1;
  1012. lowResMouse = Math.abs(deltaX) >= lowResCutoff || Math.abs(deltaY) >= lowResCutoff;
  1013. if (lowResMouse) {
  1014. deltaX /= 120;
  1015. deltaY /= 120
  1016. } else {
  1017. var numLinesToScroll = 1;
  1018. deltaX /= numLinesToScroll;
  1019. deltaY /= numLinesToScroll
  1020. }
  1021. }
  1022. if (lowResMouse) {
  1023. let timestamp = e.timeStamp / 1e3;
  1024. const directionX = Math.sign(deltaX);
  1025. const directionY = Math.sign(deltaY);
  1026. let multiplier = 1;
  1027. if (timestamp - lastTimestamp < .05 && directionX == lastDirectionX && directionY == lastDirectionY) {
  1028. multiplier = lastMultiplier * 1.25;
  1029. }
  1030. deltaX *= multiplier;
  1031. deltaY *= multiplier;
  1032. const max = 120;
  1033. var lengthSquared = deltaX * deltaX + deltaY * deltaY;
  1034. if (lengthSquared > max * max) {
  1035. deltaX *= max / Math.sqrt(lengthSquared);
  1036. deltaY *= max / Math.sqrt(lengthSquared)
  1037. }
  1038. lastMultiplier = multiplier;
  1039. lastTimestamp = timestamp;
  1040. lastDirectionX = directionX;
  1041. lastDirectionY = directionY
  1042. }
  1043. }
  1044. return {
  1045. deltaX,
  1046. deltaY,
  1047. deltaMode,
  1048. }
  1049. }
  1050. var getDeltaWheelFactor = function () {
  1051. let deltaFactor = 0.01;
  1052. if (isMac()) {
  1053. if (!FIREFOX) {
  1054. deltaFactor *= 8;
  1055. }
  1056. }
  1057. if (FIREFOX) {
  1058. deltaFactor *= 100 / 3;
  1059. }
  1060. return deltaFactor;
  1061. }
  1062. function isTrackPadDetected(e) {
  1063. var isTrackpad = false;
  1064. if (e.wheelDeltaY || e.wheelDeltaX) {
  1065. if (
  1066. (e.wheelDeltaY && e.wheelDeltaY === (e.deltaY * -3))
  1067. || (e.wheelDeltaX && e.wheelDeltaX === (e.deltaX * -3))
  1068. ) {
  1069. isTrackpad = true;
  1070. }
  1071. } else if (e.deltaMode === 0) {
  1072. isTrackpad = true;
  1073. }
  1074. return isTrackpad;
  1075. }
  1076. var toggleZoomOverlay = function (value) {
  1077. var $body = $($('#mainFrame')[0].contentDocument).find("body");
  1078. if (!value) {
  1079. $body.find('#zoomOverlay').remove();
  1080. } else if ($body.find('#zoomOverlay').length <= 0) {
  1081. $body.append($('<div id="zoomOverlay"/>'));
  1082. }
  1083. }
  1084. var isDragModeEnabled = false;
  1085. var toggleDragMode = function(value) {
  1086. if (isDragModeEnabled === value) {
  1087. return;
  1088. }
  1089. var viewer = $($('#mainFrame')[0].contentWindow);
  1090. var $body = $($('#mainFrame')[0].contentDocument).find("body");
  1091. if (!value) {
  1092. $body.find('#dragOverlay').remove();
  1093. } else if ($body.find('#dragOverlay').length <= 0) {
  1094. $body.append($('<div id="dragOverlay"/>'));
  1095. }
  1096. if (value) {
  1097. viewer.on("mousedown.drag", function(event) { startDrag(event) });
  1098. } else {
  1099. if (isDragModeEnabled) {
  1100. stopDrag();
  1101. }
  1102. viewer.off("mousedown.drag");
  1103. }
  1104. isDragModeEnabled = value;
  1105. }
  1106. var startDrag = function (event) {
  1107. event.preventDefault();
  1108. var viewer = $($('#mainFrame')[0].contentWindow);
  1109. if (event.clientX === undefined || event.clientY === undefined) return;
  1110. let mouseX = event.clientX;
  1111. let mouseY = event.clientY;
  1112. function move({ clientX, clientY }) {
  1113. if (clientX === undefined || clientY === undefined) return;
  1114. const changeX = clientX - mouseX;
  1115. const changeY = clientY - mouseY;
  1116. let pagePosition = getPageScrollPosition();
  1117. pagePosition.x -= changeX ;
  1118. pagePosition.y -= changeY ;
  1119. setPageScrollPosition({ x: pagePosition.x, y: pagePosition.y });
  1120. mouseX = clientX;
  1121. mouseY = clientY;
  1122. };
  1123. $($('#mainFrame')[0].contentDocument).find('#dragOverlay').toggleClass("dragging__start", true);
  1124. viewer.on("mouseup.drag", function() { stopDrag(); });
  1125. viewer.on("mouseout.drag mousemove.drag", function(e) { move(e); });
  1126. }
  1127. var stopDrag = function () {
  1128. var viewer = $($('#mainFrame')[0].contentWindow);
  1129. $($('#mainFrame')[0].contentDocument).find("#dragOverlay").toggleClass("dragging__start", false);
  1130. viewer.off("mouseup.drag");
  1131. viewer.off("mouseout.drag mousemove.drag");
  1132. }
  1133. var getPageScrollPosition = function () {
  1134. var $iframe = $($('#mainFrame')[0].contentWindow);
  1135. return {
  1136. x: $iframe.scrollLeft(),
  1137. y: $iframe.scrollTop()
  1138. }
  1139. }
  1140. var setPageScrollPosition = function (position) {
  1141. if (forcePanZoomDisabled) return;
  1142. var $iframe = $($('#mainFrame')[0].contentWindow);
  1143. $iframe.scrollTop(position.y);
  1144. $iframe.scrollLeft(position.x);
  1145. }
  1146. // This is the full width and height of the prototype (beyond the window width and height)
  1147. var determineIframeDimensions = function () {
  1148. var $iframe = $($('#mainFrame')[0].contentWindow);
  1149. return {
  1150. width: $iframe.width(),
  1151. height: $iframe.height()
  1152. };
  1153. };
  1154. // Position of this (upper left hand corner) should match the existingPinPanel position
  1155. var determineIframePosition = function () {
  1156. var dimensions = determineIframeDimensions();
  1157. var $iframe = $($('#mainFrame')[0].contentWindow);
  1158. var $body = $($iframe[0].document.body);
  1159. var bodyWidth = $body.offset().left !== 0 ? $body.width() : dimensions.width;
  1160. if (FIREFOX) {
  1161. var left = $body[0].getBoundingClientRect().left;
  1162. bodyWidth = left !== 0 ? $body.width() : dimensions.width;
  1163. }
  1164. return {
  1165. top: 0,// Math.max(0, (dimensions.height - $($iframe[0].document.body).height()) / 2),
  1166. left: Math.max(0, (dimensions.width - bodyWidth) / 2)
  1167. };
  1168. };
  1169. // Return iframe scroll top and scroll left
  1170. var determineIframeScroll = function () {
  1171. var $iframe = $($('#mainFrame')[0].contentWindow);
  1172. return {
  1173. scrollTop: $iframe.scrollTop(),
  1174. scrollLeft: $iframe.scrollLeft()
  1175. };
  1176. };
  1177. function calculateClippingBoundsWidth(panelSize, isLeftPanel) {
  1178. var $leftPanel = $('.leftPanel:visible');
  1179. var leftPanelOffset = (!isMobileMode() && $leftPanel.length > 0 && !$leftPanel.hasClass('popup')) ? $leftPanel.width() : 0;
  1180. var $rightPanel = $('.rightPanel:visible');
  1181. var rightPanelOffset = (!isMobileMode() && $rightPanel.length > 0) ? $rightPanel.width() : 0;
  1182. // Replace current panel size with panel size after animation for expand or collapse completes
  1183. if (typeof panelSize !== 'undefined') {
  1184. if (isLeftPanel) leftPanelOffset = panelSize;
  1185. else rightPanelOffset = panelSize;
  1186. }
  1187. return $(window).width() - rightPanelOffset - leftPanelOffset;
  1188. }
  1189. var updateClippingBoundsWidth = $axure.player.updateClippingBoundsWidth = function () {
  1190. if ($('.leftPanel').is(':visible')) $('#clippingBounds').css('left', $('.leftPanel').width());
  1191. else $('#clippingBounds').css('left', '0px');
  1192. $('#clippingBounds').width(calculateClippingBoundsWidth());
  1193. }
  1194. var contentLeftOfOriginOffset = 0;
  1195. function calculateClippingBoundsScrollPosition() {
  1196. // Adjust for mainPanelContainer scaling (scale should be "none" for scaleVal == 0 or scaleVal == 1)
  1197. var $iframe = $($('#mainFrame')[0].contentWindow);
  1198. var selectedScale = $('.vpScaleOption').find('.selectedRadioButton');
  1199. var scaleVal = $(selectedScale).parent().attr('val');
  1200. var dimStr = $('.currentAdaptiveView').attr('data-dim');
  1201. var dim = dimStr ? dimStr.split('x') : { w: '0', h: '0' };
  1202. var isDevice = dim[1] != '0' ? true : false;
  1203. // This line is necessary for right handling DEFAULT SCALE
  1204. // Because default scale relates to scale-to-fit item for device projects
  1205. if (scaleVal == '0' && isDevice) scaleVal = 2;
  1206. var scale = $('#mainPanelContainer').css('transform');;
  1207. scale = (scale == "none") ? 1 : Number(scale.substring(scale.indexOf('(') + 1, scale.indexOf(',')));
  1208. // Iframe and Main Panel Positioning
  1209. var iframeScroll = determineIframeScroll();
  1210. var iframePos = determineIframePosition();
  1211. var viewablePanelLeftMargin = parseInt($('#mainPanelContainer').css('margin-left'));
  1212. var viewablePanelTop = parseInt($('#mainPanelContainer').css('top'));
  1213. if (isNaN(viewablePanelTop)) viewablePanelTop = 0;
  1214. if (scaleVal == 2) {
  1215. // Scale to Fit (account for main panel container scale) -- needed for device mode in Scale to Fit
  1216. viewablePanelLeftMargin = ($('#mainPanel').width() - ($('#mainPanelContainer').width() * scale)) / 2
  1217. viewablePanelTop = ($('#mainPanel').height() - ($('#mainPanelContainer').height() * scale)) / 2
  1218. }
  1219. if (scaleVal == 3) {
  1220. // Scale to Fit (account for main panel container scale) -- needed for device mode in Scale to Fit
  1221. viewablePanelLeftMargin = ($('#mainPanel').width() - ($('#mainPanelContainer').width() * scale)) / 2;
  1222. if (viewablePanelLeftMargin < 0) {
  1223. viewablePanelLeftMargin = 0;
  1224. }
  1225. }
  1226. // left and top positioning
  1227. var leftPos = viewablePanelLeftMargin + (iframePos.left - iframeScroll.scrollLeft) * scale;
  1228. var topPos = viewablePanelTop - iframeScroll.scrollTop * scale;
  1229. // Special cases for Centered Page
  1230. var isCentered = $($iframe[0].document.body).css('position') == 'relative';
  1231. if (isCentered && scaleVal == 1) leftPos = 0;
  1232. else if (isCentered && scaleVal == 2) leftPos = $('#mainPanelContainer').width() * scale / 2.0 - contentLeftOfOriginOffset;
  1233. // Include clipFrameScroll offset in mainPanelContainer
  1234. topPos += (parseFloat($('#clipFrameScroll').css("top")) || 0) * scale;
  1235. return {
  1236. left: leftPos,
  1237. top: topPos
  1238. }
  1239. }
  1240. function repositionClippingBoundsScroll() {
  1241. if (!$axure.player.settings.isAxshare) return;
  1242. (function repositionWhenReady() {
  1243. if ($($('#mainFrame')[0].contentWindow.document.body).length === 0) {
  1244. setTimeout(repositionWhenReady, 50);
  1245. } else {
  1246. var position = calculateClippingBoundsScrollPosition();
  1247. // Adding mainPanel scroll here, since it does not work well with calculating animation left position
  1248. position.left = position.left - $('#mainPanel').scrollLeft() - $('#clipFrameScroll').scrollLeft();
  1249. position.top = position.top - $('#mainPanel').scrollTop() - $('#clipFrameScroll').scrollTop();
  1250. $('#clippingBoundsScrollContainer').css('left', position.left + 'px');
  1251. $('#clippingBoundsScrollContainer').css('top', position.top + 'px');
  1252. }
  1253. })();
  1254. }
  1255. function calculateScrollLeftWithOffset(offset, isLeftPanel) {
  1256. if (!$axure.player.settings.isAxshare) return;
  1257. if ($($('#mainFrame')[0].contentWindow.document.body).length === 0) return;
  1258. var scaleVal = $('.vpScaleOption').find('.selectedRadioButton').parent().attr('val');
  1259. if (scaleVal == 2) return;
  1260. var $iframe = $($('#mainFrame')[0].contentWindow);
  1261. var $body = $($iframe[0].document.body);
  1262. var dimStr = $('.currentAdaptiveView').attr('data-dim');
  1263. var hasFrame = (!dimStr ? false : dimStr.split('x')[1] != '0') && !$axure.player.noFrame;
  1264. var isCentered = $body.css('position') == 'relative'; //body position is always static while page is still loading (thus false, if called on intial load)
  1265. var isCollapsing = offset > 0; //offset is positive when collapsing since we are gaining offset more space for content viewing
  1266. // Base case left positioning
  1267. var leftPos = calculateClippingBoundsScrollPosition().left;
  1268. // If maintaining view options requires a left adjustment not equivalent to panel size (which has already being added in leftPos above)
  1269. var viewAdjustment = 0;
  1270. // Mobile Frame adjustment
  1271. if (hasFrame) {
  1272. var viewablePanelLeftMargin = parseInt($('#mainPanelContainer').css('margin-left'));
  1273. var viewablePanelRightMargin = parseInt($('#mainPanelContainer').css('margin-right'));
  1274. // Cases
  1275. // 0) Adaptive view frame doesn't fit in viewable bounds (viewablePanelLeftMargin is zero) -- use entire offset of panel (no adjustment needed)
  1276. // 1) Adaptive view frame fits in bounds -- then half of incoming panel will be split left and half right (offset / 2)
  1277. // 2) and 3) View Frame either fits in bounds before animation and no longer will after, or vice versa. Mix of previous two cases
  1278. if (isCollapsing) {
  1279. if (viewablePanelLeftMargin != 0) {
  1280. viewAdjustment = offset / 2;
  1281. } else if (-viewablePanelRightMargin < offset) {
  1282. viewAdjustment = ((offset + viewablePanelRightMargin) / 2);
  1283. }
  1284. } else if (viewablePanelLeftMargin != 0) {
  1285. viewAdjustment = Math.max(offset / 2, -viewablePanelLeftMargin)
  1286. }
  1287. }
  1288. // Centered Page adjustment
  1289. if (isCentered) {
  1290. // Width of content not able to fit inside current viewable frame
  1291. var clippedContentWidth = $body.width() - calculateClippingBoundsWidth(Math.abs(offset), isLeftPanel);
  1292. // Cases
  1293. // 0) Content never fits in bounds -- then entire offset of panel will move content left value (no adjustment needed as already handled)
  1294. // 1) Content fits in bounds -- then half of incoming panel offset will be split left and half right (offset / 2)
  1295. // 2) and 3) Content either fits in bounds before animation and no longer will after, or vice versa. Mix of previous two cases
  1296. if (clippedContentWidth <= 0) {
  1297. viewAdjustment = offset / 2;
  1298. } else if (isCollapsing && clippedContentWidth < offset) {
  1299. viewAdjustment = (offset - clippedContentWidth) / 2;
  1300. } else if (!isCollapsing && clippedContentWidth < -offset) {
  1301. viewAdjustment = (clippedContentWidth + offset) / 2;
  1302. }
  1303. }
  1304. return leftPos + viewAdjustment;
  1305. }
  1306. // Set to true when left panel or right panel are being expanded/collapsed
  1307. // returns to false when lsplitbar (switched to clippingBounds) finishes animation (thus panels will be fully expanded or retracted at this point)
  1308. var isAnimating = $axure.player.isAnimating = false;
  1309. $axure.player.collapseToBar = function (context, hostId) {
  1310. lastLeftPanelWidth = $('.leftPanel').width();
  1311. lastRightPanelWidth = $('.rightPanel').width();
  1312. if (context === 'project' || context === 'all') {
  1313. if(!isMobileMode()) {
  1314. isAnimating = true;
  1315. var newWidth = lastLeftPanelWidth != 0 ? lastLeftPanelWidth : lastLeftPanelWidthDefault;
  1316. var clippingWidth = calculateClippingBoundsWidth(0, true);
  1317. var newLeft = calculateScrollLeftWithOffset(newWidth, true);
  1318. $('.leftPanel').animate({ 'margin-left': -newWidth + 'px' },
  1319. { duration: 200, complete: function() { $('.leftPanel').width(0).hide().css({ 'marginLeft': '' }); } });
  1320. $('#lsplitbar').animate({ left: '-4px' },
  1321. { duration: 200, complete: function() { $('#lsplitbar').hide(); } });
  1322. $('#clippingBounds').animate({ left: '', width: clippingWidth + 'px' }, { duration: 200 });
  1323. $('#clippingBoundsScrollContainer').animate({ left: newLeft + 'px' },
  1324. { duration: 200, complete: function () {
  1325. isAnimating = false;
  1326. $axure.player.resizeContent();
  1327. $axure.player.pluginVisibleChanged(hostId, false);
  1328. }});
  1329. } else {
  1330. $('.leftPanel').width(0);
  1331. $('#lsplitbar').hide();
  1332. }
  1333. }
  1334. if (context === 'inspect' || context === 'all') {
  1335. if (!isMobileMode()) {
  1336. isAnimating = true;
  1337. var newWidth = lastRightPanelWidth != 0 ? lastRightPanelWidth : lastRightPanelWidthDefault;
  1338. var clippingWidth = calculateClippingBoundsWidth(0, false);
  1339. var newLeft = calculateScrollLeftWithOffset(newWidth, false);
  1340. $('.rightPanel').animate({ 'margin-right': -newWidth + 'px' },
  1341. { duration: 200, complete: function () { $('.rightPanel').width(0).hide().css({ 'marginRight': '' }); } });
  1342. $('#rsplitbar').animate({ left: $(window).width() + 'px' },
  1343. { duration: 200, complete: function () { $('#rsplitbar').hide(); } });
  1344. $('#clippingBounds').animate({ width: clippingWidth + 'px' }, { duration: 200 });
  1345. $('#clippingBoundsScrollContainer').animate({ left: newLeft + 'px' },
  1346. { duration: 200, complete: function () {
  1347. isAnimating = false;
  1348. $axure.player.resizeContent();
  1349. $axure.player.pluginVisibleChanged(hostId, false);
  1350. }});
  1351. } else {
  1352. $('.rightPanel').width(0);
  1353. $('#rsplitbar').hide();
  1354. }
  1355. }
  1356. $(window).resize();
  1357. toolBarOnly = true;
  1358. }
  1359. $axure.player.expandFromBar = function (hostId, context, isFinalPluginToRestore) {
  1360. if (context === 'project') {
  1361. if ($('#lsplitbar').is(':visible')) return;
  1362. $('.leftPanel').removeClass('popup');
  1363. if(!isMobileMode()) {
  1364. isAnimating = true;
  1365. var newWidth = (lastLeftPanelWidth ? lastLeftPanelWidth : lastLeftPanelWidthDefault);
  1366. var clippingWidth = calculateClippingBoundsWidth(newWidth, true);
  1367. var newLeft = calculateScrollLeftWithOffset(-newWidth, true);
  1368. $('.leftPanel').width(newWidth);
  1369. $('.leftPanel').css('margin-left', -newWidth + 'px').show();
  1370. $('.leftPanel').animate({ 'margin-left': '0px' }, { duration: 200, complete: function () { $('.leftPanel').css({ 'marginLeft': '' }); } });
  1371. $('#lsplitbar').css('left', '-4px');
  1372. $('#lsplitbar').show();
  1373. $('#lsplitbar').animate({ left: newWidth - 4 + 'px' }, { duration: 200 });
  1374. $('#clippingBounds').animate({ left: newWidth + 'px', width: clippingWidth + 'px' }, { duration: 200 });
  1375. $('#clippingBoundsScrollContainer').animate({ left: newLeft + 'px' },
  1376. { duration: 200, complete: function () {
  1377. isAnimating = false;
  1378. $axure.player.resizeContent();
  1379. if (isFinalPluginToRestore) $('#clippingBoundsScrollContainer').show();
  1380. $axure.player.pluginVisibleChanged(hostId, true);
  1381. }});
  1382. }
  1383. } else {
  1384. if ($('#rsplitbar').is(':visible')) {
  1385. // update width of rightPanel plugin
  1386. var newWidth = lastRightPanelWidth ? lastRightPanelWidth : lastRightPanelWidthDefault;
  1387. $('#' + hostId).width(newWidth);
  1388. $('#' + hostId).show();
  1389. $axure.player.pluginVisibleChanged(hostId, true);
  1390. return;
  1391. }
  1392. if (!isMobileMode()) {
  1393. isAnimating = true;
  1394. var newWidth = lastRightPanelWidth ? lastRightPanelWidth : lastRightPanelWidthDefault;
  1395. var clippingWidth = calculateClippingBoundsWidth(newWidth, false);
  1396. var newLeft = calculateScrollLeftWithOffset(-newWidth, false);
  1397. $('.rightPanel').width(newWidth);
  1398. $('.rightPanel').css('margin-right', -newWidth + 'px');
  1399. $('#' + hostId).show();
  1400. $('.rightPanel').animate({ 'margin-right': '0px' }, { duration: 200, complete: function () { $('.rightPanel').css({ 'marginRight': '' }); } });
  1401. $('#rsplitbar').css('left', $(window).width());
  1402. $('#rsplitbar').show();
  1403. $('#rsplitbar').animate({ left: $(window).width() - $('.rightPanel').width() + 'px' }, { duration: 200 });
  1404. $('#clippingBounds').animate({ width: clippingWidth + 'px' }, { duration: 200 });
  1405. $('#clippingBoundsScrollContainer').animate({ left: newLeft + 'px' },
  1406. { duration: 200, complete: function () {
  1407. isAnimating = false;
  1408. $axure.player.resizeContent();
  1409. if (isFinalPluginToRestore) $('#clippingBoundsScrollContainer').show();
  1410. $axure.player.pluginVisibleChanged(hostId, true);
  1411. }});
  1412. }
  1413. }
  1414. $(window).resize();
  1415. toolBarOnly = false;
  1416. if (isMobileMode()) {
  1417. $('#mHideSidebar').show();
  1418. $('#nativeAppControlFrame').show();
  1419. }
  1420. }
  1421. var suspendRefreshViewPort = $axure.player.suspendRefreshViewPort = false;
  1422. $axure.player.refreshViewPort = function () {
  1423. if (suspendRefreshViewPort) return;
  1424. var dimStr = $('.currentAdaptiveView').attr('data-dim');
  1425. var dim = dimStr ? dimStr.split('x') : { w: '0', h: '0' };
  1426. var w = dim[0] != '0' ? dim[0] : '';
  1427. var h = dim[1] != '0' ? dim[1] : '';
  1428. var scaleVal = $('.vpScaleOption').find('.selectedRadioButton').parent().attr('val');
  1429. var selectedScaleValue = scaleVal;
  1430. $axure.player.noFrame = false;
  1431. if (h && scaleVal == 1) $axure.player.noFrame = true;
  1432. $('#mainPanelContainer').attr({
  1433. "data-scale-n": scaleVal,
  1434. "data-page-dimensions-type": h ? "device" : w ? "web" : "auto",
  1435. "data-scale-shift-x": null,
  1436. "data-scale-shift-y": null,
  1437. });
  1438. var clipToView = h && !$axure.player.noFrame;
  1439. var isDevice = h;
  1440. var mainPanelWidth = $('#mainPanel').width();
  1441. var mainPanelHeight = $('#mainPanel').height();
  1442. if (!w || !clipToView) w = mainPanelWidth;
  1443. if (!h || !clipToView) h = mainPanelHeight;
  1444. if (MOBILE_DEVICE && h > mainPanelHeight) h = mainPanelHeight;
  1445. if (MOBILE_DEVICE && w > mainPanelWidth) w = mainPanelWidth;
  1446. const mainFrameHeight = h;
  1447. const mainFrameWidth = w;
  1448. if (clipToView) {
  1449. if (!MOBILE_DEVICE && scaleVal == '0') scaleVal = 2;
  1450. w = Number(w);
  1451. h = Number(h);
  1452. $('#mainFrame').width(w);
  1453. $('#clipFrameScroll').width(w);
  1454. $('#clipFrameScroll').height(h);
  1455. var topPadding = MOBILE_DEVICE ? 0 : 10;
  1456. var leftPadding = 0;
  1457. var rightPadding = 0;
  1458. var bottomPadding = MOBILE_DEVICE ? 0 : 10;
  1459. if (scaleVal == 3) {
  1460. topPadding = 0;
  1461. bottomPadding = 0;
  1462. }
  1463. w = w + leftPadding + rightPadding;
  1464. h = h + topPadding + bottomPadding;
  1465. var x = (mainPanelWidth - w) / 2;
  1466. var y = (mainPanelHeight - h) / 2 - 1;
  1467. if (scaleVal != 2) {
  1468. x = Math.max(0, x);
  1469. y = Math.max(0, y);
  1470. }
  1471. $('#mainPanelContainer').attr({
  1472. "data-scale-shift-x": x,
  1473. "data-scale-shift-y": y,
  1474. });
  1475. $('#mainPanelContainer').css({
  1476. 'margin': 'auto',
  1477. 'top': y + 'px',
  1478. 'left': (x < 0 ? x + 'px' : 'auto')
  1479. });
  1480. $('#clipFrameScroll').css({
  1481. 'left': leftPadding + 'px',
  1482. 'top': topPadding + 'px'
  1483. });
  1484. $('#mainPanelContainer').width(w);
  1485. $('#mainPanelContainer').height(h);
  1486. } else {
  1487. $('#mainFrame').width('100%');
  1488. $('#clipFrameScroll').width('100%');
  1489. $('#clipFrameScroll').height(h);
  1490. $('#clipFrameScroll').css({ 'left': '', 'top': '' });
  1491. $('#mainPanelContainer').height(h);
  1492. $('#mainPanelContainer').css({
  1493. 'left': '',
  1494. 'margin': '',
  1495. 'top': ''
  1496. });
  1497. }
  1498. $axure.messageCenter.postMessage('setDeviceMode', { device: isDevice, width: w, scaleToWidth: (scaleVal == "1") });
  1499. $(".vpScaleOption").show();
  1500. var prevScaleN = $('#mainPanelContainer').css('transform');
  1501. prevScaleN = (prevScaleN == "none") ? 1 : Number(prevScaleN.substring(prevScaleN.indexOf('(') + 1, prevScaleN.indexOf(',')));
  1502. $('#mainPanelContainer').css({
  1503. 'transform': '',
  1504. 'transformOrigin': ''
  1505. });
  1506. var $leftPanel = $('.leftPanel:visible');
  1507. var leftPanelOffset = (!isMobileMode() && $leftPanel.length > 0) ? $leftPanel.width() : 0;
  1508. var $rightPanel = $('.rightPanel:visible');
  1509. var rightPanelOffset = (!isMobileMode() && $rightPanel.length > 0) ? $rightPanel.width() : 0;
  1510. var vpScaleData = {
  1511. scale: scaleVal,
  1512. prevScaleN: prevScaleN,
  1513. mainFrameHeight,
  1514. mainFrameWidth,
  1515. viewportHeight: h,
  1516. viewportWidth: w,
  1517. panelWidthOffset: leftPanelOffset + rightPanelOffset,
  1518. clipToView: clipToView
  1519. };
  1520. $axure.messageCenter.postMessage('getScale', vpScaleData);
  1521. $axure.messageCenter.postMessage('cloud_ScaleValueChanged', {
  1522. scale: selectedScaleValue,
  1523. });
  1524. if (scaleVal == '0' && clipToView) $('#mainPanel').css('overflow', 'auto');
  1525. else $('#mainPanel').css('overflow', '');
  1526. }
  1527. $axure.player.getProjectName = function getProjectName() {
  1528. if (typeof PREVIEW_INFO !== 'undefined') {
  1529. return PREVIEW_INFO.fileName;
  1530. } else if(typeof $axure.player.settings.projectName !== 'undefined') {
  1531. return $axure.player.settings.projectName;
  1532. } else return false;
  1533. }
  1534. function initializeLogo() {
  1535. if(typeof PREVIEW_INFO !== 'undefined') {
  1536. $('#previewNotice').show();
  1537. }
  1538. //if (typeof PREVIEW_INFO !== 'undefined') {
  1539. // $('#interfaceControlFrameLogoCaptionContainer').html(PREVIEW_INFO.fileName);
  1540. //} else if (typeof $axure.player.settings.projectName !== 'undefined') {
  1541. // $('#interfaceControlFrameLogoCaptionContainer').html($axure.player.settings.projectName);
  1542. //} else {
  1543. // $('#interfaceControlFrameLogoCaptionContainer').hide();
  1544. //}
  1545. //if ($axure.document.configuration.logoImagePath) {
  1546. // var image = new Image();
  1547. // //image.onload = function () {
  1548. // // //$('#logoImage').css('max-width', this.width + 'px');
  1549. // // $('#interfaceControlFrameContainer').css('margin-left', '-' + $('#logoImage').width() / 2 + 'px');
  1550. // // //$axure.player.resizeContent();
  1551. // //};
  1552. // image.src = $axure.document.configuration.logoImagePath;
  1553. // $('#interfaceControlFrameLogoImageContainer').html('<img id="logoImage" src="" />');
  1554. // $('#logoImage').attr('src', $axure.document.configuration.logoImagePath);//.on('load', function () { $axure.player.resizeContent(); });
  1555. //} else $('#interfaceControlFrameLogoImageContainer').hide();
  1556. //if ($axure.document.configuration.logoImageCaption) {
  1557. // $('#interfaceControlFrameLogoCaptionContainer').html($axure.document.configuration.logoImageCaption);
  1558. //} else $('#interfaceControlFrameLogoCaptionContainer').hide();
  1559. //if(!$('#interfaceControlFrameLogoImageContainer').is(':visible') && !$('#interfaceControlFrameLogoCaptionContainer').is(':visible')) {
  1560. // $('#interfaceControlFrameLogoContainer').hide();
  1561. //}
  1562. }
  1563. function initializePreview() {
  1564. if (typeof PREVIEW_INFO !== 'undefined') {
  1565. $('#separatorContainer').addClass('hasLeft');
  1566. $('#overflowMadeWith').addClass('preview');
  1567. var callback = undefined;
  1568. $('#publishButton').click(function () {
  1569. $.ajax({
  1570. type: 'GET',
  1571. url: 'publish',
  1572. data: {},
  1573. success: function (response) {
  1574. if (callback) callback(response);
  1575. },
  1576. error: function (response) {
  1577. if (callback) callback(response);
  1578. },
  1579. dataType: 'jsonp'
  1580. });
  1581. });
  1582. }
  1583. }
  1584. var iosInnerHeight = (function () {
  1585. if (!navigator.userAgent.match(/iphone|ipod|ipad/i)) {
  1586. /**
  1587. * Avoids conditional logic in the implementation
  1588. * @return {number} - window's innerHeight measurement in pixels
  1589. */
  1590. return function () {
  1591. return window.innerHeight;
  1592. };
  1593. }
  1594. // Store initial orientation
  1595. var axis = Math.abs(window.orientation);
  1596. // And hoist cached dimensions
  1597. var dims = { w: 0, h: 0 };
  1598. /**
  1599. * Creates an element with a height of 100vh since iOS accurately
  1600. * reports vp height (but not window.innerHeight). Then destroy it.
  1601. */
  1602. var createRuler = function () {
  1603. var ruler = document.createElement('div');
  1604. ruler.style.position = 'fixed';
  1605. ruler.style.height = '100vh';
  1606. ruler.style.width = 0;
  1607. ruler.style.top = 0;
  1608. document.documentElement.appendChild(ruler);
  1609. // Set cache conscientious of device orientation
  1610. dims.w = axis === 90 ? ruler.offsetHeight : window.innerWidth;
  1611. dims.h = axis === 90 ? window.innerWidth : ruler.offsetHeight;
  1612. // Clean up after ourselves
  1613. document.documentElement.removeChild(ruler);
  1614. ruler = null;
  1615. };
  1616. // Measure once
  1617. createRuler();
  1618. /**
  1619. * Returns window's cached innerHeight measurement
  1620. * based on viewport height and device orientation
  1621. * @return {number} - window's innerHeight measurement in pixels
  1622. */
  1623. return function () {
  1624. if (Math.abs(window.orientation) !== 90) {
  1625. return dims.h;
  1626. }
  1627. return dims.w;
  1628. };
  1629. }());
  1630. function includeTokens(ajaxData, excludeUser) {
  1631. //If the authCookieValue is set (a password-protected local prototype), then send the
  1632. //token as well (because cookies don't always get sent to external domains)
  1633. if (authCookieValue) {
  1634. $.extend(ajaxData, { token: authCookieValue });
  1635. }
  1636. if (!excludeUser && userCookieValue) {
  1637. $.extend(ajaxData, { utoken: userCookieValue });
  1638. }
  1639. }
  1640. function setUserLoggedInStatus(response, safariAuthResponseProfile) {
  1641. if (!response.success) {
  1642. userAcct.isUsingAxureAcct = false;
  1643. } else {
  1644. if (safariAuthResponseProfile) response = safariAuthResponseProfile;
  1645. userAcct.userId = response.userId;
  1646. if (safariAuthResponseProfile)
  1647. userAcct.userName = response.username == null || response.username.trim() === '' ? response.userEmail : response.username.trim();
  1648. else
  1649. userAcct.userName = response.nickname == null || response.nickname.trim() === '' ? response.userEmail : response.nickname.trim();
  1650. userAcct.userEmail = response.userEmail;
  1651. userAcct.userProfileImg = response.profileImageUrl;
  1652. userAcct.isUsingAxureAcct = true;
  1653. if (response.authToken != null) {
  1654. $axshare.setAuthCookie(response.authToken);
  1655. userCookieValue = response.authToken;
  1656. }
  1657. }
  1658. // If feedback is loaded, update feedback with new account information
  1659. if (typeof feedback !== 'undefined') feedback.updateUserAccountInfo(userAcct, authCookieValue, userCookieValue);
  1660. }
  1661. // TODO: for on prem, we need to use an ajax call directly to share instead of accounts
  1662. // Verify authentication against axure accounts
  1663. $axure.player.axureAuth = function axureAuth(callback) {
  1664. if (window.$axshare != null) {
  1665. $axshare.auth(function (response) {
  1666. if (response.success) {
  1667. setUserLoggedInStatus(response);
  1668. } else {
  1669. if (isSafari()) {
  1670. var ajaxData = {
  1671. userId: userAcct.isUsingAxureAcct ? userAcct.userId : ""
  1672. };
  1673. includeTokens(ajaxData);
  1674. $.ajax({
  1675. type: 'GET',
  1676. url: feedbackServiceUrl + '/safariAuth',
  1677. data: ajaxData,
  1678. success: function (response) {
  1679. if (!response.success) {
  1680. setUserLoggedInStatus(response);
  1681. } else {
  1682. setUserLoggedInStatus(response, response.data.profile[userAcct.userId]);
  1683. if (callback != null) {
  1684. callback(response);
  1685. }
  1686. }
  1687. },
  1688. dataType: 'jsonp'
  1689. });
  1690. } else {
  1691. setUserLoggedInStatus(response);
  1692. }
  1693. }
  1694. if (callback != null) {
  1695. callback(response);
  1696. }
  1697. });
  1698. }
  1699. }
  1700. // TODO: for on prem, we need to use an ajax call directly to share instead of accounts
  1701. // Log into axure accounts
  1702. $axure.player.axureLogin = function axureLogin(email, password, success, failure, saml) {
  1703. if (window.$axshare != null) {
  1704. password = password === passHint ? "" : password;
  1705. $axshare.login(email, password, false, function (response) {
  1706. if (response.redirecturl !== "" && response.redirecturl != null) {
  1707. saml(response);
  1708. return;
  1709. }
  1710. if (response.success && (response.verified || isSubInstance)) {
  1711. if (isSafari()) setUserLoggedInStatus(response);
  1712. $axure.player.axureAuth(success);
  1713. } else {
  1714. failure(response);
  1715. }
  1716. }, window.ON_PREM_LDAP_ENABLED);
  1717. } else {
  1718. failure();
  1719. }
  1720. }
  1721. function playerLogout() {
  1722. userAcct.isUsingAxureAcct = false;
  1723. userAcct.userId = '';
  1724. userAcct.userProfileImg = '';
  1725. // If feedback is loaded, update feedback with new account information
  1726. if (typeof feedback !== 'undefined') feedback.updateUserAccountInfo(userAcct);
  1727. }
  1728. $axure.player.logout = function (feedbackLogout) {
  1729. var completeLogout = playerLogout;
  1730. if (feedbackLogout) {
  1731. completeLogout = function () {
  1732. feedbackLogout();
  1733. playerLogout();
  1734. }
  1735. }
  1736. if (window.$axshare != null) {
  1737. $axshare.logout(completeLogout);
  1738. } else {
  1739. completeLogout();
  1740. }
  1741. }
  1742. /*
  1743. * TODO: Start of Login/Account Mgmt UI, which will need to be updated (currenly uses feedback9.css often)
  1744. */
  1745. function buildAccountLoginPopup() {
  1746. return [
  1747. '<div class="axClearMsgBubble_Player axureLoginBubble_Player">',
  1748. ' <div class="axureLoginBubbleContainer_Player">',
  1749. ' <span style="font-weight: bold; font-size: 10px;">Login into your Axure Cloud account</span>',
  1750. ' <input type="text" autocapitalize="none" name="email" class="axureEmail" style="margin-top: 7px;"/>',
  1751. ' <input name="password" autocapitalize="none" class="axurePassword" />',
  1752. ' <div class="feedbackGreenBtn_Player">LOG IN</div>',
  1753. ' <div class="errorMessage"></div>',
  1754. ' <div id="playerSignUpLink" style="text-align: right; margin-top: 5px; font-size: 10px;">',
  1755. ' <span>No account? <a class="axureSignUpLink" href="', window.AXSHARE_HOST_SECURE_URL, '" target="_blank">Sign Up</a></span>',
  1756. ' </div>',
  1757. ' </div>',
  1758. '</div>'
  1759. ].join("");
  1760. }
  1761. // Bind events to axure login speech bubble (watermark, login, errors, click outside)
  1762. function bindAxureLoginContainerEvent() {
  1763. var $container = $("#accountLoginContainer");
  1764. $container.find('input[name="email"]').addClass("watermark").val(emailHint).focus(function () {
  1765. if ($(this).val() === emailHint) {
  1766. $(this).removeClass("watermark").val("");
  1767. }
  1768. }).blur(function () {
  1769. if ($(this).val() === "") {
  1770. $(this).addClass("watermark").val(emailHint);
  1771. }
  1772. $container.find('.errorMessage').text('');
  1773. $container.find('.errorMessage').hide();
  1774. }).keyup(function (event) {
  1775. if (event.keyCode == 13) {
  1776. $container.find('.feedbackGreenBtn').click();
  1777. }
  1778. });
  1779. $container.find('input[name="password"]').addClass("watermark").val(passHint).focus(function () {
  1780. if ($(this).val() === passHint) {
  1781. $(this).removeClass("watermark").val("");
  1782. //$(this).removeClass("watermark").val("").attr("type", "password");
  1783. // Note: this might be an issue since jquery doesn't like it. Test in IE
  1784. $(this)[0].setAttribute('type', 'password');
  1785. }
  1786. }).blur(function () {
  1787. if ($(this).val() === "") {
  1788. $(this).val(passHint).addClass("watermark");
  1789. //$(this).val(passHint).addClass("watermark").removeAttr("type");
  1790. // Note: this might be an issue since jquery doesn't like it. Test in IE
  1791. $(this)[0].setAttribute('type', 'text');
  1792. }
  1793. $container.find('.errorMessage').text('');
  1794. $container.find('.errorMessage').hide();
  1795. }).keyup(function (event) {
  1796. if (event.keyCode == 13) {
  1797. $container.find('.feedbackGreenBtn_Player').click();
  1798. }
  1799. });
  1800. // Login Submit Event
  1801. $container.find('.feedbackGreenBtn_Player').click(function (e) {
  1802. var email = $container.find('.axureEmail').val();
  1803. var password = $container.find('.axurePassword').val();
  1804. $axure.player.axureLogin(email, password, function (response) {
  1805. // Success
  1806. // Clear out fields
  1807. $container.find('.axureEmail').val(emailHint).addClass("watermark");
  1808. $container.find('.axurePassword').val(passHint).addClass("watermark");
  1809. $container.find('.axurePassword')[0].setAttribute('type', 'text');
  1810. closePopup();
  1811. }, function (response) {
  1812. // Failure
  1813. $container.find('.errorMessage').text(response != null && response.message ? response.message : "There was an error connecting to the server, please try again later.");
  1814. $container.find('.errorMessage').show();
  1815. }, function (response) {
  1816. // SAML User
  1817. $container.find('.errorMessage').empty();
  1818. $container.find('.errorMessage').append("Please <a class='refreshLink' style='text-decoration: underline;'>refresh</a> this page after logging in via your identity provider.");
  1819. $container.find('.errorMessage').show();
  1820. window.open(response.redirecturl, '_blank');
  1821. $container.find('.errorMessage').find('.refreshLink').click(function () {
  1822. location.reload(true);
  1823. });
  1824. });
  1825. });
  1826. };
  1827. function initializeSignIn() {
  1828. if (typeof PREVIEW_INFO === 'undefined' && $axure.player.settings.isAxshare) {
  1829. (function finishInit() {
  1830. if (window.$axshare == null || $axshare.auth == null || $axshare.login == null) {
  1831. setTimeout(finishInit, 50);
  1832. } else {
  1833. // Call to set readOnlyMode, readOnlyMessage, and isSubinstance (readOnlyMode/Message currently only used for feedback9)
  1834. $.ajax({
  1835. type: 'GET',
  1836. url: feedbackServiceUrl + '/GetShareStatus',
  1837. data: {},
  1838. success: function (response) {
  1839. //readOnlyMode = response.readOnlyMode;
  1840. //readOnlyMessage = response.readOnlyMessage;
  1841. isSubInstance = response.isSubInstance;
  1842. if (isSubInstance) $('#accountLoginContainer').find("#playerSignUpLink").hide();
  1843. // For now, calling methods to set these values in feedback on start (could later make a general method to retrieve these values from player)
  1844. if (typeof feedback !== 'undefined') {
  1845. feedback.setReadOnlyModeAndMessage(response.readOnlyMode, response.readOnlyMessage);
  1846. feedback.setIsSubInstance(isSubInstance);
  1847. }
  1848. },
  1849. dataType: 'jsonp'
  1850. });
  1851. // Login container
  1852. $("#accountLoginContainer").append(buildAccountLoginPopup());
  1853. bindAxureLoginContainerEvent();
  1854. // Attempt to auth and acquire account information, then update top panel
  1855. $axure.player.axureAuth();
  1856. }
  1857. })();
  1858. }
  1859. }
  1860. function overflowProvidesScroll(node) {
  1861. var style = getComputedStyle(node);
  1862. var overflowIsHidden = style.overflow === 'hidden' || (style.overflowX === 'hidden' && style.overflowY === 'hidden');
  1863. var overflowIsVisible = style.overflow === 'visible'|| (style.overflowX === 'visible' && style.overflowY === 'visible');
  1864. var mozTextareaOverflowVisible = FIREFOX && overflowIsVisible && node instanceof HTMLTextAreaElement;
  1865. return !overflowIsHidden && !overflowIsVisible || mozTextareaOverflowVisible;
  1866. }
  1867. function findNearestScrollableParent(firstNode) {
  1868. var node = firstNode;
  1869. var scrollable = null;
  1870. while (!scrollable && node) {
  1871. if (node.scrollWidth > node.clientWidth || node.scrollHeight > node.clientHeight) {
  1872. if (overflowProvidesScroll(node) || $(node).css('-webkit-overflow-scrolling') === 'touch') {
  1873. scrollable = node;
  1874. }
  1875. }
  1876. node = node.parentNode;
  1877. }
  1878. return scrollable;
  1879. }
  1880. function getScrollOwner(target) {
  1881. var owner = findNearestScrollableParent(target);
  1882. if (!owner || owner === document.documentElement || owner === document.body || $(owner).parents('#topPanel').length || owner == document.getElementById('forwardSlash')) {
  1883. return null;
  1884. }
  1885. return owner;
  1886. }
  1887. function removeElasticScrollFromIframe() {
  1888. var $iframe = $($('#mainFrame')[0].contentWindow);
  1889. $iframe[0].document.body.addEventListener('touchmove', function (event) {
  1890. if (!getScrollOwner(event.target)) {
  1891. event.preventDefault();
  1892. }
  1893. }, { passive: false });
  1894. }
  1895. $(document).ready(function () {
  1896. (function finishPlayerInit() {
  1897. if ($axure.player.settings.isAxshare) {
  1898. $axure.page.bind('load.start', contentDocument_onload);
  1899. if ($axure.player.settings.loadFeedbackPlugin) {
  1900. $axure.utils.loadJS('/Scripts/plugins/feedback/feedback9.js');
  1901. /******* DEBUG: Allows for debugging/viewing feedback9.js in browser inspect mode ******/
  1902. //var hdr = document.createElement('script');
  1903. //hdr.type = "text/javascript"
  1904. //hdr.src = '/Scripts/plugins/feedback/feedback9.js';
  1905. //document.head.appendChild(hdr);
  1906. }
  1907. } else {
  1908. $axure.page.bind('load.start', common_contentDocument_onload);
  1909. }
  1910. initializeEvents();
  1911. initializeMainFrame();
  1912. $('.leftPanel').width(0);
  1913. $('#maximizePanelContainer').hide();
  1914. if ($axure.player.settings.startCollapsed) {
  1915. collapse();
  1916. $('.leftPanel').width(0);
  1917. var maxPanelWidth = $('#maximizePanel').width();
  1918. setTimeout(function() {
  1919. $('#maximizePanel').animate({
  1920. left:'-' + maxPanelWidth + 'px'
  1921. }, 300);
  1922. }, 2000);
  1923. }
  1924. if (MOBILE_DEVICE) {
  1925. $('body').removeClass('hashover');
  1926. if (SAFARI) {
  1927. // Stop pinch zoom (stopping all gestures for now)
  1928. // Gesturestart is only supported in Safari
  1929. document.addEventListener("gesturestart", function (e) {
  1930. e.preventDefault();
  1931. });
  1932. }
  1933. if (IOS) {
  1934. // Attempt at removing elastic scroll while in mobile menu
  1935. var touching = false;
  1936. var pageYStart = 0;
  1937. var pageYOffset = 0;
  1938. document.body.addEventListener('touchend', function (event) {
  1939. if (getScrollOwner(event.target)) {
  1940. touching = false;
  1941. }
  1942. }, { passive: false });
  1943. document.body.addEventListener('touchmove', function (event) {
  1944. var owner = getScrollOwner(event.target)
  1945. if (!owner) {
  1946. event.preventDefault();
  1947. } else {
  1948. if ($(owner).scrollTop() == 0) {
  1949. if (touching) {
  1950. if (event.pageY >= pageYStart) {
  1951. event.preventDefault();
  1952. }
  1953. }
  1954. }
  1955. if ($(owner).scrollTop() + $(owner).height() == owner.scrollHeight) {
  1956. if (touching) {
  1957. if (event.pageY <= pageYStart) {
  1958. event.preventDefault();
  1959. }
  1960. }
  1961. }
  1962. }
  1963. }, { passive: false });
  1964. document.body.addEventListener('touchstart', function (event) {
  1965. var owner = getScrollOwner(event.target);
  1966. if (owner) {
  1967. if ($(owner).scrollTop() == 0) {
  1968. touching = true;
  1969. pageYStart = event.pageY;
  1970. pageYOffset = event.pageY;
  1971. }
  1972. if ($(owner).scrollTop() + $(owner).height() == owner.scrollHeight) {
  1973. touching = true;
  1974. pageYStart = event.pageY;
  1975. pageYOffset = event.pageY;
  1976. }
  1977. }
  1978. }, { passive: false });
  1979. removeElasticScrollFromIframe();
  1980. $('html').css('-webkit-tap-highlight-color', 'transparent');
  1981. // Stop iOS from automatically scaling parts of the mobile player
  1982. // Could stop automatic scaling on Ipads as well that we actually want, but for now, seems fine
  1983. $('body').css('-webkit-text-size-adjust', '100%');
  1984. window.addEventListener("orientationchange", function () {
  1985. var viewport = document.querySelector("meta[name=viewport]");
  1986. //so iOS doesn't zoom when switching back to portrait
  1987. if (IOS) {
  1988. viewport.setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover');
  1989. viewport.setAttribute('content', 'width=device-width, initial-scale=1.0, viewport-fit=cover');
  1990. } else {
  1991. viewport.setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0');
  1992. viewport.setAttribute('content', 'width=device-width, initial-scale=1.0');
  1993. }
  1994. $axure.player.resizeContent();
  1995. }, false);
  1996. $axure.page.bind('load.start', function () {
  1997. $axure.player.resizeContent();
  1998. });
  1999. }
  2000. // Always append both mobile browser menu and native menu, as app might not have returned value signifying native at this point
  2001. appendNativePrototypeControlFrame();
  2002. appendMobileBrowserControlFrame();
  2003. appendProjectOptions();
  2004. }
  2005. initializeLogo();
  2006. initializePreview();
  2007. $axure.player.resizeContent(true);
  2008. $axure.messageCenter.postMessage('finishInit');
  2009. })();
  2010. });
  2011. function appendProjectOptions() {
  2012. var toAppend = '';
  2013. toAppend += '<div id="projectOptionsHost" class="mobileOnlyPanel mobileMode">';
  2014. toAppend += ' <div class="pluginNameHeader">PROJECT OPTIONS</div>';
  2015. toAppend += ' <div id="projectOptionsScrollContainer">';
  2016. toAppend += ' <div class="mobileSubHeader">Hotspots</div>';
  2017. toAppend += ' <div id="projectOptionsShowHotspots" class="mobileText projectOptionsHotspotsRow" style="border-bottom: solid 1px #c7c7c7">';
  2018. toAppend += ' <div id="projectOptionsHotspotsCheckbox"></div>';
  2019. toAppend += ' Show Hotspots</div> ';
  2020. toAppend += ' <div class="mobileSubHeader" style="margin-top: 16px">Scale</div>';
  2021. toAppend += ' <div id="projectOptionsScaleContainer" class="mobileText"></div>';
  2022. toAppend += ' <div id="projectOptionsAdaptiveViewsHeader" class="mobileSubHeader" style="margin-top: 16px">Adaptive Views</div>';
  2023. toAppend += ' <div id="projectOptionsAdaptiveViewsContainer" class="mobileText"></div>'
  2024. toAppend += ' </div>'
  2025. toAppend += '</div>';
  2026. $('#mHideSidebar').prepend(toAppend);
  2027. $(('#projectOptionsHost')).click(function (e) { e.stopPropagation(); });
  2028. if (isMobileMode()) $axure.player.resizeContent();
  2029. }
  2030. function appendMobileBrowserControlFrame() {
  2031. var toAppend = "";
  2032. toAppend += '<div id="mobileBrowserControlFrame" class="mobilePrototypeControlFrame">';
  2033. toAppend += ' <div id="return" style="width:100%; position:relative; top:-15px; float:left">';
  2034. toAppend += ' <div id="closeBackground" class="circleBackground">';
  2035. toAppend += ' <div id="forwardSlash" class="closeIconSlash"><div id="backwardSlash" class="closeIconSlash"></div></div>';
  2036. toAppend += ' </div>';
  2037. toAppend += ' </div>';
  2038. toAppend += '</div>';
  2039. $('#mobileControlFrameContainer').append(toAppend);
  2040. $('#closeBackground').click(collapse);
  2041. // iOS will do incorrect click position / content bounds calculation which results in scroll getting reset to (0, 0)
  2042. if (IOS) $('#mobileControlFrameContainer').on($axure.eventNames.mouseDownName, function (e) { e.stopPropagation(); });
  2043. }
  2044. function appendNativePrototypeControlFrame() {
  2045. var toAppend = "";
  2046. toAppend += '<div id="nativeAppControlFrame" class="mobilePrototypeControlFrame">';
  2047. toAppend += ' <ul id="nativeMenuBlueBackground">';
  2048. toAppend += ' <li style="width:30%; float:left;">';
  2049. toAppend += ' <div id="exit" class="nativePrototypeButton" >';
  2050. toAppend += ' <div>';
  2051. toAppend += ' <div id="exitIcon"></div>';
  2052. toAppend += ' <div id="exitText" class="nativeMenuText">Exit</div>';
  2053. toAppend += ' </div>';
  2054. toAppend += ' </div>';
  2055. toAppend += ' </li>';
  2056. toAppend += ' <li id="return" style="width:40%; position:relative; top:-15px; float:left">';
  2057. toAppend += ' <div id="returnBackground" class="circleBackground">';
  2058. toAppend += ' <div id="returnIcon"></div>';
  2059. toAppend += ' </div>';
  2060. toAppend += ' <div id="returnText" class="nativeMenuText">Return to Prototype</div>';
  2061. toAppend += ' </li>';
  2062. toAppend += ' <li style="width:30%; float:right;">';
  2063. toAppend += ' <div id="refresh" class="nativePrototypeButton" >';
  2064. toAppend += ' <div>';
  2065. toAppend += ' <div id="refreshIcon"></div>';
  2066. toAppend += ' <div id="refreshText" class="nativeMenuText">Refresh</div>';
  2067. toAppend += ' </div>';
  2068. toAppend += ' </div>';
  2069. toAppend += ' </li>';
  2070. toAppend += ' </ul>';
  2071. toAppend += '</div>';
  2072. $('#mobileControlFrameContainer').append(toAppend);
  2073. var barHeight = IOS ? '72px' : '60px';
  2074. var returnIconDisplacement = IOS ? '-15px': '-20px';
  2075. var iconTopMargin = IOS ? '14px': '7px';
  2076. var returnTextTopMargin = IOS ? '9px': '7px';
  2077. document.getElementById('nativeAppControlFrame').style.height = barHeight;
  2078. document.getElementById('nativeMenuBlueBackground').style.height = barHeight;
  2079. document.getElementById('return').style.top = returnIconDisplacement;
  2080. document.getElementById('returnText').style.marginTop = returnTextTopMargin;
  2081. document.getElementById('refreshIcon').style.marginTop = iconTopMargin;
  2082. document.getElementById('exitIcon').style.marginTop = iconTopMargin;
  2083. addAppButtonClickListener("exit");
  2084. addAppButtonClickListener("refresh");
  2085. $('#returnBackground').click(collapse);
  2086. $('#nativeAppControlFrame').on('touchmove', function (e) {
  2087. e.stopPropagation();
  2088. }, false);
  2089. }
  2090. function addAppButtonClickListener(id) {
  2091. var func = function () { IOS ? window.webkit.messageHandlers.prototypeMenuButtonClick.postMessage(id) : ShareApp.PrototypeMenuButtonClick(id); };
  2092. document.getElementById(id).addEventListener("click", func, false);
  2093. }
  2094. function toggleSitemap() {
  2095. $axure.player.showPlugin(1);
  2096. }
  2097. function closePopup() {
  2098. var $container = $('.popup');
  2099. $container.removeClass('popup');
  2100. $('#overflowMenuButton').removeClass('selected');
  2101. $('#scaleMenuButton').removeClass('selected');
  2102. $('#interfaceAdaptiveViewsContainer').removeClass('selected');
  2103. $container.hide();
  2104. $('div.splitterMask').unbind($axure.eventNames.mouseDownName, closePopup);
  2105. $('div.splitterMask').remove();
  2106. }
  2107. $axure.player.closePopup = closePopup;
  2108. function showPopup($container) {
  2109. if ($('#browserOutOfDateNotification').is(":visible")) return;
  2110. $container.addClass('popup');
  2111. $container.show();
  2112. $('<div class="splitterMask"></div>').insertAfter($container);
  2113. $('div.splitterMask').bind($axure.eventNames.mouseDownName, closePopup);
  2114. }
  2115. $axure.player.showPopup = showPopup;
  2116. function toggleAdaptiveViewsPopup() {
  2117. if (($('#interfaceAdaptiveViewsListContainer').hasClass('popup'))) {
  2118. closePopup();
  2119. } else {
  2120. $('#interfaceAdaptiveViewsContainer').addClass('selected');
  2121. showPopup($('#interfaceAdaptiveViewsListContainer'));
  2122. }
  2123. }
  2124. function toggleOverflowMenuPopup() {
  2125. if (($('#overflowMenuContainer').hasClass('popup'))) {
  2126. closePopup();
  2127. } else {
  2128. $('#overflowMenuButton').addClass('selected');
  2129. showPopup($('#overflowMenuContainer'));
  2130. }
  2131. }
  2132. function toggleScaleMenuPopup() {
  2133. if (($('#scaleMenuContainer').hasClass('popup'))) {
  2134. closePopup();
  2135. } else {
  2136. $('#scaleMenuButton').addClass('selected');
  2137. showPopup($('#scaleMenuContainer'));
  2138. }
  2139. }
  2140. $axure.player.toggleScaleMenuPopup = toggleScaleMenuPopup;
  2141. var startSplitX;
  2142. var startSplitWidth;
  2143. function startLeftSplit() {
  2144. startSplitX = window.event.pageX;
  2145. startSplitWidth = lastLeftPanelWidth;
  2146. var $left = $('#lsplitbar');
  2147. $left.addClass('active');
  2148. $('<div class="splitterMask"></div>').insertAfter($left);
  2149. $(document).bind($axure.eventNames.mouseMoveName, doLeftSplitMove).bind($axure.eventNames.mouseUpName, endLeftSplitMove);
  2150. }
  2151. function startRightSplit() {
  2152. startSplitX = window.event.pageX;
  2153. startSplitWidth = lastRightPanelWidth;
  2154. var $left = $('#rsplitbar');
  2155. $left.addClass('active');
  2156. $('<div class="splitterMask"></div>').insertAfter($left);
  2157. $(document).bind($axure.eventNames.mouseMoveName, doRightSplitMove).bind($axure.eventNames.mouseUpName, endRightSplitMove);
  2158. }
  2159. function doLeftSplitMove() {
  2160. var currentX = window.event.pageX;
  2161. var newWidth = Math.min(startSplitWidth + currentX - startSplitX, $(window).width() - $('.rightPanel').width(), $(window).width() - lastRightPanelWidthDefault);
  2162. lastLeftPanelWidth = Math.max(lastLeftPanelWidthDefault, newWidth);
  2163. $('.leftPanel').width(lastLeftPanelWidth ? lastLeftPanelWidth : lastLeftPanelWidthDefault);
  2164. $('#lsplitbar').css('left', $('.leftPanel').width() - 4);
  2165. $axure.player.updateClippingBoundsWidth();
  2166. $axure.player.refreshViewPort();
  2167. }
  2168. function doRightSplitMove() {
  2169. var currentX = window.event.pageX;
  2170. var newWidth = Math.min(startSplitWidth - currentX + startSplitX, $(window).width() - $('.leftPanel').width(), $(window).width() - lastLeftPanelWidthDefault);
  2171. lastRightPanelWidth = Math.max(lastRightPanelWidthDefault, newWidth);
  2172. $('.rightPanel').width(lastRightPanelWidth ? lastRightPanelWidth : lastRightPanelWidthDefault);
  2173. $('#rsplitbar').css('left', $(window).width() - $('.rightPanel').width());
  2174. $axure.player.updateClippingBoundsWidth();
  2175. $axure.player.refreshViewPort();
  2176. }
  2177. function endLeftSplitMove() {
  2178. $('div.splitterMask').remove();
  2179. var $left = $('#lsplitbar');
  2180. $left.removeClass('active');
  2181. $(document).unbind($axure.eventNames.mouseMoveName, doLeftSplitMove).unbind($axure.eventNames.mouseUpName, endLeftSplitMove);
  2182. setAdaptiveView()
  2183. }
  2184. function endRightSplitMove() {
  2185. $('div.splitterMask').remove();
  2186. var $left = $('#rsplitbar');
  2187. $left.removeClass('active');
  2188. $(document).unbind($axure.eventNames.mouseMoveName, doRightSplitMove).unbind($axure.eventNames.mouseUpName, endRightSplitMove);
  2189. setAdaptiveView()
  2190. }
  2191. var startMX;
  2192. var startMLeft;
  2193. var startMElement;
  2194. var maxMLeft;
  2195. var getMaxMLeft = function () {
  2196. if ($('.rightPanel.mobileMode').length == 0) return $('.leftPanel.mobileMode').last().position().left + 100;
  2197. return $('.rightPanel.mobileMode').last().position().left + 100;
  2198. }
  2199. function startM(e) {
  2200. // Android touch event does not define pageX directly
  2201. if(window.event.pageX) {
  2202. startMX = window.event.pageX;
  2203. } else {
  2204. startMX = window.event.touches[0].pageX;
  2205. }
  2206. startMElement = window.event.target.id;
  2207. var $m = $('#mHideSidebar');
  2208. startMLeft = Number($m.css('left').replace('px', ''));
  2209. $(document).bind($axure.eventNames.mouseMoveName, doMMove).bind($axure.eventNames.mouseUpName, endMMove);
  2210. // Must stop propagation on iOS; otherwise scroll position of content will be reset to (0, 0)
  2211. // (likely due to position of click being calculated as out of bounds for outerContainer -- iOS is not adding scroll offset to bounds)
  2212. if (IOS) { e.stopPropagation() };
  2213. }
  2214. function doMMove() {
  2215. var $m = $('#mHideSidebar');
  2216. if(window.event.pageX) {
  2217. currentX = window.event.pageX;
  2218. } else {
  2219. currentX = window.event.touches[0].pageX;
  2220. }
  2221. var deltaX = currentX - startMX;
  2222. if (Math.abs(deltaX) > 0 && $('.splitterMask').length == 0) {
  2223. $('<div class="splitterMask"></div>').insertAfter($m);
  2224. }
  2225. var newLeft = startMLeft + deltaX;
  2226. newLeft = Math.min(0, newLeft);
  2227. newLeft = Math.max(-getMaxMLeft(), newLeft);
  2228. $m.css('left', newLeft + 'px');
  2229. }
  2230. function endMMove(e) {
  2231. $('div.splitterMask').remove();
  2232. $(document).unbind($axure.eventNames.mouseMoveName, doMMove).unbind($axure.eventNames.mouseUpName, endMMove);
  2233. e.stopPropagation();
  2234. var $m = $('#mHideSidebar');
  2235. if(window.event.pageX) {
  2236. currentX = window.event.pageX;
  2237. } else {
  2238. currentX = window.event.changedTouches[0].pageX;
  2239. }
  2240. var deltaX = currentX - startMX;
  2241. if (deltaX != 0 || startMElement != 'mHideSidebar') {
  2242. adjustM(currentX < startMX ? 'left' : 'right', true);
  2243. }
  2244. }
  2245. function adjustM(direction, animate) {
  2246. var $m = $('#mHideSidebar');
  2247. var duration = animate ? 100 : 0;
  2248. var newLeft = Number($m.css('left').replace('px', ''));
  2249. if (!$m.is(':visible') || newLeft > -100) {
  2250. $m.animate({ 'left': '-60px' }, duration);
  2251. } else if (newLeft < -getMaxMLeft() + 100) {
  2252. $m.animate({ 'left': (-getMaxMLeft() + 125) + 'px' }, duration);
  2253. } else if (direction == 'left') {
  2254. var handled = false;
  2255. var $panels = $('.rightPanel.mobileMode, .leftPanel.mobileMode');
  2256. $panels.each(function () {
  2257. var panelX = $(this).position().left;
  2258. if (panelX > -newLeft) {
  2259. $m.animate({ 'left': (-panelX + 25) + 'px' }, duration);
  2260. handled = true;
  2261. return false;
  2262. }
  2263. });
  2264. if (!handled) {
  2265. $m.animate({ 'left': (-$panels.last().position().left + 25) + 'px' }, duration);
  2266. }
  2267. } else if (direction == 'right') {
  2268. var handled = false;
  2269. var $panels = $('.rightPanel.mobileMode, .leftPanel.mobileMode');
  2270. $($panels.get().reverse()).each(function () {
  2271. var panelRight = $(this).position().left + $(this).width();
  2272. if (panelRight < -newLeft + $(window).width()) {
  2273. $m.animate({ 'left': (-$(this).position().left + 25) + 'px' }, duration);
  2274. handled = true;
  2275. return false;
  2276. }
  2277. });
  2278. if (!handled) {
  2279. $m.animate({ 'left': '-60px' }, duration);
  2280. }
  2281. }
  2282. }
  2283. function repositionPinsOnScaleChange(data) {
  2284. var $pins = $('#existingPinsOverlay').children();
  2285. for (var i = 0; i < $pins.length; i++) {
  2286. // calculate new position of pin
  2287. const left = parseFloat($($pins[i]).attr('data-x'));
  2288. const top = parseFloat($($pins[i]).attr('data-y'));
  2289. const width = $($pins[i]).width();
  2290. const height = $($pins[i]).height();
  2291. // Get current scale of mainPanelContainer
  2292. // MainPanelContainer scaled without setContentScale message
  2293. var scale = $('#mainPanelContainer').css('transform');
  2294. scale = (scale == "none") ? 1 : Number(scale.substring(scale.indexOf('(') + 1, scale.indexOf(',')));
  2295. const scaledLeft = (left * scale) - (width / 2);
  2296. const scaledTop = (top * scale) - (height / 2);
  2297. $($pins[i]).css('left', scaledLeft + 'px');
  2298. $($pins[i]).css('top', scaledTop + 'px');
  2299. }
  2300. // Distance from left of project content to origin (used for pins positioning when on a centered page in Scale to Fit mode)
  2301. if (typeof data.contentOriginOffset !== "undefined") contentLeftOfOriginOffset = data.contentOriginOffset;
  2302. }
  2303. function messageCenter_message(message, data) {
  2304. if (message == 'expandFrame') expand();
  2305. else if (message == 'getCollapseFrameOnLoad' && $axure.player.settings.startCollapsed && !MOBILE_DEVICE) $axure.messageCenter.postMessage('collapseFrameOnLoad');
  2306. else if (message == 'tripleClick') {
  2307. if ($axure.player.isMobileMode() || MOBILE_DEVICE) expand();
  2308. } else if (message == 'setContentScale') {
  2309. var resultScale = data.scaleN;
  2310. if (data.clipToView) {
  2311. var scaleVal = $('.vpScaleOption').find('.selectedRadioButton').parent().attr('val');
  2312. if (scaleVal == '2' || (!MOBILE_DEVICE && scaleVal == '0')) {
  2313. var scaleN = $('#mainPanel').width() / data.viewportWidth;
  2314. var hScaleN = ($('#mainPanel').height()) / data.viewportHeight;
  2315. if (hScaleN < scaleN) scaleN = hScaleN;
  2316. if (scaleVal == '0') scaleN = Math.min(1, scaleN);
  2317. resultScale = scaleN;
  2318. var scale = 'scale(' + scaleN + ')';
  2319. $('#mainPanelContainer').css({
  2320. 'transform': scale,
  2321. 'transformOrigin': ''
  2322. });
  2323. $('#mainFrame').height(data.mainFrameHeight);
  2324. } else {
  2325. var scale = 'scale(' + data.scaleN + ')';
  2326. $('#mainPanelContainer').css({
  2327. 'transform': scale,
  2328. 'transformOrigin': Number($('#mainPanelContainer').css('width').replace('px', '')) / 2 + 'px 0px',
  2329. });
  2330. var mainPanelHeight = Number($('#mainPanel').css('height').replace('px', ''));
  2331. var mainPanelContainerHeight = Number($('#mainPanelContainer').css('height').replace('px', ''));
  2332. var height = (mainPanelHeight / data.scaleN > mainPanelContainerHeight ? mainPanelContainerHeight : mainPanelHeight / data.scaleN);
  2333. var y = (mainPanelHeight - (mainPanelHeight > mainPanelContainerHeight * data.scaleN ? mainPanelContainerHeight * data.scaleN : mainPanelHeight)) / 2;
  2334. $('#mainPanelContainer').css("top", y);
  2335. height += 'px';
  2336. $('#clipFrameScroll').height(height);
  2337. $('#mainFrame').height(height);
  2338. var mainPanelWidth = Number($('#mainPanel').css('width').replace('px', ''));
  2339. var mainPanelContainerWidth = Number($('#mainPanelContainer').css('width').replace('px', ''));
  2340. var width = mainPanelWidth / data.scaleN > mainPanelContainerWidth ? mainPanelContainerWidth : mainPanelWidth / data.scaleN;
  2341. var x = (mainPanelContainerWidth - (mainPanelWidth / data.scaleN > mainPanelContainerWidth ? mainPanelContainerWidth : mainPanelWidth / data.scaleN)) / 2;
  2342. $('#mainPanelContainer').css("left", x* data.scaleN);
  2343. width += 'px';
  2344. $('#clipFrameScroll').width(width);
  2345. $('#mainFrame').width(width);
  2346. }
  2347. } else {
  2348. if (data.scaleN != 1) {
  2349. var scale = 'scale(' + data.scaleN + ')';
  2350. var width = 100 / data.scaleN + '%';
  2351. var height = Number($('#mainPanelContainer').css('height').replace('px', '')) / data.scaleN + 'px';
  2352. $('#mainPanelContainer').css({
  2353. 'transform': scale,
  2354. 'transformOrigin': '0px 0px',
  2355. 'width': width,
  2356. 'height': height
  2357. });
  2358. $('#clipFrameScroll').height(height);
  2359. $('#mainFrame').height(height);
  2360. } else {
  2361. $('#mainFrame').height(data.mainFrameHeight);
  2362. $('#mainPanelContainer').width('100%');
  2363. }
  2364. }
  2365. var scaleValue = Math.round(resultScale * 100, 0);
  2366. var scaleValueText = scaleValue + "%";
  2367. if (forcePanZoomDisabled) {
  2368. scaleValueText = 'Scale';
  2369. } else {
  2370. getIframeHtml().attr("zoom", scaleValue);
  2371. $axure.messageCenter.postMessage("cloud_SetPageScale", { scale: resultScale });
  2372. }
  2373. $("#scaleValue").text(scaleValueText);
  2374. repositionPinsOnScaleChange(data);
  2375. repositionClippingBoundsScroll();
  2376. // Fix for edge not redrawing content after scale change
  2377. if ($axure.browser.isEdge) {
  2378. newHeight = window.innerHeight - ((!isMobileMode() && $('#topPanel').is(':visible')) ? $('#topPanel').height() : 0);
  2379. newWidth = $(window).width();
  2380. $('#outerContainer').height(newHeight).width(newWidth);
  2381. $('#mainPanel').height(newHeight);
  2382. $('#clippingBounds').height(newHeight);
  2383. }
  2384. }
  2385. }
  2386. function loadVariablesFromUrl(removeVarFromUrl) {
  2387. let originalQueryValues = window.location.href.substr(window.location.href.indexOf('?')) || '';
  2388. let variables = {};
  2389. const query = (originalQueryValues.split(GLOBAL_VAR_NAME)[1] || '');
  2390. if (query.length > 0) {
  2391. $axure.utils.parseGlobalVars(query, function (varName, varValue) {
  2392. variables[varName] = varValue;
  2393. });
  2394. if (removeVarFromUrl) {
  2395. originalQueryValues = originalQueryValues.replace(GLOBAL_VAR_NAME, "").replace(query, "");
  2396. replaceHash(originalQueryValues);
  2397. }
  2398. }
  2399. return variables;
  2400. }
  2401. function getInitialUrl() {
  2402. var shortId = getHashStringVar(PAGE_ID_NAME);
  2403. var foundById = [];
  2404. if (shortId.length > 0) {
  2405. getPageUrlsById(shortId, foundById, undefined);
  2406. if (foundById.length == 1) return foundById[0];
  2407. }
  2408. var pageName = getHashStringVar(PAGE_URL_NAME);
  2409. if (pageName.length > 0) return pageName + ".html";
  2410. else {
  2411. if (foundById.length > 0) return foundById[0];
  2412. var url = getFirstPageUrl($axure.document.sitemap.rootNodes);
  2413. return (url ? url : "about:blank");
  2414. }
  2415. }
  2416. var getPageUrlsById = $axure.player.getPageUrlsById = function (packageId, foundById, nodes) {
  2417. if (!nodes) nodes = $axure.document.sitemap.rootNodes;
  2418. for (var i = 0; i < nodes.length; i++) {
  2419. var node = nodes[i];
  2420. if (node.id == packageId) foundById.push(node.url);
  2421. var hasChildren = (node.children && node.children.length > 0);
  2422. if (hasChildren) {
  2423. getPageUrlsById(packageId, foundById, node.children);
  2424. }
  2425. }
  2426. }
  2427. var getPageIdByUrl = $axure.player.getPageIdByUrl = function(url, nodes) {
  2428. if (!nodes) nodes = $axure.document.sitemap.rootNodes;
  2429. for (var i = 0; i < nodes.length; i++) {
  2430. var node = nodes[i];
  2431. if (node.url == url) return node.id;
  2432. else {
  2433. var hasChildren = (node.children && node.children.length > 0);
  2434. if (hasChildren) {
  2435. var id = getPageIdByUrl(url, node.children);
  2436. if (id) return id;
  2437. }
  2438. }
  2439. }
  2440. return null;
  2441. }
  2442. function getFirstPageUrl(nodes) {
  2443. for (var i = 0; i < nodes.length; i++) {
  2444. var node = nodes[i];
  2445. if (node.url) return node.url;
  2446. else {
  2447. var hasChildren = (node.children && node.children.length > 0);
  2448. if (hasChildren) {
  2449. var url = getFirstPageUrl(node.children);
  2450. if (url) return url;
  2451. }
  2452. }
  2453. }
  2454. return null;
  2455. }
  2456. function closePlayer() {
  2457. if ($axure.page.location) window.location.href = $axure.page.location;
  2458. else {
  2459. var pageFile = getInitialUrl();
  2460. var currentLocation = window.location.toString();
  2461. window.location.href = currentLocation.substr(0, currentLocation.lastIndexOf("/") + 1) + pageFile;
  2462. }
  2463. }
  2464. function replaceHash(newQuery) {
  2465. var currentLocWithoutQuery = window.location.toString().split('?')[0];
  2466. //We use replace so that every hash change doesn't get appended to the history stack.
  2467. //We use replaceState in browsers that support it, else replace the location
  2468. if (typeof window.history.replaceState != 'undefined') {
  2469. try {
  2470. //Chrome 45 (Version 45.0.2454.85 m) started throwing an error here when generated locally (this only happens with sitemap open) which broke all interactions.
  2471. //try catch breaks the url adjusting nicely when the sitemap is open, but all interactions and forward and back buttons work.
  2472. //Uncaught SecurityError: Failed to execute 'replaceState' on 'History': A history state object with URL 'file:///C:/Users/Ian/Documents/Axure/HTML/Untitled/start.html#p=home' cannot be created in a document with origin 'null'.
  2473. window.history.replaceState(null, null, currentLocWithoutQuery + newQuery);
  2474. } catch (ex) { }
  2475. } else {
  2476. window.location.replace(currentLocWithoutQuery + newQuery);
  2477. }
  2478. }
  2479. function collapse() {
  2480. if (IOS) {
  2481. $('body').off('touchstart');
  2482. $('body').off('touchend');
  2483. }
  2484. if ($axure.player.isMobileMode()) {
  2485. $('#mHideSidebar').hide();
  2486. $('#nativeAppControlFrame').hide();
  2487. $('#mobileBrowserControlFrame').hide();
  2488. } else {
  2489. $axure.player.deleteVarFromCurrentUrlHash('g');
  2490. $axure.player.setVarInCurrentUrlHash('c', 1);
  2491. if (!MOBILE_DEVICE) $('#maximizePanelContainer').show();
  2492. lastLeftPanelWidth = $('.leftPanel').width();
  2493. lastRightPanelWidth = $('.rightPanel').width();
  2494. $('.leftPanel').hide();
  2495. $('.rightPanel').hide();
  2496. $('#topPanel').hide();
  2497. $('.splitbar').hide();
  2498. $('#mainPanel').width($(window).width());
  2499. $('#clippingBounds').width($(window).width());
  2500. $('#clippingBounds').css('left', '0px');
  2501. $(window).resize();
  2502. $(document).trigger('sidebarCollapse');
  2503. $('#maximizeButton').addClass('rotated');
  2504. }
  2505. }
  2506. function expand() {
  2507. if ($axure.player.isMobileMode()) {
  2508. $('#mHideSidebar').show();
  2509. $('#mobileControlFrameContainer').show();
  2510. $axure.utils.isShareApp() ? $('#nativeAppControlFrame').show() : $('#mobileBrowserControlFrame').show();
  2511. } else {
  2512. $minimizeContainer = $('#interfaceControlFrameMinimizeContainer');
  2513. $minimizeContainer.removeClass('collapseHovered');
  2514. $axure.player.deleteVarFromCurrentUrlHash('c');
  2515. $('#maximizeButton').removeClass('rotated');
  2516. $('#maximizePanelContainer').hide();
  2517. $axure.player.restorePlugins();
  2518. $('#topPanel').show();
  2519. $(window).resize();
  2520. $(document).trigger('sidebarExpanded');
  2521. }
  2522. }
  2523. function mainFrame_onload() {
  2524. if ($axure.page.pageName) document.title = $axure.page.pageName;
  2525. }
  2526. function getQueryString(query) {
  2527. var qstring = self.location.href.split("?");
  2528. if (qstring.length < 2) return "";
  2529. return GetParameter(qstring, query);
  2530. }
  2531. function GetParameter(qstring, query) {
  2532. var prms = qstring[1].split("&");
  2533. var frmelements = new Array();
  2534. var currprmeter, querystr = "";
  2535. for (var i = 0; i < prms.length; i++) {
  2536. currprmeter = prms[i].split("=");
  2537. frmelements[i] = new Array();
  2538. frmelements[i][0] = currprmeter[0];
  2539. frmelements[i][1] = currprmeter[1];
  2540. }
  2541. for (j = 0; j < frmelements.length; j++) {
  2542. if (frmelements[j][0].toLowerCase() == query.toLowerCase()) {
  2543. querystr = frmelements[j][1];
  2544. break;
  2545. }
  2546. }
  2547. return querystr;
  2548. }
  2549. $axure.player.setVarInCurrentUrlHash = function (varName, varVal) {
  2550. var newQuery = $axure.utils.setHashStringVar(window.location.search, varName, varVal);
  2551. if (newQuery != null) {
  2552. replaceHash(newQuery);
  2553. }
  2554. }
  2555. function deleteHashStringVar(currentQuery, varName) {
  2556. var varWithEqual = varName + '=';
  2557. var pageIndex = currentQuery.indexOf('?' + varWithEqual);
  2558. if (pageIndex == -1) pageIndex = currentQuery.indexOf('&' + varWithEqual);
  2559. if (pageIndex != -1) {
  2560. var newQuery = currentQuery.substring(0, pageIndex);
  2561. var ampIndex = currentQuery.indexOf('&', pageIndex + 1);
  2562. //IF begin of string....if none blank, ELSE # instead of & and rest
  2563. //IF in string....prefix + if none blank, ELSE &-rest
  2564. if (newQuery == '') { //beginning of string
  2565. newQuery = ampIndex != -1 ? '?' + currentQuery.substring(ampIndex + 1) : '';
  2566. } else { //somewhere in the middle
  2567. newQuery = newQuery + (ampIndex != -1 ? currentQuery.substring(ampIndex) : '');
  2568. }
  2569. return newQuery;
  2570. }
  2571. return null;
  2572. }
  2573. $axure.player.deleteVarFromCurrentUrlHash = function (varName) {
  2574. var newQuery = deleteHashStringVar(window.location.search, varName);
  2575. if (newQuery != null) {
  2576. replaceHash(newQuery);
  2577. }
  2578. };
  2579. function setUpController() {
  2580. //$axure.utils = _axUtils;
  2581. var _page = {};
  2582. $axure.page = _page;
  2583. $axure.utils.makeBindable(_page, ['load']);
  2584. var _player = function () {
  2585. };
  2586. $axure.player = _player;
  2587. //-----------------------------------------
  2588. //Global Var array, getLinkUrl function and setGlobalVar listener are
  2589. //for use in setting global vars in page url string when clicking a
  2590. //page in the sitemap
  2591. //NEW: this is now also used when navigating to a new window/popup,
  2592. //if there are global variables on the urls
  2593. //-----------------------------------------
  2594. var _globalVars = loadVariablesFromUrl(true);
  2595. var _getLinkUrl = function (baseUrl) {
  2596. var toAdd = '';
  2597. for (var globalVarName in _globalVars) {
  2598. var val = _globalVars[globalVarName];
  2599. if (val != null) {
  2600. if (toAdd.length > 0) toAdd += '&';
  2601. toAdd += globalVarName + '=' + encodeURIComponent(val);
  2602. }
  2603. }
  2604. return toAdd.length > 0 ? baseUrl + '?' + toAdd + "&CSUM=1" : baseUrl;
  2605. };
  2606. $axure.getLinkUrlWithVars = _getLinkUrl;
  2607. $axure.messageCenter.addMessageListener(function (message, data) {
  2608. if (message == 'setGlobalVar') {
  2609. _globalVars[data.globalVarName] = data.globalVarValue;
  2610. }
  2611. });
  2612. $axure.messageCenter.addStateListener('page.data', function (key, value) {
  2613. for (var subKey in value) {
  2614. _page[subKey] = value[subKey];
  2615. }
  2616. $axure.page.triggerEvent('load');
  2617. });
  2618. // ---------------------------------------------
  2619. // Navigates the main frame (setting the currently visible page). If the link is relative,
  2620. // this method should test if it is actually a axure rp page being loaded and properly set
  2621. // up all the controller for the page if it is
  2622. // ---------------------------------------------
  2623. _page.navigate = function (url, includeVariables) {
  2624. var mainFrame = document.getElementById("mainFrame");
  2625. //var mainFrame = window.parent.mainFrame;
  2626. // if this is a relative url...
  2627. var urlToLoad;
  2628. if (url.indexOf(':') < 0 || url[0] == '/') {
  2629. var winHref = window.location.href;
  2630. var page = winHref.substring(0, winHref.lastIndexOf('/') + 1) + url;
  2631. urlToLoad = page;
  2632. } else {
  2633. urlToLoad = url;
  2634. }
  2635. if (!includeVariables) {
  2636. mainFrame.contentWindow.location.href = urlToLoad;
  2637. return;
  2638. }
  2639. var urlWithVars = $axure.getLinkUrlWithVars(urlToLoad);
  2640. mainFrame.contentWindow.location.href = urlWithVars;
  2641. // update the URL string immediately when the page changes so user doesn't have to wait for the page to load. RP-2895
  2642. $axure.player.setVarInCurrentUrlHash(PAGE_ID_NAME, getPageIdByUrl(url));
  2643. $axure.player.setVarInCurrentUrlHash(PAGE_URL_NAME, url.substring(0, url.lastIndexOf('.html')));
  2644. };
  2645. var pluginIds = [];
  2646. var plugins = {};
  2647. var currentVisibleHostId = {};
  2648. // ---------------------------------------------
  2649. // Adds a tool box frame from a url to the interface. This is useful for loading plugins
  2650. // settings is an object that supports the following properties:
  2651. // - id : the id of the element for the plugin
  2652. // - context : the context to create the plugin host for
  2653. // - title : the user-visible caption for the plugin
  2654. // ---------------------------------------------
  2655. _player.createPluginHost = function (settings) {
  2656. if (!settings.context || !(settings.context === 'project' || settings.context === 'inspect')) {
  2657. //throw ('unknown context type');
  2658. return false;
  2659. }
  2660. if (settings.id == 'feedbackHost')
  2661. $('#overflowMenuContainer').prepend('<div id="showCommentsOption" class="showOption" style="order: 2"><div class="overflowOptionCheckbox"></div>Show Comments</div>');
  2662. if (!settings.id) throw ('each plugin host needs an id');
  2663. if (typeof PREVIEW_INFO === 'undefined') {
  2664. // Share-Hosted Prototype
  2665. if (settings.id == 'debugHost') { return false; }
  2666. if (settings.id == 'handoffHost') { $('#handoffControlFrameHeaderContainer').show(); }
  2667. } else {
  2668. // Preview Mode
  2669. if (settings.id == 'handoffHost') { return false; }
  2670. }
  2671. pluginIds[pluginIds.length] = settings.id;
  2672. plugins[settings.id] = settings;
  2673. var hostContainerId = settings.context + 'ControlFrameHostContainer';
  2674. hostContainerId = _player.isMobileMode() ? 'mHideSidebar' : 'outerContainer';
  2675. var panelClass = 'rightPanel';
  2676. var host;
  2677. if (settings.context == 'project') {
  2678. panelClass = 'leftPanel';
  2679. if (_player.isMobileMode() && $('#' + hostContainerId).find('#projectOptionsHost').length > 0) {
  2680. host = $('<div id="' + settings.id + '" class="' + panelClass + '"></div>')
  2681. .insertAfter('#projectOptionsHost');
  2682. } else {
  2683. host = $('<div id="' + settings.id + '" class="' + panelClass + '"></div>')
  2684. .prependTo('#' + hostContainerId);
  2685. }
  2686. } else {
  2687. if (!$('#separatorContainer').hasClass('hasLeft')) $('#separatorContainer').addClass('hasLeft');
  2688. var closeButtonContainer = $('<div class="closeButtonContainer"></div>');
  2689. var closeButton = $('<button>&#10006;</button>');
  2690. closeButton.on('click', function () {
  2691. $axure.player.pluginClose(settings.id);
  2692. });
  2693. closeButton.appendTo(closeButtonContainer);
  2694. host = $('<div id="' + settings.id + '" class="' + panelClass + '"></div>');
  2695. closeButtonContainer.appendTo(host);
  2696. host.appendTo('#' + hostContainerId);
  2697. }
  2698. $(('#' + settings.id)).click(function (e) { e.stopPropagation(); });
  2699. var controlContainerId = getControlContainerId(settings.id);
  2700. if (!_player.isMobileMode()) host.hide();
  2701. else _player.updatePlugins();
  2702. // TODO: border radius in ie and edge causes image to be blurry (for now, just remove border-radius)
  2703. var style = (IE || $axure.browser.isEdge) ? '" style="border-radius: 0': '';
  2704. var headerLink = $('<a pluginId="' + settings.id + '" title="' + settings.title + style + '" >' + (settings.context === 'inspect' ? ('<span>' + '</span>'): '&nbsp;') + '</a>');
  2705. headerLink.mousedown($axure.utils.curry(interfaceControlHeaderButton_click, settings.id)).wrap('<li id="' + settings.id + 'Btn"' + (settings.id == "handoffHost" ? ' style="display: none"' : '') + '>');
  2706. headerLink.parent().appendTo('#' + controlContainerId);
  2707. if (_player.isMobileMode()) $axure.player.resizeContent();
  2708. $(document).trigger('pluginCreated', [settings.gid]);
  2709. };
  2710. var getControlContainerId = function (id) {
  2711. return plugins[id].context + 'ControlFrameHeader';
  2712. }
  2713. var getVisiblePlugins = function () {
  2714. var ids = '';
  2715. for (var id in plugins) {
  2716. var context = plugins[id].context;
  2717. if (currentVisibleHostId[context] == id) {
  2718. ids += plugins[id].gid;
  2719. }
  2720. }
  2721. return ids;
  2722. }
  2723. _player.pluginVisibleChanged = function(hostId, visible) {
  2724. if (plugins[hostId]) {
  2725. $axure.messageCenter.postMessage('pluginVisibleChanged', { id: hostId, gid: plugins[hostId].gid, visible: visible });
  2726. }
  2727. }
  2728. var interfaceControlHeaderButton_click = function (id) {
  2729. if (_player.isAnimating) { return; }
  2730. $axure.player.closePopup();
  2731. var controlContainerId = getControlContainerId(id);
  2732. var context = plugins[id].context;
  2733. var clickedPlugin = $('#' + controlContainerId + ' a[pluginId=' + id + ']');
  2734. if (currentVisibleHostId[context] == id) {
  2735. clickedPlugin.removeClass('selected');
  2736. if (id == "sitemapHost") { $('#sitemapControlFrameContainer').removeClass('selected'); }
  2737. currentVisibleHostId[context] = -1;
  2738. _player.collapseToBar(context, id);
  2739. $(document).trigger('pluginShown', [getVisiblePlugins()]);
  2740. } else {
  2741. $('#' + controlContainerId + ' a').removeClass('selected');
  2742. clickedPlugin.addClass('selected');
  2743. if (id == "sitemapHost") { $('#sitemapControlFrameContainer').addClass('selected'); }
  2744. $('#' + currentVisibleHostId[context]).hide();
  2745. $axure.player.pluginVisibleChanged(currentVisibleHostId[context], false);
  2746. currentVisibleHostId[context] = id;
  2747. _player.expandFromBar(id, context);
  2748. $(document).trigger('pluginShown', [getVisiblePlugins()]);
  2749. $axure.messageCenter.postMessage('openPlugin', id);
  2750. }
  2751. };
  2752. _player.pluginClose = function (id) {
  2753. var controlContainerId = getControlContainerId(id);
  2754. var context = plugins[id].context;
  2755. var clickedPlugin = $('#' + controlContainerId + ' a[pluginId=' + id + ']');
  2756. if (!clickedPlugin.hasClass('selected')) { return; }
  2757. clickedPlugin.removeClass('selected');
  2758. currentVisibleHostId[context] = -1;
  2759. _player.collapseToBar(context, id);
  2760. $(document).trigger('pluginShown', [getVisiblePlugins()]);
  2761. };
  2762. _player.showPlugin = function (gid) {
  2763. for (var id in plugins) {
  2764. if (plugins[id].gid == gid) {
  2765. interfaceControlHeaderButton_click(id);
  2766. break;
  2767. }
  2768. }
  2769. };
  2770. _player.restorePlugins = function () {
  2771. var selectedPluginsCount = 0;
  2772. for (var id in plugins) {
  2773. var clickedPlugin = $('#' + getControlContainerId(id) + ' a[pluginId=' + id + ']');
  2774. if (clickedPlugin.hasClass('selected')) selectedPluginsCount++;
  2775. }
  2776. if ($axure.player.settings.isAxshare && selectedPluginsCount != 0) $('#clippingBoundsScrollContainer').hide();
  2777. var selectedPluginsSeen = 0;
  2778. for (var id in plugins) {
  2779. var controlContainerId = getControlContainerId(id);
  2780. var context = plugins[id].context;
  2781. var clickedPlugin = $('#' + controlContainerId + ' a[pluginId=' + id + ']');
  2782. if (clickedPlugin.hasClass('selected')) {
  2783. //_player.showPlugin(id);
  2784. // TODO: handoffHost would need center inspect icon highlighted and rightFrameIcon set to visible
  2785. //if (id == 'handoffHost') { }
  2786. //$('#' + id).show();
  2787. selectedPluginsSeen++;
  2788. _player.expandFromBar(id, context, selectedPluginsCount == selectedPluginsSeen);
  2789. } else {
  2790. $('#' + id).hide();
  2791. }
  2792. }
  2793. $(document).trigger('pluginShown', [getVisiblePlugins()]);
  2794. };
  2795. _player.navigateToIssue = function (issueId) {
  2796. if (typeof feedback !== 'undefined') {
  2797. feedback.navigateToIssue(issueId);
  2798. }
  2799. };
  2800. _player.isPanZoomEnabled = function () {
  2801. return !forcePanZoomDisabled;
  2802. }
  2803. _player.handleKeyboardEvent = function (eventName) {
  2804. switch (eventName) {
  2805. case 'ctrlOrCmdPlus':
  2806. zoomIn();
  2807. break;
  2808. case 'ctrlOrCmdMinus':
  2809. zoomOut();
  2810. break;
  2811. case 'ctrlOrCmdZero':
  2812. dropScaleAndZoomPage(100);
  2813. break;
  2814. case 'spaceBarDown':
  2815. toggleDragMode(true);
  2816. break;
  2817. case 'spaceBarUp':
  2818. toggleDragMode(false);
  2819. break
  2820. default:
  2821. break;
  2822. }
  2823. }
  2824. }
  2825. $axure.player.hideAllPlayerControllers = function(isVisible) {
  2826. // TOOD: Verify that the containers are set to the right state after re-enabling them
  2827. if(isVisible) {
  2828. $('#topPanel').css('display', '');
  2829. $('#popupContainer').css('display', '');
  2830. $('#maximizePanelContainer').css('display', '');
  2831. $('#mobileControlFrameContainer').css('display', '');
  2832. } else {
  2833. $('#topPanel').hide();
  2834. $('#popupContainer').hide();
  2835. $('#maximizePanelContainer').hide(); // TODO: This needs to have a function where it prevents itself from showing up externally
  2836. $('#mobileControlFrameContainer').hide();
  2837. }
  2838. }
  2839. // TODO: General function to add bezels/overlays if applicable
  2840. $axure.player.addDeviceFraming = function (project, isEdit) {
  2841. // Temporary
  2842. var devices = {
  2843. iPhone8: 0,
  2844. iPhone8Plus: 1,
  2845. iPhoneSE: 2,
  2846. iPhoneX: 3,
  2847. iPad4: 4,
  2848. GalaxyS8: 5,
  2849. Pixel2: 6,
  2850. Pixel2XL: 7,
  2851. Mobile: 8,
  2852. Tablet9: 9,
  2853. Tablet7: 10,
  2854. Custom: 11,
  2855. Web: 12
  2856. };
  2857. // TODO: Need to bring over some platform functionality -> function might not be present
  2858. if (!$axure.player.settings.isExpo || project.Platform.Device === 12) { return; }
  2859. // TODO: Generate html for overlay and bezel containers
  2860. // TODO: Determine if preview player or full prototype player to establish where containers will be stored
  2861. var currDevice = project.Platform.Device;
  2862. var rootPath = '../../Scripts/Expo/StaticContent/resources/images/mobile/';
  2863. var framePath, overlayPath;
  2864. var $overlayParent = $(window.parent.parent.document).find('#previewPlayerDiv');
  2865. $overlayParent = isEdit && $overlayParent.length !== 0 ? $overlayParent : $('#mainPanelContainer');
  2866. $overlayParent.css('overflow', 'visible');
  2867. // TODO: Import enum of Device types -> import via TS definitions. WILL NEED TO REMEMBER THAT WE NEED TO SYNC SERVER AND CLIENT SIDE
  2868. // TODO: Create mapping of required images to device type
  2869. // images will be stored in ../../images/mobile
  2870. // TODO: Manage resizing
  2871. // TODO: Manage pointer clicks
  2872. // TODO: Status bar -> Default or via settings
  2873. // TODO: Establish img paths
  2874. switch (currDevice) {
  2875. case devices.iPhone8:
  2876. case devices.iPhone8Plus:
  2877. framePath = rootPath + 'iphone.svg';
  2878. overlayPath = "";
  2879. break;
  2880. case devices.iPhoneSE:
  2881. break;
  2882. case devices.iPhoneX:
  2883. framePath = "";
  2884. overlayPath = "";
  2885. break;
  2886. case devices.iPad4:
  2887. break;
  2888. case devices.Pixel2:
  2889. break;
  2890. case devices.Pixel2XL:
  2891. break;
  2892. case devices.GalaxyS8:
  2893. break;
  2894. case devices.Mobile:
  2895. case devices.Tablet7:
  2896. case devices.Tablet9:
  2897. case devices.Custom:
  2898. default:
  2899. break;
  2900. }
  2901. // TODO: Append images
  2902. // TODO: Position and initial dimensions
  2903. // TODO: Add resize handlers (?)
  2904. // TODO: Add pointer event handers (?)
  2905. if (framePath != undefined) {
  2906. $overlayParent.prepend(genFrameContainer());
  2907. var $fContainer = $overlayParent.find('#deviceFrameContainer');
  2908. var $frame = $fContainer.find('#deviceFrame');
  2909. $frame.css('background-image', "url('" + framePath + "')");
  2910. $frame.css('height', '');
  2911. $frame.css('width', '');
  2912. $frame.css('top', '');
  2913. $frame.css('left', '');
  2914. if(isEdit) {
  2915. $fContainer.css('z-index', -1);
  2916. }
  2917. }
  2918. if (overlayPath != undefined) {
  2919. // TODO: Update for edit mode
  2920. // $overlayParent.append(genOverlayContainer());
  2921. var $oContainer = $overlayParent.find('#deviceOverlayContainer');
  2922. var $overlay = $oContainer.find('#deviceOverlay');
  2923. $overlay.css('background-image', "url('" + overlayPath + "')");
  2924. }
  2925. }
  2926. function genFrameContainer(bezelPath) {
  2927. var container = [
  2928. '<div id="deviceFrameContainer">',
  2929. ' <div id="deviceFrame">',
  2930. ' </div>',
  2931. '</div>'
  2932. ].join("");
  2933. return container;
  2934. }
  2935. })();