81
-    {
82
-      "size" : "40x40",
83
-      "idiom" : "ipad",
84
-      "filename" : "AppIcon-40x40@2x-1.png",
85
-      "scale" : "2x"
86
-    },
87
-    {
88
-      "size" : "76x76",
89
-      "idiom" : "ipad",
90
-      "filename" : "AppIcon-76x76@1x.png",
91
-      "scale" : "1x"
92
-    },
93
-    {
94
-      "size" : "76x76",
95
-      "idiom" : "ipad",
96
-      "filename" : "AppIcon-76x76@2x.png",
97
-      "scale" : "2x"
98
-    },
99
-    {
100
-      "size" : "83.5x83.5",
101
-      "idiom" : "ipad",
102
-      "filename" : "AppIcon-83.5x83.5@2x.png",
103
-      "scale" : "2x"
104
-    },
105
-    {
106
-      "size" : "1024x1024",
107
-      "idiom" : "ios-marketing",
108
-      "filename" : "AppIcon-512@2x.png",
109
-      "scale" : "1x"
110
-    }
111
-  ],
112
-  "info" : {
113
-    "version" : 1,
114
-    "author" : "xcode"
115
-  }
116
-}

+ 0 - 6
ios/App/App/Assets.xcassets/Contents.json

@@ -1,6 +0,0 @@
1
-{
2
-  "info" : {
3
-    "version" : 1,
4
-    "author" : "xcode"
5
-  }
6
-}

+ 0 - 23
ios/App/App/Assets.xcassets/Splash.imageset/Contents.json

@@ -1,23 +0,0 @@
1
-{
2
-  "images" : [
3
-    {
4
-      "idiom" : "universal",
5
-      "filename" : "splash-2732x2732-2.png",
6
-      "scale" : "1x"
7
-    },
8
-    {
9
-      "idiom" : "universal",
10
-      "filename" : "splash-2732x2732-1.png",
11
-      "scale" : "2x"
12
-    },
13
-    {
14
-      "idiom" : "universal",
15
-      "filename" : "splash-2732x2732.png",
16
-      "scale" : "3x"
17
-    }
18
-  ],
19
-  "info" : {
20
-    "version" : 1,
21
-    "author" : "xcode"
22
-  }
23
-}

二進制
ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png


二進制
ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png


二進制
ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png


+ 0 - 32
ios/App/App/Base.lproj/LaunchScreen.storyboard

@@ -1,32 +0,0 @@
1
-<?xml version="1.0" encoding="UTF-8"?>
2
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17132" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
3
-    <device id="retina4_7" orientation="portrait" appearance="light"/>
4
-    <dependencies>
5
-        <deployment identifier="iOS"/>
6
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17105"/>
7
-        <capability name="System colors in document resources" minToolsVersion="11.0"/>
8
-        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
9
-    </dependencies>
10
-    <scenes>
11
-        <!--View Controller-->
12
-        <scene sceneID="EHf-IW-A2E">
13
-            <objects>
14
-                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
15
-                    <imageView key="view" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Splash" id="snD-IY-ifK">
16
-                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
17
-                        <autoresizingMask key="autoresizingMask"/>
18
-                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
19
-                    </imageView>
20
-                </viewController>
21
-                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
22
-            </objects>
23
-            <point key="canvasLocation" x="53" y="375"/>
24
-        </scene>
25
-    </scenes>
26
-    <resources>
27
-        <image name="Splash" width="1366" height="1366"/>
28
-        <systemColor name="systemBackgroundColor">
29
-            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
30
-        </systemColor>
31
-    </resources>
32
-</document>

+ 0 - 19
ios/App/App/Base.lproj/Main.storyboard

@@ -1,19 +0,0 @@
1
-<?xml version="1.0" encoding="UTF-8"?>
2
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14111" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
3
-    <device id="retina4_7" orientation="portrait">
4
-        <adaptation id="fullscreen"/>
5
-    </device>
6
-    <dependencies>
7
-        <deployment identifier="iOS"/>
8
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
9
-    </dependencies>
10
-    <scenes>
11
-        <!--Bridge View Controller-->
12
-        <scene sceneID="tne-QT-ifu">
13
-            <objects>
14
-                <viewController id="BYZ-38-t0r" customClass="CAPBridgeViewController" customModule="Capacitor" sceneMemberID="viewController"/>
15
-                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
16
-            </objects>
17
-        </scene>
18
-    </scenes>
19
-</document>

+ 0 - 49
ios/App/App/Info.plist

@@ -1,49 +0,0 @@
1
-<?xml version="1.0" encoding="UTF-8"?>
2
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
-<plist version="1.0">
4
-<dict>
5
-	<key>CFBundleDevelopmentRegion</key>
6
-	<string>en</string>
7
-	<key>CFBundleDisplayName</key>
8
-        <string>ra100</string>
9
-	<key>CFBundleExecutable</key>
10
-	<string>$(EXECUTABLE_NAME)</string>
11
-	<key>CFBundleIdentifier</key>
12
-	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13
-	<key>CFBundleInfoDictionaryVersion</key>
14
-	<string>6.0</string>
15
-	<key>CFBundleName</key>
16
-	<string>$(PRODUCT_NAME)</string>
17
-	<key>CFBundlePackageType</key>
18
-	<string>APPL</string>
19
-	<key>CFBundleShortVersionString</key>
20
-	<string>$(MARKETING_VERSION)</string>
21
-	<key>CFBundleVersion</key>
22
-	<string>$(CURRENT_PROJECT_VERSION)</string>
23
-	<key>LSRequiresIPhoneOS</key>
24
-	<true/>
25
-	<key>UILaunchStoryboardName</key>
26
-	<string>LaunchScreen</string>
27
-	<key>UIMainStoryboardFile</key>
28
-	<string>Main</string>
29
-	<key>UIRequiredDeviceCapabilities</key>
30
-	<array>
31
-		<string>armv7</string>
32
-	</array>
33
-	<key>UISupportedInterfaceOrientations</key>
34
-	<array>
35
-		<string>UIInterfaceOrientationPortrait</string>
36
-		<string>UIInterfaceOrientationLandscapeLeft</string>
37
-		<string>UIInterfaceOrientationLandscapeRight</string>
38
-	</array>
39
-	<key>UISupportedInterfaceOrientations~ipad</key>
40
-	<array>
41
-		<string>UIInterfaceOrientationPortrait</string>
42
-		<string>UIInterfaceOrientationPortraitUpsideDown</string>
43
-		<string>UIInterfaceOrientationLandscapeLeft</string>
44
-		<string>UIInterfaceOrientationLandscapeRight</string>
45
-	</array>
46
-	<key>UIViewControllerBasedStatusBarAppearance</key>
47
-	<true/>
48
-</dict>
49
-</plist>

+ 0 - 27
ios/App/Podfile

@@ -1,27 +0,0 @@
1
-require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'
2
-
3
-platform :ios, '13.0'
4
-use_frameworks!
5
-
6
-# workaround to avoid Xcode caching of Pods that requires
7
-# Product -> Clean Build Folder after new Cordova plugins installed
8
-# Requires CocoaPods 1.6 or newer
9
-install! 'cocoapods', :disable_input_output_paths => true
10
-
11
-def capacitor_pods
12
-  pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
13
-  pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
14
-  pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app'
15
-  pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics'
16
-  pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard'
17
-  pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar'
18
-end
19
-
20
-target 'App' do
21
-  capacitor_pods
22
-  # Add your Pods here
23
-end
24
-
25
-post_install do |installer|
26
-  assertDeploymentTarget(installer)
27
-end

File diff suppressed because it is too large
+ 17023 - 39
package-lock.json


+ 4 - 2
package.json

@@ -20,7 +20,7 @@
20 20
     "@angular/platform-browser-dynamic": "^14.0.0",
21 21
     "@angular/router": "^14.0.0",
22 22
     "@capacitor/app": "4.1.0",
23
-    "@capacitor/core": "4.4.0",
23
+    "@capacitor/core": "^4.4.0",
24 24
     "@capacitor/haptics": "4.0.1",
25 25
     "@capacitor/ios": "4.4.0",
26 26
     "@capacitor/keyboard": "4.0.1",
@@ -32,7 +32,9 @@
32 32
     "@fortawesome/free-solid-svg-icons": "^6.2.0",
33 33
     "@ionic/angular": "^6.1.9",
34 34
     "@ionic/storage-angular": "^3.0.6",
35
+    "cocoapods": "^0.0.0",
35 36
     "ionicons": "^6.0.3",
