B.C. won’t cancel Site C dam despite ballooning costs
Site C #SiteC
” ].join(“”); } return template; } /** * Generate a template for the label * @param {String} label – the label text * @returns {String} */ function displayLabel(label) { var template = “”; if (label === “opinion”) { template = [ “
“, ” “, label, “”, “
“, ].join(“”); } return template; } /** * Display “Follow”, “Following” buttons * @param {Object} tData * @returns {String} */ function displayFollowingButton(tData) { var topicName = tData.topicName; var topicSlug = tData.topicSlug; var topicType = tData.topicType; var topicImg = tData.topicImg; var isAuthor = topicType === “author”; var authorImg = isAuthor && topicImg ? “” : “”; var template = isAuthor ? “/authors/” : “/topics/”; var href = window.tgam.env.baseRootAbsoluteUrl + template + topicSlug; var linkClasses = isAuthor ? “c-topic-link c-topic-link–author” : “c-topic-link”; return [ ” “, ].join(“”); } /** * Generates story card markup * @param {Object} article – to display * @param {Object} topicData – (topicName, topicSlug, topicType, topicVariation, topicImg) * @param {Boolean} addFollowButton * @returns {String} story card markup */ function storyCard(article, topicData, addFollowButton) { // console.info(“[ARC-7130] storyCard”, { article: article, topic: topicData }); if (!article || !topicData) { return “”; } var tName = topicData.topicName; var tType = topicData.topicType; var tVariation = topicData.topicVariation; var followingTopic; var timeTemplate; var analyticsModifier = tType + “: “; if (addFollowButton) { // Display a follow button beside the topic name followingTopic = displayFollowingButton(topicData); timeTemplate = displayDateTag(article); } var label = getLabel(article); var image = getImage(article, label); var labelTemplate = displayLabel(label); var imageTemplate = displayImage(image); var headline = article.headlines.basic; var href = window.tgam.env.baseUrl + article.canonical_url; var sophiId = article._id; var dataAnalyticsClick = JSON.stringify({ type: “link”, feature: “following feed”, contentId: sophiId, label: analyticsModifier + tName.toLowerCase() + “: ” + headline.toLowerCase(), page: “sec:homepage:personalized feed:” + tVariation, hierarchy: 1 }); var cardMarkup = “”; if (!followingTopic) { cardMarkup = [ “”, ” “, ”
“, ” “, tName, “”, ”
“, ”
“, ” “, headline, “”, ”
“, labelTemplate, ” “, ”
“, imageTemplate, “
“, “” ].join(“”); } else { cardMarkup = [ ”
“, followingTopic, ”
“, ” “, ” “, ”
“, ” “, headline, “”, ”
“, ” “, timeTemplate, “”, ” “, ”
“, imageTemplate, “
“, ” “, ].join(“”); } return [ ”
“, cardMarkup, ”
“, ].join(“”); } /** * Adds the overlay trigger dot class * @param {String} type – “unread” or “no-follow” */ function addOverlayTriggerDot(type) { overlayTriggerDotClasses.forEach(function fn(dotClass) { if (dotClass === “c-your-globe__trigger–dot–” + type) { overlayTrigger.classList.add(dotClass); } else { overlayTrigger.classList.remove(dotClass); } }); overlayTrigger.classList.add(“c-your-globe__trigger–dot”); } /** * Removes the overlay trigger dot class */ function removeOverlayTriggerDot() { overlayTriggerDotClasses.forEach(function fn(dotClass) { overlayTrigger.classList.remove(dotClass); }); overlayTrigger.classList.remove(“c-your-globe__trigger–dot”); } /** * Returns a heading element to be displayed inside the overlay * @param {String} text * @returns {String} */ function overlayLabel(text) { return “” + text + “”; } var overlayHeadingHasFollowed = ( overlayLabel(“The latest in topics and authors you follow”) + “
” ); var overlayHeadingNoFollowed = ( overlayLabel(“Get started: build your personal news feed”) + “” + “
” + “
” + “” ); var upToDateMessage = “
You’re up to date on your Following feed. Check again later for new stories.
“; // ************************************************ // Parse API response and inject markup into overlay // ************************************************ // Story card markup /** * Stories originally came from the following locations in the API response: * – data.articles[i].items[i].topics * – data.articles[i].items[i].authors * @param {Array} stories * @returns {String} story card markup */ function latestStoryCards(stories) { console.info(“[ARC-7130] Display latest stories based on these stories:”, stories); var storyCards = stories.map(function fn(story) { // The “topics” and “authors” arrays will only contain one item // (i.e. the topic or author that the user is following) var topic; var topicData; if (story.topics && story.topics.length) { // Normal topic topic = story.topics[0]; topicData = { topicName: topic.name, topicSlug: topic.slug, topicType: “topic”, topicVariation: “following” }; } else if (story.authors && story.authors.length) { // Author topic topic = story.authors[0]; // Only authors have images associated with them – normal topics do not var authorImg = topic.metadata && topic.metadata.image ? topic.metadata.image : null; topicData = { topicName: topic.byline, topicSlug: topic.slug, topicType: “author”, topicVariation: “following”, topicImg: authorImg }; } // Don’t display a follow button beside the topic because the user is already following it return storyCard(story, topicData, false); }).join(“”); return storyCards; } /** * @param {Array} topics * @param {String} variation – “recommended” or “trending” (used for the click tracking analytics) * @returns {String} story card markup */ function recommendedTrendingStoryCards(topics, variation) { var uniqueStories = generateUniqueStory(topics); var storyCards = uniqueStories.map(function fn(topic) { // Grab one article var story = topic.items[0]; // Only authors have images associated with them – normal topics do not var authorImg = topic.authorTopic && topic.authorMetadata && topic.authorMetadata.image ? topic.authorMetadata.image : null; // Normally we’d display all of the topics that are assigned to an article, but // this API groups articles by topic, so we only have access to that one topic. // Even if we could display additional topics, we wouldn’t want to becuase having // multiple follow buttons would junk up the UI. var topicData = { topicName: topic.name, topicSlug: topic.slug, topicType: topic.authorTopic ? “author” : “topic”, topicVariation: variation, topicImg: authorImg }; // Display the follow button beside the topic because we’re suggesting new topics to follow return storyCard(story, topicData, true); }).join(“”); return storyCards; } /** * Topics originally came from the following locations in the API response: * – data.recommendedAuthors * – data.recommendedTopics * @param {Array} topics * @returns {String} story card markup */ function recommendedStoryCards(topics) { console.info(“[ARC-7130] Display recommended stories based on these topics:”, topics); return recommendedTrendingStoryCards(topics, “recommended”); } /** * Topics originally came from the following location in the API response: * – data.trendingTopics * @param {Array} topics * @returns {String} story card markup */ function trendingStoryCards(topics) { console.info(“[ARC-7130] Display trending stories based on these topics:”, topics); return recommendedTrendingStoryCards(topics, “trending”); } // Markup inside the overlay /** * @param {Array} stories * @returns {Object} markup for the overlay’s header and body content areas */ function showLatestStories(stories) { console.info(“[ARC-7130] Scenario: latest stories”); var storyCardsMarkup = latestStoryCards(stories); return { header: overlayHeadingHasFollowed, body: storyCardsMarkup }; } /** * @param {Array} topics * @returns {Object} markup for the overlay’s header and body content areas */ function upToDateShowRecommended(topics) { console.info(“[ARC-7130] Scenario: up to date, show recommended”); var storyCardsMarkup = recommendedStoryCards(topics); return { header: overlayHeadingHasFollowed, body: ( upToDateMessage + overlayLabel(“Recommended for you”) + storyCardsMarkup ) }; } /** * @param {Array} topics * @returns {Object} markup for the overlay’s header and body content areas */ function upToDateShowTrending(topics) { console.info(“[ARC-7130] Scenario: up to date, show trending”); var storyCardsMarkup = trendingStoryCards(topics); return { header: overlayHeadingHasFollowed, body: ( upToDateMessage + overlayLabel(“Trending topics to follow”) + storyCardsMarkup ) }; } /** * @param {Array} topics * @returns {Object} markup for the overlay’s header and body content areas */ function notFollowingShowRecommended(topics) { console.info(“[ARC-7130] Scenario: not following, show recommended”); var storyCardsMarkup = recommendedStoryCards(topics); return { header: overlayHeadingNoFollowed, body: ( overlayLabel(“Recommended for you”) + storyCardsMarkup ) }; } /** * @param {Array} topics * @returns {Object} markup for the overlay’s header and body content areas */ function notFollowingShowTrending(topics) { console.info(“[ARC-7130] Scenario: not following, show trending”); var storyCardsMarkup = trendingStoryCards(topics); return { header: overlayHeadingNoFollowed, body: ( overlayLabel(“Trending topics to follow”) + storyCardsMarkup ) }; } /** * Parse data from the personalized API and inject markup into the overlay * @see https://confluence.theglobeandmail.com/display/ARC/Logic+for+Embedded+on+Homepage++and+Your+Globe+Overlay * @param {Object} data – topic and story data provided by the API */ function parsePerzonalizedTopicsData(data) { console.info(“[ARC-7130] parsePerzonalizedTopicsData”, data); var overlayHeader = qs(“.c-your-globe__overlay-header”); var overlayHeaderText = qs(“.c-your-globe__overlay-header-text”); var overlayBody = qs(“.c-your-globe__overlay-body”); if (!overlayHeader || !overlayHeaderText || !overlayBody) { return; } var totalTopicsFollowed = data.totalTopicsFollowed || 0; var totalAuthorsFollowed = data.totalAuthorsFollowed || 0; var recommendedTopics = data.recommendedTopics || []; var recommendedAuthors = data.recommendedAuthors || []; var latestStories = data.articles || []; var topics = []; var stories = []; var markup = “”; var headerBorder = true; if (totalTopicsFollowed || totalAuthorsFollowed) { if (latestStories.length) { // Scenario 1: “Latest stories” stories = generateLatestStories(latestStories); markup = showLatestStories(stories); // Similar to displayLatestAndRecommended() in ARC-6292 addOverlayTriggerDot(“unread”); } else { if (recommendedTopics.length || recommendedAuthors.length) { // Scenario 2: “Up to date, show recommended” topics = recommendedAuthors.concat(recommendedTopics); markup = upToDateShowRecommended(topics); // Similar to displayRecommendedTrendingTopicList(“rec”) in ARC-6292 } else { // Scenario 3: “Up to date, show trending” topics = data.trendingTopics || []; markup = upToDateShowTrending(topics); // Similar to displayRecommendedTrendingTopicList(“trend”) in ARC-6292 } } } else { topics = recommendedAuthors.concat(recommendedTopics); if (topics.length) { // Scenario 4: “Not following, show recommended” markup = notFollowingShowRecommended(topics); // Similar to displayThreeTopicsOneStory(“rec”) in ARC-6292 } else { // Scenario 5: “Not following, show trending” topics = data.trendingTopics || []; markup = notFollowingShowTrending(topics); // Similar to displayThreeTopicsOneStory(“trend”) in ARC-6292 } addOverlayTriggerDot(“no-follow”); headerBorder = false; } console.info(“[ARC-7130] Append markup”); var spinner = qs(“.c-spinner”); spinner && spinner.parentElement.removeChild(spinner); overlayHeaderText.insertAdjacentHTML(“afterbegin”, markup.header); overlayBody.insertAdjacentHTML(“afterbegin”, markup.body); if (!headerBorder) { overlayHeader.classList.add(“c-your-globe__overlay-header–no-border”); } addFollowingFunctionality(); } // ************************************************ // API calls // ************************************************ /** * Get the personalized feed * @param {String} hashId – user’s hash id * @param {String} env – environment * @see https://confluence.theglobeandmail.com/display/ARC/Logic+for+Embedded+on+Homepage++and+Your+Globe+Overlay * @returns {Promise