PageSourceSearch

https://www.tourney.nz/views/pitch.js

js tourney.nz collected 2026-10-02 02:03:28 UTC 11,275 bytes, 294 lines download raw bytes

1import {gameEditor} from '/views/gameEditor.js';
2import {textEditor} from '/views/textEditor.js';
3import {searchMixin} from '/mixins/searchMixin.js';
4
5export const pitch = {
6  mixins: [searchMixin],
7  template: `
8<div class="flexrow">
9  <div v-if="pitch.gameTimes" class="fixedleft flexrow pitch" style="z-index: 1000">    
10    <div class="card">      
11      <div class="cardheader"></div>
12      <table id="game-times" class="selectable">
13        <thead>
14          <tr><th>Time</th></tr>
15        </thead>
16        <tbody>
17          <template v-if="maxGameCount() > 0">
18            <template v-for="(value, index) in maxGameCount()">
19              <tr v-on:click="selectGame($event)" v-on:mouseover="hoverGame($event)" v-on:mouseout="hoverGame(null)" :style="getTimeCellStyle(index, $root.$data.searchText)">  
20                <td><template v-if="pitch.gameTimes && pitch.gameTimes.length > index">{{ pitch.gameTimes[index] }}</template></td>
21              </tr>
22            </template>
23          </template>
24        </tbody>    
25      </table>
26    </div>
27  </div>
28  <div class="pitch card">
29    <div class="cardheader flexrow flexcenter">
30      <h3>{{ pitch.name }}</h3>
31      <div v-if="tournament.canEdit" class="dropdown">      
32        <svg v-on:click="localShowDropdown($event, 'pitchDropdown' + pitch.id.value)" class="dropdown-button"><use xlink:href="/html/icons.svg/#menu"></use></svg>
33        <div :id="'pitchDropdown' + pitch.id.value" class="dropdown-content">        
34          <a v-on:click="pasteGames">Paste Games</a>        
35          <a v-on:click="editName">Edit Name</a>
36          <a v-on:click="pasteGameTimes">Paste Game Times</a>        
37          <a v-on:click="clearGameTimes">Clear Game Times</a>
38          <div class="dropdown-text">Only add game times if different from main times.</div>        
39        </div>
40      </div>
41    </div>
42    <div>    
43      <table id="games" class="selectable">
44        <thead>
45          <tr>
46            <th>Group</th>
47            <th>Team 1</th>
48            <th></th>    
49            <th>Team 2</th>          
50            <th>Duty</th>
51            <td v-if="tournament.canEdit"></td>
52          </tr>
53        </thead>
54        <tbody>
55          <template v-if="maxGameCount() > 0">
56            <template v-for="(value, index) in maxGameCount()">
57              <template v-for="game in [pitch.games[index]]">                                  
58                <tr v-on:click="selectGame($event)" v-on:mouseover="hoverGame($event)" v-on:mouseout="hoverGame(null)" v-on:dblclick="editGame(pitch, game)" :style="getRowStyle(index, $root.$data.searchText)">
59                  <template v-if="game">         
60                    <td :style="getCellStyle(game.group, $root.$data.searchText)">{{ game.group }}</td>
61                    <td :style="getCellStyle(game.team1, $root.$data.searchText)">{{ game.team1 }}</td>                  
62                    <td class="score-cell" v-on:click="editGame(pitch, game)">
63                      <div class="score-content flexrow flexcenter">
64                        <template v-if="game.status !== 'pending' && game.team1 && game.team2">
65                          <div :class="{ scoreactive: game.status === 'active', scorewin: game.status === 'complete' && game.team1Score > game.team2Score, scoredraw: game.status === 'complete' && game.team1Score === game.team2Score, scorelose: game.status === 'complete' && game.team1Score < game.team2Score }">{{ game.team1Score }}</div>
66                          <div :class="{ scoreactive: game.status === 'active' }">&nbsp;-&nbsp;</div>
67                          <div :class="{ scoreactive: game.status === 'active', scorewin: game.status === 'complete' && game.team2Score > game.team1Score, scoredraw: game.status === 'complete' && game.team2Score === game.team1Score, scorelose: game.status === 'complete' && game.team2Score < game.team1Score }">{{ game.team2Score }}</div>                    
68                        </template>
69                      </div>
70                    </td>
71                    <td :style="getCellStyle(game.team2, $root.$data.searchText)">{{ game.team2 }}</td>
72                    <td :style="getCellStyle(game.dutyTeam, $root.$data.searchText)">{{ game.dutyTeam }}</td>
73                    <td v-if="tournament.canEdit">
74                      <svg v-on:click="editGame(pitch, game)" class="edit-button"><use xlink:href="/html/icons.svg/#edit-circle"></use></svg>                                          
75                    </td>
76                  </template>
77                  <template v-else>
78                    <td colspan="5"></td>
79                  </template>            
80                </tr>
81              </template>
82            </template> 
83          </template>
84        </tbody>    
85      </table>
86    </div>  
87  </div>
88</div>
89`,
90  props: ['tournament', 'gameDate', 'pitch', 'searchText'],
91  data () {
92    return {
93      loading: false,
94    }
95  },
96  created () {
97    
98  },
99  methods:
100  {
101    refresh: function() {
102      this.$parent.refresh();
103    },
104    sendData: function(route, data, refresh) {
105      var _this = this
106      if (_this.pitch != undefined)
107      {
108        fetch('/data/tournament/' + _this.tournament.id.value + '/date/' + _this.gameDate.id.value + '/pitch/' + _this.pitch.id.value + '/' + route, {
109          method: 'PUT',
110          body: JSON.stringify(data)
111        })
112        .then(function(tournament)
113        {
114          if (refresh)
115          {
116            _this.refresh();
117          }
118        })
119        .catch(function(error) {
120          console.log(error);        
121          alert('Oops. Something went wrong.');
122        });      
123      }
124    },
125    pasteGames: function(pitchId)
126    {
127      navigator.clipboard.readText()
128      .then(clipboardText => {          
129        var data = { 'mode': 'replace', 'clipboardText': clipboardText };
130        this.sendData('paste', data, true);
131      })
132      .catch(error => {
133        alert('Error reading from the clipboard:\n  ' + error.message + '\nCheck the site settings from the url bar.');
134      }); 
135    },
136    pasteGameTimes: function(pitchId)
137    {
138      navigator.clipboard.readText().then(clipboardText => {          
139        var data = { 'clipboardText': clipboardText };
140        this.sendData('pastegametimes', data, true);
141      })
142      .catch(error => {
143        alert('Error reading from the clipboard:\n  ' + error.message + '\nCheck the site settings from the url bar.');
144      }); 
145    },
146    editName: function(pitchId)
147    {
148      if (this.tournament.canEdit) {
149        var _this = this;
150        const instance = Vue.createApp(textEditor, { text: _this.pitch.name
151                , onSave:  function(text) {
152              var data = { 'name': text };
153              _this.sendData('editname', data, true);                
154            }});
155        instance.config.globalProperties.$googleUser = this.$googleUser;
156        instance.config.compilerOptions.whitespace = 'codense'
157        instance.mount('#modal-parent');  
158      }
159    },
160    clearGameTimes: function(pitchId) {
161      navigator.clipboard.readText().then(clipboardText => {                    
162        var data = { };
163        this.sendData('cleargametimes', data, true);
164      })
165      .catch(error => {
166        alert('Error reading from the clipboard:\n  ' + error.message + '\nCheck the site settings from the url bar.');
167      }); 
168    },
169    putGame: function(pitch, game) {
170      var data = { "group": game.group,
171        "team1": game.team1,
172        "team1Score": game.team1Score,
173        "team2": game.team2,
174        "team2Score": game.team2Score,
175        "dutyTeam": game.dutyTeam,
176        "status": game.status
177      };
178      this.sendData('game/' + game.id.value, data, false);
179    },
180    localShowDropdown: function(event, name) {
181      showDropdown(event, name)
182    },
183    maxGameCount: function()
184    {
185      var count = 0
186      if (this.gameDate) {      
187        if (this.gameDate.gameTimes) {
188          count = this.gameDate.gameTimes.length
189        };
190        this.gameDate.pitches.forEach(pitch => {
191          if (pitch.games.length > count) count = pitch.games.length;
192          if (pitch.gameTimes && pitch.gameTimes.length > count) count = pitch.gameTimes.length;
193        });
194      }
195      return count;
196    },
197    selectGame: function(event) {
198      var index = event.currentTarget.rowIndex;      
199      this.gameDate['selectedIndex'] = index - 1;    
200    },
201    hoverGame: function(event) {
202      var index = 0;
203      if (event) index = event.currentTarget.rowIndex;
204      this.gameDate['hoverIndex'] = index - 1;
205    },
206    rowSearchMatches: function(index, searchText) {
207      let result = 0
208      if (searchText) {
209        for (let pitch of this.gameDate.pitches) {
210          let game = pitch.games[index];
211          if (game) {
212            result = result | this.searchMatches(game.group, searchText);
213            result = result | this.searchMatches(game.team1, searchText);
214            result = result | this.searchMatches(game.team2, searchText);
215            result = result | this.searchMatches(game.dutyTeam, searchText);
216          }
217        }
218      }
219      return result;
220    },
221    getRowStyle: function(index, searchText) {
222      if (this.gameDate.hoverIndex == index) {
223        return "background-color: #eeeeff;";
224      }
225      if (this.gameDate.selectedIndex == index) {
226        return "background-color: #eeeeff;";
227      }
228      return "";
229    },
230    getTimeCellStyle: function(index, searchText) {
231      let result = this.rowSearchMatches(index, searchText);      
232      
233      let color = "#ffffff";
234
235      let c1 = "#FDF0CA";
236      let c2 = "#E4CBD6";
237      let c3 = "#D4E5CE";
238      let c4 = "#D4E5F0";
239
240      if (this.gameDate.hoverIndex == index)
241      {
242        color = "#eeeeff 100%";
243      }          
244      else if (result >= 8) {
245        color = c4;
246      }
247      else if ((result & 1) == 1) {
248        color = c1;
249      }
250      else if ((result & 2) == 2) {
251        color = c2;
252      }
253      else if ((result & 4) == 4) {
254        color = c3;
255      }
256      else if (this.gameDate.selectedIndex == index)
257      {
258        color = "#eeeeff 100%";
259      }
260
261      return "background-color: " + color + ";";
262    },
263    getCellStyle: function(text, searchText) {
264      let result = this.searchMatches(text, searchText);
265      if (result > 0) {
266        if ((result & 1) == 1) {
267          return "background-color: #FDF0CA; font-weight: bold;";
268        }
269        if ((result & 2) == 2) {
270          return "background-color: #E4CBD6; font-weight: bold;";
271        }
272        if ((result & 4) == 4) {
273          return "background-color: #D4E5CE; font-weight: bold;";
274        }
275        if (result >= 8) {
276          return "background-color: #D4E5F0; font-weight: bold;";
277        }
278      }
279      return "";
280    },
281    editGame(pitch, game) {    
282      const instance = Vue.createApp(gameEditor, { tournament: this.tournament, gameDate: this.gameDate, pitch: this.pitch, game: game });
283      instance.config.globalProperties.$googleUser = this.$googleUser;
284      instance.config.compilerOptions.whitespace = 'codense'
285      instance.mount('#modal-parent');      
286    },
287    saveGame(pitch, game) {      
288      this.putGame(pitch, game);      
289    },
290    cancelGame(pitch, game) {
291      this.refresh();
292    }
293  }    
294};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.