37
+    "pod-install": "^0.1.38",
36 38
     "rxjs": "~6.6.0",
37 39
     "swiper": "^8.4.4",
38 40
     "tslib": "^2.2.0",
@@ -48,7 +50,7 @@
48 50
     "@angular/compiler": "^14.0.0",
49 51
     "@angular/compiler-cli": "^14.0.0",
50 52
     "@angular/language-service": "^14.0.0",
51
-    "@capacitor/cli": "4.4.0",
53
+    "@capacitor/cli": "^4.4.0",
52 54
     "@ionic/angular-toolkit": "^6.0.0",
53 55
     "@types/jasmine": "~3.6.0",
54 56
     "@types/jasminewd2": "~2.0.3",

+ 2 - 2
src/app/app.component.html

@@ -2,14 +2,14 @@
2 2
   <ion-menu side="start" contentId="content">
3 3
     <ion-header>
4 4
       <ion-toolbar>
5
-        <ion-title class="menu-title">Menu</ion-title>
5
+        <ion-title class="menu-title">Active Radio</ion-title>
6 6
       </ion-toolbar>
7 7
     </ion-header>
8 8
     <ion-content>
9 9
       <ion-list>
10 10
         <ion-menu-toggle auto-hide="true">
11 11
           <ion-item routerLink="/tabs/tab1" routerDirection="forward">
12
-            <ion-label>Tab 1</ion-label>
12
+            <ion-label>Tab 111</ion-label>
13 13
           </ion-item>
14 14
           <ion-item routerLink="/tabs/tab2" routerDirection="forward">
15 15
             <ion-label>Tab 2</ion-label>

+ 15 - 24
src/app/home/home.page.html

@@ -1,9 +1,11 @@
1 1
 <ion-header>
2 2
   <ion-toolbar class="toolbar-bg-color">
3
+    <img src="../../../assets/icon/logo-fm99.png" class="head-img">
3 4
     <ion-buttons slot="end">
4
-      <ion-menu-button></ion-menu-button>
5
+      <ion-menu-button>
6
+        <ion-icon src="../assets/icon/menu-svgrepo-com.svg" color="warning"></ion-icon>
7
+      </ion-menu-button>
5 8
     </ion-buttons>
6
-    <img src="../../../assets/icon/logo-fm99.png" class="head-img">
7 9
   </ion-toolbar>
8 10
 </ion-header>
9 11
 <ion-content>
@@ -27,11 +29,11 @@
27 29
       </ion-col>
28 30
     </ion-row>
29 31
     <ion-row *ngFor="let news of newsdata | slice:0:4">
30
-      <ion-col size="5">        
31
-        <img [src]="news.better_featured_image.source_url" [style.width]="'100%'" /> 
32
+      <ion-col size="5">
33
+        <img [src]="news.better_featured_image.source_url" [style.width]="'100%'" />
32 34
       </ion-col>
33 35
       <ion-col class="ion-align-self-center"><a [routerLink]="['../news-detail' , news.id]"><span
34
-[innerHTML]="news.title.rendered"></span>
36
+            [innerHTML]="news.title.rendered"></span>
35 37
         </a>
36 38
       </ion-col>
37 39
     </ion-row>
@@ -48,26 +50,15 @@
48 50
         <hr>
49 51
       </ion-col>
50 52
     </ion-row>
51
-    <ion-row>
52
-      <ion-col size="5">
53
-        <img src="../../assets/img-static/mqdefault-1.jpg">
54
-      </ion-col>
55
-      <ion-col class="ion-align-self-center">Morning Talk [26-10-2022 l 07:30 - 09:00 น. ]</ion-col>
56
-    </ion-row>
57
-    <ion-row>
58
-      <ion-col size="5">
59
-        <img src="../../assets/img-static/mqdefault-2.jpg">
60
-      </ion-col>
61
-      <ion-col class="ion-align-self-center">Golf Trick [26-10-2022 l 09:00 - 10:00 น.]</ion-col>
62
-    </ion-row>
63
-    <ion-row>
64
-      <ion-col size="5">
65
-        <img src="../../assets/img-static/mqdefault-3.jpg">
66
-      </ion-col>
67
-      <ion-col class="ion-align-self-center">เจาะสนามบอลไทย [ 20-10-2022 l 20:00 - 21:30 น. ]</ion-col>
68
-    </ion-row>
53
+    <div *ngIf="ytalldata">
54
+      <ion-row *ngFor="let ytdata of ytalldata['items']| slice:0:4">
55
+        <ion-col size="5">
56
+          <img [src]="ytdata.snippet.thumbnails.high.url" [style.width]="'100%'" />
57
+        </ion-col>
58
+        <ion-col class="ion-align-self-center"><a href="https://www.youtube.com/watch?v={{ytdata.id.videoId}}"><span [innerHTML]="ytdata.snippet.title"></span></a></ion-col>
59
+      </ion-row>
60
+    </div>
69 61
   </ion-grid>
70
-
71 62
   <ion-grid>
72 63
     <img src="../../../assets/img-static/banner-320x100.jpeg" alt="">
73 64
   </ion-grid>

+ 17 - 10
src/app/home/home.page.ts

@@ -1,8 +1,8 @@
1 1
 import { AfterContentChecked, Component, ViewChild, ViewEncapsulation } from '@angular/core';
2
-import {SwiperComponent} from 'swiper/angular';
2
+import { SwiperComponent } from 'swiper/angular';
3 3
 import { SwiperOptions } from 'swiper';
4
-import SwiperCore, { Pagination,Autoplay,Navigation,Keyboard } from 'swiper';
5
-import { WpdataService} from '../services/wpdata.service';
4
+import SwiperCore, { Pagination, Autoplay, Navigation, Keyboard } from 'swiper';
5
+import { WpdataService } from '../services/wpdata.service';
6 6
 
7 7
 SwiperCore.use([Pagination, Autoplay, Navigation, Keyboard]);
8 8
 @Component({
@@ -13,12 +13,13 @@ SwiperCore.use([Pagination, Autoplay, Navigation, Keyboard]);
13 13
 })
14 14
 export class HomePage implements AfterContentChecked {
15 15
 
16
-  newsdata: any = [];
17
-  
16
+  newsdata: any;
17
+  ytalldata: any;
18
+
18 19
   @ViewChild('swiper') swiper: SwiperComponent;
19 20
 
20 21
   config: SwiperOptions = {
21
-    slidesPerView: 1,  
22
+    slidesPerView: 1,
22 23
     pagination: { clickable: true },
23 24
     autoplay: {
24 25
       delay: 200,
@@ -28,20 +29,26 @@ export class HomePage implements AfterContentChecked {
28 29
     navigation: true,
29 30
   }
30 31
 
31
-  constructor( private wpgetdataService : WpdataService) {}
32
+  constructor(private wpgetdataService: WpdataService) { }
32 33
 
33 34
   ngAfterContentChecked() {
34 35
     if (this.swiper) {
35 36
       this.swiper.updateSwiper({});
36
-    }    
37
+    }
37 38
   }
38 39
 
39 40
   ionViewWillEnter() {
40 41
     this.wpgetdataService.getAllNews().subscribe((data) => {
41 42
       this.newsdata = data;
42
-      console.log('load Lineup Data');
43
+      console.log('load News Data');
43 44
       console.log(this.newsdata);
44
-      });
45
+    });
46
+
47
+    this.wpgetdataService.getAllYoutube().subscribe((data) => {
48
+      this.ytalldata = data;
49
+      console.log('load YouTube');
50
+      console.log(this.ytalldata);
51
+    });
45 52
   }
46 53
 
47 54
 }

+ 4 - 3
src/app/news-detail/news-detail.page.html

@@ -1,12 +1,13 @@
1 1
 <ion-header>
2 2
   <ion-toolbar class="toolbar-bg-color">
3
+    <img src="../../../assets/icon/logo-fm99.png" class="head-img">
3 4
     <ion-buttons slot="end">
4
-      <ion-menu-button></ion-menu-button>
5
+      <ion-menu-button>
6
+        <ion-icon src="../assets/icon/menu-svgrepo-com.svg" color="warning"></ion-icon>
7
+      </ion-menu-button>
5 8
     </ion-buttons>
6
-    <img src="../../../assets/icon/logo-fm99.png" class="head-img">
7 9
   </ion-toolbar>
8 10
 </ion-header>
9
-
10 11
 <ion-content>
11 12
   <ion-grid>
12 13
     <ion-row>

+ 4 - 3
src/app/news/news.page.html

@@ -1,12 +1,13 @@
1 1
 <ion-header>
2 2
   <ion-toolbar class="toolbar-bg-color">
3
+    <img src="../../../assets/icon/logo-fm99.png" class="head-img">
3 4
     <ion-buttons slot="end">
4
-      <ion-menu-button></ion-menu-button>
5
+      <ion-menu-button>
6
+        <ion-icon src="../assets/icon/menu-svgrepo-com.svg" color="warning"></ion-icon>
7
+      </ion-menu-button>
5 8
     </ion-buttons>
6
-    <img src="../../../assets/icon/logo-fm99.png" class="head-img">
7 9
   </ion-toolbar>
8 10
 </ion-header>
9
-
10 11
 <ion-content>
11 12
   <ion-grid>
12 13
     <ion-row>

+ 10 - 3
src/app/services/wpdata.service.ts

@@ -9,7 +9,7 @@ import { Storage } from '@ionic/storage-angular';
9 9
 })
10 10
 export class WpdataService {
11 11
 
12
-  constructor(private http:HttpClient) { }
12
+  constructor(private http: HttpClient) { }
13 13
 
14 14
   // getAllNews() {
15 15
   //   return this.http.get(
@@ -18,13 +18,20 @@ export class WpdataService {
18 18
   // }
19 19
   getAllNews() {
20 20
     return this.http.get(
21
-      "https://dev-web-fm99.mcot.net/wp-json/wp/v2/news?_embed"
21
+      "https://fm99activeradio.mcot.net/wp-json/wp/v2/news?_embed"
22 22
     );
23 23
   }
24 24
 
25 25
   getNewsDetail(id) {
26
-    let url = 'https://dev-web-fm99.mcot.net/'
26
+    let url = 'https://fm99activeradio.mcot.net/'
27 27
     const route = url + 'wp-json/wp/v2/' + 'news/' + id + '?_embed';
28 28
     return this.http.get(route);
29 29
   }
30
+
31
+  getAllYoutube() {
32
+    return this.http.get(
33
+      // "../assets/api/youtube-data.json"
34
+      "https://youtube.googleapis.com/youtube/v3/search?part=snippet&channelId=UCfZdHbI3pIN4uselPFzzbOg&maxResults=5&order=date&key=AIzaSyDsRrS_dUxT_3PFaMZIBBdrbl37p_fqrNY"
35
+    );
36
+  }
30 37
 }

+ 4 - 3
src/app/youtube/youtube.page.html

@@ -1,12 +1,13 @@
1 1
 <ion-header>
2 2
   <ion-toolbar class="toolbar-bg-color">
3
+    <img src="../../../assets/icon/logo-fm99.png" class="head-img">
3 4
     <ion-buttons slot="end">
4
-      <ion-menu-button></ion-menu-button>
5
+      <ion-menu-button>
6
+        <ion-icon src="../assets/icon/menu-svgrepo-com.svg" color="warning"></ion-icon>
7
+      </ion-menu-button>
5 8
     </ion-buttons>
6
-    <img src="../../../assets/icon/logo-fm99.png" class="head-img">
7 9
   </ion-toolbar>
8 10
 </ion-header>
9
-
10 11
 <ion-content>
11 12
   <img src="../../../assets/img-static/banner-320x50.jpeg" alt="">
12 13
   <ion-grid>

+ 182 - 0
src/assets/api/youtube-data.json

@@ -0,0 +1,182 @@
1
+{
2
+  "kind": "youtube#searchListResponse",
3
+  "etag": "Epvia07TkaHlHcZzjhjK3NZbv-4",
4
+  "nextPageToken": "CAUQAA",
5
+  "regionCode": "TH",
6
+  "pageInfo": {
7
+    "totalResults": 13399,
8
+    "resultsPerPage": 5
9
+  },
10
+  "items": [
11
+    {
12
+      "kind": "youtube#searchResult",
13
+      "etag": "0Y_VBBo_UMU0M0-e1KA-qJCopgg",
14
+      "id": {
15
+        "kind": "youtube#video",
16
+        "videoId": "JXM0627moMU"
17
+      },
18
+      "snippet": {
19
+        "publishedAt": "2022-11-01T07:06:50Z",
20
+        "channelId": "UCfZdHbI3pIN4uselPFzzbOg",
21
+        "title": "Color Of Life [01-11-2022 I 14:00 - 15:00 น. ]",
22
+        "description": "Color Of Life [01-11-2022 I 14:00 - 15:00 น. ] ดำเนินรายการโดย สมเกียรติ คุณานิธิพงศ์ และแม่ช้อยนางรำ สันติ เศวตวิมล ฟังออนไลน์ได้ที่ ...",
23
+        "thumbnails": {
24
+          "default": {
25
+            "url": "https://i.ytimg.com/vi/JXM0627moMU/default_live.jpg",
26
+            "width": 120,
27
+            "height": 90
28
+          },
29
+          "medium": {
30
+            "url": "https://i.ytimg.com/vi/JXM0627moMU/mqdefault_live.jpg",
31
+            "width": 320,
32
+            "height": 180
33
+          },
34
+          "high": {
35
+            "url": "https://i.ytimg.com/vi/JXM0627moMU/hqdefault_live.jpg",
36
+            "width": 480,
37
+            "height": 360
38
+          }
39
+        },
40
+        "channelTitle": "FM99 ActiveRadio",
41
+        "liveBroadcastContent": "live",
42
+        "publishTime": "2022-11-01T07:06:50Z"
43
+      }
44
+    },
45
+    {
46
+      "kind": "youtube#searchResult",
47
+      "etag": "SGCS0buUo10TEELuyTbUOKVY7Xk",
48
+      "id": {
49
+        "kind": "youtube#video",
50
+        "videoId": "poDF-Bo9vZM"
51
+      },
52
+      "snippet": {
53
+        "publishedAt": "2022-11-01T07:03:56Z",
54
+        "channelId": "UCfZdHbI3pIN4uselPFzzbOg",
55
+        "title": "Motor Intrend  [01-11-2022 l 13:00 - 14:00 น. ]",
56
+        "description": "Motor Intrend [01-11-2022 l 13:00 - 14:00 น. ] ดำเนินรายการโดย เฮียก่ำ สมบูรณ์ และเฮียณัฐ เสตะจันทร์ www.fm99activeradio.com ...",
57
+        "thumbnails": {
58
+          "default": {
59
+            "url": "https://i.ytimg.com/vi/poDF-Bo9vZM/default.jpg",
60
+            "width": 120,
61
+            "height": 90
62
+          },
63
+          "medium": {
64
+            "url": "https://i.ytimg.com/vi/poDF-Bo9vZM/mqdefault.jpg",
65
+            "width": 320,
66
+            "height": 180
67
+          },
68
+          "high": {
69
+            "url": "https://i.ytimg.com/vi/poDF-Bo9vZM/hqdefault.jpg",
70
+            "width": 480,
71
+            "height": 360
72
+          }
73
+        },
74
+        "channelTitle": "FM99 ActiveRadio",
75
+        "liveBroadcastContent": "none",
76
+        "publishTime": "2022-11-01T07:03:56Z"
77
+      }
78
+    },
79
+    {
80
+      "kind": "youtube#searchResult",
81
+      "etag": "nN6VLHMJhxlIBQuBEIcR6Ct9wxs",
82
+      "id": {
83
+        "kind": "youtube#video",
84
+        "videoId": "Znw4acOwB9E"
85
+      },
86
+      "snippet": {
87
+        "publishedAt": "2022-11-01T06:02:47Z",
88
+        "channelId": "UCfZdHbI3pIN4uselPFzzbOg",
89
+        "title": "เกาะกระแสกีฬาไทย  [01-11-2022 l 12:30 - 13:00 น.]",
90
+        "description": "เกาะกระแสกีฬาไทย [01-11-2022 l 12:30 - 13:00 น.] ดำเนินรายการโดย เจ๋ง ทรงศักดิ์ www.fm99activeradio.com ...",
91
+        "thumbnails": {
92
+          "default": {
93
+            "url": "https://i.ytimg.com/vi/Znw4acOwB9E/default.jpg",
94
+            "width": 120,
95
+            "height": 90
96
+          },
97
+          "medium": {
98
+            "url": "https://i.ytimg.com/vi/Znw4acOwB9E/mqdefault.jpg",
99
+            "width": 320,
100
+            "height": 180
101
+          },
102
+          "high": {
103
+            "url": "https://i.ytimg.com/vi/Znw4acOwB9E/hqdefault.jpg",
104
+            "width": 480,
105
+            "height": 360
106
+          }
107
+        },
108
+        "channelTitle": "FM99 ActiveRadio",
109
+        "liveBroadcastContent": "none",
110
+        "publishTime": "2022-11-01T06:02:47Z"
111
+      }
112
+    },
113
+    {
114
+      "kind": "youtube#searchResult",
115
+      "etag": "yOpIXnqHzU92tD1PpDzKDgL8D0s",
116
+      "id": {
117
+        "kind": "youtube#video",
118
+        "videoId": "Yo7xp1OEbHU"
119
+      },
120
+      "snippet": {
121
+        "publishedAt": "2022-11-01T05:05:30Z",
122
+        "channelId": "UCfZdHbI3pIN4uselPFzzbOg",
123
+        "title": "MSM Action [01-11-2022 I 11:00 - 12:00 น.]",
124
+        "description": "MSM Action [01-11-2022 I 11:00 - 12:00 น.] ดำเนินรายการโดย เปอ นพฤทธิ์ เก่ง มนต์ชัยและจีน viewfinder ฟังออนไลน์ได้ที่ ...",
125
+        "thumbnails": {
126
+          "default": {
127
+            "url": "https://i.ytimg.com/vi/Yo7xp1OEbHU/default.jpg",
128
+            "width": 120,
129
+            "height": 90
130
+          },
131
+          "medium": {
132
+            "url": "https://i.ytimg.com/vi/Yo7xp1OEbHU/mqdefault.jpg",
133
+            "width": 320,
134
+            "height": 180
135
+          },
136
+          "high": {
137
+            "url": "https://i.ytimg.com/vi/Yo7xp1OEbHU/hqdefault.jpg",
138
+            "width": 480,
139
+            "height": 360
140
+          }
141
+        },
142
+        "channelTitle": "FM99 ActiveRadio",
143
+        "liveBroadcastContent": "none",
144
+        "publishTime": "2022-11-01T05:05:30Z"
145
+      }
146
+    },
147
+    {
148
+      "kind": "youtube#searchResult",
149
+      "etag": "rg3juQB2wGg76UkOvxrG078ueN4",
150
+      "id": {
151
+        "kind": "youtube#video",
152
+        "videoId": "7vCjUyqoI2Q"
153
+      },
154
+      "snippet": {
155
+        "publishedAt": "2022-11-01T04:03:58Z",
156
+        "channelId": "UCfZdHbI3pIN4uselPFzzbOg",
157
+        "title": "Active Entertain   [01-11-2022 l 09:00 - 10:00 น.]",
158
+        "description": "Active Entertain [01-11-2022 l 09:00 - 10:00 น.] ดำเนินรายการโดย พัตโตะและกีรติ ฟังออนไลน์ได้ที่ www.fm99activeradio.com ...",
159
+        "thumbnails": {
160
+          "default": {
161
+            "url": "https://i.ytimg.com/vi/7vCjUyqoI2Q/default.jpg",
162
+            "width": 120,
163
+            "height": 90
164
+          },
165
+          "medium": {
166
+            "url": "https://i.ytimg.com/vi/7vCjUyqoI2Q/mqdefault.jpg",
167
+            "width": 320,
168
+            "height": 180
169
+          },
170
+          "high": {
171
+            "url": "https://i.ytimg.com/vi/7vCjUyqoI2Q/hqdefault.jpg",
172
+            "width": 480,
173
+            "height": 360
174
+          }
175
+        },
176
+        "channelTitle": "FM99 ActiveRadio",
177
+        "liveBroadcastContent": "none",
178
+        "publishTime": "2022-11-01T04:03:58Z"
179
+      }
180
+    }
181
+  ]
182
+}

+ 1 - 0
src/assets/icon/menu-alt-left-svgrepo-com.svg

@@ -0,0 +1 @@
1
+<svg width="24px" height="24px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M4 11h12v2H4zm0-5h16v2H4zm0 12h7.235v-2H4z"/></svg>

+ 1 - 0
src/assets/icon/menu-svgrepo-com.svg

@@ -0,0 +1 @@
1
+<svg width="24px" height="24px" viewBox="-5 -7 24 24" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin" class="jam jam-menu"><path d='M1 0h5a1 1 0 1 1 0 2H1a1 1 0 1 1 0-2zm7 8h5a1 1 0 0 1 0 2H8a1 1 0 1 1 0-2zM1 4h12a1 1 0 0 1 0 2H1a1 1 0 1 1 0-2z' /></svg>

+ 6 - 1
src/global.scss

@@ -79,6 +79,11 @@
79 79
 }
