var lensHtmlUtils = { showTabsOrNot: function showTabsOrNot() { const logHdr = 'showTabsOrNot: '; log(logHdr + 'enter'); log(logHdr + 'viewWidth=' + viewWidth); const showTabs = (viewWidth > 375); // if the view is wide enough to show tabs in the lens cards log(logHdr + 'showTabs=' + showTabs); log(logHdr + 'leave'); return showTabs; }, _getHtmlForLensCardWithTabsAsync: async function _getHtmlForLensCardWithTabs(lens, expanded, explicitWidthStr) { // this function returns HTML for a lens card with 4 tabs: // When, How, Examples, Video // // expanded: true if we should create the card in expanded mode // explicitWidthStr: undefined or empty string: do nothing // otherwise, this string is a CSS width value for the lens card div // for example: // 600px // 90% const logHdr = '_getHtmlForLensCardWithTabsAsync: '; log(logHdr + 'enter'); log(logHdr + 'lens name=' + lens.LensName); log(logHdr + 'expanded=' + expanded); log(logHdr + 'explicitWidthStr=' + explicitWidthStr); var widthStr = explicitWidthStr; if (typeof widthStr === "undefined") { widthStr = ''; } if (widthStr === null) widthStr = ''; // lens: a lens DTO // expanded: if true, show the card in expanded mode, with tabs revealed // otherwise, show card in collpased mode, with tabs hidden. // NOTE: we could use // '<h5 class="card-title">' + lens.LensName + '</h5>' // for a large card title at the top of the card var lensId = lens.LensId; log(logHdr + 'lensId=' + lensId); const bookmarked = bookmarkStorageUtils.isLensBookmarked(lensId); log(logHdr + 'bookmarked=' + bookmarked); const descrHtml = lens.DescriptionHtml; log(logHdr + 'descrHtml=' + descrHtml); var styleStr = ''; if (widthStr.length > 0) { styleStr = ' style="width: ' + widthStr + '" '; } var aWhen = ''; var aHow = ''; var aExamples = ''; var aVideo = ''; // clear var divWhen = ''; var divHow = ''; var divExamples = ''; var divVideo = ''; // clear const selTab = selectedTabUtils.getSelectedTab(lensId); // get the name of the selected tab, or empty string if none selected log(logHdr + 'selTab=' + selTab); switch (selTab) { case '': aWhen = 'active'; divWhen = 'active show'; break; case 'when': aWhen = 'active'; divWhen = 'active show'; break; case 'how': aHow = 'active'; divHow = 'active show'; break; case 'examples': aExamples = 'active'; divExamples = 'active show'; break; case 'video': aVideo = 'active'; divVideo = 'active show'; break; } const cardId = elemIdUtils.getElemId(lensId, elemIdUtils.CARD_PREFIX, undefined); // get the id of the card div // this div itself doesn't show/hide, so the third parameter is undefined var lensHtml = '<div id="' + cardId + '" class="card"' + styleStr + '>'; const cardHdrId = elemIdUtils.getElemId(lensId, elemIdUtils.CARD_HEADER_PREFIX, undefined); lensHtml += '<div id="' + cardHdrId + '" class="card-hdr">'; const nameSpanId = elemIdUtils.getElemId(lensId, elemIdUtils.SPAN_LENS_NAME_PREFIX, undefined); lensHtml += '<span id="' + nameSpanId + '" class="card-hdr-lens-name">' + lens.LensName + '</span>'; const btnId = elemIdUtils.getElemId(lensId, elemIdUtils.BUTTON_CLOSE_CARD_HEADER_PREFIX, expanded); lensHtml += '<button id="' + btnId + '" class="btn card-hdr-close-btn float-right" type="button" aria-label="Close"><span class="card-hdr-close-x" aria-hidden="true">×</span></button>'; const showBk = bookmarkUIUtils.showBookmarks(); // should we show bookmark icons? log('getHtmlForLensCard: showBk=' + showBk); if (showBk) { // if we should show bookmarks var wImgPath = ''; var bkClass = ''; if (viewWide) { // if the user is using a wider screen, we show smaller bookmarks bkClass = 'bk-sm'; if (bookmarked) { // if the lens is bookmarked wImgPath = urlUtils.getUrl('/images/bookmarkfilled-sm.png'); } else { // if the lens is not bookmarked wImgPath = urlUtils.getUrl('/images/bookmarkempty-sm.png'); } } else { // if the user is on a smaller screen, we show larger bookmarks bkClass = 'bk-lg'; if (bookmarked) { // if the lens is bookmarked wImgPath = urlUtils.getUrl('/images/bookmarkfilled.png'); } else { // if the lens is not bookmarked wImgPath = urlUtils.getUrl('/images/bookmarkempty.png'); } } const imgBkId = elemIdUtils.getElemId(lensId, elemIdUtils.IMAGE_BOOKMARK_PREFIX, expanded); lensHtml += '<img id="' + imgBkId + '" class="empty-bookmark ' + bkClass + '" src="' + wImgPath + '" />'; // add the bookmark image to the lens markup } lensHtml += '</div>'; lensHtml += '<div class="card-body">'; const spanId = elemIdUtils.getElemId(lensId, elemIdUtils.SPAN_LENS_NAME_PREFIX, undefined); const pDescr = descrHtml.replace('<span ', '<span id="' + spanId + '" '); // store an HTML element id in the span element in the description const cardDescrId = elemIdUtils.getElemId(lensId, elemIdUtils.CARD_DESCR_PREFIX, undefined); lensHtml += '<p id="' + cardDescrId + '" class="card-text">' + pDescr; lensHtml += ' '; var moreStyle = ''; var lessStyle = ''; if (expanded) { // if the caller wants the card created in expanded mode moreStyle = ' style="display: none;"'; // mode is already more, so hide the more link lessStyle = ''; } else { // if the caller wants the card created in collapsed mode moreStyle = ''; lessStyle = ' style="display: none;"'; // mode is already less, so hide the less link } const spanMoreId = elemIdUtils.getElemId(lensId, elemIdUtils.SPAN_MORE_PREFIX, undefined); const spanLessId = elemIdUtils.getElemId(lensId, elemIdUtils.SPAN_LESS_PREFIX, undefined); // the "more..." link which allows the user to expand the card // NOTE: s-more-tabs is the class for "more" links in cards with tabs // NOTE: s-less-tabs is the class for "less" links in cards with tabs lensHtml += '<span id="' + spanMoreId + '" class="s-more-tabs"' + moreStyle + ' > '; lensHtml += 'more...'; lensHtml += '</span>'; // the "less..." link which allows the user to collapse the card lensHtml += '<span id="' + spanLessId + '" class="s-less-tabs"' + lessStyle + ' > '; lensHtml += 'less...'; lensHtml += '</span>'; lensHtml += '</p>'; var displayStyle = 'display: none;'; if (expanded) { // if the caller wants the tabs displayed displayStyle = 'display: block;'; } const collapseId = elemIdUtils.getElemId(lensId, elemIdUtils.COLLAPSE_TABS_PREFIX, undefined); // while the tabs do show/hide, there is a max of one set of tabs per card // so the expanded flag is undefined lensHtml += '<div id="' + collapseId + '" class="collapse-tabs" style="' + displayStyle + '">'; const cardTabId = elemIdUtils.getElemId(lensId, elemIdUtils.LIST_PREFIX, expanded); // this code uses Bootstrap and <ul>/<li> elements to display the tabs lensHtml += '<ul class="nav nav-tabs" id="' + cardTabId + '" role="tablist">'; const liWhenId = elemIdUtils.getElemId(lensId, elemIdUtils.LIST_ITEM_WHEN_TAB_PREFIX, expanded); const liHowId = elemIdUtils.getElemId(lensId, elemIdUtils.LIST_ITEM_HOW_TAB_PREFIX, expanded); const liExId = elemIdUtils.getElemId(lensId, elemIdUtils.LIST_ITEM_EXAMPLES_TAB_PREFIX, expanded); const liVideoId = elemIdUtils.getElemId(lensId, elemIdUtils.LIST_ITEM_VIDEO_TAB_PREFIX, expanded); const whenId = elemIdUtils.getElemId(lensId, elemIdUtils.TAB_PANE_WHEN_PREFIX, expanded); const howId = elemIdUtils.getElemId(lensId, elemIdUtils.TAB_PANE_HOW_PREFIX, expanded); const examplesId = elemIdUtils.getElemId(lensId, elemIdUtils.TAB_PANE_EXAMPLES_PREFIX, expanded); const videoId = elemIdUtils.getElemId(lensId, elemIdUtils.TAB_PANE_VIDEO_PREFIX, undefined); // undefined => there is only one of these elements for each lens // create unique ids for the nav-link elements lensHtml += '<li id="' + liWhenId + '" class="nav-item card-tab-caption when-tab">'; lensHtml += '<a class="nav-link ' + aWhen + '" id="' + whenId + '-tab" data-toggle="tab" href="#' + whenId + '" role="tab" aria-controls="' + whenId + '" aria-selected="true">When</a>'; lensHtml += '</li>'; lensHtml += '<li id="' + liHowId + '" class="nav-item card-tab-caption how-tab">'; lensHtml += '<a class="nav-link ' + aHow + '" id="' + howId + '-tab" data-toggle="tab" href="#' + howId + '" role="tab" aria-controls="' + howId + '" aria-selected="false">How</a>'; lensHtml += '</li>'; lensHtml += '<li id="' + liExId + '" class="nav-item card-tab-caption examples-tab">'; lensHtml += '<a class="nav-link ' + aExamples + '" id="' + examplesId + '-tab" data-toggle="tab" href="#' + examplesId + '" role="tab" aria-controls="' + examplesId + '" aria-selected="false">Examples</a>'; lensHtml += '</li>'; lensHtml += '<li id="' + liVideoId + '" class="nav-item card-tab-caption video-tab">'; lensHtml += '<a class="nav-link ' + aVideo + '" id="' + videoId + '-tab" data-toggle="tab" href="#' + videoId + '" role="tab" aria-controls="' + videoId + '" aria-selected="false">Video</a>'; lensHtml += '</li>'; lensHtml += '</ul>'; const tcId = elemIdUtils.getElemId(lensId, elemIdUtils.CARD_TAB_CONTENT_PREFIX, undefined); lensHtml += '<div class="tab-content" id="' + tcId + '">'; lensHtml += '<div class="tab-pane fade card-text-when ' + divWhen + '" id="' + whenId + '" role="tabpanel" aria-labelledby="when-tab">' + lens.WhenToUse + '</div>'; lensHtml += '<div class="tab-pane fade card-text-how ' + divHow + '" id="' + howId + '" role="tabpanel" aria-labelledby="how-tab">' + lens.HowToUse + '</div>'; const lensExamples = lensExampleUtils.getExamplesForLens(lensId); const exCount = lensExamples.length; log(logHdr + 'exCount=' + exCount); var examplesHtml = ''; for (var zIndex = 0; zIndex < exCount; zIndex++) { // once for each example var lensExample = lensExamples[zIndex]; var exTitle = lensExample.Name; var exText = lensExample.Text; var exTitleHtml = '<div class="example-title">' + exTitle + '</div>' var exTextHtml = '<div class="example-text">' + exText + '</div>' examplesHtml += exTitleHtml; examplesHtml += exTextHtml; // append example title and text to the HTML } lensHtml += '<div class="tab-pane fade lens-examples ' + divExamples + '" id="' + examplesId + '" role="tabpanel" aria-labelledby="examples-tab">' + examplesHtml + '</div>'; lensHtml += '<div class="tab-pane fade ' + divVideo + '" id="' + videoId + '" role="tabpanel" aria-labelledby="video-tab">'; // this is where we append the video element // TAB_PANE_VIDEO_PREFIX if (aVideo.length > 0) { // if the Video tab will be selected, we need to add the video element now const videoType = videoUtils.getVideoType(lensId); // what is the video type for this lens? log(logHdr + 'videoType=' + videoType); log(logHdr + 'we need to add the video element'); const videoElemSize = videoUtils.getVideoElemSize(viewWidth, viewHeight); // get the desired size of the video element given the view dimensions const videoElemWidth = videoElemSize.width; const videoElemHeight = videoElemSize.height; log(logHdr + 'viewWidth=' + viewWidth); log(logHdr + 'viewHeight=' + viewHeight); log(logHdr + 'video element size is ' + videoElemWidth + ' x ' + videoElemHeight); var videoHtml = ''; if (videoType === videoUtils.VIDEO_TYPE_BLOB) { // if the video for the lens is a video element const blubUrl = videoUtils.getVideoUrl(lensId); // get the URL of the video blob videoHTML = videoUtils.getVideoHtml_video(lensId, videoElemWidth, videoElemHeight, blubUrl); // get the html for the video element log(logHdr + 'computed the HTML for the video element'); } else { // if the video for the lens is an iFrame const iFrameSourceUrl = videoUtils.getIFrameUrl(lensId); // get the URL for the iFrame source log(logHdr + 'iFrameSourceUrl=' + iFrameSourceUrl); videoHTML = videoUtils.getVideoHtml_iFrame(lensId, videoElemWidth, videoElemHeight, iFrameSourceUrl); // get the html for the iFrame element log(logHdr + 'computed the HTML for the iFrame video element'); } log('videoHTML=' + videoHTML); lensHtml += videoHTML; // add it to the markup // NOTE: code elsewhere will have to subscribe to video events for this video element } lensHtml += '</div> '; lensHtml += '</div>'; // add markup for the tabs lensHtml += '</div>'; // card-body lensHtml += '</div>'; // card-hdr lensHtml += '</div>'; // card log(logHdr + ' leave'); return lensHtml; }, _getHtmlForLensCardNoTabs: function _getHtmlForLensCardNoTabs(lens, videoBtn, explicitWidthStr) { // this function returns HTML for a lens card without tabs. // instead of tabs, the HTML returned by this function contains 4 sections: // When, How, Examples, Video // separated by section headers, which are simply text captions. // // lens: a lens DTO // videoBtn: if true, add a button the user can click to load the video. // if false, add the video element // explicitWidthStr: undefined or empty string: do nothing // otherwise, this string is a CSS width value for the lens card div // for example: // 600px // 90% // NOTE: as of 2/27/20 we hard-code to not show the Load Video button // All videos are loaded. // We plan on moving to all streaming (Vimeo) videos soon. const logHeader = '_getHtmlForLensCardNoTabs: '; log(logHeader + 'enter'); log(logHeader + 'lens name=' + lens.LensName); log(logHeader + 'videoBtn=' + videoBtn + ' (IGNORED for now)'); log(logHeader + 'explicitWidthStr=' + explicitWidthStr); var widthStr = explicitWidthStr; if (typeof widthStr === "undefined") { widthStr = ''; } if (widthStr === null) widthStr = ''; var lensId = lens.LensId; log(logHeader + 'lensId=' + lensId); const bookmarked = bookmarkStorageUtils.isLensBookmarked(lensId); log(logHeader + 'bookmarked=' + bookmarked); const descrHtml = lens.DescriptionHtml; log(logHeader + 'descrHtml=' + descrHtml); var styleStr = ''; if (widthStr.length > 0) { styleStr = ' style="width: ' + widthStr + '" '; } const cardId = elemIdUtils.getElemId(lensId, elemIdUtils.CARD_PREFIX, undefined); // get an id for the card // don't pass the expanded flag // the card has expandable contents but the card div itself is not expandable var lensHtml = '<div id="' + cardId + '" class="card"' + styleStr + '>'; const cardHdrId = elemIdUtils.getElemId(lensId, elemIdUtils.CARD_HEADER_PREFIX, undefined); lensHtml += '<div id="' + cardHdrId + '" class="card-hdr">'; const nameSpanId = elemIdUtils.getElemId(lensId, elemIdUtils.SPAN_LENS_NAME_PREFIX, undefined); lensHtml += '<span id="' + nameSpanId + '" class="card-hdr-lens-name">' + lens.LensName + '</span>'; const btnId = elemIdUtils.getElemId(lensId, elemIdUtils.BUTTON_CLOSE_CARD_HEADER_PREFIX, undefined); lensHtml += '<button id="' + btnId + '" class="btn card-hdr-close-btn float-right" type="button" aria-label="Close"><span class="card-hdr-close-x" aria-hidden="true">×</span></button>'; const showBk = bookmarkUIUtils.showBookmarks(); // should we show bookmark icons? log('getHtmlForLensCard: showBk=' + showBk); if (showBk) { // if we should show bookmarks var wImgPath = ''; var bkClass = ''; if (viewWide) { // if the user is using a wider screen, we show smaller bookmarks bkClass = 'bk-sm'; if (bookmarked) { // if the lens is bookmarked wImgPath = urlUtils.getUrl('/images/bookmarkfilled-sm.png'); } else { // if the lens is not bookmarked wImgPath = urlUtils.getUrl('/images/bookmarkempty-sm.png'); } } else { // if the user is on a smaller screen, we show larger bookmarks bkClass = 'bk-lg'; if (bookmarked) { // if the lens is bookmarked wImgPath = urlUtils.getUrl('/images/bookmarkfilled.png'); } else { // if the lens is not bookmarked wImgPath = urlUtils.getUrl('/images/bookmarkempty.png'); } } const imgId = elemIdUtils.getElemId(lensId, elemIdUtils.IMAGE_BOOKMARK_PREFIX, undefined); lensHtml += '<img id="' + imgId + '" class="empty-bookmark ' + bkClass + '" src="' + wImgPath + '" />'; // add the bookmark image to the lens markup } lensHtml += '</div>'; // #cardHdr lensHtml += '<div class="card-body">'; const lensNameSpanId = elemIdUtils.getElemId(lensId, elemIdUtils.SPAN_LENS_NAME_PREFIX, undefined); const pDescr = descrHtml.replace('<span ', '<span id="' + lensNameSpanId + '" '); // store an HTML element id in the span element in the description const cardDescrId = elemIdUtils.getElemId(lensId, elemIdUtils.CARD_DESCR_PREFIX, undefined); lensHtml += '<p id="' + cardDescrId + '" class="card-text">' + pDescr + '</p>'; // NOTE: at this point in the code, we create two sets of content: collapsed and expanded var expHtml = ''; // the HTML for the expanded contents if (true) { // create the code for the expanded content const eContentId = elemIdUtils.getElemId(lensId, elemIdUtils.CARD_TEXT_PREFIX, true); expHtml += '<div class="" id="' + eContentId + '">'; expHtml += '<div class="section-caption">When to Use</div>'; const eWhenId = elemIdUtils.getElemId(lensId, elemIdUtils.WHEN_CONTENT_PREFIX, true); expHtml += '<div class="section-content" id="' + eWhenId + '">' + lens.WhenToUse + '</div>'; expHtml += '<div class="section-caption">How to Use</div>'; const eHowId = elemIdUtils.getElemId(lensId, elemIdUtils.HOW_CONTENT_PREFIX, true); expHtml += '<div class="section-content" id="' + eHowId + '">' + lens.HowToUse + '</div>'; expHtml += '<div class="section-caption">Examples</div>'; const lensExamples = lensExampleUtils.getExamplesForLens(lensId); const exCount = lensExamples.length; log(logHeader + 'exCount=' + exCount); var examplesHtml = ''; for (var zIndex = 0; zIndex < exCount; zIndex++) { // once for each example var lensExample = lensExamples[zIndex]; var exTitle = lensExample.Name; var exText = lensExample.Text; var exTitleHtml = '<div class="example-title">' + exTitle + '</div>'; var exTextHtml = '<div class="example-text">' + exText + '</div>'; examplesHtml += exTitleHtml; examplesHtml += exTextHtml; // append example title and text to the HTML } const eExId = elemIdUtils.getElemId(lensId, elemIdUtils.EXAMPLES_CONTENT_PREFIX, true); expHtml += '<div class="section-content" id="' + eExId + '">' + examplesHtml + '</div>'; expHtml += '<div class="section-caption">Video</div>'; const eVideoId = elemIdUtils.getElemId(lensId, elemIdUtils.VIDEO_CONTENT_PREFIX, true); expHtml += '<div class="" id="' + eVideoId + '">'; // NOTE: for now, we don't show the Load Video button //if (videoBtn) { // log(logHeader + 'add the "Load Video" button'); // const eBtnLoadVideoId = elemIdUtils.getElemId(lensId, elemIdUtils.BUTTON_LOAD_VIDEO_PREFIX, undefined); // log(logHeader + 'eBtnLoadVideoId=' + eBtnLoadVideoId); // const buttonHTML = '<button id="' + eBtnLoadVideoId + '" type="button" class="btn btn-primary load-video">Load Video</button>'; // expHtml += buttonHTML; //} log(logHeader + 'add the video markup to the HTML'); var videoElemSize = lensUIUtils._getVideoElemSize(viewWidth, viewHeight); // get the desired size of the video element given the view dimensions var videoElemWidth = videoElemSize.width; var videoElemHeight = videoElemSize.height; const videoType = videoUtils.getVideoType(lensId); // what type of video will we create? log(logHeader + 'videoType=' + videoType); var videoHtml = ''; var videoUrl = ''; var videoElemId; videoElemId = elemIdUtils.getVideoElemId(lensId); // get the id of the video element log(logHeader + 'videoElemId=' + videoElemId); if (videoType === videoUtils.VIDEO_TYPE_BLOB) { // if blob video videoUrl = videoUtils.getVideoUrl(lensId); // get the URL of the blob videoHTML = videoUtils.getVideoHtml_video(lensId, videoElemWidth, videoElemHeight, videoUrl); // get html for the video } else { // if Vimeo video videoUrl = videoUtils.getIFrameUrl(lensId); // get the URL of the iFrame source videoHTML = videoUtils.getVideoHtml_iFrame(lensId, videoElemWidth, videoElemHeight, videoUrl); // get html for the Vimeo video in an iFrame } expHtml += videoHTML; // add the video HTML to the markup expHtml += '</div> '; // #videoContent const spanLessId = elemIdUtils.getElemId(lensId, elemIdUtils.SPAN_LESS_PREFIX, true); // the "less..." link which allows the user to collapse the card // NOTE: s-less is the class for "less" links in cards without tabs expHtml += '<span id="' + spanLessId + '" class="s-less"> '; expHtml += 'less...'; expHtml += '</span>'; expHtml += '</div>'; // #cardContent } const expElemId = elemIdUtils.getElemId(lensId, elemIdUtils.CARD_EXPANDED_CONTENT_PREFIX, undefined); const expanded = noTabsCardExpStorageUtils.isCardExpanded(lensId); // is this no tabs card expanded? log(logHeader + 'expanded=' + expanded); var expStyle = ''; if (!expanded) { // if the current card is not expanded expStyle = ' style="display: none;" '; } lensHtml += '<div id="' + expElemId + '" ' + expStyle + '>' + expHtml + '</div>'; // add the expanded contents inside a div to the lens HTML var collHtml = ''; // the HTML for the collapsed contents if (true) { // add the collapsed content here var whenIntro = lens.WhenToUse; // default to the full when text const periodIndex = whenIntro.indexOf('.'); // find the first period if (periodIndex >= 0) { // if we found one whenIntro = whenIntro.substr(0, periodIndex + 1); // get the first sentence of the when text } const eContentIdC = elemIdUtils.getElemId(lensId, elemIdUtils.CARD_TEXT_PREFIX, false); collHtml += '<div class="" id="' + eContentIdC + '">'; collHtml += '<div class="section-caption">When to Use</div>'; const eWhenIdC = elemIdUtils.getElemId(lensId, elemIdUtils.WHEN_CONTENT_PREFIX, false); collHtml += '<div class="section-content" id="' + eWhenIdC + '">' + whenIntro + '</div>'; const spanMoreId = elemIdUtils.getElemId(lensId, elemIdUtils.SPAN_MORE_PREFIX, false); // the "more..." link which allows the user to expand the card // NOTE: s-more is the class for "more" links in cards without tabs collHtml += '<span id="' + spanMoreId + '" class="s-more"> '; collHtml += 'more...'; collHtml += '</span>'; collHtml += '</div>'; } const collElemId = elemIdUtils.getElemId(lensId, elemIdUtils.CARD_COLLAPSED_CONTENT_PREFIX, undefined); var collStyle = ''; if (expanded) { // if the current card is expanded collStyle = ' style="display: none;" '; } lensHtml += '<div id="' + collElemId + '" ' + collStyle + '>' + collHtml + '</div>'; // add the collapsed contents inside a div to the lens HTML lensHtml += '</div>'; // .card-body lensHtml += '</div>'; // #card log(logHeader + ' leave'); return lensHtml; }, getHtmlForLensCardAsync: async function getHtmlForLensCardAsync(lens, showTabs, expanded, cardIndex, explicitWidthStr) { // showTabs: true => create the card with tabs // false => create the cards with all info (when, how, etc.) visible, with headers and content in each section // expanded: true => create the card in expanded mode // false => created the card in collapsed mode // cardIndex: zero-based index to the card on the web page // explicitWidthStr: undefined or empty string: do nothing // otherwise, this string is a CSS width value for the lens card div // for example: // 600px // 90% const logHdr = 'getHtmlForLensCardAsync: '; log(logHdr + 'enter'); log(logHdr + 'lens name=' + lens.LensName); log(logHdr + 'showTabs=' + showTabs); log(logHdr + 'expanded=' + expanded); log(logHdr + 'cardIndex=' + cardIndex); log(logHdr + 'explicitWidthStr=' + explicitWidthStr); var lensHtml = ''; if (showTabs) { // if we should show tabs lensHtml = await lensHtmlUtils._getHtmlForLensCardWithTabsAsync(lens, expanded, explicitWidthStr); // get HTML for the lens, with tabs } else { // if no tabs // NOTE: on iOS, if we add <video> elements to the page, Safari loads the entire video file // whether or not the user clicks the play button on the video thumbnail. // for this reason we only show video thumbnails for the first 3 videos on the page. // after that, we show a "Load Video" button that the user can click to load the video. // that way, we speed up the page and reduce bandwidth usage. var videoBtn = (cardIndex > 2); // cardIndex is zero-based // if this video is past the third one on the page, show a Load Video button // instead of a video thumbnail lensHtml = this._getHtmlForLensCardNoTabs(lens, videoBtn, explicitWidthStr); // get HTML for the lens, without tabs } log(logHdr + ' leave'); return lensHtml; }, getHtmlForLensesByAlphaAsync: async function getHtmlForLensesByAlphaAsync(lensDTOs) { // get HTML for the given array of lenses // display lenses alphabetically, not by group // NOTE: this function sorts the array of lenses const logHdr = 'getHtmlForLensesByAlphaAsync: '; log(logHdr + 'enter'); lensDTOs.sort(function (a, b) { return (a.LensName > b.LensName) ? 1 : -1 }); // sort lenses ascending by lens name var theHtml = ''; var theCount = lensDTOs.length; log(logHdr + 'theCount=' + theCount); if (theCount < 1) { log(logHdr + 'no lenses so we are done'); log(logHdr + 'leave'); return ''; } var showTabs = lensHtmlUtils.showTabsOrNot(); // should we show tabs in the lens cards? // if the viewport width is below a specific value, we show lens cards without tabs // because the tabs don't fit, so they would wrap to a second row // which looks bad and could confuse the user as to which tab is selected log(logHdr + 'showTabs=' + showTabs); var lensesHtml = ''; for (var zIndex = 0; zIndex < theCount; zIndex++) { // once for each card to display var lens = lensDTOs[zIndex]; var lensId = lens.LensId; var expanded = tabsCardExpStorageUtils.isCardExpanded(lensId); // have we stored a request to expand the card? if (!expanded) { // if not expanded yet if (theCount === 1) { // if there is precisely one lens in the array tabsCardExpStorageUtils.addToLensIds(lensId); // store the flag // other code needs to know that this lens is expanded, eg code to show expand/collapse buttons expanded = true; // expand it, so the user doesn't have to click to see all the info in the card } } var widthStr = ''; const cardWidth = cardWidthUtils.getCardWidth(lensId); // do we have a card width stored? // types of values // 0 => no width stored // 600 => numeric value greater than zero, number of pixels // 90% => string, percentage value log(logHdr + 'cardWidth=' + cardWidth); if (cardWidth === 0) { // if no value } else { if (typeof cardWidth === "number") { widthStr = cardWidth + 'px'; // pixels } else { widthStr = cardWidth; // percentage string } } if (theCount === 1) { // if we will generate precisely one card widthStr = '90%'; // make it wide } var oneLensHtml = await lensHtmlUtils.getHtmlForLensCardAsync(lens, showTabs, expanded, zIndex, widthStr); // get the HTML for one lens card lensesHtml += oneLensHtml; } theHtml = '<div id="divLensResults" class="d-flex flex-row flex-wrap justify-content-center">' + lensesHtml + '</div>'; log(logHdr + 'leave'); return theHtml; }, getHtmlForLensesByGroupAsync: async function getHtmlForLensesByGroupAsync(lensDTOs) { // get HTML for the given array of lenses // display lenses by group // NOTE: this function sorts the array of lenses const logHdr = 'lensUIUtils.getHtmlForLensesByGroupAsync: '; log(logHdr + 'enter'); var theHtml = ''; const allLensCount = lensDTOs.length; log(logHdr + 'allLensCount=' + allLensCount); if (allLensCount < 1) { log(logHdr + 'no lenses so we are done'); log(logHdr + 'leave'); return theHtml; } var lensesInCats = lensUtils.getLensesInCategories(lensDTOs); // return an array of 5 arrays // each element in the first order array represents a category // the first order elements are in ascending category sort order // each first order element contains a (possibly empty) array of lenses // from the source list that belong to the category const catCount = lensesInCats.length; // get the number of categories log(logHdr + 'catCount=' + catCount); var categoriesHtml = '<hr id="hrAboveFirstCat" class="one-cat-hr" />'; // start with an hr above the first category var totalIndex = 0; for (var catIndex = 0; catIndex < catCount; catIndex++) { // once for each category log(logHdr + 'Processing category ' + catIndex + ' of ' + catCount + '...'); const lensesInCat = lensesInCats[catIndex]; const lensesInCatCount = lensesInCat.length; log(logHdr + 'lensesInCatCount=' + lensesInCatCount); if (lensesInCatCount < 1) continue; // if no lenses in this category, skip it var firstLens = lensesInCat[0]; var catName = firstLens.CategoryName; var catId = firstLens.CategoryId; log(logHdr + 'catName=' + catName); var showTabs = lensHtmlUtils.showTabsOrNot(); // should we show tabs in the lens cards? // if the viewport width is below a specific value, we show lens cards without tabs // because the tabs don't fit, so they would wrap to a second row // which looks bad and could confuse the user as to which tab is selected log(logHdr + 'showTabs=' + showTabs); var lensesHtml = ''; for (var lensIndex = 0; lensIndex < lensesInCatCount; lensIndex++) { // once for each lens in the category var lens = lensesInCat[lensIndex]; log(logHdr + 'lens name=' + lens.LensName); var lensId = lens.LensId; log(logHdr + 'lensId=' + lensId); var expanded = tabsCardExpStorageUtils.isCardExpanded(lensId); // have we stored a request to expand the card? var widthStr = ''; const cardWidth = cardWidthUtils.getCardWidth(lensId); // do we have a card width stored? // types of values // 0 => no width stored // 600 => numeric value greater than zero, number of pixels // 90% => string, percentage value log(logHdr + 'cardWidth=' + cardWidth); if (cardWidth === 0) { // if no value } else { if (typeof cardWidth === "number") { widthStr = cardWidth + 'px'; // pixels } else { widthStr = cardWidth; // percentage string } } var oneLensHtml = await lensHtmlUtils.getHtmlForLensCardAsync(lens, showTabs, expanded, totalIndex, widthStr); // get the HTML for one lens card // showTabs: should we show tabs or flow sections? // expanded: is the card expanded or collapsed? totalIndex += 1; // increment index of the card on the page lensesHtml += oneLensHtml; } var oneCatHtml = '<h5 id="catName' + catId + '" class="category-name">' + catName + '</h5>'; // start with an element for the category name oneCatHtml += '<div id="divCategory' + catId + '" class="div-category-lenses d-flex flex-row flex-wrap justify-content-left">'; // append a parent div for the lenses in the category oneCatHtml += lensesHtml; // append the lenses oneCatHtml += '</div>'; // close the parent div categoriesHtml += oneCatHtml; // append the HTML for this category to the categories HTML categoriesHtml += '<hr id="hrCategory' + catId + '" class="one-cat-hr" />'; // append a horizontal rule } theHtml = '<div id="divResultsByCat">' + categoriesHtml + '</div>'; // wrap the categories HTML in a parent div so we can style it log(logHdr + 'leave'); return theHtml; } };