2024-04-01, udpate for cityline
							parent
							
								
									ff5b9bfcb8
								
							
						
					
					
						commit
						4d3c8e7587
					
				|  | @ -44,7 +44,7 @@ except Exception as exc: | |||
|     print(exc) | ||||
|     pass | ||||
| 
 | ||||
| CONST_APP_VERSION = "MaxBot (2024.03.31)" | ||||
| CONST_APP_VERSION = "MaxBot (2024.04.01)" | ||||
| 
 | ||||
| CONST_MAXBOT_ANSWER_ONLINE_FILE = "MAXBOT_ONLINE_ANSWER.txt" | ||||
| CONST_MAXBOT_CONFIG_FILE = "settings.json" | ||||
|  | @ -725,27 +725,31 @@ def get_driver_by_config(config_dict): | |||
|         print("create web driver object fail @_@;") | ||||
|     else: | ||||
|         try: | ||||
|             NETWORK_BLOCKED_URLS = ['*/adblock.js' | ||||
|             ,'*/google_ad_block.js' | ||||
|             ,'*google-analytics.*' | ||||
|             ,'*googletagmanager.*' | ||||
|             ,'*googletagservices.*' | ||||
|             ,'*googlesyndication.*' | ||||
|             ,'*play.google.com/*' | ||||
|             ,'*cdn.cookielaw.org/*' | ||||
|             ,'*fundingchoicesmessages.google.com/*' | ||||
|             ,'*.doubleclick.net/*' | ||||
|             ,'*.rollbar.com/*' | ||||
|             ,'*.cloudfront.com/*' | ||||
|             ,'*.lndata.com/*' | ||||
|             ,'*.twitter.com/i/*' | ||||
|             ,'*platform.twitter.com/*' | ||||
|             ,'*syndication.twitter.com/*' | ||||
|             ,'*youtube.com/*' | ||||
|             ,'*player.youku.*' | ||||
|             ,'*.clarity.ms/*' | ||||
|             ,'*img.uniicreative.com/*' | ||||
|             ,'*e2elog.fetnet.net*'] | ||||
|             NETWORK_BLOCKED_URLS = [ | ||||
|                 '*.clarity.ms/*', | ||||
|                 '*.cloudfront.com/*', | ||||
|                 '*.doubleclick.net/*', | ||||
|                 '*.lndata.com/*', | ||||
|                 '*.rollbar.com/*', | ||||
|                 '*.twitter.com/i/*', | ||||
|                 '*/adblock.js', | ||||
|                 '*/google_ad_block.js', | ||||
|                 '*cityline.com/js/others.min.js', | ||||
|                 '*anymind360.com/*', | ||||
|                 '*cdn.cookielaw.org/*', | ||||
|                 '*e2elog.fetnet.net*', | ||||
|                 '*fundingchoicesmessages.google.com/*', | ||||
|                 '*google-analytics.*', | ||||
|                 '*googlesyndication.*', | ||||
|                 '*googletagmanager.*', | ||||
|                 '*googletagservices.*', | ||||
|                 '*img.uniicreative.com/*', | ||||
|                 '*platform.twitter.com/*', | ||||
|                 '*play.google.com/*', | ||||
|                 '*player.youku.*', | ||||
|                 '*syndication.twitter.com/*', | ||||
|                 '*youtube.com/*', | ||||
|             ] | ||||
| 
 | ||||
|             if config_dict["advanced"]["hide_some_image"]: | ||||
|                 NETWORK_BLOCKED_URLS.append('*.woff') | ||||
|  | @ -4700,18 +4704,20 @@ def cityline_purchase_button_press(driver, config_dict): | |||
|     if config_dict["advanced"]["verbose"]: | ||||
|         show_debug_message = True | ||||
| 
 | ||||
| 
 | ||||
|     date_auto_select_mode = config_dict["date_auto_select"]["mode"] | ||||
|     date_keyword = config_dict["date_auto_select"]["date_keyword"].strip() | ||||
|     auto_reload_coming_soon_page_enable = config_dict["tixcraft"]["auto_reload_coming_soon_page"] | ||||
| 
 | ||||
|     if show_debug_message: | ||||
|         print("date_keyword:", date_keyword) | ||||
|      | ||||
|     is_date_assign_by_bot = cityline_date_auto_select(driver, date_auto_select_mode, date_keyword, auto_reload_coming_soon_page_enable) | ||||
| 
 | ||||
|     is_button_clicked = False | ||||
|     if is_date_assign_by_bot: | ||||
|         print("press purchase button") | ||||
|         is_button_clicked = press_button(driver, By.CSS_SELECTOR, 'button.purchase-btn') | ||||
|         time.sleep(0.2) | ||||
| 
 | ||||
|     return is_button_clicked | ||||
| 
 | ||||
|  | @ -10906,6 +10912,7 @@ def main(args): | |||
| 
 | ||||
|         if not is_quit_bot: | ||||
|             url, is_quit_bot = get_current_url(driver) | ||||
|             #print("url:", url) | ||||
| 
 | ||||
|         if is_quit_bot: | ||||
|             try: | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ import webbrowser | |||
| 
 | ||||
| import util | ||||
| 
 | ||||
| CONST_APP_VERSION = "MaxBot (2024.03.31)" | ||||
| CONST_APP_VERSION = "MaxBot (2024.04.01)" | ||||
| 
 | ||||
| CONST_MAXBOT_LAUNCHER_FILE = "config_launcher.json" | ||||
| CONST_MAXBOT_CONFIG_FILE = "settings.json" | ||||
|  |  | |||
|  | @ -29,7 +29,7 @@ from datetime import datetime | |||
| 
 | ||||
| import util | ||||
| 
 | ||||
| CONST_APP_VERSION = "MaxBot (2024.03.31)" | ||||
| CONST_APP_VERSION = "MaxBot (2024.04.01)" | ||||
| 
 | ||||
| CONST_MAXBOT_CONFIG_FILE = "settings.json" | ||||
| CONST_MAXBOT_KKTIX_CONFIG_FILE = "kktix.json" | ||||
|  |  | |||
|  | @ -32,7 +32,7 @@ except Exception as exc: | |||
|     print(exc) | ||||
|     pass | ||||
| 
 | ||||
| CONST_APP_VERSION = "MaxBot (2024.03.31)" | ||||
| CONST_APP_VERSION = "MaxBot (2024.04.01)" | ||||
| 
 | ||||