80 80
 
81 81
 
82
+// ion-menu-button {
83
+//   --background: rgb(221, 221, 222);
84
+//   --color: darkorange;
85
+// }
86
+
82 87
 ion-content {
83 88
   // --ion-background-color: #111D12;
84 89
   --background: url('./assets/img-static/bg-content-min.jpg') no-repeat 
@@ -110,7 +115,7 @@ h3 {
110 115
 }
111 116
 
112 117
 .head-img {
113
-  width: 15%;
118
+  width: 18%;
114 119
   display: flex;
115 120
   margin-left: 10px;
116 121
   margin-top: 5px;

二進制
www/IBMPlexSansThai-Regular.ttf


二進制
www/IBMPlexSansThai-SemiBold.ttf


二進制
www/K2D-Light.ttf


二進制
www/Montserrat-Medium.ttf


二進制
www/Prompt-Medium.ttf


二進制
www/Prompt-Regular.ttf


File diff suppressed because it is too large
+ 0 - 3244
www/assets/api/news-api.json


二進制
www/assets/fonts/IBMPlexSansThai-Regular.ttf


二進制
www/assets/fonts/IBMPlexSansThai-SemiBold.ttf


二進制
www/assets/fonts/K2D-Light.ttf


二進制
www/assets/fonts/Montserrat-Medium.ttf


二進制
www/assets/fonts/Montserrat-SemiBold.ttf


二進制
www/assets/fonts/Prompt-Light.ttf


二進制
www/assets/fonts/Prompt-Medium.ttf


二進制
www/assets/fonts/Prompt-Regular.ttf


二進制
www/assets/icon/favicon.png


二進制
www/assets/icon/logo-fm99.png


二進制
www/assets/img-static/SEI129887404-c4a9.jpg


二進制
www/assets/img-static/background_982645-1-min.png


二進制
www/assets/img-static/banner-250x250.jpeg


二進制
www/assets/img-static/banner-320x100.jpeg


二進制
www/assets/img-static/banner-320x50.jpeg


二進制
www/assets/img-static/bg-content-min.jpg


二進制
www/assets/img-static/fb-Ad-1.jpeg


二進制
www/assets/img-static/fb-Ad-2.jpeg


二進制
www/assets/img-static/fb-Ad-3.jpeg


二進制
www/assets/img-static/mqdefault-1.jpg


二進制
www/assets/img-static/mqdefault-2.jpg


二進制
www/assets/img-static/mqdefault-3.jpg


File diff suppressed because it is too large
+ 0 - 1
www/assets/shapes.svg


二進制
www/background_982645-1-min.png


二進制
www/bg-content-min.jpg


File diff suppressed because it is too large
+ 0 - 1329
www/common.js


File diff suppressed because it is too large
+ 0 - 1
www/common.js.map


File diff suppressed because it is too large
+ 0 - 1823
www/default-node_modules_ionic_core_dist_esm_parse-71f28cd7_js-node_modules_ionic_core_dist_esm_t-0c999b.js


File diff suppressed because it is too large
+ 0 - 1
www/default-node_modules_ionic_core_dist_esm_parse-71f28cd7_js-node_modules_ionic_core_dist_esm_t-0c999b.js.map


+ 0 - 26
www/index.html

@@ -1,26 +0,0 @@
1
-<!DOCTYPE html>
2
-<html lang="en">
3
-
4
-<head>
5
-  <meta charset="utf-8"/>
6
-  <title>Ionic App</title>
7
-
8
-  <base href="/"/>
9
-
10
-  <meta name="color-scheme" content="light dark"/>
11
-  <meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
12
-  <meta name="format-detection" content="telephone=no"/>
13
-  <meta name="msapplication-tap-highlight" content="no"/>
14
-
15
-  <link rel="icon" type="image/png" href="assets/icon/favicon.png"/>
16
-
17
-  <!-- add to homescreen for ios -->
18
-  <meta name="apple-mobile-web-app-capable" content="yes"/>
19
-  <meta name="apple-mobile-web-app-status-bar-style" content="black"/>
20
-<link rel="stylesheet" href="styles.css"></head>
21
-
22
-<body>
23
-  <app-root></app-root>
24
-<script src="runtime.js" type="module"></script><script src="polyfills.js" type="module"></script><script src="vendor.js" type="module"></script><script src="main.js" type="module"></script></body>
25
-
26
-</html>

File diff suppressed because it is too large
+ 0 - 501
www/main.js


File diff suppressed because it is too large
+ 0 - 1
www/main.js.map


+ 0 - 239
www/node_modules_ionic_core_dist_esm_index-0bc00b33_js.js

@@ -1,239 +0,0 @@
1
-"use strict";
2
-(self["webpackChunkapp"] = self["webpackChunkapp"] || []).push([["node_modules_ionic_core_dist_esm_index-0bc00b33_js"],{
3
-
4
-/***/ 1612:
5
-/*!*************************************************************!*\
6
-  !*** ./node_modules/@ionic/core/dist/esm/index-0bc00b33.js ***!
7
-  \*************************************************************/
8
-/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
9
-
10
-__webpack_require__.r(__webpack_exports__);
11
-/* harmony export */ __webpack_require__.d(__webpack_exports__, {
12
-/* harmony export */   "startTapClick": () => (/* binding */ startTapClick)
13
-/* harmony export */ });
14
-/* harmony import */ var _helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./helpers-3b390e48.js */ 9234);
15
-/*!
16
- * (C) Ionic http://ionicframework.com - MIT License
17
- */
18
-
19
-
20
-const startTapClick = config => {
21
-  let lastTouch = -MOUSE_WAIT * 10;
22
-  let lastActivated = 0;
23
-  let activatableEle;
24
-  let activeRipple;
25
-  let activeDefer;
26
-  const useRippleEffect = config.getBoolean('animated', true) && config.getBoolean('rippleEffect', true);
27
-  const clearDefers = new WeakMap(); // Touch Events
28
-
29
-  const onTouchStart = ev => {
30
-    lastTouch = (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_0__.u)(ev);
31
-    pointerDown(ev);
32
-  };
33
-
34
-  const onTouchEnd = ev => {
35
-    lastTouch = (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_0__.u)(ev);
36
-    pointerUp(ev);
37
-  };
38
-
39
-  const onMouseDown = ev => {
40
-    // Ignore right clicks
41
-    if (ev.button === 2) {
42
-      return;
43
-    }
44
-
45
-    const t = (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_0__.u)(ev) - MOUSE_WAIT;
46
-
47
-    if (lastTouch < t) {
48
-      pointerDown(ev);
49
-    }
50
-  };
51
-
52
-  const onMouseUp = ev => {
53
-    const t = (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_0__.u)(ev) - MOUSE_WAIT;
54
-
55
-    if (lastTouch < t) {
56
-      pointerUp(ev);
57
-    }
58
-  };
59
-
60
-  const cancelActive = () => {
61
-    clearTimeout(activeDefer);
62
-    activeDefer = undefined;
63
-
64
-    if (activatableEle) {
65
-      removeActivated(false);
66
-      activatableEle = undefined;
67
-    }
68
-  };
69
-
70
-  const pointerDown = ev => {
71
-    if (activatableEle) {
72
-      return;
73
-    }
74
-
75
-    setActivatedElement(getActivatableTarget(ev), ev);
76
-  };
77
-
78
-  const pointerUp = ev => {
79
-    setActivatedElement(undefined, ev);
80
-  };
81
-
82
-  const setActivatedElement = (el, ev) => {
83
-    // do nothing
84
-    if (el && el === activatableEle) {
85
-      return;
86
-    }
87
-
88
-    clearTimeout(activeDefer);
89
-    activeDefer = undefined;
90
-    const {
91
-      x,
92
-      y
93
-    } = (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_0__.p)(ev); // deactivate selected
94
-
95
-    if (activatableEle) {
96
-      if (clearDefers.has(activatableEle)) {
97
-        throw new Error('internal error');
98
-      }
99
-
100
-      if (!activatableEle.classList.contains(ACTIVATED)) {
101
-        addActivated(activatableEle, x, y);
102
-      }
103
-
104
-      removeActivated(true);
105
-    } // activate
106
-
107
-
108
-    if (el) {
109
-      const deferId = clearDefers.get(el);
110
-
111
-      if (deferId) {
112
-        clearTimeout(deferId);
113
-        clearDefers.delete(el);
114
-      }
115
-
116
-      const delay = isInstant(el) ? 0 : ADD_ACTIVATED_DEFERS;
117
-      el.classList.remove(ACTIVATED);
118
-      activeDefer = setTimeout(() => {
119
-        addActivated(el, x, y);
120
-        activeDefer = undefined;
121
-      }, delay);
122
-    }
123
-
124
-    activatableEle = el;
125
-  };
126
-
127
-  const addActivated = (el, x, y) => {
128
-    lastActivated = Date.now();
129
-    el.classList.add(ACTIVATED);
130
-    if (!useRippleEffect) return;
131
-    const rippleEffect = getRippleEffect(el);
132
-
133
-    if (rippleEffect !== null) {
134
-      removeRipple();
135
-      activeRipple = rippleEffect.addRipple(x, y);
136
-    }
137
-  };
138
-
139
-  const removeRipple = () => {
140
-    if (activeRipple !== undefined) {
141
-      activeRipple.then(remove => remove());
142
-      activeRipple = undefined;
143
-    }
144
-  };
145
-
146
-  const removeActivated = smooth => {
147
-    removeRipple();
148
-    const active = activatableEle;
149
-
150
-    if (!active) {
151
-      return;
152
-    }
153
-
154
-    const time = CLEAR_STATE_DEFERS - Date.now() + lastActivated;
155
-
156
-    if (smooth && time > 0 && !isInstant(active)) {
157
-      const deferId = setTimeout(() => {
158
-        active.classList.remove(ACTIVATED);
159
-        clearDefers.delete(active);
160
-      }, CLEAR_STATE_DEFERS);
161
-      clearDefers.set(active, deferId);
162
-    } else {
163
-      active.classList.remove(ACTIVATED);
164
-    }
165
-  };
166
-
167
-  const doc = document;
168
-  doc.addEventListener('ionGestureCaptured', cancelActive);
169
-  doc.addEventListener('touchstart', onTouchStart, true);
170
-  doc.addEventListener('touchcancel', onTouchEnd, true);
171
-  doc.addEventListener('touchend', onTouchEnd, true);
172
-  /**
173
-   * Tap click effects such as the ripple effect should
174
-   * not happen when scrolling. For example, if a user scrolls
175
-   * the page but also happens to do a touchstart on a button
176
-   * as part of the scroll, the ripple effect should not
177
-   * be dispatched. The ripple effect should only happen
178
-   * if the button is activated and the page is not scrolling.
179
-   *
180
-   * pointercancel is dispatched on a gesture when scrolling
181
-   * starts, so this lets us avoid having to listen for
182
-   * ion-content's scroll events.
183
-   */
184
-
185
-  doc.addEventListener('pointercancel', cancelActive, true);
186
-  doc.addEventListener('mousedown', onMouseDown, true);
187
-  doc.addEventListener('mouseup', onMouseUp, true);
188
-};
189
-
190
-const getActivatableTarget = ev => {
191
-  if (ev.composedPath !== undefined) {
192
-    /**
193
-     * composedPath returns EventTarget[]. However,
194
-     * objects other than Element can be targets too.
195
-     * For example, AudioContext can be a target. In this
196
-     * case, we know that the event is a UIEvent so we
197
-     * can assume that the path will contain either Element
198
-     * or ShadowRoot.
199
-     */
200
-    const path = ev.composedPath();
201
-
202
-    for (let i = 0; i < path.length - 2; i++) {
203
-      const el = path[i];
204
-
205
-      if (!(el instanceof ShadowRoot) && el.classList.contains('ion-activatable')) {
206
-        return el;
207
-      }
208
-    }
209
-  } else {
210
-    return ev.target.closest('.ion-activatable');
211
-  }
212
-};
213
-
214
-const isInstant = el => {
215
-  return el.classList.contains('ion-activatable-instant');
216
-};
217
-
218
-const getRippleEffect = el => {
219
-  if (el.shadowRoot) {
220
-    const ripple = el.shadowRoot.querySelector('ion-ripple-effect');
221
-
222
-    if (ripple) {
223
-      return ripple;
224
-    }
225
-  }
226
-
227
-  return el.querySelector('ion-ripple-effect');
228
-};
229
-
230
-const ACTIVATED = 'ion-activated';
231
-const ADD_ACTIVATED_DEFERS = 200;
232
-const CLEAR_STATE_DEFERS = 200;
233
-const MOUSE_WAIT = 2500;
234
-
235
-
236
-/***/ })
237
-
238
-}]);
239
-//# sourceMappingURL=node_modules_ionic_core_dist_esm_index-0bc00b33_js.js.map

