CounterStyle.define constructor
CounterStyle.define({})
A simple way to define CounterStyle. Based off of systems defined at https://www.w3.org/TR/css-counter-styles-3/#counter-style-system
Implementation
factory CounterStyle.define({
/// The name of the system. Not used internally, but could be used in a
/// list of CounterStyle's to lookup a given style.
required String name,
/// The system type. See [System] for more details.
System system = System.symbolic,
/// The character to prepend to negative values.
String negative = '-',
// TODO add negativeSuffix
/// A prefix to add when generating marker content
String prefix = '',
/// A suffix to add when generating marker content (Defaults to
/// a full stop followed by a space: ". ").
String suffix = '\u002E\u0020',
/// The range of values this CounterStyle can accept. If a counter value is
/// given outside of this range, then the CounterStyle will fall back on
/// the CounterStyle defined by [fallback].
///
/// If null, defaults to the given [System]'s range
IntRange? range,
/// The length each output must have at minimum, including negative symbols, but not
/// including any suffix or prefix symbols.
/// padLength must be greater than or equal to 0.
int padLength = 0,
/// The character with which to pad the output to reach the given padLength.
/// If more than one character is given in [padCharacter], then the output
/// will be longer than [padLength] (but never shorter).
String padCharacter = '',
/// The CounterStyle to fall back on if the given algorithm can't compute
/// an output or is given out-of-range input.
String fallback = 'decimal',
/// The list of symbols used by this algorithm
List<String> symbols = const [],
/// A map of weights to symbols used by the additive algorithm
Map<int, String> additiveSymbols = const {},
//TODO speak-as descriptor (https://www.w3.org/TR/css-counter-styles-3/#counter-style-speak-as)
}) {
assert(padLength >= 0);
assert(symbols.isNotEmpty || additiveSymbols.isNotEmpty);
range ??= system.range;
algorithm(int count) {
if (!range!.withinRange(count)) {
return CounterStyleRegistry.lookup(fallback)._algorithm(count);
}
switch (system) {
case System.cyclic:
assert(symbols.isNotEmpty);
return symbols[(count - 1) % symbols.length];
case System.fixed:
assert(symbols.isNotEmpty);
//TODO this could potentially be defined by the user (see https://www.w3.org/TR/css-counter-styles-3/#fixed-system)
int firstSymbolValue = 1;
if (count >= firstSymbolValue &&
count < firstSymbolValue + symbols.length) {
return symbols[count - firstSymbolValue];
} else {
return CounterStyleRegistry.lookup(fallback)._algorithm(count);
}
case System.numeric:
assert(symbols.length >= 2);
int n = symbols.length;
String result = '';
int value = count;
if (value == 0) {
result = symbols[0];
}
while (value != 0) {
result = '${symbols[value % n]}$result';
value = value ~/ n;
}
return result;
case System.alphabetic:
assert(symbols.length >= 2);
int n = symbols.length;
String result = '';
int value = count;
while (value != 0) {
value--;
result = '${symbols[value % n]}$result';
value = value ~/ n;
}
return result;
case System.symbolic:
int n = symbols.length;
final representation = StringBuffer();
for (int i = 0; i < ((count ~/ n) + 1); i++) {
representation.write(symbols[(count - 1) % n]);
}
return representation.toString();
case System.additive:
assert(additiveSymbols.isNotEmpty);
int value = count;
final tuples = additiveSymbols.entries;
if (value == 0) {
if (additiveSymbols.containsKey(0)) {
return additiveSymbols[0]!;
}
return CounterStyleRegistry.lookup(fallback)._algorithm(count);
}
final buffer = StringBuffer();
for (var tuple in tuples) {
final weight = tuple.key;
final symbol = tuple.value;
if (weight == 0 || weight > value) continue;
final reps = value ~/ weight;
for (int i = 0; i < reps; i++) {
buffer.write(symbol);
}
value -= weight * reps;
if (value == 0) {
return buffer.toString();
}
}
return CounterStyleRegistry.lookup(fallback)._algorithm(count);
}
}
return CounterStyle._(
name: name,
algorithm: algorithm,
negative: negative,
prefix: prefix,
suffix: suffix,
range: range,
padLength: padLength,
padCharacter: padCharacter,
usesNegative: system.usesNegative,
fallbackStyle: fallback,
);
}