CINXE.COM

Saenai Heroine no Sodatekata (Anime) - Episodes Release Dates

<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" lang="en"> <head> <meta charset="utf-8"> <title>Saenai Heroine no Sodatekata (Anime) - Episodes Release Dates</title> <meta name="description" content="Air dates for all new episodes and upcoming seasons of ‘Saenai Heroine no Sodatekata’ (anime)."> <meta name="keywords" content="Saenai Heroine no Sodatekata, release dates, air dates, next episode, episodes, new episode, upcoming episodes, new season, schedule"> <meta name="apple-itunes-app" content="app-id=1511279349"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0"> <meta name="apple-mobile-web-app-title" content="Toramp"> <meta name="application-name" content="Toramp"> <link rel="stylesheet" type="text/css" href="https://www.toramp.com/css/gl.css?0ef26085ee95010b855a18fd66c865db"> <link rel="apple-touch-icon" sizes="180x180" href="https://www.toramp.com/i/apple-touch-icon.png"> <link rel="mask-icon" href="https://www.toramp.com/svg/logo.svg" color="#fe3195"> <link rel="icon" type="image/png" href="https://www.toramp.com/i/favicon-32x32.png" sizes="32x32"> <link rel="icon" type="image/png" href="https://www.toramp.com/i/favicon-16x16.png" sizes="16x16"> <link rel="manifest" href="https://www.toramp.com/i/manifest.json"> <link rel="alternate" hreflang="en" href="https://www.toramp.com/shows/1793/" /><link rel="alternate" hreflang="ru" href="https://www.toramp.com/schedule.php?id=1793" /><!--google-analytics[BEGIN]--> <script> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-26288240-1', 'auto'); ga('send', 'pageview'); </script> <!--google-analytics[END]--> <!--ADS_ALL[BEGIN]--> <script data-ad-client="ca-pub-8730893242604623" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script><script>window.yaContextCb=window.yaContextCb||[]</script> <script src="https://yandex.ru/ads/system/context.js" async></script><!--ADS_ALL[END]--> <script type="application/javascript"> var pageSettings = {"TVShows":{"isLoggedIn":false,"path":{"userStatus":"https:\/\/www.toramp.com\/script\/user\/show\/user_status.php","recommend":"https:\/\/www.toramp.com\/script\/user\/show\/recommend.php","watchedEpisode":"https:\/\/www.toramp.com\/script\/user\/show\/watched_episode.php","favoriteEpisode":"https:\/\/www.toramp.com\/script\/user\/show\/love_episode.php","rating":"https:\/\/www.toramp.com\/script\/user\/show\/rating.php","editUserNote":"https:\/\/www.toramp.com\/script\/user\/show\/user_note.php","deleteUserNote":"https:\/\/www.toramp.com\/script\/user\/show\/delete_user_note.php","watchedSeason":"https:\/\/www.toramp.com\/script\/db\/show\/episode_season_watched.php"},"airedEpisodeCount":25,"canceled":true,"trailers":[],"btnRecommend":{"squanchy":{"active":"Unrecommend","inactive":"Recommend"}},"btnRating":{"squanchy":{"remove":"Undo","stars":["The worst I've seen","Terrible","Barely watchable","Wasted my time","Meh","Not bad","Good","Excellent","Masterpiece","Film of the century"]}},"markSeasonBtn":{"textMark":"Mark all episodes","textUnmark":"Unmark all episodes"},"login":{"text":"Toramp \u2013 discover, organize, and track tv shows & anime.","SignUp":"Sign up for free","LogIn":"Log in"}},"global":{"lang":{"texts":{"header":"Choose a language"},"specialPage":false,"checked":"en","items":[{"title":"English","language":"en","locale":"en_US","url":"https:\/\/www.toramp.com\/shows\/1793\/"},{"title":"\u0420\u0443\u0441\u0441\u043a\u0438\u0439","language":"ru","locale":"ru_RU","data":"ru","url":"https:\/\/www.toramp.com\/schedule.php?id=1793"}]},"base_url":"https:\/\/www.toramp.com","base_url_lang":"https:\/\/www.toramp.com","base_src":"https:\/\/www.toramp.com","language":"en","search":{"path":"https:\/\/www.toramp.com\/search_all.php","url":"https:\/\/www.toramp.com\/search\/?q=","text":{"noResults":"No results","searching":"Searching..."}},"movieTooltip":{"path":"https:\/\/www.toramp.com\/script\/tooltip\/movie.php"},"showTooltip":{"path":"https:\/\/www.toramp.com\/script\/tooltip\/show.php"},"gent":{"path":"https:\/\/www.toramp.com\/script\/gent.php","time":1200},"log_in_or_sign_up_txt":"Log in or sign up."}}; </script> </head> <body class="bg_white" data-id="1793" data-lang="en"> <div class="root"> <nav class="gnav"> <div class="top"> <div class="logo"> <a href="https://www.toramp.com/en/" title="TORAMP [gh]">TORAMP</a> </div> <div class="search_container"> <div class="searchInputWrapper"> <input type="search" id="globalSearchInput" class="input input-medium" autocomplete="off" placeholder="Search"> <svg class="icon iconMagnifyingGlass"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconMagnifyingGlass"></svg> <span class="shortcut_for_search_info">/</span> <button type="button" class="btn-text fs_normal" data-global-search="cancel">Cancel</button> </div> <div class="globalSearchResultsWrapper" data-global-search="results"> <nav> <label for="globalSearchInput" data-global-search-nav="2" class="active">shows</label> <label for="globalSearchInput" data-global-search-nav="3">Users</label> </nav> </div> </div> <div class="links_corner fs_small"> <a href="https://www.toramp.com/sign-up/" class="margin_r_16">Sign Up</a> <a href="https://www.toramp.com/login/">Log In</a> <label for="globalSearchInput" class="searchLabel margin_l_20" aria-label="Search"> <svg class="icon iconMagnifyingGlass"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconMagnifyingGlass"></svg> </label> </div> </div> <div class="bottom"> <div class="dis_ib first_link"> <a href="https://www.toramp.com/explore/shows/" title="Explore [ge]">Explore</a> </div> <a href="https://www.toramp.com/premieres/">All premieres</a> <a href="https://www.toramp.com/new-netflix-tv-shows/2025/">Netflix premieres</a> </div> </nav> <div style="background-image:linear-gradient(160deg,#E84271 0%,#F9905E 50%,#C96DD8 100%);height:3px"></div> <main role="main"> <!-- pagehead --> <header class="pagehead"> <div class="container clearfix"> <h1>Saenai Heroine no Sodatekata <span class="c_g5">(2015 — 2017)</span> <span class="anime_type border_rad_12 pl_2 pr_2 float_r fw_normal fs_normal">anime</span></h1> </div> </header> <div class="page_container_wrapper_1 series_page_desktop_min_height" style="margin-bottom: 250px"> <!-- centered container --> <div class="container pos_rel"> <div class="series_main_div"> <section class="series_poster mb_6"> <div class="imgWrapper"> <img src="https://www.toramp.com/posters/shows/1793/width360/saenai_heroine_no_sodatekata.jpg" alt="Saenai Heroine no Sodatekata (anime)"> </div> </section> <section class="series_user_actions mb_6 pb_6 ht_tw"> <!-- User status mobile --> <div class="change_user_status_mobile"> <button type="button" class="btn btn-large btnMyStatus" data-my-status="no_status" data-global-dropdown-btn="tv-show-user-status-mobile"> Haven't seen <svg class="icon iconChevronDown"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconChevronDown"></svg> </button> <div class="details_menu hide" data-global-dropdown="tv-show-user-status-mobile"> <div class="details_menu_header"> <span class="details_menu_title">Add to...</span> </div> <ul> <li data-value="no_status" data-text="Haven't seen" class="checked_true"> <i><svg class="icon iconCheckMark"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconCheckMark"></svg></i> <div class="option_txt">Haven't seen</div> </li> <li data-value="want_to_see" data-text="Want to see"> <div class="option_txt">Want to see</div> </li> <li data-value="watching" data-text="Watching"> <div class="option_txt">Watching</div> </li> <li data-value="on_hold" data-text="On hold"> <div class="option_txt">On hold</div> </li> <li data-value="dropped" data-text="Dropped"> <div class="option_txt">Dropped</div> </li> <li data-value="completed" data-text="Completed"> <div class="option_txt">Completed</div> </li> </ul> </div> </div> <!-- User status for desktops and iPads --> <div class="change_user_status_full user_select_off border_b pb_6 border_c0"> <button type="button" class="ta_center fw_normal" data-my-status="watching" data-btn="user-status-decktop"> <span class="no_pointer_events">Watching</span> </button> <button type="button" class="ta_center fw_normal" data-my-status="want_to_see" data-btn="user-status-decktop"> <span class="no_pointer_events">Want to see</span> </button> <button type="button" class="ta_center fw_normal" data-my-status="on_hold" data-btn="user-status-decktop"> <span class="no_pointer_events">On hold</span> </button> <button type="button" class="ta_center fw_normal" data-my-status="dropped" data-btn="user-status-decktop"> <span class="no_pointer_events">Dropped</span> </button> <button type="button" class="ta_center fw_normal" data-my-status="completed" data-btn="user-status-decktop"> <span class="no_pointer_events">Completed</span> </button> <button type="button" class="ta_center fw_normal border_all selected" data-my-status="no_status" data-btn="user-status-decktop"> <span class="no_pointer_events">Haven't seen</span> </button> </div> <!-- User score, likes, and share buttons --> <div class="actions_bottom"> <!-- Rating for desktop --> <div class="btnRating" data-tv-show="change-rating"> <button type="button" class="btn btnLightGray" data-squanchy="The worst I've seen" data-btn="change-rating" data-star="1"><svg class="icon iconStar"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconStar"></svg></button> <button type="button" class="btn btnLightGray" data-squanchy="Terrible" data-btn="change-rating" data-star="2"><svg class="icon iconStar"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconStar"></svg></button> <button type="button" class="btn btnLightGray" data-squanchy="Barely watchable" data-btn="change-rating" data-star="3"><svg class="icon iconStar"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconStar"></svg></button> <button type="button" class="btn btnLightGray" data-squanchy="Wasted my time" data-btn="change-rating" data-star="4"><svg class="icon iconStar"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconStar"></svg></button> <button type="button" class="btn btnLightGray" data-squanchy="Meh" data-btn="change-rating" data-star="5"><svg class="icon iconStar"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconStar"></svg></button> <button type="button" class="btn btnLightGray" data-squanchy="Not bad" data-btn="change-rating" data-star="6"><svg class="icon iconStar"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconStar"></svg></button> <button type="button" class="btn btnLightGray" data-squanchy="Good" data-btn="change-rating" data-star="7"><svg class="icon iconStar"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconStar"></svg></button> <button type="button" class="btn btnLightGray" data-squanchy="Excellent" data-btn="change-rating" data-star="8"><svg class="icon iconStar"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconStar"></svg></button> <button type="button" class="btn btnLightGray" data-squanchy="Masterpiece" data-btn="change-rating" data-star="9"><svg class="icon iconStar"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconStar"></svg></button> <button type="button" class="btn btnLightGray" data-squanchy="Film of the century" data-btn="change-rating" data-star="10"><svg class="icon iconStar"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconStar"></svg></button> </div> <!-- Right corner mobile btns --> <div class="corner_btns"> <button data-btn="recommend" data-active="0" class="btn btn-medium btn-icon btnLightGray mb_5 btn_like" data-squanchy="Recommend"> <svg class="icon iconThumbsUp"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconThumbsUp"></svg> </button> <button class="btn btn-medium btn-icon btnLightGray mb_5 btn_note" data-btn="add-user-note" data-squanchy="Add note"> <svg class="icon iconPencil"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconPencil"></svg> </button> <button class="btn btn-medium btn-icon btnLightGray btn_rate" data-global-dropdown-btn="tv-show-rating" data-squanchy="Rate"> <svg class="icon iconStar"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconStar"></svg> </button> <div class="user_score_indicator pos_rel hide" data-element="user-score-mobile"> 0,0 </div> <div class="details_menu hide" data-global-dropdown="tv-show-rating"> <ul> <div class="details_menu_header"> <span class="details_menu_title">My score</span> </div> <li data-star="101"> <div class="option_txt"> <svg class="icon iconCheckMark"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconCheckMark"></svg> No rating </div> </li> <li data-star="1"> <div class="option_txt"> 1 — The worst I've seen </div> </li> <li data-star="2"> <div class="option_txt"> 2 — Terrible </div> </li> <li data-star="3"> <div class="option_txt"> 3 — Barely watchable </div> </li> <li data-star="4"> <div class="option_txt"> 4 — Wasted my time </div> </li> <li data-star="5"> <div class="option_txt"> 5 — Meh </div> </li> <li data-star="6"> <div class="option_txt"> 6 — Not bad </div> </li> <li data-star="7"> <div class="option_txt"> 7 — Good </div> </li> <li data-star="8"> <div class="option_txt"> 8 — Excellent </div> </li> <li data-star="9"> <div class="option_txt"> 9 — Masterpiece </div> </li> <li data-star="10"> <div class="option_txt"> 10 — Film of the century </div> </li> </ul> </div> </div> <!-- Share btn --> <div class="share pos_rel"> <button class="btn-text fw_normal fs_small c_g4" data-global-dropdown-btn="tv-show-share"> <em>share</em> </button> <div class="details_menu even_padding hide" data-global-dropdown="tv-show-share"> <ul> <div class="details_menu_header"> <span class="details_menu_title">Share link <div class="fw_normal fs_tiny c_g5">https://www.toramp.com/shows/1793/</div> </span> </div> <li><a href="https://twitter.com/intent/tweet?url=https%3A%2F%2Fwww.toramp.com%2Fshows%2F1793%2F" rel="nofollow noopener" target="_blank">Twitter</a></li> <li><a href="https://t.me/share/url?url=https%3A%2F%2Fwww.toramp.com%2Fshows%2F1793%2F" rel="nofollow noopener" target="_blank">Telegram</a> <li><a href="https://vk.com/share.php?url=https%3A%2F%2Fwww.toramp.com%2Fshows%2F1793%2F" rel="nofollow noopener" target="_blank">VK</a></li> <li data-item="copy-link" class="link_to_copy"> <div class="option_txt">Copy link to clipboard</div> </li> </ul> </div> </div> </div> </section> <section class="series_stats mb_6 pb_6 border_b border_c0x bg_white"> <div class="users_total ta_center mb_2"> <div> <span class="num c_g1 fs_large">468</span> <span class="txt c_g2">users</span> </div> </div> <ul class="dis_flex justify_content_center"> <li class="pr_5"> <div class="dis_flex flex_items_center" data-squanchy="Watching 111 (23.7%)"> <svg class="icon iconTriangle"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconTriangle"></use></svg> <div class="c_g3 ml_2 no_pointer_events">111</div> </div> </li> <li class="pr_5"> <div class="dis_flex flex_items_center" data-squanchy="Want to see 229 (48.9%)"> <svg class="icon iconEye"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconEye"></svg> <div class="c_g3 ml_2 no_pointer_events">229</div> </div> </li> <li class="pr_5"> <div class="dis_flex flex_items_center" data-squanchy="On hold 26 (5.6%)"> <svg class="icon iconPause"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconPause"></svg> <div class="c_g3 ml_2 no_pointer_events">26</div> </div> </li> <li class="pr_5"> <div class="dis_flex flex_items_center" data-squanchy="Dropped 32 (6.8%)"> <svg class="icon iconDrop"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconDrop"></use></svg> <div class="c_g3 ml_2 no_pointer_events">32</div> </div> </li> <li> <div class="dis_flex flex_items_center" data-squanchy="Completed 70 (15%)"> <svg class="icon iconDoubleCheckMarks"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconDoubleCheckMarks"></use></svg> <div class="c_g3 ml_2 no_pointer_events">70</div> </div> </li> </ul> </section> <!-- MARK: Season navigation --> <section class="series_season_nav border_t border_b border_c0x pt_6 mb_6"> <div class="dis_flex flex_items_center border_rad_6 mb_6"> <div class="txt mr_4">Seasons:</div> <ul class="dis_flex link_list"> <li><a href="#season_special" title="Saenai Heroine no Sodatekata special episodes">S</a></li> <li><a href="#season_1" title="Saenai Heroine no Sodatekata season 1">1</a></li> <li><a href="#season_2" title="Saenai Heroine no Sodatekata season 2">2</a></li> </ul> <div class="pos_rel btn_mark_seasons_holder"> <button type="button" class="btn btn-small c_g2 btnActive" data-btn="show-mark-seasons">Mark <svg class="icon iconChevronDown"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconChevronDown"></svg></button> </div> </div> </section> <section class="series_details border_all border_c0x border_rad_6 shadow_a1 rm_shadow_at_1024 mb_6 overflow_h bg_white"> <header class="pl_5 pr_5 pt_3 pb_3 border_b border_c0x bg_gb1 ht_tw clearfix"> <h2 class="fs_small text_shadow_white">About this anime</h2> </header> <ul class="pad_16 row_hover"> <li class="dis_flex pt_3 pb_3 border_t border_b border_c1"> <span class="title mr_5">Status</span> <span class="val c_g3">🏁 finished/canceled</span> </li> <li class="dis_flex pt_3 pb_3 border_b border_c1"> <span class="title mr_5">Years</span> <span class="val c_g3">2015 &mdash; 2017</span> </li> <li class="dis_flex pt_3 pb_3 border_b border_c1"> <span class="title mr_5">Channel</span> <span class="val c_g3">Fuji TV</span> </li> <li class="dis_flex pt_3 pb_3 border_b border_c1"> <span class="title mr_5">Genres</span> <span class="val c_g3"> <a href="https://www.toramp.com/explore/shows/?genre=3" class="c_g3 rm_v">comedy</a> </span> </li> <li class="dis_flex pt_3 pb_3 border_b border_c1"> <span class="title mr_5">Tags</span> <span class="val c_g3"> - </span> </li> <li class="dis_flex pt_3 pb_3 border_b border_c1"> <span class="title mr_5">Original language</span> <span class="val c_g3">japanese</span> </li> <li class="dis_flex pt_3 pb_3 border_b border_c1"> <span class="title mr_5">Running time</span> <span class="val c_g3">25 <abbr title="Minutes">m</abbr> / 10.4 <abbr title="Hours">h</abbr> </span> </li> <li class="dis_flex pt_3 pb_3 border_b border_c1"> <span class="title mr_5">Alternative titles</span> <span class="val c_g3">Saenai Heroine no Sodatekata <sup class="c_g4"><abbr title="japanese">ja</abbr> + <abbr title="original title">orig</abbr></sup>, Как воспитать из обычной девушки героиню <sup class="c_g4"><abbr title="russian">ru</abbr></sup> </span> </li> </ul> </section> <section class="series_rating border_all border_c0x border_rad_6 shadow_a1 rm_shadow_at_1024 mb_6 overflow_h bg_white"> <header class="pl_5 pr_5 pt_3 pb_3 border_b border_c0x bg_gb1 ht_tw"> <h2 class="fs_small text_shadow_white">Anime score</h2> </header> <div class="rating_view pad_16"> <div class="ta_center mr_6"> <div class="fs_small c_g5 mb_1">score</div> <div class="fs_huge mb_1">6.71</div> <div class="fs_small c_g4 lh_1p3">73 <div>votes</div></div> </div> <div class="histogram"> <span data-squanchy="1 star — 5 votes (7%)" style="height: 7%;"></span> <span data-squanchy="2 stars — 1 votes (1%)" style="height: 1%;"></span> <span data-squanchy="3 stars — 0 votes (0%)" style="height: 0%;"></span> <span data-squanchy="4 stars — 1 votes (1%)" style="height: 1%;"></span> <span data-squanchy="5 stars — 3 votes (4%)" style="height: 4%;"></span> <span data-squanchy="6 stars — 8 votes (11%)" style="height: 11%;"></span> <span data-squanchy="7 stars — 10 votes (14%)" style="height: 14%;"></span> <span data-squanchy="8 stars — 12 votes (16%)" style="height: 16%;"></span> <span data-squanchy="9 stars — 13 votes (18%)" style="height: 18%;"></span> <span data-squanchy="10 stars — 20 votes (27%)" style="height: 27%;"></span> </div> </div> </section> <section class="border_all_dashed pad_16 border_rad_6 border_c0x bg_lightyellow mb_6"> <h1 class="border_b border_c1 pb_5 mb_5">Will there be season 3 of <span class="c_g2">“Saenai Heroine no Sodatekata”</span>?</h1> <div> <p class="mb_3"><em>No, the last season was the final one. Current anime status — finished/canceled.</em></p> <p class="mb_0">The anime consists of 2 seasons (25 episodes in total).</p> </div> </section> <div class="dis_flex flex_items_center justify_content_center pt_5 pb_5 mb_6"> <script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-8730893242604623" crossorigin="anonymous"></script> <!-- g_series_eps_content_top --> <ins class="adsbygoogle responsive_a1" style="display:inline-block" data-ad-client="ca-pub-8730893242604623" data-ad-slot="1678959005" data-full-width-responsive="true"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </div> <div class="dis_flex flex_items_center mb_6"> <div style="flex-grow:1;border-top: 2px dashed #d1d5da;"></div> <div class="uppercase pl_4 pr_4 c_g5">Seasons</div> <div style="flex-grow:1;border-top: 2px dashed #d1d5da;"></div> </div> <!-- MARK: Season eps --> <section class="series_seasons mb_6 border_all border_rad_6 border_c0x shadow_a1 rm_shadow_at_1024 overflow_h bg_white" id="season_2" data-season-number="2"> <header class="dis_flex flex_items_center pad_16 bg_gb1 ht_tw border_b border_c0x"> <div class="imgWrapper mr_4"> <img src="https://www.toramp.com/posters/shows/1793/width82/saenai_heroine_no_sodatekata.jpg"> </div> <div class="txt text_shadow_white"> <h2 class="mb_2" title="Saenai Heroine no Sodatekata season 2"> <div class="s dis_ib" data-season-header="2" data-season-unwatched-ep-count="11" data-season-aired-ep-count="11">season 2</div> </h2> <div class="dis_flex fs_tiny c_g3 flex_wrap"> <div>Episodes: <span class="c_g2" title="Total number of episodes (season 2)">11</span> </div> <div class="c_g5 ml_2 mr_2">/</div> <div>Marked as watched: <span class="c_g2" title="Number of episodes that you marked as watched" data-element="watched-episode-count">0</span> </div> </div> <button class="btn-text fs_tiny c_g3" data-btn="mark-season">Mark all episodes</button> </div> </header> <div class="pad_16"> <table class="base_table lh_1p3 series_eps_table"> <thead> <tr> <th title="Episode number" data-type="number" data-sort="default" data-sort-default="down"><span>#</span></th> <th class="fill_space ta_left unsortable"><span>Episode title</span></th> <th title="Release date" data-type="number" data-sort="default" data-sort-default="down" class="th_date"><span>Date</span></th> <th class="unsortable"><span>Actions</span></th> </tr> </thead> <tbody> <tr id="episode_2.1" data-episode-id="85849"> <td data-value="1"> <a href="#episode_2.1" class="se c_g2" title="Saenai Heroine no Sodatekata season 2 episode 1">2.01</a> </td> <td class="fill_space ta_left"> <div class="ft">Saenai Ry&umacr;ko no Aimie Kata</div> </td> <td class="date" data-value="1492128000"> <time datetime="2017-04-14" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 2 episode 1">April 14, 2017</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_2.2" data-episode-id="125427"> <td data-value="2"> <a href="#episode_2.2" class="se c_g2" title="Saenai Heroine no Sodatekata season 2 episode 2">2.02</a> </td> <td class="fill_space ta_left"> <div class="ft">Honki de Hont&omacr; na Bunki Ten</div> </td> <td class="date" data-value="1492732800"> <time datetime="2017-04-21" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 2 episode 2">April 21, 2017</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_2.3" data-episode-id="125428"> <td data-value="3"> <a href="#episode_2.3" class="se c_g2" title="Saenai Heroine no Sodatekata season 2 episode 3">2.03</a> </td> <td class="fill_space ta_left"> <div class="ft">Shok&omacr; to nik&omacr; to dai ch&omacr;k&omacr;</div> </td> <td class="date" data-value="1493337600"> <time datetime="2017-04-28" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 2 episode 3">April 28, 2017</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_2.4" data-episode-id="128100"> <td data-value="4"> <a href="#episode_2.4" class="se c_g2" title="Saenai Heroine no Sodatekata season 2 episode 4">2.04</a> </td> <td class="fill_space ta_left"> <div class="ft">Ni Haku San Nichi no Shinr&umacr;to</div> </td> <td class="date" data-value="1493942400"> <time datetime="2017-05-05" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 2 episode 4">May 5, 2017</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_2.5" data-episode-id="128101"> <td data-value="5"> <a href="#episode_2.5" class="se c_g2" title="Saenai Heroine no Sodatekata season 2 episode 5">2.05</a> </td> <td class="fill_space ta_left"> <div class="ft">Shimekiri ga saki ka&comma; kakusei ga saki ka</div> </td> <td class="date" data-value="1494547200"> <time datetime="2017-05-12" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 2 episode 5">May 12, 2017</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_2.6" data-episode-id="128102"> <td data-value="6"> <a href="#episode_2.6" class="se c_g2" title="Saenai Heroine no Sodatekata season 2 episode 6">2.06</a> </td> <td class="fill_space ta_left"> <div class="ft">Yuki ni umoreta masut&amacr;appu</div> </td> <td class="date" data-value="1495152000"> <time datetime="2017-05-19" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 2 episode 6">May 19, 2017</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_2.7" data-episode-id="128103"> <td data-value="7"> <a href="#episode_2.7" class="se c_g2" title="Saenai Heroine no Sodatekata season 2 episode 7">2.07</a> </td> <td class="fill_space ta_left"> <div class="ft">Ribenji-mamire no shin kikaku</div> </td> <td class="date" data-value="1495756800"> <time datetime="2017-05-26" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 2 episode 7">May 26, 2017</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_2.8" data-episode-id="128992"> <td data-value="8"> <a href="#episode_2.8" class="se c_g2" title="Saenai Heroine no Sodatekata season 2 episode 8">2.08</a> </td> <td class="fill_space ta_left"> <div class="ft">Furaggu o oranakatta</div> </td> <td class="date" data-value="1496361600"> <time datetime="2017-06-02" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 2 episode 8">June 2, 2017</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_2.9" data-episode-id="128993"> <td data-value="9"> <a href="#episode_2.9" class="se c_g2" title="Saenai Heroine no Sodatekata season 2 episode 9">2.09</a> </td> <td class="fill_space ta_left"> <div class="ft">Sotsugy&omacr;shiki to ch&omacr; tenkai</div> </td> <td class="date" data-value="1496966400"> <time datetime="2017-06-09" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 2 episode 9">June 9, 2017</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_2.10" data-episode-id="128994"> <td data-value="10"> <a href="#episode_2.10" class="se c_g2" title="Saenai Heroine no Sodatekata season 2 episode 10">2.10</a> </td> <td class="fill_space ta_left"> <div class="ft">Soshite ry&umacr;ko wa kami ni idoman</div> </td> <td class="date" data-value="1497571200"> <time datetime="2017-06-16" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 2 episode 10">June 16, 2017</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_2.11" data-episode-id="129568"> <td data-value="11"> <a href="#episode_2.11" class="se c_g2" title="Saenai Heroine no Sodatekata season 2 episode 11">2.11</a> </td> <td class="fill_space ta_left"> <div class="ft">Saiki to shinki no g&emacr;musut&amacr;to</div> </td> <td class="date" data-value="1498176000"> <time datetime="2017-06-23" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 2 episode 11">June 23, 2017</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> </tbody> </table> </div> </section> <section class="series_seasons mb_6 border_all border_rad_6 border_c0x shadow_a1 rm_shadow_at_1024 overflow_h bg_white" id="season_1" data-season-number="1"> <header class="dis_flex flex_items_center pad_16 bg_gb1 ht_tw border_b border_c0x"> <div class="imgWrapper mr_4"> <img src="https://www.toramp.com/posters/shows/1793/width82/saenai_heroine_no_sodatekata.jpg"> </div> <div class="txt text_shadow_white"> <h2 class="mb_2" title="Saenai Heroine no Sodatekata season 1"> <div class="s dis_ib" data-season-header="1" data-season-unwatched-ep-count="12" data-season-aired-ep-count="12">season 1</div> </h2> <div class="dis_flex fs_tiny c_g3 flex_wrap"> <div>Episodes: <span class="c_g2" title="Total number of episodes (season 1)">12</span> </div> <div class="c_g5 ml_2 mr_2">/</div> <div>Marked as watched: <span class="c_g2" title="Number of episodes that you marked as watched" data-element="watched-episode-count">0</span> </div> </div> <button class="btn-text fs_tiny c_g3" data-btn="mark-season">Mark all episodes</button> </div> </header> <div class="pad_16"> <table class="base_table lh_1p3 series_eps_table"> <thead> <tr> <th title="Episode number" data-type="number" data-sort="default" data-sort-default="down"><span>#</span></th> <th class="fill_space ta_left unsortable"><span>Episode title</span></th> <th title="Release date" data-type="number" data-sort="default" data-sort-default="down" class="th_date"><span>Date</span></th> <th class="unsortable"><span>Actions</span></th> </tr> </thead> <tbody> <tr id="episode_1.1" data-episode-id="74008"> <td data-value="1"> <a href="#episode_1.1" class="se c_g2" title="Saenai Heroine no Sodatekata season 1 episode 1">1.01</a> </td> <td class="fill_space ta_left"> <div class="ft">Machigai Darake no Puror&omacr;gu</div> </td> <td class="date" data-value="1421366400"> <time datetime="2015-01-16" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 1 episode 1">January 16, 2015</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_1.2" data-episode-id="74009"> <td data-value="2"> <a href="#episode_1.2" class="se c_g2" title="Saenai Heroine no Sodatekata season 1 episode 2">1.02</a> </td> <td class="fill_space ta_left"> <div class="ft">Furagu no Tatanai Kanojo</div> </td> <td class="date" data-value="1421971200"> <time datetime="2015-01-23" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 1 episode 2">January 23, 2015</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_1.3" data-episode-id="74010"> <td data-value="3"> <a href="#episode_1.3" class="se c_g2" title="Saenai Heroine no Sodatekata season 1 episode 3">1.03</a> </td> <td class="fill_space ta_left"> <div class="ft">Kuraimakkusu wa Riteiku de</div> </td> <td class="date" data-value="1422576000"> <time datetime="2015-01-30" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 1 episode 3">January 30, 2015</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_1.4" data-episode-id="74011"> <td data-value="4"> <a href="#episode_1.4" class="se c_g2" title="Saenai Heroine no Sodatekata season 1 episode 4">1.04</a> </td> <td class="fill_space ta_left"> <div class="ft">Yosan to N&omacr;ki to Shin Tenkai</div> </td> <td class="date" data-value="1423180800"> <time datetime="2015-02-06" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 1 episode 4">February 6, 2015</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_1.5" data-episode-id="74012"> <td data-value="5"> <a href="#episode_1.5" class="se c_g2" title="Saenai Heroine no Sodatekata season 1 episode 5">1.05</a> </td> <td class="fill_space ta_left"> <div class="ft">Surechigai no D&emacr;toibento</div> </td> <td class="date" data-value="1423785600"> <time datetime="2015-02-13" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 1 episode 5">February 13, 2015</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_1.6" data-episode-id="74013"> <td data-value="6"> <a href="#episode_1.6" class="se c_g2" title="Saenai Heroine no Sodatekata season 1 episode 6">1.06</a> </td> <td class="fill_space ta_left"> <div class="ft">Futari no Yoru no Sentakushi</div> </td> <td class="date" data-value="1424390400"> <time datetime="2015-02-20" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 1 episode 6">February 20, 2015</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_1.7" data-episode-id="74030"> <td data-value="7"> <a href="#episode_1.7" class="se c_g2" title="Saenai Heroine no Sodatekata season 1 episode 7">1.07</a> </td> <td class="fill_space ta_left"> <div class="ft">Teki ka Mikata ka Shin Kyara ka</div> </td> <td class="date" data-value="1424995200"> <time datetime="2015-02-27" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 1 episode 7">February 27, 2015</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_1.8" data-episode-id="77071"> <td data-value="8"> <a href="#episode_1.8" class="se c_g2" title="Saenai Heroine no Sodatekata season 1 episode 8">1.08</a> </td> <td class="fill_space ta_left"> <div class="ft">Ateuma Torauma Kais&omacr; M&omacr;do</div> </td> <td class="date" data-value="1425600000"> <time datetime="2015-03-06" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 1 episode 8">March 6, 2015</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_1.9" data-episode-id="77072"> <td data-value="9"> <a href="#episode_1.9" class="se c_g2" title="Saenai Heroine no Sodatekata season 1 episode 9">1.09</a> </td> <td class="fill_space ta_left"> <div class="ft">Hachi-nen-buri no Kobetsu R&umacr;to</div> </td> <td class="date" data-value="1426204800"> <time datetime="2015-03-13" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 1 episode 9">March 13, 2015</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_1.10" data-episode-id="77073"> <td data-value="10"> <a href="#episode_1.10" class="se c_g2" title="Saenai Heroine no Sodatekata season 1 episode 10">1.10</a> </td> <td class="fill_space ta_left"> <div class="ft">Omoide to Tekoire no Merodi</div> </td> <td class="date" data-value="1426809600"> <time datetime="2015-03-20" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 1 episode 10">March 20, 2015</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_1.11" data-episode-id="80018"> <td data-value="11"> <a href="#episode_1.11" class="se c_g2" title="Saenai Heroine no Sodatekata season 1 episode 11">1.11</a> </td> <td class="fill_space ta_left"> <div class="ft">Fukusen Kaish&umacr; Junbi Yoshi</div> </td> <td class="date" data-value="1427328000"> <time datetime="2015-03-26" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 1 episode 11">March 26, 2015</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_1.12" data-episode-id="80440"> <td data-value="12"> <a href="#episode_1.12" class="se c_g2" title="Saenai Heroine no Sodatekata season 1 episode 12">1.12</a> </td> <td class="fill_space ta_left"> <div class="ft">Haran to Gekid&omacr; no Nichij&omacr; Endo</div> </td> <td class="date" data-value="1427328000"> <time datetime="2015-03-26" class="nowrap " title="Release date of Saenai Heroine no Sodatekata season 1 episode 12">March 26, 2015</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> </tbody> </table> </div> </section> <section class="series_seasons mb_6 border_all border_rad_6 border_c0x shadow_a1 rm_shadow_at_1024 overflow_h bg_white" id="season_special" data-season-number="0"> <header class="dis_flex flex_items_center pad_16 bg_gb1 ht_tw border_b border_c0x"> <div class="imgWrapper mr_4"> <img src="https://www.toramp.com/posters/shows/1793/width82/saenai_heroine_no_sodatekata.jpg"> </div> <div class="txt text_shadow_white"> <h2 class="mb_2" title="Saenai Heroine no Sodatekata special episodes"> <div class="s dis_ib" data-season-header="0" data-season-unwatched-ep-count="2" data-season-aired-ep-count="2">special episodes</div> </h2> <div class="dis_flex fs_tiny c_g3 flex_wrap"> <div>Episodes: <span class="c_g2" title="Total number of special episodes">2</span> </div> <div class="c_g5 ml_2 mr_2">/</div> <div>Marked as watched: <span class="c_g2" title="Number of episodes that you marked as watched" data-element="watched-episode-count">0</span> </div> </div> <button class="btn-text fs_tiny c_g3" data-btn="mark-season">Mark all episodes</button> </div> </header> <div class="pad_16"> <table class="base_table lh_1p3 series_eps_table"> <thead> <tr> <th title="Episode number" data-type="number" data-sort="default" data-sort-default="down"><span>#</span></th> <th class="fill_space ta_left unsortable"><span>Episode title</span></th> <th title="Release date" data-type="number" data-sort="default" data-sort-default="down" class="th_date"><span>Date</span></th> <th class="unsortable"><span>Actions</span></th> </tr> </thead> <tbody> <tr id="episode_0.1" data-episode-id="74007"> <td data-value="1"> <a href="#episode_0.1" class="se c_g2" title="Saenai Heroine no Sodatekata episode 1">0.01</a> </td> <td class="fill_space ta_left"> <div class="ft">Ai to Seishun no S&amacr;bisu kai</div> </td> <td class="date" data-value="1420761600"> <time datetime="2015-01-09" class="nowrap " title="Release date of Saenai Heroine no Sodatekata episode 1">January 9, 2015</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> <tr id="episode_0.2" data-episode-id="128104"> <td data-value="2"> <a href="#episode_0.2" class="se c_g2" title="Saenai Heroine no Sodatekata episode 2">0.02</a> </td> <td class="fill_space ta_left"> <div class="ft">Fan Service of Love and Pure Heart</div> </td> <td class="date" data-value="1491436800"> <time datetime="2017-04-06" class="nowrap " title="Release date of Saenai Heroine no Sodatekata episode 2">April 6, 2017</time> </td> <td> <div class="bh"> <button class="btn btn-love mr_4" aria-label="Add to favorites" data-squanchy="Add to favorites" data-btn="favorite-episode"></button> <button class="btn btn-cb btn-cb-h20 checked-bg-green" aria-label="Mark as watched" data-squanchy="Mark as watched" data-btn="mark-episode"></button> </div> </td> </tr> </tbody> </table> </div> </section> </div> <!-- series_main_div --> </div> <!-- container pos_rel --> </div> <!-- page_container_wrapper --> </main> <script type="application/ld+json">{"@context":"https://schema.org","@type":"TVSeries","name":"Saenai Heroine no Sodatekata","url":"https://www.toramp.com/shows/1793/","image":"https://www.toramp.com/posters/shows/1793/width360/saenai_heroine_no_sodatekata.jpg","numberOfSeasons":2,"numberOfEpisodes":25,"dateCreated":"2015-01-09T00:00:00+0000","datePublished":"2015-01-09T00:00:00+0000","startDate":"2015-01-09T00:00:00+0000","endDate":"2017-06-23T00:00:00+0000","aggregateRating":{"@type":"AggregateRating","worstRating":1,"bestRating":10,"ratingValue":6.71,"ratingCount":73},"genre":["Comedy"],"containsSeason":[{"@type":"TVSeason","name":"Season 2","datePublished":"2017-04-14T00:00:00+0000","startDate":"2017-04-14T00:00:00+0000","endDate":"2017-06-23T00:00:00+0000","seasonNumber":2,"numberOfEpisodes":11},{"@type":"TVSeason","name":"Season 1","datePublished":"2015-01-16T00:00:00+0000","startDate":"2015-01-16T00:00:00+0000","endDate":"2015-03-26T00:00:00+0000","seasonNumber":1,"numberOfEpisodes":12}]}</script> </div> <footer> <div class="footer_wraper"> <nav class="container"> <a class="logo c_g1 rm_v" href="https://www.toramp.com/en/"> <div><svg class="icon iconLogo" width="22px" height="16px"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconLogo"></svg></div> <div class="txt">TORAMP</div> </a> <ul> <li class="mr_5"><a class="c_g4 rm_v" href="https://www.toramp.com/contacts/">Contacts</a></li> <li class="mr_5"><a class="c_g4 rm_v" href="https://www.toramp.com/privacy/">Privacy</a></li> <li class="mr_5"><a class="c_g4 rm_v" href="https://www.toramp.com/terms/">Terms</a></li> <li><div class="change_lang dis_ib" data-select="lang"><svg class="icon iconChevronDown"><use xlink:href="https://www.toramp.com/svg/icons.svg#iconChevronDown"></svg> <span>English</span></div></li> </ul> </nav> </div> </footer> <script type="application/javascript"> let base_url = pageSettings.global.base_url, BASE_URL_LANG = pageSettings.global.base_url_lang, base_src = pageSettings.global.base_src; const LANGUAGE = pageSettings.global.language; var SPINNER_TIME = 500; // ms function makeHttpRequest(path, params, cb) { var xmlhttp, p = '', ajaxToken, lang = ''; ajaxToken = getCookie('ajax_token'); if (typeof ajaxToken === 'undefined') { console.log("[error] ajaxToken is undefined"); return; } if (isEmptyObject(params)) { p = null; } else { for (var key in params) { if (p) p += '&'; p += key + '=' + encodeURIComponent(params[key]); } console.log(p); } xmlhttp = getXmlHttp(); xmlhttp.open('POST', path, true); xmlhttp.setRequestHeader('X-CSRF-TOKEN', ajaxToken); xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xmlhttp.onreadystatechange = function() { if (this.readyState != 4) return; if (this.status != 200) { console.log( xhr.status + ': ' + xhr.statusText ); return; } cb(xmlhttp.responseText); }; xmlhttp.send(p); } function getCookie(name) { var matches = document.cookie.match(new RegExp( "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)" )); return matches ? decodeURIComponent(matches[1]) : undefined; } function isEmptyObject(obj) { for (var i in obj) { if (obj.hasOwnProperty(i)) { return false; } } return true; } function getXmlHttp() { try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (ee) { } } if (typeof XMLHttpRequest != 'undefined') { return new XMLHttpRequest(); } } var fnDelay = (function() { var timer = 0; return function(callback, ms) { clearTimeout(timer); timer = setTimeout(callback, ms); }; })(); function debounce(fn, interval) { var timer; return function debounced() { clearTimeout(timer); var args = arguments; var that = this; timer = setTimeout(function callOriginalFn() { fn.apply(that, args); }, interval); }; } function createSVGSpinner() { var span = document.createElement('span'); span.classList.add('svgSpinner'); return span; } // ... var isMobile = { Android: function() { return navigator.userAgent.match(/Android/i); }, BlackBerry: function() { return navigator.userAgent.match(/BlackBerry/i); }, iOS: function() { return navigator.userAgent.match(/iPhone|iPad|iPod/i); }, Opera: function() { return navigator.userAgent.match(/Opera Mini/i); }, Windows: function() { return navigator.userAgent.match(/IEMobile/i); }, any: function() { return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows()); } }; function createSvg(svgClass, useXlink) { var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'), use = document.createElementNS('http://www.w3.org/2000/svg', 'use'); if (typeof svgClass === 'undefined') { svgClass = 'icon iconCircle'; useXlink = base_src + '/svg/icons.svg#iconCircle'; } svg.setAttribute('class', svgClass); use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', useXlink); svg.appendChild(use); return svg; } //// Tooltip //// (function() { if (isMobile.any()) return; var currentElement = null; var elementTooltip = document.createElement('div'); var squanchyTriangle = createSvg('icon iconTriangleDown hide', base_src + '/svg/icons.svg#iconTriangleDown'); var movieInfo = []; var showInfo = []; document.body.appendChild(squanchyTriangle); function handler(event) { var target = event.target, params = {}; if (currentElement) { return; } if (target.nodeType !== 1) { return; } if (target.hasAttribute('data-squanchy')) { currentElement = target; elementTooltip.className = 'squanchy'; elementTooltip.innerHTML = target.getAttribute('data-squanchy'); showTooltip(target, elementTooltip); } else { return; } } function handlerInfo(event) { var target = event.target, params = {}; if (currentElement) { return; } if (target.nodeType !== 1) { return; } if (target.hasAttribute('data-movie-info')) { currentElement = target; elementTooltip.className = 'tooltip_with_poster'; params.id = target.getAttribute('data-movie-info'); if (movieInfo[params.id]) { elementTooltip.innerHTML = movieInfo[params.id]; showTooltip(target, elementTooltip, {type: 'movie'}); } else { makeHttpRequest(pageSettings.global.movieTooltip.path, params, function(responseText) { if (!responseText) return; elementTooltip.innerHTML = responseText; movieInfo[params.id] = responseText; showTooltip(target, elementTooltip, {type: 'movie'}); }); } } else if (target.hasAttribute('data-show-info')) { currentElement = target; elementTooltip.className = 'tooltip_with_poster'; params.id = target.getAttribute('data-show-info'); if (showInfo[params.id]) { elementTooltip.innerHTML = showInfo[params.id]; showTooltip(target, elementTooltip, {type: 'movie'}); } else { makeHttpRequest(pageSettings.global.showTooltip.path, params, function(responseText) { if (!responseText) return; elementTooltip.innerHTML = responseText; showInfo[params.id] = responseText; showTooltip(target, elementTooltip, {type: 'movie'}); }); } } else if (target.hasAttribute('data-show-info-without-poster')) { currentElement = target; elementTooltip.className = 'tooltip_with_poster'; params.id = target.getAttribute('data-show-info-without-poster'); if (showInfo[params.id]) { elementTooltip.innerHTML = showInfo[params.id]; showTooltip(target, elementTooltip, {type: 'movie'}); } else { params.without_poster = 1; makeHttpRequest(pageSettings.global.showTooltip.path, params, function(responseText) { if (!responseText) return; elementTooltip.innerHTML = responseText; showInfo[params.id] = responseText; showTooltip(target, elementTooltip, {type: 'movie'}); }); } } else { return; } } var delayHandlerInfo = debounce(handlerInfo, 300); document.addEventListener("mouseover", delayHandlerInfo); document.addEventListener("mouseover", handler); document.onmouseout = hideTooltip; window.addEventListener('scroll', hideTooltip); function hideTooltip() { if (!currentElement) { return; } document.body.removeChild(elementTooltip); squanchyTriangle.classList.add('hide'); currentElement = null; } function showTooltip(target, elementTooltip, settings) { var coords, top = 0, left = 0, right = 0, ri = false; var marginLeft = 16, marginRight = 16, marginFromTarget = 8, heightAwesomeBar = 50; var classMovie = { up: 'triangle_up_for_poster_tooltip', down: 'triangle_down_for_poster_tooltip' }; coords = target.getBoundingClientRect(); document.body.appendChild(elementTooltip); top = coords.top - elementTooltip.offsetHeight - marginFromTarget; topTriangle = coords.top - marginFromTarget; left = coords.left + (target.offsetWidth - elementTooltip.offsetWidth) / 2; right = coords.right + Math.abs((target.offsetWidth - elementTooltip.offsetWidth) / 2); if (top < heightAwesomeBar) { top = coords.top + target.offsetHeight + marginFromTarget; topTriangle = coords.top + marginFromTarget - 4 + target.offsetHeight; if (!squanchyTriangle.classList.contains('iconTriangleUp')) { squanchyTriangle.classList.remove('iconTriangleDown'); squanchyTriangle.classList.add('iconTriangleUp'); } if (settings && settings.type && settings.type == 'movie') { if (!squanchyTriangle.classList.contains(classMovie.up)) { squanchyTriangle.classList.remove(classMovie.down); squanchyTriangle.classList.add(classMovie.up); } } else { squanchyTriangle.classList.remove(classMovie.up); squanchyTriangle.classList.remove(classMovie.down); } } else { if (!squanchyTriangle.classList.contains('iconTriangleDown')) { squanchyTriangle.classList.remove('iconTriangleUp'); squanchyTriangle.classList.add('iconTriangleDown'); } if (settings && settings.type && settings.type == 'movie') { if (!squanchyTriangle.classList.contains(classMovie.down)) { squanchyTriangle.classList.remove(classMovie.up); squanchyTriangle.classList.add(classMovie.down); } } else { squanchyTriangle.classList.remove(classMovie.up); squanchyTriangle.classList.remove(classMovie.down); } } if (left < 0) { left = marginLeft; } else if (right > document.body.offsetWidth) { ri = true; } if (ri) { elementTooltip.style.right = marginRight + 'px'; } else { elementTooltip.style.left = left + 'px'; } elementTooltip.style.top = top + 'px'; squanchyTriangle.style.left = (coords.right - 5 - target.offsetWidth / 2) + 'px'; squanchyTriangle.style.top = topTriangle + 'px'; squanchyTriangle.classList.remove('hide'); } })(); var globalDropdown = (function () { 'use strict'; var thCurrent = function() {}; function setCurrent(current) { thCurrent(); thCurrent = current; } function hide(target) { thCurrent(target); thCurrent = function() {}; } return { setCurrent: setCurrent, hide: hide }; })(); (function () { 'use strict'; function clickDropdown(event) { var target = event.target; if (!target.closest('[data-global-dropdown]') && !target.closest('[data-global-dropdown-btn]')) { globalDropdown.hide(target); } } document.body.addEventListener('click', clickDropdown, false); })(); (function(opts) { 'use strict'; var globalSearch = document.querySelector('nav.gnav'), iconSearch = globalSearch.querySelector('label.searchLabel'), inputSearch = document.getElementById('globalSearchInput'), searchBtnCancel = globalSearch.querySelector('[data-global-search="cancel"]'), elementSearchResult = globalSearch.querySelector('div[data-global-search="results"]'), elementSearchNav = elementSearchResult.querySelector('nav'); var activeSearch = false, currentSection = 2, searchSection = 2, val = '', focusElem; var actionSearchNav = function(e) { var element = e.target, activeElement = elementSearchNav.querySelector('label.active'); if (activeSearch) return; if (!element.hasAttribute('data-global-search-nav')) return; searchSection = element.getAttribute('data-global-search-nav'); if (activeElement) { activeElement.classList.remove('active'); } element.classList.add('active'); if (inputSearch.value) { searchAll(); } }; var showSearch = function() { if (globalSearch.classList.contains('searchMode')) return; globalSearch.classList.add('searchMode'); var modal = document.body.querySelectorAll('[data-modal]'), i, l; var modalBtns = document.body.querySelectorAll('[data-modal-btn]'); for (i = 0, l = modal.length; i < l; ++i) { modal[i].classList.add('hide'); } for (i = 0, l = modalBtns.length; i < l; ++i) { if (modalBtns[i].classList.contains('btnActive')) { modalBtns[i].classList.remove('btnActive'); } } if (inputSearch.value) { searchAll(); } }; var hideSearch = function() { globalSearch.classList.remove('searchMode'); }; var clickHideSearch = function(event) { var target = event.target; if ( !target.closest('#globalSearchInput') && !target.closest('.globalSearchResultsWrapper') && !target.closest('.searchLabel') ) { hideSearch(); } }; var searchAll = function() { var params = {}, timerId; if (searchSection == currentSection && inputSearch.value == val) { return; } val = inputSearch.value; if (!val) { removeResults(); return; } showSearch(); activeSearch = true; params.value = val; params.db = searchSection; currentSection = searchSection; timerId = setTimeout(function() { removeResults(); globalSearchStatus(opts.global.search.text.searching); }, 500); makeHttpRequest(opts.global.search.path, params, function(responseText) { clearTimeout(timerId); console.log('httpRequest'); focusElem = undefined; activeSearch = false; val = inputSearch.value; if (!val) return; removeResults(); if (responseText) { elementSearchResult.insertAdjacentHTML('beforeend', responseText); } else { globalSearchStatus(opts.global.search.text.noResults); } }); }; var removeResults = function() { var ulResults = globalSearch.querySelector('[data-global-search="ul-results"]'); if (ulResults) ulResults.parentNode.removeChild(ulResults); removeView('search_status'); }; var globalSearchStatus = function(text, idStatus) { var div = document.createElement('div'); if (idStatus === undefined) { idStatus = 'search_status'; } removeView(idStatus); div.id = idStatus; div.classList.add('SearchStatus'); div.innerHTML = text; elementSearchResult.appendChild(div); }; if (elementSearchNav) { elementSearchNav.addEventListener('click', actionSearchNav, false); elementSearchNav.addEventListener('touchend', actionSearchNav, false); } searchBtnCancel.addEventListener('click', hideSearch, false); document.body.addEventListener('click', clickHideSearch, false); iconSearch.addEventListener('click', showSearch, false); iconSearch.addEventListener('touchend', showSearch, false); inputSearch.addEventListener('focus', function() { showSearch(); }, false); inputSearch.addEventListener('input', function() { fnDelay(function() { searchAll(); }, 250); }, false); inputSearch.addEventListener('keyup', function(event) { event.preventDefault(); if (event.keyCode === 27) { inputSearch.blur(); // divDarkBG.hide(); hideSearch(); } }); inputSearch.addEventListener('keydown', function(event) { var list = elementSearchResult.querySelector('[data-global-search="ul-results"]'); if (inputSearch.value == '') return; if (event.keyCode === 13) { if (list && list.querySelector('a.focused')) { window.location = list.querySelector('a.focused').href; } else { window.location = opts.global.search.url + encodeURIComponent(inputSearch.value); } } if (!list) { return; } if (event.keyCode == 38) { if (focusElem) { focusElem.querySelector('a').classList.remove('focused'); focusElem = focusElem.previousElementSibling; focusElem = (focusElem !== null) ? focusElem : list.lastElementChild; } else { focusElem = list.lastElementChild; } focusElem.querySelector('a').classList.add('focused'); console.log(38); } if (event.keyCode == 40) { if (focusElem) { focusElem.querySelector('a').classList.remove('focused'); focusElem = focusElem.nextElementSibling; focusElem = (focusElem !== null) ? focusElem : list.firstElementChild; } else { focusElem = list.firstElementChild; } focusElem.querySelector('a').classList.add('focused'); console.log(40); } }); })(pageSettings); // Choose language var modalChooseLanguage = (function () { 'use strict'; var modal, specialPage = false, texts = {}, items = {}, langChecked; function setTexts(obj) { texts = obj; } function setItems(obj) { items = obj; } function setLang(checked) { langChecked = checked; } function setSpecialPage(checked) { specialPage = checked; } function show() { divDarkBG.show(hideDarkBG); if (!modal) { modal = create(); modal.addEventListener('change', handlerChange, false); document.body.appendChild(modal); } else { modal.classList.remove('hide'); } } function hideDarkBG(e) { var element = e.target; if (!divDarkBG.isDarkBG(element)) { return; } hide(); } function hide() { divDarkBG.hide(); modal.classList.add('hide'); } function create() { return createModalTiny(createBody()); } function createBody() { var section = document.createElement('section'), h3 = document.createElement('h3'); section.className = 'SECTION'; h3.textContent = texts.header; section.appendChild(h3); for (var key in items) { var checked = (items[key].language === langChecked) ? true : false; section.appendChild(inputControls.createRadio(items[key].title, items[key].data, checked)); } return section; } function handlerChange(event) { var element = event.target, pathname = '', changeLocale = '', changeLang = element.parentNode.getAttribute('data-value') || ''; var key, date; if (element.checked && langChecked != changeLang) { if (specialPage) { if (changeLang) { changeLang = '/' + changeLang; } for (key in items) { if ('/' + items[key].data + '/' === location.pathname.substr(0,4)) { pathname = location.pathname.substr(3); break; } } if (!pathname) { pathname = location.pathname; } date = new Date(new Date().getTime() + 24*60*60 * 1000); document.cookie = "language=" + encodeURIComponent(changeLocale) + "; path=/; expires=" + date.toUTCString(); location = location.protocol + '//' + location.host + changeLang + pathname + location.search; } else { let LocationPath = ''; if (!changeLang) changeLang = undefined; for (key in items) { if (items[key].data == changeLang) { changeLocale = items[key].locale; if (items[key].url) { LocationPath = items[key].url; } break; } } date = new Date(new Date().getTime() + 24*60*60 * 1000); document.cookie = "language=" + encodeURIComponent(changeLocale) + "; path=/; expires=" + date.toUTCString(); if (LocationPath) { location = LocationPath; } else { location.reload(); } } } } return { show: show, setTexts: setTexts, setItems: setItems, setLang: setLang, setSpecialPage: setSpecialPage }; })(); (function (opts) { 'use strict'; var elLang = document.querySelector('footer [data-select="lang"]'); if (!elLang) return; modalChooseLanguage.setLang(opts.global.lang.checked); modalChooseLanguage.setSpecialPage(opts.global.lang.specialPage); modalChooseLanguage.setItems(opts.global.lang.items); modalChooseLanguage.setTexts(opts.global.lang.texts); elLang.addEventListener('click', function() { modalChooseLanguage.show(); }); })(pageSettings); var divDarkBG = (function () { var hideClick; var show = function(funHide) { var bg = document.getElementById('dark_bg'); if (funHide === undefined) { document.body.removeEventListener('click', hideClick, false); document.body.addEventListener('click', hide, false); hideClick = hide; } else { document.body.removeEventListener('click', hideClick, false); document.body.addEventListener('click', funHide, false); hideClick = funHide; } if (bg) { bg.className = 'DarkBG-visible'; } else { bg = document.createElement("div"); bg.id = 'dark_bg'; bg.className = 'DarkBG-visible'; document.body.appendChild(bg); } }; var hide = function(e) { if (e.target.className === 'DarkBG-visible') { e.target.className = 'DarkBG-invisible'; } }; var hideP = function() { var bg = document.getElementById('dark_bg'); bg.className = 'DarkBG-invisible'; }; function isDarkBG(element) { return ( element.classList.contains('DarkBG-visible') || element.classList.contains('ModalBox') ); } return { show:show, hide:hideP, isDarkBG:isDarkBG, }; })(); // Modal function createModalTiny(bodyModal, opts) { return createModal(bodyModal, opts, 'ModalTiny'); } function createModal(bodyModal, opts, modalClass) { var divModal = document.createElement('div'), divBox = document.createElement('div'), divBG = document.createElement('div'); var modalClassName = 'Modal'; if (modalClass) { modalClassName += ' ' + modalClass; } divModal.className = modalClassName; divBox.className = 'ModalBox'; divBG.className = 'ModalBG'; if (opts && opts.modal) { if (opts.modal.data) { setAttrsData(divModal, opts.modal.data); } if (opts.modal.id) { divModal.id = opts.modal.id; } } divBG.appendChild(bodyModal); divBox.appendChild(divBG); divModal.appendChild(divBox); return divModal; } var inputControls = { createCheckbox: function(opts) { var label = document.createElement('label'), input = document.createElement('input'), span = document.createElement('span'), svg = createSvg('icon iconCheckMark', base_src + '/svg/icons.svg#iconCheckMark'), textNode = document.createTextNode(opts.text); if (typeof opts.input === 'undefined') { opts.input = {}; } if (typeof opts.label === 'undefined') { opts.label = {}; } opts.checked = (opts.checked) ? true : false; // Input input.type = 'checkbox'; input.name = 'checkbox'; input.checked = opts.checked; setAttrsData(input, opts.input.data); // Span span.className = 'indicator'; span.appendChild(svg); // Label label.className = 'inputControls checkbox'; setAttrsData(label, opts.label.data); label.appendChild(input); label.appendChild(span); label.appendChild(textNode); return label; }, createRadio: function(text, data, checked) { var label = document.createElement('label'), input = document.createElement('input'), span = document.createElement('span'), svg = createSvg('icon iconCircle', base_src + '/svg/icons.svg#iconCircle'), textNode = document.createTextNode(text); if (typeof checked === 'undefined') { checked = false; } label.className = 'inputControls radio'; if (data) { label.setAttribute('data-value', data); } input.type = 'radio'; input.name = 'radio'; input.checked = checked; span.className = 'indicator'; span.appendChild(svg); label.appendChild(input); label.appendChild(span); label.appendChild(textNode); return label; }, // createSwitch: function(item) { // return label // } }; function removeView(idView) { var view = document.getElementById(idView); if (view) { view.parentNode.removeChild(view); } } (function() { 'use strict'; var elemProfile = document.querySelector('nav [data-global-dropdown-btn="global_nav_profile"]'); var elemProfileDropdown = document.querySelector('[data-global-dropdown="global_nav_profile"]'); function handler() { if (elemProfileDropdown.classList.contains('hide')) { elemProfileDropdown.classList.remove('hide'); globalDropdown.setCurrent(function() { elemProfileDropdown.classList.add('hide'); }); } else { globalDropdown.hide(); } } if (elemProfile) { elemProfile.addEventListener('click', handler, false); } })(); // Shortcuts var shortcuts = (function() { 'use strict'; var keyCombos = []; var timer = { 'num' : null }; var kCodes = { 'g' : 71, 'h' : 72, 'c' : 67, 'm' : 77, 's' : 83, 'p' : 80, 'e' : 69, }; var strCombos = { 'gh' : kCodes['g'].toString() + kCodes['h'].toString(), 'ge' : kCodes['g'].toString() + kCodes['e'].toString(), 'gc' : kCodes['g'].toString() + kCodes['c'].toString(), 'gm' : kCodes['g'].toString() + kCodes['m'].toString(), 'gs' : kCodes['g'].toString() + kCodes['s'].toString(), 'gp' : kCodes['g'].toString() + kCodes['p'].toString(), }; function isFullNav() { if (document.getElementById('gnav_full')) { return true; } return false; } function isInputOrTextareaHasFocus() { var activeElement = document.activeElement; var inputs = ['input', 'textarea']; if (inputs.indexOf(activeElement.tagName.toLowerCase()) !== -1) { return true; } return false; } function onPress(event) { // Bail out if user is editing. if (isInputOrTextareaHasFocus()) { return; } // If one of the supported keys are pressed create a keycombo. if ((Object.keys(kCodes).map(function(x) { return kCodes[x]; })).includes(event.keyCode)) { keyCombos.push(event.keyCode); // make sure that string does not get huge. keyCombos = keyCombos.length > 2 ? keyCombos.slice(-2) : keyCombos; // Reset key combos after `n` seconds so that we don't trigger them // accidentally. var n = 1.5; if (timer['num']) { clearTimeout(timer['num']); } timer['num'] = setTimeout(function() { keyCombos = []; }, n * 1000); } var combo = keyCombos.join(''); if (event.key === '/') { // `/` (search) document.getElementById('globalSearchInput').focus(); } else if (combo == strCombos['gh']) { keyCombos = []; window.location.href = BASE_URL_LANG; } else if (combo == strCombos['ge']) { keyCombos = []; window.location.href = BASE_URL_LANG + "/explore/shows/"; } else if (combo == strCombos['gm'] && isFullNav()) { keyCombos = []; window.location.href = base_url + "/not-watched/movies/"; } else if (combo == strCombos['gs'] && isFullNav()) { keyCombos = []; window.location.href = base_url + "/not-watched/episodes/"; } else if (combo == strCombos['gc'] && isFullNav()) { keyCombos = []; window.location.href = base_url + "/contributions/waiting-for-conformation/"; } else if (combo == strCombos['gp'] && isFullNav()) { keyCombos = []; window.location.href = "/" + document.getElementById('user_profile_link').getAttribute('data-username'); } } return { f: onPress }; })(); document.addEventListener('keyup', shortcuts.f); function numDeclension(n, titles) { n = Math.abs(n) % 100; var n1 = n % 10; if (n > 10 && n < 20) { return titles[2]; } if (n1 > 1 && n1 < 5) { return titles[1]; } if (n1 == 1) { return titles[0]; } return titles[2]; } //// Tv show mark episodes //// var dropdownMarkSeasons = (function () { 'use strict'; var elementBtn; var elementDropdown; var items = {}; function setItems(obj) { items = obj; } function setElement(element) { if (elementBtn === element) { globalDropdown.setCurrent(function() {}); } else { globalDropdown.setCurrent(function(element) { if (!elementBtn) return; if (!elementDropdown) return; if (element.hasAttribute('data-btn') && element.getAttribute('data-btn') == 'show-mark-seasons') return; stop(); }); // Init elementBtn = element; elementDropdown = createDropdown(); elementBtn.insertAdjacentElement('afterEnd', elementDropdown); } } function createDropdown() { var elemMain = document.createElement('div'); var elemUL = document.createElement('ul'); var sum = 0; elemMain.className = 'details_menu'; for (var i = 0; i < items.length; i++) { elemUL.appendChild( createItem( { title: items[i].textContent, season: items[i].getAttribute('data-season-header'), numEps: items[i].getAttribute('data-season-unwatched-ep-count') } ) ); sum += parseInt(items[i].getAttribute('data-season-unwatched-ep-count')); } elemUL.appendChild( createItem( { title: 'all episodes', season: 'all', numEps: sum } ) ); elemMain.appendChild(elemUL); function createItem(item) { let elemLI = document.createElement('li'), elemOpt = document.createElement('div'), elemNumEps = document.createElement('span'), elemIcon = document.createElement('i'), svgIcon = createSvg('icon iconCheckMark', base_src + '/svg/icons.svg#iconCheckMark'); let declension = (item.numEps == 1) ? 'episode' : 'episodes'; if (LANGUAGE == 'ru') { declension = numDeclension(item.numEps, ['серия', 'серии', 'серий']); } elemNumEps.textContent = item.numEps + ' ' + declension; elemNumEps.className = 'explain_txt float_r'; elemOpt.textContent = item.title; elemOpt.className = 'option_txt'; if (item.numEps == '0') { elemIcon.appendChild(svgIcon); elemLI.appendChild(elemIcon); elemLI.className = 'checked_true'; } elemLI.setAttribute('data-mark-season', item.season); elemOpt.appendChild(elemNumEps); elemLI.appendChild(elemOpt); return elemLI; } return elemMain; } function stop() { elementBtn = undefined; if (elementDropdown) { elementDropdown.parentNode.removeChild(elementDropdown); elementDropdown = undefined; } } function isActive() { return Boolean(elementDropdown); } return { setElement: setElement, isActive: isActive, stop: stop, setItems: setItems }; })(); function escapeHtml(text) { var map = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#039;' }; return text.replace(/[&<>"']/g, function(m) { return map[m]; }); } function removeSpaces(str) { return str.trim().replace(/ +/g," "); } </script> <script type="application/javascript"> (function(pageOpts) {'use strict'; let TVShowID = document.body.getAttribute('data-id'); let elementRating = document.body.querySelector('div[data-tv-show="change-rating"]'), elementRatingMobileBtn = document.body.querySelector('[data-global-dropdown-btn="tv-show-rating"]'), elementRatingMobileDropdown = document.body.querySelector('[data-global-dropdown="tv-show-rating"]'), elementUserRatingMobile = document.body.querySelector('[data-element="user-score-mobile"]'), elementUserStatusMobileBtn = document.body.querySelector('[data-global-dropdown-btn="tv-show-user-status-mobile"]'), elementUserStatusMobileDropdown = document.body.querySelector('[data-global-dropdown="tv-show-user-status-mobile"]'), elementUserNoteText = document.body.querySelector('[data-element="user-note-text"]'), elementCast = document.body.querySelector('[data-tv-show="cast"]'), elementCrew = document.body.querySelector('[data-tv-show="crew"]'); let elementShareBtn = document.body.querySelector('[data-global-dropdown-btn="tv-show-share"]'), elementShareDropdown = document.body.querySelector('[data-global-dropdown="tv-show-share"]'), elementShareDropdownURL = elementShareDropdown.querySelector('span.details_menu_title div'); let elementUserProgress = document.body.querySelector('[data-element="user-progress"]'), elementUserProgressPercent = document.body.querySelector('[data-element="user-progress-percent"]'), elementUserProgressBar = document.body.querySelector('[data-element="user-progress-bar"]'), elementUserProgressText = document.body.querySelector('[data-element="user-progress-text"]'); //// Input //// function handleInput(event) { let element = event.target; if (!element.hasAttribute('data-input')) return; switch (element.getAttribute('data-input')) { case 'user-note': toggleButtonSaveTextarea(element, element.parentNode.querySelector('button[data-btn="save-user-note"]')); break; default: break; } } function toggleButtonSaveTextarea(element, elementBtn) { if (element.value !== element.textContent) { elementBtn.disabled = false; } else { elementBtn.disabled = true; } } //// Click //// function handleClick(event) { let element = event.target; if (element.hasAttribute('data-btn')) { handleButtonClick(element); } if (element.hasAttribute('data-nav')) { handleNavClick(element); } if (element.hasAttribute('data-item')) { handleItemClick(element); } if (element.hasAttribute('data-modal-trailer')) { showModalTrailer(element); } if (element.hasAttribute('data-modal-trailer-nav')) { showTrailer(element); } if (element.hasAttribute('data-mark-season')) { markSeasonAsWatchedDropdown(element); } if (element.classList.contains('overlay_dark')) { handleClickDark(element); } } //// Buttons function handleButtonClick(elementBtn) { switch (elementBtn.getAttribute('data-btn')) { case 'hide-modal-login': hideDark(); hideModalLogin(elementBtn); break; case 'close-modal-trailer': hideDark(); hideModalTrailer(elementBtn); break; case 'show-all-cast': showAllCast(elementBtn); break; case 'show-all-crew': showAllCrew(elementBtn); break; // User actions case 'user-status-decktop': changeUserStatusDecktop(elementBtn); break; case 'change-rating': changeRating(elementBtn); break; case 'recommend': recommend(elementBtn); break; // User note case 'add-user-note': case 'edit-user-note': showModalUserNote(); break; case 'hide-modal-user-note': hideDark(); hideModalUserNote(elementBtn); break; case 'save-user-note': saveUserNote(elementBtn); break; case 'delete-user-note': deleteUserNote(elementBtn); break; // Episodes case 'mark-episode': markEpisodeAsWatched(elementBtn); break; case 'favorite-episode': addToFavorites(elementBtn); break; case 'mark-season': markSeasonAsWatchedButton(elementBtn); break; case 'show-mark-seasons': showDropdownMarkSeasons(elementBtn); break; case 'edit-mode': toggleEditMode(); break; default: break; } } function hideModalLogin() { if (!elementModalLogin) return; document.body.removeChild(elementModalLogin); elementModalLogin = undefined; } function hideModalTrailer() { if (!elementModalTrailer) return; document.body.removeChild(elementModalTrailer); elementModalTrailer = undefined; } // Makers function showAllCast(element) { let items = elementCast.querySelectorAll('li.hide'); element.classList.add('hide'); items.forEach(function(item) { item.classList.remove('hide'); }); } function showAllCrew(element) { let items = elementCrew.querySelectorAll('li.hide'); element.classList.add('hide'); items.forEach(function(item) { item.classList.remove('hide'); }); } // User status function changeUserStatusDecktop(element) { let params = {}; let status = element.getAttribute('data-my-status'); let activeUserStatus = element.parentNode.querySelector('button.selected'); if (!pageOpts.isLoggedIn) { redirect_to_login(); return; } if (status == 'no_status') { elementUserProgress.classList.add('hide'); // Disable the progress tab and switch to trailers. let userProgressLi = document.body.querySelector('[data-nav="series_user_progress"]'); userProgressLi.classList.toggle('disabled'); userProgressLi.parentNode.querySelector('.selected').classList.toggle('selected'); // rm prev selection. let infoSwitcher = document.getElementById("info_switcher_content"); infoSwitcher.className = "selected_series_trailers"; document.body.querySelector('[data-nav="series_trailers"]').classList.toggle('selected'); } else if (elementUserProgress.classList.contains('hide')) { elementUserProgress.classList.remove('hide'); // Enable the tab and switch to it. let userProgressLi = document.body.querySelector('[data-nav="series_user_progress"]'); userProgressLi.parentNode.querySelector('.selected').classList.toggle('selected'); // rm prev selection. userProgressLi.classList.toggle('disabled'); userProgressLi.classList.toggle('selected'); let infoSwitcher = document.getElementById("info_switcher_content"); infoSwitcher.className = "selected_series_user_progress"; } element.className += ' border_all selected'; if (activeUserStatus) { activeUserStatus.classList.remove('border_all'); activeUserStatus.classList.remove('selected'); } // Request params.id = TVShowID; params.status = status; makeHttpRequest(pageOpts.path.userStatus, params, function(responseText) { if (responseText) { console.log(responseText); } }); } // Rating var btnRating = { active: function(btn) { if (!elementRating) return; this.removeClassActive(); btn.classList.add('Active'); btn.setAttribute('data-squanchy', pageOpts.btnRating.squanchy.remove); if (!elementRating.classList.contains('btnHasRating')) { elementRating.classList.add('btnHasRating'); } }, inactive: function() { if (!elementRating) return; this.removeClassActive(); if (elementRating.classList.contains('btnHasRating')) { elementRating.classList.remove('btnHasRating'); } }, removeClassActive: function() { if (!elementRating) return; var btnActive = elementRating.querySelector('button.Active'); if (btnActive) { btnActive.classList.remove('Active'); btnActive.setAttribute('data-squanchy', pageOpts.btnRating.squanchy.stars[btnActive.getAttribute('data-star')-1]); } } }; function changeRating(elementStar) { var activeStar = 0, star = 0, params = {}; var newStar = elementStar.getAttribute('data-star'), elementActiveStar = elementRating.querySelector('button.Active'), elementSvgStar = elementStar.querySelector('svg.iconStar'); if (!pageOpts.isLoggedIn) { redirect_to_login(); return; } if (elementActiveStar) { activeStar = elementActiveStar.getAttribute('data-star'); } star = (newStar === activeStar) ? 101 : newStar; params.id = TVShowID; params.rating = star; // Spinner var startSpinner = new Date(); var elemSpanSpinner = createSVGSpinner(); showSpinner(); // Request makeHttpRequest(pageOpts.path.rating, params, function(responseText) { var spinnerTimeout = SPINNER_TIME - (new Date() - startSpinner), timerSpinner; if (spinnerTimeout > 0) { timerSpinner = setTimeout(function() { rated(); }, spinnerTimeout); } else { rated(); } if (responseText) { console.log(responseText); } }); // Functions function showSpinner() { elementRating.classList.add('savingRating'); elementSvgStar.parentNode.replaceChild(elemSpanSpinner, elementSvgStar); } function rated() { elementRating.classList.remove('savingRating'); elemSpanSpinner.parentNode.replaceChild(elementSvgStar, elemSpanSpinner); if (newStar !== activeStar) { btnRating.active(elementStar); } else { btnRating.inactive(); } } } // Button recommend function recommend(element) { var btnRecommend = new ButtonRecommend( pageOpts.path.recommend, element, TVShowID, pageOpts.btnRecommend ); if (pageOpts.isLoggedIn) { btnRecommend.send(); } else { redirect_to_login(); } } function ButtonRecommend(path, btn, id, opts) { this.path = path; this.btn = btn; this.id = id; this.opts = opts; if (!this.btn) return; this.svg = this.btn.querySelector('svg'); if (!this.svg) return; this.use = this.svg.querySelector('use'); } ButtonRecommend.prototype.isActive = function() { return Number(this.btn.getAttribute('data-active')); }; ButtonRecommend.prototype.active = function() { this.btn.setAttribute('data-active', 1); this.btn.classList.add('btnActive'); this.btn.setAttribute('data-squanchy', this.opts.squanchy.active); this.setTimeoutSpinner(); }; ButtonRecommend.prototype.inactive = function() { this.btn.setAttribute('data-active', 0); this.btn.classList.remove('btnActive'); this.btn.setAttribute('data-squanchy', this.opts.squanchy.inactive); this.setTimeoutSpinner(); }; ButtonRecommend.prototype.setTimeoutSpinner = function() { if (!this.isSpinner) return; var timerSpinner, self = this; var spinnerTimeout = 500 - (new Date() - this.startSpinner); if (spinnerTimeout > 0) { timerSpinner = setTimeout(function() { self.hideSpinner(); }, spinnerTimeout); } else { this.hideSpinner(); } }; ButtonRecommend.prototype.showSpinner = function() { this.isSpinner = true; this.startSpinner = new Date(); this.btn.disabled = true; this.btn.classList.add('showSpinner'); }; ButtonRecommend.prototype.hideSpinner = function() { if (!this.isSpinner) return; this.isSpinner = false; this.btn.disabled = false; this.btn.classList.remove('showSpinner'); }; ButtonRecommend.prototype.send = function() { var thisBtn = this; var action = (this.isActive()) ? 2 : 1; var xmlhttp, p; var ajaxToken = getCookie('ajax_token'); if (typeof ajaxToken === 'undefined') { return; } this.showSpinner(); p = 'id=' + this.id + '&action=' + action; xmlhttp = getXmlHttp(); xmlhttp.open('POST', this.path, true); xmlhttp.setRequestHeader('X-CSRF-TOKEN', ajaxToken); xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xmlhttp.onreadystatechange = function() { if (this.readyState != 4) return; if (this.status != 200) { console.log( xhr.status + ': ' + xhr.statusText ); return; } if (xmlhttp.responseText) { console.log(xmlhttp.responseText); } if (thisBtn.isActive()) { thisBtn.inactive(); } else { thisBtn.active(); } }; xmlhttp.send(p); }; // User note function showModalUserNote() { if (!pageOpts.isLoggedIn) { redirect_to_login(); return; } if (elementModalUserNote) return; let modal = ` <div class="overlay_dark"></div> <div class="container modal" data-modal="user-note"> <section class="bg_white border_rad_8 overflow_h shadow_modal_1"> <header class="bg_gb1 pad_16 border_b border_c0x text_shadow_white"> <button type="button" class="btn btn-emoji pos_abs" data-btn="hide-modal-user-note"> <svg class="icon iconX"><use xlink:href="` + base_src + `/svg/icons.svg#iconX"></use></svg> </button> <h2>` + pageOpts.userNote.header + `</h2> <div class="c_g5">` + pageOpts.userNote.message + `</div> </header> <div class="pad_16"> <textarea class="textarea mb_5 fs_normal" autofocus data-input="user-note">` + pageOpts.userNote.text + `</textarea> <div class="border_t border_c1 pt_5 ta_right"> <button class="btn btn-large btnRed mr_1" data-btn="delete-user-note">` + pageOpts.userNote.deleteBtnText + `</button> <button class="btn btn-large btnGreen" data-btn="save-user-note" disabled>` + pageOpts.userNote.btnText + `</button> </div> </div> </section> </div>`; document.body.insertAdjacentHTML('beforeend', modal); elementDark = document.body.querySelector('div.overlay_dark'); elementModalUserNote = document.body.querySelector('[data-modal="user-note"]'); } function hideModalUserNote() { if (!elementModalUserNote) return; document.body.removeChild(elementModalUserNote); elementModalUserNote = undefined; } function saveUserNote(elementBtn) { let text = elementModalUserNote.querySelector('textarea'), params = {}; text.value = removeSpaces(text.value); params.id = TVShowID; params.text = text.value; makeHttpRequest(pageOpts.path.editUserNote, params, function(responseText) { if (responseText) { console.log(responseText); } text.textContent = params.text; pageOpts.userNote.text = escapeHtml(params.text); elementModalUserNote.querySelector('[data-btn="save-user-note"]').disabled = true; if (elementUserNoteText) { if (elementUserNoteText.parentNode.classList.contains('hide')) { elementUserNoteText.parentNode.classList.remove('hide'); } elementUserNoteText.innerHTML = formatTextWithLinks(escapeHtml(params.text)); } }); } function formatTextWithLinks(text) { var urlRegex = /(https?:\/\/[^\s]+)/g; return text.replace(urlRegex, '<a href="$1">$1</a>'); } function deleteUserNote(elementBtn) { let text = elementModalUserNote.querySelector('textarea'), params = {}; params.id = TVShowID; makeHttpRequest(pageOpts.path.deleteUserNote, params, function(responseText) { if (responseText) { console.log(responseText); } text.textContent = ''; text.value = ''; pageOpts.userNote.text = ''; if (elementUserNoteText) { elementUserNoteText.textContent = ''; } }); } // Episodes function markEpisodeAsWatched(elementBtn) { if (!pageOpts.isLoggedIn) { redirect_to_login(); return; } let params = {}; let elementSeason = elementBtn.closest('[data-season-number]'), elementSeasonHeader = elementSeason.querySelector('[data-season-header]'), elementWatchedEpisodeCount = elementSeason.querySelector('[data-element="watched-episode-count"]'), elementFavoriteBtn = elementBtn.parentNode.querySelector('[data-btn="favorite-episode"]'); let episodeId = elementBtn.closest('[data-episode-id]').getAttribute('data-episode-id'), season = elementSeason.getAttribute('data-season-number'), unwatchedEpisodeCount = elementSeasonHeader.getAttribute('data-season-unwatched-ep-count'), airedEpisodeCount = elementSeasonHeader.getAttribute('data-season-aired-ep-count'); if (elementBtn.classList.contains('checked-true')) { params.action = 2; unwatchedEpisodeCount = +unwatchedEpisodeCount + 1; elementBtn.classList.remove('checked-true'); elementFavoriteBtn.classList.remove('btn-love-fill'); setUserProgress(-1); } else { params.action = 1; unwatchedEpisodeCount = +unwatchedEpisodeCount - 1; elementBtn.classList.add('checked-true'); setUserProgress(1); } elementSeasonHeader.setAttribute('data-season-unwatched-ep-count', unwatchedEpisodeCount); elementWatchedEpisodeCount.textContent = airedEpisodeCount - unwatchedEpisodeCount; setMarkSeasonBtnTextContent(season, unwatchedEpisodeCount); // Request params.id = episodeId; makeHttpRequest(pageOpts.path.watchedEpisode, params, function(responseText) { if (responseText) { console.log(responseText); } }); } function addToFavorites(elementBtn) { if (!pageOpts.isLoggedIn) { redirect_to_login(); return; } let params = {}; let elementSeason = elementBtn.closest('[data-season-number]'), elementSeasonHeader = elementSeason.querySelector('[data-season-header]'), elementWatchedEpisodeCount = elementSeason.querySelector('[data-element="watched-episode-count"]'), elementWatchedBtn = elementBtn.parentNode.querySelector('[data-btn="mark-episode"]'); let episodeId = elementBtn.closest('[data-episode-id]').getAttribute('data-episode-id'), season = elementSeason.getAttribute('data-season-number'), unwatchedEpisodeCount = elementSeasonHeader.getAttribute('data-season-unwatched-ep-count'), airedEpisodeCount = elementSeasonHeader.getAttribute('data-season-aired-ep-count'); if (elementBtn.classList.contains('btn-love-fill')) { params.action = 2; elementBtn.classList.remove('btn-love-fill'); } else { params.action = 1; elementBtn.classList.add('btn-love-fill'); if (!elementWatchedBtn.classList.contains('checked-true')) { unwatchedEpisodeCount = +unwatchedEpisodeCount - 1; setUserProgress(1); elementWatchedBtn.classList.add('checked-true'); elementSeasonHeader.setAttribute('data-season-unwatched-ep-count', unwatchedEpisodeCount); elementWatchedEpisodeCount.textContent = airedEpisodeCount - unwatchedEpisodeCount; setMarkSeasonBtnTextContent(season, unwatchedEpisodeCount); } } params.id = episodeId; makeHttpRequest(pageOpts.path.favoriteEpisode, params, function(responseText) { if (responseText) { console.log(responseText); } }); } function markSeasonAsWatchedButton(elementBtn) { if (!pageOpts.isLoggedIn) { redirect_to_login(); return; } let elementSeason = elementBtn.closest('[data-season-number]'); let season = elementSeason.getAttribute('data-season-number'); markSeasonAsWatched(season); } function showDropdownMarkSeasons(elementBtn) { var items = document.body.querySelectorAll('[data-season-header]'); if (dropdownMarkSeasons.isActive()) { dropdownMarkSeasons.stop(); } else { dropdownMarkSeasons.setItems(items); dropdownMarkSeasons.setElement(elementBtn); } } //// Nav function handleNavClick(element) { switch (element.getAttribute('data-nav')) { case 'series_user_progress': case 'series_info': case 'series_trailers': case 'series_makers': case 'series_friends': case 'series_mods_panel': selectNavInfoSwitcher(element); break; case 'cast': showCast(); selectNavMakers(element); break; case 'crew': showCrew(); selectNavMakers(element); break; default: break; } } // Info switcher function selectNavInfoSwitcher(element) { let targetAttr = element.getAttribute("data-nav"); let infoSwitcherContent = document.getElementById("info_switcher_content"); infoSwitcherContent.className = "selected_" + targetAttr; selectNavMakers(element); } // Makers function showCast() { elementCast.classList.remove('hide'); elementCrew.classList.add('hide'); } function showCrew() { elementCrew.classList.remove('hide'); elementCast.classList.add('hide'); } function selectNavMakers(element) { let selectedLi = element.parentNode.parentNode.querySelector('.selected'); selectedLi.classList.remove('selected'); element.classList.add('selected'); } //// Item function handleItemClick(element) { switch (element.getAttribute('data-item')) { case 'copy-link': copyLink(element); break; default: break; } } function copyLink(element) { let range = document.createRange(); range.selectNode(elementShareDropdownURL); window.getSelection().addRange(range); document.execCommand('copy'); window.getSelection().removeAllRanges(); } //// Modal //// let elementDark, elementModalUserNote, elementModalTrailer, elementModalLogin; function handleClickDark() { hideDark(); hideModalUserNote(); hideModalTrailer(); hideModalLogin(); } function hideDark() { if (!elementDark) return; document.body.removeChild(elementDark); elementDark = undefined; } //// Modal trailers //// function showModalTrailer(element) { if (elementModalTrailer) return; let yt = element.getAttribute('data-modal-trailer'), list = '', selectedClass = ''; for (let key in pageOpts.trailers) { if (yt == pageOpts.trailers[key].url) { selectedClass = ' selected'; } else { selectedClass = ''; } list += '<li><span class="nowrap' + selectedClass + '" data-modal-trailer-nav="' + pageOpts.trailers[key].url + '">' + pageOpts.trailers[key].name + '</span></li>'; } let li = ` <div class="overlay_dark"></div> <div class="container modal modal_trailer" data-modal="trailers"> <section> <header> <button type="button" class="btn btn-emoji pos_abs" data-btn="close-modal-trailer"> <svg class="icon iconX"><use xlink:href="` + base_src + `/svg/icons.svg#iconX"></use></svg> </button> <ul class="trailer_list dis_flex border_t border_b mb_6 user_select_off h_scroll"> ` + list + ` </ul> </header> <div class="pos_rel video_wrapper"> <iframe frameborder="0" src="https://www.youtube.com/embed/` + yt + `" class="pos_abs trailer" allowfullscreen></iframe> </div> </section> </div>`; document.body.insertAdjacentHTML('beforeend', li); elementDark = document.body.querySelector('div.overlay_dark'); elementModalTrailer = document.body.querySelector('[data-modal="trailers"]'); } function showTrailer(elementBtn) { let elementVideo = elementModalTrailer.querySelector('div.video_wrapper iframe'), elementSelected = elementModalTrailer.querySelector('ul.trailer_list span.selected'); elementVideo.setAttribute('src', 'https://www.youtube.com/embed/' + elementBtn.getAttribute('data-modal-trailer-nav')); elementSelected.classList.remove('selected'); elementBtn.classList.add('selected'); } //// Edit mode (toggle) function toggleEditMode() { document.body.classList.toggle('edit_mode'); var expDate = new Date(); expDate = new Date(expDate.getTime() + 69*24*60*60 * 1000); // 69 days. if (document.body.classList.contains('edit_mode')) { document.cookie = "edit_mode=on" + "; expires=" + expDate.toUTCString() + "; path=/; secure"; } else { document.cookie = "edit_mode=off" + "; expires=" + expDate.toUTCString() + "; path=/; secure"; } let btn = document.body.querySelector('[data-btn="edit-mode"]'); if (btn.innerHTML === pageOpts.editModeOn) { btn.innerHTML = pageOpts.editModeOff; } else { btn.innerHTML = pageOpts.editModeOn; } } //// User status //// function handeClickUserStatusMobileBtn(event) { if (elementUserStatusMobileDropdown.classList.contains('hide')) { elementUserStatusMobileBtn.classList.add('btnPressed'); elementUserStatusMobileDropdown.classList.remove('hide'); globalDropdown.setCurrent(function() { elementUserStatusMobileBtn.classList.remove('btnPressed'); elementUserStatusMobileDropdown.classList.add('hide'); }); } else { globalDropdown.hide(); } } function handleClickUserStatusMobileDropdown(event) { if (!pageOpts.isLoggedIn) { redirect_to_login(); return; } var params = {}; var item = event.target, value = item.getAttribute('data-value'), text = item.getAttribute('data-text'); if (!value) return; var activeItem = elementUserStatusMobileDropdown.querySelector('.checked_true'), svg = elementUserStatusMobileDropdown.querySelector('i'); globalDropdown.hide(); // Btn status elementUserStatusMobileBtn.setAttribute('data-my-status', value); elementUserStatusMobileBtn.firstChild.textContent = text + ' '; // Item active item.insertBefore(svg, item.firstChild); item.classList.add('checked_true'); if (activeItem) { activeItem.classList.remove('checked_true'); } // Request params.id = TVShowID; params.status = value; makeHttpRequest(pageOpts.path.userStatus, params, function(responseText) { if (responseText) { console.log(responseText); } }); } if (elementUserStatusMobileBtn) { elementUserStatusMobileBtn.addEventListener('click', handeClickUserStatusMobileBtn, false); } if (elementUserStatusMobileDropdown) { elementUserStatusMobileDropdown.addEventListener('click', handleClickUserStatusMobileDropdown, false); } //// User rating //// function handeClickRatingMobileBtn(event) { if (elementRatingMobileDropdown.classList.contains('hide')) { elementRatingMobileDropdown.classList.remove('hide'); globalDropdown.setCurrent(function() { elementRatingMobileDropdown.classList.add('hide'); }); } else { globalDropdown.hide(); } } function handleClickRatingMobileDropdown(event) { if (!pageOpts.isLoggedIn) { redirect_to_login(); return; } var params = {}; var item = event.target, star = item.getAttribute('data-star'), iconCheckMark = elementRatingMobileDropdown.querySelector('svg.iconCheckMark'); if (!star) return; params.id = TVShowID; params.rating = star; makeHttpRequest(pageOpts.path.rating, params, function(responseText) { if (responseText) { console.log(responseText); } // globalDropdown.hide(); item.insertAdjacentElement('afterbegin',iconCheckMark); if (star == 101) { elementUserRatingMobile.classList.add('hide'); elementUserRatingMobile.textContent = ''; } else { if (elementUserRatingMobile.classList.contains('hide')) { elementUserRatingMobile.classList.remove('hide'); } elementUserRatingMobile.textContent = star; } }); } if (elementRatingMobileBtn) { elementRatingMobileBtn.addEventListener('click', handeClickRatingMobileBtn, false); } if (elementRatingMobileDropdown) { elementRatingMobileDropdown.addEventListener('click', handleClickRatingMobileDropdown, false); } //// Share function handeClickShareBtn(event) { if (elementShareDropdown.classList.contains('hide')) { elementShareDropdown.classList.remove('hide'); globalDropdown.setCurrent(function() { elementShareDropdown.classList.add('hide'); }); } else { globalDropdown.hide(); } } if (elementShareBtn) { elementShareBtn.addEventListener('click', handeClickShareBtn, false); } //// Mark seasons //// function markSeasonAsWatchedDropdown(element) { if (!pageOpts.isLoggedIn) { redirect_to_login(); return; } let season = element.getAttribute('data-mark-season'); if (season == 'all') { markAllEpisodesAsWatched(); } else { markSeasonAsWatched(season); } } function markAllEpisodesAsWatched() { let listWBtns, listFBtns, elementWatchedEpisodeCount, params = {}; let elementsSeasonHeader = document.body.querySelectorAll('[data-season-header]'); let airedEpisodeCount = 0, unwatchedEpisodeCount = 0, unwatchedAllEpisodeCount = 0; for (let elementHeader of elementsSeasonHeader) { unwatchedEpisodeCount = elementHeader.getAttribute('data-season-unwatched-ep-count'); unwatchedAllEpisodeCount += +unwatchedEpisodeCount; } // Отметить эпизоды if (unwatchedAllEpisodeCount > 0) { // Headers for (let elementHeader of elementsSeasonHeader) { elementHeader.setAttribute('data-season-unwatched-ep-count', 0); elementWatchedEpisodeCount = elementHeader.parentNode.parentNode.querySelector('[data-element="watched-episode-count"]'); elementWatchedEpisodeCount.textContent = airedEpisodeCount; } // Buttons listWBtns = document.body.querySelectorAll('[data-btn="mark-episode"]:not(.checked-true)'); for (let btn of listWBtns) { btn.classList.add('checked-true'); } params.active = 1; // Убрать отметку } else { // Headers for (let elementHeader of elementsSeasonHeader) { airedEpisodeCount = elementHeader.getAttribute('data-season-aired-ep-count'); elementHeader.setAttribute('data-season-unwatched-ep-count', airedEpisodeCount); elementWatchedEpisodeCount = elementHeader.parentNode.parentNode.querySelector('[data-element="watched-episode-count"]'); elementWatchedEpisodeCount.textContent = 0; } // Buttons listWBtns = document.body.querySelectorAll('[data-btn="mark-episode"].checked-true'); listFBtns = document.body.querySelectorAll('[data-btn="favorite-episode"].btn-love-fill'); for (let btn of listWBtns) { btn.classList.remove('checked-true'); } for (let btn of listFBtns) { btn.classList.remove('btn-love-fill'); } params.active = 2; } // Request if (params.active) { params.show_id = TVShowID; params.season = 'all'; makeHttpRequest(pageOpts.path.watchedSeason, params, function(responseText) {}); } } function markSeasonAsWatched(season, mark) { let listWBtns, listFBtns, params = {}; let elementSeason = document.body.querySelector('[data-season-number="' + season + '"]'), elementSeasonHeader = elementSeason.querySelector('[data-season-header="' + season + '"]'), elementMarkSeasonBtn = elementSeason.querySelector('[data-btn="mark-season"]'), elementWatchedEpisodeCount = elementSeason.querySelector('[data-element="watched-episode-count"]'); let unwatchedEpisodeCount = elementSeasonHeader.getAttribute('data-season-unwatched-ep-count'), airedEpisodeCount = elementSeasonHeader.getAttribute('data-season-aired-ep-count'); // Отметить эпизоды if (unwatchedEpisodeCount > 0) { listWBtns = elementSeason.querySelectorAll('[data-btn="mark-episode"]:not(.checked-true)'); for (let btn of listWBtns) { btn.classList.add('checked-true'); } setUserProgress(unwatchedEpisodeCount); params.active = 1; elementSeasonHeader.setAttribute('data-season-unwatched-ep-count', 0); elementWatchedEpisodeCount.textContent = airedEpisodeCount; setMarkSeasonBtnTextContent(season, 0); // Убрать отметку } else { if (mark) return; listWBtns = elementSeason.querySelectorAll('[data-btn="mark-episode"].checked-true'); listFBtns = elementSeason.querySelectorAll('[data-btn="favorite-episode"].btn-love-fill'); for (let btn of listWBtns) { btn.classList.remove('checked-true'); } for (let btn of listFBtns) { btn.classList.remove('btn-love-fill'); } setUserProgress(-airedEpisodeCount); params.active = 2; elementSeasonHeader.setAttribute('data-season-unwatched-ep-count', airedEpisodeCount); elementWatchedEpisodeCount.textContent = 0; setMarkSeasonBtnTextContent(season, airedEpisodeCount); } // Request if (params.active) { params.show_id = TVShowID; params.season = (season > 0) ? season : 'special'; makeHttpRequest(pageOpts.path.watchedSeason, params, function(responseText) {}); } } function setMarkSeasonBtnTextContent(season, unwatchedEpisodeCount) { let elementSeason = document.body.querySelector('[data-season-number="' + season + '"]'), elementMarkSeasonBtn = elementSeason.querySelector('[data-btn="mark-season"]'); if (unwatchedEpisodeCount == 0 && elementMarkSeasonBtn.textContent != pageOpts.markSeasonBtn.textUnmark) { elementMarkSeasonBtn.textContent = pageOpts.markSeasonBtn.textUnmark; } else if (unwatchedEpisodeCount > 0 && elementMarkSeasonBtn.textContent != pageOpts.markSeasonBtn.textMark) { elementMarkSeasonBtn.textContent = pageOpts.markSeasonBtn.textMark; } } // Functions function setUserProgress(number) { let percent; pageOpts.userProgress.watchedEpisodeCount += Number(number); pageOpts.userProgress.textCount = pageOpts.userProgress.textCount.replace(/[0-9]+/, pageOpts.userProgress.watchedEpisodeCount); percent = Math.round(pageOpts.userProgress.watchedEpisodeCount / pageOpts.airedEpisodeCount * 100); elementUserProgressPercent.textContent = percent + '%'; elementUserProgressBar.setAttribute('style', 'width: ' + percent + '%'); if (elementUserProgressBar.classList.contains('style_green')) { elementUserProgressBar.classList.remove('style_green'); elementUserProgressBar.classList.add('style_purple'); } if (pageOpts.airedEpisodeCount > pageOpts.userProgress.watchedEpisodeCount) { elementUserProgressText.textContent = pageOpts.userProgress.textCount; } else if (pageOpts.canceled) { elementUserProgressBar.classList.remove('style_purple'); elementUserProgressBar.classList.add('style_green'); elementUserProgressText.textContent = pageOpts.userProgress.textWatchedAll; } else { elementUserProgressText.textContent = pageOpts.userProgress.textWatchedReleased; } } function redirect_to_login() { let div = ` <div class="overlay_dark"></div> <div class="container_min modal" data-modal="login"> <section class="bg_white border_rad_8 overflow_h shadow_modal_1 ta_center"> <header class="bg_gb1 pl_5 pr_5 pt_5 pb_3 border_b border_c0x mb_4"> <button type="button" class="btn btn-emoji pos_abs" data-btn="hide-modal-login"> <svg class="icon iconX"><use xlink:href="` + base_src + `/svg/icons.svg#iconX"></use></svg> </button> <svg class="icon iconLogo" width="36" height="25" fill="#1d2125"><use xlink:href="` + base_src + `/svg/icons.svg#iconLogo"></use></svg> </header> <div class="pad_16 ml_6 mr_6 mb_6"> <div class="mb_5 pb_5 border_b border_c1 full_width">` + pageOpts.login.text + `</div> <div class="mb_5"><a href="` + BASE_URL_LANG + `/sign-up/" class="btn btn-large btnBlue full_width">` + pageOpts.login.SignUp + `</a></div> <div><a href="` + BASE_URL_LANG + `/login/" class="btn btn-large btnPurple full_width">` + pageOpts.login.LogIn + `</a></div> </div> </section> </div>`; document.body.insertAdjacentHTML('beforeend', div); elementDark = document.body.querySelector('div.overlay_dark'); elementModalLogin = document.body.querySelector('[data-modal="login"]'); } // Listener document.body.addEventListener('input', handleInput, false); document.body.addEventListener('click', handleClick, false); })(pageSettings.TVShows); //// Сортировать эпизоды (function() { 'use strict'; document.body.addEventListener('click', handlerGrid, false); function handlerGrid(event) { var target = event.target; if (target.tagName != 'TH') return; if (!target.hasAttribute('data-type')) return; grid.sort( target.parentNode.parentNode.parentNode, target ); } })(); var grid = (function () { 'use strict'; var thCurrent; function setCurrent(current) { thCurrent = current; } function sortGrid(grid, elemTh) { if (!elemTh) return; var colNum = elemTh.cellIndex; var type = elemTh.getAttribute('data-type'); var nan_sort = elemTh.getAttribute('data-nan') || ''; var tbody = grid.getElementsByTagName('tbody')[0]; var rowsArray = [].slice.call(tbody.rows); var compare; switch (type) { case 'number': compare = function(rowA, rowB) { var result = 0; var valA = getValueNumber(rowA.cells[colNum]); var valB = getValueNumber(rowB.cells[colNum]); if (isNaN(valA) && isNaN(valB)) { valA = 0; valB = 0; } else if (isNaN(valA)) { valA = (nan_sort == 'most') ? valB + 1 : 0; } else if (isNaN(valB)) { valB = (nan_sort == 'most') ? valA + 1 : 0; } result = valA - valB; if (result == 0) { result = parseInt(rowA.cells[0].textContent, 10) - parseInt(rowB.cells[0].textContent, 10); } return result; }; break; case 'string': compare = function(rowA, rowB) { var result = 0; if (rowA.cells[colNum].hasAttribute('[data-value]') && rowB.cells[colNum].hasAttribute('[data-value]') ) { result = rowA.cells[colNum].getAttribute('[data-value]') > rowB.cells[colNum].getAttribute('[data-value]'); } else if (rowA.cells[colNum].querySelector('[data-td="value"]') && rowB.cells[colNum].querySelector('[data-td="value"]') ) { result = rowA.cells[colNum].querySelector('[data-td="value"]').textContent > rowB.cells[colNum].querySelector('[data-td="value"]').textContent; } else { result = rowA.cells[colNum].textContent > rowB.cells[colNum].textContent; } return (result) ? 1 : -1; }; break; } if (!compare) return; // Default if (thCurrent && thCurrent != elemTh) { thCurrent.setAttribute('data-sort', 'default'); } // Attr data var thData = 'up'; if (elemTh.getAttribute('data-sort') === 'up' || ( elemTh.getAttribute('data-sort') === 'default' && elemTh.getAttribute('data-sort-default') === 'down' ) ) { thData = 'down'; } elemTh.setAttribute('data-sort', thData); thCurrent = elemTh; // Sort grid.removeChild(tbody); rowsArray.sort(compare); if (thData == 'down') { rowsArray.reverse(); } for (var i = 0, max = rowsArray.length; i < max; i++) { tbody.appendChild(rowsArray[i]); } grid.appendChild(tbody); } function getValueNumber(element) { var val = 0; if ( element.hasAttribute('data-value') ) { val = element.getAttribute('data-value'); } else if ( element.querySelector('[data-td="value"]') ) { val = element.querySelector('[data-td="value"]').textContent; } else { val = element.textContent; } return parseInt(val, 10); } return { sort: sortGrid, setCurrent: setCurrent }; })(); </script> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10