File diff suppressed because it is too large
+ 0 - 1
www/node_modules_ionic_core_dist_esm_index-0bc00b33_js.js.map


+ 0 - 526
www/node_modules_ionic_core_dist_esm_input-shims-6ed8f5a5_js.js

@@ -1,526 +0,0 @@
1
-"use strict";
2
-(self["webpackChunkapp"] = self["webpackChunkapp"] || []).push([["node_modules_ionic_core_dist_esm_input-shims-6ed8f5a5_js"],{
3
-
4
-/***/ 4508:
5
-/*!*******************************************************************!*\
6
-  !*** ./node_modules/@ionic/core/dist/esm/input-shims-6ed8f5a5.js ***!
7
-  \*******************************************************************/
8
-/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
9
-
10
-__webpack_require__.r(__webpack_exports__);
11
-/* harmony export */ __webpack_require__.d(__webpack_exports__, {
12
-/* harmony export */   "startInputShims": () => (/* binding */ startInputShims)
13
-/* harmony export */ });
14
-/* harmony import */ var _Users_simplicoltd_projects_fm99_rev_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 1670);
15
-/* harmony import */ var _index_5d0c8232_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./index-5d0c8232.js */ 3081);
16
-/* harmony import */ var _helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./helpers-3b390e48.js */ 9234);
17
-/* harmony import */ var _index_c4b11676_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./index-c4b11676.js */ 9273);
18
-
19
-
20
-/*!
21
- * (C) Ionic http://ionicframework.com - MIT License
22
- */
23
-
24
-
25
-
26
-const cloneMap = new WeakMap();
27
-
28
-const relocateInput = (componentEl, inputEl, shouldRelocate, inputRelativeY = 0) => {
29
-  if (cloneMap.has(componentEl) === shouldRelocate) {
30
-    return;
31
-  }
32
-
33
-  if (shouldRelocate) {
34
-    addClone(componentEl, inputEl, inputRelativeY);
35
-  } else {
36
-    removeClone(componentEl, inputEl);
37
-  }
38
-};
39
-
40
-const isFocused = input => {
41
-  return input === input.getRootNode().activeElement;
42
-};
43
-
44
-const addClone = (componentEl, inputEl, inputRelativeY) => {
45
-  // this allows for the actual input to receive the focus from
46
-  // the user's touch event, but before it receives focus, it
47
-  // moves the actual input to a location that will not screw
48
-  // up the app's layout, and does not allow the native browser
49
-  // to attempt to scroll the input into place (messing up headers/footers)
50
-  // the cloned input fills the area of where native input should be
51
-  // while the native input fakes out the browser by relocating itself
52
-  // before it receives the actual focus event
53
-  // We hide the focused input (with the visible caret) invisible by making it scale(0),
54
-  const parentEl = inputEl.parentNode; // DOM WRITES
55
-
56
-  const clonedEl = inputEl.cloneNode(false);
57
-  clonedEl.classList.add('cloned-input');
58
-  clonedEl.tabIndex = -1;
59
-  parentEl.appendChild(clonedEl);
60
-  cloneMap.set(componentEl, clonedEl);
61
-  const doc = componentEl.ownerDocument;
62
-  const tx = doc.dir === 'rtl' ? 9999 : -9999;
63
-  componentEl.style.pointerEvents = 'none';
64
-  inputEl.style.transform = `translate3d(${tx}px,${inputRelativeY}px,0) scale(0)`;
65
-};
66
-
67
-const removeClone = (componentEl, inputEl) => {
68
-  const clone = cloneMap.get(componentEl);
69
-
70
-  if (clone) {
71
-    cloneMap.delete(componentEl);
72
-    clone.remove();
73
-  }
74
-
75
-  componentEl.style.pointerEvents = '';
76
-  inputEl.style.transform = '';
77
-};
78
-
79
-const enableHideCaretOnScroll = (componentEl, inputEl, scrollEl) => {
80
-  if (!scrollEl || !inputEl) {
81
-    return () => {
82
-      return;
83
-    };
84
-  }
85
-
86
-  const scrollHideCaret = shouldHideCaret => {
87
-    if (isFocused(inputEl)) {
88
-      relocateInput(componentEl, inputEl, shouldHideCaret);
89
-    }
90
-  };
91
-
92
-  const onBlur = () => relocateInput(componentEl, inputEl, false);
93
-
94
-  const hideCaret = () => scrollHideCaret(true);
95
-
96
-  const showCaret = () => scrollHideCaret(false);
97
-
98
-  (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__.a)(scrollEl, 'ionScrollStart', hideCaret);
99
-  (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__.a)(scrollEl, 'ionScrollEnd', showCaret);
100
-  inputEl.addEventListener('blur', onBlur);
101
-  return () => {
102
-    (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__.b)(scrollEl, 'ionScrollStart', hideCaret);
103
-    (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__.b)(scrollEl, 'ionScrollEnd', showCaret);
104
-    inputEl.addEventListener('ionBlur', onBlur);
105
-  };
106
-};
107
-
108
-const SKIP_SELECTOR = 'input, textarea, [no-blur], [contenteditable]';
109
-
110
-const enableInputBlurring = () => {
111
-  let focused = true;
112
-  let didScroll = false;
113
-  const doc = document;
114
-
115
-  const onScroll = () => {
116
-    didScroll = true;
117
-  };
118
-
119
-  const onFocusin = () => {
120
-    focused = true;
121
-  };
122
-
123
-  const onTouchend = ev => {
124
-    // if app did scroll return early
125
-    if (didScroll) {
126
-      didScroll = false;
127
-      return;
128
-    }
129
-
130
-    const active = doc.activeElement;
131
-
132
-    if (!active) {
133
-      return;
134
-    } // only blur if the active element is a text-input or a textarea
135
-
136
-
137
-    if (active.matches(SKIP_SELECTOR)) {
138
-      return;
139
-    } // if the selected target is the active element, do not blur
140
-
141
-
142
-    const tapped = ev.target;
143
-
144
-    if (tapped === active) {
145
-      return;
146
-    }
147
-
148
-    if (tapped.matches(SKIP_SELECTOR) || tapped.closest(SKIP_SELECTOR)) {
149
-      return;
150
-    }
151
-
152
-    focused = false; // TODO: find a better way, why 50ms?
153
-
154
-    setTimeout(() => {
155
-      if (!focused) {
156
-        active.blur();
157
-      }
158
-    }, 50);
159
-  };
160
-
161
-  (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__.a)(doc, 'ionScrollStart', onScroll);
162
-  doc.addEventListener('focusin', onFocusin, true);
163
-  doc.addEventListener('touchend', onTouchend, false);
164
-  return () => {
165
-    (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__.b)(doc, 'ionScrollStart', onScroll, true);
166
-    doc.removeEventListener('focusin', onFocusin, true);
167
-    doc.removeEventListener('touchend', onTouchend, false);
168
-  };
169
-};
170
-
171
-const SCROLL_ASSIST_SPEED = 0.3;
172
-
173
-const getScrollData = (componentEl, contentEl, keyboardHeight) => {
174
-  var _a;
175
-
176
-  const itemEl = (_a = componentEl.closest('ion-item,[ion-item]')) !== null && _a !== void 0 ? _a : componentEl;
177
-  return calcScrollData(itemEl.getBoundingClientRect(), contentEl.getBoundingClientRect(), keyboardHeight, componentEl.ownerDocument.defaultView.innerHeight);
178
-};
179
-
180
-const calcScrollData = (inputRect, contentRect, keyboardHeight, platformHeight) => {
181
-  // compute input's Y values relative to the body
182
-  const inputTop = inputRect.top;
183
-  const inputBottom = inputRect.bottom; // compute visible area
184
-
185
-  const visibleAreaTop = contentRect.top;
186
-  const visibleAreaBottom = Math.min(contentRect.bottom, platformHeight - keyboardHeight); // compute safe area
187
-
188
-  const safeAreaTop = visibleAreaTop + 15;
189
-  const safeAreaBottom = visibleAreaBottom * 0.75; // figure out if each edge of the input is within the safe area
190
-
191
-  const distanceToBottom = safeAreaBottom - inputBottom;
192
-  const distanceToTop = safeAreaTop - inputTop; // desiredScrollAmount is the negated distance to the safe area according to our calculations.
193
-
194
-  const desiredScrollAmount = Math.round(distanceToBottom < 0 ? -distanceToBottom : distanceToTop > 0 ? -distanceToTop : 0); // our calculations make some assumptions that aren't always true, like the keyboard being closed when an input
195
-  // gets focus, so make sure we don't scroll the input above the visible area
196
-
197
-  const scrollAmount = Math.min(desiredScrollAmount, inputTop - visibleAreaTop);
198
-  const distance = Math.abs(scrollAmount);
199
-  const duration = distance / SCROLL_ASSIST_SPEED;
200
-  const scrollDuration = Math.min(400, Math.max(150, duration));
201
-  return {
202
-    scrollAmount,
203
-    scrollDuration,
204
-    scrollPadding: keyboardHeight,
205
-    inputSafeY: -(inputTop - safeAreaTop) + 4
206
-  };
207
-};
208
-
209
-const enableScrollAssist = (componentEl, inputEl, contentEl, footerEl, keyboardHeight) => {
210
-  let coord;
211
-
212
-  const touchStart = ev => {
213
-    coord = (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__.p)(ev);
214
-  };
215
-
216
-  const touchEnd = ev => {
217
-    // input cover touchend/mouseup
218
-    if (!coord) {
219
-      return;
220
-    } // get where the touchend/mouseup ended
221
-
222
-
223
-    const endCoord = (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__.p)(ev); // focus this input if the pointer hasn't moved XX pixels
224
-    // and the input doesn't already have focus
225
-
226
-    if (!hasPointerMoved(6, coord, endCoord) && !isFocused(inputEl)) {
227
-      // begin the input focus process
228
-      jsSetFocus(componentEl, inputEl, contentEl, footerEl, keyboardHeight);
229
-    }
230
-  };
231
-
232
-  componentEl.addEventListener('touchstart', touchStart, {
233
-    capture: true,
234
-    passive: true
235
-  });
236
-  componentEl.addEventListener('touchend', touchEnd, true);
237
-  return () => {
238
-    componentEl.removeEventListener('touchstart', touchStart, true);
239
-    componentEl.removeEventListener('touchend', touchEnd, true);
240
-  };
241
-};
242
-
243
-const jsSetFocus = /*#__PURE__*/function () {
244
-  var _ref = (0,_Users_simplicoltd_projects_fm99_rev_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (componentEl, inputEl, contentEl, footerEl, keyboardHeight) {
245
-    if (!contentEl && !footerEl) {
246
-      return;
247
-    }
248
-
249
-    const scrollData = getScrollData(componentEl, contentEl || footerEl, keyboardHeight);
250
-
251
-    if (contentEl && Math.abs(scrollData.scrollAmount) < 4) {
252
-      // the text input is in a safe position that doesn't
253
-      // require it to be scrolled into view, just set focus now
254
-      inputEl.focus();
255
-      return;
256
-    } // temporarily move the focus to the focus holder so the browser
257
-    // doesn't freak out while it's trying to get the input in place
258
-    // at this point the native text input still does not have focus
259
-
260
-
261
-    relocateInput(componentEl, inputEl, true, scrollData.inputSafeY);
262
-    inputEl.focus();
263
-    /**
264
-     * Relocating/Focusing input causes the
265
-     * click event to be cancelled, so
266
-     * manually fire one here.
267
-     */
268
-
269
-    (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__.r)(() => componentEl.click());
270
-
271
-    if (typeof window !== 'undefined') {
272
-      let scrollContentTimeout;
273
-
274
-      const scrollContent = /*#__PURE__*/function () {
275
-        var _ref2 = (0,_Users_simplicoltd_projects_fm99_rev_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () {
276
-          // clean up listeners and timeouts
277
-          if (scrollContentTimeout !== undefined) {
278
-            clearTimeout(scrollContentTimeout);
279
-          }
280
-
281
-          window.removeEventListener('ionKeyboardDidShow', doubleKeyboardEventListener);
282
-          window.removeEventListener('ionKeyboardDidShow', scrollContent); // scroll the input into place
283
-
284
-          if (contentEl) {
285
-            yield (0,_index_5d0c8232_js__WEBPACK_IMPORTED_MODULE_1__.c)(contentEl, 0, scrollData.scrollAmount, scrollData.scrollDuration);
286
-          } // the scroll view is in the correct position now
287
-          // give the native text input focus
288
-
289
-
290
-          relocateInput(componentEl, inputEl, false, scrollData.inputSafeY); // ensure this is the focused input
291
-
292
-          inputEl.focus();
293
-        });
294
-
295
-        return function scrollContent() {
296
-          return _ref2.apply(this, arguments);
297
-        };
298
-      }();
299
-
300
-      const doubleKeyboardEventListener = () => {
301
-        window.removeEventListener('ionKeyboardDidShow', doubleKeyboardEventListener);
302
-        window.addEventListener('ionKeyboardDidShow', scrollContent);
303
-      };
304
-
305
-      if (contentEl) {
306
-        const scrollEl = yield (0,_index_5d0c8232_js__WEBPACK_IMPORTED_MODULE_1__.g)(contentEl);
307
-        /**
308
-         * scrollData will only consider the amount we need
309
-         * to scroll in order to properly bring the input
310
-         * into view. It will not consider the amount
311
-         * we can scroll in the content element.
312
-         * As a result, scrollData may request a greater
313
-         * scroll position than is currently available
314
-         * in the DOM. If this is the case, we need to
315
-         * wait for the webview to resize/the keyboard
316
-         * to show in order for additional scroll
317
-         * bandwidth to become available.
318
-         */
319
-
320
-        const totalScrollAmount = scrollEl.scrollHeight - scrollEl.clientHeight;
321
-
322
-        if (scrollData.scrollAmount > totalScrollAmount - scrollEl.scrollTop) {
323
-          /**
324
-           * On iOS devices, the system will show a "Passwords" bar above the keyboard
325
-           * after the initial keyboard is shown. This prevents the webview from resizing
326
-           * until the "Passwords" bar is shown, so we need to wait for that to happen first.
327
-           */
328
-          if (inputEl.type === 'password') {
329
-            // Add 50px to account for the "Passwords" bar
330
-            scrollData.scrollAmount += 50;
331
-            window.addEventListener('ionKeyboardDidShow', doubleKeyboardEventListener);
332
-          } else {
333
-            window.addEventListener('ionKeyboardDidShow', scrollContent);
334
-          }
335
-          /**
336
-           * This should only fire in 2 instances:
337
-           * 1. The app is very slow.
338
-           * 2. The app is running in a browser on an old OS
339
-           * that does not support Ionic Keyboard Events
340
-           */
341
-
342
-
343
-          scrollContentTimeout = setTimeout(scrollContent, 1000);
344
-          return;
345
-        }
346
-      }
347
-
348
-      scrollContent();
349
-    }
350
-  });
351
-
352
-  return function jsSetFocus(_x, _x2, _x3, _x4, _x5) {
353
-    return _ref.apply(this, arguments);
354
-  };
355
-}();
356
-
357
-const hasPointerMoved = (threshold, startCoord, endCoord) => {
358
-  if (startCoord && endCoord) {
359
-    const deltaX = startCoord.x - endCoord.x;
360
-    const deltaY = startCoord.y - endCoord.y;
361
-    const distance = deltaX * deltaX + deltaY * deltaY;
362
-    return distance > threshold * threshold;
363
-  }
364
-
365
-  return false;
366
-};
367
-
368
-const PADDING_TIMER_KEY = '$ionPaddingTimer';
369
-
370
-const enableScrollPadding = keyboardHeight => {
371
-  const doc = document;
372
-
373
-  const onFocusin = ev => {
374
-    setScrollPadding(ev.target, keyboardHeight);
375
-  };
376
-
377
-  const onFocusout = ev => {
378
-    setScrollPadding(ev.target, 0);
379
-  };
380
-
381
-  doc.addEventListener('focusin', onFocusin);
382
-  doc.addEventListener('focusout', onFocusout);
383
-  return () => {
384
-    doc.removeEventListener('focusin', onFocusin);
385
-    doc.removeEventListener('focusout', onFocusout);
386
-  };
387
-};
388
-
389
-const setScrollPadding = (input, keyboardHeight) => {
390
-  var _a, _b;
391
-
392
-  if (input.tagName !== 'INPUT') {
393
-    return;
394
-  }
395
-
396
-  if (input.parentElement && input.parentElement.tagName === 'ION-INPUT') {
397
-    return;
398
-  }
399
-
400
-  if (((_b = (_a = input.parentElement) === null || _a === void 0 ? void 0 : _a.parentElement) === null || _b === void 0 ? void 0 : _b.tagName) === 'ION-SEARCHBAR') {
401
-    return;
402
-  }
403
-
404
-  const el = (0,_index_5d0c8232_js__WEBPACK_IMPORTED_MODULE_1__.f)(input);
405
-
406
-  if (el === null) {
407
-    return;
408
-  }
409
-
410
-  const timer = el[PADDING_TIMER_KEY];
411
-
412
-  if (timer) {
413
-    clearTimeout(timer);
414
-  }
415
-
416
-  if (keyboardHeight > 0) {
417
-    el.style.setProperty('--keyboard-offset', `${keyboardHeight}px`);
418
-  } else {
419
-    el[PADDING_TIMER_KEY] = setTimeout(() => {
420
-      el.style.setProperty('--keyboard-offset', '0px');
421
-    }, 120);
422
-  }
423
-};
424
-
425
-const INPUT_BLURRING = true;
426
-const SCROLL_PADDING = true;
427
-
428
-const startInputShims = config => {
429
-  const doc = document;
430
-  const keyboardHeight = config.getNumber('keyboardHeight', 290);
431
-  const scrollAssist = config.getBoolean('scrollAssist', true);
432
-  const hideCaret = config.getBoolean('hideCaretOnScroll', true);
433
-  const inputBlurring = config.getBoolean('inputBlurring', true);
434
-  const scrollPadding = config.getBoolean('scrollPadding', true);
435
-  const inputs = Array.from(doc.querySelectorAll('ion-input, ion-textarea'));
436
-  const hideCaretMap = new WeakMap();
437
-  const scrollAssistMap = new WeakMap();
438
-
439
-  const registerInput = /*#__PURE__*/function () {
440
-    var _ref3 = (0,_Users_simplicoltd_projects_fm99_rev_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (componentEl) {
441
-      yield new Promise(resolve => (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__.c)(componentEl, resolve));
442
-      const inputRoot = componentEl.shadowRoot || componentEl;
443
-      const inputEl = inputRoot.querySelector('input') || inputRoot.querySelector('textarea');
444
-      const scrollEl = (0,_index_5d0c8232_js__WEBPACK_IMPORTED_MODULE_1__.f)(componentEl);
445
-      const footerEl = !scrollEl ? componentEl.closest('ion-footer') : null;
446
-
447
-      if (!inputEl) {
448
-        return;
449
-      }
450
-
451
-      if (!!scrollEl && hideCaret && !hideCaretMap.has(componentEl)) {
452
-        const rmFn = enableHideCaretOnScroll(componentEl, inputEl, scrollEl);
453
-        hideCaretMap.set(componentEl, rmFn);
454
-      }
455
-      /**
456
-       * date/datetime-locale inputs on mobile devices show date picker
457
-       * overlays instead of keyboards. As a result, scroll assist is
458
-       * not needed. This also works around a bug in iOS <16 where
459
-       * scroll assist causes the browser to lock up. See FW-1997.
460
-       */
461
-
462
-
463
-      const isDateInput = inputEl.type === 'date' || inputEl.type === 'datetime-local';
464
-
465
-      if (!isDateInput && (!!scrollEl || !!footerEl) && scrollAssist && !scrollAssistMap.has(componentEl)) {
466
-        const rmFn = enableScrollAssist(componentEl, inputEl, scrollEl, footerEl, keyboardHeight);
467
-        scrollAssistMap.set(componentEl, rmFn);
468
-      }
469
-    });
470
-
471
-    return function registerInput(_x6) {
472
-      return _ref3.apply(this, arguments);
473
-    };
474
-  }();
475
-
476
-  const unregisterInput = componentEl => {
477
-    if (hideCaret) {
478
-      const fn = hideCaretMap.get(componentEl);
479
-
480
-      if (fn) {
481
-        fn();
482
-      }
483
-
484
-      hideCaretMap.delete(componentEl);
485
-    }
486
-
487
-    if (scrollAssist) {
488
-      const fn = scrollAssistMap.get(componentEl);
489
-
490
-      if (fn) {
491
-        fn();
492
-      }
493
-
494
-      scrollAssistMap.delete(componentEl);
495
-    }
496
-  };
497
-
498
-  if (inputBlurring && INPUT_BLURRING) {
499
-    enableInputBlurring();
500
-  }
501
-
502
-  if (scrollPadding && SCROLL_PADDING) {
503
-    enableScrollPadding(keyboardHeight);
504
-  } // Input might be already loaded in the DOM before ion-device-hacks did.
505
-  // At this point we need to look for all of the inputs not registered yet
506
-  // and register them.
507
-
508
-
509
-  for (const input of inputs) {
510
-    registerInput(input);
511
-  }
512
-
513
-  doc.addEventListener('ionInputDidLoad', ev => {
514
-    registerInput(ev.detail);
515
-  });
516
-  doc.addEventListener('ionInputDidUnload', ev => {
517
-    unregisterInput(ev.detail);
518
-  });
519
-};
520
-
521
-
522
-
523
-/***/ })
524
-
525
-}]);
526
-//# sourceMappingURL=node_modules_ionic_core_dist_esm_input-shims-6ed8f5a5_js.js.map

File diff suppressed because it is too large
+ 0 - 1
www/node_modules_ionic_core_dist_esm_input-shims-6ed8f5a5_js.js.map


File diff suppressed because it is too large
+ 0 - 799
www/node_modules_ionic_core_dist_esm_ion-accordion_2_entry_js.js


File diff suppressed because it is too large
+ 0 - 1
www/node_modules_ionic_core_dist_esm_ion-accordion_2_entry_js.js.map


File diff suppressed because it is too large
+ 0 - 450
www/node_modules_ionic_core_dist_esm_ion-action-sheet_entry_js.js


File diff suppressed because it is too large
+ 0 - 1
www/node_modules_ionic_core_dist_esm_ion-action-sheet_entry_js.js.map


File diff suppressed because it is too large
+ 0 - 780
www/node_modules_ionic_core_dist_esm_ion-alert_entry_js.js


File diff suppressed because it is too large
+ 0 - 1
www/node_modules_ionic_core_dist_esm_ion-alert_entry_js.js.map


File diff suppressed because it is too large
+ 0 - 1726
www/node_modules_ionic_core_dist_esm_ion-app_8_entry_js.js


File diff suppressed because it is too large
+ 0 - 1
www/node_modules_ionic_core_dist_esm_ion-app_8_entry_js.js.map


