| #!/usr/bin/python |
| # |
| # Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| # for details. All rights reserved. Use of this source code is governed by a |
| # BSD-style license that can be found in the LICENSE file. |
| |
| """Generates CSSStyleDeclaration template file from css property definitions |
| defined in WebKit.""" |
| |
| import tempfile, os |
| |
| COMMENT_LINE_PREFIX = ' * ' |
| # TODO(efortuna): Pull from DEPS so that we have latest css *in sync* with our |
| # Dartium. Then remove the checked in CSSPropertyNames.in. |
| SOURCE_PATH = 'CSSPropertyNames.in' |
| #SOURCE_PATH = 'Source/WebCore/css/CSSPropertyNames.in' |
| TEMPLATE_FILE = '../templates/html/impl/impl_CSSStyleDeclaration.darttemplate' |
| |
| # Supported annotations for any specific CSS properties. |
| annotated = { |
| 'transition': '''@SupportedBrowser(SupportedBrowser.CHROME) |
| @SupportedBrowser(SupportedBrowser.FIREFOX) |
| @SupportedBrowser(SupportedBrowser.IE, '10') |
| @SupportedBrowser(SupportedBrowser.SAFARI)''' |
| } |
| |
| def camelCaseName(name): |
| """Convert a CSS property name to a lowerCamelCase name.""" |
| name = name.replace('-webkit-', '') |
| words = [] |
| for word in name.split('-'): |
| if words: |
| words.append(word.title()) |
| else: |
| words.append(word) |
| return ''.join(words) |
| |
| def GenerateCssTemplateFile(): |
| data = open(SOURCE_PATH).readlines() |
| |
| # filter CSSPropertyNames.in to only the properties |
| # TODO(efortuna): do we also want CSSPropertyNames.in? |
| data = [d[:-1] for d in data |
| if len(d) > 1 |
| and not d.startswith('#') |
| and not d.startswith('//') |
| and not '=' in d] |
| |
| class_file = open(TEMPLATE_FILE, 'w') |
| |
| class_file.write(""" |
| // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| // WARNING: DO NOT EDIT THIS TEMPLATE FILE. |
| // The template file was generated by scripts/css_code_generator.py |
| |
| // Source of CSS properties: |
| // %s |
| |
| part of $LIBRARYNAME; |
| |
| $(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS) class $CLASSNAME $EXTENDS with |
| $(CLASSNAME)Base $IMPLEMENTS { |
| factory $CLASSNAME() => new CssStyleDeclaration.css(''); |
| |
| factory $CLASSNAME.css(String css) { |
| final style = new Element.tag('div').style; |
| style.cssText = css; |
| return style; |
| } |
| |
| String getPropertyValue(String propertyName) { |
| var propValue = _getPropertyValueHelper(propertyName); |
| return propValue != null ? propValue : ''; |
| } |
| |
| String _getPropertyValueHelper(String propertyName) { |
| if (_supportsProperty(_camelCase(propertyName))) { |
| return _getPropertyValue(propertyName); |
| } else { |
| return _getPropertyValue(Device.cssPrefix + propertyName); |
| } |
| } |
| |
| /** |
| * Returns true if the provided *CSS* property name is supported on this |
| * element. |
| * |
| * Please note the property name camelCase, not-hyphens. This |
| * method returns true if the property is accessible via an unprefixed _or_ |
| * prefixed property. |
| */ |
| bool supportsProperty(String propertyName) { |
| return _supportsProperty(propertyName) || |
| _supportsProperty(_camelCase(Device.cssPrefix + propertyName)); |
| } |
| |
| bool _supportsProperty(String propertyName) { |
| $if DART2JS |
| return JS('bool', '# in #', propertyName, this); |
| $else |
| // You can't just check the value of a property, because there is no way |
| // to distinguish between property not being present in the browser and |
| // not having a value at all. (Ultimately we'll want the native method to |
| // return null if the property doesn't exist and empty string if it's |
| // defined but just doesn't have a value. |
| return _hasProperty(propertyName); |
| $endif |
| } |
| $if DARTIUM |
| |
| bool _hasProperty(String propertyName) => |
| _blink.BlinkCSSStyleDeclaration.$__propertyQuery___Callback_1(this, propertyName); |
| $endif |
| |
| @DomName('CSSStyleDeclaration.setProperty') |
| void setProperty(String propertyName, String value, [String priority]) { |
| if (_supportsProperty(_camelCase(propertyName))) { |
| return _setPropertyHelper(propertyName, value, priority); |
| } else { |
| return _setPropertyHelper(Device.cssPrefix + propertyName, value, |
| priority); |
| } |
| } |
| |
| static String _camelCase(String hyphenated) { |
| $if DART2JS |
| var replacedMs = JS('String', r'#.replace(/^-ms-/, "ms-")', hyphenated); |
| |
| var fToUpper = const JS_CONST( |
| r'function(_, letter) { return letter.toUpperCase(); }'); |
| return JS('String', r'#.replace(/-([\da-z])/ig, #)', replacedMs, fToUpper); |
| $else |
| // The "ms" prefix is always lowercased. |
| return hyphenated.replaceFirst(new RegExp('^-ms-'), 'ms-').replaceAllMapped( |
| new RegExp('-([a-z]+)', caseSensitive: false), |
| (match) => match[0][1].toUpperCase() + match[0].substring(2)); |
| $endif |
| } |
| |
| $if DART2JS |
| void _setPropertyHelper(String propertyName, String value, [String priority]) { |
| // try/catch for IE9 which throws on unsupported values. |
| try { |
| if (value == null) value = ''; |
| if (priority == null) { |
| priority = ''; |
| } |
| JS('void', '#.setProperty(#, #, #)', this, propertyName, value, priority); |
| // Bug #2772, IE9 requires a poke to actually apply the value. |
| if (JS('bool', '!!#.setAttribute', this)) { |
| JS('void', '#.setAttribute(#, #)', this, propertyName, value); |
| } |
| } catch (e) {} |
| } |
| |
| /** |
| * Checks to see if CSS Transitions are supported. |
| */ |
| static bool get supportsTransitions { |
| return document.body.style.supportsProperty('transition'); |
| } |
| $else |
| void _setPropertyHelper(String propertyName, String value, [String priority]) { |
| if (priority == null) { |
| priority = ''; |
| } |
| _setProperty(propertyName, value, priority); |
| } |
| |
| /** |
| * Checks to see if CSS Transitions are supported. |
| */ |
| static bool get supportsTransitions => true; |
| $endif |
| $!MEMBERS |
| } |
| |
| class _CssStyleDeclarationSet extends Object with CssStyleDeclarationBase { |
| final Iterable<Element> _elementIterable; |
| Iterable<CssStyleDeclaration> _elementCssStyleDeclarationSetIterable; |
| |
| _CssStyleDeclarationSet(this._elementIterable) { |
| _elementCssStyleDeclarationSetIterable = new List.from( |
| _elementIterable).map((e) => e.style); |
| } |
| |
| String getPropertyValue(String propertyName) => |
| _elementCssStyleDeclarationSetIterable.first.getPropertyValue( |
| propertyName); |
| |
| void setProperty(String propertyName, String value, [String priority]) { |
| _elementCssStyleDeclarationSetIterable.forEach((e) => |
| e.setProperty(propertyName, value, priority)); |
| } |
| // Important note: CssStyleDeclarationSet does NOT implement every method |
| // available in CssStyleDeclaration. Some of the methods don't make so much |
| // sense in terms of having a resonable value to return when you're |
| // considering a list of Elements. You will need to manually add any of the |
| // items in the MEMBERS set if you want that functionality. |
| } |
| |
| abstract class CssStyleDeclarationBase { |
| String getPropertyValue(String propertyName); |
| void setProperty(String propertyName, String value, [String priority]); |
| """ % SOURCE_PATH) |
| |
| class_lines = []; |
| |
| seen = set() |
| for prop in sorted(data, key=lambda p: camelCaseName(p)): |
| camel_case_name = camelCaseName(prop) |
| upper_camel_case_name = camel_case_name[0].upper() + camel_case_name[1:]; |
| css_name = prop.replace('-webkit-', '') |
| base_css_name = prop.replace('-webkit-', '') |
| |
| if base_css_name in seen or base_css_name.startswith('-internal'): |
| continue |
| seen.add(base_css_name) |
| |
| comment = ' /** %s the value of "' + base_css_name + '" */' |
| class_lines.append('\n'); |
| class_lines.append(comment % 'Gets') |
| if base_css_name in annotated: |
| class_lines.append(annotated[base_css_name]) |
| class_lines.append(""" |
| String get %s => |
| getPropertyValue('%s'); |
| |
| """ % (camel_case_name, css_name)) |
| |
| class_lines.append(comment % 'Sets') |
| if base_css_name in annotated: |
| class_lines.append(annotated[base_css_name]) |
| class_lines.append(""" |
| void set %s(String value) { |
| setProperty('%s', value, ''); |
| } |
| """ % (camel_case_name, css_name)) |
| |
| class_file.write(''.join(class_lines)); |
| class_file.write('}\n') |
| class_file.close() |