def show_fixgen_table(tourney_name, module_list, title, description): cgicommon.writeln("<h2>%s</h2>" % (cgicommon.escape(title))) if description: cgicommon.writeln("<p>") cgicommon.writeln(description) cgicommon.writeln("</p>") cgicommon.writeln("<table class=\"fixgentable\">") #cgicommon.writeln("<tr><th class=\"fixgentable fixgenth\"></th><th class=\"fixgentable fixgenth\">Generator</th><th class=\"fixgentable fixgenth\">Description</th></tr>"); for module_name in module_list: fixgen_module = importlib.import_module(module_name) cgicommon.writeln("<tr>") cgicommon.writeln("<td class=\"fixgentable fixgen\">") cgicommon.writeln( "<a href=\"/cgi-bin/fixturegen.py?generator=%s&tourney=%s\">" % (urllib.parse.quote_plus(module_name), urllib.parse.quote_plus(tourney_name))) cgicommon.writeln("<img src=\"/images/fixgen/%s.png\" alt=\"%s\" />" % (cgicommon.escape(module_name), cgicommon.escape(fixgen_module.name))) cgicommon.writeln("</a>") cgicommon.writeln("</td>") cgicommon.writeln("<td class=\"fixgentable fixgen\">") cgicommon.writeln( "<a href=\"/cgi-bin/fixturegen.py?generator=%s&tourney=%s\">%s</a>" % (urllib.parse.quote_plus(module_name), urllib.parse.quote_plus(tourney_name), cgicommon.escape(fixgen_module.name))) cgicommon.writeln("</td>") #cgicommon.writeln("<td class=\"fixgentable fixgenmodule\">%s</td>" % (cgicommon.escape(module_name))); cgicommon.writeln( "<td class=\"fixgentable fixgendescription\">%s</td>" % (cgicommon.escape(fixgen_module.description))) cgicommon.writeln("</tr>") cgicommon.writeln("</table>")
def show_player_drop_down_box(players, control_name): cgicommon.writeln("<select name=\"%s\">" % (control_name)) cgicommon.writeln("<option value=\"\">-- select player --</option>") for p in players: cgicommon.writeln( "<option value=\"%s\">%s (%g)</option>" % (cgicommon.escape( p.name, True), cgicommon.escape(p.name), p.rating)) cgicommon.writeln("</select>")
def show_player_search_form(tourney): cgicommon.writeln("<form method=\"GET\" action=\"%s\">" % (cgicommon.escape(baseurl, True))) cgicommon.writeln("<input type=\"hidden\" name=\"tourney\" value=\"%s\" />" % (cgicommon.escape(tourney.get_name()))) cgicommon.writeln("<p>") cgicommon.writeln("Search player name: <input type=\"text\" name=\"searchname\" value=\"\" /> ") cgicommon.writeln("<input type=\"submit\" name=\"searchsubmit\" value=\"Search\" />") cgicommon.writeln("</p>") cgicommon.writeln("</form>")
def print_tourney_table(tourney_list, destination_page, show_last_modified, show_export_html_link=False, show_display_link=False): cgicommon.writeln("<table class=\"tourneylist\">") cgicommon.writeln("<tr>") cgicommon.writeln( "<th><a href=\"/cgi-bin/home.py?orderby=%s\">Name</a></th>" % ("name_d" if order_by == "name_a" else "name_a")) if show_last_modified: cgicommon.writeln( "<th><a href=\"/cgi-bin/home.py?orderby=%s\">Last modified</a></th>" % ("mtime_a" if order_by == "mtime_d" else "mtime_d")) if show_display_link or show_export_html_link: cgicommon.writeln( "<th colspan=\"%d\">Useful links</th>" % (2 if show_display_link and show_export_html_link else 1)) cgicommon.writeln("</tr>") for tourney_basename in tourney_list: name = tourney_basename[:-3] filename = os.path.join(cgicommon.dbdir, tourney_basename) st = os.stat(filename) modified_time = time.localtime(st.st_mtime) cgicommon.writeln("<tr>") cgicommon.writeln('<td class=\"tourneylistname\">') if destination_page: cgicommon.writeln( '<a href="%s?tourney=%s">%s</a>' % (cgicommon.escape(destination_page, True), urllib.parse.quote_plus(name), cgicommon.escape(name))) else: cgicommon.writeln(cgicommon.escape(name)) cgicommon.writeln('</td>') if show_last_modified: cgicommon.writeln("<td class=\"tourneylistmtime\">%s</td>" % (time.strftime("%d %b %Y %H:%M", modified_time))) if show_export_html_link: cgicommon.writeln("<td class=\"tourneylistlink\">") cgicommon.writeln( "<a href=\"/cgi-bin/export.py?tourney=%s&format=html\">Tourney report</a>" % (urllib.parse.quote_plus(name))) cgicommon.writeln("</td>") if show_display_link: cgicommon.writeln("<td class=\"tourneylistlink\">") cgicommon.writeln( "<a href=\"/cgi-bin/display.py?tourney=%s\">Full screen display</a>" % (urllib.parse.quote_plus(name))) cgicommon.writeln("</td>") cgicommon.writeln("</tr>") cgicommon.writeln("</table>")
def show_division_drop_down_box(control_name, tourney, player): num_divisions = tourney.get_num_divisions() cgicommon.writeln("<select name=\"%s\">" % (cgicommon.escape(control_name, True))) for div in range(num_divisions): cgicommon.writeln("<option value=\"%d\" %s >%s (%d active players)</option>" % (div, "selected" if (player is not None and div == player.get_division()) or (player is None and div == 0) else "", cgicommon.escape(tourney.get_division_name(div)), tourney.get_num_active_players(div))) cgicommon.writeln("</select>")
def include_scripts(dir_name, url_path): for filename in sorted(os.listdir(dir_name)): if (os.path.isdir(dir_name + "/" + filename)): include_scripts(dir_name + "/" + filename, url_path + "/" + filename) elif filename[-3:] == ".js": base_filename = os.path.basename(filename) cgicommon.writeln( "<script src=\"%s/%s\"></script>" % (cgicommon.escape( url_path, True), cgicommon.escape(base_filename, True)))
def show_player_selection(players, control_name, value): cgicommon.writeln("<select name=\"%s\">" % cgicommon.escape(control_name, True)) for p in players: player_name = p.get_name() if player_name == value: sel = " selected" else: sel = "" cgicommon.writeln( "<option value=\"%s\"%s>%s</option>" % (cgicommon.escape( player_name, True), sel, cgicommon.escape(player_name))) cgicommon.writeln("</select>")
def show_player_form(tourney, player): num_divisions = tourney.get_num_divisions() tourneyname = tourney.get_name() if player: player_id = player.get_id() else: player_id = None if player: cgicommon.writeln("<form method=\"POST\" action=\"%s?tourney=%s&id=%d\">" % (cgicommon.escape(baseurl), urllib.parse.quote_plus(tourneyname), player_id)) else: cgicommon.writeln("<form method=\"POST\" action=\"%s?tourney=%s\">" % (cgicommon.escape(baseurl), urllib.parse.quote_plus(tourneyname))) cgicommon.writeln("<table>") cgicommon.writeln("<tr><td>Name</td><td><input type=\"text\" name=\"setname\" value=\"%s\" /></td></tr>" % ("" if not player else cgicommon.escape(player.get_name(), True))) cgicommon.writeln("<tr><td>Rating</td><td><input style=\"width: 5em;\" type=\"text\" name=\"setrating\" value=\"%g\"/>" % (1000 if not player else player.get_rating())) cgicommon.writeln("<span class=\"playercontrolhelp\">(1000 is the default; use 0 to indicate this player is a Prune)</span>") cgicommon.writeln("</td></tr>") if num_divisions > 1: cgicommon.writeln("<tr><td>Division</td>") cgicommon.writeln("<td>") show_division_drop_down_box("setdivision", tourney, player) cgicommon.writeln("</td></tr>") cgicommon.writeln("<tr><td>Withdrawn?</td><td><input type=\"checkbox\" name=\"setwithdrawn\" value=\"1\" %s /> <span class=\"playercontrolhelp\">(if ticked, fixture generators will not include this player)</span></td></tr>" % ("checked" if player and player.is_withdrawn() else "")) cgicommon.writeln("<tr><td>Requires accessible table?</td><td><input type=\"checkbox\" name=\"setrequiresaccessibletable\" value=\"1\" %s /> <span class=\"playercontrolhelp\">(if ticked, fixture generators will place this player and their opponents on an accessible table, as defined in <a href=\"/cgi-bin/tourneysetup.py?tourney=%s\">General Setup</a>)</span></td></tr>" % ( "checked" if player and player.is_requiring_accessible_table() else "", urllib.parse.quote_plus(tourneyname) )) if player is None: pref = None else: pref = player.get_preferred_table() cgicommon.writeln("<tr><td>Preferred table number</td><td><input type=\"text\" name=\"setpreferredtable\" style=\"width: 5em;\" value=\"%s\" /> <span class=\"playercontrolhelp\">(player will be assigned this table number if possible - if blank, player has no specific table preference)</span></td></tr>" % (cgicommon.escape(str(pref)) if pref is not None else "")) cgicommon.writeln("<tr><td>Avoid Prune?</td><td><input type=\"checkbox\" name=\"setavoidprune\" value=\"1\" %s /> <span class=\"playercontrolhelp\">(if ticked, the Swiss fixture generator will behave as if this player has already played a Prune)</span></td></tr>" % ("checked" if player and player.is_avoiding_prune() else "")) cgicommon.writeln("</table>") cgicommon.writeln("<p>") cgicommon.writeln("<input type=\"hidden\" name=\"tourney\" value=\"%s\" />" % (cgicommon.escape(tourneyname, True))) if player: cgicommon.writeln("<input type=\"hidden\" name=\"id\" value=\"%d\" />" % (player_id)) if player: cgicommon.writeln("<input type=\"submit\" name=\"editplayer\" class=\"bigbutton\" value=\"Save Changes\" />") else: cgicommon.writeln("<input type=\"submit\" name=\"newplayersubmit\" class=\"bigbutton\" value=\"Create Player\" />") cgicommon.writeln("</p>") cgicommon.writeln("</form>")
def show_rerate_button(tourney): tourney_name = tourney.get_name() cgicommon.writeln("<h2>Rerate players by player ID</h2>") cgicommon.writeln("<p>") cgicommon.writeln(""" Set the ratings of players in order, by player ID, which corresponds to the order in which they appeared in the list you put into the text box at the start of the tournament. The player at the top of the list (the lowest player ID) gets the highest rating, and the player at the bottom of the list (the highest player ID) gets the lowest rating. Any player with a rating of zero remains unchanged.""") cgicommon.writeln("</p>") cgicommon.writeln("<p>") cgicommon.writeln(""" This is useful if when you pasted in the player list you forgot to select the option which tells Atropine that they're in rating order, and now the Overachievers page thinks they're all seeded the same. """) cgicommon.writeln("</p>") cgicommon.writeln("<p>") cgicommon.writeln(""" If you press this button, it will overwrite all other non-zero ratings you may have given the players. That's why you need to tick the box as well. """) cgicommon.writeln("</p>") cgicommon.writeln("<p>") cgicommon.writeln("<form method=\"POST\" action=\"%s?tourney=%s\">" % (cgicommon.escape(baseurl), urllib.parse.quote_plus(tourney_name))) cgicommon.writeln("<input type=\"submit\" name=\"reratebyplayerid\" value=\"Rerate players by player ID\" />") cgicommon.writeln("<input type=\"checkbox\" name=\"reratebyplayeridconfirm\" id=\"reratebyplayeridconfirm\" style=\"margin-left: 20px\" />") cgicommon.writeln("<label for=\"reratebyplayeridconfirm\">Yes, I'm sure</label>") cgicommon.writeln("</form>") cgicommon.writeln("</p>")
if num_players == 0: cgicommon.writeln( "<p>This tourney doesn't have any players, so you can't specify teams yet.</p>" ) cgicommon.writeln( '<p><a href="/cgi-bin/tourneysetup.py?tourney=%s">Back to Tourney Setup</a></p>' % (urllib.parse.quote_plus(tourneyname))) else: #print '<p><a href="/cgi-bin/tourneysetup.py?tourney=%s">Back to tourney setup</a></p>' % (urllib.quote_plus(tourneyname)); cgicommon.writeln('<h2>Teams</h2>') for team in teams: cgicommon.writeln('<p>') cgicommon.writeln( cgicommon.make_team_dot_html(team) + " " + cgicommon.escape(team.get_name())) player_name_list = [ cgicommon.escape(p.get_name()) for (p, pt) in player_teams if pt is not None and pt.get_id() == team.get_id() ] if player_name_list: cgicommon.writeln( " (%d): %s" % (len(player_name_list), ", ".join(player_name_list))) else: cgicommon.writeln(" (no players)") cgicommon.writeln('</p>') cgicommon.writeln('<h2>Players</h2>') cgicommon.writeln(
else: #print '<p><a href="%s?tourney=%s">%s</a></p>' % (baseurl, urllib.quote_plus(tourneyname), cgicommon.escape(tourneyname)); if request_method == "POST" and "submit" in form: try: tourney.set_show_tournament_rating_column(show_tournament_rating) tourney.set_tournament_rating_config(tr_bonus, tr_diff_cap) tourney.set_rank_method(rank) tourney.set_rank_finals(rank_finals) cgicommon.show_success_box("Options updated.") except countdowntourney.TourneyException as e: cgicommon.show_tourney_exception(e) cgicommon.writeln(('<form action="%s?tourney=%s" method="post">' % (baseurl, urllib.parse.quote_plus(tourneyname)))) cgicommon.writeln(('<input type="hidden" name="tourney" value="%s" />' % cgicommon.escape(tourneyname, True))) cgicommon.writeln("<h2>Team Setup</h2>") cgicommon.writeln("""<p>Atropine can assign each player to one of two teams. Every match between players on opposing teams gives a point to the winner's team. The team scores are displayed alongside the standings.</p>""") cgicommon.writeln("""<p> <a href=\"/cgi-bin/teamsetup.py?tourney=%s\">Go to the Team Setup page</a> </p>""" % (urllib.parse.quote_plus(tourneyname))) cgicommon.writeln("<h2>Ranking order</h2>") rank = tourney.get_rank_method() rank_finals = tourney.get_rank_finals() cgicommon.writeln( "<p>How do you want to rank players in the standings table?</p>") cgicommon.writeln("<div class=\"generalsetupcontrolgroup\">")
cgicommon.writeln("<h1>Tim Down Award</h1>") cgicommon.writeln("<form action=\"%s\" method=\"GET\">" % (baseurl)) cgicommon.writeln("<p>") cgicommon.writeln( "The Tim Down Award goes to the player whose opponents have the highest average standings position, and who lost " ) cgicommon.writeln( "<input type=\"number\" name=\"numlosinggames\" value=\"%d\" min=\"0\" max=\"999\" size=\"3\" />" % (num_losing_games)) cgicommon.writeln("or more games.") cgicommon.writeln("</p>") cgicommon.writeln("<p>") cgicommon.writeln( "<input type=\"hidden\" name=\"tourney\" value=\"%s\" />" % (cgicommon.escape(tourney_name, True))) cgicommon.writeln( "<input type=\"submit\" name=\"submit\" value=\"Refresh\" />") cgicommon.writeln("</p>") cgicommon.writeln("</form>") num_divisions = tourney.get_num_divisions() for division in range(num_divisions): if num_divisions > 1: div_name = tourney.get_division_name(division) cgicommon.writeln("<h2>%s</h2>" % (cgicommon.escape(div_name))) td_standings = tourney.get_tim_down_award_standings( division, num_losing_games) pos = 0
def show_conflict_resolution_box(tourney, games, round_no, stored_revision_no, stored_revision_timestamp, form): tourney_name = tourney.get_name() existing_strategy = int_or_none(form.getfirst("conflictstrategy")) if existing_strategy is None: existing_strategy = CONFLICT_STRATEGY_DO_NOT_EMBLANKIFY cgicommon.writeln(""" <script> function update_conflict_resolution_example(value) { var blank_to_non_blank = document.getElementById("cr_blanktononblank"); var non_blank_to_non_blank = document.getElementById("cr_nonblanktononblank"); var non_blank_to_blank = document.getElementById("cr_nonblanktoblank"); if (value == 0) { /* CONFLICT_STRATEGY_FORCE */ blank_to_non_blank.innerHTML = "88-88"; non_blank_to_non_blank.innerHTML = "88-88"; non_blank_to_blank.innerHTML = "-"; } else if (value == 1) { /* CONFLICT_STRATEGY_DO_NOT_EMBLANKIFY */ blank_to_non_blank.innerHTML = "88-88"; non_blank_to_non_blank.innerHTML = "88-88"; non_blank_to_blank.innerHTML = "77-77"; } else if (value == 2) { /* CONFLICT_STRATEGY_ONLY_FILL_BLANKS */ blank_to_non_blank.innerHTML = "88-88"; non_blank_to_non_blank.innerHTML = "77-77"; non_blank_to_blank.innerHTML = "77-77"; } else if (value == 3) { /* CONFLICT_STRATEGY_DISCARD */ blank_to_non_blank.innerHTML = "-"; non_blank_to_non_blank.innerHTML = "77-77"; non_blank_to_blank.innerHTML = "77-77"; } } </script> """) cgicommon.writeln("<div class=\"conflictresolution\">") cgicommon.writeln( "<form method=\"POST\" action=\"%s?tourney=%s&round=%d\">" % (baseurl, urllib.parse.quote_plus(tourney_name), round_no)) cgicommon.writeln( "<input type=\"hidden\" name=\"tourney\" value=\"%s\" />" % (cgicommon.escape(tourney_name, True))) cgicommon.writeln("<input type=\"hidden\" name=\"round\" value=\"%d\" />" % (round_no)) cgicommon.writeln( "<input type=\"hidden\" name=\"revision\" value=\"%d\" />" % (stored_revision_no)) # Include the submitted scores in this conflict resolution form, so that # when the user presses "Resolve Conflicts" we remember what the original # submissions were. for g in games: input_name = "gamescore_%d_%d" % (g.round_no, g.seq) submitted_score = form.getfirst(input_name) if submitted_score is not None: cgicommon.writeln( "<input type=\"hidden\" name=\"%s\" value=\"%s\" />" % (cgicommon.escape(input_name), cgicommon.escape(submitted_score, True))) score = form.getfirst("gamescore_%d_%d" % (g.round_no, g.seq)) cgicommon.writeln("<div class=\"conflictresolutiontoprow\">") cgicommon.writeln("Last conflicting modification occurred at: %s" % (cgicommon.escape(stored_revision_timestamp))) cgicommon.writeln("</div>") cgicommon.writeln("<div class=\"conflictresolutionchoicerow\">") cgicommon.writeln("<div class=\"conflictresolutionradiobutton\">") cgicommon.writeln( "<input type=\"radio\" name=\"conflictstrategy\" id=\"conflictstrategydiscard\" value=\"%d\" onchange=\"update_conflict_resolution_example(this.value)\" %s />" % (CONFLICT_STRATEGY_DISCARD, "checked" if existing_strategy == CONFLICT_STRATEGY_DISCARD else "")) cgicommon.writeln("</div>") cgicommon.writeln("<div class=\"conflictresolutionlabel\">") cgicommon.writeln( "<label for=\"conflictstrategydiscard\">Discard my submission - go with what's currently in the database.</label>" ) cgicommon.writeln("</div>") cgicommon.writeln("</div>") cgicommon.writeln("<div class=\"conflictresolutionchoicerow\">") cgicommon.writeln("<div class=\"conflictresolutionradiobutton\">") cgicommon.writeln( "<input type=\"radio\" name=\"conflictstrategy\" id=\"conflictstrategyfillblanks\" value=\"%d\" onchange=\"update_conflict_resolution_example(this.value)\" %s />" % (CONFLICT_STRATEGY_ONLY_FILL_BLANKS, "checked" if existing_strategy == CONFLICT_STRATEGY_ONLY_FILL_BLANKS else "")) cgicommon.writeln("</div>") cgicommon.writeln("<div class=\"conflictresolutionlabel\">") cgicommon.writeln( "<label for=\"conflictstrategyfillblanks\">If a game currently has no result but my submission provides one, fill in that game's result with my submission. Discard any other changes.</label>" ) cgicommon.writeln("</div>") cgicommon.writeln("</div>") cgicommon.writeln("<div class=\"conflictresolutionchoicerow\">") cgicommon.writeln("<div class=\"conflictresolutionradiobutton\">") cgicommon.writeln( "<input type=\"radio\" name=\"conflictstrategy\" id=\"conflictstrategydonotemblankify\" value=\"%d\" onchange=\"update_conflict_resolution_example(this.value);\" %s />" % (CONFLICT_STRATEGY_DO_NOT_EMBLANKIFY, "checked" if existing_strategy == CONFLICT_STRATEGY_DO_NOT_EMBLANKIFY else "")) cgicommon.writeln("</div>") cgicommon.writeln("<div class=\"conflictresolutionlabel\">") cgicommon.writeln( "<label for=\"conflictstrategydonotemblankify\">If my submission has a result for a game, overwrite the existing result with my submission, but do not overwrite an existing result with a blank one.</label>" ) cgicommon.writeln("</div>") cgicommon.writeln("</div>") cgicommon.writeln("<div class=\"conflictresolutionchoicerow\">") cgicommon.writeln("<div class=\"conflictresolutionradiobutton\">") cgicommon.writeln( "<input type=\"radio\" name=\"conflictstrategy\" id=\"conflictstrategyforce\" value=\"%d\" onchange=\"update_conflict_resolution_example(this.value);\" %s />" % (CONFLICT_STRATEGY_FORCE, "checked" if existing_strategy == CONFLICT_STRATEGY_FORCE else "")) cgicommon.writeln("</div>") cgicommon.writeln("<div class=\"conflictresolutionlabel\">") cgicommon.writeln( "<label for=\"conflictstrategyforce\">Overwrite everything with my submission, even if that means overwriting existing results with blank results.</label>" ) cgicommon.writeln("</div>") cgicommon.writeln("</div>") show_conflict_resolution_example(existing_strategy) cgicommon.writeln("<div class=\"conflictresolutionbottomrow\">") cgicommon.writeln("<div class=\"conflictresolutionsubmit\">") cgicommon.writeln( "<input type=\"submit\" name=\"save\" value=\"Resolve Conflicts\" />") cgicommon.writeln("</div>") cgicommon.writeln("</div>") cgicommon.writeln("</form>") cgicommon.writeln("</div>")
def show_view_option_controls(tourney, form, options): if not options: return cgicommon.writeln( "<div class=\"teleostoptionheading\">Options for this screen mode</div>" ) for o in options: cgicommon.writeln("<div class=\"teleostoption\">") name_escaped = "teleost_option_" + cgicommon.escape(o.name, True) if o.value is None: value_escaped = "" else: value_escaped = cgicommon.escape(str(o.value), True) desc_escaped = cgicommon.escape(o.desc) # If $INDENT exists, replace it with a checkbox-width of empty space desc_escaped = re.sub( "\\$INDENT\\b", "<span style=\"visibility: hidden;\"><input type=\"checkbox\" name=\"_placeholder_%s\" /></span>" % (name_escaped), desc_escaped, 0) m = re.search("\\$CONTROL\\b", desc_escaped) if m: before_control = desc_escaped[0:m.start()] after_control = desc_escaped[m.end():] else: before_control = desc_escaped after_control = "" cgicommon.writeln(before_control) if o.name in checkbox_to_assoc_field: onclick_value = "var numberField = document.getElementById('%s'); var checkboxField = document.getElementById('%s'); numberField.disabled = !checkboxField.checked;" % ( "teleost_option_" + checkbox_to_assoc_field[o.name], name_escaped) else: onclick_value = None disabled_attr = "" if o.name in assoc_field_to_checkbox: for oo in options: if oo.name == assoc_field_to_checkbox[o.name]: try: value = int(oo.value) except ValueError: value = 0 if value: disabled_attr = "" else: disabled_attr = "disabled" break if o.control_type == countdowntourney.CONTROL_NUMBER: cgicommon.writeln( "<input type=\"number\" style=\"width: 5em;\" name=\"%s\" id=\"%s\" value=\"%s\" %s />" % (name_escaped, name_escaped, value_escaped, disabled_attr)) elif o.control_type == countdowntourney.CONTROL_CHECKBOX: if o.value is not None and int(o.value): checked_str = "checked" else: checked_str = "" cgicommon.writeln( "<input type=\"checkbox\" name=\"%s\" id=\"%s\" value=\"1\" %s %s />" % (name_escaped, name_escaped, checked_str, "" if not onclick_value else "onclick=\"" + re.sub("\"", "\\\"", onclick_value, 0) + "\"")) cgicommon.writeln( "<input type=\"hidden\" name=\"%s\" value=\"1\" />" % ("exists_checkbox_" + name_escaped)) cgicommon.writeln(after_control) cgicommon.writeln("</div>")
<a href="/cgi-bin/display.py?tourney=%s" target=\"_blank\"> Open Display Window <img src=\"/images/opensinnewwindow.png\" alt=\"Opens in new window\" title=\"Opens in new window\" /> </a>""" % (urllib.parse.quote_plus(tourney.name))) cgicommon.writeln("</div>") cgicommon.writeln("<div class=\"bannercontrol\">") cgicommon.writeln("<form action=\"" + baseurl + "?tourney=%s&selectedview=%d\" method=\"POST\">" % (urllib.parse.quote_plus(tourney_name), selected_view)) cgicommon.writeln( "Banner text: <input type=\"text\" name=\"bannertext\" id=\"bannereditbox\" value=\"%s\" size=\"50\" onclick=\"this.select();\" />" % (cgicommon.escape(banner_text, True))) cgicommon.writeln( "<input type=\"submit\" style=\"min-width: 60px;\" name=\"setbanner\" value=\"Set\" />" ) cgicommon.writeln( "<input type=\"submit\" style=\"min-width: 60px;\" name=\"clearbanner\" value=\"Clear\" />" ) cgicommon.writeln("</form>") cgicommon.writeln("</div>") cgicommon.writeln("<div class=\"viewselection\">") cgicommon.writeln("<div class=\"viewpreviewandoptions\">") cgicommon.writeln("<div class=\"displaysetupview viewnowshowing\">") show_now_showing_frame(tourney) cgicommon.writeln("<div class=\"viewpreviewcurrent\">")
def get_user_form(tourney, settings, div_rounds): num_divisions = tourney.get_num_divisions() div_num_games = dict() div_game_types = dict() players = sorted(tourney.get_active_players(), key=lambda x: x.get_name()) latest_round_no = tourney.get_latest_round_no() if latest_round_no is None: latest_round_no = 0 prev_settings = settings.get_previous_settings() for key in prev_settings: if key not in settings and re.match("^d[0-9]*_groupsize$", key): settings[key] = prev_settings[key] if settings.get("submitrestore", None): for key in prev_settings: if key not in ["submit", "submitrestore", "submitplayers"]: settings[key] = prev_settings[key] elements = [] elements.append(htmlform.HTMLFormHiddenInput("numgamessubmit", "1")) elements.append( htmlform.HTMLFormHiddenInput("roundno", str(latest_round_no + 1))) # If there's a previously-saved form for this round, offer to load it prev_settings = settings.get_previous_settings() round_no = int_or_none(prev_settings.get("roundno", None)) if round_no is not None and round_no == latest_round_no + 1: elements.append( htmlform.HTMLFragment("<div class=\"infoboxcontainer\">")) elements.append(htmlform.HTMLFragment("<div class=\"infoboximage\">")) elements.append( htmlform.HTMLFragment( "<img src=\"/images/info.png\" alt=\"Info\" />")) elements.append(htmlform.HTMLFragment("</div>")) elements.append( htmlform.HTMLFragment("<div class=\"infoboxmessagecontainer\">")) elements.append( htmlform.HTMLFragment("<div class=\"infoboxmessage\">")) elements.append(htmlform.HTMLFragment("<p>")) elements.append( htmlform.HTMLFragment( "There is an incomplete fixtures form saved. Do you want to carry on from where you left off?" )) elements.append(htmlform.HTMLFragment("</p>")) elements.append(htmlform.HTMLFragment("<p>")) elements.append( htmlform.HTMLFormSubmitButton("submitrestore", "Restore previously-saved form")) elements.append(htmlform.HTMLFragment("</p>")) elements.append(htmlform.HTMLFragment("</div></div></div>")) # When we pass these settings to fixgen_manual, we don't want it asking # awkward questions about the number of players in a group when we're # fixing at it two, so tell it that's already been submitted. settings["tablesizesubmit"] = "1" for div_index in div_rounds: num_games_name = "d%d_num_groups" % (div_index) game_type_name = "d%d_game_type" % (div_index) # For fully-manual, number of players per group is always 2, and # we're allowed to put a player on more than one table settings["d%d_groupsize" % (div_index)] = "2" settings["d%d_allow_player_repetition" % (div_index)] = "1" # Also we want fixgen_manual to show the standings table for each # division. settings["d%d_show_standings" % (div_index)] = "1" if settings.get(num_games_name, None) is not None: try: div_num_games[div_index] = int(settings.get(num_games_name)) if div_num_games[div_index] < 0: div_num_games[div_index] = 0 except ValueError: div_num_games[div_index] = 0 else: div_num_games[div_index] = 0 if settings.get(game_type_name, None) is not None: try: div_game_types[div_index] = settings.get(game_type_name) if div_game_types[div_index] in special_round_names: settings["d%d_round_name" % (div_index)] = special_round_names[ div_game_types[div_index]] except ValueError: div_game_types[div_index] = None if num_divisions > 1: elements.append( htmlform.HTMLFragment( "<h2>%s</h2>" % (cgicommon.escape(tourney.get_division_name(div_index))))) elements.append(htmlform.HTMLFragment("<div class=\"fixgenoption\">")) num_games_element = htmlform.HTMLFormTextInput( "Number of games to create", num_games_name, "") elements.append(num_games_element) elements.append(htmlform.HTMLFragment("</div>")) elements.append(htmlform.HTMLFragment("<div class=\"fixgenoption\">")) elements.append(htmlform.HTMLFragment("Create games of this type: ")) game_type_options = [ htmlform.HTMLFormDropDownOption(x["code"], x["name"] + " (" + x["code"] + ")") for x in countdowntourney.get_game_types() ] type_element = htmlform.HTMLFormDropDownBox( "d%d_game_type" % (div_index), game_type_options) current_setting = settings.get("d%d_game_type" % (div_index)) if current_setting: type_element.set_value(current_setting) elements.append(type_element) elements.append(htmlform.HTMLFragment("</div>")) num_games_total = sum([div_num_games[x] for x in div_num_games]) if num_games_total == 0 or not (settings.get("numgamessubmit", "")): elements.append(htmlform.HTMLFragment("<div class=\"fixgenoption\">")) elements.append(htmlform.HTMLFormSubmitButton("submit", "Continue")) elements.append(htmlform.HTMLFragment("</div>")) return htmlform.HTMLForm( "POST", "/cgi-bin/fixturegen.py?tourney=%s" % (urllib.parse.quote_plus(tourney.name)), elements) else: return fixgen_manual.get_user_form(tourney, settings, div_rounds)
if round_no is not None: games = tourney.get_games(round_no=round_no) rounds = tourney.get_rounds() round_name = None last_modified_element = None for r in rounds: if r["num"] == round_no: round_name = r.get("name", None) break if not round_name: round_name = "Round " + str(round_no) remarks = dict() cgicommon.writeln("<h1>Score editor: %s</h1>" % cgicommon.escape(round_name)) cgicommon.writeln("<p>") cgicommon.writeln( "<a href=\"/cgi-bin/fixtureedit.py?tourney=%s&round=%d\">Edit fixtures</a>" % (urllib.parse.quote_plus(tourney_name), round_no)) cgicommon.writeln("</p>") cgicommon.writeln("<script>") cgicommon.writeln("""function set_unsaved_data_warning() { if (window.onbeforeunload == null) { window.onbeforeunload = function() { return 'You have modified scores on this page and not saved them.'; }; } }
def get_user_form(tourney, settings, div_rounds): num_divisions = tourney.get_num_divisions() div_table_sizes = dict() players = sorted(tourney.get_active_players(), key=lambda x: x.get_name()) latest_round_no = tourney.get_latest_round_no() if latest_round_no is None: latest_round_no = 0 prev_settings = settings.get_previous_settings() for key in prev_settings: if key not in settings and re.match("^d[0-9]*_groupsize$", key): settings[key] = prev_settings[key] if settings.get("submitrestore", None): for key in prev_settings: if key not in ["submit", "submitrestore", "submitplayers"]: settings[key] = prev_settings[key] elements = [] elements.append(htmlform.HTMLFormHiddenInput("tablesizesubmit", "1")) elements.append( htmlform.HTMLFormHiddenInput("roundno", str(latest_round_no + 1))) # If there's a previously-saved form for this round, offer to load it prev_settings = settings.get_previous_settings() round_no = int_or_none(prev_settings.get("roundno", None)) if round_no is not None and round_no == latest_round_no + 1: elements.append( htmlform.HTMLFragment("<div class=\"infoboxcontainer\">")) elements.append(htmlform.HTMLFragment("<div class=\"infoboximage\">")) elements.append( htmlform.HTMLFragment( "<img src=\"/images/info.png\" alt=\"Info\" />")) elements.append(htmlform.HTMLFragment("</div>")) elements.append( htmlform.HTMLFragment("<div class=\"infoboxmessagecontainer\">")) elements.append( htmlform.HTMLFragment("<div class=\"infoboxmessage\">")) elements.append(htmlform.HTMLFragment("<p>")) elements.append( htmlform.HTMLFragment( "There is an incomplete fixtures form saved. Do you want to carry on from where you left off?" )) elements.append(htmlform.HTMLFragment("</p>")) elements.append(htmlform.HTMLFragment("<p>")) elements.append( htmlform.HTMLFormSubmitButton("submitrestore", "Restore previously-saved form")) elements.append(htmlform.HTMLFragment("</p>")) elements.append(htmlform.HTMLFragment("</div></div></div>")) for div_index in div_rounds: div_players = [x for x in players if x.get_division() == div_index] table_size = None table_size_name = "d%d_groupsize" % (div_index) if settings.get(table_size_name, None) is not None: try: div_table_sizes[div_index] = int(settings.get(table_size_name)) except ValueError: div_table_sizes[div_index] = None else: div_table_sizes[div_index] = None choices = [] # Number of groups may be specified by fully-manual generator. # If it isn't, then use all the players. num_groups = int_or_none(settings.get("d%d_num_groups" % (div_index))) if num_groups: if div_table_sizes[ div_index] is not None and div_table_sizes[div_index] <= 0: raise countdowntourney.FixtureGeneratorException( "%s: invalid table size for fully-manual setup." % (tourney.get_division_name(div_index))) else: for size in (2, 3, 4, 5): if num_groups or len(div_players) % size == 0: choices.append( htmlform.HTMLFormChoice( str(size), str(size), size == div_table_sizes[div_index])) if len(div_players) >= 8: choices.append( htmlform.HTMLFormChoice("-5", "5&3", div_table_sizes[div_index] == -5)) if not choices: raise countdowntourney.FixtureGeneratorException( "%s: number of players (%d) is not compatible with any supported table size." % (tourney.get_division_name(div_index), len(div_players))) if num_divisions > 1: elements.append( htmlform.HTMLFragment( "<h2>%s</h2>" % (cgicommon.escape(tourney.get_division_name(div_index))))) elements.append(htmlform.HTMLFragment("<p>")) elements.append( htmlform.HTMLFormRadioButton(table_size_name, "Players per table", choices)) elements.append(htmlform.HTMLFragment("</p>")) all_table_sizes_given = True for div in div_table_sizes: if div_table_sizes.get(div) is None: all_table_sizes_given = False if not all_table_sizes_given or not (settings.get("tablesizesubmit", "")): elements.append(htmlform.HTMLFragment("<p>")) elements.append( htmlform.HTMLFormSubmitButton( "submit", "Submit table sizes and select players")) elements.append(htmlform.HTMLFragment("</p>")) return htmlform.HTMLForm( "POST", "/cgi-bin/fixturegen.py?tourney=%s" % (urllib.parse.quote_plus(tourney.name)), elements) show_already_assigned_players = bool(settings.get("showallplayers")) div_num_slots = dict() for div_index in div_rounds: num_groups = int_or_none(settings.get("d%d_num_groups" % (div_index))) div_players = [x for x in players if x.get_division() == div_index] table_size = div_table_sizes[div_index] if num_groups: # If num_groups is specified, then we can't use the 5&3 setup. # If it's any other table setup then the number of player slots is # the number of players per table times num_groups. if table_size <= 0: raise countdowntourney.FixtureGeneratorException( "%s: invalid table size for fully-manual setup" % (tourney.get_division_name(div_index))) else: num_slots = table_size * num_groups else: # If num_groups is not specified, then the number if slots is # simply the number of active players in this division. num_slots = len(div_players) div_num_slots[div_index] = num_slots if table_size > 0 and num_slots % table_size != 0: raise countdowntourney.FixtureGeneratorException( "%s: table size of %d is not allowed, as the number of player slots (%d) is not a multiple of it." % (tourney.get_division_name(div_index), table_size, num_slots)) if table_size == -5 and num_slots < 8: raise countdowntourney.FixtureGeneratorException( "%s: can't use table sizes of five and three - you need at least 8 players and you have %d" % (tourney.get_division_name(div_index), num_slots)) if table_size not in (2, 3, 4, 5, -5): raise countdowntourney.FixtureGeneratorException( "%s: invalid table size: %d" % (tourney.get_division_name(div_index), table_size)) div_set_players = dict() div_duplicate_slots = dict() div_empty_slots = dict() div_invalid_slots = dict() div_count_in_standings = dict() div_set_text = dict() div_game_type = dict() all_filled = True for div_index in div_rounds: div_players = [x for x in players if x.get_division() == div_index] num_groups = int_or_none(settings.get("d%d_num_groups" % (div_index))) num_slots = div_num_slots[div_index] set_players = [None for i in range(0, num_slots)] set_text = ["" for i in range(0, num_slots)] game_type = settings.get("d%d_game_type" % (div_index)) if not game_type: if not settings.get("submitplayers"): count_in_standings = True else: count_in_standings = settings.get("d%d_heats" % (div_index)) if count_in_standings is None: count_in_standings = False else: count_in_standings = True else: count_in_standings = (game_type == "P") # Slot numbers which contain text that doesn't match any player name invalid_slots = [] allow_player_repetition = int_or_none( settings.get("d%d_allow_player_repetition" % (div_index))) if allow_player_repetition is None: allow_player_repetition = False else: allow_player_repetition = bool(allow_player_repetition) # Ask the user to fill in N little drop-down boxes, where N is the # number of players, to decide who's going on what table. for player_index in range(0, num_slots): name = settings.get("d%d_player%d" % (div_index, player_index)) if name is None: name = "" set_text[player_index] = name if name: set_players[player_index] = lookup_player(div_players, name) if set_players[player_index] is None: invalid_slots.append(player_index) else: set_players[player_index] = None # Slot numbers which contain a player already contained in another slot duplicate_slots = [] # Slot numbers which don't contain a player empty_slots = [] player_index = 0 for p in set_players: if player_index in invalid_slots: all_filled = False elif p is None: empty_slots.append(player_index) all_filled = False else: if not allow_player_repetition: count = 0 for q in set_players: if q is not None and q.get_name() == p.get_name(): count += 1 if count > 1: duplicate_slots.append(player_index) all_filled = False player_index += 1 div_set_players[div_index] = set_players div_duplicate_slots[div_index] = duplicate_slots div_empty_slots[div_index] = empty_slots div_invalid_slots[div_index] = invalid_slots div_count_in_standings[div_index] = count_in_standings div_set_text[div_index] = set_text div_game_type[div_index] = game_type interface_type = int_or_none( settings.get("interfacetype", INTERFACE_AUTOCOMPLETE)) if all_filled and settings.get("submitplayers"): # All slots filled, don't need to ask the user anything more return None elements = [] elements.append( htmlform.HTMLFormHiddenInput("roundno", str(latest_round_no + 1))) elements.append( htmlform.HTMLFragment("""<style type=\"text/css\"> table.seltable { margin-top: 20px; } .seltable td { padding: 2px; border: 2px solid white; } td.tablenumber { font-family: "Cabin"; background-color: blue; color: white; text-align: center; min-width: 1.5em; } .duplicateplayer { background-color: violet; } .emptyslot { /*background-color: #ffaa00;*/ } .invalidslot { background-color: red; } .validslot { background-color: #00cc00; } </style> """)) elements.append( htmlform.HTMLFragment("""<script> function set_unsaved_data_warning() { if (window.onbeforeunload == null) { window.onbeforeunload = function() { return "You have modified entries on this page and not submitted them. If you navigate away from the page, these changes will be lost."; }; } } function unset_unsaved_data_warning() { window.onbeforeunload = null; } </script> """)) autocomplete_script = "<script>\n" autocomplete_script += "var divPlayerNames = " div_player_names = {} for div_index in div_rounds: name_list = [ x.get_name() for x in players if x.get_division() == div_index ] div_player_names[div_index] = name_list autocomplete_script += json.dumps(div_player_names, indent=4) + ";\n" autocomplete_script += """ function setLastEditedBox(controlId) { var lastEdited = document.getElementById("lasteditedinput"); if (lastEdited != null) { lastEdited.value = controlId; } } function editBoxEdit(divIndex, controlId) { var control = document.getElementById(controlId); if (control == null) return; setLastEditedBox(controlId); var value = control.value; //console.log("editBoxEdit() called, value " + value); var previousValue = control.getAttribute("previousvalue"); /* If the change has made the value longer, then proceed. Otherwise don't do any autocompletion because that would interfere with the user's attempt to backspace out the text. */ //console.log("editBoxEdit() called, value " + value + ", previousValue " + previousValue); control.setAttribute("previousvalue", value); if (previousValue != null && value.length <= previousValue.length) { return; } /* Take the portion of the control's value from the start of the string to the start of the selected part. If that string is the start of exactly one player's name, then: 1. Set the control's value to the player's full name 2. Highlight the added portion 3. Leave the cursor where it was before. */ var validNames = divPlayerNames[divIndex]; if (validNames) { var lastMatch = null; var numMatches = 0; var selStart = control.selectionStart; // head is the part the user typed in, i.e. the bit not highlighted var head = value.toLowerCase().substring(0, selStart); for (var i = 0; i < validNames.length; ++i) { if (validNames[i].toLowerCase().startsWith(head)) { numMatches++; lastMatch = validNames[i]; } } if (numMatches == 1) { control.focus(); control.value = lastMatch; control.setSelectionRange(head.length, lastMatch.length); } } } """ autocomplete_script += "</script>\n" elements.append(htmlform.HTMLFragment(autocomplete_script)) elements.append( htmlform.HTMLFragment( "<p>Enter player names below. Each horizontal row is one group, or table.</p>" )) choice_data = [("Auto-completing text boxes", INTERFACE_AUTOCOMPLETE), ("Drop-down boxes", INTERFACE_DROP_DOWN), ("Combo boxes (not supported on all browsers)", INTERFACE_DATALIST)] choices = [ htmlform.HTMLFormChoice(str(x[1]), x[0], interface_type == x[1]) for x in choice_data ] interface_menu = htmlform.HTMLFormRadioButton( "interfacetype", "Player name selection interface", choices) elements.append(interface_menu) if interface_type == INTERFACE_DROP_DOWN: elements.append(htmlform.HTMLFragment("<div class=\"fixgenoption\">")) elements.append( htmlform.HTMLFormCheckBox( "showallplayers", "Show all players in drop-down boxes, even those already assigned a table", show_already_assigned_players)) elements.append(htmlform.HTMLFragment("</div>")) (acc_tables, acc_default) = tourney.get_accessible_tables() table_no = 1 for div_index in div_rounds: div_players = [x for x in players if x.get_division() == div_index] player_index = 0 table_size = div_table_sizes[div_index] duplicate_slots = div_duplicate_slots[div_index] invalid_slots = div_invalid_slots[div_index] empty_slots = div_empty_slots[div_index] set_players = div_set_players[div_index] set_text = div_set_text[div_index] num_slots = div_num_slots[div_index] game_type = div_game_type[div_index] if num_divisions > 1: elements.append( htmlform.HTMLFragment( "<h2>%s</h2>" % (cgicommon.escape(tourney.get_division_name(div_index))))) if not game_type: # Ask the user if they want these games to count towards the # standings table (this is pretty much universally yes) elements.append( htmlform.HTMLFragment("<div class=\"fixgenoption\">")) elements.append( htmlform.HTMLFormCheckBox( "d%d_heats" % (div_index), "Count the results of these matches in the standings table", div_count_in_standings[div_index])) elements.append(htmlform.HTMLFragment("</div>")) # Show the table of groups for the user to fill in elements.append(htmlform.HTMLFragment("<table class=\"seltable\">\n")) prev_table_no = None unselected_names = [x.get_name() for x in div_players] if table_size > 0: table_sizes = [ table_size for i in range(0, num_slots // table_size) ] else: table_sizes = countdowntourney.get_5_3_table_sizes(num_slots) for p in set_players: if p and p.get_name() in unselected_names: unselected_names.remove(p.get_name()) for table_size in table_sizes: elements.append(htmlform.HTMLFragment("<tr>\n")) elements.append( htmlform.HTMLFragment( "<td>%s</td><td class=\"tablenumber\">%d</td>\n" % (" ♿" if (table_no in acc_tables) != acc_default else "", table_no))) if game_type is not None: elements.append( htmlform.HTMLFragment( "<td class=\"fixturegametype\">%s</td>" % (cgicommon.escape(game_type, True)))) for i in range(table_size): p = set_players[player_index] td_style = "" value_is_valid = False if player_index in duplicate_slots: td_style = "class=\"duplicateplayer\"" elif player_index in empty_slots: td_style = "class=\"emptyslot\"" elif player_index in invalid_slots: td_style = "class=\"invalidslot\"" else: td_style = "class=\"validslot\"" value_is_valid = True elements.append(htmlform.HTMLFragment("<td %s>" % td_style)) # Make a drop down list with every unassigned player in it player_option_list = [] if interface_type == INTERFACE_DROP_DOWN: # Drop-down list needs an initial "nothing selected" option player_option_list.append( htmlform.HTMLFormDropDownOption("", " -- select --")) selected_name = "" if show_already_assigned_players: name_list = [x.get_name() for x in div_players] else: if p: name_list = sorted(unselected_names + [p.get_name()]) else: name_list = unselected_names for q in name_list: if p is not None and q == p.get_name(): selected_name = p.get_name() if interface_type == INTERFACE_DROP_DOWN: player_option_list.append( htmlform.HTMLFormDropDownOption(q, q)) else: player_option_list.append(q) if interface_type != INTERFACE_DROP_DOWN and not selected_name: selected_name = set_text[player_index] # Select the appropriate player control_name = "d%d_player%d" % (div_index, player_index) if interface_type == INTERFACE_DATALIST: sel = htmlform.HTMLFormComboBox( control_name, player_option_list, other_attrs={ "onchange": "set_unsaved_data_warning();" }) elif interface_type == INTERFACE_DROP_DOWN: sel = htmlform.HTMLFormDropDownBox( control_name, player_option_list, other_attrs={ "onchange": "set_unsaved_data_warning();" }) elif interface_type == INTERFACE_AUTOCOMPLETE: sel = htmlform.HTMLFormTextInput( "", control_name, selected_name, other_attrs={ "oninput": "editBoxEdit(%d, \"%s\");" % (div_index, control_name), "onclick": "if (this.selectionStart == this.selectionEnd) { this.select(); }", "id": control_name, "validvalue": "1" if value_is_valid else "0", "previousvalue": selected_name, "class": "playerslot" }) else: sel = None sel.set_value(selected_name) elements.append(sel) elements.append(htmlform.HTMLFragment("</td>")) player_index += 1 table_no += 1 elements.append(htmlform.HTMLFragment("</tr>\n")) elements.append(htmlform.HTMLFragment("</table>\n")) if len(acc_tables) > 0: # Warn the user that the table numbers displayed above might not # end up being the final table numbers. elements.append( htmlform.HTMLFragment( "<p style=\"font-size: 10pt\">Note: You have designated accessible tables, so the table numbers above may be automatically reassigned to fulfil accessibility requirements.</p>" )) # Add the submit button elements.append(htmlform.HTMLFragment("<p>\n")) elements.append(htmlform.HTMLFormHiddenInput("submitplayers", "1")) elements.append( htmlform.HTMLFormHiddenInput("lasteditedinput", "", other_attrs={"id": "lasteditedinput"})) elements.append( htmlform.HTMLFormSubmitButton("submit", "Submit", other_attrs={ "onclick": "unset_unsaved_data_warning();", "class": "bigbutton" })) elements.append(htmlform.HTMLFragment("</p>\n")) if invalid_slots: elements.append( htmlform.HTMLFragment( "<p>You have slots with unrecognised player names; these are highlighted in <span style=\"color: red; font-weight: bold;\">red</span>.</p>" )) if duplicate_slots: elements.append( htmlform.HTMLFragment( "<p>You have players in multiple slots; these are highlighted in <span style=\"color: violet; font-weight: bold;\">violet</span>.</p>" )) if unselected_names: elements.append( htmlform.HTMLFragment( "<p>Players still to be given a table:\n")) for i in range(len(unselected_names)): name = unselected_names[i] elements.append( htmlform.HTMLFragment( "%s%s" % (cgicommon.escape(name, True), "" if i == len(unselected_names) - 1 else ", "))) elements.append(htmlform.HTMLFragment("</p>\n")) elements.append( htmlform.HTMLFormHiddenInput("d%d_groupsize" % (div_index), str(div_table_sizes[div_index]))) show_standings = int_or_none( settings.get("d%d_show_standings" % (div_index))) if show_standings: elements.append( htmlform.HTMLFormStandingsTable("d%d_standings" % (div_index), tourney, div_index)) last_edited_input_name = settings.get("lasteditedinput", "") set_element_focus_script = """ <script> var lastEditedElementName = %s; var playerBoxes = document.getElementsByClassName("playerslot"); var playerBoxesBefore = []; var playerBoxesAfter = []; var foundElement = false; for (var i = 0; i < playerBoxes.length; ++i) { if (playerBoxes[i].name == lastEditedElementName) { foundElement = true; } if (foundElement) { playerBoxesAfter.push(playerBoxes[i]); } else { playerBoxesBefore.push(playerBoxes[i]); } } //console.log("playerBoxesAfter " + playerBoxesAfter.length.toString() + ", playerBoxesBefore " + playerBoxesBefore.length.toString()); /* Give focus to the first text box equal to or after this one which does not have a valid value in it. If there are no such text boxes, search from the beginning of the document onwards. */ var playerBoxOrder = playerBoxesAfter.concat(playerBoxesBefore); for (var i = 0; i < playerBoxOrder.length; ++i) { var box = playerBoxOrder[i]; var validValue = box.getAttribute("validvalue"); if (validValue == null || validValue == "0") { box.focus(); box.select(); break; } } </script> """ % (json.dumps(last_edited_input_name)) elements.append(htmlform.HTMLFragment(set_element_focus_script)) form = htmlform.HTMLForm( "POST", "/cgi-bin/fixturegen.py?tourney=%s" % (urllib.parse.quote_plus(tourney.name)), elements) return form
cgicommon.show_success_box("Players successfully rerated by player ID.") except countdowntourney.TourneyException as e: cgicommon.show_tourney_exception(e) if tourney.get_num_games() == 0: cgicommon.writeln("<p>No games have been played yet.</p>") else: cgicommon.writeln("<p>Each player is assigned a seed according to their rating, with the top-rated player in a division being the #1 seed, and so on down. Players are listed here in order of the difference between their position in the standings table and their seed position.</p>") num_divisions = tourney.get_num_divisions() do_show_rerate_button = False for div_index in range(num_divisions): div_name = tourney.get_division_name(div_index) overachievements = tourney.get_players_overachievements(div_index) if num_divisions > 1: cgicommon.writeln("<h2>%s</h2>" % (cgicommon.escape(div_name))) if not overachievements: cgicommon.writeln("<p>There are no players to show.</p>") continue if tourney.are_player_ratings_uniform(div_index): cgicommon.show_warning_box("<p>All the players have the same rating. This means the Overachievers table won't be meaningful. If when you set up the tournament you pasted the players into the player list in order of rating but forgot to tell Atropine you'd done that, try the \"Rerate players by player ID\" button below.</p>") do_show_rerate_button = True else: cgicommon.writeln("<table class=\"miscranktable\">") cgicommon.writeln("<tr>") cgicommon.writeln("<th></th><th>Player</th><th>Seed</th><th>Pos</th><th>+/-</th>") cgicommon.writeln("</tr>") pos = 0 joint = 1 prev_overachievement = None for row in overachievements:
num_losing_games = cgicommon.int_or_none(form.getfirst("numlosinggames", 3)) if num_losing_games is None or num_losing_games <= 0: num_losing_games = 3 cgicommon.writeln("<div class=\"mainpane\">") cgicommon.writeln("<h1>Tuff Luck</h1>") cgicommon.writeln("<form action=\"/cgi-bin/tuffluck.py\" method=\"GET\">") cgicommon.writeln("<p>") cgicommon.writeln("A player's Tuff Luck is their aggregate losing margin over their") cgicommon.writeln("<input type=\"number\" name=\"numlosinggames\" value=\"%d\" min=\"1\" max=\"999\" size=\"3\" />" % (num_losing_games)) cgicommon.writeln("closest losing games, for players who have lost at least that many games.") cgicommon.writeln("</p>") cgicommon.writeln("<p>") cgicommon.writeln("<input type=\"hidden\" name=\"tourney\" value=\"%s\" />" % (cgicommon.escape(tourney_name, True))) cgicommon.writeln("<input type=\"submit\" name=\"submit\" value=\"Refresh\" />") cgicommon.writeln("</p>") cgicommon.writeln("</form>") players_tuff_luck = tourney.get_players_tuff_luck(num_losing_games) pos = 0 joint = 1 prev_tuffness = None if not players_tuff_luck: cgicommon.writeln("<p>No players have lost %d or more games.</p>" % (num_losing_games)) else: cgicommon.writeln("<table class=\"miscranktable\">") cgicommon.writeln("<tr>") cgicommon.writeln("<th></th><th>Player</th><th>Margins</th><th>Tuff Luck</th>")
username = state.get("username", "") if not password: password = state.get("password", "") if private_tourney is None: private_tourney = state.get("private", None) if private_tourney is None: private_tourney = tourney.is_broadcast_private() upload_on = state.get("publishing", False) if exception_text: cgicommon.show_error_text(exception_context + ": " + exception_text) if delete_success: cgicommon.show_success_box( "Successfully deleted tourney <strong>%s</strong> from the website." % (cgicommon.escape(tourney_name))) web_link = colive_url_base + "/" + cgicommon.escape(tourney_name, True) web_link_raw = colive_url_base + "/" + tourney_name cgicommon.writeln( "<p>This will upload the tourney state every few seconds so that games, scores and standings are visible at <a href=\"%s\" target=\"_blank\">%s <img src=\"/images/opensinnewwindow.png\" alt=\"Opens in new window\"/></a></p>" % (web_link, web_link)) cgicommon.writeln("<p>You will need:</p>") cgicommon.writeln("<ul>") cgicommon.writeln( "<li>A username and password for the server at %s. If you don't have these, then ignore this whole feature. Just pretend it doesn't exist.</li>" % (cgicommon.escape(uploader.http_server_host))) cgicommon.writeln("<li>A connection to the internet.</li>") cgicommon.writeln("</ul>") cgicommon.writeln( "<p>If you lose internet access, uploads will be suspended but everything that doesn't require internet access such as results entry, fixture generation and the public display window will be unaffected. Uploads to the server will resume when the internet connection is restored.</p>"
# Write the sidebar, but not the normal sidebar, because that requires a # tourney, and we might not have a usable one. cgicommon.writeln("<div class=\"sidebar sqlsidebar\">") cgicommon.writeln("<div style=\"margin-bottom: 20px;\">") cgicommon.writeln( "<img src=\"/images/eyebergine128.png\" alt=\"Eyebergine\" />") cgicommon.writeln("</div>") cgicommon.writeln("<div class=\"sqlsidebarname\">") if tourney_name: cgicommon.writeln( "<a href=\"/cgi-bin/tourneysetup.py?tourney=%s\">%s</a>" % (urllib.parse.quote_plus(tourney_name), cgicommon.escape(tourney_name))) cgicommon.writeln("</div>") # Display list of tables and views, which can be expanded to show columns if db: for (tl, object_type) in ((tables, "Tables"), (views, "Views")): cgicommon.writeln("<div class=\"sqldictsection\">") cgicommon.writeln("<div class=\"sqldictsectionheading\">%s</div>" % (cgicommon.escape(object_type))) cgicommon.writeln("<ul class=\"sqldict\">") for tab in tl: tab_escaped = cgicommon.escape(tab.get_name()) tab_sq_escaped = "".join( [x if x != '\'' else '\\\'' for x in tab.get_name()]) cgicommon.writeln( "<li class=\"tablename handcursor\" onclick=\"clickTableName('%s');\"><span style=\"display: inline-block; min-width: 0.75em;\" id=\"table_expand_symbol_%s\">▸</span> %s</li>"
def get_user_form(tourney, settings, div_rounds): div_group_size = dict() div_init_max_rematches = dict() div_init_max_win_diff = dict() prev_settings = settings.get_previous_settings() for key in prev_settings: if key not in settings and key != "submit": settings[key] = prev_settings[key] rounds = tourney.get_rounds(); num_divisions = tourney.get_num_divisions() max_time = int_or_none(settings.get("maxtime", None)) ignore_rematches_before_round = int_or_none(settings.get("ignorerematchesbefore", None)) div_ready = [] for div in range(num_divisions): if div in div_rounds: div_ready.append(False) else: div_ready.append(True) default_group_size = int_or_none(settings.get("groupsize", None)) for div_index in sorted(div_rounds): group_size = int_or_none(settings.get("d%d_groupsize" % (div_index), None)) if group_size is None or group_size == 0: group_size = default_group_size init_max_rematches = int_or_none(settings.get("d%d_initmaxrematches" % (div_index), "0")) init_max_win_diff = int_or_none(settings.get("d%d_initmaxwindiff" % (div_index), 0)) games = tourney.get_games(game_type='P', division=div_index); players = [x for x in tourney.get_active_players() if x.division == div_index]; if max_time is not None and max_time > 0 and group_size in valid_group_sizes and (group_size == -5 or len(players) % group_size == 0): div_ready[div_index] = True # else: # if max_time is None or max_time == 0: # max_time = 30; # if group_size is None or group_size not in valid_group_sizes: # if len(players) % 3 == 0: # group_size = 3 # elif len(players) % 2 == 0: # group_size = 2 # elif len(players) % 5 == 0: # group_size = 5 # elif len(players) >= 8: # group_size = -5 # elif len(players) % 4 == 0: # group_size = 4 # else: # group_size = None div_group_size[div_index] = group_size div_init_max_rematches[div_index] = init_max_rematches div_init_max_win_diff[div_index] = init_max_win_diff if False not in div_ready and settings.get("submit") is not None: return None elements = []; javascript = """ <script type="text/javascript"> var click_time = 0; var limit_seconds = 0; var noticed_results_overdue = false; var gerunds = ["Reticulating", "Exaggerating", "Refrigerating", "Bisecting", "Reordering", "Unseeding", "Reconstituting", "Inverting", "Convolving", "Reinventing", "Overpopulating", "Unwedging", "Tenderising", "Refactoring", "Frobnicating", "Normalising", "Factorising", "Transforming", "Relaying", "Decoupling", "Randomising", "Ignoring", "Disposing of", "Translating", "Restarting", "Entertaining", "Checking", "Verifying", "Flushing", "Contextualising", "Deconstructing", "Justifying", "Hacking", "Redrawing", "Reimagining", "Reinterpreting", "Reasoning with", "Impersonating", "Abbreviating", "Underestimating", "Misappropriating", "Constructing", "Preparing", "Redelivering", "Arguing over", "Grilling", "Baking", "Poaching", "Washing", "Stealing", "Emulsifying", "Discombobulating", "Correcting", "Extracting", "Unspooling", "Descaling", "Duplicating", "Overwriting" ]; var nouns = ["seeding list", "rule book", "hypergrid", "network services", "timestamps", "multidimensional array", "decision tree", "player list", "weighting matrix", "instrument panel", "database", "videprinter", "standings table", "preclusion rules", "event handlers", "dynamic modules", "hypertext", "fixture generator", "linked lists", "hash tables", "system clock", "file descriptors", "syntax tree", "binary tree", "dictionary", "homework", "breakfast", "contextualiser", "splines", "supercluster", "record books", "sandwiches", "grouping strategy", "reality", "spatula", "Eyebergine", "scripts", "blockchain", "phone charger", "fixtures", "associative arrays", "browser window", "subfolders" ]; var endings = [ "Bribing officials", "Talking bollocks", "Feeding cat", "Rewinding tape", "Invading privacy", "Falling off cliff", "Kicking tyres", "Tapping barometer", "Serving hot", "Deploying parachute", "Cleaning up mess", "Straightening tie", "Seasoning to taste", "Stealing towels", "Reversing polarity", "Untangling headphones", "Compounding misery" ]; function spam_progress_label() { var progress = ""; var pc = 0; var ms_elapsed = 0; if (limit_seconds != NaN) { current_time = new Date(); ms_elapsed = current_time.getTime() - click_time.getTime(); pc = Math.floor(ms_elapsed * 100 / (limit_seconds * 1000)); if (pc > 100) { pc = 100; } progress = pc.toString() + "%"; } if (ms_elapsed < 500) { document.getElementById('progresslabel').innerHTML = "Generating fixtures..."; } else if (pc < 100) { if (Math.random() < 0.4) { var gerund = ""; var noun = ""; gerund = gerunds[Math.floor(Math.random() * gerunds.length)]; noun = nouns[Math.floor(Math.random() * nouns.length)]; document.getElementById('progresslabel').innerHTML = progress + " " + gerund + " " + noun + "..."; } } else if (ms_elapsed < limit_seconds * 1000 + 3000) { if (!noticed_results_overdue) { var ending = endings[Math.floor(Math.random() * endings.length)]; document.getElementById('progresslabel').innerHTML = "100% " + ending + "..."; noticed_results_overdue = true; } } else { document.getElementById('progresslabel').innerHTML = "We ought to have finished by now."; } } function generate_fixtures_clicked() { click_time = new Date(); noticed_results_overdue = false; limit_seconds = parseInt(document.getElementById('maxtime').value) * parseInt(document.getElementById('numdivisions').value); // document.getElementById('generatefixtures').disabled = true; spam_progress_label(); setInterval(function() { spam_progress_label(); }, 300); } </script>"""; elements.append(htmlform.HTMLFragment(javascript)); elements.append(htmlform.HTMLFragment("<h2>Overall settings</h2>")) div_valid_table_sizes = [] for div_index in sorted(div_rounds): div_players = [x for x in tourney.get_active_players() if x.get_division() == div_index] sizes = get_valid_group_sizes(len(div_players), len(rounds)) div_valid_table_sizes.append(sizes) table_sizes_valid_for_all_divs = [] for size in valid_group_sizes: for div_sizes in div_valid_table_sizes: if size not in div_sizes: break else: table_sizes_valid_for_all_divs.append(size) for size in (3, 2, 5, -5, 4): if size in table_sizes_valid_for_all_divs: default_default_group_size = size break else: default_default_group_size = None if num_divisions > 1 and len(table_sizes_valid_for_all_divs) > 0: elements.append(htmlform.HTMLFragment("<p>")) group_size_choices = [ htmlform.HTMLFormChoice(str(gs), "5&3" if gs == -5 else str(gs), int_or_none(settings.get("groupsize", default_default_group_size)) == gs) for gs in table_sizes_valid_for_all_divs ] elements.append(htmlform.HTMLFormRadioButton("groupsize", "Default players per table", group_size_choices)) elements.append(htmlform.HTMLFragment("</p>")) elements.append(htmlform.HTMLFragment("<p>\n")) elements.append(htmlform.HTMLFormTextInput("Fixture generator time limit %s(seconds)" % ("per division " if num_divisions > 1 else ""), "maxtime", settings.get("maxtime", "30"), other_attrs={"size": "3", "id" : "maxtime"})); elements.append(htmlform.HTMLFragment("</p>\n<p>\n")) elements.append(htmlform.HTMLFormTextInput("For the purpose of avoiding rematches, disregard games before round ", "ignorerematchesbefore", str(ignore_rematches_before_round) if ignore_rematches_before_round is not None else "", other_attrs={"size": "3"})); elements.append(htmlform.HTMLFragment(" (leave blank to count all rematches)")) elements.append(htmlform.HTMLFormHiddenInput("numdivisions", str(len(div_rounds)), other_attrs={"id" : "numdivisions"})) elements.append(htmlform.HTMLFragment("</p>\n")) elements.append(htmlform.HTMLFragment("<hr />\n")) for div_index in sorted(div_rounds): group_size = div_group_size[div_index] init_max_rematches = div_init_max_rematches[div_index] init_max_win_diff = div_init_max_win_diff[div_index] players = [x for x in tourney.get_active_players() if x.division == div_index]; div_prefix = "d%d_" % (div_index) if num_divisions > 1: elements.append(htmlform.HTMLFragment("<h2>%s (%d active players)</h2>" % (cgicommon.escape(tourney.get_division_name(div_index)), len(players)))) else: elements.append(htmlform.HTMLFragment("<h2>Fixture generation (%d active players)</h2>" % (len(players)))) elements.append(htmlform.HTMLFragment("<p>")) div_valid_sizes = get_valid_group_sizes(len(players), len(rounds)) ticked_group_size = int_or_none(settings.get(div_prefix + "groupsize")) if ticked_group_size is None: if len(table_sizes_valid_for_all_divs) > 0 and num_divisions > 1: # There is a "default table size" option ticked_group_size = 0 else: ticked_group_size = get_default_group_size(len(players), len(rounds)) group_size_choices = [ htmlform.HTMLFormChoice(str(gs), "5&3" if gs == -5 else str(gs), gs == ticked_group_size) for gs in div_valid_sizes ] if num_divisions > 1 and len(table_sizes_valid_for_all_divs) > 0: group_size_choices = [ htmlform.HTMLFormChoice("0", "Round default (above)", ticked_group_size == 0) ] + group_size_choices elements.append(htmlform.HTMLFormRadioButton(div_prefix + "groupsize", "Players per table", group_size_choices)) elements.append(htmlform.HTMLFragment("</p>\n")) elements.append(htmlform.HTMLFragment("<p>Increase the following values if the fixture generator has trouble finding a grouping within the time limit.</p>\n")); elements.append(htmlform.HTMLFragment("<blockquote>")) elements.append(htmlform.HTMLFormTextInput("Initial maximum rematches between players", div_prefix + "initmaxrematches", str(init_max_rematches), other_attrs={"size" : "3"})) elements.append(htmlform.HTMLFragment("</blockquote>\n<blockquote>")) elements.append(htmlform.HTMLFormTextInput("Initial maximum win count difference between players", div_prefix + "initmaxwindiff", str(init_max_win_diff), other_attrs={"size" : "3"})) elements.append(htmlform.HTMLFragment("</blockquote>\n")) if num_divisions > 1: elements.append(htmlform.HTMLFragment("<hr />\n")) elements.append(htmlform.HTMLFormSubmitButton("submit", "Generate Fixtures", other_attrs={"onclick": "generate_fixtures_clicked();", "id": "generatefixtures", "class" : "bigbutton"})); elements.append(htmlform.HTMLFragment("<p id=\"progresslabel\">For large numbers of players or unusual formats, fixture generation is not immediate - it can take up to the specified number of seconds, or longer if no permissible configurations are found in that time.</p><hr /><p></p>")); elements.append(htmlform.HTMLFragment("<noscript>Your browser doesn't have Javascript enabled, which means you miss out on progress updates while fixtures are being generated.</noscript>")); form = htmlform.HTMLForm("POST", "/cgi-bin/fixturegen.py", elements); return form;
cgicommon.show_sidebar(tourney, show_misc_table_links=True) cgicommon.writeln("<div class=\"mainpane\">") rd = tourney.get_current_round() if rd is None: cgicommon.writeln("<h1>Table assignment</h1>") cgicommon.writeln("<p>There are no fixtures yet.</p>") else: round_no = rd["num"] round_name = rd["name"] cgicommon.writeln("<h1>Table assignment: %s</h1>" % (cgicommon.escape(round_name))) games = tourney.get_games(round_no) # Map of player name -> list of table numbers they're on in this round player_name_to_table_list = dict() # Map of player name -> player object player_name_to_player = dict() # Map of table number -> list of players table_to_player_list = dict() for g in games: names = [] current_player_list = table_to_player_list.get(g.table_no, []) for p in [g.p1, g.p2]:
wikitext_date_y = today.year wikitext_game_prefix = "" for c in tourney_name.upper(): if c.isupper() or c.isdigit(): wikitext_game_prefix += c if wikitext_game_prefix[-1].isdigit(): wikitext_game_prefix += "." cgicommon.writeln("<div class=\"mainpane\">") cgicommon.writeln("<h1>Tournament report - Wikitext</h1>") if errors: cgicommon.writeln("<h2>Failed to generate wikitext...</h2>") cgicommon.writeln("<blockquote>") for txt in errors: cgicommon.writeln("<li>%s</li>" % (cgicommon.escape(txt))) cgicommon.writeln("</blockquote>") cgicommon.writeln("<p>") cgicommon.writeln( "Select the date the tournament was played, and a string to prefix each game ID. Then generate the wikitext for copy-pasting into a new wiki page." ) cgicommon.writeln("</p>") cgicommon.writeln( "<form method=\"GET\" action=\"/cgi-bin/export.py\">") cgicommon.writeln("<table>") cgicommon.writeln("<tr><td>Day</td><td>Month</td><td>Year</td></tr>") cgicommon.writeln("<tr>") cgicommon.writeln( "<td><input type=\"number\" name=\"wikitextday\" value=\"%d\" min=\"1\" max=\"31\" size=\"2\" /></td>" % (wikitext_date_d))
def fatal_error(text): cgicommon.print_html_head("Table Index") cgicommon.writeln("<body>") cgicommon.writeln("<p>%s</p>" % (cgicommon.escape(text))) cgicommon.writeln("</body></html>") sys.exit(1)
cgicommon.writeln("<body>") cgicommon.writeln("<h1>Welcome to Atropine</h1>") if cgicommon.is_client_from_localhost(): # Client is from localhost, so serve the administrator's front page, which # produces a menu of tournaments and the ability to create a new one. tourney_created = False if request_method == "POST" and tourneyname: try: tourney = countdowntourney.tourney_create(tourneyname, cgicommon.dbdir) tourney.close() cgicommon.show_success_box( "Tourney \"%s\" was created successfully." % cgicommon.escape(tourneyname)) cgicommon.writeln("<p>") cgicommon.writeln( '<a href="/cgi-bin/tourneysetup.py?tourney=%s">Click here to continue</a>' % urllib.parse.quote_plus(tourneyname)) cgicommon.writeln("</p>") tourney_created = True except countdowntourney.TourneyException as e: cgicommon.show_tourney_exception(e) if not tourney_created: # If name has been filled in, attempt to create tourney cgicommon.writeln("<h2>Create new tourney</h2>") cgicommon.writeln('<form action="%s" method="POST">' % cgicommon.escape(baseurl, True))
def get_user_form(tourney, settings): elements = [] num_players = settings.get("num_players") if num_players: try: num_players = int(num_players) num_players_in_tourney = len(tourney.get_active_players()) if num_players < 2 or num_players > num_players_in_tourney: elements.append( htmlform.HTMLFragment( "<p><strong>%d is an invalid number of players: must be between 2 and %d.</strong></p>" % (num_players, num_players_in_tourney))) num_players = None except ValueError: elements.append( htmlform.HTMLFragment( "<p><strong>The number of players must be a number.</strong></p>" )) num_players = None player_selection_mode = settings.get("player_sel_mode") if player_selection_mode not in ("topntable", "topnrating", "random", "manual"): player_selection_mode = None if not num_players: # Page 1 elements.append( htmlform.HTMLFormTextInput("How many players?", "num_players", "", other_attrs={"size": "4"})) elements.append(htmlform.HTMLFormSubmitButton("submit", "Submit")) elif not player_selection_mode: # Page 2 elements.append( htmlform.HTMLFragment( "<p>How do you want to pick these %d players?</p>" % num_players)) sel_options = [] sel_options.append( htmlform.HTMLFormDropDownOption( "topntable", "Top %d players by table position" % num_players)) sel_options.append( htmlform.HTMLFormDropDownOption( "topnrating", "Top %d players by rating" % num_players)) sel_options.append( htmlform.HTMLFormDropDownOption( "random", "%d players in a random draw" % num_players)) sel_options.append( htmlform.HTMLFormDropDownOption("manual", "Specify draw manually")) elements.append(htmlform.HTMLFragment("<p>")) elements.append( htmlform.HTMLFormDropDownBox("player_sel_mode", sel_options)) elements.append(htmlform.HTMLFormHiddenInput("page2", "1")) elements.append(htmlform.HTMLFragment("</p><p>")) elements.append(htmlform.HTMLFormSubmitButton("submit", "Pick Players")) elements.append(htmlform.HTMLFragment("</p>")) else: # Page 3 players = tourney.get_active_players() standings = tourney.get_standings() # If we've just come from page 2, decide on initial player names in # "settings" for seed1 ... seedN. if settings.get("page2"): del settings["page2"] if player_selection_mode == "topntable": seed = 1 for standing in standings[0:num_players]: settings["seed%d" % seed] = standing[1] seed += 1 elif player_selection_mode == "topnrating": players_by_rating = sorted(players, key=lambda x: x.rating, reverse=True) seed = 1 for p in players_by_rating[0:num_players]: settings["seed%d" % seed] = p.name seed += 1 elif player_selection_mode == "random": random_player_order = players[:] random.shuffle(random_player_order) seed = 1 for p in random_player_order[0:num_players]: settings["seed%d" % seed] = p.name seed += 1 all_seeds_set = True found_dupes = False seed_players = [None for i in range(num_players)] elements.append( htmlform.HTMLFragment( "<p>Use the following %d players in the knockout series...</p>" % num_players)) # Make N drop-down boxes, each containing the N players for seed_index in range(1, num_players + 1): keyname = "seed%d" % seed_index current_player_name = settings.get(keyname) if current_player_name: for p in players: if current_player_name == p.get_name(): break else: # Don't recognise this player current_player_name = None else: current_player_name = None if not current_player_name: all_seeds_set = False options = [] options.append( htmlform.HTMLFormDropDownOption("", "--- select player ---", current_player_name is None)) for standing in standings: player = tourney.get_player_from_name(standing[1]) player_string = "%d. %s (%d wins, %d draws, %d points)" % ( standing[0], player.get_name(), standing[3], standing[5], standing[4]) options.append( htmlform.HTMLFormDropDownOption( player.get_name(), player_string, (player.get_name() == current_player_name))) if player.get_name() == current_player_name: if player in seed_players: # player is already in seed_players, so we have # a duplicate found_dupes = True all_seeds_set = False seed_players[seed_index - 1] = player elements.append(htmlform.HTMLFragment("#%d " % seed_index)) elements.append( htmlform.HTMLFormDropDownBox("seed%d" % seed_index, options)) elements.append(htmlform.HTMLFragment("<br />")) if found_dupes: elements.append( htmlform.HTMLFragment( "<p><strong>Warning</strong>: one or more players appears more than once above. You need to fix this before generating fixtures.</p>" )) # Are any of the seeds involved in a tie? if player_selection_mode == "topntable": ties_mentioned = [] for p in seed_players: if p: player_standing = None for s in standings: if s[1] == p.name: player_standing = s break for s in standings: if (s[3] * 2 + s[5] == player_standing[3] * 2 + player_standing[5] and s[4] == player_standing[4] and s[1] != player_standing[1] and (s[1], player_standing[1]) not in ties_mentioned and (player_standing[1], s[1]) not in ties_mentioned): elements.append( htmlform.HTMLFragment( "<p><strong>Warning:</strong> %s and %s have the same number of wins and points and have been ordered arbitrarily.</p>" % (player_standing[1], s[1]))) ties_mentioned.append((s[1], player_standing[1])) elements.append(htmlform.HTMLFormSubmitButton("setseeds", "Save Order")) if all_seeds_set: # All seed positions have a player in them and no player appears # more than once. # Work out fixtures and display them. (rounds, fixtures) = generate_knockout(tourney, seed_players) if settings.get("generate"): # The fixtures have already been okayed, so nothing more to do return None html = "<h2>Fixture list</h2>\n" html += "<p>The following rounds will be generated</p>\n" html += "<blockquote>\n" for r in rounds: html += "<li>%s</li>\n" % cgicommon.escape(r["name"]) html += "</blockquote>\n" elements.append(htmlform.HTMLFragment(html)) html = "<p>The following fixtures will be generated</p>\n" prev_round_no = None html += "<table>" for g in fixtures: if g.round_no != prev_round_no: round_name = None for r in rounds: if r["round"] == g.round_no: round_name = r["name"] break if not round_name: round_name = "Round %d" % g.round_no html += "<tr><th colspan=\"4\">%s</td></tr>\n" % round_name prev_round_no = g.round_no html += "<tr>" html += "<td>%d</td>" % g.seq html += "<td>%s</td>" % str(g.p1) html += "<td>v</td>" html += "<td>%s</td>" % str(g.p2) html += "</tr>" html += "</table>" elements.append(htmlform.HTMLFragment(html)) elements.append( htmlform.HTMLFragment( "<p>Click the button below to proceed. On the next screen you can review the fixtures and accept them.</p>" )) elements.append( htmlform.HTMLFormSubmitButton("generate", "Yep, looks good to me")) else: if "generate" in settings: del settings["generate"] return htmlform.HTMLForm( "POST", "/cgi-bin/fixturegen.py?tourney=%s" % urllib.parse.quote_plus(tourney.name), elements)
div_active_player_count = [ len([ p for p in div_players[div_index] if not p.is_withdrawn() ]) for div_index in range(num_divisions) ] div_withdrawn_player_count = [ len([p for p in div_players[div_index] if p.is_withdrawn()]) for div_index in range(num_divisions) ] for div_index in range(num_divisions): div_name = tourney.get_division_name(div_index) cgicommon.writeln("<tr>") cgicommon.writeln("<td class=\"divsummaryname\">%s</td>" % (cgicommon.escape(div_name))) cgicommon.writeln( "<td class=\"divsummaryactiveplayers\">%d</td>" % (div_active_player_count[div_index])) cgicommon.writeln( "<td class=\"divsummarywithdrawnplayers\">%d</td>" % (div_withdrawn_player_count[div_index])) cgicommon.writeln("<td class=\"divsummaryrename\">") cgicommon.writeln( "<div class=\"divrenamecontrols\" id=\"divrenamecontrols%d\">" % (div_index)) cgicommon.writeln( "<form action=\"%s?tourney=%s\" method=\"POST\">" % (baseurl, urllib.parse.quote_plus(tourneyname))) cgicommon.writeln( "<input type=\"hidden\" name=\"tourney\" value=\"%s\" />" %
cgicommon.writeln("<div class=\"prefstaborderrow\">") cgicommon.writeln("<div class=\"prefstabordercontrol\">") cgicommon.writeln( "<input type=\"radio\" name=\"resultstab\" id=\"resultstab_%s\" value=\"%s\" %s />" % (option_tab_order, option_tab_order, "checked" if tab_order == option_tab_order else "")) cgicommon.writeln("<label for=\"resultstab_%s\">" % (option_tab_order)) cgicommon.writeln(" → ".join(field_name_list)) cgicommon.writeln("</label>") cgicommon.writeln("</div>") cgicommon.writeln("<div class=\"prefstaborderimage\">") cgicommon.writeln("<label for=\"resultstab_%s\">" % (option_tab_order)) cgicommon.writeln( "<img src=\"/images/taborder%d.png\" alt=\"%s\" />" % (idx + 1, cgicommon.escape("-".join(field_name_list), True))) cgicommon.writeln("</label>") cgicommon.writeln("</div>") cgicommon.writeln("</div>") cgicommon.writeln("<div class=\"prefsclear\"></div>") cgicommon.writeln("<div class=\"prefstaborderfooter\">") cgicommon.writeln( "Saved changes will take effect after you refresh the results entry page.") cgicommon.writeln("</div>") cgicommon.writeln("</div>") # preferencestaborder cgicommon.writeln("<div class=\"prefsfeedback\">") cgicommon.writeln("<span class=\"prefssaved\" id=\"prefssavedspan\">")