+ 0 - 0
www/node_modules_ionic_core_dist_esm_ion-avatar_3_entry_js.js


部分文件因文件數量過多而無法顯示

tum/TMTApp - Gogs: Simplico Git Service

Nenhuma Descrição

manifest.webmanifest 970B

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
  1. {
  2. "icons": [
  3. {
  4. "src": "../icons/icon-48.webp",
  5. "type": "image/png",
  6. "sizes": "48x48",
  7. "purpose": "any maskable"
  8. },
  9. {
  10. "src": "../icons/icon-72.webp",
  11. "type": "image/png",
  12. "sizes": "72x72",
  13. "purpose": "any maskable"
  14. },
  15. {
  16. "src": "../icons/icon-96.webp",
  17. "type": "image/png",
  18. "sizes": "96x96",
  19. "purpose": "any maskable"
  20. },
  21. {
  22. "src": "../icons/icon-128.webp",
  23. "type": "image/png",
  24. "sizes": "128x128",
  25. "purpose": "any maskable"
  26. },
  27. {
  28. "src": "../icons/icon-192.webp",
  29. "type": "image/png",
  30. "sizes": "192x192",
  31. "purpose": "any maskable"
  32. },
  33. {
  34. "src": "../icons/icon-256.webp",
  35. "type": "image/png",
  36. "sizes": "256x256",
  37. "purpose": "any maskable"
  38. },
  39. {
  40. "src": "../icons/icon-512.webp",
  41. "type": "image/png",
  42. "sizes": "512x512",
  43. "purpose": "any maskable"
  44. }
  45. ]
  46. }