It is currently Sat Nov 30, 2024 11:57 pm

All times are UTC - 6 hours [ DST ]




Post new topic Reply to topic  [ 39 posts ]  Go to page Previous  1, 2
Author Message
PostPosted: Wed Dec 11, 2013 10:23 am 
Offline
Development Lead
User avatar

Joined: Sep 19, 2013
Posts: 1542
1) PHP
2) I'm a Magic person, no worries. :)

_________________
"In the beginning, there was nothing, which exploded." — Terry Pratchett


Like this post
Top
 Profile  
 
PostPosted: Wed Dec 11, 2013 12:41 pm 
Offline
Member
User avatar

Joined: Oct 02, 2013
Posts: 5379
Location: 1,824.5 meters underground.
Preferred Pronoun Set: Mr.
MrP,
I implore you this time to add a paypal button somewhere in there so we may donate.
You deserve something for your time other than virtual pats on the back.

_________________
It is better to remain silent and be thought a fool than to open one's mouth and remove all doubt. - Maurice Switzer


Come and enjoy the best of sim racing action. Please subscribe.
https://www.youtube.com/@shakeymark4969/videos
My band Shakey Deal YouTube channel
https://www.youtube.com/channel/UCBpPU1fbAjSPTfu3g0vubLw
Shakey Deal Facebook
https://www.facebook.com/ShakeyDeal.Neil.Young.tribute/


Like this post
Top
 Profile  
 
PostPosted: Sun Dec 15, 2013 11:39 am 
Offline
Member
User avatar

Joined: Nov 12, 2013
Posts: 100
Welder, I'm close to done with the spec, but I have run into an issue. User-defined CSS is not secure, and a simple regex is not going to make it so. So I need to come up with a workaround.

Is it possible to define a tag that renders, but cannot be entered by users? In that case, we can use that setting to mark the option1 tags that use custom CSS text.

A better option would be for you to intercept all [style] tags when posted and do a validation parse of the contents, with whitelisting of allowed properties and allowed values (one example among many: links in background-url properties must start with http(s): and not javascript:). There are probably libraries out there to make the CSS parsing easy.

Unfortunately, either of these choices may kill the ability for users (and my deck planner) to place inline styles on tags. I suppose you could intercept each of those tags at post time (e.g. tbody:cs and so on) and validate the inline style text.

I would really like to keep some sort of custom CSS capability since the deck planner needs it for custom colors, and occasionally for special output.


Like this post
Top
 Profile  
 
PostPosted: Sun Dec 15, 2013 12:45 pm 
Offline
Development Lead
User avatar

Joined: Sep 19, 2013
Posts: 1542
Is it possible to define a tag that renders, but cannot be entered by users?

No. If you allow users to enter any bbcodes, you allow them all.

Also, I don't see how this would be helpful. If it's put into the posting box (say, copy-pasted from your tool) then the software has no way to tell it wasn't entered by a person. If it's auto-generated on post submit, I'm planning on writing the code to do all the rendering myself (when I said it would 'produce all the nastiness of option 3a' I meant that we'd need to generate and encode basically the same set of information you'd already laid out, not that it would actually generate a giant pile of bbcode tags that the forum would render on post view).

Quote:
A better option would be for you to intercept all [style] tags when posted and do a validation parse of the contents, with whitelisting of allowed properties and allowed values (one example among many: links in background-url properties must start with http(s): and not javascript:). There are probably libraries out there to make the CSS parsing easy.

That's a possibility.

Quote:
Unfortunately, either of these choices may kill the ability for users (and my deck planner) to place inline styles on tags. I suppose you could intercept each of those tags at post time (e.g. tbody:cs and so on) and validate the inline style text.

This would be a huuuuuge pain.

Quote:
I would really like to keep some sort of custom CSS capability since the deck planner needs it for custom colors, and occasionally for special output.

Do you really need the full power of custom CSS for colors, or is there some limited set of color schemes you use? Ideally I'd like to be as flexible as possible, but if this is going to be a stopping point I'm OK with limiting people's options a little to get past it.

_________________
"In the beginning, there was nothing, which exploded." — Terry Pratchett


Like this post
Top
 Profile  
 
PostPosted: Sun Dec 15, 2013 3:09 pm 
Offline
Member
User avatar

Joined: Nov 12, 2013
Posts: 100
I'm planning on writing the code to do all the rendering myself (when I said it would 'produce all the nastiness of option 3a' I meant that we'd need to generate and encode basically the same set of information you'd already laid out, not that it would actually generate a giant pile of bbcode tags that the forum would render on post view).
Oh, whoops. I thought the plan was to take the fancydeck tag and transform it into a bunch of hidden option 1 tags, which would then generate the output at render time. The spec I'm writing was using option 1 tags as the target format.

Now I'm confused -- I thought there was no way to pre-cache HTML for a post. Could you explain the sequence of transformations, and what the output result will be? You start with the fancydeck tag that the user put in the post. What were you thinking would happen at post time, what gets stored in the post database, and what would happen at render time? For more complex deck planner layouts, I was planning to use some of the option 1 tags to create additional structure (e.g. my sealed deck example has an extra table at the bottom for unused colors).

I'll probably just post the spec with my current understanding later today, since it's so close to done. Once I see how you were thinking of handling the "nastiness", I can update the spec where necessary. If we're not translating the option 3 tag into option 1 tags, then I think some of these problems go away.

Quote:
Quote:
Unfortunately, either of these choices may kill the ability for users (and my deck planner) to place inline styles on tags. I suppose you could intercept each of those tags at post time (e.g. tbody:cs and so on) and validate the inline style text.

This would be a huuuuuge pain.
OK, I'll avoid this option. But if validating [style] tags is doable, I'm not sure why this is so much harder.

Quote:
Quote:
I would really like to keep some sort of custom CSS capability since the deck planner needs it for custom colors, and occasionally for special output.

Do you really need the full power of custom CSS for colors, or is there some limited set of color schemes you use? Ideally I'd like to be as flexible as possible, but if this is going to be a stopping point I'm OK with limiting people's options a little to get past it.
I've been assigning most decks unique color combinations to match the deck art and to keep e.g. multiple mono-green decks looking different from each other. Given what you said above, this may or may not be an issue any longer.


Like this post
Top
 Profile  
 
PostPosted: Sun Dec 15, 2013 3:40 pm 
Offline
Development Lead
User avatar

Joined: Sep 19, 2013
Posts: 1542
I need to head out in about five minutes (drafting Modern Masters! Woo!) so this is necessarily brief.

When the user submits a post, a function (that I'll write) will take the [fancydeck] tags, look up mana costs etc., encode that information, and store the encoded stuff in the database. The information stored will be essentially what you laid out in the option 3a stuff; how it's stored will depend on what's easy to encode/decode in php.

When they go to edit/quote a post with [fancydeck]s, a function (that I'll write) will take the encoded information, strip out all of the extra information added on post submit, and display something as close as possible to what was originally entered.

When the post is rendered, a function (that I'll write) will take the encoded information and convert it into pretty HTML. Doing this with a custom function rather than custom bbcodes allows us to avoid the limitations of using custom bbcodes. It should not be markedly slower than using custom bbcodes, either.

I will write up a more complete description when I get back. Sorry for not doing that earlier; I fear my poor communication has caused you to waste a nontrivial amount of time/effort. Well, on second thought, the spec will still be valuable regardless of what we do, as it provides a template for the HTML generation code.


Intercepting one tag ([style]) is much easier than intercepting multiple tags and inspecting/validating particular attributes of those tags.

_________________
"In the beginning, there was nothing, which exploded." — Terry Pratchett


Like this post
Top
 Profile  
 
PostPosted: Sun Dec 15, 2013 4:45 pm 
Offline
Member
User avatar

Joined: Nov 12, 2013
Posts: 100
Specification for [fancydeck]
This post contains all the details on the behavior and settings of the new fancydeck tag (CSS styles will be in a later post due to length). The desired result is modeled after the output of my Duels of the Planeswalkers deck planner, minus the header and footer text.

Image



Card database

Open Issues
  • #database-format? Decide whether to use JSON, CSV, a real database, or something else.
  • #data-source? Decide whether data comes from Gatherer or somewhere else.
  • #invalid-cards? Decide whether tables with unknown cards can be automatically updated or not.
  • #community-cards? Think about whether [fancydeck] can be modified to support community-created cards in the future.
Work items
  • #database-builder Create a tool to reconstruct the database.
  • #database-custom-fields Compute cost and type by the rules given here.

A database of all Magic cards is kept on the server. Since this database must be rebuilt every few weeks when new cards are released, an easy to use tool is needed to rebuild the database.

Here is an example card entry in JSON format.
  "Mikaeus, the Lunarch": {
    name: "Mikaeus, the Lunarch",
    manaSymbols: ["X", "W"],
    types: { "Legendary": true, "Creature": true },
    subtypes: { "Human": true, "Cleric": true },
    p: "0",
    t: "0",
    printings: [["ISD", "M", "247234"], ["V11", "M", "259296"]],
   
    // convenience properties derived from the above
    cmc: 1,
    cost: "X",
    type: "Creature",
    mid: "247234",
    rarity: "M",
    color: "W",
   
    // Trick property for grouping -- same value for all cards
    none: "none",
  }

The fields shown above can all be extracted from Gatherer's "compact" output format, although a few require parsing of HTML attribute values in the Gatherer output. Some information such as collector number is not available from Gatherer, so is not included in this example. A few notes about card properties:
  • p and t are the card's power and toughness. Non-creature cards use empty strings for these values. Non-integer values such as "{1+*}" are converted to "*" to keep the displayed results clean.
  • types includes supertypes such as Legendary. This is for convenience in building the database. The type line on a card separates supertypes/types from subtypes by a dash character, so there isn't a textual way to distinguish supertypes from types.
  • printings has one entry for each printing of the card, containing a set code, rarity, and mid (multiverse id).
  • cost is not exactly the Magic CMC value.
    Lands get a special cost of "Land". Cards with "X" in their mana cost are given a cost of "X" (because it's silly to list Fireball as a 1-drop). These special cost values improve the grouping and sorting of cards in the final output.
    A reminder of the CMC rules:
    • Numeric symbols add their numeric value to the CMC. (Take care parsing multi-digit symbols like "12"! Also be aware that there are joke cards with costs like "1,000,000" and "1 1/2". Handling the joke cards correctly is low priority, but mustn't cause any errors.)
    • Hybrid mana symbols use the higher of the two costs, so (2/W) adds 2, and (R/G) adds 1.
    • Phyrexian mana symbols like (U/P) count as 1.
    • X symbols count as zero in the standard rules, but we give such cards a special cost of "X".
    • Other symbols count as 1.
    • Cards with no mana symbols have a CMC of 0, but we give land cards a special cost of "Land".
    • A special value of "?" is used for unknown cards, but never appears in the database itself.
  • type is exactly one of the following: Planeswalker, Creature, Land, Spell, unknown. The special value "unknown" is used for unknown cards, but never appears in the database itself. If a card contains any of the first three among its types, that value is the type (chosen in priority order as listed if more than one is present). Cards with none of those three types are assigned the "Spell" type. This results in a single grouping for the remaining types such as Enchantment, Sorcery, and Instant.
  • mid of the most recent printing is repeated as a top level property.
  • rarity of the most recent printing is repeated as a top level property. I believe the possible values are "M", "R", "S" (timeshifted), "U", "C", "L" (land). Unknown cards get "?".
  • color is either "X" for colorless cards (including lands), or a subset of "WUBRG", with characters appearing in exactly that order.

Invalid card names
There is an important issue to resolve regarding spoilers. Upcoming cards are revealed by Wizards weeks before their set ships, but the data is not added to Gatherer until then. When using the [deck] tag, users can include any card name they wish, and the broken links will automatically begin working when the card appears in Gatherer.

However, because [fancydeck] output depends on card properties other than the name, we have to use placeholder data for unknown cards. The generated table will have invalid data and will place the card in the wrong group. When the card appears in Gatherer, the mouseover link will automatically work, but the table will still have incorrect values.

There are a few choices here, in increasing difficulty order.
  • Tables containing cards from the future remain broken. Users must edit and resubmit their posts when the set is released in order to regenerate the table with correct values.
  • Use a data source other than Gatherer that can be relied on to make daily updates as spoiled cards are released.
  • Provide a mechanism where users can supply the missing data (mana cost, power, toughness, type). This is an ugly option, but it would also allow users to use [fancydeck] with community-created cards, so it's worth thinking about.
  • Note at post time when a table contains unknown card entries. When the database is updated, rebuild posts as needed. (This is unlikely to be feasible.)

Unknown cards receive the following default properties.
  DEFAULT_CARD: {
    // name will always be specified by the user, so no default is needed
    manaSymbols: [],
    types: { "unknown": true },
    subtypes: {  },
    p: "",
    t: "",
    printings: [],
    cmc: 0,
    cost: "?",
    type: "unknown",
    mid: "0",
    rarity: "?",
    color: "X",
    none: "none",
  }




The main tag

Open Issues
  • #tag-name? Decide whether to name the tag [fancydeck], [decktable], or something else.
  • #server-side-colors? Can we convert HTML color names into rgb values on the server? Needed for the auto-text-contrast feature.
Work items
  • #fancydeck-tag Define the fancydeck tag
  • #fancydeck-parameter-parser Parse the parameters and generate missing color values if needed.
  • #fancydeck-body-parser Split the body of the fancydeck tag into main, sideboard, and epilog sections.
  • #fancydeck-main-parser Parse the tag's main section into card data structures.
  • #fancydeck-sideboard-parser Parse the tag's sideboard section into text/card data structures.
  • #auto-text-contrast Code to generate contrasting header-text-color
  • #test-auto-contrast Code to generate many background colors to test whether auto text colors are always legible.

A single new tag is visible to users. Instead of "fancydeck", you might choose to call the tag "decktable" or something else.

This tag has no rendered output, and does not need to support nesting. Since we have to manually parse the tag ourselves, I don't believe there's any benefit in defining the parameters using phpBB patterns.
Code:
[fancydeck]{TEXT}[/fancydeck]
[fancydeck={TEXT1}]{TEXT}[/fancydeck]

Parsing the tag parameters
The following parameterizations are accepted.
Code:
[fancydeck]
[fancydeck=grouping]
[fancydeck=grouping,header-color,light-color,medium-color]
[fancydeck=grouping,header-color,light-color,medium-color,dark-color]
The color parameters are either HTML color names or hex values, as with phpBB's {COLOR} type.
If no color parameters are given, all colors get default values from the CSS file.
If only the dark-color parameter is omitted, dark-color is set equal to medium-color.
If a header-color is given, a header-text-color value is automatically generated to ensure contrast.
Auto header text color wrote:
NOTE: This assumes that we can convert HTML color names to (r,g,b) values on the server side.

We use the W3 Accessibility formula for determining contrast. Our text colors are only black or white, which have L values of 0 or 1. The test is as follows.
  • r, g, and b are the 0-255 color components of header-color
  • rnorm = r/255; gnorm = g/255; bnorm = b/255;
  • R = (rnorm <= 0.03928) ? rnorm/12.92 : ((rnorm + 0.055)/1.055) ^ 2.4
  • G = (gnorm <= 0.03928) ? gnorm/12.92 : ((gnorm + 0.055)/1.055) ^ 2.4
  • B = (bnorm <= 0.03928) ? bnorm/12.92 : ((bnorm + 0.055)/1.055) ^ 2.4
  • L = 0.2126 * R + 0.7152 * G + 0.0722 * B
  • header-text-color = (L > 0.2) ? "#000000" : "#FFFFFF"
I have not tested this myself yet, so we need to generate a bunch of test colors and verify readability.


The grouping parameter matches phpBB's {IDENTIFIER} type.
The following values are accepted.
none_none | none_each | none_cost | none_type | none_category
cost_none | cost_each | | cost_type | cost_category
type_none | type_each | type_cost | | type_category
category_none | category_each | category_cost | category_type |

Users will probably use one of the following more convenient single-term synonyms. The single-term value is internally replaced by the two-term equivalent before proceeding.
none ==> none_none
each ==> none_each
cost ==> cost_type
type ==> type_cost
category ==> category_cost

If the grouping parameter is not given or if an invalid value is provided, it defaults to "cost_type".

The meanings of these values are described in the Card grouping section later in this document.

Parsing the tag body
The {TEXT} of the tag is first broken into up to three sections. Sections may be omitted, but they must appear in this order.
  • main includes all rows from the beginning up to one of the following delimiter lines.
  • sideboard begins with a line that contains only the word "sideboard" after trimming white space. The test is case insensitive.
  • epilog begins with a line that contains only the phrase "epilog_text", again after trimming and case insensitive. This section will generally only be used by my deck planner.

I don't know how phpBB handles platform variations in line break characters, but of course any of backslash-n, backslash-r, or backslash-r backslash-n should be accepted as line separators.

The main section is parsed into an ordered list of (name, count, category) structures.
A category variable is initialized as "(no category)".
A deckColors variable is initialized as empty (in JavaScript it would be { W:false,U:false,B:false,R:false,G:false,X:false }).
  • Lines with only whitespace are skipped.
  • Card lines (after trimming whitespace from the ends) have this form.
    (Example: "3x Lightning Bolt")
    1. required number
    2. optional whitespace
    3. optional "x", "X", or the &times; (backslash-xD7) character
    4. required whitespace
    5. required text
  • My deck planner needs an alternate format for card lines. The planner sometimes needs to color the count boxes separately to indicate special cards.
    (Example: "{#888, black, #fa3232} Lightning Bolt")
    1. required "{"
    2. required sequence of colors separated by commas and optional whitespace. The regex might be "([#a-zA-Z0-9]+)(?:s*,s*([#a-zA-Z0-9]+))*"
    3. required "}"
    4. required whitespace
    5. required text
    If this format is detected, save the array of color strings in the card entry as a "countColors" field. The "count" field is set to the length of this array.
  • Any other lines are treated as custom category labels. Whitespace is trimmed, and the line contents are assigned to the category variable.

As each card line is encountered, a card data structure is created with "name" and "count" fields taken from the line, and "category" taken from the current value of the category variable. If a card name is repeated on multiple lines, the first data structure has its "count" field incremented by the amount on the subsequent lines, but no new data structure is created for the duplicate lines.

In JavaScript I made these card data structures inherit from the cards in the database, so that "count" and "category" can be accessed in the same way as the base properties of the card such as "cost". Alternatively, the base card's properties could be copied into these data structures when they are created.

In addition, as each card line is encountered, the card's color is fetched and the deckColors variable is updated to include the colors present in the card. Only cards in the main section influence the deckColors.

The order of the custom category labels (starting with "(no category)") must be recorded for use as a custom sort order later on. See the Card grouping section below.

After all lines are read, the deckColors variable is updated. If none of WUBRG is present, ensure that X is present. If any of WUBRG is present, remove X.

The sideboard section is parsed into an ordered list of lines, which are either text or (name, count) structures.
  • Lines which match the card pattern given above have the name and count properties assigned. No category property exists.
  • Other lines--including whitespace lines--are added to the list as text entries.
Afterward, if the first entry in the list is not text, we prepend a text entry which contains "[b]Sideboard[/b] (NNN cards)". The NNN is replaced with the total of all card counts in the sideboard section.

The epilog section is not parsed, but does have whitespace trimmed from the ends.

Summary of parsing
The results of parsing a [fancydeck] tag are the following fields.
  • grouping - must be one of the valid two-part values
  • tableColors - header, header-text, light, medium, dark. These are either all valid colors, or all NULL.
  • deckColors - A string which is either "X" or a subset of "WUBRG" (with characters in that order).
  • main - A list of card entries
    • ("card name 1", count1, "category 1")
    • ("card name 2", count2, "category 2")
    • ...
  • sideboard - A list (possibly empty) of text/card entries
    • "text line 1"
    • "text line 2"
    • ("card name", count)
    • ("card name", count)
    • "text line 3"
    • ...
  • epilog - A single string



Data flow

Open Issues
  • (none)
Work items
  • #hidden-tag-stripper Code to strip out hidden tag blocks from post text.
  • #guid-generation Create a unique ID for each [fancydeck] tag.

For performance reasons, posts using the [fancydeck] tag are expanded into a block of hidden tags that can be rendered inexpensively. The user never sees the hidden tags.

At submission time, server code scans the submitted post text for [fancydeck] tags and parses them as described above. The data is analyzed and matched with the card database, and the card table is generated by inserting a block of hidden tags after the [fancydeck] tag. The details of this are given in a later section.

At rendering time, the [fancydeck] tag generates no output. The block of hidden tags generates the HTML table.

At edit time (including quoting), the block of hidden tags is stripped from the post body before presenting it to the user. When the user resubmits, the [fancydeck] tag is re-parsed from scratch, generating a new block of hidden tags.

It's worth thinking about possible failure modes here. One is that the block of hidden tags is not correctly stripped, which means that after each edit the card table (or fragments of it) would be duplicated. This would probably show up in the post edit box as spurious tags, which the user could manually delete.

A worse failure mode would be if multiple tables exist in a post, and the server code strips all text from the beginning of the first hidden block to the end of the last hidden block. This would delete all text that the user had included in between the tables--a severe error.

To reduce the chances of the second failure, each hidden block is delimited by [d_begin] and [d_end] tags, which contain a unique GUID generated from the user name and the time of posting. When the hidden block is to be stripped, the code reads the GUID from the [d_begin] tag and ensures that the [d_end] tag has a matching GUID before deletion.

This GUID is also used in the <style> tag for custom colors (see the Output generation section below). To make it a valid CSS class name, all non-alphanumeric characters are deleted.




The hidden tags

Open Issues
  • #css-security? Figure out how to do user-defined CSS validation
Work items
  • #css-regex Define the {CSS} regex for inline style text.
  • #define-hidden-tags Create the custom tags.

These custom tags generate the actual HTML output. Named parameters are used below for readability; they correspond to the following regex types.
  • stylesheet - {TEXT}
  • class - {SIMPLETEXT}
  • style - {CSS} a new custom regex


IMPORTANT: Allowing users to provide arbitrary CSS strings is not secure. We need to either validate all CSS text and whitelist allowed properties and values, or come up with some other solution. This section will require substantial changes.



A new {CSS} regex is created that matches inline style text. Note that inline styles can contain commas, so we must make sure that tags such as
    [tbl:cs=class-name,font-weight: bold; font-family: "Verdana", sans-serif;]
are always parsed correctly. If necessary, a pipe character can be used instead of a comma to separate the parameters.

All these tags support nesting, except for
  • d_begin
  • d_end
  • style
  • td (It is important that td not support nesting because there may be more than 255 of them in a single post. The td_nest tag is used when nesting is required.)

The [br] tag is used to break long table cells across lines, e.g. mana costs with more than 8 symbols.
Tag definitions






Card grouping

Open Issues
  • #grouping-design? Decide whether to use my recommended data structure or something different.
Work items
  • #group-data-structure Create the Group data structure
  • #group-add The routine to add a card to the hierarchy
  • #group-sort The routine to sort subgroups or cards
  • #sort-comparators Routines for all the custom sort orderings.
  • #group-debug-dump I found it very helpful to have a text dump of the hierarchy so I could see if things were working
  • #group-test-lists Put together several card lists to exercise all the features of the grouping system

With all those preliminaries completed, the meat of the task can be begun: organizing the cards and creating the output.

When a post is submitted, each [fancydeck] tag is parsed as described above. The resulting data structures are used to generate the hierarchical grouping which determines the structure of the output.

Doing the grouping and sorting in my deck planner was surprisingly difficult to get right, because I needed a very flexible system since it was used in many different places. Implementing something flexible here will make it trivial to add more grouping types in the future, including 0-, 1-, and 2-level hierarchies, so it's worth investing some extra time up front instead of hardcoding a lot of switch statements.

I'll describe a simplified version of the data structure that I used. This section is described at a finer level of detail than the rest of the spec--I hope that will be helpful as you implement the behavior.

The grouping process begins with the list of (name, count, category) entries parsed from the main section of the [fancydeck] tag.

Supported grouping patterns
The grouping and subgrouping of the output is determined by the [fancydeck]'s grouping parameter. The resulting output behavior is described in the table below.
none_none
    ["none", "none"]
      No headers
        No banding
        | none_each
          ["none", "name"]
            No headers
              Banding each row
              | none_cost
                ["none", "cost"]
                  No headers
                    Banding by cost
                    | none_type
                      ["none", "type"]
                        No headers
                          Banding by type
                          | none_category
                            ["none", "category"]
                              No headers
                                Banding by category

                                cost_none
                                  ["cost", "none"]
                                    Headers by cost
                                      No banding
                                      | cost_each
                                        ["cost", "name"]
                                          Headers by cost
                                            Banding each row
                                            | | cost_type
                                              ["cost", "type"]
                                                Headers by cost
                                                  Banding by type
                                                  | cost_category
                                                    ["cost", "category"]
                                                      Headers by cost
                                                        Banding by category

                                                        type_none
                                                          ["type", "none"]
                                                            Headers by type
                                                              No banding
                                                              | type_each
                                                                ["type", "name"]
                                                                  Headers by type
                                                                    Banding each row
                                                                    | type_cost
                                                                      ["type", "cost"]
                                                                        Headers by type
                                                                          Banding by cost
                                                                          | | type_category
                                                                            ["type", "category"]
                                                                              Headers by type
                                                                                Banding by category

                                                                                category_none
                                                                                  ["category", "none"]
                                                                                    Headers by category
                                                                                      No banding
                                                                                      | category_each
                                                                                        ["category", "name"]
                                                                                          Headers by category
                                                                                            Banding each row
                                                                                            | category_cost
                                                                                              ["category", "cost"]
                                                                                                Headers by category
                                                                                                  Banding by cost
                                                                                                  | category_type
                                                                                                    ["category", "type"]
                                                                                                      Headers by category
                                                                                                        Banding by type
                                                                                                        |

                                                                                                        Two special grouping styles deserve mention.
                                                                                                        • each - Makes every item its own group. This makes no sense at the main grouping level, so there are no "each_xxx" grouping values. Since card names are unique, the "name" property of each card is used as the subgrouping field in order to generate a subgroup for every card.
                                                                                                        • none - Indicates that no grouping should be done at this level, i.e. all entries belong to the same group. As a convenience trick, we assign every card in the database a "none" property, all with the same value. Thus when we group on the "none" property, all cards will naturally fall into a single group.
                                                                                                        The trick of using the "name" and "none" properties makes the correct grouping happen without special case code. However, there are still places where "each" and "none" require special behavior. These are mentioned where needed in later sections.

                                                                                                        A groupings variable is initialized from the second line of the appropriate table cell above. This array holds the card properties that drive the grouping and subgrouping in the output.

                                                                                                        Group data structure
                                                                                                        Define a recursive Group data structure.
                                                                                                        • level - The depth in the hierarchy of this group. The root Group is level 0.
                                                                                                        • parent - the parent of this Group.
                                                                                                        • children - an array of either cards or Groups
                                                                                                        • childrenGroupedBy - how the children are grouped (e.g. "cost", "type", etc.) If there are no subgroups, this is NULL.
                                                                                                        • childFromId - lookup hash to find a child group corresponding to a specific ID value (e.g. find the subgroup for "Creature")
                                                                                                        • siblingsGroupedBy - convenience property that always matches parent.childrenGroupedBy
                                                                                                        • groupId - the value of this Group among its siblings. (e.g. if siblingsGroupedBy=="cost", then 3 or "X" are possible values.) All cards in the subtree rooted at this Group have this value (e.g. cost of 3).
                                                                                                        • comparator - a sort comparator used to sort the children. Each allowed value of childrenGroupedBy corresponds to a different comparator.
                                                                                                        • cardCount - number of cards are contained in all descendants

                                                                                                        A rootGroup is created, with level=0, parent=NULL, childrenGroupedBy=groupings[0], siblingsGroupedBy = NULL. The hierarchy of child Groups gets created as we add cards to the structure.

                                                                                                        For each card entry from the tag's main section, call rootGroup.add(card, groupings), a function which does the following.
                                                                                                        • If there are no more grouping levels (i.e. this.level >= groupings.length):
                                                                                                          • Append the card to the this.children array. (This assumes no duplicate cards can occur, which was ensured in the parsing section above.)
                                                                                                          • Increment this.cardCount by the card's "count" entry.
                                                                                                          • Recursively increment cardCount of all ancestor Groups by the same amount.
                                                                                                        • If some grouping levels remain (this.level < groupings.length):
                                                                                                          • Let cardValue = the card's value for the this.childrenGroupedBy field.
                                                                                                          • Find the child Group corresponding to cardValue (using the childFromId hash).
                                                                                                            If the child doesn't exist, create it and initialize with
                                                                                                            • child.level = this.level + 1
                                                                                                            • child.parent = this
                                                                                                            • child.children = empty array
                                                                                                            • child.childrenGroupedBy = groupings[child.level] (NULL if we go past end of array)
                                                                                                            • child.childFromId = empty hash
                                                                                                            • child.siblingsGroupedBy = this.childrenGroupedBy
                                                                                                            • child.groupId = childValue
                                                                                                            • child.comparator is the appropriate sort comparator for child.childrenGroupedBy
                                                                                                            • child.cardCount = 0
                                                                                                          • Call child.add(card, groupings)

                                                                                                        Here are some examples of the resulting data structures.
                                                                                                        Note that the nested Groups and the cards will not be in the correct order at this point.
                                                                                                        Also note that since we only add Group structures when adding cards, every Group has at least one card in it (e.g. there is no Group with cost==2 in the first example).
                                                                                                        Grouping examples


                                                                                                        Custom sorting
                                                                                                        After all cards have been added, call rootGroup.sort(), which does the following.
                                                                                                        • If this Group's children are Groups (i.e. childrenGroupedBy != NULL), recursively call sort() on all children.
                                                                                                        • Sort this Group's children array.
                                                                                                          • If the children are Groups (childrenGroupedBy != NULL), sort by their groupId fields using the approprite custom sort comparator. See below for custom sort orderings.
                                                                                                          • If the children are cards (childrenGroupedBy == NULL), sort by their "name" fields.

                                                                                                        Depending on the value of childrenGroupedBy, one of the following sort orderings is used.
                                                                                                        • NULL - i.e., the children to be sorted are cards, not subgroups
                                                                                                          • The cards are alphabetically sorted by their "name" field. (My deck planner needed multi-key sorts in some places, but I don't think [fancydeck] ever needs complex card sorting.)
                                                                                                        • "none"
                                                                                                          • There will be only one child Group, so no sorting is necessary, but doing a sort anyway does no harm.
                                                                                                        • "name"
                                                                                                          • This grouping field is used when the user types "each" in the tag. Sort the child Groups alphabetically.
                                                                                                        • "cost"
                                                                                                          1. "Land"
                                                                                                          2. all numerical values (remember that 10 needs to sort after 9, not after 1)
                                                                                                          3. "X"
                                                                                                          4. "?"
                                                                                                          5. Any other values are invalid and should sort last if they occur.
                                                                                                          6. (Joke cards with weird costs can get sorted anywhere convenient, but mustn't cause errors.)
                                                                                                        • "type"
                                                                                                          1. "Planeswalker"
                                                                                                          2. "Creature"
                                                                                                          3. "Spell"
                                                                                                          4. "Land"
                                                                                                          5. "unknown"
                                                                                                          6. Any other values are invalid and should sort last if they occur.
                                                                                                        • "category"
                                                                                                          1. "(no category)"
                                                                                                          2. All other categories sort in the order they were provided by the user (not alphabetically). If the user duplicated a category label, all such cards will naturally fall into one subgroup if the above algorithm is followed. The custom sort order should ignore duplicate category labels gracefully.
                                                                                                        • "rarity" - this is not supported in the initial release, but might be added later
                                                                                                          1. "M"
                                                                                                          2. "R"
                                                                                                          3. "S"
                                                                                                          4. "U"
                                                                                                          5. "C"
                                                                                                          6. "L"
                                                                                                          7. "?" - for unknown cards
                                                                                                          8. Any other values are invalid and should sort last if they occur.
                                                                                                        • "color" - also not supported initially. This simply sorts by the color string, e.g. "B" < "URG" < "W" < "WU" < "X"



                                                                                                        Output generation

                                                                                                        Open Issues
                                                                                                        • #output-format? If the output format is not bbcodes, modify the templates accordingly.
                                                                                                        • #custom-stylesheet? Decide whether custom colors use a <style> tag or inline styles.
                                                                                                        • #template-system? Decide how to implement the templates
                                                                                                        Work items
                                                                                                        • #strip-template-whitespace Remove readability whitespace from the provided templates
                                                                                                        • #master-template Code to emit the master template and insert data.
                                                                                                        • #card-table-templates Code to emit pieces of the main table
                                                                                                        • #sideboard-templates Code to emit lines into the sideboard


                                                                                                        NOTE: Due to a bit of miscommunication, we may not be outputting hidden bbcode tags as assumed here. This section (and The hidden tags above) may need extensive revision.



                                                                                                        The output is inserted into the post immediately after the [/fancydeck] closing tag.

                                                                                                        Templates are given below for various fragments of the output. These templates could be implemented using a templating feature if PHP has one, or as functions that emit fixed strings interleaved with calls to sub-functions for the non-constant sections.

                                                                                                        I have added whitespace to the templates for readability, but the whitespace must be stripped before using the strings in actual code. This is because whitespace at certain points in the tag stream will actually affect the output, e.g. if it appears at the beginning of a <td>, or if line breaks in the template result in line breaks in the output. I believe that all whitespace must be stripped except for:
                                                                                                        • Spaces between class names in [xxx:c] tags that have multiple classes
                                                                                                        • Spaces between selectors in the [style] template

                                                                                                        Custom colors
                                                                                                        NOTE: Since arbitrary CSS can't be allowed (see The hidden tags above), this approach for custom colors may not work out.

                                                                                                        Custom colors can be included in the output in two different ways.
                                                                                                        • Prepend a <style> tag to override the colors. This requires a unique class name to be applied to the table, so that the stylesheet can target only that table.
                                                                                                        • Manually apply the custom colors to each [tbody] tag as an inline style.

                                                                                                        I suggest using the <style> tag, because then the table output does not need to change when custom colors are used. The GUID for the [d_begin] tag can be used to target the <style> selectors.

                                                                                                        Master template
                                                                                                        The overall structure of the output is given by the following template.
                                                                                                        Asterisks mark insertion points for non-constant data:
                                                                                                        • GUID - a unique ID as discussed above
                                                                                                        • STYLE - see the next template
                                                                                                        • CARD TABLE - see below
                                                                                                        • EPILOG TEXT - the epilog string from parsing the [fancydeck] tag
                                                                                                        • SIDEBOARD - see below

                                                                                                        Code:
                                                                                                        [d_begin]****** GUID ******[/d_begin]

                                                                                                        ****** STYLE ******

                                                                                                        [tbl:c=fancy-deck-wrapper *****GUID*****]
                                                                                                          [tbody]
                                                                                                            [tr]
                                                                                                              [td_nest]
                                                                                                                ******* CARD TABLE ******
                                                                                                                ******* EPILOG TEXT ******
                                                                                                              [/td_nest]
                                                                                                              [td_nest:c=fancy-deck-sideboard]
                                                                                                                ******* SIDEBOARD ******
                                                                                                              [/td_nest]
                                                                                                            [/tr]
                                                                                                          [/tbody]
                                                                                                        [/tbl]

                                                                                                        [d_end]******** GUID ******[/d_end]


                                                                                                        The STYLE entry uses the custom color values (header-color, header-text-color, light-color, medium-color, dark-color) and the same GUID as above. If custom colors are not being used, the STYLE entry is an empty string instead of this template.
                                                                                                        Code:
                                                                                                        [style]
                                                                                                          table.fancy-deck-wrapper.****GUID**** table.fancy-deck                    { border-color:     ****HEADER****; }
                                                                                                          table.fancy-deck-wrapper.****GUID**** table.fancy-deck tbody.header       { background-color: ****HEADER****; color: ****HEADER TEXT****; }
                                                                                                          table.fancy-deck-wrapper.****GUID**** table.fancy-deck tbody.odd          { background-color: ****LIGHT****; }
                                                                                                          table.fancy-deck-wrapper.****GUID**** table.fancy-deck tbody.even         { background-color: ****MEDIUM****; }
                                                                                                          table.fancy-deck-wrapper.****GUID**** table.fancy-deck tbody.Planeswalker { background-color: ****DARK****; }
                                                                                                          table.fancy-deck-wrapper.****GUID**** table.fancy-deck tbody.Creature     { background-color: ****LIGHT****; }
                                                                                                          table.fancy-deck-wrapper.****GUID**** table.fancy-deck tbody.Spell        { background-color: ****MEDIUM****; }
                                                                                                          table.fancy-deck-wrapper.****GUID**** table.fancy-deck tbody.Land         { background-color: ****DARK****; }
                                                                                                        [/style]




                                                                                                        Card table templates
                                                                                                        A series of fragments is emitted corresponding to the recursive Group structure given above, based on the level within the hierarchy.

                                                                                                        If custom colors are implemented with a <style> tag, these templates are the same whether or not the default colors are used. If you decide to use inline formatting for custom colors, the template text below includes the variants needed (but those variants should not be used when custom colors are not provided).



                                                                                                        From the single level-0 Group (the root):
                                                                                                        • HEADER COLOR - the custom header-color
                                                                                                        • DECK COLORS - the deckColors string: either a subset of "WUBRG", or "X"
                                                                                                        • CHILDREN - either level-1 Groups, or cards.
                                                                                                        Code:
                                                                                                        [tbl:c=fancy-deck ****DECK COLORS****]
                                                                                                          **** SEQUENCE OF CHILDREN ****
                                                                                                        [/tbl]

                                                                                                        (with inline custom colors)
                                                                                                        [tbl:cs=fancy-deck ****DECK COLORS****,border-color: ****HEADER COLOR****;]



                                                                                                        From each level-1 Group (the top level of grouping):
                                                                                                        • GROUP ID - taken from the Group.
                                                                                                          If the group ID is a cost, i.e. siblingsGroupedBy == "cost", then instead emit "[mc]****GROUP ID****[/mc] cost".
                                                                                                        • GROUP COUNT - a number taken from the Group, followed by either " card" if count==1, or " cards" otherwise.
                                                                                                        • HEADER COLOR - the custom header-color
                                                                                                        • HEADER TEXT COLOR - the custom header-text-color
                                                                                                        • CHILDREN - could be either level-2 Groups or cards (see below for both cases)
                                                                                                        Code:
                                                                                                          [tbody:c=header]
                                                                                                            [tr]
                                                                                                              [td:colspan=5]
                                                                                                                ****GROUP ID****[span:c=count]****GROUP COUNT****[/span]
                                                                                                              [/td]
                                                                                                            [/tr]
                                                                                                          [/tbody]
                                                                                                          **** SEQUENCE OF CHILDREN ****
                                                                                                         
                                                                                                          (with inline custom colors)
                                                                                                          [tbody:cs=header,background-color: ****HEADER COLOR****; color: ****HEADER TEXT COLOR****]
                                                                                                        Special case: If siblingsGroupedBy=="none", then do not emit the header [tbody]; only emit the children.



                                                                                                        From each level-2 Group (corresponding to subgroups):
                                                                                                        • SUBGROUP CLASS
                                                                                                          • odd/even - Alternate between "odd" and "even", with the first subgroup in each group always being "odd".
                                                                                                          • types - If siblingsGroupedBy=="type", a second class is added, equal to this.groupId: "Planeswalker", "Creature", "Spell", "Land", or "unknown".
                                                                                                          • invalid cards - Unknown cards will fall into a separate <tbody> in most cases, because they will have a "?" or "unknown" in their card properties. A special style highlights such <tbody>s as being invalid. To do this, an "invalid" class is added to the <tbody> for a subgroup if siblingsGroupedBy!="category" && (groupId=="?" || groupId=="unknown") on either the level-2 Group or its parent Group.
                                                                                                        • CHILDREN - Since we don't support nesting more than 2 levels deep, children are always cards.
                                                                                                        • SUBGROUP COLOR - (Only if inline styles are used for custom colors.) This also depends on siblingsGroupedBy.
                                                                                                          • type == "Planeswalker" Use dark-color
                                                                                                          • type == "Creature" Use light-color
                                                                                                          • type == "Spell" Use medium-color
                                                                                                          • type == "Land" Use dark-color
                                                                                                          • type == "unknown" Do not apply a background color, or use an invalid value.
                                                                                                          • (any other grouping type) - Alternate between light-color and medium-color, with the first subgroup in a group always being light-color.
                                                                                                        Code:
                                                                                                          [tbody:c=****SUBGROUP CLASS****]
                                                                                                            **** SEQUENCE OF CHILDREN ****
                                                                                                          [/tbody]
                                                                                                         
                                                                                                          (with inline custom colors)
                                                                                                          [tbody:cs=****SUBGROUP CLASS****,background-color: ****SUBGROUP COLOR****;]



                                                                                                        From each card:
                                                                                                        • FIRST ROW SUBGROUP ID - If this card's parent is a level-2 Group, and if this is the first child, emit the parent's groupId.
                                                                                                          But if the subgroup ID is a cost (i.e. the card's parent's siblingsGroupedBy=="cost"), then instead emit "[mc]****GROUP ID****[/mc] cost".
                                                                                                        • COUNT BOXES - emit a number of &#x25A0; characters matching the card's count field.
                                                                                                          If a countColors array is saved with the card, wrap each character in a <span style="color: *****COLOR*****">, with the COLOR taken from the array.
                                                                                                          If the count is larger than 8, instead emit the numeric count followed by &times; (ignore any countColors field in this case).
                                                                                                        • CARD NAME - Note the [c] and [/c] tags in the template
                                                                                                        • POWER/TOUGHNESS - If the card's power is not an empty string, emit the two values separated by "/".
                                                                                                          If the power is an empty string, emit nothing.
                                                                                                        • CARD COST - Emit the card's mana symbols, wrapped in [mc] and [/mc] tags. Symbols longer than one character must be wrapped in parentheses. If there are more than 8 symbols, after emitting half the symbols (rounded down), emit "...[br]..." to keep the table from getting too wide. (See the Rainbow 2013 deck in the deck planner for an example).
                                                                                                        Code:
                                                                                                            [tr]
                                                                                                              [td]**** FIRST ROW SUBGROUP ID****[/td]
                                                                                                              [td]**** COUNT BOXES *****[/td]
                                                                                                              [td][c]**** CARD NAME *****[/c][/td]
                                                                                                              [td]**** POWER/TOUGHNESS ****[/td]
                                                                                                              [td]**** CARD COST *****[/td]
                                                                                                            [/tr]
                                                                                                        Special case: If the level-2 Group above us has childrenGroupedBy=="name" or "none", then emit nothing in the FIRST ROW SUBGROUP position.



                                                                                                        Sideboard template
                                                                                                        The sideboard data is an ordered list of either text or card entries.
                                                                                                        For text entries, emit the following HTML
                                                                                                        Code:
                                                                                                        <p class="fancy-deck-sideboard-label">*****TEXT*****</p>

                                                                                                        For card entries, emit the following HTML
                                                                                                        Code:
                                                                                                        <p class="fancy-deck-sideboard-card">****COUNT****&times; <span class="autocard">****CARD NAME****</span></p>




                                                                                                        HTML vs BBcode
                                                                                                        This spec was originally written assuming that the output format would be BBcode, but the output format is actually going to be HTML. Most of what's written here translates smoothly into HTML, but a few issues do arise.

                                                                                                        The most important one is security. We can no longer rely on phpBB to sanitize user input, so we must carefully handle all user-entered text. In most cases the text simply needs to be HTML escaped before being emitted into the HTML stream. I believe these are the only potentially dangerous items.
                                                                                                        • Category labels
                                                                                                          These can be emitted in either the level-1 template (GROUP ID), or in the card template (FIRST ROW SUBGROUP ID).
                                                                                                        • Card names
                                                                                                          These are emitted in the card template and the sideboard template.
                                                                                                        • Sideboard labels
                                                                                                          Only emitted in the sideboard template.
                                                                                                        • Epilog text
                                                                                                          Only emitted in the master template.
                                                                                                        Card names require special treatment. A malicious user could include HTML code, so they must be escaped. However, two joke cards include the "&" character in the name, and escaping that will probably break autocarding. Perhaps card names should only escape the "<" and ">" characters.

                                                                                                        Another issue is that I don't think BBcode can be included in text strings since it gets directly emitted to HTML. That requires thinking about a few cases.
                                                                                                        • The templates above use the [mc] tags to generate mana symbols in the table when the group or subgroup type is "cost". I presume that the mana symbol images can be directly created instead.
                                                                                                        • My deck planner includes a link in the epilog_text that lets users instantly import a card list into the deck planner. However, this requires the use of the [url] tag. The URL can't be included raw in the text because it is very long (it encodes the entire deck list). I don't know enough about how you are handling the text to suggest workarounds.
                                                                                                        • A minor issue is that category and sideboard labels can't include formatting or [mc] tags. (So I'd have to slightly change the format of my sealed deck output, which used color symbols in the sideboard labels).
                                                                                                        If you have thoughts on encoding URLs please let me know. Perhaps it wouldn't be too hard to just search for "(http://S+)" and turn the matched string into an <a> tag?


                                                                                                        Last edited by MysteriousMisterP on Fri Dec 27, 2013 10:59 pm, edited 9 times in total.

                                                                                                        Like this post
                                                                                                        Top
                                                                                                         Profile  
                                                                                                         
                                                                                                        PostPosted: Sun Dec 15, 2013 4:46 pm 
                                                                                                        Offline
                                                                                                        Member
                                                                                                        User avatar

                                                                                                        Joined: Nov 12, 2013
                                                                                                        Posts: 100


                                                                                                        Default CSS

                                                                                                        Open Issues
                                                                                                          (none)
                                                                                                        Work items
                                                                                                        • #add-css-rules Add the CSS rules to the NGA stylesheet.
                                                                                                        • #default-colors Test all 32 sets of colors for legibility and aesthetics. Check if changing the site theme causes problems.
                                                                                                        • #tweak-css MysteriousMisterP will need a few iterations to settle on final values for all stylesheet properties.

                                                                                                        The output colors come from the stylesheet given here unless colors are provided in the [fancydeck] tag.

                                                                                                        Users of my deck planner seemed to enjoy having different colors for each of the game's decks. We can provide something similar by specifying different default colors for each of the 32 different possible color combinations in Magic. Placeholder colors are assigned below, but these will have to be revised once we see them in action to ensure that all of them are legible and reasonably attractive.

                                                                                                        Class names used:
                                                                                                        • fancy-deck-wrapper sets default formatting on the wrapper <table>
                                                                                                        • fancy-deck on a <table> applies the card list styles
                                                                                                        • fancy-deck-sideboard on a <td> applies the sideboard text styles
                                                                                                        • fancy-deck-sideboard-label and fancy-deck-sideboard-card on a <p> styles lines in the sideboard.
                                                                                                        • fancy-deck-group-count on a <span> for the dimmed card count field
                                                                                                        • header, odd, even, Planeswalker, Creature, Spell, Land, unknown on a <tbody> set the banding colors
                                                                                                        • (deck colors), a second class on the fancy-deck <table>, is either a subset of "WUBRG" or "X", used to default to one of the 32 color sets.

                                                                                                        fancydeck.css


                                                                                                        Last edited by MysteriousMisterP on Fri Dec 27, 2013 11:02 pm, edited 3 times in total.

                                                                                                        Like this post
                                                                                                        Top
                                                                                                         Profile  
                                                                                                         
                                                                                                        PostPosted: Sun Dec 15, 2013 10:49 pm 
                                                                                                        Offline
                                                                                                        Development Lead
                                                                                                        User avatar

                                                                                                        Joined: Sep 19, 2013
                                                                                                        Posts: 1542
                                                                                                        Out of curiosity, did you hit the character limit on the first post?



                                                                                                        OK, for the quick-and-easy open issues:
                                                                                                        • #database-format: We'll use a real database (MySQL). phpbb provides convenient ways to talk to MySQL.
                                                                                                        • #data-source: Probably magiccards.info. That way the information on printings can be reused to improve autocarding.
                                                                                                        • #tag-name: [fancydeck] should be fine.
                                                                                                        • #server-side-colors: Making an associative array to turn color names into RGB values should be good enough.

                                                                                                        _________________
                                                                                                        "In the beginning, there was nothing, which exploded." — Terry Pratchett


                                                                                                        Like this post
                                                                                                        Top
                                                                                                         Profile  
                                                                                                         
                                                                                                        PostPosted: Mon Dec 16, 2013 7:03 am 
                                                                                                        Offline
                                                                                                        Member
                                                                                                        User avatar

                                                                                                        Joined: Nov 12, 2013
                                                                                                        Posts: 100
                                                                                                        Out of curiosity, did you hit the character limit on the first post?
                                                                                                        Yep, the CSS file just got too long. Looks like I was at 66k total.

                                                                                                        Quote:
                                                                                                        #data-source: Probably magiccards.info. That way the information on printings can be reused to improve autocarding.
                                                                                                        Ok, gotcha. I went there and the first thing on the about page says "You can not get a copy of the database!", but I guess you have a plan :)


                                                                                                        Like this post
                                                                                                        Top
                                                                                                         Profile  
                                                                                                         
                                                                                                        PostPosted: Mon Dec 16, 2013 9:00 am 
                                                                                                        Offline
                                                                                                        Member
                                                                                                        User avatar

                                                                                                        Joined: Nov 12, 2013
                                                                                                        Posts: 100
                                                                                                        Specification change log

                                                                                                        Since the spec post is so long, I'll call out any changes made here so they don't get overlooked.

                                                                                                        2013 12 16 - Although backslashes appear in the preview form, they seem to get eaten when the post is submitted (even in a [code] tag). I have replaced the backslashes with "backslash-" in a few places: the linebreak characters that vanished from Parsing the tag body, and the multiplication character code (hex D7) in Parsing the tag body and Sideboard template.

                                                                                                        2013 12 16 - Added missing "invalid" entry to the reference list of classes in the CSS post (class is used in the output generation section)

                                                                                                        2013 12 16 - Added line breaking for cards with long mana costs to the card output template description.

                                                                                                        2013 12 23 - Revised the CSS file with better default color styles (some colors still missing).

                                                                                                        2013 12 27 - Made explicit that the sideboard templates should emit a <p>, with appropriate classes. Modified CSS file to use these new classes.
                                                                                                        2013 12 27 - Added alternate input format for card lines as "{#444, #000} Lightning Bolt" so deck planner can colorize the count boxes. Modifications to the tag parsing section and the card template section.
                                                                                                        2013 12 27 - Added new section to end on HTML vs BBcode


                                                                                                        Last edited by MysteriousMisterP on Fri Dec 27, 2013 11:08 pm, edited 2 times in total.

                                                                                                        Like this post
                                                                                                        Top
                                                                                                         Profile  
                                                                                                         
                                                                                                        PostPosted: Thu Dec 26, 2013 9:00 pm 
                                                                                                        Offline
                                                                                                        Member
                                                                                                        User avatar

                                                                                                        Joined: Nov 12, 2013
                                                                                                        Posts: 100
                                                                                                        Sample deck lists for testing
                                                                                                        For convenience, here are some deck lists that test a few of the special cases. This is definitely not a comprehensive list, though.

                                                                                                        Main, sideboard, and epilog
                                                                                                        Expect:
                                                                                                        • tag text broken into sections appropriately
                                                                                                        • color scheme based only on cards in main section
                                                                                                        • epilog text snug against table even though sideboard is long
                                                                                                        • Initial line of sideboard automatically adds "Sideboard (nnn cards)"
                                                                                                        • epilog still works when no sideboard section given
                                                                                                        Spoiler





                                                                                                        Counts and mana costs
                                                                                                        Expect:
                                                                                                        • count == 0 handled correctly (no boxes shown in count field)
                                                                                                        • large counts displayed as numbers rather than boxes
                                                                                                        • long mana costs broken over two lines
                                                                                                        • hybrid and phyrexian mana rendered correctly
                                                                                                        • multi-character mana symbols (e.g. ) rendered correctly (not as )

                                                                                                        Spoiler




                                                                                                        (no category)
                                                                                                        Expect: first group of cards to get "(no category)" label
                                                                                                        Spoiler






                                                                                                        Invalid cards
                                                                                                        Expect:
                                                                                                        • Groups and/or subgroups for invalid cards receive the "invalid" style with special formatting
                                                                                                        • Invalid cards in sideboard treated get no special treatment
                                                                                                        Spoiler








                                                                                                        Basic groupings
                                                                                                        Expect: missing and single-word groupings to group as specified
                                                                                                        Spoiler










                                                                                                        Two-part groupings
                                                                                                        Spoiler


                                                                                                        Like this post
                                                                                                        Top
                                                                                                         Profile  
                                                                                                         
                                                                                                        PostPosted: Thu Dec 26, 2013 9:14 pm 
                                                                                                        Offline
                                                                                                        Member
                                                                                                        User avatar

                                                                                                        Joined: Nov 12, 2013
                                                                                                        Posts: 100
                                                                                                        Color schemes
                                                                                                        MysteriousMisterP will use these examples to adjust the color styles, and to assign colors for the 4- and 5-color decks.


                                                                                                        Custom colors
                                                                                                        Expect: the user-provided colors to be used (gray header, red/green banding with blue used for land/planeswalker subgroups)

                                                                                                        NOTE: there may be a forum bug here, unless I'm missing something. The first spoiler tag here isn't working, and the whitespace between the spoiler and fancydeck tags (both opening and closing) is getting removed from the bbcode source after I preview the post, which shouldn't happen.
                                                                                                        [spoiler][fancydeck=cost,#888,#f00,#00ff00,blue]
                                                                                                        land
                                                                                                        4 Arctic Flats
                                                                                                        4 Boreal Shelf
                                                                                                        4 Frost Marsh

                                                                                                        colorless

                                                                                                        1 Karn Liberated

                                                                                                        1 Emrakul, the Aeons Torn

                                                                                                        white

                                                                                                        1 Ajani Goldmane

                                                                                                        1 Aegis of Honor
                                                                                                        2 Ajani's Pridemate
                                                                                                        3 Alaborn Trooper
                                                                                                        4 Altar's Light
                                                                                                        5 Angel of Flight Alabaster
                                                                                                        6 Angelic Skirmisher
                                                                                                        7 Arbiter of Knollridge
                                                                                                        8 Archangel's Light
                                                                                                        9 Blessed Wind

                                                                                                        blue

                                                                                                        1 Tezzeret the Seeker

                                                                                                        1 Abjure
                                                                                                        2 Accumulated Knowledge
                                                                                                        3 Anti-Magic Aura
                                                                                                        4 Aphetto Runecaster
                                                                                                        5 Arcane Melee
                                                                                                        6 Arcanis the Omnipotent
                                                                                                        7 Blatant Thievery
                                                                                                        8 Decree of Silence
                                                                                                        9 Denying Wind

                                                                                                        1 Disrupting Shoal
                                                                                                        [/fancydeck][/spoiler]




                                                                                                        Color schemes by type
                                                                                                        Expect: each table gets assigned the appropriate color style.

                                                                                                        Since the subgrouping is not by type in this case, only three colors are used (header, light, dark) from the CSS.
                                                                                                        By type










                                                                                                        Color schemes by cost
                                                                                                        Since the subgroups are by type in this case, the Land and Planeswalkers subgroups use a special fourth color.

                                                                                                        By cost


                                                                                                        Like this post
                                                                                                        Top
                                                                                                         Profile  
                                                                                                         
                                                                                                        PostPosted: Thu Dec 26, 2013 9:42 pm 
                                                                                                        Offline
                                                                                                        Member
                                                                                                        User avatar

                                                                                                        Joined: Nov 12, 2013
                                                                                                        Posts: 100
                                                                                                        Welder, even though you're not using the option 1 tags as an output format anymore, I'm leaving them in the spec for now since it should be easy to translate into the necessary HTML.

                                                                                                        There are a couple of issues related to that, but I hope they will not be a problem for you:



                                                                                                        I can use [fancydeck] for my normal deck output (using the custom color parameters), which will be great!

                                                                                                        However, look at a sealed deck example:
                                                                                                        Spoiler
                                                                                                        To build the extended sideboard below the table, I'm going to need some of the option 1 tags anyway. (I don't need the problematic ones with style data, just the vanilla and :c versions).

                                                                                                        I'm assuming that sealed deck functionality isn't something that should be built in to [fancydeck], so my deck planner will generate the extra bits. If you think the ability to post sealed decks with an automatic breakdown of used/unused sideboard colors would be useful, I can write up the details. It's obviously not that complicated, but it would probably take a few hours to implement.

                                                                                                        The extended sideboard table can be as large as 2 rows by 3 columns, depending on how many colors are unused.



                                                                                                        In the sideboard, I was planning to use a CSS hack to automatically indent the cards (it looks much less readable without the indentation). However, for this to work, each line needs to be its own <p> rather than separating the lines with <br>. Since you're generating the HTML yourself, I'll add a reminder to the spec about that.



                                                                                                        There is one more special case in the deck planner output that I forgot to mention until now. The Duels games have three kinds of cards.
                                                                                                        • Ordinary cards that you can freely add or remove
                                                                                                        • Fixed cards that must always be included
                                                                                                        • Promotional cards that are known to be coming in the future but cannot currently be used in-game
                                                                                                        The deck planner output colored the count boxes for fixed and promo cards. The special colors help prevent arguments like "You should take that weak card out" ("I know it's weak, but the game won't let you take it out") or "You made a mistake in your build--there is only 1 copy of that card" ("No, it's not a mistake. This list is for next month when the promos are out"). Without the colored boxes there's no way to tell if a build is currently legal within the game.

                                                                                                        To recreate that in [fancydeck], I need a small extension. Instead of giving a number for a card such as "3 Unsummon", accept a list of colors instead "{#888, #000, #f22} Unsummon". The card's count would be set to the number of colors given. The array of colors would be used to apply <span color="#xxx"> tags around each box character in the count field.

                                                                                                        I think this should be pretty easy.
                                                                                                        • Add a second regex test when parsing the card lines.
                                                                                                        • When populating the count <td> for the card with box characters, check to see if an array of colors was given. If so, wrap each box character with a <span> to color it.

                                                                                                        I'll add this to the spec later. I hope you'll be able to do it.

                                                                                                        Thanks.


                                                                                                        Like this post
                                                                                                        Top
                                                                                                         Profile  
                                                                                                         
                                                                                                        PostPosted: Fri Dec 27, 2013 11:07 pm 
                                                                                                        Offline
                                                                                                        Member
                                                                                                        User avatar

                                                                                                        Joined: Nov 12, 2013
                                                                                                        Posts: 100
                                                                                                        I've updated the spec with my notes from the previous post.

                                                                                                        I've also added a small section to the end on HTML vs BBcode with a couple of important issues on HTML security and a little problem I have with emitting urls since we're not using BBcode.

                                                                                                        All changes are listed in the change log post above. I'm not sure if you've already started work on this, so I'm trying to be very careful making changes to the spec since I don't want to create confusion once you get deep into things.


                                                                                                        Like this post
                                                                                                        Top
                                                                                                         Profile  
                                                                                                         
                                                                                                        PostPosted: Sat Dec 28, 2013 1:45 am 
                                                                                                        Offline
                                                                                                        Development Lead
                                                                                                        User avatar

                                                                                                        Joined: Sep 19, 2013
                                                                                                        Posts: 1542
                                                                                                        I'm not sure if you've already started work on this, so I'm trying to be very careful making changes to the spec since I don't want to create confusion once you get deep into things.

                                                                                                        I have not yet begun working directly on this — I've been doing smaller things* that are similar to parts of what fancydecks will need, in order to get some experience actually working with the systems. I've also done some work on scraping magiccards.info (in a slow-but-polite way) for the card database. And, y'know, working my real job and celebrating the holidays.

                                                                                                        And yes, I know, there's a bug with the spoiler tag. It just uses a normal HTML replacement, plus a mod to allow nesting a tag inside of the same tag (for nested spoilers). Unfortunately, the mod is kind of dumb and if you use [spoiler] and [spoiler=foo] in the same post, it gets very confused about which end tag corresponds to which start tag and claims it's invalid bbcode.**

                                                                                                        * [card], [mc], and [deck] are now handled in the bbcode engine directly instead of using standard HTML replacements.
                                                                                                        ** this weekend I want to move [spoiler] into the bbcode engine as well, which should fix this issue.

                                                                                                        _________________
                                                                                                        "In the beginning, there was nothing, which exploded." — Terry Pratchett


                                                                                                        Like this post
                                                                                                        Top
                                                                                                         Profile  
                                                                                                         
                                                                                                        PostPosted: Sat Dec 28, 2013 2:25 am 
                                                                                                        Offline
                                                                                                        Member
                                                                                                        User avatar

                                                                                                        Joined: Nov 12, 2013
                                                                                                        Posts: 100
                                                                                                        I'm not sure if you've already started work on this, so I'm trying to be very careful making changes to the spec since I don't want to create confusion once you get deep into things.

                                                                                                        I have not yet begun working directly on this — I've been doing smaller things* that are similar to parts of what fancydecks will need, in order to get some experience actually working with the systems.

                                                                                                        Ah, good! I don't feel so bad about making tweaks to the document then. As I said before, there's no rush as far as I'm concerned.

                                                                                                        Do let me know if you discover anything that seems to be an obstacle, and we can try to figure things out.

                                                                                                        Enjoy the new year!


                                                                                                        Like this post
                                                                                                        Top
                                                                                                         Profile  
                                                                                                         
                                                                                                        PostPosted: Tue Oct 07, 2014 2:15 pm 
                                                                                                        Offline
                                                                                                        Member
                                                                                                        User avatar

                                                                                                        Joined: Oct 31, 2013
                                                                                                        Posts: 7350
                                                                                                        Location: Newfoundland
                                                                                                        Now that this is up-and-running for D15, are there any plans to expand it to the rest of Magic in general? Just curious, I'm certainly grateful for all the hard work you've put in to make this possible.

                                                                                                        _________________
                                                                                                        Check me out on YouTube


                                                                                                        Like this post
                                                                                                        Top
                                                                                                         Profile  
                                                                                                         
                                                                                                        PostPosted: Tue Oct 07, 2014 5:12 pm 
                                                                                                        Offline
                                                                                                        Member
                                                                                                        User avatar

                                                                                                        Joined: Nov 12, 2013
                                                                                                        Posts: 100
                                                                                                        Hakeem928 wrote:
                                                                                                        Now that this is up-and-running for D15, are there any plans to expand it to the rest of Magic in general? Just curious, I'm certainly grateful for all the hard work you've put in to make this possible.

                                                                                                        It's unlikely. To make this work, the NGA folks would have to re-implement features of my deck planner on the server side, using a different programming language. Probably over 2000 lines of the planner code would need to be rebuilt (card database, card arrangement, and table construction). The spec I wrote above would spare them a lot of design effort, but there would still be substantial development time needed.

                                                                                                        A second minor issue is that the custom forum tags used by the planner are very specific to the planner's needs. This may be hard to believe, but that huge block of tag soup generated by the planner would be a lot longer if I'd used more general purpose tags. So even if someone made an independent tool that used the existing tags, it wouldn't work--new tags would have to be created.


                                                                                                        Like this post
                                                                                                        Top
                                                                                                         Profile  
                                                                                                         
                                                                                                        Display posts from previous:  Sort by  
                                                                                                        Post new topic Reply to topic  [ 39 posts ]  Go to page Previous  1, 2

                                                                                                        All times are UTC - 6 hours [ DST ]


                                                                                                        You cannot post new topics in this forum
                                                                                                        You cannot reply to topics in this forum
                                                                                                        You cannot edit your posts in this forum
                                                                                                        You cannot delete your posts in this forum
                                                                                                        You cannot post attachments in this forum

                                                                                                        Jump to:  
                                                                                                        Powered by phpBB® Forum Software © phpBB Group