| CONST_MAXBOT_ANSWER_ONLINE_FILE = "MAXBOT_ONLINE_ANSWER.txt" | ||||
| CONST_MAXBOT_CONFIG_FILE = "settings.json" | ||||
|  | @ -46,6 +46,7 @@ CONST_MAXBLOCK_EXTENSION_FILTER =[ | |||
| "*.googlesyndication.com/*", | ||||
| "*.ssp.hinet.net/*", | ||||
| "*a.amnet.tw/*", | ||||
| "*anymind360.com/*", | ||||
| "*adx.c.appier.net/*", | ||||
| "*cdn.cookielaw.org/*", | ||||
| "*cdnjs.cloudflare.com/ajax/libs/clipboard.js/*", | ||||
|  | @ -380,7 +381,7 @@ async def nodriver_kktix_travel_price_list(tab, config_dict, kktix_area_auto_sel | |||
| 
 | ||||
|     ticket_price_list = None | ||||
|     try: | ||||
|         ticket_price_list = await tab.select_all('div.display-table-row') | ||||
|         ticket_price_list = await tab.query_selector_all('div.display-table-row') | ||||
|     except Exception as exc: | ||||
|         ticket_price_list = None | ||||
|         print("find ticket-price Exception:") | ||||
|  | @ -420,12 +421,14 @@ async def nodriver_kktix_travel_price_list(tab, config_dict, kktix_area_auto_sel | |||
|             row_input = None | ||||
|             current_ticket_number = "0" | ||||
|             try: | ||||
|                 js_attr = await row.get_js_attributes() | ||||
|                 row_html = js_attr["innerHTML"] | ||||
|                 row_text = js_attr["innerText"] | ||||
|                 #js_attr = await row.get_js_attributes() | ||||
|                 row_html = await row.get_html() | ||||
|                 row_text = util.remove_html_tags(row_html) | ||||
| 
 | ||||
|                 row_input = await row.query_selector("input") | ||||
|                 if not row_input is None: | ||||
|                 if row_input: | ||||
|                     js_attr_input = await row_input.get_js_attributes() | ||||
|                     if js_attr_input: | ||||
|                         current_ticket_number = js_attr_input["value"] | ||||
|             except Exception as exc: | ||||
|                 is_dom_ready = False | ||||
|  | @ -960,9 +963,12 @@ async def nodriver_get_text_by_selector(tab, my_css_selector, attribute='innerHT | |||
|     try: | ||||
|         div_element = await tab.query_selector(my_css_selector) | ||||
|         if div_element: | ||||
|             js_attr = await div_element.get_js_attributes() | ||||
|             if js_attr: | ||||
|                 div_text = js_attr[attribute] | ||||
|             #js_attr = await div_element.get_js_attributes() | ||||
|             div_text = await div_element.get_html() | ||||
|              | ||||
|             # only this case to remove tags | ||||
|             if attribute=="innerText": | ||||
|                 div_text = util.remove_html_tags(div_text) | ||||
|     except Exception as exc: | ||||
|         print("find verify textbox fail") | ||||
|         pass | ||||
|  | @ -1654,6 +1660,128 @@ async def nodriver_cityline_login(tab, cityline_account): | |||
|             print(exc) | ||||
|             pass | ||||
| 
 | ||||
| async def nodriver_cityline_date_auto_select(tab, auto_select_mode, date_keyword): | ||||
|     show_debug_message = True       # debug. | ||||
|     show_debug_message = False      # online | ||||
| 
 | ||||
|     ret = False | ||||
| 
 | ||||
|     area_list = None | ||||
|     try: | ||||
|         my_css_selector = "button.date-time-position" | ||||
|         area_list = await tab.query_selector_all(my_css_selector) | ||||
|     except Exception as exc: | ||||
|         print(exc) | ||||
| 
 | ||||
|     matched_blocks = None | ||||
|     if area_list: | ||||
|         formated_area_list = None | ||||
|         area_list_count = len(area_list) | ||||
|         if show_debug_message: | ||||
|             print("date_list_count:", area_list_count) | ||||
| 
 | ||||
|         if area_list_count > 0: | ||||
|             formated_area_list = area_list | ||||
|             if show_debug_message: | ||||
|                 print("formated_area_list count:", len(formated_area_list)) | ||||
| 
 | ||||
|             if len(date_keyword) == 0: | ||||
|                 matched_blocks = formated_area_list | ||||
|             else: | ||||
|                 # match keyword. | ||||
|                 if show_debug_message: | ||||
|                     print("start to match keyword:", date_keyword) | ||||
|                 matched_blocks = [] | ||||
| 
 | ||||
|                 for row in formated_area_list: | ||||
|                     row_text = "" | ||||
|                     row_html = "" | ||||
|                     try: | ||||
|                         row_html = await row.get_html() | ||||
|                         row_text = util.remove_html_tags(row_html) | ||||
|                         # PS: get_js_attributes on cityline due to: the JSON object must be str, bytes or bytearray, not NoneType | ||||
|                         #js_attr = await row.get_js_attributes() | ||||
|                         #row_html = js_attr["innerHTML"] | ||||
|                         #row_text = js_attr["innerText"] | ||||
|                     except Exception as exc: | ||||
|                         if show_debug_message: | ||||
|                             print(exc) | ||||
|                         # error, exit loop | ||||
|                         break | ||||
| 
 | ||||
|                     if len(row_text) > 0: | ||||
|                         if show_debug_message: | ||||
|                             print("row_text:", row_text) | ||||
|                         is_match_area = util.is_row_match_keyword(date_keyword, row_text) | ||||
|                         if is_match_area: | ||||
|                             matched_blocks.append(row) | ||||
|                             if auto_select_mode == CONST_FROM_TOP_TO_BOTTOM: | ||||
|                                 break | ||||
| 
 | ||||
|                 if show_debug_message: | ||||
|                     if not matched_blocks is None: | ||||
|                         print("after match keyword, found count:", len(matched_blocks)) | ||||
|         else: | ||||
|             print("not found date-time-position") | ||||
|             pass | ||||
|     else: | ||||
|         print("date date-time-position is None") | ||||
|         pass | ||||
| 
 | ||||
|     target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) | ||||
|     if not target_area is None: | ||||
|         try: | ||||
|             await target_area.scroll_into_view() | ||||
|             await target_area.click() | ||||
|             ret = True | ||||
|         except Exception as exc: | ||||
|             print(exc) | ||||
| 
 | ||||
|     return ret | ||||
| 
 | ||||
| async def nodriver_check_modal_dialog_popup(tab): | ||||
|     ret = False | ||||
|     try: | ||||
|         el_div = tab.query_selector('div.modal-dialog > div.modal-content') | ||||
|         if el_div: | ||||
|             ret = True | ||||
|     except Exception as exc: | ||||
|         print(exc) | ||||
|         pass | ||||
|     return ret | ||||
| 
 | ||||
| async def nodriver_cityline_purchase_button_press(tab, config_dict): | ||||
|     date_auto_select_mode = config_dict["date_auto_select"]["mode"] | ||||
|     date_keyword = config_dict["date_auto_select"]["date_keyword"].strip() | ||||
|     is_date_assign_by_bot = await nodriver_cityline_date_auto_select(tab, date_auto_select_mode, date_keyword) | ||||
| 
 | ||||
|     is_button_clicked = False | ||||
|     if is_date_assign_by_bot: | ||||
|         print("press purchase button") | ||||
|         await nodriver_press_button(tab, 'button.purchase-btn') | ||||
|         is_button_clicked = True | ||||
|         # wait reCAPTCHA popup. | ||||
|         time.sleep(6) | ||||
| 
 | ||||
|     return is_button_clicked | ||||
| 
 | ||||
| async def nodriver_cityline_close_second_tab(tab, url): | ||||
|     new_tab = tab | ||||
|     #print("tab count:", len(tab.browser.tabs)) | ||||
|     if len(tab.browser.tabs) > 1: | ||||
|         # wait page ready. | ||||
|         time.sleep(0.3) | ||||
|         for tmp_tab in tab.browser.tabs: | ||||
|             if tmp_tab != tab: | ||||
|                 tmp_url, is_quit_bot = await nodriver_current_url(tmp_tab) | ||||
|                 if len(tmp_url) > 0: | ||||
|                     if tmp_url[:5] == "https": | ||||
|                         await new_tab.activate() | ||||
|                         await tab.close() | ||||
|                         time.sleep(0.3) | ||||
|                         new_tab = tmp_tab | ||||
|                         break | ||||
|     return new_tab | ||||
| 
 | ||||
| async def nodriver_cityline_main(tab, url, config_dict): | ||||
|     if 'msg.cityline.com' in url or 'event.cityline.com' in url: | ||||
|  | @ -1664,11 +1792,33 @@ async def nodriver_cityline_main(tab, url, config_dict): | |||
|         if len(cityline_account) > 4: | ||||
|             await nodriver_cityline_login(tab, cityline_account) | ||||
| 
 | ||||
|     # main page: | ||||
|     tab = await nodriver_cityline_close_second_tab(tab, url) | ||||
| 
 | ||||
|     # date page. | ||||
|     #https://venue.cityline.com/utsvInternet/EVENT_NAME/eventDetail?event=EVENT_CODE | ||||
|     global cityline_purchase_button_pressed | ||||
|     if not 'cityline_purchase_button_pressed' in globals(): | ||||
|         cityline_purchase_button_pressed = False | ||||
|     if '/eventDetail?' in url: | ||||
|         # detect fail. | ||||
|         #is_modal_dialog_popup = await nodriver_check_modal_dialog_popup(tab) | ||||
| 
 | ||||
|         if not cityline_purchase_button_pressed: | ||||
|             if config_dict["date_auto_select"]["enable"]: | ||||
|                 is_button_clicked = await nodriver_cityline_purchase_button_press(tab, config_dict) | ||||
|                 if is_button_clicked: | ||||
|                     cityline_purchase_button_pressed = True | ||||
|     else: | ||||
|         cityline_purchase_button_pressed = False | ||||
| 
 | ||||
| 
 | ||||
|     # area page: | ||||
|     # TODO: | ||||
|     #https://venue.cityline.com/utsvInternet/EVENT_NAME/performance?event=EVENT_CODE&perfId=PROFORMANCE_ID | ||||
|     pass | ||||
| 
 | ||||
|     return tab | ||||
| 
 | ||||
| 
 | ||||
| async def nodriver_facebook_main(tab, config_dict): | ||||
|     facebook_account = config_dict["advanced"]["facebook_account"].strip() | ||||
|  | @ -1766,27 +1916,31 @@ def get_extension_config(config_dict): | |||
|     return conf | ||||
| 
 | ||||
| async def nodrver_block_urls(tab, config_dict): | ||||
|     NETWORK_BLOCKED_URLS = ['*/adblock.js' | ||||
|     ,'*/google_ad_block.js' | ||||
|     ,'*google-analytics.*' | ||||
|     ,'*googletagmanager.*' | ||||
|     ,'*googletagservices.*' | ||||
|     ,'*googlesyndication.*' | ||||
|     ,'*play.google.com/*' | ||||
|     ,'*cdn.cookielaw.org/*' | ||||
|     ,'*fundingchoicesmessages.google.com/*' | ||||
|     ,'*.doubleclick.net/*' | ||||
|     ,'*.rollbar.com/*' | ||||
|     ,'*.cloudfront.com/*' | ||||
|     ,'*.lndata.com/*' | ||||
|     ,'*.twitter.com/i/*' | ||||
|     ,'*platform.twitter.com/*' | ||||
|     ,'*syndication.twitter.com/*' | ||||
|     ,'*youtube.com/*' | ||||
|     ,'*player.youku.*' | ||||
|     ,'*.clarity.ms/*' | ||||
|     ,'*img.uniicreative.com/*' | ||||
|     ,'*e2elog.fetnet.net*'] | ||||
|     NETWORK_BLOCKED_URLS = [ | ||||
|         '*.clarity.ms/*', | ||||
|         '*.cloudfront.com/*', | ||||
|         '*.doubleclick.net/*', | ||||
|         '*.lndata.com/*', | ||||
|         '*.rollbar.com/*', | ||||
|         '*.twitter.com/i/*', | ||||
|         '*/adblock.js', | ||||
|         '*/google_ad_block.js', | ||||
|         '*cityline.com/js/others.min.js', | ||||
|         '*anymind360.com/*', | ||||
|         '*cdn.cookielaw.org/*', | ||||
|         '*e2elog.fetnet.net*', | ||||
|         '*fundingchoicesmessages.google.com/*', | ||||
|         '*google-analytics.*', | ||||
|         '*googlesyndication.*', | ||||
|         '*googletagmanager.*', | ||||
|         '*googletagservices.*', | ||||
|         '*img.uniicreative.com/*', | ||||
|         '*platform.twitter.com/*', | ||||
|         '*play.google.com/*', | ||||
|         '*player.youku.*', | ||||
|         '*syndication.twitter.com/*', | ||||
|         '*youtube.com/*', | ||||
|     ] | ||||
| 
 | ||||
|     if config_dict["advanced"]["hide_some_image"]: | ||||
|         NETWORK_BLOCKED_URLS.append('*.woff') | ||||
|  | @ -1887,10 +2041,10 @@ def nodriver_overwrite_prefs(conf): | |||
|     prefs_dict["net"]["network_prediction_options"]=3 | ||||
|     prefs_dict["privacy_guide"]={} | ||||
|     prefs_dict["privacy_guide"]["viewed"]=True | ||||
|     #prefs_dict["privacy_sandbox"]={} | ||||
|     #prefs_dict["privacy_sandbox"]["first_party_sets_enabled"]=False | ||||
|     prefs_dict["privacy_sandbox"]={} | ||||
|     prefs_dict["privacy_sandbox"]["first_party_sets_enabled"]=False | ||||
|     prefs_dict["profile"]={} | ||||
|     prefs_dict["profile"]["cookie_controls_mode"]=1 | ||||
|     #prefs_dict["profile"]["cookie_controls_mode"]=1 | ||||
|     prefs_dict["profile"]["default_content_setting_values"]={} | ||||
|     prefs_dict["profile"]["default_content_setting_values"]["notifications"]=2 | ||||
|     prefs_dict["profile"]["default_content_setting_values"]["sound"]=2 | ||||
|  | @ -2017,6 +2171,7 @@ async def main(args): | |||
| 
 | ||||
|         if not is_quit_bot: | ||||
|             url, is_quit_bot = await nodriver_current_url(tab) | ||||
|             #print("url:", url) | ||||
| 
 | ||||
|         if is_quit_bot: | ||||
|             try: | ||||
|  | @ -2101,8 +2256,7 @@ async def main(args): | |||
|             pass | ||||
| 
 | ||||
|         if 'cityline.com' in url: | ||||
|             await nodriver_cityline_main(tab, url, config_dict) | ||||
|             pass | ||||
|             tab = await nodriver_cityline_main(tab, url, config_dict) | ||||
| 
 | ||||
|         softix_family = False | ||||
|         if 'hkticketing.com' in url: | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ try: | |||
| except Exception as exc: | ||||
|     pass | ||||
| 
 | ||||
| CONST_APP_VERSION = "MaxBot (2024.03.31)" | ||||
| CONST_APP_VERSION = "MaxBot (2024.04.01)" | ||||
| 
 | ||||
| CONST_MAXBOT_ANSWER_ONLINE_FILE = "MAXBOT_ONLINE_ANSWER.txt" | ||||
| CONST_MAXBOT_CONFIG_FILE = "settings.json" | ||||
|  |  | |||
|  | @ -1,467 +0,0 @@ | |||
| var getUrlParameter = function getUrlParameter(sParam) { | ||||
|     var sPageURL = window.location.search.substring(1), | ||||
|         sURLVariables = sPageURL.split('&'), | ||||
|         sParameterName, | ||||
|         i; | ||||
| 
 | ||||
|     for (i = 0; i < sURLVariables.length; i++) { | ||||
|         sParameterName = sURLVariables[i].split('='); | ||||
| 
 | ||||
|         if (sParameterName[0] === sParam) { | ||||
|             return sParameterName[1] === undefined ? true : decodeURIComponent(sParameterName[1]); | ||||
|         } | ||||
|     } | ||||
|     return false; | ||||
| }; | ||||
| 
 | ||||
| var getI18nMonthYear = function(date) { | ||||
|   let year = date.year; | ||||
|   let month = date.month - 1; | ||||
|   let monthTitles = ['month-title-jan', 'month-title-feb', 'month-title-mar', 'month-title-apr', 'month-title-may', 'month-title-jun', 'month-title-jul', 'month-title-aug', 'month-title-sep', 'month-title-oct', 'month-title-Nov', 'month-title-Dec']; | ||||
|   let monthTitle = monthTitles[month]; | ||||
|   let comma = $.i18n().locale == 'en' ? "," : ","; | ||||
|   return $.i18n(monthTitle) + comma + " " + year; | ||||
| } | ||||
| 
 | ||||
| var getI18nWeek = function(date) { | ||||
|   let weekDayTitles = ['week-title-sun', 'week-title-mon', 'week-title-tue', 'week-title-wed', 'week-title-thu', 'week-title-fri', 'week-title-sat']; | ||||
|   let day = date.weekday%7; | ||||
|   let weekDayTitle = weekDayTitles[day]; | ||||
|   return $.i18n(weekDayTitle); | ||||
| } | ||||
| 
 | ||||
| var getI18nTime = function(date) { | ||||
|   let i18nWeek = getI18nWeek(date); | ||||
|   let hour = date.hour; | ||||
|   let hourTitle = (hour < 10) ? "0" + hour : hour; | ||||
|   let minute = date.minute; | ||||
|   let minuteTitle = (minute < 10) ? "0" + minute : minute; | ||||
|   let comma = $.i18n().locale == 'en' ? "," : ","; | ||||
|   return i18nWeek + comma + " " + hourTitle + ":" + minuteTitle; | ||||
| } | ||||
| 
 | ||||
| var getI18nSrDate = function(date) { | ||||
| 	let day = date.day; | ||||
| 	let month = date.month - 1; | ||||
| 	let year = date.year; | ||||
| 	let monthTitles = ['month-title-jan', 'month-title-feb', 'month-title-mar', 'month-title-apr', 'month-title-may', 'month-title-jun', 'month-title-jul', 'month-title-aug', 'month-title-sep', 'month-title-oct', 'month-title-Nov', 'month-title-Dec']; | ||||
| 	let monthTitle = $.i18n().locale == 'en' ? $.i18n(monthTitles[month]) : month + 1; | ||||
| 	return $.i18n('sr-date-format', day, monthTitle, year); // $1=Day, $2=Month, $3=Year
 | ||||
| } | ||||
| 
 | ||||
| var getPerfHtml = function(perf) { | ||||
|   let status = perf.status; | ||||
|   let statusTitles = {"AVAILABLE" : null, "LIMIT" : "status-title-limit", "SOLDOUT" : "status-title-soldout"}; | ||||
|   let statusTitle = statusTitles[status]; | ||||
|   let statusValue = statusTitle ? $.i18n(statusTitle) : ""; | ||||
|   let statusHtml = ''; | ||||
|   if(statusValue) { | ||||
|     statusHtml =  ' <span class="limited">' + | ||||
|         '			<img class="limited-img" src="./revamp/images/limited1.svg" alt="">' + statusValue + '</span>'; | ||||
|   } | ||||
| 
 | ||||
|   let innerButtonHtml = ''; | ||||
|   let performanceNameField = getDataFieldByLang("performanceName"); | ||||
|   let performanceName = perf[performanceNameField]; | ||||
|   let performanceNameHtml = ' <span class="concert-title">' + performanceName + '</span>'; | ||||
| 
 | ||||
|   if(perf.performanceDate){ | ||||
| 		let performanceDateTz = DateTime.fromMillis(perf.performanceDate).setZone("UTC+8"); | ||||
|     let performanceDateDisplayFormat = perf.performanceDateDisplayFormat; | ||||
|     let monthYear = getI18nMonthYear(performanceDateTz); | ||||
|     let date = performanceDateTz.day; | ||||
|     let time = (performanceDateDisplayFormat == "DISPLAY_FORMAT_NAME_DATE_TIME") ? getI18nTime(performanceDateTz) : getI18nWeek(performanceDateTz); | ||||
|     let srDate = getI18nSrDate(performanceDateTz); | ||||
|     let monthYearHtml =  | ||||
|     	'	<div class="date-left" aria-label="' + srDate + ' ">' + | ||||
|         '		<span class="month-year"> '  + monthYear + '</span> <span class="day">' + date + '</span>' + | ||||
|         '	</div>'; | ||||
|     innerButtonHtml += monthYearHtml + | ||||
|         '	<div class="date-right">' + | ||||
|         '		<span class="time">' + time +'</span>' + performanceNameHtml + statusHtml + | ||||
|         '	</div>'; | ||||
|   } | ||||
|   else { | ||||
|     innerButtonHtml += ' <span class="concert-title only-title">' + performanceName + '</span>'+ statusHtml; | ||||
|   } | ||||
| 
 | ||||
|   let perfId = perf.performanceId; | ||||
|   let isPurchasable = perf.isPurchasable; | ||||
|   let disabledHtml = !isPurchasable || perf.status == 'SOLDOUT' ?  'disabled="disabled"' : ''; | ||||
|   let perfHtml = '<button type="button" class="btn btn-outline-primary date-time-position" data-perf-id="' + perfId  + '" ' + disabledHtml + ' aria-pressed="false"> ' + innerButtonHtml + '</button>'; | ||||
| 
 | ||||
|   return perfHtml; | ||||
| } | ||||
| 
 | ||||
| let myCalendar = null; | ||||
| let selDate = null; | ||||
| var fillCalendar = function(perfData){ | ||||
| 	let formattedDatePrefData = perfData.performances.map((item)=>{ | ||||
| 		return{ | ||||
| 			...item, | ||||
| 			performanceDate: moment(item.performanceDate).format("DD/MM/YYYY") | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	let formattedDateArr = perfData.performances.map((item)=>{ | ||||
| 		if(item.performanceDate){ | ||||
| 			return moment(item.performanceDate).format("DD/MM/YYYY") | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	let min = formattedDatePrefData.find(item =>item.status !== "SOLDOUT").performanceDate; | ||||
| 	let max = formattedDatePrefData[formattedDatePrefData.length-1].performanceDate; | ||||
| 
 | ||||
| 	let calendarBox = isMobileFun() ? $('.calendar-box')[0] : $('.calendar-box')[$('.calendar-box').length -1] | ||||
| 	let dateBox = isMobileFun() ? $('.date-box')[0] : $('.date-box')[$('.date-box').length -1]; | ||||
| 
 | ||||
| 	$(calendarBox).empty(); | ||||
| 	myCalendar = jsCalendar.new(calendarBox, min, { | ||||
| 		"monthFormat": "YYYY/##", | ||||
| 		"dayFormat": "DDD", | ||||
| 	}); | ||||
| 
 | ||||
| 	myCalendar.min(min); | ||||
| 	myCalendar.max(max); | ||||
| 
 | ||||
| 	$('.jsCalendar table td').mouseover(function(){ | ||||
| 		if(!$(this).hasClass('jsCalendar-previous') && !$(this).hasClass('jsCalendar-next') && !$(this).hasClass('jsCalendar-noPerfDate')){ | ||||
| 			let day = $(this)[0].innerText < 10 ? '0'+$(this)[0].innerText : $(this)[0].innerText; | ||||
| 			let date = $('.jsCalendar-title-name')[0].innerText + '/' + day; | ||||
| 			let formatDate = date.split('/').reverse().join('/') | ||||
|    | ||||
| 			let sameDatePref = fillterCurrentDatePrefList(perfData,formattedDatePrefData,formatDate); | ||||
| 			let sameDatePrefTimes = [] | ||||
| 			sameDatePref.performances.forEach(function(perf) {     | ||||
| 			  if(perf.performanceDate){ | ||||
| 				  let performanceDateTz = DateTime.fromMillis(perf.performanceDate).setZone("UTC+8"); | ||||
| 				  let time = (perf.performanceDateDisplayFormat == "DISPLAY_FORMAT_NAME_DATE_TIME") ? getI18nTime(performanceDateTz) : getI18nWeek(performanceDateTz); | ||||
| 				  let getTime = time.split(', ')[1] ? time.split(', ')[1] : time.split(', ')[1]; | ||||
| 				  let getEventName = $('#eventName').text() ? $('#eventName').text() : $('.item-title:visible').text(); | ||||
| 				  sameDatePrefTimes.push( getTime + ' ' + getEventName + '<br>'); | ||||
| 			  } | ||||
| 			})  | ||||
| 			let title = sameDatePrefTimes.join('') | ||||
| 			$(this).attr('title', title); | ||||
| 			$(this).attr('data-toggle', 'tooltip'); | ||||
| 			$(this).attr('data-placement', 'top'); | ||||
| 			$(this).attr('data-html', true); | ||||
| 			$(this).tooltip('show'); | ||||
| 		} | ||||
| 	}); | ||||
| 
 | ||||
| 	myCalendar.onDateClick(function(event,date){ | ||||
| 	  const formatDate = jsCalendar.tools.dateToString(date, "DD/MM/yyyy"); | ||||
| 
 | ||||
| 	  let curClickMonth = formatDate.split('/')[1]; | ||||
| 	  let curDisplayMonth = $('.jsCalendar-title-name')[0].innerText.split('/')[1]; | ||||
| 	  let isCurMonth = curClickMonth == curDisplayMonth ? true : false; | ||||
| 
 | ||||
| 	  selDate = formatDate; | ||||
| 	  if(formattedDateArr.indexOf(formatDate)!== -1 && isCurMonth){ | ||||
| 		  myCalendar.clearselect(); | ||||
| 
 | ||||
| 		  if($('.jsCalendar-selected').length){ | ||||
| 			toSelDate = null; | ||||
| 			$('.jsCalendar-selected')[0].classList.remove('jsCalendar-selected') | ||||
| 		  } | ||||
| 		  myCalendar.select(formatDate); | ||||
| 		  fillterCurrentDatePrefList(perfData,formattedDatePrefData,formatDate) | ||||
| 		  dateBox.classList.remove("d-none") | ||||
| 
 | ||||
| 	  } | ||||
| 	}) | ||||
| 
 | ||||
| 	let toSelDate = null; | ||||
| 	if (selectedPerfId) { | ||||
| 		toSelDate = formattedDatePrefData.find(i => i.performanceId == selectedPerfId).performanceDate; | ||||
| 		myCalendar.goto(toSelDate)		 | ||||
| 		myCalendar.select(toSelDate)	 | ||||
|     }else{ | ||||
| 		myCalendar.goto(selDate); | ||||
| 		selDate ? myCalendar.select(selDate) : myCalendar.select(min); | ||||
| 	} | ||||
| 
 | ||||
| 	myCalendar.onDateRender(function(date, element, info) { | ||||
| 		const formatDate = jsCalendar.tools.dateToString(date, "DD/MM/yyyy"); | ||||
|    | ||||
| 		element.classList.remove('jsCalendar-soldout') | ||||
|    | ||||
| 		if(formattedDateArr.indexOf(formatDate) === -1){ | ||||
| 		  element.classList.add('jsCalendar-noPerfDate') | ||||
| 		} | ||||
| 
 | ||||
|           let obj = {}; | ||||
|           let newArr = []; | ||||
|           formattedDatePrefData.forEach(item => { | ||||
|             if (!obj[item.performanceDate]) { | ||||
|               var arr = []; | ||||
|               arr.push(item); | ||||
|               newArr.push(arr); | ||||
|               obj[item.performanceDate] = item; | ||||
|             } else { | ||||
|               newArr.forEach(function (value, index) { | ||||
|                 if (value[0].performanceDate == item.performanceDate) { | ||||
|                   value.push(item) | ||||
|                 } | ||||
|               }) | ||||
|             } | ||||
|           }) | ||||
| 
 | ||||
|           let soldoutDateArr = [] | ||||
|           newArr.forEach(item =>{ | ||||
|             if(item.every(i => i.status == "SOLDOUT")){ | ||||
|               item.forEach(i => { | ||||
|                 if(soldoutDateArr.indexOf(i.performanceDate) == -1){ | ||||
|                   soldoutDateArr.push(i.performanceDate) | ||||
|                 } | ||||
|               }) | ||||
|             } | ||||
|           }) | ||||
| 
 | ||||
| 		if(soldoutDateArr.indexOf(formatDate) !== -1){ | ||||
|           element.classList.add('jsCalendar-soldout') | ||||
|         } | ||||
| 	 | ||||
|         if(document.querySelector('.jsCalendar-selected')!== null && document.querySelector('.jsCalendar-current')!== null){ | ||||
|         	document.querySelector('.jsCalendar-current').classList.remove('jsCalendar-current') | ||||
|         } | ||||
| 
 | ||||
| 	  	if(element.classList.contains('jsCalendar-selected')){ | ||||
| 	  		let sameDatePref = fillterCurrentDatePrefList(perfData,formattedDatePrefData,formatDate) | ||||
| 	  		fillPerformanceData(sameDatePref) | ||||
| 	  		postConstruct() | ||||
| 	  	} | ||||
| 
 | ||||
| 	}); | ||||
| 	myCalendar.refresh();    | ||||
| 
 | ||||
| 	changePerfCalendarTheme(); | ||||
| 	changePerfCalendarLang(); | ||||
| } | ||||
| 
 | ||||
| var fillterCurrentDatePrefList = function(perfData,formattedDatePrefData,curDate){ | ||||
| 	let sameDatePerfIdArr = [] | ||||
| 	formattedDatePrefData.forEach(i =>{ | ||||
| 		if(i.performanceDate === curDate){ | ||||
| 			return sameDatePerfIdArr.push(i.performanceId) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	let sameDatePref = {} | ||||
| 	sameDatePref.performances = [] | ||||
| 	perfData.performances.forEach(pref =>{ | ||||
| 		sameDatePerfIdArr.forEach(id =>{ | ||||
| 			if(pref.performanceId === id){ | ||||
| 				sameDatePref.performances.push(pref) | ||||
| 			} | ||||
| 		}) | ||||
| 	}) | ||||
| 	return sameDatePref; | ||||
| } | ||||
| 
 | ||||
| var changePerfCalendarTheme = function(){ | ||||
| 	if(Cookies.get('cl-theme-color') == 'black'){ | ||||
| 		document.querySelector('.jsCalendar').classList.remove('grey-theme') | ||||
| 		document.querySelector('.jsCalendar').classList.add('black-theme') | ||||
| 	}else if(Cookies.get('cl-theme-color') == 'night'){ | ||||
| 		document.querySelector('.jsCalendar').classList.remove('black-theme') | ||||
| 		document.querySelector('.jsCalendar').classList.add('grey-theme') | ||||
| 	}else{ | ||||
| 		document.querySelector('.jsCalendar').classList.remove('black-theme') | ||||
| 		document.querySelector('.jsCalendar').classList.remove('grey-theme') | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| var changePerfCalendarLang = function(){ | ||||
| 	if(get_lang() !== 'en'){ | ||||
| 		myCalendar.setLanguage("zh") | ||||
| 	}else{ | ||||
| 		myCalendar.setLanguage("en") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| var handleEventNotAvail = function() { | ||||
|   let html = '<div style="text-align: center" data-i18n="[html]event-not-available-msg">' + $.i18n("event-not-available-msg") +  "</div>"; | ||||
|   $(".main").html(html); | ||||
|   $("footer").addClass("fixed-bottom"); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| var utsvEventListCache = null; | ||||
| var eventLikeListCache = null; | ||||
| var isExpired = function(expiry) { | ||||
| 	return (new Date(expiry) < new Date()); | ||||
| } | ||||
| var getClUtsvEventByUtsvId = function(utsvId) { | ||||
| 	var result = (!utsvEventListCache) ? null : | ||||
| 		utsvEventListCache.filter(function(val, i) { | ||||
| 			return (val.utsvId == utsvId); | ||||
| 		}); | ||||
| 	return (result) ? result[0]: null; | ||||
| } | ||||
| var getLikeCountById = function(evtId) { | ||||
| 	var clEvt = getClUtsvEventByUtsvId(evtId); | ||||
| 	var jsonCount = (clEvt) ? clEvt.likeCount : 0; | ||||
| 	var cookieCount = (clEvt) ? Cookies.get('cl-like-' + clEvt.id) || 0 : 0; | ||||
| 	return Math.max(jsonCount, cookieCount); | ||||
| } | ||||
| var isLikedEvent = function(evtId) { | ||||
| 	var clEvt = getClUtsvEventByUtsvId(evtId); | ||||
| 	// var cookieLike = (clEvt) ? Cookies.get('cl-like-' + clEvt.id) || 0 : 0;
 | ||||
| 	// var result = (eventLikeListCache && clEvt) ? eventLikeListCache.indexOf(clEvt.id) : null;
 | ||||
| 	// return (cookieLike || result >= 0);
 | ||||
| 	let result | ||||
| 	if(isCitylineLogin){ | ||||
| 		result = (eventLikeListCache && clEvt) ? eventLikeListCache.indexOf(clEvt.id) : null; | ||||
| 		return result !== null && result >= 0 | ||||
| 	}else{ | ||||
| 		var list = JSON.parse(localStorage.getItem("not-login-like-utsvEvent")); | ||||
| 		result = (list && clEvt) ? list.indexOf(clEvt.id) : null; | ||||
| 		return result !== null && result >= 0 | ||||
| 	} | ||||
| } | ||||
| var drawLikeButton = function(evtId) { | ||||
| 	var likeCount = getLikeCountById(evtId); | ||||
| 	if(likeCount || likeCount == 0) | ||||
| 		$('.likeCount').text(likeCount); | ||||
| 	 | ||||
| 	if(isLikedEvent(evtId))  | ||||
| 		$('.likeIcon').addClass('liked'); | ||||
| 	else  | ||||
| 		$('.likeIcon').removeClass('liked'); | ||||
| 
 | ||||
| 	if(getClUtsvEventByUtsvId(evtId)) $('#likeButton').show(); | ||||
| } | ||||
| var getLatestClUtsvEventList = function() { | ||||
| 	// var url =  citylineDomainUrl+'/api/utsvEventList.do';
 | ||||
| 	var url =  citylineDomainUrl+'/data/utsvEventList.json'; | ||||
| 	return $.get({url: url, global: false}, function(data, status) { | ||||
| 		if(data && data.utsvEventList) { | ||||
| 			utsvEventListCache = data.utsvEventList; | ||||
| 			utsvEventListCache = utsvEventListCache.map(function(etv) { | ||||
| 			    var newEvt = {}; | ||||
| 			    newEvt['id'] = etv.id; | ||||
| 			    newEvt['utsvId'] = etv.utsvId; | ||||
| 			    newEvt['likeCount'] = etv.likeCount; | ||||
| 			    newEvt['synonym'] = etv.synonym; | ||||
| 			    return newEvt; | ||||
| 			}); | ||||
| 			var expiry = 15; // in minutes
 | ||||
| 			var localList = { | ||||
| 					utsvEventListCache, | ||||
| 					'expiry': new Date(new Date().getTime() + (expiry*60*1000)).getTime() | ||||
| 				} | ||||
| 			localStorage.setItem("like-count-utsvEvent", JSON.stringify(localList)); | ||||
| 			 | ||||
| 			var eventId = getUrlParameter('event'); | ||||
| 			drawLikeButton(eventId); | ||||
| 		} | ||||
| 	}).fail(function(){ | ||||
| 		// console.log("failed to call /api/utsvEventList.do");
 | ||||
| 		console.log("failed to call /data/utsvEventList.json"); | ||||
| 	}); | ||||
| } | ||||
| var getClUtsvEventList = function() { | ||||
| 	var deferred = $.Deferred(); | ||||
| 	var list = JSON.parse(localStorage.getItem('like-count-utsvEvent')); | ||||
| 	if (!list || (list.expiry && isExpired(list.expiry))) { | ||||
| 		return getLatestClUtsvEventList(); | ||||
| 	} else { | ||||
| 		utsvEventListCache = list.utsvEventListCache; | ||||
| 		var eventId = getUrlParameter('event'); | ||||
| 		drawLikeButton(eventId); | ||||
| 		 | ||||
| 		return deferred;  | ||||
| 	} | ||||
| } | ||||
| var getLatestEventLikeList = function() { | ||||
| 	var url = citylineDomainUrl + '/api/customer/favourite.do'; | ||||
| 	return $.get({ | ||||
| 		url: url, | ||||
| 		global: false, | ||||
| 		xhrFields: {   | ||||
| 		    withCredentials: true  | ||||
| 		  } | ||||
| 	}, function(data, status) { | ||||
| 		if(data && data.utsvEventIds) { | ||||
| 			eventLikeListCache = data.utsvEventIds; | ||||
| 			var expiry = 15; // in minutes
 | ||||
| 			var localList = { | ||||
| 					'likeList': eventLikeListCache, | ||||
| 					'expiry': new Date(new Date().getTime() + (expiry*60*1000)).getTime() | ||||
| 				} | ||||
| 			if(isCitylineLogin){ | ||||
| 				localStorage.setItem("like-list-utsvEvent", JSON.stringify(localList)); | ||||
| 			} | ||||
| 			var eventId = getUrlParameter('event'); | ||||
| 			drawLikeButton(eventId); | ||||
| 		} | ||||
| 	}).fail(function(){ | ||||
| 		console.log("failed to call /api/customer/favourite.do"); | ||||
| 	}); | ||||
| } | ||||
| var getEventLikeList = function() { | ||||
| 	var deferred = $.Deferred(); | ||||
| 	var likeListJson = JSON.parse(localStorage.getItem('like-list-utsvEvent')); | ||||
| 	if (!likeListJson || (likeListJson.expiry && isExpired(likeListJson.expiry))) { | ||||
| 		return getLatestEventLikeList(); | ||||
| 	} else { | ||||
| 		eventLikeListCache = likeListJson.likeList; | ||||
| 		var eventId = getUrlParameter('event'); | ||||
| 		drawLikeButton(eventId); | ||||
| 		 | ||||
| 		return deferred;  | ||||
| 	} | ||||
| } | ||||
| var setupLikeFeature = function() { | ||||
| 	$.when(getClUtsvEventList()) | ||||
| 		.then(getEventLikeList()); | ||||
| } | ||||
| var doLikeThisEvent = function(evtId) { | ||||
| 	var clEvt = getClUtsvEventByUtsvId(evtId); | ||||
| 	var isLiked =isLikedEvent(evtId);  | ||||
| 	if(clEvt && !isLiked) { | ||||
| 		var url = citylineDomainUrl + '/api/customer/favourite/utsvEvent/' + clEvt.id + '.do'; | ||||
| 		console.log('like!', 'utsvId: ' + evtId, 'revamp id: ' + clEvt.id); | ||||
| 		return $.post({ | ||||
| 			url: url, | ||||
| 			xhrFields: {   | ||||
| 			    withCredentials: true  | ||||
| 			  }, | ||||
| 			global: false | ||||
| 		}, function(data, status, xhr){ | ||||
| 			var clEvtId = clEvt.id | ||||
| 			var expiry = 60;	// in minutes
 | ||||
| 			var expires = new Date(new Date().getTime() + (expiry*60*1000)); | ||||
| 			 | ||||
| 			if(isCitylineLogin){ | ||||
| 
 | ||||
| 				if(Cookies.get('cl-like-' + clEvt.id)){ | ||||
| 					var likeCount = +Cookies.get('cl-like-' + clEvt.id) + 1; | ||||
| 				}else{ | ||||
| 					var likeCount = clEvt.likeCount + 1; | ||||
| 				} | ||||
| 				 | ||||
| 				getLatestEventLikeList() | ||||
| 			}else{ | ||||
| 				var likeCount = clEvt.likeCount + 1; | ||||
| 				var notLoginLikeList = JSON.parse(localStorage.getItem("not-login-like-utsvEvent") || "[]"); | ||||
| 				notLoginLikeList.push(clEvtId); | ||||
| 				localStorage.setItem("not-login-like-utsvEvent",JSON.stringify(notLoginLikeList)) | ||||
| 			} | ||||
| 			Cookies.set('cl-like-' + clEvtId, likeCount, { expires }); | ||||
| 			drawLikeButton(evtId); | ||||
| 			return true; | ||||
| 		}).fail(function() { | ||||
| 			return false; | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
| /* | ||||
| var url = contextPath + "/[activityCode]/performance?event=[eventId]&perfId=[perfId]"; | ||||
| url = url.replace("[activityCode]",activityCode) | ||||
| 		.replace("[eventId]", eventId) | ||||
| 		.replace("[perfId]",selectedPerfId) | ||||
| location.href = url; | ||||
| */ | ||||
|  | @ -1,347 +1,18 @@ | |||
| const storage = chrome.storage.local; | ||||
| var settings = null; | ||||
| $("#eventLargeCoverUrl").remove(); | ||||
| $("#s_footer").remove(); | ||||
| $("footer").remove(); | ||||
| 
 | ||||
| var eventDataCache = null; | ||||
| var performanceDataCache = null; | ||||
| var selectedPerfId = null; | ||||
| var perfPriceListMap = null; | ||||
| var pageLoaded = false; | ||||
| var eventImageUrl = null; | ||||
| var perfDisplayStyle = null; | ||||
| var allPerformanceDataCache = null; | ||||
| var contextPath = "/utsvInternet"; | ||||
| 
 | ||||
| var showEnlargedImage = function(image){ | ||||
|   if(image === 'event'){ | ||||
|     $('.image').attr('src', eventImageUrl); | ||||
|   } | ||||
|   $("#commonImageModal").modal('show'); | ||||
| } | ||||
| 
 | ||||
| var addToCalendar = function() { | ||||
|   if(eventDataCache && eventDataCache.eventDate){ | ||||
|     let addToCalButton= document.querySelector('add-to-calendar-button') | ||||
| 
 | ||||
|     localStorage.getItem('theme-color') == 'black'? addToCalButton.setAttribute('lightMode','dark') : addToCalButton.removeAttribute('lightMode') | ||||
| 
 | ||||
|     let options = []; | ||||
| 	  options.push('Google|'+ $.i18n("calendar-google")) | ||||
| 	  options.push('iCal|'+ $.i18n("calendar-ical")) | ||||
| 	  options.push('Outlook.com|'+ $.i18n("calendar-outlook"))	 | ||||
|     addToCalButton.setAttribute('options',JSON.stringify(options)) | ||||
|      | ||||
|     let customLabels = { | ||||
|       'close': $.i18n("calendar-close"), | ||||
|       'label.addtocalendar':  $.i18n("calendar-label-addtocalendar") | ||||
|     }; | ||||
|     addToCalButton.setAttribute('customLabels',JSON.stringify(customLabels)) | ||||
| 
 | ||||
|     let venueNameField = getDataFieldByLang("venueName") | ||||
|     addToCalButton.setAttribute('location',eventDataCache.venue[venueNameField]) | ||||
| 
 | ||||
|     $("#addToCal").show(); | ||||
| 
 | ||||
|     if(performanceDataCache){ | ||||
|       if(performanceDataCache.performances && performanceDataCache.performances.length > 0) { | ||||
|       let dates = [] | ||||
|       performanceDataCache.performances.forEach(perf =>{ | ||||
|         let performanceNameField = getDataFieldByLang("performanceName"); | ||||
|         let performanceName = perf[performanceNameField]; | ||||
|    | ||||
|         if(performanceDataCache.performances.length == 1){ | ||||
|           addToCalButton.setAttribute('name', performanceName) | ||||
|           addToCalButton.setAttribute('startDate', moment(perf.performanceDate).format("YYYY-MM-DD")) | ||||
|         }else{ | ||||
|           let prefDate = { | ||||
|             name: performanceName, | ||||
|             startDate: moment(perf.performanceDate).format("YYYY-MM-DD") | ||||
|           } | ||||
|           dates.push(prefDate) | ||||
|         } | ||||
|       }) | ||||
|    | ||||
|       if(performanceDataCache.performances.length > 1)  addToCalButton.setAttribute('dates',JSON.stringify(dates)) | ||||
|      | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| var fillEventData = function(data) { | ||||
|   console.log("eventData:", data); | ||||
|   eventDataCache = data; | ||||
|   eventImageUrl =  data.eventLargeCoverUrl | ||||
| 
 | ||||
|   let reload=false; | ||||
|   let eventStatues = {"TOBESOLD" : "event-status-tobesold", "SALE" : "event-status-sale", "SOLDOUT" : "event-status-soldout", "EXPIRED" : "event-status-expired"}; | ||||
|   if(data.status=="TOBESOLD") reload=true; | ||||
|   if(data.status=="SOLDOUT") reload=true;; | ||||
| 
 | ||||
|     if(reload) { | ||||
|         let auto_reload_page_interval = 0.0; | ||||
|         if(settings) { | ||||
|             auto_reload_page_interval = settings.advanced.auto_reload_page_interval; | ||||
|         } | ||||
|         if(auto_reload_page_interval == 0) { | ||||
|             //console.log('Start to reload now.');
 | ||||
|             location.reload(); | ||||
|         } else { | ||||
|             console.log('We are going to reload after few seconeds.'); | ||||
|             setTimeout(function () { | ||||
|                 location.reload(); | ||||
|             }, auto_reload_page_interval * 1000); | ||||
|         } | ||||
|     } | ||||
|    | ||||
| } | ||||
| 
 | ||||
| var openWindow = function(url) { | ||||
|   let citylineWindow = window.open(url,"_blank ","width=1020,height=600,top=0,left=20,resizable=yes,menubar=no,scrollbars=yes,status=yes"); | ||||
|   citylineWindow.focus(); | ||||
| } | ||||
| 
 | ||||
| var fillPerformanceData = function(data) { | ||||
|   //console.log("eventPerfData:", data);
 | ||||
|   performanceDataCache = data; | ||||
|   perfPriceListMap = new Map(); | ||||
|   //selectedPerfId = null;
 | ||||
|   let perfHtml = ""; | ||||
|   if(data.performances && data.performances.length > 0) { | ||||
| 
 | ||||
|     let fillerPerId = []; | ||||
|     data.performances.forEach(i => fillerPerId.push(i.performanceId)) | ||||
| 
 | ||||
|     data.performances.forEach(function(perf, i) {       | ||||
|         perfHtml += getPerfHtml(perf) | ||||
|       perfPriceListMap.set(perf.performanceId, perf.pricelist); | ||||
| 
 | ||||
|       if(perfDisplayStyle === 'DEFAULT'){ | ||||
|         if(!selectedPerfId && perf.status != 'SOLDOUT') selectedPerfId = perf.performanceId; | ||||
|       }else if(perfDisplayStyle === 'CALENDAR'){ | ||||
|         if(!selectedPerfId && perf.status != 'SOLDOUT') selectedPerfId = perf.performanceId; | ||||
| 
 | ||||
|           if(!fillerPerId.includes(+selectedPerfId)){ | ||||
|             if(perf.status != 'SOLDOUT') selectedPerfId = perf.performanceId; | ||||
|           } | ||||
| 
 | ||||
|       } | ||||
| 
 | ||||
|       /* Google Analytics */ | ||||
|       var formatDate = new Date(perf.performanceDate); | ||||
|       var item = { | ||||
| 	      id : "[" + eventSynonym + "] " + formatForGoogleAnalytics(formatDate), // 2021/08/14 23:59 (Sat)
 | ||||
| 	      name : event_en, | ||||
| 	      category : "[" + eventSynonym + "] " + formatForGoogleAnalytics(formatDate), | ||||
| 	      list_position : i | ||||
|       }; | ||||
|       viewItems.push(item); | ||||
|        | ||||
|       if (i == 0) { | ||||
|       	googleAnalyticViewItem(perf.performanceId, formatForGoogleAnalytics(perf.performanceDate)); | ||||
|       } | ||||
|     }); | ||||
|      | ||||
|     googleAnalyticViewItemList(); | ||||
|      | ||||
|     $(".date-box").html(perfHtml); | ||||
|     selectPerf(); | ||||
| 
 | ||||
|   } | ||||
|   else { | ||||
|     $(".date-title").addClass("d-none"); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| var getPerfById = function(perfId) { | ||||
| 	var perfList = performanceDataCache.performances; | ||||
| 	if(perfList && perfList.length > 0) { | ||||
| 		return perfList.find(perf => perf.performanceId == perfId) | ||||
| 	} else { | ||||
| 		return null; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| var fillPriceList = function(perfId) { | ||||
|   let priceList = perfPriceListMap.get(perfId); | ||||
|   let ticketPriceHtml = getTicketPriceHtml(priceList); | ||||
|   $(".puchase-bottom").html(ticketPriceHtml); | ||||
| } | ||||
| 
 | ||||
| var selectPerf = function() { | ||||
|   if(selectedPerfId){ | ||||
| 	$('button.date-time-position').attr("aria-pressed", false); | ||||
|     let selectedElement = $("*[data-perf-id='" + selectedPerfId + "']"); | ||||
|     selectedElement.addClass("item-onclick"); | ||||
|     selectedElement.attr("aria-pressed", true); | ||||
|     fillPriceList(selectedPerfId); | ||||
|      | ||||
|     var perf = getPerfById(selectedPerfId); | ||||
|     if (perf) {    	 | ||||
|     	var perfDate = new Date(perf.performanceDate); | ||||
|     	googleAnalyticViewItem(selectedPerfId, formatForGoogleAnalytics(perfDate)); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| var getTicketPriceHtml = function(priceList){ | ||||
|   let ticketPriceHtml = ""; | ||||
|   if(priceList){ | ||||
| 	priceList.sort((a, b) => (a.price > b.price) ? -1 : 1); | ||||
|     priceList.forEach(function(pl) { | ||||
|       let statusHtml = ""; | ||||
|       if(pl.status == 'LIMIT' || pl.status == 'SOLDOUT'){ | ||||
|         statusHtml = '<img class="limited-img" src="./revamp/images/limited2.svg" alt="">'; | ||||
|       } | ||||
|       ticketPriceHtml += '<button type="button" class="btn btn-outline-primary price-btn" ><div><span>' + getFormattedPrice(pl.price) +'</span>' +statusHtml +  '</div>'+'</button> '; | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   ticketPriceHtml = '<div class="price-box">' + | ||||
|   '	<div class="date-title price-title1" data-i18n="price-title">' + $.i18n("price-title" ) + '</div>' + | ||||
|   '	<div>'+ ticketPriceHtml + '</div>' + | ||||
|   '</div>' + | ||||
|   '<div class="ticketCard"> ' + | ||||
|   '	<button type="button" class="btn btn-outline-primary purchase-btn" data-i18n="purchase-title">' + $.i18n("purchase-title" ) + '</button>' + | ||||
|   '</div>'; | ||||
| 
 | ||||
|   return ticketPriceHtml; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| var postConstruct = function(){ | ||||
|   $(".date-time-position").click(function(){ | ||||
| 	$('button.date-time-position').attr("aria-pressed", false); | ||||
|     $(".item-onclick").removeClass("item-onclick"); | ||||
|     $(this).addClass("item-onclick"); | ||||
|     $(this).attr("aria-pressed", true); | ||||
|     let perfId = $(this).data("perf-id"); | ||||
|     selectedPerfId = perfId; | ||||
|     fillPriceList(perfId); | ||||
|     setPurchaseBtnClick(); | ||||
|   }); | ||||
|    | ||||
|   $('#likeButton').on('click', function() { | ||||
| 	  var eventId = getUrlParameter('event'); | ||||
| 	  if(doLikeThisEvent(eventId)) | ||||
| 		  $('.likeIcon').addClass('liked'); | ||||
|   }) | ||||
|    | ||||
|   setPurchaseBtnClick();   | ||||
|   if (needToPurchase) { | ||||
| 	  $(".purchase-btn").click(); | ||||
|   } | ||||
| 
 | ||||
|   // hide presenter if repeated
 | ||||
|   if($("[data-i18n=event-presenter]").text() == $("#firstDesc div p:first-child").text()) { | ||||
|     $("[data-i18n=event-presenter]").parent().hide(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| var purchaseBtnClick = function() { | ||||
| 	$.LoadingOverlay("show"); | ||||
| 	var eventId = getUrlParameter('event'); | ||||
| 	var url = contextPath + "/internet/performance?event=[eventId]&perfId=[perfId]"; | ||||
| 	url = url.replace("[eventId]", eventId) | ||||
| 			.replace("[perfId]",selectedPerfId)			 | ||||
| 	location.href = url; | ||||
| 	$.LoadingOverlay("close"); | ||||
| } | ||||
| 
 | ||||
| var setPurchaseBtnClick = function() { | ||||
|   $(".purchase-btn").click(function () { | ||||
|     if(hasLoggedIn){ | ||||
|     	purchaseBtnClick(); | ||||
|     } | ||||
|     else { | ||||
|     	var addParams = []; | ||||
|     	if(selectedPerfId) | ||||
|     		addParams.push('perfId=' + selectedPerfId); | ||||
|     	//console.log('addParams', addParams)
 | ||||
|     	loginCallback = purchaseBtnClick; | ||||
|     	login(true, addParams); | ||||
|     } | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| var reloadFromCache = function() { | ||||
|   fillEventData(eventDataCache); | ||||
|   if(perfDisplayStyle === 'DEFAULT'){ | ||||
|     fillPerformanceData(performanceDataCache); | ||||
|   }else if(perfDisplayStyle === 'CALENDAR'){ | ||||
|     fillCalendar(allPerformanceDataCache) | ||||
|   } | ||||
|   postConstruct(); | ||||
| } | ||||
| 
 | ||||
| var loadArchiveUrl = function(archiveUrl) { | ||||
|   $.ajax({ | ||||
|     type : "GET", | ||||
|     dataType: "json", | ||||
|     url: archiveUrl, | ||||
|     async: false, | ||||
|     global: false, | ||||
|     cache: true, | ||||
|     success: function(data) { | ||||
|       fillEventData(data); | ||||
|     }, | ||||
|     statusCode: { | ||||
|       403: function() { | ||||
|         handleEventNotAvail(); | ||||
|       } | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| var loadData = function() { | ||||
| function dom_ready() { | ||||
|   let eventId = getUrlParameter('event'); | ||||
|   if(eventId){ | ||||
|     let eventRequestUrl = contextPath + "/internet/api/event/" + eventId; | ||||
|     let eventPerfRequestUrl = contextPath + "/internet/api/event/" + eventId + "/performances"; | ||||
|     return $.when($.getJSON(eventRequestUrl)).then(function(data){ | ||||
|       if(data.eventId) fillEventData(data); | ||||
|       else if (data.archiveUrl){ | ||||
|         //$(".date-title").addClass("d-none");
 | ||||
|         loadArchiveUrl(data.archiveUrl); | ||||
|       } | ||||
|       else handleEventNotAvail(); | ||||
| 
 | ||||
|       perfDisplayStyle = data.performancesDisplayStyle; | ||||
|       return $.getJSON(eventPerfRequestUrl); | ||||
|     }).then(function(data){ | ||||
|       allPerformanceDataCache = data; | ||||
|     }); | ||||
|   } | ||||
|   else { | ||||
|     console.log("no event specified"); | ||||
|   } | ||||
|   //let selectedPerfId = 71202;
 | ||||
|   var url = contextPath + "/[activityCode]/performance?event=[eventId]&perfId=[perfId]"; | ||||
|   url = url.replace("[activityCode]",activityCode) | ||||
|       .replace("[eventId]", eventId) | ||||
|       .replace("[perfId]",selectedPerfId) | ||||
|   //console.log(url);
 | ||||
|   //location.href = url;
 | ||||
| } | ||||
| 
 | ||||
| function cityline_event_status_check() | ||||
| { | ||||
|   selectedPerfId = getUrlParameter('perfId'); | ||||
|   if(pageLoaded) { | ||||
|       reloadFromCache(); | ||||
|   }else{ | ||||
|       pageLoaded = true; | ||||
|       loadData(); | ||||
|   } | ||||
| } | ||||
| // not able to redirt, must click reCAPTCAH button.
 | ||||
| // dom_ready();
 | ||||
| 
 | ||||
| storage.get('settings', function (items) | ||||
| { | ||||
|     if (items.settings) | ||||
|     { | ||||
|         settings = items.settings; | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| storage.get('status', function (items) | ||||
| { | ||||
|     if (items.status && items.status=='ON') | ||||
|     { | ||||
|         cityline_event_status_check(); | ||||
|     } else { | ||||
|         console.log('no status found'); | ||||
|     } | ||||
| }); | ||||
|  |  | |||
|  | @ -25,10 +25,10 @@ function begin() | |||
|             //retry();
 | ||||
|             //console.log("trigger");
 | ||||
|             $(".eventposter").off(); | ||||
|             if (typeof setRetryUrl !== "undefined") {  | ||||
|                 setRetryUrl(window.location.href); | ||||
|             } | ||||
|             $(".btn_cta").prop('disabled', false); | ||||
|             if (ddsScheduler != undefined) | ||||
|                 clearInterval(ddsScheduler); | ||||
|             //$(".btn_cta").prop('disabled', false).trigger("click");
 | ||||
|             if (typeof goEvent !== "undefined") {  | ||||
|                 if(location.href.indexOf('home?') > -1) { | ||||
|  | @ -91,7 +91,6 @@ setInterval(() => { | |||
|     SetItem(ItemType.Local, ""); | ||||
| }, 100); | ||||
| 
 | ||||
| 
 | ||||
| function getHtmlDocName() { | ||||
|     var pathname = location.pathname; | ||||
|     var pathParts = pathname.split('/'); | ||||
|  | @ -102,7 +101,6 @@ function getHtmlDocName() { | |||
| if(getHtmlDocName()==null) { | ||||
|     history.back(); | ||||
| } | ||||
| $(".eventposter").off(); | ||||
| if (typeof goEvent !== "undefined") {  | ||||
|     if(location.href.indexOf('home?') > -1) { | ||||
|         //goEvent();
 | ||||
|  | @ -110,3 +108,4 @@ if (typeof goEvent !== "undefined") { | |||
|         history.back(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,100 @@ | |||
| const storage = chrome.storage.local; | ||||
| var settings = null; | ||||
| 
 | ||||
| function cityline_area_keyword(settings) | ||||
| { | ||||
|     let area_keyword_array = []; | ||||
|     if(settings) { | ||||
|         if(settings.area_auto_select.area_keyword.length > 0) { | ||||
|             if(settings.area_auto_select.area_keyword!='""') { | ||||
|                 area_keyword_array = JSON.parse('[' +  settings.area_auto_select.area_keyword +']'); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     //console.log(area_keyword_array);
 | ||||
|     let target_area = null; | ||||
|     let matched_block=[]; | ||||
|     let query_string = "div.price > div.form-check"; | ||||
|     if(area_keyword_array.length) { | ||||
|         for (let i = 0; i < area_keyword_array.length; i++) { | ||||
|             $(query_string).each(function () | ||||
|             { | ||||
|                 let html_text=$(this).text(); | ||||
|                 //console.log("html_text:"+html_text);
 | ||||
|                 if(html_text.indexOf('售罄')>-1) { | ||||
|                   // do nothing.
 | ||||
|                 } else { | ||||
|                   if(html_text.indexOf(area_keyword_array[i])>-1) { | ||||
|                       matched_block.push($(this)); | ||||
|                   } | ||||
|                 } | ||||
|                 target_area = get_target_area_with_order(settings, matched_block); | ||||
|             }); | ||||
| 
 | ||||
|             if (matched_block.length) { | ||||
|                 console.log("match keyword:" + area_keyword_array[i]); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         $(query_string).each(function () | ||||
|         { | ||||
|             let html_text=$(this).text(); | ||||
|             //console.log("html_text:"+html_text);
 | ||||
|             if(html_text.indexOf('售罄')>-1) { | ||||
|               // do nothing.
 | ||||
|             } else { | ||||
|               matched_block.push($(this)); | ||||
|             } | ||||
|         }); | ||||
|         target_area = get_target_area_with_order(settings, matched_block); | ||||
|     } | ||||
|      | ||||
|     if (target_area) { | ||||
|       target_area.find("input").click(); | ||||
|     } else { | ||||
|         console.log("not target_area found.") | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function cityline_performance() | ||||
| { | ||||
|     //console.log("cityline_performance");
 | ||||
|     if(settings) { | ||||
|         cityline_area_keyword(settings); | ||||
| 
 | ||||
|         $("#ticketType0").val(settings.ticket_number); | ||||
|          | ||||
|         if(settings.advanced.disable_adjacent_seat) { | ||||
|           $('input[type=checkbox]:checked').each(function() { | ||||
|               $(this).click(); | ||||
|           }); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     setTimeout(() => { | ||||
|       cityline_performance() | ||||
|     }, "500"); | ||||
| } | ||||
| 
 | ||||
| storage.get('settings', function (items) | ||||
| { | ||||
|     if (items.settings) | ||||
|     { | ||||
|         settings = items.settings; | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| storage.get('status', function (items) | ||||
| { | ||||
|     if (items.status && items.status=='ON') | ||||
|     { | ||||
|         cityline_performance(); | ||||
|     } else { | ||||
|         console.log('no status found'); | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| $("#s_footer").remove(); | ||||
| $("footer").remove(); | ||||
|  | @ -56,9 +56,10 @@ function kktix_area_keyword(settings, base_info, register_info) | |||
|     // console.log(area_keyword_array);
 | ||||
|     let target_area = null; | ||||
|     let matched_block=[]; | ||||
|     let query_string = "div.ticket-unit"; | ||||
|     if(area_keyword_array.length) { | ||||
|         for (let i = 0; i < area_keyword_array.length; i++) { | ||||
|             $("div.ticket-unit").each(function () | ||||
|             $(query_string).each(function () | ||||
|             { | ||||
|                 let html_text=$(this).text(); | ||||
|                 if(html_text.indexOf(area_keyword_array[i])>-1) { | ||||
|  | @ -73,7 +74,7 @@ function kktix_area_keyword(settings, base_info, register_info) | |||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         $("div.ticket-unit").each(function () | ||||
|         $(query_string).each(function () | ||||
|         { | ||||
|             matched_block.push($(this)); | ||||
|         }); | ||||
|  |  | |||
|  | @ -338,17 +338,19 @@ | |||
|                 "https://*.cityline.com/utsvlnternet/*/login?lang=TW" | ||||
|             ], | ||||
|             "run_at": "document_end", | ||||
|             "world": "MAIN", | ||||
|             "js": [ | ||||
|                 "jquery.min.js", | ||||
|                 "js/cityline_event_common.js" | ||||
|                 "js/cityline_event_detail.js" | ||||
|             ] | ||||
|         }, | ||||
|         { | ||||
|             "matches": [ | ||||
|                 "https://shows.cityline.com/tc/*", | ||||
|                 "https://priority.cityline.com/tc/*", | ||||
|                 "https://shows.cityline.com/en/*", | ||||
|                 "https://priority.cityline.com/en/*" | ||||
|                 "https://priority.cityline.com/tc/*", | ||||
|                 "https://priority.cityline.com/en/*", | ||||
|                 "https://cultural.cityline.com/tc/*", | ||||
|                 "https://cultural.cityline.com/en/*" | ||||
|             ], | ||||
|             "run_at": "document_end", | ||||
|             "world": "MAIN", | ||||
|  | @ -357,6 +359,17 @@ | |||
|                 "js/cityline_shows_buy_front.js" | ||||
|             ] | ||||
|         }, | ||||
|         { | ||||
|             "matches": [ | ||||
|                 "https://venue.cityline.com/utsvInternet/*/performance?*" | ||||
|             ], | ||||
|             "run_at": "document_end", | ||||
|             "js": [ | ||||
|                 "jquery.min.js", | ||||
|                 "js/common.js", | ||||
|                 "js/cityline_performance.js" | ||||
|             ] | ||||
|         }, | ||||
|         { | ||||
|             "matches": [ | ||||
|                 "https://ticketplus.com.tw/activity/*" | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue