diff --git a/seatmap-client/close.html b/seatmap-client/close.html new file mode 100644 index 0000000..1954c12 --- /dev/null +++ b/seatmap-client/close.html @@ -0,0 +1,54 @@ + + + + + + + SeatmapClose + + + + + + +
+ + Buchung abgebrochen. Sie können dieses Fenster nun schließen. +
+ + + diff --git a/seatmap-client/img/30.svg b/seatmap-client/img/30.svg new file mode 100644 index 0000000..0a6c5cb --- /dev/null +++ b/seatmap-client/img/30.svg @@ -0,0 +1 @@ + diff --git a/seatmap-client/img/FhHRx.gif b/seatmap-client/img/FhHRx.gif new file mode 100644 index 0000000..574b1d4 Binary files /dev/null and b/seatmap-client/img/FhHRx.gif differ diff --git a/seatmap-client/img/Tickets-medium.png b/seatmap-client/img/Tickets-medium.png new file mode 100644 index 0000000..16d3521 Binary files /dev/null and b/seatmap-client/img/Tickets-medium.png differ diff --git a/seatmap-client/img/Tickets-small.png b/seatmap-client/img/Tickets-small.png new file mode 100644 index 0000000..70fa65c Binary files /dev/null and b/seatmap-client/img/Tickets-small.png differ diff --git a/seatmap-client/img/favicon.png b/seatmap-client/img/favicon.png new file mode 100644 index 0000000..7b7c042 Binary files /dev/null and b/seatmap-client/img/favicon.png differ diff --git a/seatmap-client/img/iconfinder_basics-22_296812.png b/seatmap-client/img/iconfinder_basics-22_296812.png new file mode 100644 index 0000000..35dbf35 Binary files /dev/null and b/seatmap-client/img/iconfinder_basics-22_296812.png differ diff --git a/seatmap-client/img/iconfinder_tick_216457.png b/seatmap-client/img/iconfinder_tick_216457.png new file mode 100644 index 0000000..f6e67f1 Binary files /dev/null and b/seatmap-client/img/iconfinder_tick_216457.png differ diff --git a/seatmap-client/index.html b/seatmap-client/index.html new file mode 100644 index 0000000..07e0268 --- /dev/null +++ b/seatmap-client/index.html @@ -0,0 +1,102 @@ + + + + + + + + Saalplan-Buchung | Tickets.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+ +

+

+

+

+
+ + +
+
+
+ + + +
+
+
+ + +
+
+
+
+

0.5.0

+
+ +

Displaybreite zu gering: Bitte versuchen Sie, Ihren Bildschirm zu drehen, sofern Sie ein mobiles Endgerät benutzen.

Cannot display seat map: Screen width too small. Please try to rotate your screen if you are using a mobile device.

+

Internet Explorer ist veraltet und wird nicht unterstützt. Bitte benutzen Sie einen anderen Browser.

Internet Explorer is outdated and not supported. Please use another browser.

+ + + + + + + + diff --git a/seatmap-client/offline/MapTicketSales.xml b/seatmap-client/offline/MapTicketSales.xml new file mode 100644 index 0000000..1a47eb4 --- /dev/null +++ b/seatmap-client/offline/MapTicketSales.xml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+ + +
+ + + + +
+
+ + + + +
+
+ + + +
+
+ + + +
+
+ + + + + +
+
+ + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/seatmap-client/offline/MapTicketSales_Parkett.xml b/seatmap-client/offline/MapTicketSales_Parkett.xml new file mode 100644 index 0000000..a5814e4 --- /dev/null +++ b/seatmap-client/offline/MapTicketSales_Parkett.xml @@ -0,0 +1,252 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + + + + + + + + + + + + + + diff --git a/seatmap-client/offline/MapTicketSales_Rang.xml b/seatmap-client/offline/MapTicketSales_Rang.xml new file mode 100644 index 0000000..01cdce9 --- /dev/null +++ b/seatmap-client/offline/MapTicketSales_Rang.xml @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + diff --git a/seatmap-client/seatmap.1.js b/seatmap-client/seatmap.1.js new file mode 100644 index 0000000..17cab40 --- /dev/null +++ b/seatmap-client/seatmap.1.js @@ -0,0 +1,2417 @@ +// GLOBAL +var $cartBadge; +var options; +var drawTable; +var jqxhr; +var selectOptionSelected = {}; +var sc; +var inputsWithValue = []; +var showModal; +var param = new Object; +var extra_param = new Object; +var idCartModal; +var ProductManager; +var seatmapWorkflowURL; + +const branch = 'seatmap_testing'; // seatmap_testing or seatmap_main +// var config = { +// "TAD": { +// "FRONT-INDICATOR-WIDTH": "90%", +// "PADDING-LEFT": "47%", +// "PADDING-LEFT-STAGE": "49%", +// "MAX_TICKETS_PER_USER": 9, +// "BUEHNE": "TOP", +// "LEFT_NAMING": false, +// "CSS": '\ +// .booking-details p,li { \ +// font-size: 1vw; \ +// } \ +// .seatCharts-container h4, div.seatCharts-cell { \ +// font-size: 1vw; \ +// } \ +// div.seatCharts-cell { \ +// height: 0.8vw; \ +// width: 0.8vw; \ +// line-height: 1.5vw; \ +// } \ +// @media (min-width: 628px) and (max-width: 766px) { \ +// div.seatCharts-cell { \ +// height: 0.794vw; \ +// width: 0.794vw; \ +// } \ +// } \ +// @media (min-width: 498px) and (max-width: 627px) { \ +// div.seatCharts-cell { \ +// height: 0.786vw; \ +// width: 0.786vw; \ +// } \ +// } \ +// @media (min-width: 477px) and (max-width: 497px) { \ +// div.seatCharts-cell { \ +// height: 0.78vw; \ +// width: 0.78vw; \ +// } \ +// } \ +// @media (min-width: 400px) and (max-width: 476px) { \ +// div.seatCharts-cell { \ +// height: 0.77vw; \ +// width: 0.77vw; \ +// } \ +// } \ +// ', +// }, +// "KLEINER": { +// "FRONT-INDICATOR-WIDTH": "90%", +// "PADDING-LEFT": "47%", +// "PADDING-LEFT-STAGE": "49%", +// "MAX_TICKETS_PER_USER": 9, +// "BUEHNE": "TOP", +// "CUSTOM_PRICESCALES_COLOR": { +// 1824661: "228B22", +// 2542349: "8B4513", +// 2542350:"4682B4", +// }, +// "CSS": '\ +// .booking-details p,li { \ +// font-size: 1vw; \ +// } \ +// .seatCharts-container h4, div.seatCharts-cell { \ +// font-size: 1vw; \ +// } \ +// div.seatCharts-cell { \ +// height: 1.43vw; \ +// width: 1.43vw; \ +// line-height: 1.5vw; \ +// } \ +// @media (min-width: 400px) and (max-width: 540px) { \ +// div.seatCharts-cell { \ +// height: 1.398vw; \ +// width: 1.398vw; \ +// } \ +// .glyphicon { \ +// display: none; \ +// } \ +// } \ +// ', +// }, +// "INT_TH_3": { +// "FRONT-INDICATOR-WIDTH": "90%", +// "PADDING-LEFT": "47%", +// "PADDING-LEFT-STAGE": "49%", +// "MAX_TICKETS_PER_USER": 9, +// "BUEHNE": "TOP", +// "CUSTOM_PRICESCALES_COLOR": { +// 5273153: "228B22", +// }, +// "CSS": '\ +// .booking-details p,li { \ +// font-size: 1vw; \ +// } \ +// .seatCharts-container h4, div.seatCharts-cell { \ +// font-size: 1vw; \ +// } \ +// div.seatCharts-cell { \ +// height: 2.6vw; \ +// width: 2.6vw; \ +// line-height: 2.5vw; \ +// max-width: 30px; \ +// max-height: 30px; \ +// } \ +// @media (min-width: 400px) and (max-width: 700px) { \ +// div.seatCharts-cell { \ +// height: 2.52vw; \ +// width: 2.52vw; \ +// } \ +// .glyphicon { \ +// display: none; \ +// } \ +// } \ +// ', +// }, +// "GRO_SAAL": { +// "FRONT-INDICATOR-WIDTH": "90%", +// "PADDING-LEFT": "47%", +// "PADDING-LEFT-STAGE": "49%", +// "MAX_TICKETS_PER_USER": 9, +// "BUEHNE": "TOP", +// "CSS": '\ +// .booking-details p,li { \ +// font-size: 1vw; \ +// } \ +// .seatCharts-container h4, div.seatCharts-cell { \ +// font-size: 1vw; \ +// } \ +// div.seatCharts-cell { \ +// height: 0.9vw; \ +// width: 0.9vw; \ +// line-height: 1.4vw; \ +// } \ +// ', +// }, +// "STADTHAL": { +// "FRONT-INDICATOR-WIDTH": "90%", +// "PADDING-LEFT": "47%", +// "PADDING-LEFT-STAGE": "49%", +// "MAX_TICKETS_PER_USER": 9, +// "BUEHNE": "BOTTOM", +// "CSS": '\ +// .booking-details p,li { \ +// font-size: 1vw; \ +// } \ +// .seatCharts-container h4, div.seatCharts-cell { \ +// font-size: 1vw; \ +// } \ +// div.seatCharts-cell { \ +// height: 1.85vw; \ +// width: 1.85vw; \ +// line-height: 1.4vw; \ +// } \ +// @media (min-width: 400px) and (max-width: 480px) { \ +// div.seatCharts-cell { \ +// height: 1.81vw; \ +// width: 1.81vw; \ +// } \ +// .glyphicon { \ +// display: none; \ +// } \ +// } \ +// ', +// }, +// "STUDIONU": { +// "FRONT-INDICATOR-WIDTH": "90%", +// "PADDING-LEFT": "47%", +// "PADDING-LEFT-STAGE": "49%", +// "MAX_TICKETS_PER_USER": 9, +// "BUEHNE": "BOTTOM", +// "CUSTOM_PRICESCALES_COLOR": { +// 2447833: "B9DEA0", +// }, +// "CSS": '\ +// .booking-details p,li { \ +// font-size: 1vw; \ +// } \ +// .seatCharts-container h4, div.seatCharts-cell { \ +// font-size: 1vw; \ +// } \ +// div.seatCharts-cell { \ +// height: 1.85vw; \ +// width: 1.85vw; \ +// line-height: 1.4vw; \ +// } \ +// @media (min-width: 400px) and (max-width: 480px) { \ +// div.seatCharts-cell { \ +// height: 1.81vw; \ +// width: 1.81vw; \ +// } \ +// .glyphicon { \ +// display: none; \ +// } \ +// } \ +// ', +// }, +// "GR.SAAL": { +// "FRONT-INDICATOR-WIDTH": "90%", +// "PADDING-LEFT": "47%", +// "PADDING-LEFT-STAGE": "49%", +// "MAX_TICKETS_PER_USER": 9, +// "BUEHNE": "BOTTOM", +// "CUSTOM_PRICESCALES_COLOR": { +// 152965: "FFFF00", +// 152966: "FF0000", +// 152967: "74DF00", +// 152968: "0080FF", +// }, +// "CSS": '\ +// .booking-details p,li { \ +// font-size: 1vw; \ +// } \ +// .seatCharts-container h4, div.seatCharts-cell { \ +// font-size: 1vw; \ +// } \ +// div.seatCharts-cell { \ +// height: 1.19vw; \ +// width: 1.19vw; \ +// line-height: 1.4vw; \ +// } \ +// @media (min-width: 445px) and (max-width: 555px) { \ +// div.seatCharts-cell { \ +// height: 1.17vw; \ +// width: 1.17vw; \ +// } \ +// .glyphicon { \ +// display: none; \ +// } \ +// } \ +// @media (min-width: 400px) and (max-width: 444px) { \ +// div.seatCharts-cell { \ +// height: 1.15vw; \ +// width: 1.15vw; \ +// } \ +// .glyphicon { \ +// display: none; \ +// } \ +// } \ +// ', +// }, +// "THEATHOF": { +// "FRONT-INDICATOR-WIDTH": "90%", +// "PADDING-LEFT": "50%", +// "PADDING-LEFT-STAGE": "50%", +// "MAX_TICKETS_PER_USER": 9, +// "BUEHNE": "BOTTOM", +// "CUSTOM_PRICESCALES_COLOR": { +// 2446505: "FFFF00", +// 2446506: "FF0000", +// 2446507: "74DF00", +// 2446508: "0080FF", +// }, +// "CSS": '\ +// .booking-details p,li { \ +// font-size: 1vw; \ +// } \ +// .seatCharts-container h4, div.seatCharts-cell { \ +// font-size: 1vw; \ +// } \ +// div.seatCharts-cell { \ +// height: 1.2vw; \ +// width: 1.2vw; \ +// line-height: 1.4vw; \ +// } \ +// @media (min-width: 530px) and (max-width:768px) { \ +// div.seatCharts-cell { \ +// height: 1.24vw; \ +// width: 1.24vw; \ +// } \ +// } \ +// @media (min-width: 405px) and (max-width:529px) { \ +// div.seatCharts-cell { \ +// height: 1.215vw; \ +// width: 1.215vw; \ +// } \ +// } \ +// @media (min-width: 400px) and (max-width: 768px) { \ +// .glyphicon { \ +// display: none; \ +// } \ +// } \ +// ', +// }, +// "THEATER": { +// "FRONT-INDICATOR-WIDTH": "90%", +// "PADDING-LEFT": "60%", +// "PADDING-LEFT-STAGE": "47%", +// "MAX_TICKETS_PER_USER": 9, +// "BUEHNE": "TOP", +// "CSS": '\ +// .booking-details p,li { \ +// font-size: 1vw; \ +// } \ +// .seatCharts-container h4, div.seatCharts-cell { \ +// font-size: 1vw; \ +// } \ +// div.seatCharts-cell { \ +// height: 1.54vw; \ +// width: 1.54vw; \ +// line-height: 1.4vw; \ +// } \ +// @media (min-width: 400px) and (max-width:530px) { \ +// div.seatCharts-cell { \ +// height: 1.505vw; \ +// width: 1.505vw; \ +// } \ +// .glyphicon { \ +// display: none; \ +// } \ +// } \ +// ', +// }, +// "NEUES TH": { +// "FRONT-INDICATOR-WIDTH": "90%", +// "PADDING-LEFT": "50%", +// "PADDING-LEFT-STAGE": "50%", +// "MAX_TICKETS_PER_USER": 9, +// "BUEHNE": "TOP", +// "CSS": '\ +// .booking-details p,li { \ +// font-size: 1vw; \ +// } \ +// .seatCharts-container h4, div.seatCharts-cell { \ +// font-size: 1vw; \ +// } \ +// div.seatCharts-cell { \ +// height: 3.47vw !important; \ +// width: 3.47vw !important; \ +// max-width: 27px; \ +// max-height: 27px; \ +// line-height: 1.4vw; \ +// } \ +// @media all and (-ms-high-contrast: none), \ +// (-ms-high-contrast: active) { \ +// div.seatCharts-cell { \ +// height: 3.55vw !important; \ +// width: 3.55vw !important; \ +// } \ +// } \ +// ', +// }, +// "SAAL KKM": { +// "FRONT-INDICATOR-WIDTH": "90%", +// "PADDING-LEFT": "47%", +// "PADDING-LEFT-STAGE": "47%", +// "TONPULT": "

Tonpult

", +// "MAX_TICKETS_PER_USER": 9, +// "BUEHNE": "TOP", +// "CSS": ' \ +// .booking-details p,li { \ +// font-size: 1vw; \ +// } \ +// .seatCharts-container h4, div.seatCharts-cell { \ +// font-size: 1vw; \ +// } \ +// div.seatCharts-cell { \ +// height: 1.3vw; \ +// width: 1.3vw; \ +// line-height: 1.4vw; \ +// } \ +// @media (min-width: 411px) and (max-width:539px) { \ +// div.seatCharts-cell { \ +// height: 1.275vw; \ +// width: 1.275vw; \ +// } \ +// .glyphicon { \ +// display: none; \ +// } \ +// } \ +// @media (min-width: 400px) and (max-width:410px) { \ +// div.seatCharts-cell { \ +// height: 1.25vw; \ +// width: 1.25vw; \ +// } \ +// .glyphicon { \ +// display: none; \ +// } \ +// } \ +// ', +// }, +// "GSP KKM": { +// "FRONT-INDICATOR-WIDTH": "90%", +// "PADDING-LEFT": "47%", +// "PADDING-LEFT-STAGE": "47%", +// "TONPULT": "

Tonpult

", +// "MAX_TICKETS_PER_USER": 9, +// "BUEHNE": "TOP", +// "CSS": ' \ +// .booking-details p,li { \ +// font-size: 1vw; \ +// } \ +// .seatCharts-container h4, div.seatCharts-cell { \ +// font-size: 1vw; \ +// } \ +// div.seatCharts-cell { \ +// height: 1.39vw; \ +// width: 1.39vw; \ +// line-height: 1.4vw; \ +// } \ +// @media (min-width: 400px) and (max-width:504px) { \ +// div.seatCharts-cell { \ +// height: 1.36vw; \ +// width: 1.36vw; \ +// } \ +// .glyphicon { \ +// display: none; \ +// } \ +// } \ +// ', +// }, +// 'KOMÖDIE': { +// "PADDING-LEFT": "47%", +// "MAX_TICKETS_PER_USER": 9, +// "BUEHNE": "TOP", +// "CSS": ' \ +// .booking-details p,li { \ +// font-size: 1.0vw; \ +// } \ +// .seatCharts-container h4, div.seatCharts-cell { \ +// font-size: 1.0vw; \ +// } \ +// div.seatCharts-cell { \ +// height: 2.72vw; \ +// width: 2.72vw; \ +// line-height: 1.4vw; \ +// max-height: 25px; \ +// max-width: 25px; \ +// } \ +// @media (min-width: 400px) and (max-width:405px) { \ +// div.seatCharts-cell { \ +// height: 2.7vw; \ +// width: 2.7vw; \ +// } \ +// .glyphicon { \ +// display: none; \ +// } \ +// } \ +// @media (min-width: 406px) and (max-width:768px) { \ +// div.seatCharts-cell { \ +// height: 2.72vw; \ +// width: 2.72vw; \ +// } \ +// } \ +// ', +// }, +// "THEATER AM DOM": { +// "AGENCY": "TADK", +// "BUYER_TYPES": { +// "Z1": "Vollzahler", +// } +// }, +// "GROßER SAAL": { +// "AGENCY": "GMB1", +// "BUYER_TYPES": { +// "01": "Vollzahler", +// } +// }, +// "KLEINER SAAL": { +// "AGENCY": "GMB1", +// "BUYER_TYPES": { +// "01": "Vollzahler", +// } +// }, +// "INTIMES THEATER BESTUHLT": { +// "AGENCY": "GMB1", +// "BUYER_TYPES": { +// "01": "Vollzahler", +// } +// }, +// "THEATER HOF": { +// "AGENCY": "THOF", +// "BUYER_TYPES": { +// "I1": "Vollzahler", +// "I3": "Behinderte mit Ausweis", +// "I2": "Schüler", +// "IE": "Erwachsener", +// "IK": "Kind", +// } +// }, +// "STUDIO NUMMERIERT": { +// "AGENCY": "THOF", +// "BUYER_TYPES": { +// "I1": "Vollzahler", +// "I3": "Behinderte mit Ausweis", +// "I2": "Schüler", +// "IE": "Erwachsener", +// "IK": "Kind", +// } +// }, +// "KOMÖDIE BRAUNSCHWEIG": { +// "AGENCY": "KOMB", +// "BUYER_TYPES": { +// "IV": "Vollzahler", +// "IE": "Ermäßigt", +// "IG": "Gutschein", +// "ME": "Vollzahler", +// "MK": "Ermäßigt", +// "NI": "Ermäßigt", +// "NN": "Vollzahler", +// "SI": "Vollzahler", +// } +// }, +// "THEATER IM RATHAUS": { +// "AGENCY": "TIRE", +// "BUYER_TYPES": { +// "I1": "Vollzahler", +// "I2": "Ermäßigt", +// "FR": "Freitag_13", +// "11": "10% Ermäßigung", +// } +// }, +// "NEUES THEATER HANNOVER": { +// "AGENCY": "NTHH", +// "BUYER_TYPES": { +// "WW": "Vollzahler", +// } +// }, +// "STAATSOPERETTE DRESDEN": { +// "AGENCY": "SOPD", +// "BUYER_TYPES": { +// "97": "Vollzahler", +// "A0": "Ermäßigt", +// "A5": "Online-Aktion", +// "95": "Aktionspreis", +// "09": "Schüler", +// "A6": "Kind bis 18 J.", +// "86": "Buch", +// "85": "CD", +// "00": "Tagespreis", +// "03": "Tagespreis ermäßigt", +// "98": "Aktionspreis", +// "31": "Studenten/Azubis bis 27 J.", +// "23": "Andere Gäste", +// "A7": "ab 80% GdB/Begleitung", +// } +// }, +// "SEATMAP-SERVER": { +// "ROOT_URL": "https://zinomedia.de/seatmap_main/seatmap-server/seatmap-server.pl", +// }, +// "CORS-ANYWHERE": { +// "ROOT_URL": "https://cors.zinomedia.de/", +// }, +// "DEBUG": true, +// "SEATMAP_VERSION": "0.9.7", +// "CURRENCY_SYMBOL": "€", +// }; + +// if (branch === 'seatmap_testing') { +// config["SEATMAP_VERSION"] = config["SEATMAP_VERSION"] + ' (testing)'; +// config["SEATMAP-SERVER"]["ROOT_URL"] = "https://seatmap-testing.zinomedia.de/seatmap-server/seatmap-server.pl"; +// } +var config = { + 'DEBUG': 1, + 'SEATMAP-SERVER': { }, +}; + if (branch === 'seatmap_testing') { + //config["SEATMAP_VERSION"] = config["SEATMAP_VERSION"] + ' (testing)'; + config['SEATMAP-SERVER']['ROOT_URL'] = 'https://seatmap-testing.zinomedia.de/seatmap-server/seatmap-server.pl'; +} + +const checkoutParam = [ + 'request_type', 'trxstate', 'request_action', 'agency', 'etpgcode', 'parent_offer_id', 'flashDetected', 'recapToken', 'age_consent_is_checked', 'jcarousel_auto_off_val', 'selected_seat_indexes', 'ism_map_current_state_json_data', 'is_availability_switch_from_map', 'map_coupon_code', 'is_ticket_exchange_request', 'prevtrxstate', 'user_context', 'gid', 'target_trxstate', 'target_prev_trxstate', 'target_url', 'target_name_value', 'orgid', 'p_orgid', 'pid', 'redeem_voucher_data_event_mapping', 'supplier_code', 'valid_coupon_code_message', 'replay_request', 'inventory_filtering_action', 'inventory_month', 'inventory_year', 'upsell_selected', 'listing_type', 'invalid_seats', 'package_pids', 's_mem_tkt_ren_retrieval', 'mlbamsp', 'pay_pal_token', 'dpa_selection', 'timeout_seconds', 'APPTE', 'schedule', 'hbx_discounts', 'hbx_discount_prices', 'hbx_selected_tixx', 'hbx_requested_pg', 'hbx_offered_pg', 'hbx_pids', 'hbx_perf_codes', 'hbx_perf_sub_codes', 'hbx_upsell_flag', 'selected_upsell_option', 'cancelAndRedirectTrxState', 'secure_trxn_enabled', 'isCapEnabled', 'mainEventPID', 'discountdesc=A=97', 'discountprice=A=97', 'discountfees=A=97', 'discount=A=97', 'discountdesc=A=A0', 'discountprice=A=A0', 'discountfees=A=A0', 'discount=A=A0', 'supplierCode', +]; + +// POLYPHILL repeat() +if (!String.prototype.repeat) { + String.prototype.repeat = function(count) { + 'use strict'; + if (this == null) + throw new TypeError('can\'t convert ' + this + ' to object'); + + var str = '' + this; + // To convert string to integer. + count = +count; + // Check NaN + if (count != count) + count = 0; + + if (count < 0) + throw new RangeError('repeat count must be non-negative'); + + if (count == Infinity) + throw new RangeError('repeat count must be less than infinity'); + + count = Math.floor(count); + if (str.length == 0 || count == 0) + return ''; + + // Ensuring count is a 31-bit integer allows us to heavily optimize the + // main part. But anyway, most current (August 2014) browsers can't handle + // strings 1 << 28 chars or longer, so: + if (str.length * count >= 1 << 28) + throw new RangeError('repeat count must not overflow maximum string size'); + + var maxCount = str.length * count; + count = Math.floor(Math.log(count) / Math.log(2)); + while (count) { + str += str; + count--; + } + str += str.substring(0, maxCount - str.length); + return str; + }; +} + +// EVENT DOMCONTENTLOADED +document.addEventListener("DOMContentLoaded", ready); +window.onload = function() { + if (config['DEBUG']) console.log(getFuncName()); + + checkDebug(); +}; + +// EVENT CONTAINER VISIBLE +if ($('.container-fluid').is(':visible')) { + // THROW ERROR AND DIE IF BROWSER IS IE + detect_die_IE(); + + // PARSE PARAM FROM POSTURL, CREATES param and extra_param + var decoded_uri = decodeURIComponent(getParamValue('posturl')); + getParamsFromPosturl(decoded_uri); + + // GET DATA FROM SERVER AND BUILD SEATMAP + seatmapWorkflow(decoded_uri); +} + +function load_config(DATA) { + if (config['DEBUG']) console.log(getFuncName()); + + console.log(DATA.CONFIG); + // config = JSON.parse(DATA.CONFIG); + config = DATA.CONFIG; + console.log(config); + + if (config['DEBUG']) console.log(param); + if (config['DEBUG']) console.log(extra_param); +} + +function detect_die_IE() { + if (config['DEBUG']) console.log(getFuncName()); + + var IEdetected = detectIE(); + if (parseInt(IEdetected) < 12) { + $('#IEdetected').show(); + throw new Error("IE " + IEDetected + " not supported."); + } +} + +function getParamsFromPosturl(decoded_uri) { + if (config['DEBUG']) console.log(getFuncName()); + + var checkoutParam = [ + 'APPTE', 'age_consent_is_checked', 'agency', 'cancelAndRedirectTrxState', 'cogid', 'coids', 'discount=A=IE', 'discount=A=IV', 'discountdesc=A=IE', 'discountdesc=A=IV', 'discountfees=A=IE', 'discountfees=A=IV', 'discountprice=A=IE', 'discountprice=A=IV', 'dpa_selection', 'etpgcode', 'flashDetected', 'gid', 'hbx_discount_prices', 'hbx_discounts', 'hbx_offered_pg', 'hbx_perf_codes', 'hbx_perf_sub_codes', 'hbx_pids', 'hbx_requested_pg', 'hbx_selected_tixx', 'hbx_upsell_flag', 'request_type', 'invalid_seats', 'inventory_filtering_action', 'inventory_month', 'inventory_year', 'isCapEnabled', 'is_availability_switch_from_map', 'is_ticket_exchange_request', 'ism_map_current_state_json_data', 'jcarousel_auto_off_val', 'listing_type', 'mainEventPID', 'map_coupon_code', 'mlbamsp', 'oid', 'ooids', 'orderkey', 'orgid', 'p_orgid', 'package_pids', 'parent_offer_id', 'pay_pal_token', 'pid', 'prevtrxstate', 'recapToken', 'redeem_voucher_data_event_mapping', 'replay_request', 'request_action', 's_mem_tkt_ren_retrieval', 'schedule', 'secure_trxn_enabled', 'selected_seat_indexes', 'selected_upsell_option', 'supplierCode', 'supplier_code', 'target_name_value', 'target_prev_trxstate', 'target_trxstate', 'target_url', 'timeout_seconds', 'trxstate', 'upsell_selected', 'user_context', 'valid_coupon_code_message', + ]; + var extraParam = ['note']; + + for (var i = 0; i < checkoutParam.length; i++) { + let value = getParamValue(checkoutParam[i], decoded_uri); + if (value !== undefined) { + param[checkoutParam[i]] = getParamValue(checkoutParam[i], decoded_uri); + } + } + for (var i = 0; i < extraParam.length; i++) { + let value = getParamValue(extraParam[i], decoded_uri); + if (value !== undefined) { + extra_param[extraParam[i]] = value; + } + } +} + +// EVENT RESIZE +$(window).resize(function() { + if ($(window).width() < 400) { + $('.container-fluid').hide(); + $('#screenTooSmall').show(); + } + else { + $('.container-fluid').show(); + $('#screenTooSmall').hide(); + } +}); + +function detectIE () { + var ua = window.navigator.userAgent; + + var msie = ua.indexOf('MSIE '); + if (msie > 0) { + // IE 10 or older => return version number + return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10); + } + + var trident = ua.indexOf('Trident/'); + if (trident > 0) { + // IE 11 => return version number + var rv = ua.indexOf('rv:'); + return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10); + } + + var edge = ua.indexOf('Edge/'); + if (edge > 0) { + // Edge (IE 12+) => return version number + return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10); + } + + // other browser + return false; +} + +function init() { + if (config['DEBUG']) console.log(getFuncName()); + + /* + * jQuery myCart - v1.7 - 2018-03-07 + * http://asraf-uddin-ahmed.github.io/ + * Copyright (c) 2017 Asraf Uddin Ahmed; Licensed None + */ + + (function($) { + + "use strict"; + + var OptionManager = (function() { + var objToReturn = {}; + + var _options = null; + var DEFAULT_OPTIONS = { + currencySymbol: config["CURRENCY_SYMBOL"], + classCartIcon: 'my-cart-icon', + classCartBadge: 'my-cart-badge', + classProductQuantity: 'my-product-quantity', + classProductRemove: 'my-product-remove', + classCheckoutCart: 'my-cart-checkout', + affixCartIcon: true, + showCheckoutModal: true, + numberOfDecimals: 2, + cartItems: null, + clickOnAddToCart: function($addTocart) {}, + afterAddOnCart: function(products, totalPrice, totalQuantity) {}, + clickOnCartIcon: function($cartIcon, products, totalPrice, totalQuantity) {}, + checkoutCart: function(products, totalPrice, totalQuantity) { + if (config['DEBUG']) console.log("checkoutCart"); + return false; + }, + getDiscountPrice: function(products, totalPrice, totalQuantity) { + return null; + } + }; + + var loadOptions = function(customOptions) { + _options = $.extend({}, DEFAULT_OPTIONS); + if (typeof customOptions === 'object') { + $.extend(_options, customOptions); + } + }; + var getOptions = function() { + return _options; + }; + + objToReturn.loadOptions = loadOptions; + objToReturn.getOptions = getOptions; + return objToReturn; + }()); + + var MathHelper = (function() { + var objToReturn = {}; + var getRoundedNumber = function(number) { + if (isNaN(number)) { + throw new Error('Parameter is not a Number'); + } + number = number * 1; + options = OptionManager.getOptions(); + return number.toFixed(options.numberOfDecimals); + }; + objToReturn.getRoundedNumber = getRoundedNumber; + return objToReturn; + }()); + + ProductManager = (function() { + var objToReturn = {}; + var localStorage = {}; + + /* + PRIVATE + */ + // localStorage.products = localStorage.products ? localStorage.products : ""; + if (typeof localStorage.products !== "undefined") { + if (config['DEBUG']) console.log("localStorage defined"); + localStorage.products = ""; + } + else { + if (config['DEBUG']) console.log("localStorage undefined"); + } + + var getIndexOfProduct = function(id) { + var productIndex = -1; + var products = getAllProducts(); + $.each(products, function(index, value) { + if (value.id == id) { + productIndex = index; + return; + } + }); + return productIndex; + }; + var setAllProducts = function(products) { + localStorage.products = JSON.stringify(products); + }; + var addProduct = function(id, name, summary, price, quantity, image, seatObj) { + var products = getAllProducts(); + products.push({ + id: id, + name: name, + summary: summary, + price: price, + quantity: quantity, + image: image, + seatObj: seatObj, + }); + setAllProducts(products); + }; + + /* + PUBLIC + */ + var getAllProducts = function() { + try { + var products = JSON.parse(localStorage.products); + return products; + } + catch (e) { + return []; + } + }; + var updatePoduct = function(id, quantity) { + var productIndex = getIndexOfProduct(id); + if (productIndex < 0) { + return false; + } + var products = getAllProducts(); + products[productIndex].quantity = typeof quantity === "undefined" ? products[productIndex].quantity * 1 + 1 : quantity; + setAllProducts(products); + return true; + }; + var updatePrice = function(id, price) { + var productIndex = getIndexOfProduct(id); + if (productIndex < 0) { + return false; + } + var products = getAllProducts(); + // products[productIndex].quantity = typeof quantity === "undefined" ? products[productIndex].quantity * 1 + 1 : quantity; + products[productIndex].price = price; + setAllProducts(products); + return true; + }; + var setProduct = function(id, name, summary, price, quantity, image, seatObj) { + if (typeof id === "undefined") { + console.error("id required"); + return false; + } + if (typeof name === "undefined") { + console.error("name required"); + return false; + } + if (typeof image === "undefined") { + console.error("image required"); + return false; + } + if (!$.isNumeric(price)) { + console.error("price is not a number"); + return false; + } + if (!$.isNumeric(quantity)) { + console.error("quantity is not a number"); + return false; + } + if (typeof seatObj === "undefined") { + console.error("seatObj required"); + return false; + } + summary = typeof summary === "undefined" ? "" : summary; + + if (!updatePoduct(id)) { + addProduct(id, name, summary, price, quantity, image, seatObj); + } + }; + var clearProduct = function() { + setAllProducts([]); + }; + var removeProduct = function(id) { + var products = getAllProducts(); + products = $.grep(products, function(value, index) { + return value.id != id; + }); + setAllProducts(products); + }; + var getTotalQuantity = function() { + var total = 0; + var products = getAllProducts(); + $.each(products, function(index, value) { + total += value.quantity * 1; + }); + return total; + }; + var getTotalPrice = function() { + var products = getAllProducts(); + var total = 0; + $.each(products, function(index, value) { + total += value.quantity * value.price; + total = MathHelper.getRoundedNumber(total) * 1; + }); + return total; + }; + + objToReturn.getAllProducts = getAllProducts; + objToReturn.updatePoduct = updatePoduct; + objToReturn.updatePrice = updatePrice; + objToReturn.setProduct = setProduct; + objToReturn.clearProduct = clearProduct; + objToReturn.removeProduct = removeProduct; + objToReturn.getTotalQuantity = getTotalQuantity; + objToReturn.getTotalPrice = getTotalPrice; + return objToReturn; + }()); + + + var loadMyCartEvent = function(targetSelector) { + + var options = OptionManager.getOptions(); + var $cartIcon = $("." + options.classCartIcon); + $cartBadge = $("." + options.classCartBadge); + var classProductQuantity = options.classProductQuantity; + var classProductRemove = options.classProductRemove; + var classCheckoutCart = options.classCheckoutCart; + + idCartModal = 'my-cart-modal'; + var idCartTable = 'my-cart-table'; + var idGrandTotal = 'my-cart-grand-total'; + var idEmptyCartMessage = 'my-cart-empty-message'; + var idDiscountPrice = 'my-cart-discount-price'; + var classProductTotal = 'my-product-total'; + var classAffixMyCartIcon = 'my-cart-icon-affix'; + + + if (options.cartItems && options.cartItems.constructor === Array) { + ProductManager.clearProduct(); + $.each(options.cartItems, function() { + ProductManager.setProduct(this.id, this.name, this.summary, this.price, this.quantity, this.image); + }); + } + + $cartBadge.text(ProductManager.getTotalQuantity()); + + if (!$("#" + idCartModal).length) { + var modal_body = 'Bitte überprüfen Sie Ihre Plätze. Dies ist die letze Möglichkeit, um ggfs. die Ermäßigung zu ändern.'; + if (extra_param['note']) { + modal_body = modal_body + '
' + extra_param['note']; + } + + $('body').append( + '' + ); + } + + drawTable = function() { + var DATA = jqxhr.responseJSON; + + var $cartTable = $("#" + idCartTable); + $cartTable.empty(); + + var products = ProductManager.getAllProducts(); + + $.each(products, function() { + var total = this.quantity * this.price; + + // OPTION DROPDOWN + var selectID = 'select' + this.id; + var select = "/)[1]; + console.log(errorMsg); + + if (errorMsg === '') { + successful = true; + + ProductManager.clearProduct(); + $cartBadge.text(ProductManager.getTotalQuantity()); + $("#" + idCartModal).modal("hide"); + + // REDIRECT TO TICKET PURCHASE + console.log('successfull, now going to: ' + checkoutURL); + window.location.replace(checkoutURL); + // window.open(checkoutURL, '_blank'); + // window.location.replace(proxyCheckoutURL); + } + else { + successful = false; + errorMsg = errorMsg.replace(/\/g, ' '); + + new jBox('Notice', { + content: errorMsg, + color: 'red', + width: '100vw', + responsiveWidth: true, + position: { x: 'center', y: 'top' }, + autoClose: 10000, + closeButton: 'box', + }); + } + } + }); + + return successful; +} + +function untickSeat(id) { + if (config['DEBUG']) console.log(getFuncName()); + console.log(id); + document.getElementById(id).click(); // Click on the checkbox +} + +function selectRefreshPrice(select) { + if (config['DEBUG']) console.log(getFuncName()); + + if (config['DEBUG']) console.log(select); + + var $sel = $(select); + var value = $sel.val(); + var text = $("option:selected", $sel).text(); + var idSelect = $sel[0].id; + var id = idSelect.replace("select", ""); + + ProductManager.updatePrice(id, value); + selectOptionSelected[idSelect] = { selected: text }; // Remember Select Option Value for redraw in drawTable() + // drawTable(); +} + +function setSelectedIndex() { + if (config['DEBUG']) console.log(getFuncName()); + + for (var idSelect in selectOptionSelected) { + if (selectOptionSelected.hasOwnProperty(idSelect)) { + var s = document.getElementById(idSelect); + var v = selectOptionSelected[idSelect].selected; + + if (s == null) { + delete selectOptionSelected[idSelect]; + continue; + } + else { + for (var i = 0; i < s.options.length; i++) { + if (s.options[i].text === v) { + if (config['DEBUG']) console.log(s.options[i].text + ' matches ' + v); + if (config['DEBUG']) console.log(v); + if (config['DEBUG']) console.log(s); + s.options[i].selected = true; + selectRefreshPrice(s); // FIX RIGHT PRICE OPTION DROPDOWN + } + } + } + + } + } +} + +function generateSeatmap(DATA) { + if (config['DEBUG']) console.log(getFuncName()); + + var returnArr = generateMapMatrix(DATA); + var map1d = returnArr[0]; + var seatsUnavailable = returnArr[1]; + var mappingPricescalesSections = returnArr[2]; + var rows = returnArr[3]; + var seats = generateSeats(DATA, mappingPricescalesSections); + var legend = generateLegend(DATA, 'legend'); + var firstSeatLabel = 1; + + // CHANGE HTML TITLE + document.title = DATA.EVENT.DESC + ' | Saalplanbuchung by Tickets.com'; + + // CUSTOM CONFIG SETTINGS FOR SEATMAP + var left = true; + if (typeof config[DATA.VENUE.CODE]["LEFT_NAMING"] != "undefined") { + left = config[DATA.VENUE.CODE]["LEFT_NAMING"]; + } + + // SEAT MAP + sc = $('#seat-map').seatCharts({ + map: map1d, + seats: seats, + + naming: { + top: false, + left: left, + // rows: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + rows: rows, + // columns: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y'], + getLabel: function(character, row, column) { + return firstSeatLabel++; + }, + }, + legend: legend, + click: function() { + if (this.status() == 'available') { + if ((ProductManager.getTotalQuantity() + 1) > config[DATA.VENUE.CODE]["MAX_TICKETS_PER_USER"]) { + var errorMsg = 'Maximale Ticketantahl erreicht: Sie können nicht mehr als ' + config[DATA.VENUE.CODE]["MAX_TICKETS_PER_USER"] + ' Tickets buchen.'; + new jBox('Notice', { + content: errorMsg, + color: 'red', + width: '100vw', + responsiveWidth: true, + position: { x: 'center', y: 'top' }, + closeButton: 'box', + autoClose: 10000, + }); + return; + } + + // ADD PRODUCT TO CART + fillSeatObjData(this.settings.id); + myCartAddWrapper(this.settings.id, this.settings.data.product, this.settings.data.color, this.settings.data.price, 1, '', this); + + return 'selected'; + } + else if (this.status() == 'selected') { + myCartRemoveWrapper(this.settings.id); + return 'available'; + } + else if (this.status() == 'unavailable') { + //seat has been already booked + console.log('unavailable'); + return 'unavailable'; + } + else { + return this.style(); + } + } + }); + + // INIT JBOX TOOLTIP + var jbox = new jBox('Tooltip', { + attach: '.available', + trigger: 'mouseenter', + onCreated: function() { + if (config['DEBUG']) console.log("onCreated"); + }, + onOpen: function() { + // GET SEAT ID AND OBJECT + var seatID = this.source.context.id; + var seatObj = sc.get(seatID); + // console.log(seatObj); + + if (seatID == '' || seatObj.settings.status == 'unavailable') { + if (config['DEBUG']) console.log("Not a real seat or seat unavailable -> Return."); + return; + } + + // FILL SEAT OBJECT IF NOT ALREADY + fillSeatObjData(seatID); + + // SET JBOX CONTENT + this.setContent(seatObj.settings.data.productJBox); + }, + onClose: function() {} + }); + + // DETACH JBOX FROM LEGEND AND UNAVAILABLE SEATS + for (var i = 0; i < jbox.attachedElements.length; i++) { + if (jbox.attachedElements[i].id == "") { + jbox.detach($(jbox.attachedElements[i])); + i = -1; + continue; + } + } + for (var j = 0; j < seatsUnavailable.length; j++) { + jbox.detach($('#' + seatsUnavailable[j])); + } + + // MYCART + $(function() { + var goToCartIcon = function($addTocartBtn) { + var $cartIcon = $(".my-cart-icon"); + var $image = $('').css({ "position": "fixed", "z-index": "999" }); + $addTocartBtn.prepend($image); + var position = $cartIcon.position(); + $image.animate({ + top: position.top, + left: position.left + }, 500, "linear", function() { + $image.remove(); + }); + }; + }); + + // RUN POST GENERATION HOOKS + sc.status(seatsUnavailable, 'unavailable'); // seatsUnavailable RECEIVED FROM SERVER + seperateSeatmapsCSS(DATA); // CSS CHANGES AFTER GENERATE + venueSpecificCSS(DATA); + $(window).trigger('resize'); +} + +function venueSpecificCSS(DATA) { + if (config['DEBUG']) console.log(getFuncName()); + + // VENUE SPECIFIC WIDTH TO CENTER FRONT INDICATORS + var paddingLeft = config[DATA.VENUE.CODE]["PADDING-LEFT"]; + $(".front-indicator").css({ "padding-left": paddingLeft }); + var paddingLeftStage = config[DATA.VENUE.CODE]["PADDING-LEFT-STAGE"]; + $(".stage-indicator").css({ "padding-left": paddingLeftStage }); + + // STAATSOPERETTE DRESDEN SPECIFIC + if (DATA.VENUE.CODE == "SAAL KKM" || DATA.VENUE.CODE == "GSP KKM") { + $("#seat-map").append(config[DATA.VENUE.CODE]["TONPULT"]); + } + + // VENUE SPECIFIC CSS + if (config['DEBUG']) console.log('Applying venue specific CSS for ' + config[DATA.VENUE.CODE]); + var styleSheet = document.createElement("style"); + styleSheet.type = "text/css"; + styleSheet.innerText = config[DATA.VENUE.CODE]["CSS"]; + document.head.appendChild(styleSheet); +} diff --git a/seatmap-client/seatmap.js b/seatmap-client/seatmap.js new file mode 100644 index 0000000..8f34b4d --- /dev/null +++ b/seatmap-client/seatmap.js @@ -0,0 +1,1912 @@ +// GLOBAL +var $cartBadge; +var options; +var drawTable; +var jqxhr; +var selectOptionSelected = {}; +var sc; +var inputsWithValue = []; +var showModal; +var param = new Object; +var extra_param = new Object; +var idCartModal; +var ProductManager; +var seatmapWorkflowURL; + +const branch = 'seatmap_main'; // seatmap_testing or seatmap_main +var DATA = { + 'CONFIG': {}, +}; +set_predefined_config(DATA); + +function set_predefined_config(DATA) { + DATA['CONFIG']['DEBUG'] = 1; + DATA['CONFIG']['SEATMAP-SERVER'] = {}; + + if (branch === 'seatmap_testing') { + if (typeof DATA.CONFIG['SEATMAP_VERSION'] != 'undefined') { + DATA.CONFIG["SEATMAP_VERSION"] = DATA.CONFIG["SEATMAP_VERSION"] + ' (testing)'; + } + DATA.CONFIG['SEATMAP-SERVER']['ROOT_URL'] = 'https://seatmap-testing.zinomedia.de/seatmap-server/seatmap-server.pl'; + } + else if (branch === 'seatmap_main') { + DATA.CONFIG['SEATMAP-SERVER']['ROOT_URL'] = 'https://zinomedia.de/seatmap_main/seatmap-server/seatmap-server.pl'; + } +} + +const checkoutParam = [ + 'request_type', 'trxstate', 'request_action', 'agency', 'etpgcode', 'parent_offer_id', 'flashDetected', 'recapToken', 'age_consent_is_checked', 'jcarousel_auto_off_val', 'selected_seat_indexes', 'ism_map_current_state_json_data', 'is_availability_switch_from_map', 'map_coupon_code', 'is_ticket_exchange_request', 'prevtrxstate', 'user_context', 'gid', 'target_trxstate', 'target_prev_trxstate', 'target_url', 'target_name_value', 'orgid', 'p_orgid', 'pid', 'redeem_voucher_data_event_mapping', 'supplier_code', 'valid_coupon_code_message', 'replay_request', 'inventory_filtering_action', 'inventory_month', 'inventory_year', 'upsell_selected', 'listing_type', 'invalid_seats', 'package_pids', 's_mem_tkt_ren_retrieval', 'mlbamsp', 'pay_pal_token', 'dpa_selection', 'timeout_seconds', 'APPTE', 'schedule', 'hbx_discounts', 'hbx_discount_prices', 'hbx_selected_tixx', 'hbx_requested_pg', 'hbx_offered_pg', 'hbx_pids', 'hbx_perf_codes', 'hbx_perf_sub_codes', 'hbx_upsell_flag', 'selected_upsell_option', 'cancelAndRedirectTrxState', 'secure_trxn_enabled', 'isCapEnabled', 'mainEventPID', 'discountdesc=A=97', 'discountprice=A=97', 'discountfees=A=97', 'discount=A=97', 'discountdesc=A=A0', 'discountprice=A=A0', 'discountfees=A=A0', 'discount=A=A0', 'supplierCode', +]; + +// POLYPHILL repeat() +if (!String.prototype.repeat) { + String.prototype.repeat = function(count) { + 'use strict'; + if (this == null) + throw new TypeError('can\'t convert ' + this + ' to object'); + + var str = '' + this; + // To convert string to integer. + count = +count; + // Check NaN + if (count != count) + count = 0; + + if (count < 0) + throw new RangeError('repeat count must be non-negative'); + + if (count == Infinity) + throw new RangeError('repeat count must be less than infinity'); + + count = Math.floor(count); + if (str.length == 0 || count == 0) + return ''; + + // Ensuring count is a 31-bit integer allows us to heavily optimize the + // main part. But anyway, most current (August 2014) browsers can't handle + // strings 1 << 28 chars or longer, so: + if (str.length * count >= 1 << 28) + throw new RangeError('repeat count must not overflow maximum string size'); + + var maxCount = str.length * count; + count = Math.floor(Math.log(count) / Math.log(2)); + while (count) { + str += str; + count--; + } + str += str.substring(0, maxCount - str.length); + return str; + }; +} + +// EVENT DOMCONTENTLOADED +document.addEventListener("DOMContentLoaded", ready); +window.onload = function() { + if (DATA.CONFIG['DEBUG']) console.log(getFuncName()); + + checkDebug(); +}; + +// EVENT CONTAINER VISIBLE +if ($('.container-fluid').is(':visible')) { + // THROW ERROR AND DIE IF BROWSER IS IE + detect_die_IE(); + + // PARSE PARAM FROM POSTURL, CREATES param and extra_param + var decoded_uri = decodeURIComponent(getParamValue('posturl')); + getParamsFromPosturl(decoded_uri); + if (DATA.CONFIG['DEBUG']) console.log(param); + if (DATA.CONFIG['DEBUG']) console.log(extra_param); + + // GET DATA FROM SERVER AND BUILD SEATMAP + seatmapWorkflow(decoded_uri); +} + +function detect_die_IE() { + if (DATA.CONFIG['DEBUG']) console.log(getFuncName()); + + var IEdetected = detectIE(); + if (parseInt(IEdetected) < 12) { + $('#IEdetected').show(); + throw new Error("IE " + IEDetected + " not supported."); + } +} + +function getParamsFromPosturl(decoded_uri) { + if (DATA.CONFIG['DEBUG']) console.log(getFuncName()); + + var checkoutParam = [ + 'APPTE', 'age_consent_is_checked', 'agency', 'cancelAndRedirectTrxState', 'cogid', 'coids', 'discount=A=IE', 'discount=A=IV', 'discountdesc=A=IE', 'discountdesc=A=IV', 'discountfees=A=IE', 'discountfees=A=IV', 'discountprice=A=IE', 'discountprice=A=IV', 'dpa_selection', 'etpgcode', 'flashDetected', 'gid', 'hbx_discount_prices', 'hbx_discounts', 'hbx_offered_pg', 'hbx_perf_codes', 'hbx_perf_sub_codes', 'hbx_pids', 'hbx_requested_pg', 'hbx_selected_tixx', 'hbx_upsell_flag', 'request_type', 'invalid_seats', 'inventory_filtering_action', 'inventory_month', 'inventory_year', 'isCapEnabled', 'is_availability_switch_from_map', 'is_ticket_exchange_request', 'ism_map_current_state_json_data', 'jcarousel_auto_off_val', 'listing_type', 'mainEventPID', 'map_coupon_code', 'mlbamsp', 'oid', 'ooids', 'orderkey', 'orgid', 'p_orgid', 'package_pids', 'parent_offer_id', 'pay_pal_token', 'pid', 'prevtrxstate', 'recapToken', 'redeem_voucher_data_event_mapping', 'replay_request', 'request_action', 's_mem_tkt_ren_retrieval', 'schedule', 'secure_trxn_enabled', 'selected_seat_indexes', 'selected_upsell_option', 'supplierCode', 'supplier_code', 'target_name_value', 'target_prev_trxstate', 'target_trxstate', 'target_url', 'timeout_seconds', 'trxstate', 'upsell_selected', 'user_context', 'valid_coupon_code_message', + ]; + var extraParam = ['note']; + + for (var i = 0; i < checkoutParam.length; i++) { + let value = getParamValue(checkoutParam[i], decoded_uri); + if (value !== undefined) { + param[checkoutParam[i]] = getParamValue(checkoutParam[i], decoded_uri); + } + } + for (var i = 0; i < extraParam.length; i++) { + let value = getParamValue(extraParam[i], decoded_uri); + if (value !== undefined) { + extra_param[extraParam[i]] = value; + } + } +} + +// EVENT RESIZE +$(window).resize(function() { + if ($(window).width() < 400) { + $('.container-fluid').hide(); + $('#screenTooSmall').show(); + } + else { + $('.container-fluid').show(); + $('#screenTooSmall').hide(); + } +}); + +function detectIE () { + var ua = window.navigator.userAgent; + + var msie = ua.indexOf('MSIE '); + if (msie > 0) { + // IE 10 or older => return version number + return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10); + } + + var trident = ua.indexOf('Trident/'); + if (trident > 0) { + // IE 11 => return version number + var rv = ua.indexOf('rv:'); + return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10); + } + + var edge = ua.indexOf('Edge/'); + if (edge > 0) { + // Edge (IE 12+) => return version number + return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10); + } + + // other browser + return false; +} + +function init(DATA) { + if (DATA.CONFIG['DEBUG']) console.log(getFuncName()); + + /* + * jQuery myCart - v1.7 - 2018-03-07 + * http://asraf-uddin-ahmed.github.io/ + * Copyright (c) 2017 Asraf Uddin Ahmed; Licensed None + */ + + (function($) { + + "use strict"; + + var OptionManager = (function() { + var objToReturn = {}; + + var _options = null; + var DEFAULT_OPTIONS = { + currencySymbol: DATA.CONFIG["CURRENCY_SYMBOL"], + classCartIcon: 'my-cart-icon', + classCartBadge: 'my-cart-badge', + classProductQuantity: 'my-product-quantity', + classProductRemove: 'my-product-remove', + classCheckoutCart: 'my-cart-checkout', + affixCartIcon: true, + showCheckoutModal: true, + numberOfDecimals: 2, + cartItems: null, + clickOnAddToCart: function($addTocart) {}, + afterAddOnCart: function(products, totalPrice, totalQuantity) {}, + clickOnCartIcon: function($cartIcon, products, totalPrice, totalQuantity) {}, + checkoutCart: function(products, totalPrice, totalQuantity) { + if (DATA.CONFIG['DEBUG']) console.log("checkoutCart"); + return false; + }, + getDiscountPrice: function(products, totalPrice, totalQuantity) { + return null; + } + }; + + var loadOptions = function(customOptions) { + _options = $.extend({}, DEFAULT_OPTIONS); + if (typeof customOptions === 'object') { + $.extend(_options, customOptions); + } + }; + var getOptions = function() { + return _options; + }; + + objToReturn.loadOptions = loadOptions; + objToReturn.getOptions = getOptions; + return objToReturn; + }()); + + var MathHelper = (function() { + var objToReturn = {}; + var getRoundedNumber = function(number) { + if (isNaN(number)) { + throw new Error('Parameter is not a Number'); + } + number = number * 1; + options = OptionManager.getOptions(); + return number.toFixed(options.numberOfDecimals); + }; + objToReturn.getRoundedNumber = getRoundedNumber; + return objToReturn; + }()); + + ProductManager = (function() { + var objToReturn = {}; + var localStorage = {}; + + /* + PRIVATE + */ + // localStorage.products = localStorage.products ? localStorage.products : ""; + if (typeof localStorage.products !== "undefined") { + if (DATA.CONFIG['DEBUG']) console.log("localStorage defined"); + localStorage.products = ""; + } + else { + if (DATA.CONFIG['DEBUG']) console.log("localStorage undefined"); + } + + var getIndexOfProduct = function(id) { + var productIndex = -1; + var products = getAllProducts(); + $.each(products, function(index, value) { + if (value.id == id) { + productIndex = index; + return; + } + }); + return productIndex; + }; + var setAllProducts = function(products) { + localStorage.products = JSON.stringify(products); + }; + var addProduct = function(id, name, summary, price, quantity, image, seatObj) { + var products = getAllProducts(); + products.push({ + id: id, + name: name, + summary: summary, + price: price, + quantity: quantity, + image: image, + seatObj: seatObj, + }); + setAllProducts(products); + }; + + /* + PUBLIC + */ + var getAllProducts = function() { + try { + var products = JSON.parse(localStorage.products); + return products; + } + catch (e) { + return []; + } + }; + var updatePoduct = function(id, quantity) { + var productIndex = getIndexOfProduct(id); + if (productIndex < 0) { + return false; + } + var products = getAllProducts(); + products[productIndex].quantity = typeof quantity === "undefined" ? products[productIndex].quantity * 1 + 1 : quantity; + setAllProducts(products); + return true; + }; + var updatePrice = function(id, price) { + var productIndex = getIndexOfProduct(id); + if (productIndex < 0) { + return false; + } + var products = getAllProducts(); + // products[productIndex].quantity = typeof quantity === "undefined" ? products[productIndex].quantity * 1 + 1 : quantity; + products[productIndex].price = price; + setAllProducts(products); + return true; + }; + var setProduct = function(id, name, summary, price, quantity, image, seatObj) { + if (typeof id === "undefined") { + console.error("id required"); + return false; + } + if (typeof name === "undefined") { + console.error("name required"); + return false; + } + if (typeof image === "undefined") { + console.error("image required"); + return false; + } + if (!$.isNumeric(price)) { + console.error("price is not a number"); + return false; + } + if (!$.isNumeric(quantity)) { + console.error("quantity is not a number"); + return false; + } + if (typeof seatObj === "undefined") { + console.error("seatObj required"); + return false; + } + summary = typeof summary === "undefined" ? "" : summary; + + if (!updatePoduct(id)) { + addProduct(id, name, summary, price, quantity, image, seatObj); + } + }; + var clearProduct = function() { + setAllProducts([]); + }; + var removeProduct = function(id) { + var products = getAllProducts(); + products = $.grep(products, function(value, index) { + return value.id != id; + }); + setAllProducts(products); + }; + var getTotalQuantity = function() { + var total = 0; + var products = getAllProducts(); + $.each(products, function(index, value) { + total += value.quantity * 1; + }); + return total; + }; + var getTotalPrice = function() { + var products = getAllProducts(); + var total = 0; + $.each(products, function(index, value) { + total += value.quantity * value.price; + total = MathHelper.getRoundedNumber(total) * 1; + }); + return total; + }; + + objToReturn.getAllProducts = getAllProducts; + objToReturn.updatePoduct = updatePoduct; + objToReturn.updatePrice = updatePrice; + objToReturn.setProduct = setProduct; + objToReturn.clearProduct = clearProduct; + objToReturn.removeProduct = removeProduct; + objToReturn.getTotalQuantity = getTotalQuantity; + objToReturn.getTotalPrice = getTotalPrice; + return objToReturn; + }()); + + + var loadMyCartEvent = function(targetSelector) { + + var options = OptionManager.getOptions(); + var $cartIcon = $("." + options.classCartIcon); + $cartBadge = $("." + options.classCartBadge); + var classProductQuantity = options.classProductQuantity; + var classProductRemove = options.classProductRemove; + var classCheckoutCart = options.classCheckoutCart; + + idCartModal = 'my-cart-modal'; + var idCartTable = 'my-cart-table'; + var idGrandTotal = 'my-cart-grand-total'; + var idEmptyCartMessage = 'my-cart-empty-message'; + var idDiscountPrice = 'my-cart-discount-price'; + var classProductTotal = 'my-product-total'; + var classAffixMyCartIcon = 'my-cart-icon-affix'; + + + if (options.cartItems && options.cartItems.constructor === Array) { + ProductManager.clearProduct(); + $.each(options.cartItems, function() { + ProductManager.setProduct(this.id, this.name, this.summary, this.price, this.quantity, this.image); + }); + } + + $cartBadge.text(ProductManager.getTotalQuantity()); + + if (!$("#" + idCartModal).length) { + var modal_body = 'Bitte überprüfen Sie Ihre Plätze. Dies ist die letze Möglichkeit, um ggfs. die Ermäßigung zu ändern.'; + if (extra_param['note']) { + modal_body = modal_body + '
' + extra_param['note']; + } + + $('body').append( + '' + ); + } + + drawTable = function() { + var DATA = jqxhr.responseJSON; + + var $cartTable = $("#" + idCartTable); + $cartTable.empty(); + + var products = ProductManager.getAllProducts(); + + $.each(products, function() { + var total = this.quantity * this.price; + + // OPTION DROPDOWN + var selectID = 'select' + this.id; + var select = "/)[1]; + console.log(errorMsg); + + if (errorMsg === '') { + successful = true; + + ProductManager.clearProduct(); + $cartBadge.text(ProductManager.getTotalQuantity()); + $("#" + idCartModal).modal("hide"); + + // REDIRECT TO TICKET PURCHASE + console.log('successfull, now going to: ' + checkoutURL); + window.location.replace(checkoutURL); + // window.open(checkoutURL, '_blank'); + // window.location.replace(proxyCheckoutURL); + } + else { + successful = false; + errorMsg = errorMsg.replace(/\/g, ' '); + + new jBox('Notice', { + content: errorMsg, + color: 'red', + width: '100vw', + responsiveWidth: true, + position: { x: 'center', y: 'top' }, + autoClose: 10000, + closeButton: 'box', + }); + } + } + }); + + return successful; +} + +function untickSeat(id) { + if (DATA.CONFIG['DEBUG']) console.log(getFuncName()); + console.log(id); + document.getElementById(id).click(); // Click on the checkbox +} + +function selectRefreshPrice(select) { + if (DATA.CONFIG['DEBUG']) console.log(getFuncName()); + + if (DATA.CONFIG['DEBUG']) console.log(select); + + var $sel = $(select); + var value = $sel.val(); + var text = $("option:selected", $sel).text(); + var idSelect = $sel[0].id; + var id = idSelect.replace("select", ""); + + ProductManager.updatePrice(id, value); + selectOptionSelected[idSelect] = { selected: text }; // Remember Select Option Value for redraw in drawTable() + // drawTable(); +} + +function setSelectedIndex() { + if (DATA.CONFIG['DEBUG']) console.log(getFuncName()); + + for (var idSelect in selectOptionSelected) { + if (selectOptionSelected.hasOwnProperty(idSelect)) { + var s = document.getElementById(idSelect); + var v = selectOptionSelected[idSelect].selected; + + if (s == null) { + delete selectOptionSelected[idSelect]; + continue; + } + else { + for (var i = 0; i < s.options.length; i++) { + if (s.options[i].text === v) { + if (DATA.CONFIG['DEBUG']) console.log(s.options[i].text + ' matches ' + v); + if (DATA.CONFIG['DEBUG']) console.log(v); + if (DATA.CONFIG['DEBUG']) console.log(s); + s.options[i].selected = true; + selectRefreshPrice(s); // FIX RIGHT PRICE OPTION DROPDOWN + } + } + } + + } + } +} + +function generateSeatmap(DATA) { + if (DATA.CONFIG['DEBUG']) console.log(getFuncName()); + + var returnArr = generateMapMatrix(DATA); + var map1d = returnArr[0]; + var seatsUnavailable = returnArr[1]; + var mappingPricescalesSections = returnArr[2]; + var rows = returnArr[3]; + var seats = generateSeats(DATA, mappingPricescalesSections); + var legend = generateLegend(DATA, 'legend'); + var firstSeatLabel = 1; + + // CHANGE HTML TITLE + document.title = DATA.EVENT.DESC + ' | Saalplanbuchung by Tickets.com'; + + // CUSTOM CONFIG SETTINGS FOR SEATMAP + var left = true; + if (typeof DATA.CONFIG[DATA.VENUE.CODE]["LEFT_NAMING"] != "undefined") { + left = DATA.CONFIG[DATA.VENUE.CODE]["LEFT_NAMING"]; + } + + // SEAT MAP + sc = $('#seat-map').seatCharts({ + map: map1d, + seats: seats, + + naming: { + top: false, + left: left, + // rows: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + rows: rows, + // columns: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y'], + getLabel: function(character, row, column) { + return firstSeatLabel++; + }, + }, + legend: legend, + click: function() { + if (this.status() == 'available') { + if ((ProductManager.getTotalQuantity() + 1) > DATA.CONFIG[DATA.VENUE.CODE]["MAX_TICKETS_PER_USER"]) { + var errorMsg = 'Maximale Ticketantahl erreicht: Sie können nicht mehr als ' + DATA.CONFIG[DATA.VENUE.CODE]["MAX_TICKETS_PER_USER"] + ' Tickets buchen.'; + new jBox('Notice', { + content: errorMsg, + color: 'red', + width: '100vw', + responsiveWidth: true, + position: { x: 'center', y: 'top' }, + closeButton: 'box', + autoClose: 10000, + }); + return; + } + + // ADD PRODUCT TO CART + fillSeatObjData(this.settings.id, DATA); + myCartAddWrapper(this.settings.id, this.settings.data.product, this.settings.data.color, this.settings.data.price, 1, '', this); + + return 'selected'; + } + else if (this.status() == 'selected') { + myCartRemoveWrapper(this.settings.id); + return 'available'; + } + else if (this.status() == 'unavailable') { + //seat has been already booked + console.log('unavailable'); + return 'unavailable'; + } + else { + return this.style(); + } + } + }); + + // INIT JBOX TOOLTIP + var jbox = new jBox('Tooltip', { + attach: '.available', + trigger: 'mouseenter', + onCreated: function() { + if (DATA.CONFIG['DEBUG']) console.log("onCreated"); + }, + onOpen: function() { + // GET SEAT ID AND OBJECT + var seatID = this.source.context.id; + var seatObj = sc.get(seatID); + // console.log(seatObj); + + if (seatID == '' || seatObj.settings.status == 'unavailable') { + if (DATA.CONFIG['DEBUG']) console.log("Not a real seat or seat unavailable -> Return."); + return; + } + + // FILL SEAT OBJECT IF NOT ALREADY + fillSeatObjData(seatID, DATA); + + // SET JBOX CONTENT + this.setContent(seatObj.settings.data.productJBox); + }, + onClose: function() {} + }); + + // DETACH JBOX FROM LEGEND AND UNAVAILABLE SEATS + for (var i = 0; i < jbox.attachedElements.length; i++) { + if (jbox.attachedElements[i].id == "") { + jbox.detach($(jbox.attachedElements[i])); + i = -1; + continue; + } + } + for (var j = 0; j < seatsUnavailable.length; j++) { + jbox.detach($('#' + seatsUnavailable[j])); + } + + // MYCART + $(function() { + var goToCartIcon = function($addTocartBtn) { + var $cartIcon = $(".my-cart-icon"); + var $image = $('').css({ "position": "fixed", "z-index": "999" }); + $addTocartBtn.prepend($image); + var position = $cartIcon.position(); + $image.animate({ + top: position.top, + left: position.left + }, 500, "linear", function() { + $image.remove(); + }); + }; + }); + + // RUN POST GENERATION HOOKS + sc.status(seatsUnavailable, 'unavailable'); // seatsUnavailable RECEIVED FROM SERVER + seperateSeatmapsCSS(DATA); // CSS CHANGES AFTER GENERATE + venueSpecificCSS(DATA); + $(window).trigger('resize'); +} + +function venueSpecificCSS(DATA) { + if (DATA.CONFIG['DEBUG']) console.log(getFuncName()); + + // VENUE SPECIFIC WIDTH TO CENTER FRONT INDICATORS + var paddingLeft = DATA.CONFIG[DATA.VENUE.CODE]["PADDING-LEFT"]; + $(".front-indicator").css({ "padding-left": paddingLeft }); + var paddingLeftStage = DATA.CONFIG[DATA.VENUE.CODE]["PADDING-LEFT-STAGE"]; + $(".stage-indicator").css({ "padding-left": paddingLeftStage }); + + // STAATSOPERETTE DRESDEN SPECIFIC + if (DATA.VENUE.CODE == "SAAL KKM" || DATA.VENUE.CODE == "GSP KKM") { + $("#seat-map").append(DATA.CONFIG[DATA.VENUE.CODE]["TONPULT"]); + } + + // VENUE SPECIFIC CSS + if (DATA.CONFIG['DEBUG']) console.log('Applying venue specific CSS for ' + DATA.CONFIG[DATA.VENUE.CODE]); + var styleSheet = document.createElement("style"); + styleSheet.type = "text/css"; + styleSheet.innerText = DATA.CONFIG[DATA.VENUE.CODE]["CSS"]; + document.head.appendChild(styleSheet); +} diff --git a/seatmap-client/seatmap090120.js b/seatmap-client/seatmap090120.js new file mode 100644 index 0000000..0e988bd --- /dev/null +++ b/seatmap-client/seatmap090120.js @@ -0,0 +1,2257 @@ +// GLOBAL +var $cartBadge; +var options; +var drawTable; +var jqxhr; +var selectOptionSelected = {}; +var sc; +var inputsWithValue = []; +var showModal; +var param = new Object; +var idCartModal; +var ProductManager; +var seatmapWorkflowURL; + +var branch = 'seatmap_main'; +var config = { + "TAD": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "LEFT_NAMING": false, + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 0.8vw; \ + width: 0.8vw; \ + line-height: 1.5vw; \ + } \ + @media (min-width: 628px) and (max-width: 766px) { \ + div.seatCharts-cell { \ + height: 0.794vw; \ + width: 0.794vw; \ + } \ + } \ + @media (min-width: 498px) and (max-width: 627px) { \ + div.seatCharts-cell { \ + height: 0.786vw; \ + width: 0.786vw; \ + } \ + } \ + @media (min-width: 477px) and (max-width: 497px) { \ + div.seatCharts-cell { \ + height: 0.78vw; \ + width: 0.78vw; \ + } \ + } \ + @media (min-width: 400px) and (max-width: 476px) { \ + div.seatCharts-cell { \ + height: 0.77vw; \ + width: 0.77vw; \ + } \ + } \ + ', + }, + "KLEINER": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CUSTOM_PRICESCALES_COLOR": { + 1824661: "228B22", + 2542349: "8B4513", + 2542350:"4682B4", + }, + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.43vw; \ + width: 1.43vw; \ + line-height: 1.5vw; \ + } \ + @media (min-width: 400px) and (max-width: 540px) { \ + div.seatCharts-cell { \ + height: 1.398vw; \ + width: 1.398vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "INT_TH_3": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CUSTOM_PRICESCALES_COLOR": { + 5273153: "228B22", + }, + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 2.6vw; \ + width: 2.6vw; \ + line-height: 2.5vw; \ + max-width: 30px; \ + max-height: 30px; \ + } \ + @media (min-width: 400px) and (max-width: 700px) { \ + div.seatCharts-cell { \ + height: 2.52vw; \ + width: 2.52vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "GRO_SAAL": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 0.9vw; \ + width: 0.9vw; \ + line-height: 1.4vw; \ + } \ + ', + }, + "STADTHAL": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "BOTTOM", + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.85vw; \ + width: 1.85vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 400px) and (max-width: 480px) { \ + div.seatCharts-cell { \ + height: 1.81vw; \ + width: 1.81vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "STUDIONU": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "BOTTOM", + "CUSTOM_PRICESCALES_COLOR": { + 2447833: "B9DEA0", + }, + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.85vw; \ + width: 1.85vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 400px) and (max-width: 480px) { \ + div.seatCharts-cell { \ + height: 1.81vw; \ + width: 1.81vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "GR.SAAL": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "BOTTOM", + "CUSTOM_PRICESCALES_COLOR": { + 152965: "FFFF00", + 152966: "FF0000", + 152967: "74DF00", + 152968: "0080FF", + }, + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.19vw; \ + width: 1.19vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 445px) and (max-width: 555px) { \ + div.seatCharts-cell { \ + height: 1.17vw; \ + width: 1.17vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + @media (min-width: 400px) and (max-width: 444px) { \ + div.seatCharts-cell { \ + height: 1.15vw; \ + width: 1.15vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "THEATHOF": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "50%", + "PADDING-LEFT-STAGE": "50%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "BOTTOM", + "CUSTOM_PRICESCALES_COLOR": { + 2446505: "FFFF00", + 2446506: "FF0000", + 2446507: "74DF00", + 2446508: "0080FF", + }, + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.2vw; \ + width: 1.2vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 530px) and (max-width:768px) { \ + div.seatCharts-cell { \ + height: 1.24vw; \ + width: 1.24vw; \ + } \ + } \ + @media (min-width: 405px) and (max-width:529px) { \ + div.seatCharts-cell { \ + height: 1.215vw; \ + width: 1.215vw; \ + } \ + } \ + @media (min-width: 400px) and (max-width: 768px) { \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "THEATER": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "60%", + "PADDING-LEFT-STAGE": "47%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.54vw; \ + width: 1.54vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 400px) and (max-width:530px) { \ + div.seatCharts-cell { \ + height: 1.505vw; \ + width: 1.505vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "NEUES TH": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "50%", + "PADDING-LEFT-STAGE": "50%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 3.47vw !important; \ + width: 3.47vw !important; \ + max-width: 27px; \ + max-height: 27px; \ + line-height: 1.4vw; \ + } \ + @media all and (-ms-high-contrast: none), \ + (-ms-high-contrast: active) { \ + div.seatCharts-cell { \ + height: 3.55vw !important; \ + width: 3.55vw !important; \ + } \ + } \ + ', + }, + "SAAL KKM": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "47%", + "Tonpult": "

Tonpult

", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": ' \ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.3vw; \ + width: 1.3vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 411px) and (max-width:539px) { \ + div.seatCharts-cell { \ + height: 1.275vw; \ + width: 1.275vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + @media (min-width: 400px) and (max-width:410px) { \ + div.seatCharts-cell { \ + height: 1.25vw; \ + width: 1.25vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "GSP KKM": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "47%", + "Tonpult": "

Tonpult

", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": ' \ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.39vw; \ + width: 1.39vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 400px) and (max-width:504px) { \ + div.seatCharts-cell { \ + height: 1.36vw; \ + width: 1.36vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + 'KOM├ÛDIE': { + "PADDING-LEFT": "47%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": ' \ + .booking-details p,li { \ + font-size: 1.0vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1.0vw; \ + } \ + div.seatCharts-cell { \ + height: 2.72vw; \ + width: 2.72vw; \ + line-height: 1.4vw; \ + max-height: 25px; \ + max-width: 25px; \ + } \ + @media (min-width: 400px) and (max-width:405px) { \ + div.seatCharts-cell { \ + height: 2.7vw; \ + width: 2.7vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + @media (min-width: 406px) and (max-width:768px) { \ + div.seatCharts-cell { \ + height: 2.72vw; \ + width: 2.72vw; \ + } \ + } \ + ', + }, + "THEATER AM DOM": { + "AGENCY": "TADK", + "BUYER_TYPES": { + "Z1": "Vollzahler", + } + }, + "GRO├ƑER SAAL": { + "AGENCY": "GMB1", + "BUYER_TYPES": { + "01": "Vollzahler", + } + }, + "KLEINER SAAL": { + "AGENCY": "GMB1", + "BUYER_TYPES": { + "01": "Vollzahler", + } + }, + "INTIMES THEATER BESTUHLT": { + "AGENCY": "GMB1", + "BUYER_TYPES": { + "01": "Vollzahler", + } + }, + "THEATER HOF": { + "AGENCY": "THOF", + "BUYER_TYPES": { + "I1": "Vollzahler", + "I3": "Behinderte mit Ausweis", + "I2": "Schüler", + "IE": "Erwachsener", + "IK": "Kind", + } + }, + "STUDIO NUMMERIERT": { + "AGENCY": "THOF", + "BUYER_TYPES": { + "I1": "Vollzahler", + "I3": "Behinderte mit Ausweis", + "I2": "Schüler", + "IE": "Erwachsener", + "IK": "Kind", + } + }, + "KOMÖDIE BRAUNSCHWEIG": { + "AGENCY": "KOMB", + "BUYER_TYPES": { + "IV": "Vollzahler", + "IE": "Ermäßigt", + "IG": "Gutschein", + "ME": "Vollzahler", + "MK": "Ermäßigt", + "NI": "Ermäßigt", + "NN": "Vollzahler", + } + }, + "THEATER IM RATHAUS": { + "AGENCY": "TIRE", + "BUYER_TYPES": { + "I1": "Vollzahler", + "I2": "Ermäßigt", + "FR": "Freitag_13", + } + }, + "NEUES THEATER HANNOVER": { + "AGENCY": "NTHH", + "BUYER_TYPES": { + "WW": "Vollzahler", + } + }, + "STAATSOPERETTE DRESDEN": { + "AGENCY": "SOPD", + "BUYER_TYPES": { + "97": "Vollzahler", + "A0": "Ermäßigt", + "A5": "Online-Aktion", + "95": "Aktionspreis", + "09": "Schüler", + "A6": "Kind bis 18 J.", + "86": "Buch", + "85": "CD", + "00": "Tagespreis", + "03": "Tagespreis ermäßigt", + "98": "Aktionspreis", + "31": "Studenten/Azubis bis 27 J.", + "23": "Andere Gäste", + } + }, + "SEATMAP-SERVER": { + "ROOT_URL": "https://zinomedia.de/" + branch + "/seatmap-server/seatmap-server.pl", + }, + "CORS-ANYWHERE": { + "ROOT_URL": "https://cors.zinomedia.de/", + }, + "DEBUG": true, + "SEATMAP_VERSION": "0.9.6", + "CURRENCY_SYMBOL": "€", +}; +if (branch === 'seatmap_testing') config["SEATMAP_VERSION"] = config["SEATMAP_VERSION"] + ' (testing)'; + +var checkoutParam = [ + 'request_type', 'trxstate', 'request_action', 'agency', 'etpgcode', 'parent_offer_id', 'flashDetected', 'recapToken', 'age_consent_is_checked', 'jcarousel_auto_off_val', 'selected_seat_indexes', 'ism_map_current_state_json_data', 'is_availability_switch_from_map', 'map_coupon_code', 'is_ticket_exchange_request', 'prevtrxstate', 'user_context', 'gid', 'target_trxstate', 'target_prev_trxstate', 'target_url', 'target_name_value', 'orgid', 'p_orgid', 'pid', 'redeem_voucher_data_event_mapping', 'supplier_code', 'valid_coupon_code_message', 'replay_request', 'inventory_filtering_action', 'inventory_month', 'inventory_year', 'upsell_selected', 'listing_type', 'invalid_seats', 'package_pids', 's_mem_tkt_ren_retrieval', 'mlbamsp', 'pay_pal_token', 'dpa_selection', 'timeout_seconds', 'APPTE', 'schedule', 'hbx_discounts', 'hbx_discount_prices', 'hbx_selected_tixx', 'hbx_requested_pg', 'hbx_offered_pg', 'hbx_pids', 'hbx_perf_codes', 'hbx_perf_sub_codes', 'hbx_upsell_flag', 'selected_upsell_option', 'cancelAndRedirectTrxState', 'secure_trxn_enabled', 'isCapEnabled', 'mainEventPID', 'discountdesc=A=97', 'discountprice=A=97', 'discountfees=A=97', 'discount=A=97', 'discountdesc=A=A0', 'discountprice=A=A0', 'discountfees=A=A0', 'discount=A=A0', 'supplierCode', +]; + +// POLYPHILL repeat() +if (!String.prototype.repeat) { + String.prototype.repeat = function(count) { + 'use strict'; + if (this == null) + throw new TypeError('can\'t convert ' + this + ' to object'); + + var str = '' + this; + // To convert string to integer. + count = +count; + // Check NaN + if (count != count) + count = 0; + + if (count < 0) + throw new RangeError('repeat count must be non-negative'); + + if (count == Infinity) + throw new RangeError('repeat count must be less than infinity'); + + count = Math.floor(count); + if (str.length == 0 || count == 0) + return ''; + + // Ensuring count is a 31-bit integer allows us to heavily optimize the + // main part. But anyway, most current (August 2014) browsers can't handle + // strings 1 << 28 chars or longer, so: + if (str.length * count >= 1 << 28) + throw new RangeError('repeat count must not overflow maximum string size'); + + var maxCount = str.length * count; + count = Math.floor(Math.log(count) / Math.log(2)); + while (count) { + str += str; + count--; + } + str += str.substring(0, maxCount - str.length); + return str; + } +} + +// EVENT DOMCONTENTLOADED +document.addEventListener("DOMContentLoaded", ready); +window.onload = function() { + if (config['DEBUG']) console.log(getFuncName()); + + checkDebug(); +}; + +// EVENT CONTAINER VISIBLE +if ($('.container-fluid').is(':visible')) { + if (config['DEBUG']) console.log("Visible"); + + var IEdetected = detectIE(); + if (config['DEBUG']) console.log("IE " + IEdetected); + if (parseInt(IEdetected) < 12) { + $('#IEdetected').show(); + throw new Error("IE " + IEDetected + " not supported."); + } + init(); + + var decoded_uri = decodeURIComponent(getParamValue('posturl')); + getParamsFromPosturl(decoded_uri); + + if (config['DEBUG']) console.log(param); + + seatmapWorkflow(decoded_uri); +} + +function getParamsFromPosturl(decoded_uri) { + if (config['DEBUG']) console.log(getFuncName()); + console.log(decoded_uri); + + var checkoutParam = [ + 'APPTE', 'age_consent_is_checked', 'agency', 'cancelAndRedirectTrxState', 'cogid', 'coids', 'discount=A=IE', 'discount=A=IV', 'discountdesc=A=IE', 'discountdesc=A=IV', 'discountfees=A=IE', 'discountfees=A=IV', 'discountprice=A=IE', 'discountprice=A=IV', 'dpa_selection', 'etpgcode', 'flashDetected', 'gid', 'hbx_discount_prices', 'hbx_discounts', 'hbx_offered_pg', 'hbx_perf_codes', 'hbx_perf_sub_codes', 'hbx_pids', 'hbx_requested_pg', 'hbx_selected_tixx', 'hbx_upsell_flag', 'request_type', 'invalid_seats', 'inventory_filtering_action', 'inventory_month', 'inventory_year', 'isCapEnabled', 'is_availability_switch_from_map', 'is_ticket_exchange_request', 'ism_map_current_state_json_data', 'jcarousel_auto_off_val', 'listing_type', 'mainEventPID', 'map_coupon_code', 'mlbamsp', 'oid', 'ooids', 'orderkey', 'orgid', 'p_orgid', 'package_pids', 'parent_offer_id', 'pay_pal_token', 'pid', 'prevtrxstate', 'recapToken', 'redeem_voucher_data_event_mapping', 'replay_request', 'request_action', 's_mem_tkt_ren_retrieval', 'schedule', 'secure_trxn_enabled', 'selected_seat_indexes', 'selected_upsell_option', 'supplierCode', 'supplier_code', 'target_name_value', 'target_prev_trxstate', 'target_trxstate', 'target_url', 'timeout_seconds', 'trxstate', 'upsell_selected', 'user_context', 'valid_coupon_code_message' + ]; + for (var i = 0; i < checkoutParam.length; i++) { + var value = getParamValue(checkoutParam[i], decoded_uri); + if (value !== undefined) { + param[checkoutParam[i]] = getParamValue(checkoutParam[i], decoded_uri); + } + } +} + +// EVENT RESIZE +$(window).resize(function() { + if ($(window).width() < 400) { + $('.container-fluid').hide(); + $('#screenTooSmall').show(); + } + else { + $('.container-fluid').show(); + $('#screenTooSmall').hide(); + } +}); + +function detectIE () { + var ua = window.navigator.userAgent; + + var msie = ua.indexOf('MSIE '); + if (msie > 0) { + // IE 10 or older => return version number + return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10); + } + + var trident = ua.indexOf('Trident/'); + if (trident > 0) { + // IE 11 => return version number + var rv = ua.indexOf('rv:'); + return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10); + } + + var edge = ua.indexOf('Edge/'); + if (edge > 0) { + // Edge (IE 12+) => return version number + return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10); + } + + // other browser + return false; +} + +function init() { + if (config['DEBUG']) console.log(getFuncName()); + + /* + * jQuery myCart - v1.7 - 2018-03-07 + * http://asraf-uddin-ahmed.github.io/ + * Copyright (c) 2017 Asraf Uddin Ahmed; Licensed None + */ + + (function($) { + + "use strict"; + + var OptionManager = (function() { + var objToReturn = {}; + + var _options = null; + var DEFAULT_OPTIONS = { + currencySymbol: config["CURRENCY_SYMBOL"], + classCartIcon: 'my-cart-icon', + classCartBadge: 'my-cart-badge', + classProductQuantity: 'my-product-quantity', + classProductRemove: 'my-product-remove', + classCheckoutCart: 'my-cart-checkout', + affixCartIcon: true, + showCheckoutModal: true, + numberOfDecimals: 2, + cartItems: null, + clickOnAddToCart: function($addTocart) {}, + afterAddOnCart: function(products, totalPrice, totalQuantity) {}, + clickOnCartIcon: function($cartIcon, products, totalPrice, totalQuantity) {}, + checkoutCart: function(products, totalPrice, totalQuantity) { + if (config['DEBUG']) console.log("checkoutCart"); + return false; + }, + getDiscountPrice: function(products, totalPrice, totalQuantity) { + return null; + } + }; + + var loadOptions = function(customOptions) { + _options = $.extend({}, DEFAULT_OPTIONS); + if (typeof customOptions === 'object') { + $.extend(_options, customOptions); + } + }; + var getOptions = function() { + return _options; + }; + + objToReturn.loadOptions = loadOptions; + objToReturn.getOptions = getOptions; + return objToReturn; + }()); + + var MathHelper = (function() { + var objToReturn = {}; + var getRoundedNumber = function(number) { + if (isNaN(number)) { + throw new Error('Parameter is not a Number'); + } + number = number * 1; + options = OptionManager.getOptions(); + return number.toFixed(options.numberOfDecimals); + }; + objToReturn.getRoundedNumber = getRoundedNumber; + return objToReturn; + }()); + + ProductManager = (function() { + var objToReturn = {}; + var localStorage = {}; + + /* + PRIVATE + */ + // localStorage.products = localStorage.products ? localStorage.products : ""; + if (typeof localStorage.products !== "undefined") { + if (config['DEBUG']) console.log("localStorage defined"); + localStorage.products = ""; + } + else { + if (config['DEBUG']) console.log("localStorage undefined"); + } + + var getIndexOfProduct = function(id) { + var productIndex = -1; + var products = getAllProducts(); + $.each(products, function(index, value) { + if (value.id == id) { + productIndex = index; + return; + } + }); + return productIndex; + }; + var setAllProducts = function(products) { + localStorage.products = JSON.stringify(products); + }; + var addProduct = function(id, name, summary, price, quantity, image, seatObj) { + var products = getAllProducts(); + products.push({ + id: id, + name: name, + summary: summary, + price: price, + quantity: quantity, + image: image, + seatObj: seatObj, + }); + setAllProducts(products); + }; + + /* + PUBLIC + */ + var getAllProducts = function() { + try { + var products = JSON.parse(localStorage.products); + return products; + } + catch (e) { + return []; + } + }; + var updatePoduct = function(id, quantity) { + var productIndex = getIndexOfProduct(id); + if (productIndex < 0) { + return false; + } + var products = getAllProducts(); + products[productIndex].quantity = typeof quantity === "undefined" ? products[productIndex].quantity * 1 + 1 : quantity; + setAllProducts(products); + return true; + }; + var updatePrice = function(id, price) { + var productIndex = getIndexOfProduct(id); + if (productIndex < 0) { + return false; + } + var products = getAllProducts(); + // products[productIndex].quantity = typeof quantity === "undefined" ? products[productIndex].quantity * 1 + 1 : quantity; + products[productIndex].price = price; + setAllProducts(products); + return true; + }; + var setProduct = function(id, name, summary, price, quantity, image, seatObj) { + if (typeof id === "undefined") { + console.error("id required"); + return false; + } + if (typeof name === "undefined") { + console.error("name required"); + return false; + } + if (typeof image === "undefined") { + console.error("image required"); + return false; + } + if (!$.isNumeric(price)) { + console.error("price is not a number"); + return false; + } + if (!$.isNumeric(quantity)) { + console.error("quantity is not a number"); + return false; + } + if (typeof seatObj === "undefined") { + console.error("seatObj required"); + return false; + } + summary = typeof summary === "undefined" ? "" : summary; + + if (!updatePoduct(id)) { + addProduct(id, name, summary, price, quantity, image, seatObj); + } + }; + var clearProduct = function() { + setAllProducts([]); + }; + var removeProduct = function(id) { + var products = getAllProducts(); + products = $.grep(products, function(value, index) { + return value.id != id; + }); + setAllProducts(products); + }; + var getTotalQuantity = function() { + var total = 0; + var products = getAllProducts(); + $.each(products, function(index, value) { + total += value.quantity * 1; + }); + return total; + }; + var getTotalPrice = function() { + var products = getAllProducts(); + var total = 0; + $.each(products, function(index, value) { + total += value.quantity * value.price; + total = MathHelper.getRoundedNumber(total) * 1; + }); + return total; + }; + + objToReturn.getAllProducts = getAllProducts; + objToReturn.updatePoduct = updatePoduct; + objToReturn.updatePrice = updatePrice; + objToReturn.setProduct = setProduct; + objToReturn.clearProduct = clearProduct; + objToReturn.removeProduct = removeProduct; + objToReturn.getTotalQuantity = getTotalQuantity; + objToReturn.getTotalPrice = getTotalPrice; + return objToReturn; + }()); + + + var loadMyCartEvent = function(targetSelector) { + + var options = OptionManager.getOptions(); + var $cartIcon = $("." + options.classCartIcon); + $cartBadge = $("." + options.classCartBadge); + var classProductQuantity = options.classProductQuantity; + var classProductRemove = options.classProductRemove; + var classCheckoutCart = options.classCheckoutCart; + + idCartModal = 'my-cart-modal'; + var idCartTable = 'my-cart-table'; + var idGrandTotal = 'my-cart-grand-total'; + var idEmptyCartMessage = 'my-cart-empty-message'; + var idDiscountPrice = 'my-cart-discount-price'; + var classProductTotal = 'my-product-total'; + var classAffixMyCartIcon = 'my-cart-icon-affix'; + + + if (options.cartItems && options.cartItems.constructor === Array) { + ProductManager.clearProduct(); + $.each(options.cartItems, function() { + ProductManager.setProduct(this.id, this.name, this.summary, this.price, this.quantity, this.image); + }); + } + + $cartBadge.text(ProductManager.getTotalQuantity()); + + if (!$("#" + idCartModal).length) { + $('body').append( + '' + ); + } + + drawTable = function() { + var DATA = jqxhr.responseJSON; + + var $cartTable = $("#" + idCartTable); + $cartTable.empty(); + + var products = ProductManager.getAllProducts(); + + $.each(products, function() { + var total = this.quantity * this.price; + + // OPTION DROPDOWN + var selectID = 'select' + this.id; + var select = "/)[1]; + console.log(errorMsg); + + if (errorMsg === '') { + successful = true; + + ProductManager.clearProduct(); + $cartBadge.text(ProductManager.getTotalQuantity()); + $("#" + idCartModal).modal("hide"); + + // REDIRECT TO TICKET PURCHASE + console.log('successfull, now going to: ' + checkoutURL); + window.location.replace(checkoutURL); + // window.open(checkoutURL, '_blank'); + // window.location.replace(proxyCheckoutURL); + } + else { + successful = false; + errorMsg = errorMsg.replace(/\/g, ' '); + + new jBox('Notice', { + content: errorMsg, + color: 'red', + width: '100vw', + responsiveWidth: true, + position: { x: 'center', y: 'top' }, + autoClose: 10000, + closeButton: 'box', + }); + } + } + }); + + return successful; +} + +function untickSeat(id) { + if (config['DEBUG']) console.log(getFuncName()); + console.log(id); + document.getElementById(id).click(); // Click on the checkbox +} + +function selectRefreshPrice(select) { + if (config['DEBUG']) console.log(getFuncName()); + + if (config['DEBUG']) console.log(select); + + var $sel = $(select); + var value = $sel.val(); + var text = $("option:selected", $sel).text(); + var idSelect = $sel[0].id; + var id = idSelect.replace("select", ""); + + ProductManager.updatePrice(id, value); + selectOptionSelected[idSelect] = { selected: text }; // Remember Select Option Value for redraw in drawTable() + // drawTable(); +} + +function setSelectedIndex() { + if (config['DEBUG']) console.log(getFuncName()); + + for (var idSelect in selectOptionSelected) { + if (selectOptionSelected.hasOwnProperty(idSelect)) { + var s = document.getElementById(idSelect); + var v = selectOptionSelected[idSelect].selected; + + if (s == null) { + delete selectOptionSelected[idSelect]; + continue; + } + else { + for (var i = 0; i < s.options.length; i++) { + if (s.options[i].text === v) { + if (config['DEBUG']) console.log(s.options[i].text + ' matches ' + v); + if (config['DEBUG']) console.log(v); + if (config['DEBUG']) console.log(s); + s.options[i].selected = true; + selectRefreshPrice(s); // FIX RIGHT PRICE OPTION DROPDOWN + } + } + } + + } + } +} + +function generateSeatmap(DATA) { + if (config['DEBUG']) console.log(getFuncName()); + + var returnArr = generateMapMatrix(DATA); + var map1d = returnArr[0]; + var seatsUnavailable = returnArr[1]; + var mappingPricescalesSections = returnArr[2]; + var rows = returnArr[3]; + var seats = generateSeats(DATA, mappingPricescalesSections); + var legend = generateLegend(DATA, 'legend'); + var firstSeatLabel = 1; + + // CHANGE HTML TITLE + document.title = DATA.EVENT.DESC + ' | Saalplanbuchung by Tickets.com'; + + // CUSTOM CONFIG SETTINGS FOR SEATMAP + var left = true; + if (typeof config[DATA.VENUE.CODE]["LEFT_NAMING"] != "undefined") { + left = config[DATA.VENUE.CODE]["LEFT_NAMING"]; + } + + // SEAT MAP + sc = $('#seat-map').seatCharts({ + map: map1d, + seats: seats, + + naming: { + top: false, + left: left, + // rows: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + rows: rows, + // columns: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y'], + getLabel: function(character, row, column) { + return firstSeatLabel++; + }, + }, + legend: legend, + click: function() { + if (this.status() == 'available') { + if ((ProductManager.getTotalQuantity() + 1) > config[DATA.VENUE.CODE]["MAX_TICKETS_PER_USER"]) { + var errorMsg = 'Maximale Ticketantahl erreicht: Sie können nicht mehr als ' + config[DATA.VENUE.CODE]["MAX_TICKETS_PER_USER"] + ' Tickets buchen.'; + new jBox('Notice', { + content: errorMsg, + color: 'red', + width: '100vw', + responsiveWidth: true, + position: { x: 'center', y: 'top' }, + closeButton: 'box', + autoClose: 10000, + }); + return; + } + + // ADD PRODUCT TO CART + fillSeatObjData(this.settings.id); + myCartAddWrapper(this.settings.id, this.settings.data.product, this.settings.data.color, this.settings.data.price, 1, '', this); + + return 'selected'; + } + else if (this.status() == 'selected') { + myCartRemoveWrapper(this.settings.id); + return 'available'; + } + else if (this.status() == 'unavailable') { + //seat has been already booked + console.log('unavailable'); + return 'unavailable'; + } + else { + return this.style(); + } + } + }); + + // INIT JBOX TOOLTIP + var jbox = new jBox('Tooltip', { + attach: '.available', + trigger: 'mouseenter', + onCreated: function() { + if (config['DEBUG']) console.log("onCreated"); + }, + onOpen: function() { + // GET SEAT ID AND OBJECT + var seatID = this.source.context.id; + var seatObj = sc.get(seatID); + // console.log(seatObj); + + if (seatID == '' || seatObj.settings.status == 'unavailable') { + if (config['DEBUG']) console.log("Not a real seat or seat unavailable -> Return."); + return; + } + + // FILL SEAT OBJECT IF NOT ALREADY + fillSeatObjData(seatID); + + // SET JBOX CONTENT + this.setContent(seatObj.settings.data.productJBox); + }, + onClose: function() {} + }); + + // DETACH JBOX FROM LEGEND AND UNAVAILABLE SEATS + for (var i = 0; i < jbox.attachedElements.length; i++) { + if (jbox.attachedElements[i].id == "") { + jbox.detach($(jbox.attachedElements[i])); + i = -1; + continue; + } + } + for (var j = 0; j < seatsUnavailable.length; j++) { + jbox.detach($('#' + seatsUnavailable[j])); + } + + // MYCART + $(function() { + var goToCartIcon = function($addTocartBtn) { + var $cartIcon = $(".my-cart-icon"); + var $image = $('').css({ "position": "fixed", "z-index": "999" }); + $addTocartBtn.prepend($image); + var position = $cartIcon.position(); + $image.animate({ + top: position.top, + left: position.left + }, 500, "linear", function() { + $image.remove(); + }); + }; + }); + + // RUN POST GENERATION HOOKS + sc.status(seatsUnavailable, 'unavailable'); // seatsUnavailable RECEIVED FROM SERVER + seperateSeatmapsCSS(DATA); // CSS CHANGES AFTER GENERATE + venueSpecificCSS(DATA); + $(window).trigger('resize'); +} + +function venueSpecificCSS(DATA) { + if (config['DEBUG']) console.log(getFuncName()); + + // VENUE SPECIFIC WIDTH TO CENTER FRONT INDICATORS + var paddingLeft = config[DATA.VENUE.CODE]["PADDING-LEFT"]; + $(".front-indicator").css({ "padding-left": paddingLeft }); + var paddingLeftStage = config[DATA.VENUE.CODE]["PADDING-LEFT-STAGE"]; + $(".stage-indicator").css({ "padding-left": paddingLeftStage }); + + // STAATSOPERETTE DRESDEN SPECIFIC + if (DATA.VENUE.CODE == "SAAL KKM" || DATA.VENUE.CODE == "GSP KKM") { + $("#seat-map").append(config[DATA.VENUE.CODE]["Tonpult"]); + } + + // VENUE SPECIFIC CSS + if (config['DEBUG']) console.log('Applying venue specific CSS for ' + config[DATA.VENUE.CODE]); + var styleSheet = document.createElement("style"); + styleSheet.type = "text/css"; + styleSheet.innerText = config[DATA.VENUE.CODE]["CSS"]; + document.head.appendChild(styleSheet); +} diff --git a/seatmap-client/seatmap11_18_19.js b/seatmap-client/seatmap11_18_19.js new file mode 100644 index 0000000..73aee4f --- /dev/null +++ b/seatmap-client/seatmap11_18_19.js @@ -0,0 +1,2065 @@ +// GLOBAL +var $cartBadge; +var options; +var drawTable; +var jqxhr; +var selectOptionSelected = {}; +var sc; +var inputsWithValue = []; +var showModal; +var param = new Object; +var idCartModal; +var ProductManager; +var seatmapWorkflowURL; + +var branch = 'seatmap_main'; +var config = { + "STADTHAL": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "BOTTOM", + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.85vw; \ + width: 1.85vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 400px) and (max-width: 480px) { \ + div.seatCharts-cell { \ + height: 1.81vw; \ + width: 1.81vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "STUDIONU": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "BOTTOM", + "CUSTOM_PRICESCALES_COLOR": { + 2447833: "B9DEA0", + }, + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.85vw; \ + width: 1.85vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 400px) and (max-width: 480px) { \ + div.seatCharts-cell { \ + height: 1.81vw; \ + width: 1.81vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "GR.SAAL": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "BOTTOM", + "CUSTOM_PRICESCALES_COLOR": { + 152965: "FFFF00", + 152966: "FF0000", + 152967: "74DF00", + 152968: "0080FF", + }, + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.19vw; \ + width: 1.19vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 445px) and (max-width: 555px) { \ + div.seatCharts-cell { \ + height: 1.17vw; \ + width: 1.17vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + @media (min-width: 400px) and (max-width: 444px) { \ + div.seatCharts-cell { \ + height: 1.15vw; \ + width: 1.15vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "THEATHOF": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "50%", + "PADDING-LEFT-STAGE": "50%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "BOTTOM", + "CUSTOM_PRICESCALES_COLOR": { + 2446505: "FFFF00", + 2446506: "FF0000", + 2446507: "74DF00", + 2446508: "0080FF", + }, + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.2vw; \ + width: 1.2vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 530px) and (max-width:768px) { \ + div.seatCharts-cell { \ + height: 1.24vw; \ + width: 1.24vw; \ + } \ + } \ + @media (min-width: 405px) and (max-width:529px) { \ + div.seatCharts-cell { \ + height: 1.215vw; \ + width: 1.215vw; \ + } \ + } \ + @media (min-width: 400px) and (max-width: 768px) { \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "THEATER": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "60%", + "PADDING-LEFT-STAGE": "47%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.54vw; \ + width: 1.54vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 400px) and (max-width:530px) { \ + div.seatCharts-cell { \ + height: 1.505vw; \ + width: 1.505vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "NEUES TH": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "50%", + "PADDING-LEFT-STAGE": "50%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 3.47vw !important; \ + width: 3.47vw !important; \ + max-width: 27px; \ + max-height: 27px; \ + line-height: 1.4vw; \ + } \ + @media all and (-ms-high-contrast: none), \ + (-ms-high-contrast: active) { \ + div.seatCharts-cell { \ + height: 3.55vw !important; \ + width: 3.55vw !important; \ + } \ + } \ + ', + }, + "SAAL KKM": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "47%", + "Tonpult": "

Tonpult

", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": ' \ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.3vw; \ + width: 1.3vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 411px) and (max-width:539px) { \ + div.seatCharts-cell { \ + height: 1.275vw; \ + width: 1.275vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + @media (min-width: 400px) and (max-width:410px) { \ + div.seatCharts-cell { \ + height: 1.25vw; \ + width: 1.25vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "GSP KKM": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "47%", + "Tonpult": "

Tonpult

", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": ' \ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.39vw; \ + width: 1.39vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 400px) and (max-width:504px) { \ + div.seatCharts-cell { \ + height: 1.36vw; \ + width: 1.36vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + 'KOM├ÛDIE': { + "PADDING-LEFT": "47%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": ' \ + .booking-details p,li { \ + font-size: 1.0vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1.0vw; \ + } \ + div.seatCharts-cell { \ + height: 2.72vw; \ + width: 2.72vw; \ + line-height: 1.4vw; \ + max-height: 25px; \ + max-width: 25px; \ + } \ + @media (min-width: 400px) and (max-width:405px) { \ + div.seatCharts-cell { \ + height: 2.7vw; \ + width: 2.7vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + @media (min-width: 406px) and (max-width:768px) { \ + div.seatCharts-cell { \ + height: 2.72vw; \ + width: 2.72vw; \ + } \ + } \ + ', + }, + "GRO├ƑER SAAL": { + "AGENCY": "GMB1", + "BUYER_TYPES": { + "01": "Vollzahler", + } + }, + "THEATER HOF": { + "AGENCY": "THOF", + "BUYER_TYPES": { + "I1": "Vollzahler", + "I3": "Behinderte mit Ausweis", + "I2": "Schüler", + "IE": "Erwachsener", + "IK": "Kind", + } + }, + "STUDIO NUMMERIERT": { + "AGENCY": "THOF", + "BUYER_TYPES": { + "I1": "Vollzahler", + "I3": "Behinderte mit Ausweis", + "I2": "Schüler", + "IE": "Erwachsener", + "IK": "Kind", + } + }, + "KOMÖDIE BRAUNSCHWEIG": { + "AGENCY": "KOMB", + "BUYER_TYPES": { + "IV": "Vollzahler", + "IE": "Ermäßigt", + "IG": "Gutschein", + "ME": "Vollzahler", + "MK": "Ermäßigt", + "NI": "Ermäßigt", + "NN": "Vollzahler", + } + }, + "THEATER IM RATHAUS": { + "AGENCY": "TIRE", + "BUYER_TYPES": { + "I1": "Vollzahler", + "I2": "Ermäßigt", + } + }, + "NEUES THEATER HANNOVER": { + "AGENCY": "NTHH", + "BUYER_TYPES": { + "WW": "Vollzahler", + } + }, + "STAATSOPERETTE DRESDEN": { + "AGENCY": "SOPD", + "BUYER_TYPES": { + "97": "Vollzahler", + "A0": "Ermäßigt", + "A5": "Online-Aktion", + "95": "Aktionspreis", + "09": "Schüler", + "A6": "Kind bis 18 J.", + "86": "Buch", + "85": "CD", + "00": "Tagespreis", + "03": "Tagespreis ermäßigt", + "98": "Aktionspreis", + "31": "Studenten/Azubis bis 27 J.", + "23": "Andere Gäste", + } + }, + "SEATMAP-SERVER": { + "ROOT_URL": "https://zinomedia.de/" + branch + "/seatmap-server/seatmap-server.pl", + }, + "CORS-ANYWHERE": { + "ROOT_URL": "https://cors.zinomedia.de/", + }, + "DEBUG": true, + "SEATMAP_VERSION": "0.9.1", + "CURRENCY_SYMBOL": "€", +}; +if (branch === 'seatmap_testing') config["SEATMAP_VERSION"] = config["SEATMAP_VERSION"] + ' (testing)'; + +var checkoutParam = [ + 'request_type', 'trxstate', 'request_action', 'agency', 'etpgcode', 'parent_offer_id', 'flashDetected', 'recapToken', 'age_consent_is_checked', 'jcarousel_auto_off_val', 'selected_seat_indexes', 'ism_map_current_state_json_data', 'is_availability_switch_from_map', 'map_coupon_code', 'is_ticket_exchange_request', 'prevtrxstate', 'user_context', 'gid', 'target_trxstate', 'target_prev_trxstate', 'target_url', 'target_name_value', 'orgid', 'p_orgid', 'pid', 'redeem_voucher_data_event_mapping', 'supplier_code', 'valid_coupon_code_message', 'replay_request', 'inventory_filtering_action', 'inventory_month', 'inventory_year', 'upsell_selected', 'listing_type', 'invalid_seats', 'package_pids', 's_mem_tkt_ren_retrieval', 'mlbamsp', 'pay_pal_token', 'dpa_selection', 'timeout_seconds', 'APPTE', 'schedule', 'hbx_discounts', 'hbx_discount_prices', 'hbx_selected_tixx', 'hbx_requested_pg', 'hbx_offered_pg', 'hbx_pids', 'hbx_perf_codes', 'hbx_perf_sub_codes', 'hbx_upsell_flag', 'selected_upsell_option', 'cancelAndRedirectTrxState', 'secure_trxn_enabled', 'isCapEnabled', 'mainEventPID', 'discountdesc=A=97', 'discountprice=A=97', 'discountfees=A=97', 'discount=A=97', 'discountdesc=A=A0', 'discountprice=A=A0', 'discountfees=A=A0', 'discount=A=A0', 'supplierCode', +]; + +// POLYPHILL repeat() +if (!String.prototype.repeat) { + String.prototype.repeat = function(count) { + 'use strict'; + if (this == null) + throw new TypeError('can\'t convert ' + this + ' to object'); + + var str = '' + this; + // To convert string to integer. + count = +count; + // Check NaN + if (count != count) + count = 0; + + if (count < 0) + throw new RangeError('repeat count must be non-negative'); + + if (count == Infinity) + throw new RangeError('repeat count must be less than infinity'); + + count = Math.floor(count); + if (str.length == 0 || count == 0) + return ''; + + // Ensuring count is a 31-bit integer allows us to heavily optimize the + // main part. But anyway, most current (August 2014) browsers can't handle + // strings 1 << 28 chars or longer, so: + if (str.length * count >= 1 << 28) + throw new RangeError('repeat count must not overflow maximum string size'); + + var maxCount = str.length * count; + count = Math.floor(Math.log(count) / Math.log(2)); + while (count) { + str += str; + count--; + } + str += str.substring(0, maxCount - str.length); + return str; + } +} + +// EVENT DOMCONTENTLOADED +document.addEventListener("DOMContentLoaded", ready); +window.onload = function() { + if (config['DEBUG']) console.log(getFuncName()); + + checkDebug(); +}; + +// EVENT CONTAINER VISIBLE +if ($('.container-fluid').is(':visible')) { + if (config['DEBUG']) console.log("Visible"); + + var IEdetected = detectIE(); + if (config['DEBUG']) console.log("IE " + IEdetected); + if (parseInt(IEdetected) < 12) { + $('#IEdetected').show(); + throw new Error("IE " + IEDetected + " not supported."); + } + init(); + param["posturl"] = getParamValue('posturl'); + param["decodedURI"] = decodeURIComponent(param["posturl"]); + param["user_context"] = getParamValue('user_context', param["decodedURI"]); + param["pid"] = getParamValue('pid', param["decodedURI"]); + + if (config['DEBUG']) console.log("posturl: " + param["posturl"]); + if (config['DEBUG']) console.log("decodedURI: " + param["decodedURI"]); + if (config['DEBUG']) console.log("user_context: " + param["user_context"]); + if (config['DEBUG']) console.log("pid: " + param["pid"]); + + seatmapWorkflow(param["decodedURI"]); +} + +// EVENT RESIZE +$(window).resize(function() { + if ($(window).width() < 400) { + $('.container-fluid').hide(); + $('#screenTooSmall').show(); + } + else { + $('.container-fluid').show(); + $('#screenTooSmall').hide(); + } +}); + +function detectIE () { + var ua = window.navigator.userAgent; + + var msie = ua.indexOf('MSIE '); + if (msie > 0) { + // IE 10 or older => return version number + return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10); + } + + var trident = ua.indexOf('Trident/'); + if (trident > 0) { + // IE 11 => return version number + var rv = ua.indexOf('rv:'); + return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10); + } + + var edge = ua.indexOf('Edge/'); + if (edge > 0) { + // Edge (IE 12+) => return version number + return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10); + } + + // other browser + return false; +} + +function init() { + if (config['DEBUG']) console.log(getFuncName()); + + /* + * jQuery myCart - v1.7 - 2018-03-07 + * http://asraf-uddin-ahmed.github.io/ + * Copyright (c) 2017 Asraf Uddin Ahmed; Licensed None + */ + + (function($) { + + "use strict"; + + var OptionManager = (function() { + var objToReturn = {}; + + var _options = null; + var DEFAULT_OPTIONS = { + currencySymbol: config["CURRENCY_SYMBOL"], + classCartIcon: 'my-cart-icon', + classCartBadge: 'my-cart-badge', + classProductQuantity: 'my-product-quantity', + classProductRemove: 'my-product-remove', + classCheckoutCart: 'my-cart-checkout', + affixCartIcon: true, + showCheckoutModal: true, + numberOfDecimals: 2, + cartItems: null, + clickOnAddToCart: function($addTocart) {}, + afterAddOnCart: function(products, totalPrice, totalQuantity) {}, + clickOnCartIcon: function($cartIcon, products, totalPrice, totalQuantity) {}, + checkoutCart: function(products, totalPrice, totalQuantity) { + if (config['DEBUG']) console.log("checkoutCart"); + return false; + }, + getDiscountPrice: function(products, totalPrice, totalQuantity) { + return null; + } + }; + + var loadOptions = function(customOptions) { + _options = $.extend({}, DEFAULT_OPTIONS); + if (typeof customOptions === 'object') { + $.extend(_options, customOptions); + } + }; + var getOptions = function() { + return _options; + }; + + objToReturn.loadOptions = loadOptions; + objToReturn.getOptions = getOptions; + return objToReturn; + }()); + + var MathHelper = (function() { + var objToReturn = {}; + var getRoundedNumber = function(number) { + if (isNaN(number)) { + throw new Error('Parameter is not a Number'); + } + number = number * 1; + options = OptionManager.getOptions(); + return number.toFixed(options.numberOfDecimals); + }; + objToReturn.getRoundedNumber = getRoundedNumber; + return objToReturn; + }()); + + ProductManager = (function() { + var objToReturn = {}; + var localStorage = {}; + + /* + PRIVATE + */ + // localStorage.products = localStorage.products ? localStorage.products : ""; + if (typeof localStorage.products !== "undefined") { + if (config['DEBUG']) console.log("localStorage defined"); + localStorage.products = ""; + } + else { + if (config['DEBUG']) console.log("localStorage undefined"); + } + + var getIndexOfProduct = function(id) { + var productIndex = -1; + var products = getAllProducts(); + $.each(products, function(index, value) { + if (value.id == id) { + productIndex = index; + return; + } + }); + return productIndex; + }; + var setAllProducts = function(products) { + localStorage.products = JSON.stringify(products); + }; + var addProduct = function(id, name, summary, price, quantity, image, seatObj) { + var products = getAllProducts(); + products.push({ + id: id, + name: name, + summary: summary, + price: price, + quantity: quantity, + image: image, + seatObj: seatObj, + }); + setAllProducts(products); + }; + + /* + PUBLIC + */ + var getAllProducts = function() { + try { + var products = JSON.parse(localStorage.products); + return products; + } + catch (e) { + return []; + } + }; + var updatePoduct = function(id, quantity) { + var productIndex = getIndexOfProduct(id); + if (productIndex < 0) { + return false; + } + var products = getAllProducts(); + products[productIndex].quantity = typeof quantity === "undefined" ? products[productIndex].quantity * 1 + 1 : quantity; + setAllProducts(products); + return true; + }; + var updatePrice = function(id, price) { + var productIndex = getIndexOfProduct(id); + if (productIndex < 0) { + return false; + } + var products = getAllProducts(); + // products[productIndex].quantity = typeof quantity === "undefined" ? products[productIndex].quantity * 1 + 1 : quantity; + products[productIndex].price = price; + setAllProducts(products); + return true; + }; + var setProduct = function(id, name, summary, price, quantity, image, seatObj) { + if (typeof id === "undefined") { + console.error("id required"); + return false; + } + if (typeof name === "undefined") { + console.error("name required"); + return false; + } + if (typeof image === "undefined") { + console.error("image required"); + return false; + } + if (!$.isNumeric(price)) { + console.error("price is not a number"); + return false; + } + if (!$.isNumeric(quantity)) { + console.error("quantity is not a number"); + return false; + } + if (typeof seatObj === "undefined") { + console.error("seatObj required"); + return false; + } + summary = typeof summary === "undefined" ? "" : summary; + + if (!updatePoduct(id)) { + addProduct(id, name, summary, price, quantity, image, seatObj); + } + }; + var clearProduct = function() { + setAllProducts([]); + }; + var removeProduct = function(id) { + var products = getAllProducts(); + products = $.grep(products, function(value, index) { + return value.id != id; + }); + setAllProducts(products); + }; + var getTotalQuantity = function() { + var total = 0; + var products = getAllProducts(); + $.each(products, function(index, value) { + total += value.quantity * 1; + }); + return total; + }; + var getTotalPrice = function() { + var products = getAllProducts(); + var total = 0; + $.each(products, function(index, value) { + total += value.quantity * value.price; + total = MathHelper.getRoundedNumber(total) * 1; + }); + return total; + }; + + objToReturn.getAllProducts = getAllProducts; + objToReturn.updatePoduct = updatePoduct; + objToReturn.updatePrice = updatePrice; + objToReturn.setProduct = setProduct; + objToReturn.clearProduct = clearProduct; + objToReturn.removeProduct = removeProduct; + objToReturn.getTotalQuantity = getTotalQuantity; + objToReturn.getTotalPrice = getTotalPrice; + return objToReturn; + }()); + + + var loadMyCartEvent = function(targetSelector) { + + var options = OptionManager.getOptions(); + var $cartIcon = $("." + options.classCartIcon); + $cartBadge = $("." + options.classCartBadge); + var classProductQuantity = options.classProductQuantity; + var classProductRemove = options.classProductRemove; + var classCheckoutCart = options.classCheckoutCart; + + idCartModal = 'my-cart-modal'; + var idCartTable = 'my-cart-table'; + var idGrandTotal = 'my-cart-grand-total'; + var idEmptyCartMessage = 'my-cart-empty-message'; + var idDiscountPrice = 'my-cart-discount-price'; + var classProductTotal = 'my-product-total'; + var classAffixMyCartIcon = 'my-cart-icon-affix'; + + + if (options.cartItems && options.cartItems.constructor === Array) { + ProductManager.clearProduct(); + $.each(options.cartItems, function() { + ProductManager.setProduct(this.id, this.name, this.summary, this.price, this.quantity, this.image); + }); + } + + $cartBadge.text(ProductManager.getTotalQuantity()); + + if (!$("#" + idCartModal).length) { + $('body').append( + '' + ); + } + + drawTable = function() { + var DATA = jqxhr.responseJSON; + + var $cartTable = $("#" + idCartTable); + $cartTable.empty(); + + var products = ProductManager.getAllProducts(); + + $.each(products, function() { + var total = this.quantity * this.price; + + // OPTION DROPDOWN + var selectID = 'select' + this.id; + var select = "/)[1]; + console.log(errorMsg); + + if (errorMsg === '') { + // if (errorMsg == '') { + successful = true; + + ProductManager.clearProduct(); + $cartBadge.text(ProductManager.getTotalQuantity()); + $("#" + idCartModal).modal("hide"); + + // REDIRECT TO TICKET PURCHASE + window.location.replace(checkoutURL); + // window.location.replace(proxyCheckoutURL); + } + else { + successful = false; + + errorMsg = errorMsg.replace(/\/g, ' '); + + new jBox('Notice', { + content: errorMsg, + color: 'red', + width: '100vw', + responsiveWidth: true, + position: { x: 'center', y: 'top' }, + autoClose: 10000, + closeButton: 'box', + }); + } + } + }); + + return successful; +} + +function untickSeat(id) { + if (config['DEBUG']) console.log(getFuncName()); + console.log(id); + document.getElementById(id).click(); // Click on the checkbox +} + +function selectRefreshPrice(select) { + if (config['DEBUG']) console.log(getFuncName()); + + if (config['DEBUG']) console.log(select); + + var $sel = $(select); + var value = $sel.val(); + var text = $("option:selected", $sel).text(); + var idSelect = $sel[0].id; + var id = idSelect.replace("select", ""); + + ProductManager.updatePrice(id, value); + selectOptionSelected[idSelect] = { selected: text }; // Remember Select Option Value for redraw in drawTable() + // drawTable(); +} + +function setSelectedIndex() { + if (config['DEBUG']) console.log(getFuncName()); + + for (var idSelect in selectOptionSelected) { + if (selectOptionSelected.hasOwnProperty(idSelect)) { + var s = document.getElementById(idSelect); + var v = selectOptionSelected[idSelect].selected; + + if (s == null) { + delete selectOptionSelected[idSelect]; + continue; + } + else { + for (var i = 0; i < s.options.length; i++) { + if (s.options[i].text === v) { + if (config['DEBUG']) console.log(s.options[i].text + ' matches ' + v); + if (config['DEBUG']) console.log(v); + if (config['DEBUG']) console.log(s); + s.options[i].selected = true; + selectRefreshPrice(s); // FIX RIGHT PRICE OPTION DROPDOWN + } + } + } + + } + } +} + +function generateSeatmap(DATA) { + if (config['DEBUG']) console.log(getFuncName()); + + var returnArr = generateMapMatrix(DATA); + var map1d = returnArr[0]; + var seatsUnavailable = returnArr[1]; + var mappingPricescalesSections = returnArr[2]; + var rows = returnArr[3]; + var seats = generateSeats(DATA, mappingPricescalesSections); + var legend = generateLegend(DATA, 'legend'); + var firstSeatLabel = 1; + + // CHANGE HTML TITLE + document.title = DATA.EVENT.DESC + ' | Saalplanbuchung by Tickets.com'; + + // SEAT MAP + sc = $('#seat-map').seatCharts({ + map: map1d, + seats: seats, + + naming: { + top: false, + left: true, + // rows: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + rows: rows, + // columns: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y'], + getLabel: function(character, row, column) { + return firstSeatLabel++; + }, + }, + legend: legend, + click: function() { + if (this.status() == 'available') { + if ((ProductManager.getTotalQuantity() + 1) > config[DATA.VENUE.CODE]["MAX_TICKETS_PER_USER"]) { + var errorMsg = 'Maximale Ticketantahl erreicht: Sie können nicht mehr als ' + config[DATA.VENUE.CODE]["MAX_TICKETS_PER_USER"] + ' Tickets buchen.'; + new jBox('Notice', { + content: errorMsg, + color: 'red', + width: '100vw', + responsiveWidth: true, + position: { x: 'center', y: 'top' }, + closeButton: 'box', + autoClose: 10000, + }); + return; + } + + // ADD PRODUCT TO CART + fillSeatObjData(this.settings.id); + myCartAddWrapper(this.settings.id, this.settings.data.product, this.settings.data.color, this.settings.data.price, 1, '', this); + + return 'selected'; + } + else if (this.status() == 'selected') { + myCartRemoveWrapper(this.settings.id); + return 'available'; + } + else if (this.status() == 'unavailable') { + //seat has been already booked + console.log('unavailable'); + return 'unavailable'; + } + else { + return this.style(); + } + } + }); + + // INIT JBOX TOOLTIP + var jbox = new jBox('Tooltip', { + attach: '.available', + trigger: 'mouseenter', + onCreated: function() { + if (config['DEBUG']) console.log("onCreated"); + }, + onOpen: function() { + // GET SEAT ID AND OBJECT + var seatID = this.source.context.id; + var seatObj = sc.get(seatID); + // console.log(seatObj); + + if (seatID == '' || seatObj.settings.status == 'unavailable') { + if (config['DEBUG']) console.log("Not a real seat or seat unavailable -> Return."); + return; + } + + // FILL SEAT OBJECT IF NOT ALREADY + fillSeatObjData(seatID); + + // SET JBOX CONTENT + this.setContent(seatObj.settings.data.productJBox); + }, + onClose: function() {} + }); + + // DETACH JBOX FROM LEGEND AND UNAVAILABLE SEATS + for (var i = 0; i < jbox.attachedElements.length; i++) { + if (jbox.attachedElements[i].id == "") { + jbox.detach($(jbox.attachedElements[i])); + i = -1; + continue; + } + } + for (var j = 0; j < seatsUnavailable.length; j++) { + jbox.detach($('#' + seatsUnavailable[j])); + } + + // MYCART + $(function() { + var goToCartIcon = function($addTocartBtn) { + var $cartIcon = $(".my-cart-icon"); + var $image = $('').css({ "position": "fixed", "z-index": "999" }); + $addTocartBtn.prepend($image); + var position = $cartIcon.position(); + $image.animate({ + top: position.top, + left: position.left + }, 500, "linear", function() { + $image.remove(); + }); + }; + }); + + // RUN POST GENERATION HOOKS + sc.status(seatsUnavailable, 'unavailable'); // seatsUnavailable RECEIVED FROM SERVER + seperateSeatmapsCSS(DATA); // CSS CHANGES AFTER GENERATE + venueSpecificCSS(DATA); + $(window).trigger('resize'); +} + +function venueSpecificCSS(DATA) { + if (config['DEBUG']) console.log(getFuncName()); + + // VENUE SPECIFIC WIDTH TO CENTER FRONT INDICATORS + var paddingLeft = config[DATA.VENUE.CODE]["PADDING-LEFT"]; + $(".front-indicator").css({ "padding-left": paddingLeft }); + var paddingLeftStage = config[DATA.VENUE.CODE]["PADDING-LEFT-STAGE"]; + $(".stage-indicator").css({ "padding-left": paddingLeftStage }); + + // STAATSOPERETTE DRESDEN SPECIFIC + if (DATA.VENUE.CODE == "SAAL KKM" || DATA.VENUE.CODE == "GSP KKM") { + $("#seat-map").append(config[DATA.VENUE.CODE]["Tonpult"]); + } + + // VENUE SPECIFIC CSS + if (config['DEBUG']) console.log('Applying venue specific CSS for ' + config[DATA.VENUE.CODE]); + var styleSheet = document.createElement("style"); + styleSheet.type = "text/css"; + styleSheet.innerText = config[DATA.VENUE.CODE]["CSS"]; + document.head.appendChild(styleSheet); +} diff --git a/seatmap-client/seatmap11_22_19.js b/seatmap-client/seatmap11_22_19.js new file mode 100644 index 0000000..5104b65 --- /dev/null +++ b/seatmap-client/seatmap11_22_19.js @@ -0,0 +1,2162 @@ +// GLOBAL +var $cartBadge; +var options; +var drawTable; +var jqxhr; +var selectOptionSelected = {}; +var sc; +var inputsWithValue = []; +var showModal; +var param = new Object; +var idCartModal; +var ProductManager; +var seatmapWorkflowURL; + +var branch = 'seatmap_main'; +var config = { + "KLEINER": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CUSTOM_PRICESCALES_COLOR": { + 1824661: "228B22", + 2542349: "8B4513", + 2542350:"4682B4", + }, + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.43vw; \ + width: 1.43vw; \ + line-height: 1.5vw; \ + } \ + @media (min-width: 400px) and (max-width: 540px) { \ + div.seatCharts-cell { \ + height: 1.398vw; \ + width: 1.398vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "INT_TH_3": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CUSTOM_PRICESCALES_COLOR": { + 5273153: "228B22", + }, + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 2.6vw; \ + width: 2.6vw; \ + line-height: 2.5vw; \ + max-width: 30px; \ + max-height: 30px; \ + } \ + @media (min-width: 400px) and (max-width: 700px) { \ + div.seatCharts-cell { \ + height: 2.52vw; \ + width: 2.52vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "GRO_SAAL": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 0.9vw; \ + width: 0.9vw; \ + line-height: 1.4vw; \ + } \ + ', + }, + "STADTHAL": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "BOTTOM", + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.85vw; \ + width: 1.85vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 400px) and (max-width: 480px) { \ + div.seatCharts-cell { \ + height: 1.81vw; \ + width: 1.81vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "STUDIONU": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "BOTTOM", + "CUSTOM_PRICESCALES_COLOR": { + 2447833: "B9DEA0", + }, + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.85vw; \ + width: 1.85vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 400px) and (max-width: 480px) { \ + div.seatCharts-cell { \ + height: 1.81vw; \ + width: 1.81vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "GR.SAAL": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "BOTTOM", + "CUSTOM_PRICESCALES_COLOR": { + 152965: "FFFF00", + 152966: "FF0000", + 152967: "74DF00", + 152968: "0080FF", + }, + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.19vw; \ + width: 1.19vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 445px) and (max-width: 555px) { \ + div.seatCharts-cell { \ + height: 1.17vw; \ + width: 1.17vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + @media (min-width: 400px) and (max-width: 444px) { \ + div.seatCharts-cell { \ + height: 1.15vw; \ + width: 1.15vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "THEATHOF": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "50%", + "PADDING-LEFT-STAGE": "50%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "BOTTOM", + "CUSTOM_PRICESCALES_COLOR": { + 2446505: "FFFF00", + 2446506: "FF0000", + 2446507: "74DF00", + 2446508: "0080FF", + }, + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.2vw; \ + width: 1.2vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 530px) and (max-width:768px) { \ + div.seatCharts-cell { \ + height: 1.24vw; \ + width: 1.24vw; \ + } \ + } \ + @media (min-width: 405px) and (max-width:529px) { \ + div.seatCharts-cell { \ + height: 1.215vw; \ + width: 1.215vw; \ + } \ + } \ + @media (min-width: 400px) and (max-width: 768px) { \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "THEATER": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "60%", + "PADDING-LEFT-STAGE": "47%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.54vw; \ + width: 1.54vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 400px) and (max-width:530px) { \ + div.seatCharts-cell { \ + height: 1.505vw; \ + width: 1.505vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "NEUES TH": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "50%", + "PADDING-LEFT-STAGE": "50%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 3.47vw !important; \ + width: 3.47vw !important; \ + max-width: 27px; \ + max-height: 27px; \ + line-height: 1.4vw; \ + } \ + @media all and (-ms-high-contrast: none), \ + (-ms-high-contrast: active) { \ + div.seatCharts-cell { \ + height: 3.55vw !important; \ + width: 3.55vw !important; \ + } \ + } \ + ', + }, + "SAAL KKM": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "47%", + "Tonpult": "

Tonpult

", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": ' \ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.3vw; \ + width: 1.3vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 411px) and (max-width:539px) { \ + div.seatCharts-cell { \ + height: 1.275vw; \ + width: 1.275vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + @media (min-width: 400px) and (max-width:410px) { \ + div.seatCharts-cell { \ + height: 1.25vw; \ + width: 1.25vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "GSP KKM": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "47%", + "Tonpult": "

Tonpult

", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": ' \ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.39vw; \ + width: 1.39vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 400px) and (max-width:504px) { \ + div.seatCharts-cell { \ + height: 1.36vw; \ + width: 1.36vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + 'KOM├ÛDIE': { + "PADDING-LEFT": "47%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": ' \ + .booking-details p,li { \ + font-size: 1.0vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1.0vw; \ + } \ + div.seatCharts-cell { \ + height: 2.72vw; \ + width: 2.72vw; \ + line-height: 1.4vw; \ + max-height: 25px; \ + max-width: 25px; \ + } \ + @media (min-width: 400px) and (max-width:405px) { \ + div.seatCharts-cell { \ + height: 2.7vw; \ + width: 2.7vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + @media (min-width: 406px) and (max-width:768px) { \ + div.seatCharts-cell { \ + height: 2.72vw; \ + width: 2.72vw; \ + } \ + } \ + ', + }, + "GRO├ƑER SAAL": { + "AGENCY": "GMB1", + "BUYER_TYPES": { + "01": "Vollzahler", + } + }, + "KLEINER SAAL": { + "AGENCY": "GMB1", + "BUYER_TYPES": { + "01": "Vollzahler", + } + }, + "INTIMES THEATER BESTUHLT": { + "AGENCY": "GMB1", + "BUYER_TYPES": { + "01": "Vollzahler", + } + }, + "THEATER HOF": { + "AGENCY": "THOF", + "BUYER_TYPES": { + "I1": "Vollzahler", + "I3": "Behinderte mit Ausweis", + "I2": "Schüler", + "IE": "Erwachsener", + "IK": "Kind", + } + }, + "STUDIO NUMMERIERT": { + "AGENCY": "THOF", + "BUYER_TYPES": { + "I1": "Vollzahler", + "I3": "Behinderte mit Ausweis", + "I2": "Schüler", + "IE": "Erwachsener", + "IK": "Kind", + } + }, + "KOMÖDIE BRAUNSCHWEIG": { + "AGENCY": "KOMB", + "BUYER_TYPES": { + "IV": "Vollzahler", + "IE": "Ermäßigt", + "IG": "Gutschein", + "ME": "Vollzahler", + "MK": "Ermäßigt", + "NI": "Ermäßigt", + "NN": "Vollzahler", + } + }, + "THEATER IM RATHAUS": { + "AGENCY": "TIRE", + "BUYER_TYPES": { + "I1": "Vollzahler", + "I2": "Ermäßigt", + } + }, + "NEUES THEATER HANNOVER": { + "AGENCY": "NTHH", + "BUYER_TYPES": { + "WW": "Vollzahler", + } + }, + "STAATSOPERETTE DRESDEN": { + "AGENCY": "SOPD", + "BUYER_TYPES": { + "97": "Vollzahler", + "A0": "Ermäßigt", + "A5": "Online-Aktion", + "95": "Aktionspreis", + "09": "Schüler", + "A6": "Kind bis 18 J.", + "86": "Buch", + "85": "CD", + "00": "Tagespreis", + "03": "Tagespreis ermäßigt", + "98": "Aktionspreis", + "31": "Studenten/Azubis bis 27 J.", + "23": "Andere Gäste", + } + }, + "SEATMAP-SERVER": { + "ROOT_URL": "https://zinomedia.de/" + branch + "/seatmap-server/seatmap-server.pl", + }, + "CORS-ANYWHERE": { + "ROOT_URL": "https://cors.zinomedia.de/", + }, + "DEBUG": true, + "SEATMAP_VERSION": "0.9.2", + "CURRENCY_SYMBOL": "€", +}; +if (branch === 'seatmap_testing') config["SEATMAP_VERSION"] = config["SEATMAP_VERSION"] + ' (testing)'; + +var checkoutParam = [ + 'request_type', 'trxstate', 'request_action', 'agency', 'etpgcode', 'parent_offer_id', 'flashDetected', 'recapToken', 'age_consent_is_checked', 'jcarousel_auto_off_val', 'selected_seat_indexes', 'ism_map_current_state_json_data', 'is_availability_switch_from_map', 'map_coupon_code', 'is_ticket_exchange_request', 'prevtrxstate', 'user_context', 'gid', 'target_trxstate', 'target_prev_trxstate', 'target_url', 'target_name_value', 'orgid', 'p_orgid', 'pid', 'redeem_voucher_data_event_mapping', 'supplier_code', 'valid_coupon_code_message', 'replay_request', 'inventory_filtering_action', 'inventory_month', 'inventory_year', 'upsell_selected', 'listing_type', 'invalid_seats', 'package_pids', 's_mem_tkt_ren_retrieval', 'mlbamsp', 'pay_pal_token', 'dpa_selection', 'timeout_seconds', 'APPTE', 'schedule', 'hbx_discounts', 'hbx_discount_prices', 'hbx_selected_tixx', 'hbx_requested_pg', 'hbx_offered_pg', 'hbx_pids', 'hbx_perf_codes', 'hbx_perf_sub_codes', 'hbx_upsell_flag', 'selected_upsell_option', 'cancelAndRedirectTrxState', 'secure_trxn_enabled', 'isCapEnabled', 'mainEventPID', 'discountdesc=A=97', 'discountprice=A=97', 'discountfees=A=97', 'discount=A=97', 'discountdesc=A=A0', 'discountprice=A=A0', 'discountfees=A=A0', 'discount=A=A0', 'supplierCode', +]; + +// POLYPHILL repeat() +if (!String.prototype.repeat) { + String.prototype.repeat = function(count) { + 'use strict'; + if (this == null) + throw new TypeError('can\'t convert ' + this + ' to object'); + + var str = '' + this; + // To convert string to integer. + count = +count; + // Check NaN + if (count != count) + count = 0; + + if (count < 0) + throw new RangeError('repeat count must be non-negative'); + + if (count == Infinity) + throw new RangeError('repeat count must be less than infinity'); + + count = Math.floor(count); + if (str.length == 0 || count == 0) + return ''; + + // Ensuring count is a 31-bit integer allows us to heavily optimize the + // main part. But anyway, most current (August 2014) browsers can't handle + // strings 1 << 28 chars or longer, so: + if (str.length * count >= 1 << 28) + throw new RangeError('repeat count must not overflow maximum string size'); + + var maxCount = str.length * count; + count = Math.floor(Math.log(count) / Math.log(2)); + while (count) { + str += str; + count--; + } + str += str.substring(0, maxCount - str.length); + return str; + } +} + +// EVENT DOMCONTENTLOADED +document.addEventListener("DOMContentLoaded", ready); +window.onload = function() { + if (config['DEBUG']) console.log(getFuncName()); + + checkDebug(); +}; + +// EVENT CONTAINER VISIBLE +if ($('.container-fluid').is(':visible')) { + if (config['DEBUG']) console.log("Visible"); + + var IEdetected = detectIE(); + if (config['DEBUG']) console.log("IE " + IEdetected); + if (parseInt(IEdetected) < 12) { + $('#IEdetected').show(); + throw new Error("IE " + IEDetected + " not supported."); + } + init(); + param["posturl"] = getParamValue('posturl'); + param["decodedURI"] = decodeURIComponent(param["posturl"]); + param["user_context"] = getParamValue('user_context', param["decodedURI"]); + param["pid"] = getParamValue('pid', param["decodedURI"]); + + if (config['DEBUG']) console.log("posturl: " + param["posturl"]); + if (config['DEBUG']) console.log("decodedURI: " + param["decodedURI"]); + if (config['DEBUG']) console.log("user_context: " + param["user_context"]); + if (config['DEBUG']) console.log("pid: " + param["pid"]); + + seatmapWorkflow(param["decodedURI"]); +} + +// EVENT RESIZE +$(window).resize(function() { + if ($(window).width() < 400) { + $('.container-fluid').hide(); + $('#screenTooSmall').show(); + } + else { + $('.container-fluid').show(); + $('#screenTooSmall').hide(); + } +}); + +function detectIE () { + var ua = window.navigator.userAgent; + + var msie = ua.indexOf('MSIE '); + if (msie > 0) { + // IE 10 or older => return version number + return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10); + } + + var trident = ua.indexOf('Trident/'); + if (trident > 0) { + // IE 11 => return version number + var rv = ua.indexOf('rv:'); + return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10); + } + + var edge = ua.indexOf('Edge/'); + if (edge > 0) { + // Edge (IE 12+) => return version number + return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10); + } + + // other browser + return false; +} + +function init() { + if (config['DEBUG']) console.log(getFuncName()); + + /* + * jQuery myCart - v1.7 - 2018-03-07 + * http://asraf-uddin-ahmed.github.io/ + * Copyright (c) 2017 Asraf Uddin Ahmed; Licensed None + */ + + (function($) { + + "use strict"; + + var OptionManager = (function() { + var objToReturn = {}; + + var _options = null; + var DEFAULT_OPTIONS = { + currencySymbol: config["CURRENCY_SYMBOL"], + classCartIcon: 'my-cart-icon', + classCartBadge: 'my-cart-badge', + classProductQuantity: 'my-product-quantity', + classProductRemove: 'my-product-remove', + classCheckoutCart: 'my-cart-checkout', + affixCartIcon: true, + showCheckoutModal: true, + numberOfDecimals: 2, + cartItems: null, + clickOnAddToCart: function($addTocart) {}, + afterAddOnCart: function(products, totalPrice, totalQuantity) {}, + clickOnCartIcon: function($cartIcon, products, totalPrice, totalQuantity) {}, + checkoutCart: function(products, totalPrice, totalQuantity) { + if (config['DEBUG']) console.log("checkoutCart"); + return false; + }, + getDiscountPrice: function(products, totalPrice, totalQuantity) { + return null; + } + }; + + var loadOptions = function(customOptions) { + _options = $.extend({}, DEFAULT_OPTIONS); + if (typeof customOptions === 'object') { + $.extend(_options, customOptions); + } + }; + var getOptions = function() { + return _options; + }; + + objToReturn.loadOptions = loadOptions; + objToReturn.getOptions = getOptions; + return objToReturn; + }()); + + var MathHelper = (function() { + var objToReturn = {}; + var getRoundedNumber = function(number) { + if (isNaN(number)) { + throw new Error('Parameter is not a Number'); + } + number = number * 1; + options = OptionManager.getOptions(); + return number.toFixed(options.numberOfDecimals); + }; + objToReturn.getRoundedNumber = getRoundedNumber; + return objToReturn; + }()); + + ProductManager = (function() { + var objToReturn = {}; + var localStorage = {}; + + /* + PRIVATE + */ + // localStorage.products = localStorage.products ? localStorage.products : ""; + if (typeof localStorage.products !== "undefined") { + if (config['DEBUG']) console.log("localStorage defined"); + localStorage.products = ""; + } + else { + if (config['DEBUG']) console.log("localStorage undefined"); + } + + var getIndexOfProduct = function(id) { + var productIndex = -1; + var products = getAllProducts(); + $.each(products, function(index, value) { + if (value.id == id) { + productIndex = index; + return; + } + }); + return productIndex; + }; + var setAllProducts = function(products) { + localStorage.products = JSON.stringify(products); + }; + var addProduct = function(id, name, summary, price, quantity, image, seatObj) { + var products = getAllProducts(); + products.push({ + id: id, + name: name, + summary: summary, + price: price, + quantity: quantity, + image: image, + seatObj: seatObj, + }); + setAllProducts(products); + }; + + /* + PUBLIC + */ + var getAllProducts = function() { + try { + var products = JSON.parse(localStorage.products); + return products; + } + catch (e) { + return []; + } + }; + var updatePoduct = function(id, quantity) { + var productIndex = getIndexOfProduct(id); + if (productIndex < 0) { + return false; + } + var products = getAllProducts(); + products[productIndex].quantity = typeof quantity === "undefined" ? products[productIndex].quantity * 1 + 1 : quantity; + setAllProducts(products); + return true; + }; + var updatePrice = function(id, price) { + var productIndex = getIndexOfProduct(id); + if (productIndex < 0) { + return false; + } + var products = getAllProducts(); + // products[productIndex].quantity = typeof quantity === "undefined" ? products[productIndex].quantity * 1 + 1 : quantity; + products[productIndex].price = price; + setAllProducts(products); + return true; + }; + var setProduct = function(id, name, summary, price, quantity, image, seatObj) { + if (typeof id === "undefined") { + console.error("id required"); + return false; + } + if (typeof name === "undefined") { + console.error("name required"); + return false; + } + if (typeof image === "undefined") { + console.error("image required"); + return false; + } + if (!$.isNumeric(price)) { + console.error("price is not a number"); + return false; + } + if (!$.isNumeric(quantity)) { + console.error("quantity is not a number"); + return false; + } + if (typeof seatObj === "undefined") { + console.error("seatObj required"); + return false; + } + summary = typeof summary === "undefined" ? "" : summary; + + if (!updatePoduct(id)) { + addProduct(id, name, summary, price, quantity, image, seatObj); + } + }; + var clearProduct = function() { + setAllProducts([]); + }; + var removeProduct = function(id) { + var products = getAllProducts(); + products = $.grep(products, function(value, index) { + return value.id != id; + }); + setAllProducts(products); + }; + var getTotalQuantity = function() { + var total = 0; + var products = getAllProducts(); + $.each(products, function(index, value) { + total += value.quantity * 1; + }); + return total; + }; + var getTotalPrice = function() { + var products = getAllProducts(); + var total = 0; + $.each(products, function(index, value) { + total += value.quantity * value.price; + total = MathHelper.getRoundedNumber(total) * 1; + }); + return total; + }; + + objToReturn.getAllProducts = getAllProducts; + objToReturn.updatePoduct = updatePoduct; + objToReturn.updatePrice = updatePrice; + objToReturn.setProduct = setProduct; + objToReturn.clearProduct = clearProduct; + objToReturn.removeProduct = removeProduct; + objToReturn.getTotalQuantity = getTotalQuantity; + objToReturn.getTotalPrice = getTotalPrice; + return objToReturn; + }()); + + + var loadMyCartEvent = function(targetSelector) { + + var options = OptionManager.getOptions(); + var $cartIcon = $("." + options.classCartIcon); + $cartBadge = $("." + options.classCartBadge); + var classProductQuantity = options.classProductQuantity; + var classProductRemove = options.classProductRemove; + var classCheckoutCart = options.classCheckoutCart; + + idCartModal = 'my-cart-modal'; + var idCartTable = 'my-cart-table'; + var idGrandTotal = 'my-cart-grand-total'; + var idEmptyCartMessage = 'my-cart-empty-message'; + var idDiscountPrice = 'my-cart-discount-price'; + var classProductTotal = 'my-product-total'; + var classAffixMyCartIcon = 'my-cart-icon-affix'; + + + if (options.cartItems && options.cartItems.constructor === Array) { + ProductManager.clearProduct(); + $.each(options.cartItems, function() { + ProductManager.setProduct(this.id, this.name, this.summary, this.price, this.quantity, this.image); + }); + } + + $cartBadge.text(ProductManager.getTotalQuantity()); + + if (!$("#" + idCartModal).length) { + $('body').append( + '' + ); + } + + drawTable = function() { + var DATA = jqxhr.responseJSON; + + var $cartTable = $("#" + idCartTable); + $cartTable.empty(); + + var products = ProductManager.getAllProducts(); + + $.each(products, function() { + var total = this.quantity * this.price; + + // OPTION DROPDOWN + var selectID = 'select' + this.id; + var select = "/)[1]; + console.log(errorMsg); + + if (errorMsg === '') { + // if (errorMsg == '') { + successful = true; + + ProductManager.clearProduct(); + $cartBadge.text(ProductManager.getTotalQuantity()); + $("#" + idCartModal).modal("hide"); + + // REDIRECT TO TICKET PURCHASE + window.location.replace(checkoutURL); + // window.location.replace(proxyCheckoutURL); + } + else { + successful = false; + + errorMsg = errorMsg.replace(/\/g, ' '); + + new jBox('Notice', { + content: errorMsg, + color: 'red', + width: '100vw', + responsiveWidth: true, + position: { x: 'center', y: 'top' }, + autoClose: 10000, + closeButton: 'box', + }); + } + } + }); + + return successful; +} + +function untickSeat(id) { + if (config['DEBUG']) console.log(getFuncName()); + console.log(id); + document.getElementById(id).click(); // Click on the checkbox +} + +function selectRefreshPrice(select) { + if (config['DEBUG']) console.log(getFuncName()); + + if (config['DEBUG']) console.log(select); + + var $sel = $(select); + var value = $sel.val(); + var text = $("option:selected", $sel).text(); + var idSelect = $sel[0].id; + var id = idSelect.replace("select", ""); + + ProductManager.updatePrice(id, value); + selectOptionSelected[idSelect] = { selected: text }; // Remember Select Option Value for redraw in drawTable() + // drawTable(); +} + +function setSelectedIndex() { + if (config['DEBUG']) console.log(getFuncName()); + + for (var idSelect in selectOptionSelected) { + if (selectOptionSelected.hasOwnProperty(idSelect)) { + var s = document.getElementById(idSelect); + var v = selectOptionSelected[idSelect].selected; + + if (s == null) { + delete selectOptionSelected[idSelect]; + continue; + } + else { + for (var i = 0; i < s.options.length; i++) { + if (s.options[i].text === v) { + if (config['DEBUG']) console.log(s.options[i].text + ' matches ' + v); + if (config['DEBUG']) console.log(v); + if (config['DEBUG']) console.log(s); + s.options[i].selected = true; + selectRefreshPrice(s); // FIX RIGHT PRICE OPTION DROPDOWN + } + } + } + + } + } +} + +function generateSeatmap(DATA) { + if (config['DEBUG']) console.log(getFuncName()); + + var returnArr = generateMapMatrix(DATA); + var map1d = returnArr[0]; + var seatsUnavailable = returnArr[1]; + var mappingPricescalesSections = returnArr[2]; + var rows = returnArr[3]; + var seats = generateSeats(DATA, mappingPricescalesSections); + var legend = generateLegend(DATA, 'legend'); + var firstSeatLabel = 1; + + // CHANGE HTML TITLE + document.title = DATA.EVENT.DESC + ' | Saalplanbuchung by Tickets.com'; + + // SEAT MAP + sc = $('#seat-map').seatCharts({ + map: map1d, + seats: seats, + + naming: { + top: false, + left: true, + // rows: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + rows: rows, + // columns: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y'], + getLabel: function(character, row, column) { + return firstSeatLabel++; + }, + }, + legend: legend, + click: function() { + if (this.status() == 'available') { + if ((ProductManager.getTotalQuantity() + 1) > config[DATA.VENUE.CODE]["MAX_TICKETS_PER_USER"]) { + var errorMsg = 'Maximale Ticketantahl erreicht: Sie können nicht mehr als ' + config[DATA.VENUE.CODE]["MAX_TICKETS_PER_USER"] + ' Tickets buchen.'; + new jBox('Notice', { + content: errorMsg, + color: 'red', + width: '100vw', + responsiveWidth: true, + position: { x: 'center', y: 'top' }, + closeButton: 'box', + autoClose: 10000, + }); + return; + } + + // ADD PRODUCT TO CART + fillSeatObjData(this.settings.id); + myCartAddWrapper(this.settings.id, this.settings.data.product, this.settings.data.color, this.settings.data.price, 1, '', this); + + return 'selected'; + } + else if (this.status() == 'selected') { + myCartRemoveWrapper(this.settings.id); + return 'available'; + } + else if (this.status() == 'unavailable') { + //seat has been already booked + console.log('unavailable'); + return 'unavailable'; + } + else { + return this.style(); + } + } + }); + + // INIT JBOX TOOLTIP + var jbox = new jBox('Tooltip', { + attach: '.available', + trigger: 'mouseenter', + onCreated: function() { + if (config['DEBUG']) console.log("onCreated"); + }, + onOpen: function() { + // GET SEAT ID AND OBJECT + var seatID = this.source.context.id; + var seatObj = sc.get(seatID); + // console.log(seatObj); + + if (seatID == '' || seatObj.settings.status == 'unavailable') { + if (config['DEBUG']) console.log("Not a real seat or seat unavailable -> Return."); + return; + } + + // FILL SEAT OBJECT IF NOT ALREADY + fillSeatObjData(seatID); + + // SET JBOX CONTENT + this.setContent(seatObj.settings.data.productJBox); + }, + onClose: function() {} + }); + + // DETACH JBOX FROM LEGEND AND UNAVAILABLE SEATS + for (var i = 0; i < jbox.attachedElements.length; i++) { + if (jbox.attachedElements[i].id == "") { + jbox.detach($(jbox.attachedElements[i])); + i = -1; + continue; + } + } + for (var j = 0; j < seatsUnavailable.length; j++) { + jbox.detach($('#' + seatsUnavailable[j])); + } + + // MYCART + $(function() { + var goToCartIcon = function($addTocartBtn) { + var $cartIcon = $(".my-cart-icon"); + var $image = $('').css({ "position": "fixed", "z-index": "999" }); + $addTocartBtn.prepend($image); + var position = $cartIcon.position(); + $image.animate({ + top: position.top, + left: position.left + }, 500, "linear", function() { + $image.remove(); + }); + }; + }); + + // RUN POST GENERATION HOOKS + sc.status(seatsUnavailable, 'unavailable'); // seatsUnavailable RECEIVED FROM SERVER + seperateSeatmapsCSS(DATA); // CSS CHANGES AFTER GENERATE + venueSpecificCSS(DATA); + $(window).trigger('resize'); +} + +function venueSpecificCSS(DATA) { + if (config['DEBUG']) console.log(getFuncName()); + + // VENUE SPECIFIC WIDTH TO CENTER FRONT INDICATORS + var paddingLeft = config[DATA.VENUE.CODE]["PADDING-LEFT"]; + $(".front-indicator").css({ "padding-left": paddingLeft }); + var paddingLeftStage = config[DATA.VENUE.CODE]["PADDING-LEFT-STAGE"]; + $(".stage-indicator").css({ "padding-left": paddingLeftStage }); + + // STAATSOPERETTE DRESDEN SPECIFIC + if (DATA.VENUE.CODE == "SAAL KKM" || DATA.VENUE.CODE == "GSP KKM") { + $("#seat-map").append(config[DATA.VENUE.CODE]["Tonpult"]); + } + + // VENUE SPECIFIC CSS + if (config['DEBUG']) console.log('Applying venue specific CSS for ' + config[DATA.VENUE.CODE]); + var styleSheet = document.createElement("style"); + styleSheet.type = "text/css"; + styleSheet.innerText = config[DATA.VENUE.CODE]["CSS"]; + document.head.appendChild(styleSheet); +} diff --git a/seatmap-client/seatmap12_12.js b/seatmap-client/seatmap12_12.js new file mode 100644 index 0000000..5171c1c --- /dev/null +++ b/seatmap-client/seatmap12_12.js @@ -0,0 +1,2163 @@ +// GLOBAL +var $cartBadge; +var options; +var drawTable; +var jqxhr; +var selectOptionSelected = {}; +var sc; +var inputsWithValue = []; +var showModal; +var param = new Object; +var idCartModal; +var ProductManager; +var seatmapWorkflowURL; + +var branch = 'seatmap_main'; +var config = { + "KLEINER": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CUSTOM_PRICESCALES_COLOR": { + 1824661: "228B22", + 2542349: "8B4513", + 2542350:"4682B4", + }, + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.43vw; \ + width: 1.43vw; \ + line-height: 1.5vw; \ + } \ + @media (min-width: 400px) and (max-width: 540px) { \ + div.seatCharts-cell { \ + height: 1.398vw; \ + width: 1.398vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "INT_TH_3": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CUSTOM_PRICESCALES_COLOR": { + 5273153: "228B22", + }, + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 2.6vw; \ + width: 2.6vw; \ + line-height: 2.5vw; \ + max-width: 30px; \ + max-height: 30px; \ + } \ + @media (min-width: 400px) and (max-width: 700px) { \ + div.seatCharts-cell { \ + height: 2.52vw; \ + width: 2.52vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "GRO_SAAL": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 0.9vw; \ + width: 0.9vw; \ + line-height: 1.4vw; \ + } \ + ', + }, + "STADTHAL": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "BOTTOM", + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.85vw; \ + width: 1.85vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 400px) and (max-width: 480px) { \ + div.seatCharts-cell { \ + height: 1.81vw; \ + width: 1.81vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "STUDIONU": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "BOTTOM", + "CUSTOM_PRICESCALES_COLOR": { + 2447833: "B9DEA0", + }, + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.85vw; \ + width: 1.85vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 400px) and (max-width: 480px) { \ + div.seatCharts-cell { \ + height: 1.81vw; \ + width: 1.81vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "GR.SAAL": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "49%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "BOTTOM", + "CUSTOM_PRICESCALES_COLOR": { + 152965: "FFFF00", + 152966: "FF0000", + 152967: "74DF00", + 152968: "0080FF", + }, + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.19vw; \ + width: 1.19vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 445px) and (max-width: 555px) { \ + div.seatCharts-cell { \ + height: 1.17vw; \ + width: 1.17vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + @media (min-width: 400px) and (max-width: 444px) { \ + div.seatCharts-cell { \ + height: 1.15vw; \ + width: 1.15vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "THEATHOF": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "50%", + "PADDING-LEFT-STAGE": "50%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "BOTTOM", + "CUSTOM_PRICESCALES_COLOR": { + 2446505: "FFFF00", + 2446506: "FF0000", + 2446507: "74DF00", + 2446508: "0080FF", + }, + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.2vw; \ + width: 1.2vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 530px) and (max-width:768px) { \ + div.seatCharts-cell { \ + height: 1.24vw; \ + width: 1.24vw; \ + } \ + } \ + @media (min-width: 405px) and (max-width:529px) { \ + div.seatCharts-cell { \ + height: 1.215vw; \ + width: 1.215vw; \ + } \ + } \ + @media (min-width: 400px) and (max-width: 768px) { \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "THEATER": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "60%", + "PADDING-LEFT-STAGE": "47%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.54vw; \ + width: 1.54vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 400px) and (max-width:530px) { \ + div.seatCharts-cell { \ + height: 1.505vw; \ + width: 1.505vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "NEUES TH": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "50%", + "PADDING-LEFT-STAGE": "50%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": '\ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 3.47vw !important; \ + width: 3.47vw !important; \ + max-width: 27px; \ + max-height: 27px; \ + line-height: 1.4vw; \ + } \ + @media all and (-ms-high-contrast: none), \ + (-ms-high-contrast: active) { \ + div.seatCharts-cell { \ + height: 3.55vw !important; \ + width: 3.55vw !important; \ + } \ + } \ + ', + }, + "SAAL KKM": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "47%", + "Tonpult": "

Tonpult

", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": ' \ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.3vw; \ + width: 1.3vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 411px) and (max-width:539px) { \ + div.seatCharts-cell { \ + height: 1.275vw; \ + width: 1.275vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + @media (min-width: 400px) and (max-width:410px) { \ + div.seatCharts-cell { \ + height: 1.25vw; \ + width: 1.25vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + "GSP KKM": { + "FRONT-INDICATOR-WIDTH": "90%", + "PADDING-LEFT": "47%", + "PADDING-LEFT-STAGE": "47%", + "Tonpult": "

Tonpult

", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": ' \ + .booking-details p,li { \ + font-size: 1vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1vw; \ + } \ + div.seatCharts-cell { \ + height: 1.39vw; \ + width: 1.39vw; \ + line-height: 1.4vw; \ + } \ + @media (min-width: 400px) and (max-width:504px) { \ + div.seatCharts-cell { \ + height: 1.36vw; \ + width: 1.36vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + ', + }, + 'KOM├ÛDIE': { + "PADDING-LEFT": "47%", + "MAX_TICKETS_PER_USER": 9, + "BUEHNE": "TOP", + "CSS": ' \ + .booking-details p,li { \ + font-size: 1.0vw; \ + } \ + .seatCharts-container h4, div.seatCharts-cell { \ + font-size: 1.0vw; \ + } \ + div.seatCharts-cell { \ + height: 2.72vw; \ + width: 2.72vw; \ + line-height: 1.4vw; \ + max-height: 25px; \ + max-width: 25px; \ + } \ + @media (min-width: 400px) and (max-width:405px) { \ + div.seatCharts-cell { \ + height: 2.7vw; \ + width: 2.7vw; \ + } \ + .glyphicon { \ + display: none; \ + } \ + } \ + @media (min-width: 406px) and (max-width:768px) { \ + div.seatCharts-cell { \ + height: 2.72vw; \ + width: 2.72vw; \ + } \ + } \ + ', + }, + "GRO├ƑER SAAL": { + "AGENCY": "GMB1", + "BUYER_TYPES": { + "01": "Vollzahler", + } + }, + "KLEINER SAAL": { + "AGENCY": "GMB1", + "BUYER_TYPES": { + "01": "Vollzahler", + } + }, + "INTIMES THEATER BESTUHLT": { + "AGENCY": "GMB1", + "BUYER_TYPES": { + "01": "Vollzahler", + } + }, + "THEATER HOF": { + "AGENCY": "THOF", + "BUYER_TYPES": { + "I1": "Vollzahler", + "I3": "Behinderte mit Ausweis", + "I2": "Schüler", + "IE": "Erwachsener", + "IK": "Kind", + } + }, + "STUDIO NUMMERIERT": { + "AGENCY": "THOF", + "BUYER_TYPES": { + "I1": "Vollzahler", + "I3": "Behinderte mit Ausweis", + "I2": "Schüler", + "IE": "Erwachsener", + "IK": "Kind", + } + }, + "KOMÖDIE BRAUNSCHWEIG": { + "AGENCY": "KOMB", + "BUYER_TYPES": { + "IV": "Vollzahler", + "IE": "Ermäßigt", + "IG": "Gutschein", + "ME": "Vollzahler", + "MK": "Ermäßigt", + "NI": "Ermäßigt", + "NN": "Vollzahler", + } + }, + "THEATER IM RATHAUS": { + "AGENCY": "TIRE", + "BUYER_TYPES": { + "I1": "Vollzahler", + "I2": "Ermäßigt", + } + }, + "NEUES THEATER HANNOVER": { + "AGENCY": "NTHH", + "BUYER_TYPES": { + "WW": "Vollzahler", + } + }, + "STAATSOPERETTE DRESDEN": { + "AGENCY": "SOPD", + "BUYER_TYPES": { + "97": "Vollzahler", + "A0": "Ermäßigt", + "A5": "Online-Aktion", + "95": "Aktionspreis", + "09": "Schüler", + "A6": "Kind bis 18 J.", + "86": "Buch", + "85": "CD", + "00": "Tagespreis", + "03": "Tagespreis ermäßigt", + "98": "Aktionspreis", + "31": "Studenten/Azubis bis 27 J.", + "23": "Andere Gäste", + } + }, + "SEATMAP-SERVER": { + "ROOT_URL": "https://zinomedia.de/" + branch + "/seatmap-server/seatmap-server.pl", + }, + "CORS-ANYWHERE": { + "ROOT_URL": "https://cors.zinomedia.de/", + }, + "DEBUG": true, + "SEATMAP_VERSION": "0.9.3", + "CURRENCY_SYMBOL": "€", +}; +if (branch === 'seatmap_testing') config["SEATMAP_VERSION"] = config["SEATMAP_VERSION"] + ' (testing)'; + +var checkoutParam = [ + 'request_type', 'trxstate', 'request_action', 'agency', 'etpgcode', 'parent_offer_id', 'flashDetected', 'recapToken', 'age_consent_is_checked', 'jcarousel_auto_off_val', 'selected_seat_indexes', 'ism_map_current_state_json_data', 'is_availability_switch_from_map', 'map_coupon_code', 'is_ticket_exchange_request', 'prevtrxstate', 'user_context', 'gid', 'target_trxstate', 'target_prev_trxstate', 'target_url', 'target_name_value', 'orgid', 'p_orgid', 'pid', 'redeem_voucher_data_event_mapping', 'supplier_code', 'valid_coupon_code_message', 'replay_request', 'inventory_filtering_action', 'inventory_month', 'inventory_year', 'upsell_selected', 'listing_type', 'invalid_seats', 'package_pids', 's_mem_tkt_ren_retrieval', 'mlbamsp', 'pay_pal_token', 'dpa_selection', 'timeout_seconds', 'APPTE', 'schedule', 'hbx_discounts', 'hbx_discount_prices', 'hbx_selected_tixx', 'hbx_requested_pg', 'hbx_offered_pg', 'hbx_pids', 'hbx_perf_codes', 'hbx_perf_sub_codes', 'hbx_upsell_flag', 'selected_upsell_option', 'cancelAndRedirectTrxState', 'secure_trxn_enabled', 'isCapEnabled', 'mainEventPID', 'discountdesc=A=97', 'discountprice=A=97', 'discountfees=A=97', 'discount=A=97', 'discountdesc=A=A0', 'discountprice=A=A0', 'discountfees=A=A0', 'discount=A=A0', 'supplierCode', +]; + +// POLYPHILL repeat() +if (!String.prototype.repeat) { + String.prototype.repeat = function(count) { + 'use strict'; + if (this == null) + throw new TypeError('can\'t convert ' + this + ' to object'); + + var str = '' + this; + // To convert string to integer. + count = +count; + // Check NaN + if (count != count) + count = 0; + + if (count < 0) + throw new RangeError('repeat count must be non-negative'); + + if (count == Infinity) + throw new RangeError('repeat count must be less than infinity'); + + count = Math.floor(count); + if (str.length == 0 || count == 0) + return ''; + + // Ensuring count is a 31-bit integer allows us to heavily optimize the + // main part. But anyway, most current (August 2014) browsers can't handle + // strings 1 << 28 chars or longer, so: + if (str.length * count >= 1 << 28) + throw new RangeError('repeat count must not overflow maximum string size'); + + var maxCount = str.length * count; + count = Math.floor(Math.log(count) / Math.log(2)); + while (count) { + str += str; + count--; + } + str += str.substring(0, maxCount - str.length); + return str; + } +} + +// EVENT DOMCONTENTLOADED +document.addEventListener("DOMContentLoaded", ready); +window.onload = function() { + if (config['DEBUG']) console.log(getFuncName()); + + checkDebug(); +}; + +// EVENT CONTAINER VISIBLE +if ($('.container-fluid').is(':visible')) { + if (config['DEBUG']) console.log("Visible"); + + var IEdetected = detectIE(); + if (config['DEBUG']) console.log("IE " + IEdetected); + if (parseInt(IEdetected) < 12) { + $('#IEdetected').show(); + throw new Error("IE " + IEDetected + " not supported."); + } + init(); + param["posturl"] = getParamValue('posturl'); + param["decodedURI"] = decodeURIComponent(param["posturl"]); + param["user_context"] = getParamValue('user_context', param["decodedURI"]); + param["pid"] = getParamValue('pid', param["decodedURI"]); + + if (config['DEBUG']) console.log("posturl: " + param["posturl"]); + if (config['DEBUG']) console.log("decodedURI: " + param["decodedURI"]); + if (config['DEBUG']) console.log("user_context: " + param["user_context"]); + if (config['DEBUG']) console.log("pid: " + param["pid"]); + + seatmapWorkflow(param["decodedURI"]); +} + +// EVENT RESIZE +$(window).resize(function() { + if ($(window).width() < 400) { + $('.container-fluid').hide(); + $('#screenTooSmall').show(); + } + else { + $('.container-fluid').show(); + $('#screenTooSmall').hide(); + } +}); + +function detectIE () { + var ua = window.navigator.userAgent; + + var msie = ua.indexOf('MSIE '); + if (msie > 0) { + // IE 10 or older => return version number + return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10); + } + + var trident = ua.indexOf('Trident/'); + if (trident > 0) { + // IE 11 => return version number + var rv = ua.indexOf('rv:'); + return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10); + } + + var edge = ua.indexOf('Edge/'); + if (edge > 0) { + // Edge (IE 12+) => return version number + return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10); + } + + // other browser + return false; +} + +function init() { + if (config['DEBUG']) console.log(getFuncName()); + + /* + * jQuery myCart - v1.7 - 2018-03-07 + * http://asraf-uddin-ahmed.github.io/ + * Copyright (c) 2017 Asraf Uddin Ahmed; Licensed None + */ + + (function($) { + + "use strict"; + + var OptionManager = (function() { + var objToReturn = {}; + + var _options = null; + var DEFAULT_OPTIONS = { + currencySymbol: config["CURRENCY_SYMBOL"], + classCartIcon: 'my-cart-icon', + classCartBadge: 'my-cart-badge', + classProductQuantity: 'my-product-quantity', + classProductRemove: 'my-product-remove', + classCheckoutCart: 'my-cart-checkout', + affixCartIcon: true, + showCheckoutModal: true, + numberOfDecimals: 2, + cartItems: null, + clickOnAddToCart: function($addTocart) {}, + afterAddOnCart: function(products, totalPrice, totalQuantity) {}, + clickOnCartIcon: function($cartIcon, products, totalPrice, totalQuantity) {}, + checkoutCart: function(products, totalPrice, totalQuantity) { + if (config['DEBUG']) console.log("checkoutCart"); + return false; + }, + getDiscountPrice: function(products, totalPrice, totalQuantity) { + return null; + } + }; + + var loadOptions = function(customOptions) { + _options = $.extend({}, DEFAULT_OPTIONS); + if (typeof customOptions === 'object') { + $.extend(_options, customOptions); + } + }; + var getOptions = function() { + return _options; + }; + + objToReturn.loadOptions = loadOptions; + objToReturn.getOptions = getOptions; + return objToReturn; + }()); + + var MathHelper = (function() { + var objToReturn = {}; + var getRoundedNumber = function(number) { + if (isNaN(number)) { + throw new Error('Parameter is not a Number'); + } + number = number * 1; + options = OptionManager.getOptions(); + return number.toFixed(options.numberOfDecimals); + }; + objToReturn.getRoundedNumber = getRoundedNumber; + return objToReturn; + }()); + + ProductManager = (function() { + var objToReturn = {}; + var localStorage = {}; + + /* + PRIVATE + */ + // localStorage.products = localStorage.products ? localStorage.products : ""; + if (typeof localStorage.products !== "undefined") { + if (config['DEBUG']) console.log("localStorage defined"); + localStorage.products = ""; + } + else { + if (config['DEBUG']) console.log("localStorage undefined"); + } + + var getIndexOfProduct = function(id) { + var productIndex = -1; + var products = getAllProducts(); + $.each(products, function(index, value) { + if (value.id == id) { + productIndex = index; + return; + } + }); + return productIndex; + }; + var setAllProducts = function(products) { + localStorage.products = JSON.stringify(products); + }; + var addProduct = function(id, name, summary, price, quantity, image, seatObj) { + var products = getAllProducts(); + products.push({ + id: id, + name: name, + summary: summary, + price: price, + quantity: quantity, + image: image, + seatObj: seatObj, + }); + setAllProducts(products); + }; + + /* + PUBLIC + */ + var getAllProducts = function() { + try { + var products = JSON.parse(localStorage.products); + return products; + } + catch (e) { + return []; + } + }; + var updatePoduct = function(id, quantity) { + var productIndex = getIndexOfProduct(id); + if (productIndex < 0) { + return false; + } + var products = getAllProducts(); + products[productIndex].quantity = typeof quantity === "undefined" ? products[productIndex].quantity * 1 + 1 : quantity; + setAllProducts(products); + return true; + }; + var updatePrice = function(id, price) { + var productIndex = getIndexOfProduct(id); + if (productIndex < 0) { + return false; + } + var products = getAllProducts(); + // products[productIndex].quantity = typeof quantity === "undefined" ? products[productIndex].quantity * 1 + 1 : quantity; + products[productIndex].price = price; + setAllProducts(products); + return true; + }; + var setProduct = function(id, name, summary, price, quantity, image, seatObj) { + if (typeof id === "undefined") { + console.error("id required"); + return false; + } + if (typeof name === "undefined") { + console.error("name required"); + return false; + } + if (typeof image === "undefined") { + console.error("image required"); + return false; + } + if (!$.isNumeric(price)) { + console.error("price is not a number"); + return false; + } + if (!$.isNumeric(quantity)) { + console.error("quantity is not a number"); + return false; + } + if (typeof seatObj === "undefined") { + console.error("seatObj required"); + return false; + } + summary = typeof summary === "undefined" ? "" : summary; + + if (!updatePoduct(id)) { + addProduct(id, name, summary, price, quantity, image, seatObj); + } + }; + var clearProduct = function() { + setAllProducts([]); + }; + var removeProduct = function(id) { + var products = getAllProducts(); + products = $.grep(products, function(value, index) { + return value.id != id; + }); + setAllProducts(products); + }; + var getTotalQuantity = function() { + var total = 0; + var products = getAllProducts(); + $.each(products, function(index, value) { + total += value.quantity * 1; + }); + return total; + }; + var getTotalPrice = function() { + var products = getAllProducts(); + var total = 0; + $.each(products, function(index, value) { + total += value.quantity * value.price; + total = MathHelper.getRoundedNumber(total) * 1; + }); + return total; + }; + + objToReturn.getAllProducts = getAllProducts; + objToReturn.updatePoduct = updatePoduct; + objToReturn.updatePrice = updatePrice; + objToReturn.setProduct = setProduct; + objToReturn.clearProduct = clearProduct; + objToReturn.removeProduct = removeProduct; + objToReturn.getTotalQuantity = getTotalQuantity; + objToReturn.getTotalPrice = getTotalPrice; + return objToReturn; + }()); + + + var loadMyCartEvent = function(targetSelector) { + + var options = OptionManager.getOptions(); + var $cartIcon = $("." + options.classCartIcon); + $cartBadge = $("." + options.classCartBadge); + var classProductQuantity = options.classProductQuantity; + var classProductRemove = options.classProductRemove; + var classCheckoutCart = options.classCheckoutCart; + + idCartModal = 'my-cart-modal'; + var idCartTable = 'my-cart-table'; + var idGrandTotal = 'my-cart-grand-total'; + var idEmptyCartMessage = 'my-cart-empty-message'; + var idDiscountPrice = 'my-cart-discount-price'; + var classProductTotal = 'my-product-total'; + var classAffixMyCartIcon = 'my-cart-icon-affix'; + + + if (options.cartItems && options.cartItems.constructor === Array) { + ProductManager.clearProduct(); + $.each(options.cartItems, function() { + ProductManager.setProduct(this.id, this.name, this.summary, this.price, this.quantity, this.image); + }); + } + + $cartBadge.text(ProductManager.getTotalQuantity()); + + if (!$("#" + idCartModal).length) { + $('body').append( + '' + ); + } + + drawTable = function() { + var DATA = jqxhr.responseJSON; + + var $cartTable = $("#" + idCartTable); + $cartTable.empty(); + + var products = ProductManager.getAllProducts(); + + $.each(products, function() { + var total = this.quantity * this.price; + + // OPTION DROPDOWN + var selectID = 'select' + this.id; + var select = "/)[1]; + console.log(errorMsg); + + if (errorMsg === '') { + // if (errorMsg == '') { + successful = true; + + ProductManager.clearProduct(); + $cartBadge.text(ProductManager.getTotalQuantity()); + $("#" + idCartModal).modal("hide"); + + // REDIRECT TO TICKET PURCHASE + window.location.replace(checkoutURL); + // window.location.replace(proxyCheckoutURL); + } + else { + successful = false; + + errorMsg = errorMsg.replace(/\/g, ' '); + + new jBox('Notice', { + content: errorMsg, + color: 'red', + width: '100vw', + responsiveWidth: true, + position: { x: 'center', y: 'top' }, + autoClose: 10000, + closeButton: 'box', + }); + } + } + }); + + return successful; +} + +function untickSeat(id) { + if (config['DEBUG']) console.log(getFuncName()); + console.log(id); + document.getElementById(id).click(); // Click on the checkbox +} + +function selectRefreshPrice(select) { + if (config['DEBUG']) console.log(getFuncName()); + + if (config['DEBUG']) console.log(select); + + var $sel = $(select); + var value = $sel.val(); + var text = $("option:selected", $sel).text(); + var idSelect = $sel[0].id; + var id = idSelect.replace("select", ""); + + ProductManager.updatePrice(id, value); + selectOptionSelected[idSelect] = { selected: text }; // Remember Select Option Value for redraw in drawTable() + // drawTable(); +} + +function setSelectedIndex() { + if (config['DEBUG']) console.log(getFuncName()); + + for (var idSelect in selectOptionSelected) { + if (selectOptionSelected.hasOwnProperty(idSelect)) { + var s = document.getElementById(idSelect); + var v = selectOptionSelected[idSelect].selected; + + if (s == null) { + delete selectOptionSelected[idSelect]; + continue; + } + else { + for (var i = 0; i < s.options.length; i++) { + if (s.options[i].text === v) { + if (config['DEBUG']) console.log(s.options[i].text + ' matches ' + v); + if (config['DEBUG']) console.log(v); + if (config['DEBUG']) console.log(s); + s.options[i].selected = true; + selectRefreshPrice(s); // FIX RIGHT PRICE OPTION DROPDOWN + } + } + } + + } + } +} + +function generateSeatmap(DATA) { + if (config['DEBUG']) console.log(getFuncName()); + + var returnArr = generateMapMatrix(DATA); + var map1d = returnArr[0]; + var seatsUnavailable = returnArr[1]; + var mappingPricescalesSections = returnArr[2]; + var rows = returnArr[3]; + var seats = generateSeats(DATA, mappingPricescalesSections); + var legend = generateLegend(DATA, 'legend'); + var firstSeatLabel = 1; + + // CHANGE HTML TITLE + document.title = DATA.EVENT.DESC + ' | Saalplanbuchung by Tickets.com'; + + // SEAT MAP + sc = $('#seat-map').seatCharts({ + map: map1d, + seats: seats, + + naming: { + top: false, + left: true, + // rows: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '1', '2', '3', '4', '5', '6', '7', '8', '9'], + rows: rows, + // columns: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y'], + getLabel: function(character, row, column) { + return firstSeatLabel++; + }, + }, + legend: legend, + click: function() { + if (this.status() == 'available') { + if ((ProductManager.getTotalQuantity() + 1) > config[DATA.VENUE.CODE]["MAX_TICKETS_PER_USER"]) { + var errorMsg = 'Maximale Ticketantahl erreicht: Sie können nicht mehr als ' + config[DATA.VENUE.CODE]["MAX_TICKETS_PER_USER"] + ' Tickets buchen.'; + new jBox('Notice', { + content: errorMsg, + color: 'red', + width: '100vw', + responsiveWidth: true, + position: { x: 'center', y: 'top' }, + closeButton: 'box', + autoClose: 10000, + }); + return; + } + + // ADD PRODUCT TO CART + fillSeatObjData(this.settings.id); + myCartAddWrapper(this.settings.id, this.settings.data.product, this.settings.data.color, this.settings.data.price, 1, '', this); + + return 'selected'; + } + else if (this.status() == 'selected') { + myCartRemoveWrapper(this.settings.id); + return 'available'; + } + else if (this.status() == 'unavailable') { + //seat has been already booked + console.log('unavailable'); + return 'unavailable'; + } + else { + return this.style(); + } + } + }); + + // INIT JBOX TOOLTIP + var jbox = new jBox('Tooltip', { + attach: '.available', + trigger: 'mouseenter', + onCreated: function() { + if (config['DEBUG']) console.log("onCreated"); + }, + onOpen: function() { + // GET SEAT ID AND OBJECT + var seatID = this.source.context.id; + var seatObj = sc.get(seatID); + // console.log(seatObj); + + if (seatID == '' || seatObj.settings.status == 'unavailable') { + if (config['DEBUG']) console.log("Not a real seat or seat unavailable -> Return."); + return; + } + + // FILL SEAT OBJECT IF NOT ALREADY + fillSeatObjData(seatID); + + // SET JBOX CONTENT + this.setContent(seatObj.settings.data.productJBox); + }, + onClose: function() {} + }); + + // DETACH JBOX FROM LEGEND AND UNAVAILABLE SEATS + for (var i = 0; i < jbox.attachedElements.length; i++) { + if (jbox.attachedElements[i].id == "") { + jbox.detach($(jbox.attachedElements[i])); + i = -1; + continue; + } + } + for (var j = 0; j < seatsUnavailable.length; j++) { + jbox.detach($('#' + seatsUnavailable[j])); + } + + // MYCART + $(function() { + var goToCartIcon = function($addTocartBtn) { + var $cartIcon = $(".my-cart-icon"); + var $image = $('').css({ "position": "fixed", "z-index": "999" }); + $addTocartBtn.prepend($image); + var position = $cartIcon.position(); + $image.animate({ + top: position.top, + left: position.left + }, 500, "linear", function() { + $image.remove(); + }); + }; + }); + + // RUN POST GENERATION HOOKS + sc.status(seatsUnavailable, 'unavailable'); // seatsUnavailable RECEIVED FROM SERVER + seperateSeatmapsCSS(DATA); // CSS CHANGES AFTER GENERATE + venueSpecificCSS(DATA); + $(window).trigger('resize'); +} + +function venueSpecificCSS(DATA) { + if (config['DEBUG']) console.log(getFuncName()); + + // VENUE SPECIFIC WIDTH TO CENTER FRONT INDICATORS + var paddingLeft = config[DATA.VENUE.CODE]["PADDING-LEFT"]; + $(".front-indicator").css({ "padding-left": paddingLeft }); + var paddingLeftStage = config[DATA.VENUE.CODE]["PADDING-LEFT-STAGE"]; + $(".stage-indicator").css({ "padding-left": paddingLeftStage }); + + // STAATSOPERETTE DRESDEN SPECIFIC + if (DATA.VENUE.CODE == "SAAL KKM" || DATA.VENUE.CODE == "GSP KKM") { + $("#seat-map").append(config[DATA.VENUE.CODE]["Tonpult"]); + } + + // VENUE SPECIFIC CSS + if (config['DEBUG']) console.log('Applying venue specific CSS for ' + config[DATA.VENUE.CODE]); + var styleSheet = document.createElement("style"); + styleSheet.type = "text/css"; + styleSheet.innerText = config[DATA.VENUE.CODE]["CSS"]; + document.head.appendChild(styleSheet); +} diff --git a/seatmap-client/style.css b/seatmap-client/style.css new file mode 100644 index 0000000..c3b075a --- /dev/null +++ b/seatmap-client/style.css @@ -0,0 +1,486 @@ +body { + background-color: #e9e9e9; + margin: 2em; +} + +a { + color: #b71a4c; +} + +.front-indicator { + text-align: left; + text-transform: uppercase; + font-size: 1.2vw; + margin-bottom: 1vw; + margin-top: 5vw; + display: inline-grid; +} + +.stage-indicator { + display: inline-grid; + background-color: none; + text-align: left; + text-transform: uppercase; +} + +.wrapper { + width: 100%; + text-align: center; +} + +.container { + margin: 0 auto; + width: 100% !important; + text-align: left; +} + +.booking-details { + float: left; +} + +.booking-details p,li { + font-size: 1vw; +} + +.booking-details h2 { + margin: 0px 0 10px 0; + font-size: 1.2vw; + text-transform: uppercase; +} + +.booking-details h3 { + margin: 0px 0 10px 0; + font-size: 1vw; +} + +div.seatCharts-cell { + color: #182C4E; + background-color: #e9e9e9; +} + +div.seatCharts-seat { + color: #FFFFFF; + cursor: pointer; +} + +div.seatCharts-row { + /*height: 35px;*/ + height: 1vw; +} + +div.seatCharts-seat.available { + background-color: #B9DEA0; +} + +div.seatCharts-seat.available.first-class { + /* background: url(vip.png); */ + background-color: #3a78c3; +} + +div.seatCharts-seat.focused { + background-color: #76B474; +} + +div.seatCharts-seat.selected { + background-image: url("img/iconfinder_tick_216457.png"); + background-repeat: no-repeat; + background-position: center center; + /*background-size: 100% 100%, auto;*/ + background-size: 100% 100%, auto; +} + +div.seatCharts-seat.unavailable { + /*background-color: red;*/ + cursor: not-allowed; + background: url("data:image/svg+xml;charset=utf8,"); + background-image: url("img/iconfinder_basics-22_296812.png"); + background-repeat: no-repeat; + background-position: center center; + background-size: 100% 100%, auto; + opacity: 0.3; +} + +/*div.seatCharts-seat.unavailable:before {*/ + +/* background: #037CA9;*/ + +/* content: "";*/ + +/* width: 10px;*/ + +/* height: 5px;*/ + +/* position: absolute;*/ + +/* top: 5px;*/ + +/* left: -5px;*/ + +/*}*/ + +div.seatCharts-container { + /*border-right: 1px dotted #adadad;*/ + width: auto; + padding: 0; +} + +div.seatCharts-legend { + /*padding-left: 0px;*/ + /*position: absolute;*/ + /*bottom: 16px;*/ + padding-top: 0px; +} + +ul.seatCharts-legendList { + padding-left: 0px; + display: grid; + margin: 0; +} + +span.seatCharts-legendDescription { + margin-left: 0.5vw; + line-height: 1.2vw; + /*font-size: 1vw;*/ +} + +.checkout-button { + display: block; + margin: 10px 0; + font-size: 14px; +} + +#selected-seats { + max-height: 90px; + overflow-y: scroll; + overflow-x: none; + width: 170px; +} + +#spacer { + /*margin: 40px 0px 0px 0px;*/ + margin: 2vw 0vw 0vw 0vw; +} + +p { + margin: 0px !important; + font-size: 1vw; +} + +.top-buffer-20 { + margin-top: 20px; +} + +.top-buffer-25 { + margin-top: 25px; +} + +.top-buffer-30 { + margin-top: 30px; +} + +div.seatCharts-cell { + margin: 0.2vw; +} + +#logo { + width: 50%; + position: absolute; + bottom: 0; + ; +} + +.container-fluid { + visibility: hidden; + margin: 0; + padding: 0; + + /*padding-right: 1vw;*/ + /*padding-left: 1vw;*/ + /*margin-right: auto;*/ + /*margin-left: auto;*/ +} + +h4 { + font-size: 1.2vw; +} + +/*.row {*/ + +/* display: -webkit-box;*/ + +/* display: -webkit-flex;*/ + +/* display: -ms-flexbox;*/ + +/* display: flex;*/ + +/* flex-wrap: wrap;*/ + +/*}*/ + +/*.row > [class*='col-'] {*/ + +/* display: flex;*/ + +/* flex-direction: column;*/ + +/*}*/ + +.centered { + position: fixed; + /* or absolute */ + top: 50%; + left: 50%; + /* bring your own prefixes */ + transform: translate(-50%, -50%); +} + +/*SHOPPING CART*/ + +/*.badge-notify{*/ + +/* background:red;*/ + +/* position:relative;*/ + +/* top: -20px;*/ + +/* right: 10px;*/ + +/*}*/ + +/*.my-cart-icon-affix {*/ + +/* position: fixed;*/ + +/* z-index: 999;*/ + +/*}*/ + +.glyphicon { + font-size: 2vw; + top: -.2vw; + white-space:nowrap; +} + +.btn-danger { + width: 20px; + text-align: center; + height: 20px; +} + +#my-cart-table td { + vertical-align: middle; + padding: 10px 0px 10px 0px; + font-size: 14px; +} + +.selectBuyerTypes { + width: 200px; + font-size: 14px; +} + +.badge { + padding: 0.3vw 0.5vw 0.5vw 0.5vw !important; + font-size: 0.7vw !important; + display: inline-block; + padding: 3px 7px; + font-size: 12px; + font-weight: 700; + color: #fff; + vertical-align: middle; + border-radius: 10px; +} + +.modal-backdrop { + display: none; +} + +.badge-notify { + background: red; + position: relative; + top: -0.8vw; + right: 0.5vw; +} + +.my-cart-icon-affix { + position: relative; + z-index: 999; +} + +li.seatCharts-legendItem { + margin-top: 0.2vw; + line-height: 1.8vw; +} + +#border { + width: 80vw; + margin: auto; + border-bottom: 1px dotted #ccc; +} + +#eventDesc { + text-decoration: underline; + font-weight: bold; + font-family: "Bodoni","Times New Roman",Times,serif; +} + +#venueList { + display: none; +} + +#venueDesc { + font-family: "Franklin Gothic Medium","Times New Roman",Times,serif; +} + +#datetime_DE { + font-family: "Franklin Gothic Medium","Times New Roman",Times,serif; +} + +.buttonOpenCart { + background-color: dimgrey; + color: floralwhite; + font-size: 1vw; + opacity: 0.8; + text-align: center; + transition: 0.3s; + cursor: pointer; + padding-top: 1vw; + width: 20vw; +} + +.buttonOpenCart:hover { + opacity: 1; +} + +#divCart { + margin-top: 1vw; +} + +#mycart { + float: right; + cursor: pointer; +} + +/* Start by setting display:none to make this hidden. + Then we position it in relation to the viewport window + with position:fixed. Width, height, top and left speak + for themselves. Background we set to 80% white with + our animation centered, and no-repeating */ + +.modal { + display: none; + position: fixed; + z-index: 1000; + top: 0; + left: 0; + height: 100%; + width: 100%; + background: rgba( 255, 255, 255, .8) url('img/30.svg') 50% 60% no-repeat; +} + +.modal:before { + content: ''; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + background: rgba( 255, 255, 255, .8) url('img/Tickets-small.png') 50% 50% no-repeat; +} + +.modal.special:before { + background: none; +} + +/* When the body has the loading class, we turn + the scrollbar off with overflow:hidden */ + +body.loading .modal { + overflow: hidden; +} + +/* Anytime the body has the loading class, our + modal element will be visible */ + +body.loading .modal { + display: block; + background-color: #ffffff; +} + +#seatmap_version { + text-align: right; + font-style: italic; + font-size: 1vw; +} + +.modal-content { + background-color: #e9e9e9; + min-width: 400px; +} + +.jBox-closeButton-box:before { + top: 0.7vw; +} + +.jBox-closeButton-box .jBox-closeButton { + top: 0.7vw; +} + +.jBox-content { + font-size: 1vw; +} + +h3 { + font-size: 2vw; +} + +h5 { + font-size: 1vw; +} + +.cartFont { + font-size: 14px; +} + +#screenTooSmall { + display: none; + font-size: 1.5vw; +} + +#IEdetected { + display: none; + font-size: 1.5vw; +} + +.rowBooking { + width: 60%; + margin: auto; +} + +/*ONLY IE < 10*/ + +/*@media all and (-ms-high-contrast: none),*/ +/*(-ms-high-contrast: active) {*/ +/* div.seatCharts-cell {*/ +/* height: 1.36vw;*/ +/* width: 1.36vw;*/ +/* }*/ +/*}*/ + +/*@media (min-width: 531px) and (max-width:770px) {*/ +/* div.seatCharts-cell {*/ +/* height: 1.33vw;*/ +/* width: 1.33vw;*/ +/* }*/ +/*}*/ + +/*@media (min-width: 400px) and (max-width:530px) {*/ +/* div.seatCharts-cell {*/ +/* height: 1.301vw;*/ +/* width: 1.301vw;*/ +/* }*/ +/* .glyphicon {*/ +/* display: none;*/ +/* }*/ +/*}*/ \ No newline at end of file diff --git a/seatmap-client/venue.css b/seatmap-client/venue.css new file mode 100644 index 0000000..a412471 --- /dev/null +++ b/seatmap-client/venue.css @@ -0,0 +1,9 @@ +.modal:before { + content: ''; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + background: rgba( 255, 255, 255, .8) url('img/Tickets-small.png') 50% 50% no-repeat; +} \ No newline at end of file diff --git a/seatmap-inject/seatmap-inject-np.js b/seatmap-inject/seatmap-inject-np.js new file mode 100644 index 0000000..6ada7a8 --- /dev/null +++ b/seatmap-inject/seatmap-inject-np.js @@ -0,0 +1,151 @@ +var config = { + 'DEBUG': true, + 'BRANCH': 'seatmap_main', +}; +if (config['BRANCH'] === 'seatmap_testing') { + config['SEATMAP_WEBAPI_URL'] = 'https://seatmap-testing.zinomedia.de/seatmap-webapi/api.php'; +} +else if (config['BRANCH'] === 'seatmap_main') { + config['SEATMAP_WEBAPI_URL'] = 'https://zinomedia.de/seatmap_main/seatmap-webapi/api.php'; +} + +jQuery(document).ready(function() { + if (config['DEBUG']) console.log(getFuncName('ready')); + + check_inject(); +}); + +function check_inject() { + if (config['DEBUG']) console.log(getFuncName()); + + var pvo_venue_name = jQuery('.venue span')[0].textContent.toUpperCase(); + var url = config['SEATMAP_WEBAPI_URL'] + '/records/halls?filter=PVO_VENUE_NAME,eq,' + pvo_venue_name + '&include=INJECT'; + + var result = jQuery.get(url, function(data) {}) + .done(function(data) { + if (data['records'][0]['INJECT']) { + if (config['DEBUG']) console.log('Starting inject...'); + inject_seatmap(); + } + else { + if (config['DEBUG']) console.log('Not injecting.'); + } + }); +} +function inject_seatmap() { + var url, param; + var content = document.getElementsByTagName('html')[0].innerHTML; + var inputsWithValue = getInputs(content); + if (config['DEBUG']) console.log(inputsWithValue); + + if (!jQuery.isEmptyObject(inputsWithValue)) { + if (inputsWithValue.hasOwnProperty("trxstate") && inputsWithValue["trxstate"].value == 20) { + if (config['DEBUG']) console.log("trxstate 20 identified"); + + manipulateDocument(); + var note = important_note(); + param = getPosturl(content); + if (jQuery('#flash_seat_map_box_id').length) { + url = generateUrl(param, inputsWithValue, note); + if (config['DEBUG']) console.log(url); + jQuery("#viewSeatFlashMapButton").unbind(); + jQuery('#viewSeatFlashMapButton').click(function() { + if (config['BRANCH'] === 'seatmap_testing') { + window.location.href = 'https://seatmap-testing.zinomedia.de/seatmap-client/index.html?' + "posturl=" + url; + } + else if (config['BRANCH'] === 'seatmap_main') { + window.location.href = 'https://purchase.tickets.zinomedia.de/?' + "posturl=" + url; + } + else { + throw new Error('Die: Branch not defined.'); + } + }); + } + } + else if (inputsWithValue.hasOwnProperty("prevtrxstate") && inputsWithValue["prevtrxstate"].value == 30) { + if (config['DEBUG']) console.log("prevtrxstate 30 identified"); + + // jQuery(".jq_replace")[0].text = 'Abbrechen'; + // jQuery('.jq_add').css('display', 'none'); + } + } +} +function generateUrl(param, inputsWithValue, note) { + if (config['DEBUG']) console.log(getFuncName()); + + var url = param[0]; + var event = param[1]; + var holdcode = param[2]; + + var parameter = ''; + for (var property in inputsWithValue) { + if (inputsWithValue.hasOwnProperty(property)) { + parameter = parameter + property + '=' + inputsWithValue[property].value + '&'; + } + } + parameter = parameter.substring(0, parameter.length - 1); + + url = url + "&holdcode=" + holdcode + "&event=" + event + '&nocache=0&inclpkg=Y&incloffer=Y&inclcartdetails=Y&inclCart=Y&inclvenue=Y' + parameter; + if (typeof note !== 'undefined') { + url = url + '¬e=' + note; + } + url = encodeURIComponent(url); + + return url; +} +function getPosturl(content) { + if (config['DEBUG']) console.log(getFuncName()); + + var posturl = content.match(/posturl:"(.+?)"/)[1]; + var event = content.match(/event:"(.+?)"/)[1]; + var holdcode = content.match(/holdcode:"(.+?)"/)[1]; + + return [posturl, event, holdcode, content]; +} +function getInputs(content) { + if (config['DEBUG']) console.log(getFuncName()); + + var inputsWithValue = new Object(); + var data = jQuery.parseHTML(content); + var checkoutParam = [ + 'APPTE', 'age_consent_is_checked', 'agency', 'cancelAndRedirectTrxState', 'cogid', 'coids', 'discount=A=IE', 'discount=A=IV', 'discountdesc=A=IE', 'discountdesc=A=IV', 'discountfees=A=IE', 'discountfees=A=IV', 'discountprice=A=IE', 'discountprice=A=IV', 'dpa_selection', 'etpgcode', 'flashDetected', 'gid', 'hbx_discount_prices', 'hbx_discounts', 'hbx_offered_pg', 'hbx_perf_codes', 'hbx_perf_sub_codes', 'hbx_pids', 'hbx_requested_pg', 'hbx_selected_tixx', 'hbx_upsell_flag', 'request_type', 'invalid_seats', 'inventory_filtering_action', 'inventory_month', 'inventory_year', 'isCapEnabled', 'is_availability_switch_from_map', 'is_ticket_exchange_request', 'ism_map_current_state_json_data', 'jcarousel_auto_off_val', 'listing_type', 'mainEventPID', 'map_coupon_code', 'mlbamsp', 'oid', 'ooids', 'orderkey', 'orgid', 'p_orgid', 'package_pids', 'parent_offer_id', 'pay_pal_token', 'pid', 'prevtrxstate', 'recapToken', 'redeem_voucher_data_event_mapping', 'replay_request', 'request_action', 's_mem_tkt_ren_retrieval', 'schedule', 'secure_trxn_enabled', 'selected_seat_indexes', 'selected_upsell_option', 'supplierCode', 'supplier_code', 'target_name_value', 'target_prev_trxstate', 'target_trxstate', 'target_url', 'timeout_seconds', 'trxstate', 'upsell_selected', 'user_context', 'valid_coupon_code_message' + ]; + jQuery(data).find('input').each(function() { + if (this.value !== '') { + if (checkoutParam.indexOf(this.name)) { + inputsWithValue[this.name] = this; + } + } + }); + + return inputsWithValue; +} + +function manipulateDocument() { + if (config['DEBUG']) console.log(getFuncName()); + + jQuery('#flash_seat_map_box_id').css('display', 'block'); + jQuery('#get_flash').css('display', 'none'); +} +function important_note() { + if (config['DEBUG']) console.log(getFuncName()); + + var element = document.getElementsByClassName('important_note'); + if (element.length > 0) { + var important_note = element[0].textContent; + if (config['DEBUG']) console.log(important_note); + + return important_note; + } +} +function getFuncName(arg) { + var caller; + if (getFuncName.caller.name !== '') { + caller = getFuncName.caller.name; + } + else { + caller = arg; + } + + return '\n' + '-'.repeat(80) + '\n' + 'PARENT ' + caller + '\n' + '-'.repeat(80); +} \ No newline at end of file diff --git a/seatmap-server/seatmap-server.pl b/seatmap-server/seatmap-server.pl new file mode 100755 index 0000000..42e8af5 --- /dev/null +++ b/seatmap-server/seatmap-server.pl @@ -0,0 +1,619 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use CGI ":standard"; +use CGI::Carp qw(warningsToBrowser fatalsToBrowser); +use Data::Dumper; +use LWP::UserAgent (); +use XML::LibXML; +use Encode; +use URI; +use Benchmark; +use JSON; +use utf8; +use feature qw/say/; +use Encode::Deep; +use DBD::mysql; +use URI::Encode qw(uri_encode uri_decode); + +# LWP +my $ua = LWP::UserAgent->new(keep_alive => 1); +$ua->agent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'); +$ua->timeout(10); +$ua->env_proxy; + +# CGI +my $cgi = CGI->new; + +# GLOBAL +my %CONFIG = + ( + 'DEBUG' => 0, + 'DEBUG_PRINT_DATA' => 0, + 'ONLINE' => 1, + 'OFFLINE_XML' => '../seatmap-client/offline/MapTicketSales.xml', + 'OFFLINE_XML_PARKETT' => '../seatmap-client/offline/MapTicketSales_Parkett.xml', + 'OFFLINE_XML_RANG' => '../seatmap-client/offline/MapTicketSales_Rang.xml', + 'MYSQL' => { + 'database' => 'seatmap', + 'hostname' => 'localhost', + 'user' => 'seatmap_p', + 'pw' => 'r4Iybg75&3Q@9N!*', + 'port' => 3306, + }, + ); +my %DATA; +my $connection; + +# WORKFLOW +my $t0 = Benchmark->new if $CONFIG{'DEBUG'}; +&getParameter(); +print Dumper $DATA{'PARAMETER'} if $CONFIG{'DEBUG'}; +&checkHost(); +&generateVenueUrl(); + +my $xml; +if ($CONFIG{'ONLINE'}) { + print "SET AS ONLINE\n" if $CONFIG{'DEBUG'}; + + $xml = get($DATA{'PARAMETER'}{'urlVenue'}); + &loadXML($xml, \$DATA{'DOM'}); + &parseXML(); + &getSeatmaps(); +} +elsif (!$CONFIG{'ONLINE'}) { + print "SET AS OFFLINE: USING LOCAL XML\n" if $CONFIG{'DEBUG'}; + $xml = $CONFIG{'OFFLINE_XML'}; + + &loadXML($xml, \$DATA{'DOM'}); + &parseXML(); + &loadXML($CONFIG{'OFFLINE_XML_PARKETT'}, \$DATA{'DOM'}); + parxeXML_section(); + &loadXML($CONFIG{'OFFLINE_XML_RANG'}, \$DATA{'DOM'}); + parxeXML_section(); +} + +my $config_ref = &getVenueConfig(); +&benchmarkEnd(); +&printOutput($config_ref); + + +# SUBS + +sub db_getVenueConfig { + &Delimiter((caller(0))[3]); + + my $query = "Select \ + venues.AGENCY As VENUE_AGENCY, + venues.NAME As VENUE_NAME, + halls.NAME As HALL_NAME, + halls.CODE As HALL_CODE, + halls.`FRONT-INDICATOR_WIDTH` As HALL_FRONT_INDICATOR, + halls.`PADDING-LEFT` As HALL_PADDING_LEFT, + halls.`PADDING-LEFT-STAGE` As HALL_PADDING_LEFT_STAGE, + halls.MAX_TICKETS_PER_USER As HALL_MAX_TICKETS_PER_USER, + halls.BUEHNE As HALL_BUEHNE, + halls.LEFT_NAMING As HALL_LEFT_NAMING, + halls.TONPULT As HALL_TONPULT, + halls.CSS As HALL_CSS, + halls.DESCRIPTION As HALL_DESC, + buyer_types.CODE As BUYER_TYPE_CODE, + buyer_types.DESCRIPTION As BUYER_TYPE_DESC, + halls.ID As HALL_ID + From + venues Inner Join + halls On halls.VENUE_ID = venues.ID Inner Join + buyer_types On buyer_types.VENUE_ID = halls.VENUE_ID + Where + venues.AGENCY = '$DATA{'PARAMETER'}{'supplier_code'}'"; + + print Dumper $query if $CONFIG{'DEBUG'}; + my $response = &db_query($query, $connection, 'selectall_arrayref'); + + my $query_config = "SELECT * FROM config"; + print Dumper $query_config if $CONFIG{'DEBUG'}; + my $response_config = &db_query($query_config, $connection, 'selectall_hashref', 'NAME'); + + return ($response, $response_config); +} + +sub accumulate_halls_data { + &Delimiter((caller(0))[3]); + my ($response) = @_; + + my %halls; + + for my $i (0 .. $#{$response}) { + # print Dumper $$response[$i]; + + my $hall_code = $$response[$i][3]; + $halls{$hall_code}{'VENUE_AGENCY'} = $$response[$i][0]; + $halls{$hall_code}{'VENUE_NAME'} = $$response[$i][1]; + $halls{$hall_code}{'HALL_NAME'} = $$response[$i][2]; + $halls{$hall_code}{'HALL_CODE'} = $$response[$i][3]; + $halls{$hall_code}{'HALL_FRONT_INDICATOR'} = $$response[$i][4]; + $halls{$hall_code}{'HALL_PADDING_LEFT'} = $$response[$i][5]; + $halls{$hall_code}{'HALL_PADDING_LEFT_STAGE'} = $$response[$i][6]; + $halls{$hall_code}{'HALL_MAX_TICKETS_PER_USER'} = $$response[$i][7]; + $halls{$hall_code}{'HALL_BUEHNE'} = $$response[$i][8]; + $halls{$hall_code}{'HALL_LEFT_NAMING'} = $$response[$i][9]; + $halls{$hall_code}{'HALL_TONPULT'} = $$response[$i][10]; + $halls{$hall_code}{'HALL_CSS'} = $$response[$i][11]; + $halls{$hall_code}{'HALL_DESC'} = $$response[$i][12]; + $halls{$hall_code}{'BUYER_TYPES'}{$$response[$i][13]} = $$response[$i][14]; + $halls{$hall_code}{'HALL_ID'} = $$response[$i][15]; + + my $hall_id = $$response[0][15]; + my $query_color = "SELECT * FROM custom_pricescales_color WHERE HALL_ID = $halls{$hall_code}{'HALL_ID'}"; + print Dumper $query_color if $CONFIG{'DEBUG'}; + my $response_color = &db_query($query_color, $connection, 'selectall_hashref', 'ID'); + if (%$response_color) { + $halls{$hall_code}{'CUSTOM_PRICESCALES_COLOR'} = $response_color; + } + + }; + + return \%halls; +} + +sub convert_to_config_format { + &Delimiter((caller(0))[3]); + my ($halls_ref, $response_config) = @_; + + + my %seatmap_config; + for my $hall_code (keys %{$halls_ref}) { + my $hall_name = $$halls_ref{$hall_code}{'HALL_NAME'}; + + $seatmap_config{$hall_code} = # HALL CONFIG + { + "FRONT-INDICATOR-WIDTH" => $$halls_ref{$hall_code}{'HALL_FRONT_INDICATOR'}, + "PADDING-LEFT" => $$halls_ref{$hall_code}{'HALL_PADDING_LEFT'}, + "PADDING-LEFT-STAGE" => $$halls_ref{$hall_code}{'HALL_PADDING_LEFT_STAGE'}, + "MAX_TICKETS_PER_USER" => $$halls_ref{$hall_code}{'HALL_MAX_TICKETS_PER_USER'}, + "BUEHNE" => $$halls_ref{$hall_code}{'HALL_BUEHNE'}, + "LEFT_NAMING" => $$halls_ref{$hall_code}{'HALL_LEFT_NAMING'}, + "CSS" => $$halls_ref{$hall_code}{'HALL_CSS'}, + }; + $seatmap_config{$hall_name} = # HALL BUYER TYPES + { + "AGENCY" => $$halls_ref{$hall_code}{'VENUE_AGENCY'}, + "BUYER_TYPES" => $$halls_ref{$hall_code}{'BUYER_TYPES'}, + }; + + if ($$halls_ref{$hall_code}{'CUSTOM_PRICESCALES_COLOR'}) { + for my $id (keys %{$$halls_ref{$hall_code}{'CUSTOM_PRICESCALES_COLOR'}}) { + my $code = $$halls_ref{$hall_code}{'CUSTOM_PRICESCALES_COLOR'}{$id}{'CODE'}; + my $color = $$halls_ref{$hall_code}{'CUSTOM_PRICESCALES_COLOR'}{$id}{'COLOR'}; + $seatmap_config{$hall_code}{'CUSTOM_PRICESCALES_COLOR'}{$code} = $color; + }; + } + + } + + for my $key (keys %$response_config) { + if ($key eq 'CORS_ANYWHERE') { + $seatmap_config{'CORS-ANYWHERE'}{'ROOT_URL'} = $$response_config{$key}{'VALUE'}; + } + else { + $seatmap_config{$key} = $$response_config{$key}{'VALUE'}; + } + }; + + + return \%seatmap_config; +} + +sub getVenueConfig { + &Delimiter((caller(0))[3]); + + # CONNECT TO DB + $connection = connectToMySql(); + + # GET DB DATA FOR VENUE / HALLS / BUYER TYPES + my ($response, $response_config) = db_getVenueConfig(); + + # CREATE ONE DATASET AND ACCUMULATE ALL BUYER TYPES FOR HALL + my $halls_ref = &accumulate_halls_data($response); + # print Dumper $halls_ref; + + # CONVERT DATA TO STEAMAP CONFIG FORMAT + my $seatmap_config_ref = convert_to_config_format($halls_ref, $response_config); + + # DISCONNECT FROM DB + $connection->disconnect(); + + return $seatmap_config_ref; +} + +sub db_query { + &Delimiter((caller(0))[3]); + my ($query, $connection, $switch, @rest) = @_; + my $response; + + my $statement; + if ($switch eq 'fetchrow') { + $statement = $connection->prepare($query); + $statement->execute(); + $response = $statement->fetchrow(); + } + elsif ($switch eq 'fetchall_hashref') { + $statement = $connection->prepare($query); + $statement->execute(); + $response = $statement->fetchall_hashref($rest[0]); + } + elsif ($switch eq 'fetchall_arrayref') { + $statement = $connection->prepare($query); + $statement->execute(); + $response = $statement->fetchall_arrayref(); + } + elsif ($switch eq 'do') { + $response = $connection->do($query) or die $connection->errstr; + } + elsif ($switch eq 'selectall_hashref') { + $response = $connection->selectall_hashref($query, $rest[0]) or die $connection->errstr; + } + elsif ($switch eq 'selectall_array') { + my @response = $connection->selectall_array($query) or die $connection->errstr; + return \@response; + } + elsif ($switch eq 'selectall_arrayref') { + $response = $connection->selectall_arrayref($query) or die $connection->errstr; + } + elsif ($switch eq 'selectrow_hashref') { + $response = $connection->selectrow_hashref($query) or die $connection->errstr; + } + $statement->finish if $statement; + + return $response; +} + +sub connectToMySql { + &Delimiter((caller(0))[3]); + + my $connectionInfo = "dbi:mysql:$CONFIG{'MYSQL'}{'database'};$CONFIG{'MYSQL'}{'hostname'}"; + + # make connection to database + my $connection = DBI->connect($connectionInfo, $CONFIG{'MYSQL'}{'user'}, $CONFIG{'MYSQL'}{'pw'}, { + RaiseError => 0, # SUGGESTED BY AnyEvent::DBI::MySQL + AutoCommit => 1, + mysql_auto_reconnect => 1, + }); + return $connection; +} + +sub wipeDataOverhead { + &Delimiter((caller(0))[3]); + + delete $DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{'AVAILABILITY'}; + for my $pricescaleID (keys(%{$DATA{'COMPILED'}{'VENUE'}{'PRICESCALES'}})) { + delete $DATA{'COMPILED'}{'VENUE'}{'PRICESCALES'}{$pricescaleID}{'SEATS'}; + } +} + +sub printOutput { + my $config_ref = shift; + + if (!$CONFIG{'DEBUG'}) { + &wipeDataOverhead(); + # print header('application/json; charset=utf-8;'), encode_json $DATA{'COMPILED'}; + + print header( + -type => 'application/json', + -access_control_allow_origin => '*', + -charset => 'utf-8', + ); + + # FIX ENCODING + $DATA{'COMPILED'} = Encode::Deep::decode('utf-8', Encode::Deep::encode('cp850', $DATA{'COMPILED'})); + # my $encoded = Encode::Deep::encode('cp850', $DATA{'COMPILED'}); + # my $decoded = Encode::Deep::decode('utf-8', $encoded); + + # ADD SEATMAP CONFIG + $DATA{'COMPILED'}{'CONFIG'} = $config_ref; + + # OUTPUT JSON + print encode_json $DATA{'COMPILED'}; + } + elsif ($CONFIG{'DEBUG'} && $CONFIG{'DEBUG_PRINT_DATA'}) { + &Delimiter((caller(0))[3]); + + print "\n\n" . encode_json $DATA{'COMPILED'}; + # print "\n\n" . Dumper(\%DATA); + + } +} + +sub checkHost() { + &Delimiter((caller(0))[3]); + return if !$CONFIG{'ONLINE'}; + + my $URI = URI->new($DATA{'PARAMETER'}{'url'}, 'http'); + if (($URI->host() eq 'purchase.tickets.com') && $URI->scheme && $DATA{'PARAMETER'}{'url'}) { + print "VALID HOST\n" if $CONFIG{'DEBUG'}; + } + else { + die "INVALID OR MISSING HOST.\n"; + } +} + +sub benchmarkEnd() { + &Delimiter((caller(0))[3]); + + if ($CONFIG{'DEBUG'}) { + my $t1 = Benchmark->new; + my $td = timediff($t1, $t0); + print "BENCHMARK: ",timestr($td),"\n" if $CONFIG{'DEBUG'}; + } +} + +sub generateVenueUrl() { + &Delimiter((caller(0))[3]); + return if !$CONFIG{'ONLINE'}; + + $DATA{'PARAMETER'}{'urlVenue'} = $DATA{'PARAMETER'}{'url'} . "&supplier_code=$DATA{'PARAMETER'}{'supplier_code'}&bots_event_code=$DATA{'PARAMETER'}{'bots_event_code'}&event_sub_code=$DATA{'PARAMETER'}{'event_sub_code'}" . "&holdcode=0&event=$DATA{'PARAMETER'}{'event'}&nocache=0&inclpkg=Y&incloffer=Y&inclcartdetails=Y&inclCart=Y&inclvenue=Y"; +} + +sub getSeatmaps() { + &Delimiter((caller(0))[3]); + + for my $seatmapID (keys(%{$DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}})) { + my $url = $DATA{'PARAMETER'}{'url'} . "&supplier_code=$DATA{'PARAMETER'}{'supplier_code'}&bots_event_code=$DATA{'PARAMETER'}{'bots_event_code'}&event_sub_code=$DATA{'PARAMETER'}{'event_sub_code'}" . "&event=$DATA{'PARAMETER'}{'event'}&nocache=1&inclsection=Y&incloffer=Y&offer=0&inclseatmap=Y&inclCart=Y&holdcode=0&seatmap=$seatmapID"; + + print "GET SEATMAP $seatmapID...\n" if $CONFIG{'DEBUG'}; + &loadXML(get($url), \$DATA{'DOM'}); + parxeXML_section(); + } +} + +sub parxeXML_section { + &Delimiter((caller(0))[3]); + + my $id = $DATA{'DOM'}->findvalue('//seatmap/@id'); + #print "ID: $id\n"; + + # CREATE PRICE ARRAYS + foreach my $node ($DATA{'DOM'}->findnodes('//pricescale_config/pricescale')) { + my $pricescaleID = $node->findvalue('@id'); + @{$DATA{'COMPILED'}{'VENUE'}{'PRICESCALES'}{$pricescaleID}{'SEATS'}} = split /,/, $node->findvalue('@mask'); + } + + # CREATE AVAILABILITY ARRAYS + @{$DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{'AVAILABILITY'}{'AVAILABLE'}} = split /,/, $DATA{'DOM'}->findvalue('//availability/@available_selectable_mask'); + @{$DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{'AVAILABILITY'}{'UNAVAILABLE'}} = split /,/, $DATA{'DOM'}->findvalue('//availability/@unavailable_unselectable_mask'); + + # CREATE SEATMAP_CONFIG ROWS + my $rowCalculated = 0; + foreach my $node ($DATA{'DOM'}->findnodes('//rows/row')) { + $rowCalculated++; + my @seats = split /\|/, $node->findvalue('@seats'); + my $yCoord = $node->findvalue('@y_cell_coord'); + #print Dumper(@seats); + + my $seatNR = 0; + foreach my $i (0 .. $#seats) { + $seatNR++; + my ($id1, $id2, $number, $sectionID, $row, $seatNR_parsed) = split /,/, $seats[$i]; + #print "ID1: $id1 ID2: $id2 NUMBER: $number SECTIONID: $sectionID ROW: $rowCalculated SEATNR: $seatNR\n"; + + $row =~ s/\s+$//; + ($DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'ROWS'}{$rowCalculated}{$seatNR}{'ID1'}, $DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'ROWS'}{$rowCalculated}{$seatNR}{'X_COORD'}, $DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'ROWS'}{$rowCalculated}{$seatNR}{'SECTIONID'}, $DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'ROWS'}{$rowCalculated}{$seatNR}{'ROW'}, $DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'ROWS'}{$rowCalculated}{$seatNR}{'SEATNR'}, $DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'ROWS'}{$rowCalculated}{$seatNR}{'Y_COORD'}, $DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'ROWS'}{$rowCalculated}{$seatNR}{'ROW_PARSED'}, $DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'ROWS'}{$rowCalculated}{$seatNR}{'SEATNR_PARSED'}) = ($id1, $number, $sectionID, $rowCalculated, $seatNR, $yCoord, $row, $seatNR_parsed); + + # SECTION DESC + $DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'ROWS'}{$rowCalculated}{$seatNR}{'SECTIONID_DESC'} = $DATA{'COMPILED'}{'VENUE'}{'SECTION_CONFIG'}{$sectionID}{'DESC'}; + + # CHECK PRICE AND ADD COLOR + for my $pricescaleID (keys(%{$DATA{'COMPILED'}{'VENUE'}{'PRICESCALES'}})) { + if ( grep( /^$id1$/, @{$DATA{'COMPILED'}{'VENUE'}{'PRICESCALES'}{$pricescaleID}{'SEATS'}} ) ) { + #print "found it for price $DATA{'COMPILED'}{'VENUE'}{'PRICESCALES'}{$pricescaleID}{'PRICES'}{'REF_PRICE'}\n"; + $DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'ROWS'}{$rowCalculated}{$seatNR}{'PRICESCALES_ID'} = $pricescaleID; + + #%{$DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'ROWS'}{$rowCalculated}{$seatNR}{'PRICES'}} = %{$DATA{'COMPILED'}{'VENUE'}{'PRICESCALES'}{$pricescaleID}{'PRICES'}}; + #$DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'ROWS'}{$rowCalculated}{$seatNR}{'COLOR'} = $DATA{'COMPILED'}{'VENUE'}{'PRICESCALES'}{$pricescaleID}{'COLOR'}; + } + } + + # CHECK AVAILABILITY + if ( grep( /^$id1$/, @{$DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{'AVAILABILITY'}{'AVAILABLE'}} ) ) { + $DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'ROWS'}{$rowCalculated}{$seatNR}{'AVAILABLE'} = 1; + $DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'ROWS'}{$rowCalculated}{$seatNR}{'ENABLED'} = 1; + } + elsif ( grep( /^$id1$/, @{$DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{'AVAILABILITY'}{'UNAVAILABLE'}} ) ) { + $DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'ROWS'}{$rowCalculated}{$seatNR}{'AVAILABLE'} = 0; + $DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'ROWS'}{$rowCalculated}{$seatNR}{'ENABLED'} = 1; + } + else { + $DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'ROWS'}{$rowCalculated}{$seatNR}{'AVAILABLE'} = 0; + $DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'ROWS'}{$rowCalculated}{$seatNR}{'ENABLED'} = 0; + } + + } + } +} + +sub substituteUmlauts { + &Delimiter((caller(0))[3]); + my $string_ref = shift; + + $$string_ref =~ s/\x{251c}\x{255d}/ue/ if $$string_ref =~ /\x{251c}\x{255d}/; + $$string_ref =~ s/\x{251c}\x{2562}/oe/ if $$string_ref =~ /\x{251c}\x{2562}/; + $$string_ref =~ s/\x{251c}\x{f1}/ae/ if $$string_ref =~ /\x{251c}\x{f1}/; + $$string_ref =~ s/\x{251c}\x{cd}/a/ if $$string_ref =~ /\x{251c}\x{cd}/; + + $$string_ref = uc($$string_ref); +} + +sub fix_encoding() { + my $string = shift; + return decode('utf-8', encode('cp850', $string)); +} + +sub parseXML { + &Delimiter((caller(0))[3]); + + # EVENT + $DATA{'COMPILED'}{'EVENT'}{'ID'} = $DATA{'DOM'}->findvalue('//event/@id'); + $DATA{'COMPILED'}{'EVENT'}{'CODE'} = $DATA{'DOM'}->findvalue('//event/@code'); + $DATA{'COMPILED'}{'EVENT'}{'DESC'} = $DATA{'DOM'}->findvalue('//event/@desc'); + # $DATA{'COMPILED'}{'EVENT'}{'DESC'} = &fix_encoding($DATA{'COMPILED'}{'EVENT'}{'DESC'}); + + # &substituteUmlauts(\$DATA{'COMPILED'}{'EVENT'}{'DESC'}); + $DATA{'COMPILED'}{'EVENT'}{'PUBLIC_DESC'} = $DATA{'DOM'}->findvalue('//event/@public_desc'); + # &substituteUmlauts(\$DATA{'COMPILED'}{'EVENT'}{'PUBLIC_DESC'}); + $DATA{'COMPILED'}{'EVENT'}{'YEAR'} = $DATA{'DOM'}->findvalue('//event/@year'); + $DATA{'COMPILED'}{'EVENT'}{'MONTH'} = $DATA{'DOM'}->findvalue('//event/@month'); + $DATA{'COMPILED'}{'EVENT'}{'DAY'} = $DATA{'DOM'}->findvalue('//event/@day'); + $DATA{'COMPILED'}{'EVENT'}{'HOUR'} = $DATA{'DOM'}->findvalue('//event/@hour'); + $DATA{'COMPILED'}{'EVENT'}{'MINUTE'} = $DATA{'DOM'}->findvalue('//event/@minute'); + $DATA{'COMPILED'}{'EVENT'}{'DATETIME_DE'} = "$DATA{'COMPILED'}{'EVENT'}{'DAY'}.$DATA{'COMPILED'}{'EVENT'}{'MONTH'}.$DATA{'COMPILED'}{'EVENT'}{'YEAR'} $DATA{'COMPILED'}{'EVENT'}{'HOUR'}:$DATA{'COMPILED'}{'EVENT'}{'MINUTE'}"; + + # VENUE + $DATA{'COMPILED'}{'VENUE'}{'CODE'} = $DATA{'DOM'}->findvalue('//venue/@code'); + $DATA{'COMPILED'}{'VENUE'}{'DESC'} = $DATA{'DOM'}->findvalue('//venue/@desc'); + $DATA{'COMPILED'}{'VENUE'}{'NAME'} = $DATA{'DOM'}->findvalue('//venue/@name'); + $DATA{'COMPILED'}{'VENUE'}{'ID'} = $DATA{'DOM'}->findvalue('//venue/@id'); + + # VENUE PRICESCALES + foreach my $node ($DATA{'DOM'}->findnodes('//pricescales/pricescale')) { + my $id = $node->findvalue('@id'); + $DATA{'COMPILED'}{'VENUE'}{'PRICESCALES'}{$id}{'ID'} = $id; + $DATA{'COMPILED'}{'VENUE'}{'PRICESCALES'}{$id}{'CODE'} = $node->findvalue('@code'); + $DATA{'COMPILED'}{'VENUE'}{'PRICESCALES'}{$id}{'COLOR'} = $node->findvalue('@color'); + $DATA{'COMPILED'}{'VENUE'}{'PRICESCALES'}{$id}{'DESC'} = $node->findvalue('@desc'); + } + + # VENUE BUYER TYPES + foreach my $node ($DATA{'DOM'}->findnodes('//buyer_types/buyer_type')) { + my $id = $node->findvalue('@id'); + $DATA{'COMPILED'}{'VENUE'}{'BUYER_TYPES'}{$id}{'ID'} = $id; + $DATA{'COMPILED'}{'VENUE'}{'BUYER_TYPES'}{$id}{'CODE'} = $node->findvalue('@code'); + $DATA{'COMPILED'}{'VENUE'}{'BUYER_TYPES'}{$id}{'DESC'} = uc($node->findvalue('@desc')); + # &substituteUmlauts(\$DATA{'COMPILED'}{'VENUE'}{'BUYER_TYPES'}{$id}{'DESC'}); + $DATA{'COMPILED'}{'VENUE'}{'BUYER_TYPES'}{$id}{'DISPLAY_INDICATOR'} = uc($node->findvalue('@desc')); + # &substituteUmlauts(\$DATA{'COMPILED'}{'VENUE'}{'BUYER_TYPES'}{$id}{'DISPLAY_INDICATOR'}); + } + + # MASTER CONFIG TO VENUE + $DATA{'COMPILED'}{'VENUE'}{'CAPACITY'} = $DATA{'DOM'}->findvalue('//master_config/@capacity'); + + # MASTER SECTION CONFIG + foreach my $node ($DATA{'DOM'}->findnodes('//master_config/section_config/section')) { + my $id = $node->findvalue('@id'); + $DATA{'COMPILED'}{'VENUE'}{'SECTION_CONFIG'}{$id}{'ID'} = $id; + $DATA{'COMPILED'}{'VENUE'}{'SECTION_CONFIG'}{$id}{'CODE'} = $node->findvalue('@code'); + $DATA{'COMPILED'}{'VENUE'}{'SECTION_CONFIG'}{$id}{'DESC'} = $node->findvalue('@desc'); + } + + # PRICE_STRUCTURE PRICESCALE + foreach my $node ($DATA{'DOM'}->findnodes('//price_structure/pricescale')) { + my $id = $node->findvalue('@id'); + + $DATA{'COMPILED'}{'VENUE'}{'PRICESCALES'}{$id}{'CURRENCY'} = $node->findvalue('@currency'); + $DATA{'COMPILED'}{'VENUE'}{'PRICESCALES'}{$id}{'PRICES'}{'REF_PRICE'} = $node->findvalue('@ref_price'); + + # BUYER TYPES + foreach my $node_buyer ($node->findnodes('./buyer_type')) { + my $id2 = $node_buyer->findvalue('@id'); + my $desc = $DATA{'COMPILED'}{'VENUE'}{'BUYER_TYPES'}{$id2}{'DESC'}; + my $price = $node_buyer->findvalue('@price'); + $DATA{'COMPILED'}{'VENUE'}{'PRICESCALES'}{$id}{'PRICES'}{$desc} = $price; + } + } + + # SEATMAP_CONFIG + foreach my $node ($DATA{'DOM'}->findnodes('//seatmap_config/seatmap')) { + my $id = $node->findvalue('@id'); + + $DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'ID'} = $id; + $DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'CODE'} = $node->findvalue('@code'); + $DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'DESC'} = $node->findvalue('@desc'); + $DATA{'COMPILED'}{'VENUE'}{'SEATMAP_CONFIG'}{$id}{'HOTSPOT_COORDS'} = $node->findvalue('@hotspot_coords'); + } + + # MASTER SECTION INVENTORY + foreach my $node ($DATA{'DOM'}->findnodes('//master_config/section_inventory/section')) { + my $id = $node->findvalue('@id'); + + $DATA{'COMPILED'}{'VENUE'}{'SECTION_CONFIG'}{$id}{'CAPACITY'} = $node->findvalue('@capacity'); + + # PRICESCALE + my $still_available = 0; + foreach my $node_pricescale ($node->findnodes('./pricescale')) { + my $id2 = $node_pricescale->findvalue('@id'); + my $available = $node_pricescale->findvalue('@available'); + $still_available += $available; + + my $price = $DATA{'COMPILED'}{'VENUE'}{'PRICESCALES'}{$id2}{'PRICES'}{'REF_PRICE'}; + my $code = $DATA{'COMPILED'}{'VENUE'}{'PRICESCALES'}{$id2}{'CODE'}; + + + $DATA{'COMPILED'}{'VENUE'}{'SECTION_CONFIG'}{$id}{'AVAILABLILITY'}{$code}{'PRICE'} = $price; + $DATA{'COMPILED'}{'VENUE'}{'SECTION_CONFIG'}{$id}{'AVAILABLILITY'}{$code}{'AVAILABLE'} = $available; + } + $DATA{'COMPILED'}{'VENUE'}{'SECTION_CONFIG'}{$id}{'STILL_AVAILABLE'} = $still_available; + } +} + +sub loadXML { + &Delimiter((caller(0))[3]); + my ($xml, $DATA_ref) = @_; + + # DELETE IF DOM ALREADY PRESENT + if (ref($$DATA_ref) eq 'XML::LibXML::Document') { + print 'DELETING EXISTING ' . ref($$DATA_ref) . "\n" if $CONFIG{'DEBUG'}; + $$DATA_ref = (); + } + + if (!$CONFIG{'ONLINE'}) { + print "LOADING $xml...\n" if $CONFIG{'DEBUG'}; + $$DATA_ref = eval { XML::LibXML->load_xml(location => $xml) } or die "DIE: XML LOADING ERROR\n" . $@; + } + elsif ($CONFIG{'ONLINE'}) { + print "LOADING XML...\n" if $CONFIG{'DEBUG'}; + $$DATA_ref = eval { XML::LibXML->load_xml(string => $xml) } or die "DIE: XML LOADING ERROR\n" . $@; + # $$DATA_ref = eval { decode('utf-8', encode('cp850', XML::LibXML->load_xml(string => $xml) ) ) } or die "DIE: XML LOADING ERROR\n" . $@; + } +} + +sub getParameter { + &Delimiter((caller(0))[3]); + return if !$CONFIG{'ONLINE'}; + + my $url = $ENV{QUERY_STRING}; + my $decoded = uri_decode($url); + my $uri = URI->new($decoded); + %{$DATA{'PARAMETER'}} = $uri->query_form; + $DATA{'PARAMETER'}{'url'} = url_param('url'); +} + +sub get { + &Delimiter((caller(0))[3]); + my $url = shift; + + if ($CONFIG{'ONLINE'}) { + print "GET:\n$url\n" if $CONFIG{'DEBUG'}; + + my $response = $ua->get($url); + print 'STATUS_LINE: ' . $response->status_line . "\n" if $CONFIG{'DEBUG'}; + if ($response->is_success) { + return $response->decoded_content; + } + else { + $response->code(); + $response->message(); + $response->status_line(); + } + } + elsif (!$CONFIG{'ONLINE'}) { + print "SET AS OFFLINE: USING LOCAL XML\n" if $CONFIG{'DEBUG'}; + } + +} + +sub Delimiter { + my $SubName = shift; + print "\n" . "\n> SUB " . $SubName . "\n" . '-' x 80 . "\n" if $CONFIG{'DEBUG'}; + #print "\n" . "-" x 80 . "\nSUB " . $SubName . "\n" . '-' x 80 . "\n"; +} + +exit; \ No newline at end of file