i18n-element
Version:
I18N Base Element for lit-html and Polymer
21,864 lines • 737 kB
HTML
<html lang="en" preferred=""><head><!--
@license https://github.com/t2ym/i18n-behavior/blob/master/LICENSE.md
Copyright (c) 2016, Tetsuya Mori <t2y3141592@gmail.com>. All rights reserved.
-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<script>
/*!
* @license https://github.com/t2ym/i18n-behavior/blob/master/LICENSE.md
* Copyright (c) 2016, Tetsuya Mori <t2y3141592@gmail.com>. All rights reserved.
*/
</script>
<script src="../../../webcomponentsjs/webcomponents-lite.min.js"></script>
<script src="../../../wct-browser-legacy/browser.js"></script>
<script>"use strict";
var fakeServerContents =
{
"/commented-simple-text-element/commented-simple-text-element.json": "{\n \"meta\": {},\n \"model\": {},\n \"text\": \" outermost text at the beginning \",\n \"h1_3\": \"outermost header 1\",\n \"text_4\": \" outermost text in the middle \",\n \"span_5\": \"simple text without id\",\n \"span_6\": \"simple text without id 2\",\n \"label-1\": \"simple text with id\",\n \"label-2\": \"simple text with id 2\",\n \"div_9:span\": \"simple text within div\",\n \"div_9:span_1\": \"simple text within div 2\",\n \"div_9:div_2:div\": \"great grandchild text within div\",\n \"div_10:text\": \" simple text as the first element in div \",\n \"div_10:span_1\": \"simple text within div\",\n \"div_10:text_2\": \" simple text in the middle of div \",\n \"div_10:span_3\": \"simple text within div 2\",\n \"div_10:div_4:div\": \"great grandchild text within div\",\n \"div_10:text_5\": \" simple text at the last element in div \",\n \"toplevel-div:span\": \"simple text within div\",\n \"toplevel-div:span_1\": \"simple text within div 2\",\n \"third-level-div\": \"great grandchild text within div\",\n \"second-level-div:div_1\": \"great grandchild text within div without id\",\n \"div_12:ul:li\": \"line item without id 1\",\n \"div_12:ul:li_1\": \"line item without id 2\",\n \"div_12:ul:li_2\": \"line item without id 3\",\n \"line-items:li\": \"line item with id 1\",\n \"line-items:li_1\": \"line item with id 2\",\n \"line-items:li_2\": \"line item with id 3\",\n \"p_13\": [\n \"A paragraph with {1} is converted to {2}.\",\n \"parameters\",\n \"<i18n-format>\"\n ],\n \"paragraph\": [\n \"A paragraph with {1} is converted to {2}.\",\n \"id\",\n \"<i18n-format>\"\n ],\n \"text_15\": \" outermost text at the end \"\n}",
"/commented-simple-text-element/locales/commented-simple-text-element.fr.json": "{\n \"model\": {},\n \"text\": \"fr outermost text at the beginning \",\n \"h1_3\": \"fr outermost header 1\",\n \"text_4\": \"fr outermost text in the middle \",\n \"span_5\": \"fr simple text without id\",\n \"span_6\": \"fr simple text without id 2\",\n \"label-1\": \"fr simple text with id\",\n \"label-2\": \"fr simple text with id 2\",\n \"div_9:span\": \"fr simple text within div\",\n \"div_9:span_1\": \"fr simple text within div 2\",\n \"div_9:div_2:div\": \"fr great grandchild text within div\",\n \"div_10:text\": \"fr simple text as the first element in div \",\n \"div_10:span_1\": \"fr simple text within div\",\n \"div_10:text_2\": \"fr simple text in the middle of div \",\n \"div_10:span_3\": \"fr simple text within div 2\",\n \"div_10:div_4:div\": \"fr great grandchild text within div\",\n \"div_10:text_5\": \"fr simple text at the last element in div \",\n \"toplevel-div:span\": \"fr simple text within div\",\n \"toplevel-div:span_1\": \"fr simple text within div 2\",\n \"third-level-div\": \"fr great grandchild text within div\",\n \"second-level-div:div_1\": \"fr great grandchild text within div without id\",\n \"div_12:ul:li\": \"fr line item without id 1\",\n \"div_12:ul:li_1\": \"fr line item without id 2\",\n \"div_12:ul:li_2\": \"fr line item without id 3\",\n \"line-items:li\": \"fr line item with id 1\",\n \"line-items:li_1\": \"fr line item with id 2\",\n \"line-items:li_2\": \"fr line item with id 3\",\n \"p_13\": [\n \"fr A paragraph with {1} is converted to {2}.\",\n \"fr parameters\",\n \"fr <i18n-format>\"\n ],\n \"paragraph\": [\n \"fr A paragraph with {1} is converted to {2}.\",\n \"fr id\",\n \"fr <i18n-format>\"\n ],\n \"text_15\": \"fr outermost text at the end \"\n}\n",
"/compound-binding-dom-bind.json": "{\n \"meta\": {},\n \"model\": {},\n \"text\": [\n \" outermost text at the beginning with compound {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"h1_3\": [\n \"outermost header 1 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"text_4\": [\n \" outermost text in the middle with {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"span_5\": [\n \"simple text without id with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"span_6\": [\n \"simple text without id 2 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"label-1\": [\n \"simple text with id and {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"label-2\": [\n \"simple text with id and {1} and {2} variables 2\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_9:span\": [\n \"simple text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_9:span_1\": [\n \"simple text within div with {1} and {2} variables 2\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_9:div_2:div\": [\n \"great grandchild text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:text\": [\n \" simple text as the first element in div with {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:span_1\": [\n \"simple text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:text_2\": [\n \" simple text in the middle of div with {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:span_3\": [\n \"simple text within div with {1} and {2} variables 2\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:div_4:div\": [\n \"great grandchild text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:text_5\": [\n \" simple text at the last element in div with {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"toplevel-div:span\": [\n \"simple text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"toplevel-div:span_1\": [\n \"simple text within div 2 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"third-level-div\": [\n \"great grandchild text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"second-level-div:div_1\": [\n \"great grandchild text within div without id with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_12:ul:li\": [\n \"line item without id 1 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_12:ul:li_1\": [\n \"line item without id 2 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_12:ul:li_2\": [\n \"line item without id 3 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"line-items:li\": [\n \"line item with id 1 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"line-items:li_1\": [\n \"line item with id 2 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"line-items:li_2\": [\n \"line item with id 3 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"p_13\": [\n \"A paragraph with {1} is converted to {2}.\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"paragraph\": [\n \"A paragraph with {1}, {2}, and {3} is converted to {4}.\",\n \"id\",\n \"{{param1}}\",\n \"{{param2}}\",\n \"<i18n-format>\"\n ],\n \"text_15\": [\n \" outermost text at the end with {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ]\n}",
"/compound-binding-element/compound-binding-element.json": "{\n \"meta\": {},\n \"model\": {},\n \"text\": [\n \" outermost text at the beginning with compound {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"h1_3\": [\n \"outermost header 1 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"text_4\": [\n \" outermost text in the middle with {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"span_5\": [\n \"simple text without id with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"span_6\": [\n \"simple text without id 2 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"label-1\": [\n \"simple text with id and {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"label-2\": [\n \"simple text with id and {1} and {2} variables 2\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_9:span\": [\n \"simple text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_9:span_1\": [\n \"simple text within div with {1} and {2} variables 2\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_9:div_2:div\": [\n \"great grandchild text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:text\": [\n \" simple text as the first element in div with {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:span_1\": [\n \"simple text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:text_2\": [\n \" simple text in the middle of div with {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:span_3\": [\n \"simple text within div with {1} and {2} variables 2\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:div_4:div\": [\n \"great grandchild text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:text_5\": [\n \" simple text at the last element in div with {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"toplevel-div:span\": [\n \"simple text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"toplevel-div:span_1\": [\n \"simple text within div 2 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"third-level-div\": [\n \"great grandchild text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"second-level-div:div_1\": [\n \"great grandchild text within div without id with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_12:ul:li\": [\n \"line item without id 1 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_12:ul:li_1\": [\n \"line item without id 2 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_12:ul:li_2\": [\n \"line item without id 3 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"line-items:li\": [\n \"line item with id 1 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"line-items:li_1\": [\n \"line item with id 2 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"line-items:li_2\": [\n \"line item with id 3 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"p_13\": [\n \"A paragraph with {1} is converted to {2}.\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"paragraph\": [\n \"A paragraph with {1}, {2}, and {3} is converted to {4}.\",\n \"id\",\n \"{{param1}}\",\n \"{{param2}}\",\n \"<i18n-format>\"\n ],\n \"text_15\": [\n \" outermost text at the end with {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ]\n}",
"/compound-binding-element/locales/compound-binding-element.fr.json": "{\n \"model\": {},\n \"text\": [\n \"fr outermost text at the beginning with compound {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"h1_3\": [\n \"fr outermost header 1 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"text_4\": [\n \"fr outermost text in the middle with {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"span_5\": [\n \"fr simple text without id with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"span_6\": [\n \"fr simple text without id 2 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"label-1\": [\n \"fr simple text with id and {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"label-2\": [\n \"fr simple text with id and {1} and {2} variables 2\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_9:span\": [\n \"fr simple text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_9:span_1\": [\n \"fr simple text within div with {1} and {2} variables 2\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_9:div_2:div\": [\n \"fr great grandchild text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:text\": [\n \"fr simple text as the first element in div with {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:span_1\": [\n \"fr simple text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:text_2\": [\n \"fr simple text in the middle of div with {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:span_3\": [\n \"fr simple text within div with {1} and {2} variables 2\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:div_4:div\": [\n \"fr great grandchild text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:text_5\": [\n \"fr simple text at the last element in div with {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"toplevel-div:span\": [\n \"fr simple text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"toplevel-div:span_1\": [\n \"fr simple text within div 2 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"third-level-div\": [\n \"fr great grandchild text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"second-level-div:div_1\": [\n \"fr great grandchild text within div without id with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_12:ul:li\": [\n \"fr line item without id 1 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_12:ul:li_1\": [\n \"fr line item without id 2 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_12:ul:li_2\": [\n \"fr line item without id 3 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"line-items:li\": [\n \"fr line item with id 1 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"line-items:li_1\": [\n \"fr line item with id 2 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"line-items:li_2\": [\n \"fr line item with id 3 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"p_13\": [\n \"fr A paragraph with {1} is converted to {2}.\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"paragraph\": [\n \"fr A paragraph with {1}, {2}, and {3} is converted to {4}.\",\n \"fr id\",\n \"{{param1}}\",\n \"{{param2}}\",\n \"fr <i18n-format>\"\n ],\n \"text_15\": [\n \"fr outermost text at the end with {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ]\n}\n",
"/edge-case-dom-bind.json": "{\n \"meta\": {},\n \"model\": {},\n \"text\": [\n \" name = {1} \",\n \"{{text.name}}\"\n ],\n \"i18n-number_1\": \"1\",\n \"i18n-format_2\": [\n \"{{text.format}}\",\n \"1\"\n ],\n \"i18n-format_3\": [\n \"format\",\n \"\"\n ],\n \"p_8\": [\n \"hello {1}{2} {3} world\",\n \"<br>\",\n \"<span>\",\n \"<span>\"\n ],\n \"p_9\": [\n \"hello{1}world\",\n \"<br>\"\n ],\n \"text_10\": \" hello \",\n \"text_14\": \" world \"\n}",
"/edge-case/advanced-binding-element.json": "{\n \"meta\": {},\n \"model\": {\n \"aria-attributes\": {\n \"title\": \"tooltip text\",\n \"aria-label\": \"aria label text\",\n \"aria-valuetext\": \"aria value text\"\n }\n },\n \"annotated-format\": [\n \"{{tr(status,text.statusMessageFormats)}}\",\n \"{{parameter}}\",\n \"string parameter\"\n ],\n \"span_5\": [\n \"{1} {2}\",\n \"{{text.defaultValue}}\",\n \"{{text.defaultValue}}\"\n ],\n \"statusMessages\": {\n \"ok\": \"healthy status\",\n \"busy\": \"busy status\",\n \"error\": \"error status\",\n \"default\": \"unknown status\"\n },\n \"defaultValue\": \"default value\",\n \"statusMessageFormats\": {\n \"ok\": \"healthy status\",\n \"busy\": \"busy status with {2}\",\n \"error\": \"error status with {1} and {2}\",\n \"default\": \"unknown status\"\n },\n \"nodefault\": {\n \"ok\": \"ok status\"\n }\n}",
"/edge-case/complex-compound-binding-element.json": "{\n \"model\": {},\n \"item-update2:text\": [\n \"updated: {1}, by: \",\n \"{{text.updated}}\"\n ],\n \"item-update2:text_2\": \" xxx \",\n \"item-update2:template_3:span:b\": \"IF CONTENT\",\n \"item-update2:b_4\": \"abc\",\n \"item-update2:template_5:text\": \"IF CONTENT 2\",\n \"item-update2:text_6\": \" hello \",\n \"item-update\": [\n \"updated: {1}, by: \\n {2}\\n xxx\\n {3}\\n {4}\\n {5}\\n hello\\n \\n {6}\\n {7} \",\n \"{{text.updated}}\",\n \" {{item.name}} \",\n \"IF CONTENT\",\n \"abc\",\n \"IF CONTENT 2\",\n \"<template>\",\n \"{{text.updated}}\"\n ],\n \"item-update3:text\": [\n \"updated: {1}, by: \",\n \"{{text.updated}}\"\n ],\n \"item-update3:text_2\": \" xxx \",\n \"item-update3:template_3:b\": \"IF\",\n \"item-update3:template_3:b_1\": \"CONTENT\",\n \"item-update3:b_4\": \"abc\",\n \"item-update3:template_5:text\": \"IF CONTENT 2\",\n \"item-update3:text_6\": \" hello \",\n \"item-update4:text\": [\n \"updated: {1}, by: \",\n \"{{text.updated}}\"\n ],\n \"item-update4:template_1:text\": [\n \" {1} = {2} \",\n \"{{item.name}}\",\n \"{{text.updated}}\"\n ],\n \"item-update4:text_2\": \" xxx \",\n \"item-update4:template_3:b\": \"IF CONTENT\",\n \"item-update4:b_4\": \"abc\",\n \"item-update4:template_5:text\": \"IF CONTENT 2\",\n \"item-update4:text_6\": \" hello \",\n \"paragraph\": [\n \"A paragraph with \\n {1}\\n is converted to \\n {2}. \",\n \"{{item}} \",\n \"<i18n-format>\"\n ],\n \"paragraph2:text\": \"A paragraph with deep \",\n \"paragraph2:text_2\": \" is \",\n \"paragraph2:b_3\": \"not\",\n \"paragraph2:text_4\": \" converted to \",\n \"paragraph2:code_5\": \"<i18n-format>\",\n \"paragraph2:text_6\": \". \",\n \"authors\": [\n {\n \"name\": \"Joe\"\n },\n {\n \"name\": \"Alice\"\n }\n ],\n \"updated\": \"Jan 1st, 2016\",\n \"parameters\": [\n \"parameter 1\",\n \"parameter 2\"\n ]\n}",
"/edge-case/empty-element.json": "{}",
"/edge-case/locales/advanced-binding-element.fr.json": "{\n \"meta\": {},\n \"model\": {\n \"aria-attributes\": {\n \"title\": \"fr tooltip text\",\n \"aria-label\": \"fr aria label text\",\n \"aria-valuetext\": \"fr aria value text\"\n }\n },\n \"annotated-format\": [\n \"{{tr(status,text.statusMessageFormats)}}\",\n \"{{parameter}}\",\n \"fr string parameter\"\n ],\n \"span_5\": [\n \"fr {1} {2}\",\n \"{{text.defaultValue}}\",\n \"{{text.defaultValue}}\"\n ],\n \"statusMessages\": {\n \"ok\": \"fr healthy status\",\n \"busy\": \"fr busy status\",\n \"error\": \"fr error status\",\n \"default\": \"fr unknown status\"\n },\n \"defaultValue\": \"fr default value\",\n \"statusMessageFormats\": {\n \"ok\": \"fr healthy status\",\n \"busy\": \"fr busy status with {2}\",\n \"error\": \"fr error status with {1} and {2}\",\n \"default\": \"fr unknown status\"\n },\n \"nodefault\": {\n \"ok\": \"fr ok status\"\n }\n}",
"/edge-case/locales/complex-compound-binding-element.fr.json": "{\n \"meta\": {},\n \"model\": {},\n \"item-update2:text\": [\n \"fr updated: {1}, by: \",\n \"{{text.updated}}\"\n ],\n \"item-update2:text_2\": \"fr xxx \",\n \"item-update2:template_3:span:b\": \"fr IF CONTENT\",\n \"item-update2:b_4\": \"fr abc\",\n \"item-update2:template_5:text\": \"fr IF CONTENT 2\",\n \"item-update2:text_6\": \"fr hello \",\n \"item-update\": [\n \"fr updated: {1}, by: \\n {2}\\n xxx\\n {3}\\n {4}\\n {5}\\n hello\\n \\n {6}\\n {7} \",\n \"{{text.updated}}\",\n \" {{item.name}} \",\n \"fr IF CONTENT\",\n \"fr abc\",\n \"fr IF CONTENT 2\",\n \"<template>\",\n \"{{text.updated}}\"\n ],\n \"item-update3:text\": [\n \"fr updated: {1}, by: \",\n \"{{text.updated}}\"\n ],\n \"item-update3:text_2\": \"fr xxx \",\n \"item-update3:template_3:b\": \"fr IF\",\n \"item-update3:template_3:b_1\": \"fr CONTENT\",\n \"item-update3:b_4\": \"fr abc\",\n \"item-update3:template_5:text\": \"fr IF CONTENT 2\",\n \"item-update3:text_6\": \"fr hello \",\n \"item-update4:text\": [\n \"fr updated: {1}, by: \",\n \"{{text.updated}}\"\n ],\n \"item-update4:template_1:text\": [\n \"fr {1} = {2} \",\n \"{{item.name}}\",\n \"{{text.updated}}\"\n ],\n \"item-update4:text_2\": \"fr xxx \",\n \"item-update4:template_3:b\": \"fr IF CONTENT\",\n \"item-update4:b_4\": \"fr abc\",\n \"item-update4:template_5:text\": \"fr IF CONTENT 2\",\n \"item-update4:text_6\": \"fr hello \",\n \"paragraph\": [\n \"fr A paragraph with \\n {1}\\n is converted to \\n {2}. \",\n \"{{item}} \",\n \"fr <i18n-format>\"\n ],\n \"paragraph2:text\": \"fr A paragraph with deep \",\n \"paragraph2:text_2\": \"fr is \",\n \"paragraph2:b_3\": \"fr not\",\n \"paragraph2:text_4\": \"fr converted to \",\n \"paragraph2:code_5\": \"fr <i18n-format>\",\n \"paragraph2:text_6\": \"fr . \",\n \"authors\": [\n {\n \"name\": \"fr Joe\"\n },\n {\n \"name\": \"fr Alice\"\n }\n ],\n \"updated\": \"fr Jan 1st, 2016\",\n \"parameters\": [\n \"fr parameter 1\",\n \"fr parameter 2\"\n ]\n}",
"/edge-case/locales/empty-element.fr.json": "{}",
"/fallback-text-element/fallback-text-element.json": "{\n \"meta\": {},\n \"model\": {},\n \"text\": \" outermost text at the beginning \",\n \"h1_3\": \"outermost header 1\",\n \"text_4\": \" outermost text in the middle \",\n \"span_5\": \"simple text without id\",\n \"span_6\": \"simple text without id 2\",\n \"label-1\": \"simple text with id\",\n \"label-2\": \"simple text with id 2\",\n \"div_9:span\": \"simple text within div\",\n \"div_9:span_1\": \"simple text within div 2\",\n \"div_9:div_2:div\": \"great grandchild text within div\",\n \"div_10:text\": \" simple text as the first element in div \",\n \"div_10:span_1\": \"simple text within div\",\n \"div_10:text_2\": \" simple text in the middle of div \",\n \"div_10:span_3\": \"simple text within div 2\",\n \"div_10:div_4:div\": \"great grandchild text within div\",\n \"div_10:text_5\": \" simple text at the last element in div \",\n \"toplevel-div:span\": \"simple text within div\",\n \"toplevel-div:span_1\": \"simple text within div 2\",\n \"third-level-div\": \"great grandchild text within div\",\n \"second-level-div:div_1\": \"great grandchild text within div without id\",\n \"div_12:ul:li\": \"line item without id 1\",\n \"div_12:ul:li_1\": \"line item without id 2\",\n \"div_12:ul:li_2\": \"line item without id 3\",\n \"line-items:li\": \"line item with id 1\",\n \"line-items:li_1\": \"line item with id 2\",\n \"line-items:li_2\": \"line item with id 3\",\n \"p_13\": [\n \"A paragraph with {1} is converted to {2}.\",\n \"parameters\",\n \"<i18n-format>\"\n ],\n \"paragraph\": [\n \"A paragraph with {1} is converted to {2}.\",\n \"id\",\n \"<i18n-format>\"\n ],\n \"text_15\": \" outermost text at the end \"\n}",
"/fallback-text-element/locales/fallback-text-element.fr-CA.json": "{\n \"model\": {},\n \"text\": \"fr-CA outermost text at the beginning \",\n \"h1_3\": \"fr-CA outermost header 1\",\n \"text_4\": \"fr-CA outermost text in the middle \",\n \"span_5\": \"fr-CA simple text without id\",\n \"span_6\": \"fr-CA simple text without id 2\",\n \"label-1\": \"fr-CA simple text with id\",\n \"label-2\": \"fr-CA simple text with id 2\",\n \"div_10:span_1\": \"fr-CA simple text within div\",\n \"toplevel-div:span\": \"fr-CA simple text within div\",\n \"toplevel-div:span_1\": \"fr-CA simple text within div 2\",\n \"third-level-div\": \"fr-CA great grandchild text within div\",\n \"second-level-div:div_1\": \"fr-CA great grandchild text within div without id\",\n \"p_13\": [\n \"fr-CA A paragraph with {1} is converted to {2}.\",\n \"fr-CA parameters\",\n \"fr-CA <i18n-format>\"\n ],\n \"paragraph\": [\n \"fr-CA A paragraph with {1} is converted to {2}.\",\n \"fr-CA id\",\n \"fr-CA <i18n-format>\"\n ],\n \"text_15\": \"fr-CA outermost text at the end \"\n}\n",
"/fallback-text-element/locales/fallback-text-element.fr.json": "{\n \"model\": {},\n \"text\": \"fr outermost text at the beginning \",\n \"h1_3\": \"fr outermost header 1\",\n \"text_4\": \"fr outermost text in the middle \",\n \"span_5\": \"fr simple text without id\",\n \"span_6\": \"fr simple text without id 2\",\n \"label-1\": \"fr simple text with id\",\n \"label-2\": \"fr simple text with id 2\",\n \"toplevel-div:span\": \"fr simple text within div\",\n \"toplevel-div:span_1\": \"fr simple text within div 2\",\n \"third-level-div\": \"fr great grandchild text within div\",\n \"second-level-div:div_1\": \"fr great grandchild text within div without id\",\n \"div_12:ul:li\": \"fr line item without id 1\",\n \"div_12:ul:li_1\": \"fr line item without id 2\",\n \"div_12:ul:li_2\": \"fr line item without id 3\",\n \"line-items:li\": \"fr line item with id 1\",\n \"line-items:li_1\": \"fr line item with id 2\",\n \"line-items:li_2\": \"fr line item with id 3\",\n \"p_13\": [\n \"fr A paragraph with {1} is converted to {2}.\",\n \"fr parameters\",\n \"fr <i18n-format>\"\n ],\n \"paragraph\": [\n \"fr A paragraph with {1} is converted to {2}.\",\n \"fr id\",\n \"fr <i18n-format>\"\n ],\n \"text_15\": \"fr outermost text at the end \"\n}\n",
"/locales/compound-binding-dom-bind.fr.json": "{\n \"model\": {},\n \"text\": [\n \"fr outermost text at the beginning with compound {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"h1_3\": [\n \"fr outermost header 1 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"text_4\": [\n \"fr outermost text in the middle with {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"span_5\": [\n \"fr simple text without id with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"span_6\": [\n \"fr simple text without id 2 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"label-1\": [\n \"fr simple text with id and {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"label-2\": [\n \"fr simple text with id and {1} and {2} variables 2\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_9:span\": [\n \"fr simple text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_9:span_1\": [\n \"fr simple text within div with {1} and {2} variables 2\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_9:div_2:div\": [\n \"fr great grandchild text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:text\": [\n \"fr simple text as the first element in div with {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:span_1\": [\n \"fr simple text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:text_2\": [\n \"fr simple text in the middle of div with {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:span_3\": [\n \"fr simple text within div with {1} and {2} variables 2\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:div_4:div\": [\n \"fr great grandchild text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_10:text_5\": [\n \"fr simple text at the last element in div with {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"toplevel-div:span\": [\n \"fr simple text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"toplevel-div:span_1\": [\n \"fr simple text within div 2 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"third-level-div\": [\n \"fr great grandchild text within div with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"second-level-div:div_1\": [\n \"fr great grandchild text within div without id with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_12:ul:li\": [\n \"fr line item without id 1 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_12:ul:li_1\": [\n \"fr line item without id 2 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"div_12:ul:li_2\": [\n \"fr line item without id 3 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"line-items:li\": [\n \"fr line item with id 1 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"line-items:li_1\": [\n \"fr line item with id 2 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"line-items:li_2\": [\n \"fr line item with id 3 with {1} and {2} variables\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"p_13\": [\n \"fr A paragraph with {1} is converted to {2}.\",\n \"{{param1}}\",\n \"{{param2}}\"\n ],\n \"paragraph\": [\n \"fr A paragraph with {1}, {2}, and {3} is converted to {4}.\",\n \"fr id\",\n \"{{param1}}\",\n \"{{param2}}\",\n \"fr <i18n-format>\"\n ],\n \"text_15\": [\n \"fr outermost text at the end with {1} and {2} variables \",\n \"{{param1}}\",\n \"{{param2}}\"\n ]\n}\n",
"/locales/simple-attribute-dom-bind.fr.json": "{\n \"model\": {\n \"standard-input\": {\n \"placeholder\": \"fr standard HTML5 attribute\"\n },\n \"outer-div:input_2\": {\n \"placeholder\": \"fr standard HTML5 attribute without id\"\n },\n \"paper-input-element\": {\n \"label\": \"fr paper-input label\",\n \"error-message\": \"fr paper-input error message\",\n \"placeholder\": \"fr paper-input placeholder\"\n },\n \"outer-div:paper-input_4\": {\n \"label\": \"fr paper-input label without id\",\n \"error-message\": \"fr paper-input error message without id\",\n \"placeholder\": \"fr paper-input placeholder without id\"\n },\n \"pie-chart\": {\n \"options\": {\n \"title\": \"fr Distribution of days in 2001H1\"\n },\n \"cols\": [\n {\n \"label\": \"fr Month\",\n \"type\": \"string\"\n },\n {\n \"label\": \"fr Days\",\n \"type\": \"number\"\n }\n ],\n \"rows\": [\n [\n \"fr Jan\",\n 31\n ],\n [\n \"fr Feb\",\n 28\n ],\n [\n \"fr Mar\",\n 31\n ],\n [\n \"fr Apr\",\n 30\n ],\n [\n \"fr May\",\n 31\n ],\n [\n \"fr Jun\",\n 30\n ]\n ]\n },\n \"column-chart\": {\n \"options\": {\n \"title\": \"fr Inventory\"\n },\n \"data\": [\n [\n \"fr Year\",\n \"fr Things\",\n \"fr Stuff\"\n ],\n [\n \"2004\",\n 1000,\n 400\n ],\n [\n \"2005\",\n 1170,\n 460\n ],\n [\n \"2006\",\n 660,\n 1120\n ],\n [\n \"2007\",\n 1030,\n 540\n ]\n ]\n },\n \"custom-attr\": {\n \"custom-text-attr1\": \"fr custom text attribute 1\",\n \"custom-text-attr2\": \"fr custom text attribute 2\",\n \"custom-text-attr3\": \"fr custom text attribute 3\"\n },\n \"selective-attr\": {\n \"custom-text-attr4\": [\n \"fr {1} custom-text-attr4 attribute with param {2} and param {3} {4}\",\n \"{{text.ordinary-div}}\",\n \"{{text.ordinary-div}}\",\n \"[[text.ordinary-div]]\",\n \"{{text.ordinary-div}}\"\n ],\n \"custom-text-attr5\": [\n \"[[text.ordinary-div]]\",\n \"fr custom-text-attr5 attribute with param \",\n \"{{or('',text.ordinary-div)}}\",\n \"fr and param \",\n \"[[text.ordinary-div]]\"\n ],\n \"i18n-target\": [\n \"fr i18n-target attribute with param {1} and param {2}\",\n \"{{text.ordinary-div}}\",\n \"[[text.ordinary-div]]\"\n ],\n \"i18n-target2\": [\n \"fr i18n-target2 attribute with param \",\n \"{{or('',text.ordinary-div)}}\",\n \"fr and param \",\n \"[[text.ordinary-div]]\"\n ]\n },\n \"selective-attr2\": {\n \"i18n-target\": \"fr i18n-target attribute 2\"\n },\n \"selective-attr3\": {\n \"i18n-target6\": \"fr i18n-target6 attribute 2\"\n },\n \"selective-attr4\": {\n \"i18n-target6\": \"fr i18n-target6 attribute 3\"\n },\n \"json-data-id\": {\n \"attr1\": \"fr this attr1 is extracted\",\n \"i18n-target-attr\": \"fr this attribute is also extracted\"\n },\n \"template_2:json-data_1\": {\n \"attr1\": \"fr this attr1 without id is extracted\",\n \"i18n-target-attr\": \"fr this attribute without id is also extracted\"\n }\n },\n \"ordinary-div\": \"fr text 1\"\n}\n",
"/locales/simple-text-dom-bind.fr.json": "{\n \"model\": {},\n \"text\": \"fr outermost text at the beginning \",\n \"h1_3\": \"fr outermost header 1\",\n \"text_4\": \"fr outermost text in the middle \",\n \"span_5\": \"fr simple text without id\",\n \"span_6\": \"fr simple text without id 2\",\n \"label-1\": \"fr simple text with id\",\n \"label-2\": \"fr simple text with id 2\",\n \"div_9:span\": \"fr simple text within div\",\n \"div_9:span_1\": \"fr simple text within div 2\",\n \"div_9:div_2:div\": \"fr great grandchild text within div\",\n \"div_10:text\": \"fr simple text as the first element in div \",\n \"div_10:span_1\": \"fr simple text within div\",\n \"div_10:text_2\": \"fr simple text in the middle of div \",\n \"div_10:span_3\": \"fr simple text within div 2\",\n \"div_10:div_4:div\": \"fr great grandchild text within div\",\n \"div_10:text_5\": \"fr simple text at the last element in div \",\n \"toplevel-div:span\": \"fr simple text within div\",\n \"toplevel-div:span_1\": \"fr simple text within div 2\",\n \"third-level-div\": \"fr great grandchild text within div\",\n \"second-level-div:div_1\": \"fr great grandchild text within div without id\",\n \"div_12:ul:li\": \"fr line item without id 1\",\n \"div_12:ul:li_1\": \"fr line item without id 2\",\n \"div_12:ul:li_2\": \"fr line item without id 3\",\n \"line-items:li\": \"fr line item with id 1\",\n \"line-items:li_1\": \"fr line item with id 2\",\n \"line-items:li_2\": \"fr line item with id 3\",\n \"p_13\": [\n \"fr A paragraph with {1} is converted to {2}.\",\n \"fr parameters\",\n \"fr <i18n-format>\"\n ],\n \"paragraph\": [\n \"fr A paragraph with {1} is converted to {2}.\",\n \"fr id\",\n \"fr <i18n-format>\"\n ],\n \"text_15\": \"fr outermost text at the end \"\n}\n",
"/multiple-case/item-element.json": "{\n \"meta\": {},\n \"model\": {},\n \"label\": \"A\"\n}",
"/multiple-case/locales/item-element.fr.json": "{\n \"meta\": {},\n \"model\": {},\n \"label\": \"fr A\"\n}",
"/multiple-case/locales/multiple-element.fr.json": "{\n \"meta\": {},\n \"model\": {}\n}",
"/multiple-case/multiple-element.json": "{\n \"meta\": {},\n \"model\": {}\n}",
"/plural-gender-element/locales/plural-gender-element.fr.json": "{\n \"model\": {},\n \"compound-format-text\": [\n {\n \"0\": \"fr You ({3}) gave no gifts.\",\n \"1\": {\n \"male\": \"fr You ({3}) gave him ({4}) {5}.\",\n \"female\": \"fr You ({3}) gave her ({4}) {5}.\",\n \"other\": \"fr You ({3}) gave them ({4}) {5}.\"\n },\n \"one\": {\n \"male\": \"fr You ({3}) gave him ({4}) and one other person {5}.\",\n \"female\": \"fr You ({3}) gave her ({4}) and one other person {5}.\",\n \"other\": \"fr You ({3}) gave them ({4}) and one other person {5}.\"\n },\n \"other\": \"fr You ({3}) gave them ({4}) and {1} other people gifts.\"\n },\n \"{{recipients.length - 1}}\",\n \"{{recipients.0.gender}}\",\n \"{{sender.name}}\",\n \"{{recipients.0.name}}\",\n \"fr a gift\"\n ]\n}\n",
"/plural-gender-element/plural-gender-element.json": "{\n \"meta\": {},\n \"model\": {},\n \"compound-format-text\": [\n {\n \"0\": \"You ({3}) gave no gifts.\",\n \"1\": {\n \"male\": \"You ({3}) gave him ({4}) {5}.\",\n \"female\": \"You ({3}) gave her ({4}) {5}.\",\n \"other\": \"You ({3}) gave them ({4}) {5}.\"\n },\n \"one\": {\n \"male\": \"You ({3}) gave him ({4}) and one other person {5}.\",\n \"female\": \"You ({3}) gave her ({4}) and one other person {5}.\",\n \"other\": \"You ({3}) gave them ({4}) and one other person {5}.\"\n },\n \"other\": \"You ({3}) gave them ({4}) and {1} other people gifts.\"\n },\n \"{{recipients.length - 1}}\",\n \"{{recipients.0.gender}}\",\n \"{{sender.name}}\",\n \"{{recipients.0.name}}\",\n \"a gift\"\n ]\n}",
"/preference/preference-element.json": "{\n \"meta\": {},\n \"model\": {}\n}",
"/simple-attribute-dom-bind.json": "{\n \"meta\": {},\n \"model\": {\n \"standard-input\": {\n \"placeholder\": \"standard HTML5 attribute\"\n },\n \"outer-div:input_2\": {\n \"placeholder\": \"standard HTML5 attribute without id\"\n },\n \"paper-input-element\": {\n \"label\": \"paper-input label\",\n \"error-message\": \"paper-input error message\",\n \"placeholder\": \"paper-input placeholder\"\n },\n \"outer-div:paper-input_4\": {\n \"label\": \"paper-input label without id\",\n \"error-message\": \"paper-input error message without id\",\n \"placeholder\": \"paper-input placeholder without id\"\n },\n \"pie-chart\": {\n \"options\": {\n \"title\": \"Distribution of days in 2001H1\"\n },\n \"cols\": [\n {\n \"label\": \"Month\",\n \"type\": \"string\"\n },\n {\n \"label\": \"Days\",\n \"type\": \"number\"\n }\n ],\n \"rows\": [\n [\n \"Jan\",\n 31\n ],\n [\n \"Feb\",\n 28\n ],\n [\n \"Mar\",\n 31\n ],\n [\n \"Apr\",\n 30\n ],\n [\n \"May\",\n 31\n ],\n [\n \"Jun\",\n 30\n ]\n ]\n },\n \"column-chart\": {\n \"options\": {\n \"title\": \"Inventory\"\n },\n \"data\": [\n [\n \"Year\",\n \"Things\",\n \"Stuff\"\n ],\n [\n \"2004\",\n 1000,\n 400\n ],\n [\n \"2005\",\n 1170,\n 460\n ],\n [\n \"2006\",\n 660,\n 1120\n ],\n [\n \"2007\",\n 1030,\n 540\n ]\n ]\n },\n \"custom-attr\": {\n \"custom-text-attr1\": \"custom text attribute 1\",\n \"custom-text-attr2\": \"custom text attribute 2\",\n \"custom-text-attr3\": \"custom text attribute 3\"\n },\n \"selective-attr\": {\n \"custom-text-attr4\": [\n \"{1} custom-text-attr4 attribute with param {2} and param {3} {4}\",\n \"{{text.ordinary-div}}\",\n \"{{text.ordinary-div}}\",\n \"[[text.ordinary-div]]\",\n \"{{text.ordinary-div}}\"\n ],\n \"custom-text-attr5\": [\n \"[[text.ordinary-div]]\",\n \" custom-text-attr5 attribute with param \",\n \"{{or('',text.ordinary-div)}}\",\n \" and param \",\n \"[[text.ordinary-div]]\"\n ],\n \"i18n-target\": [\n \"i18n-target attribute with param {1} and param {2}\",\n \"{{text.ordinary-div}}\",\n \"[[text.ordinary-div]]\"\n ],\n \"i18n-target2\": [\n \"i18n-target2 attribute with param \",\n \"{{or('',text.ordinary-div)}}\",\n \" and param \",\n \"[[text.ordinary-div]]\"\n ]\n },\n \"selective-attr2\": {\n \"i18n-target\": \"i18n-target attribute 2\"\n },\n \"selective-attr3\": {\n \"i18n-target6\": \"i18n-target6 attribute 2\"\n },\n \"selective-attr4\": {\n \"i18n-target6\": \"i18n-target6 attribute 3\"\n },\n \"json-data-id\": {\n \"attr1\": \"this attr1 is extracted\",\n \"i18n-target-attr\": \"this attribute is also extracted\"\n },\n \"template_2:json-data_1\": {\n \"attr1\": \"this attr1 without id is extracted\",\n \"i18n-target-attr\": \"this attribute without id is also extracted\"\n }\n },\n \"ordinary-div\": \"text 1\"\n}",
"/simple-attribute-element/locales/simple-attribute-element.fr.json": "{\n \"model\": {\n \"standard-input\": {\n \"placeholder\": \"fr standard HTML5 attribute\"\n },\n \"outer-div:input_2\": {\n \"placeholder\": \"fr standard HTML5 attribute without id\"\n },\n \"paper-input-element\": {\n \"label\": \"fr paper-input label\",\n \"error-message\": \"fr paper-input error message\",\n \"placeholder\": \"fr paper-input placeholder\"\n },\n \"outer-div:paper-input_4\": {\n \"label\": \"fr paper-input label without id\",\n \"error-message\": \"fr paper-input error message without id\",\n \"placeholder\": \"fr paper-input placeholder without id\"\n },\n \"pie-chart\": {\n \"options\": {\n \"title\": \"fr Distribution of days in 2001H1\"\n },\n \"cols\": [\n {\n \"label\": \"fr Month\",\n \"type\": \"string\"\n },\n {\n \"label\": \"fr Days\",\n \"type\": \"number\"\n }\n ],\n \"rows\": [\n [\n \"fr Jan\",\n 31\n ],\n [\n \"fr Feb\",\n 28\n ],\n [\n \"fr Mar\",\n 31\n ],\n [\n \"fr Apr\",\n 30\n ],\n [\n \"fr May\",\n 31\n ],\n [\n \"fr Jun\",\n 30\n ]\n ]\n },\n \"column-chart\": {\n \"options\": {\n \"title\": \"fr Inventory\"\n },\n \"data\": [\n [\n \"fr Year\",\n \"fr Things\",\n \"fr Stuff\"\n ],\n [\n \"2004\",\n 1000,\n 400\n ],\n [\n \"2005\",\n 1170,\n 460\n ],\n [\n \"2006\",\n 660,\n 1120\n ],\n [\n \"2007\",\n 1030,\n 540\n ]\n ]\n },\n \"custom-attr\": {\n \"custom-text-attr1\": \"fr custom text attribute 1\",\n \"custom-text-attr2\": \"fr custom text attribute 2\",\n \"custom-text-attr3\": \"fr custom text attribute 3\"\n },\n \"selective-attr\": {\n \"custom-text-attr4\": [\n \"fr {1} custom-text-attr4 attribute with param {2} and param {3} {4}\",\n \"{{text.ordinary-div}}\",\n \"{{text.ordinary-div}}\",\n \"[[text.ordinary-div]]\",\n \"{{text.ordinary-div}}\"\n ],\n \"custom-text-attr5\": [\n \"[[text.ordinary-div]]\",\n \"fr custom-text-attr5 attribute with param \",\n \"{{or('',text.ordinary-div)}}\",\n \"fr and param \",\n \"[[text.ordinary-div]]\"\n ],\n \"i18n-target\": [\n \"fr i18n-target attribute with param {1} and param {2}\",\n \"{{text.ordinary-div}}\",\n \"[[text.ordinary-div]]\"\n ],\n \"i18n-target2\": [\n \"fr i18n-target2 attribute with param \",\n \"{{or('',text.ordinary-div)}}\",\n \"fr and param \",\n \"[[text.ordinary-div]]\"\n ]\n },\n \"selective-attr2\": {\n \"i18n-target\": \"fr i18n-target attribute 2\"\n },\n \"selective-attr3\": {\n \"i18n-target6\": \"fr i18n-target6 attribute 2\"\n },\n \"selective-attr4\": {\n \"i18n-target6\": \"fr i18n-target6 attribute 3\"\n },\n \"json-data-id\": {\n \"attr1\": \"fr this attr1 is extracted\",\n \"i18n-target-attr\": \"fr this attribute is also extracted\"\n },\n \"template_2:json-data_1\": {\n \"attr1\": \"fr this attr1 without id is extracted\",\n \"i18n-target-attr\": \"fr this attribute without id is also extracted\"\n }\n },\n \"ordinary-div\": \"fr text 1\"\n}\n",
"/simple-attribute-element/locales/text-attribute-element.fr.json": "{\n \"meta\": {},\n \"model\": {},\n \"span_4\": \"fr text\"\n}\n",
"/simple-attribute-element/simple-attribute-element.json": "{\n \"meta\": {},\n \"model\": {\n \"standard-input\": {\n \"placeholder\": \"standard HTML5 attribute\"\n },\n \"outer-div:input_2\": {\n \"placeholder\": \"standard HTML5 attribute without id\"\n },\n \"paper-input-element\": {\n \"label\": \"paper-input label\",\n \"error-message\": \"paper-input error message\",\n \"placeholder\": \"paper-input placeholder\"\n },\n \"outer-div:paper-input_4\": {\n \"label\": \"paper-input label without id\",\n \"error-message\": \"paper-input error message without id\",\n \"placeholder\": \"paper-input placeholder without id\"\n },\n \"pie-chart\": {\n \"options\": {\n \"title\": \"Distribution of days in 2001H1\"\n },\n \"cols\": [\n {\n \"label\": \"Month\",\n \"type\": \"string\"\n },\n {\n \"label\": \"Days\",\n \"type\": \"number\"\n }\n ],\n \"rows\": [\n [\n \"Jan\",\n 31\n ],\n [\n \"Feb\",\n 28\n ],\n [\n \"Mar\",\n 31\n ],\n [\n \"Apr\",\n 30\n ],\n [\n \"May\",\n 31\n ],\n [\n \"Jun\",\n 30\n ]\n ]\n },\n \"column-chart\": {\n \"options\": {\n \"title\": \"Inventory\"\n },\n \"data\": [\n [\n \"Year\",\n \"Things\",\n \"Stuff\"\n ],\n [\n \"2004\",\n 1000,\n 400\n ],\n [\n \"2005\",\n 1170,\n 460\n ],\n [\n \"2006\",\n 660,\n 1120\n ],\n [\n \"2007\",\n 1030,\n 540\n ]\n ]\n },\n \"custom-attr\": {\n \"custom-text-attr1\": \"custom text attribute 1\",\n \"custom-text-attr2\": \"custom text attribute 2\",\n \"custom-text-attr3\": \"custom text attribute 3\"\n },\n \"selective-attr\": {\n \"custom-text-attr4\": [\n \"{1} custom-text-attr4 attribute with param {2} and param {3} {4}\",\n \"{{text.ordinary-div}}\",\n \"{{text.ordinary-div}}\",\n \"[[text.ordinary-div]]\",\n \"{{text.ordinary-div}}\"\n ],\n \"custom-text-attr5\": [\n \"[[text.ordinary-div]]\",\n \" custom-text-attr5 attribute with param \",\n \"{{or('',text.ordinary-div)}}\",\n \" and param \",\n \"[[text.ordinary-div]]\"\n ],\n \"i18n-target\": [\n \"i18n-target attribute with param {1} and param {2}\",\n \"{{text.ordinary-div}}\",\n \"[[text.ordinary-div]]\"\n ],\n \"i18n-target2\": [\n \"i18n-target2 attribute with param \",\n \"{{or('',text.ordinary-div)}}\",\n \" and param \",\n \"[[text.ordinary-div]]\"\n ]\n },\n \"selective-attr2\": {\n \"i18n-target\": \"i18n-target attribute 2\"\n },\n \"selective-attr3\": {\n \"i18n-target6\": \"i18n-target6 attribute 2\"\n },\n \"selective-attr4\": {\n \"i18n-target6\": \"i18n-target6 attribute 3\"\n },\n \"json-data-id\": {\n \"attr1\": \"this attr1 is extracted\",\n \"i18n-target-attr\": \"this attribute is also extracted\"\n },\n \"template_2:json-data_1\": {\n \"attr1\": \"this attr1 without id is extracted\",\n \"i18n-target-attr\": \"this attribute without id is also extracted\"\n }\n },\n \"ordinary-div\": \"text 1\"\n}",
"/simple-attribute-element/text-attribute-element.json": "{\n \"meta\": {},\n \"model\": {},\n \"span_4\": \"text\"\n}",
"/simple-text-dom-bind.json": "{\n \"meta\": {},\n \"model\": {},\n \"text\": \" outermost text at the beginning \",\n \"h1_3\": \"outermost header 1\",\n \"text_4\": \" outermost text in the middle \",\n \"span_5\": \"simple text without id\",\n \"span_6\": \"simple text without id 2\",\n \"label-1\": \"simple text with id\",\n \"label-2\": \"simple text with id 2\",\n \"div_9:span\": \"simple text within div\",\n \"div_9:span_1\": \"simple text within div 2\",\n \"div_9:div_2:div\": \"great grandchild text within div\",\n \"div_10:text\": \" simple text as the first element in div \",\n \"div_10:span_1\": \"simple text within div\",\n \"div_10:text_2\": \" simple text in the middle of div \",\n \"div_10:span_3\": \"simple text within div 2\",\n \"div_10:div_4:div\": \"great grandchild text within div\",\n \"div_10:text_5\": \" simple text at the last element in div \",\n \"toplevel-div:span\": \"simple text within div\",\n \"toplevel-div:span_1\": \"simple text within div 2\",\n \"third-level-div\": \"great grandchild text within div\",\n \"second-level-div:div_1\": \"great grandchild text within div without id\",\n \"div_12:ul:li\": \"line item without id 1\",\n \"div_12:ul:li_1\": \"line item without id 2\",\n \"div_12:ul:li_2\": \"line item without id 3\",\n \"line-items:li\": \"line item with id 1\",\n \"line-items:li_1\": \"line item with id 2\",\n \"line-items:li_2\": \"line item with id 3\",\n \"p_13\": [\n \"A paragraph with {1} is converted to {2}.\",\n \"parameters\",\n \"<i18n-format>\"\n ],\n \"paragraph\": [\n \"A paragraph with {1} is converted to {2}.\",\n \"id\",\n \"<i18n-format>\"\n ],\n \"text_15\": \" outermost text at the end \"\n}",
"/simple-text-element/locales/simple-text-element.fr.json": "{\n \"model\": {},\n \"text\": \"fr outermost text at the beginning \",\n \"h1_3\": \"fr outermost header 1\",\n \"text_4\": \"fr outermost text in the middle \",\n \"span_5\": \"fr simple text without id\",\n \"span_6\": \"fr simple text without id 2\",\n \"label-1\": \"fr simple text with id\",\n \"label-2\": \"fr simple text with id 2\",\n \"div_9:span\": \"fr simple text within div\",\n \"div_9:span_1\": \"fr simple text within div 2\",\n \"div_9:div_2:div\": \"fr great grandchild text within div\",\n \"div_10:text\": \"fr simple text as the first element in div \",\n \"div_10:span_1\": \"fr simple text within div\",\n \"div_10:text_2\": \"fr simple text in the middle of div \",\n \"div_10:span_3\": \"fr simple text within div 2\",\n \"div_10:div_4:div\": \"fr great grandchild text within div\",\n \"div_10:text_5\": \"fr simple text at the last element in div \",\n \"toplevel-div:span\": \"fr simple text within div\",\n \"toplevel-div:span_1\": \"fr simple text within div 2\",\n \"third-level-div\": \"fr great grandchild text within div\",\n \"second-level-div:div_1\": \"fr great grandchild text within div without id\",\n \"div_12:ul:li\": \"fr line item without id 1\",\n \"div_12:ul:li_1\": \"fr line item without id 2\",\n \"div_12:ul:li_2\": \"fr line item without id 3\",\n \"line-items:li\": \"fr line item with id 1\",\n \"line-items:li_1\": \"fr line item with id 2\",\n \"line-items:li_2\": \"fr line item with id 3\",\n \"p_13\": [\n \"fr A paragraph with {1} is converted to {2}.\",\n \"fr parameters\",\n \"fr <i18n-format>\"\n ],\n \"paragraph\": [\n \"fr A paragraph with {1} is converted to {2}.\",\n \"fr id\",\n \"fr <i18n-format>\"\n ],\n \"text_15\": \"fr outermost text at the end \"\n}\n",
"/simple-text-element/locales/simple-text-element.ru.json": "{\n \"model\": {},\n \"text\": \"ru outermost text at the beginning \",\n \"h1_3\": \"ru outermost header 1\",\n \"text_4\": \"ru outermost text in the middle \",\n \"span_5\": \"ru simple text without id\",\n \"span_6\": \"ru simple text without id 2\",\n \"label-1\": \"ru simple text with id\",\n \"label-2\": \"ru simple text with id 2\",\n \"div_9:span\": \"ru simple text within div\",\n \"div_9:span_1\": \"ru simple text within div 2\",\n \"div_9:div_2:div\": \"ru great grandchild text within div\",\n \"div_10:text\": \"ru simple text as the first element in div \",\n \"div_10:span_1\": \"ru simple text within div\",\n \"div_10:text_2\": \"ru simple text in the middle of div \",\n \"div_10:span_3\": \"ru simple text within div 2\",\n \"div_10:div_4:div\": \"ru great grandchild text within div\",\n \"div_10:text_5\": \"ru simple text at the last element in div \",\n \"toplevel-div:span\": \"ru simple text within div\",\n \"toplevel-div:span_1\": \"ru simple text within div 2\",\n \"third-level-div\": \"ru great grandchild text within div\",\n \"second-level-div:div_1\": \"ru great grandchild text within div without id\",\n \"div_12:ul:li\": \"ru line item without id 1\",\n \"div_12:ul:li_1\": \"ru line item without id 2\",\n \"div_12:ul:li_2\": \"ru line item without id 3\",\n \"line-items:li\": \"ru line item with id 1\",\n \"line-items:li_1\": \"ru line item with id 2\",\n \"line-items:li_2\": \"ru line item with id 3\",\n \"p_13\": [\n \"ru A paragraph with {1} is converted to {2}.\",\n \"ru parameters\",\n \"ru <i18n-format>\"\n ],\n \"paragraph\": [\n \"ru A paragraph with {1} is converted to {2}.\",\n \"ru id\",\n \"ru <i18n-format>\"\n ],\n \"text_15\": \"ru outermost text at the end \"\n}\n",
"/simple-text-element/simple-text-element.json": "{\n \"meta\": {},\n \"model\": {},\n \"text\": \" outermost text at the beginning \",\n \"h1_3\": \"outermost header 1\",\n \"text_4\": \" outermost text in the middle \",\n \"span_5\": \"simple text without id\",\n \"span_6\": \"simple text without id 2\",\n \"label-1\": \"simple text with id\",\n \"label-2\": \"simple text with id 2\",\n \"div_9:span\": \"simple text within div\",\n \"div_9:span_1\": \"simple text within div 2\",\n \"div_9:div_2:div\": \"great grandchild text within div\",\n \"div_10:text\": \" simple text as the first element in div \",\n \"div_10:span_1\": \"simple text within div\",\n \"div_10:text_2\": \" simple text in the middle of div \",\n \"div_10:span_3\": \"simple text within div 2\",\n \"div_10:div_4:div\": \"great grandchild text within div\",\n \"div_10:text_5\": \" simple text at the last element in div \",\n \"toplevel-div:span\": \"simple text within div\",\n \"toplevel-div:span_1\": \"simple text within div 2\",\n \"third-level-div\": \"great grandchild text within div\",\n \"second-level-div:div_1\": \"great grandchild text within div without id\",\n \"div_12:ul:li\": \"line item without id 1\",\n \"div_12:ul:li_1\": \"line item without id 2\",\n \"div_12:ul:li_2\": \"line item without id 3\",\n \"line-items:li\": \"line item with id 1\",\n \"line-items:li_1\": \"line item with id 2\",\n \"line-items:li_2\": \"line item with id 3\",\n \"p_13\": [\n \"A paragraph with {1} is converted to {2}.\",\n \"parameters\",\n \"<i18n-format>\"\n ],\n \"paragraph\": [\n \"A paragraph with {1} is converted to {2}.\",\n \"id\",\n \"<i18n-format>\"\n ],\n \"text_15\": \" outermost text at the end \"\n}",
"/simple-text-id-element/locales/simple-text-id-element.fr.json": "{\n \"model\": {},\n \"text\": \"fr outermost text at the beginning \",\n \"h1_3\": \"fr outermost header 1\",\n \"text_4\": \"fr outermost text in the middle \",\n \"span_5\": \"fr simple text without id\",\n \"span_6\": \"fr simple text without id 2\",\n \"label-1\": \"fr simple text with id\",\n \"label-2\": \"fr simple text with id 2\",\n \"div_9:span\": \"fr simple text within div\",\n \"div_9:span_1\": \"fr simple text within div 2\",\n \"div_9:div_2:div\": \"fr great grandchild text within div\",\n \"div_10:text\": \"fr simple text as the first element in div \",\n \"div_10:span_1\": \"fr simple text within div\",\n \"div_10:text_2\": \"fr simple text in the middle of div \",\n \"div_10:span_3\": \"fr simple text within div 2\",\n \"div_10:div_4:div\": \"fr great grandchild text within div\",\n \"div_10:text_5\": \"fr simple text at the last element in div \",\n \"toplevel-div:span\": \"fr simple text within div\",\n \"toplevel-div:span_1\": \"fr simple text within div 2\",\n \"second-level-div\": [\n \"fr {1}\\n {2} \",\n \"fr great grandchild text within div\",\n \"fr great grandchild text within div without id\"\n ],\n \"div_12:ul:li\": \"fr line item without id 1\",\n \"div_12:ul:li_1\": \"fr line item without id 2\",\n \"div_12:ul:li_2\": \"fr line item without id 3\",\n \"line-items\": [\n \"fr {1}\\n {2}\\n {3} \",\n \"fr line item with id 1\",\n \"fr line item with id 2\",\n \"fr line item with id 3\"\n ],\n \"p_13\": [\n \"fr A paragraph with {1} is converted to {2}.\",\n \"fr parameters\",\n \"fr <i18n-format>\"\n ],\n \"paragraph\": [\n \"fr A paragraph with {1} is converted to {2}.\",\n \"fr id\",\n \"fr <i18n-format>\"\n ],\n \"text_15\": \"fr outermost text at the end \"\n}\n",
"/simple-text-id-element/simple-text-id-element.json": "{\n \"meta\": {},\n \"model\": {},\n \"text\": \" outermost text at the beginning \",\n \"h1_3\": \"outermost header 1\",\n \"text_4\": \" outermost text in the middle \",\n \"span_5\": \"simple text without id\",\n \"span_6\": \"simple text without id 2\",\n \"label-1\": \"simple text with id\",\n \"label-2\": \"simple text with id 2\",\n \"div_9:span\": \"simple text within div\",\n \"div_9:span_1\": \"simple text within div 2\",\n \"div_9:div_2:div\": \"great grandchild text within div\",\n \"div_10:text\": \" simple text as the first element in div \",\n \"div_10:span_1\": \"simple text within div\",\n \"div_10:text_2\": \" simple text in the middle of div \",\n \"div_10:span_3\": \"simple text within div 2\",\n \"div_10:div_4:div\": \"great grandchild text within div\",\n \"div_10:text_5\": \" simple text at the last element in div \",\n \"toplevel-div:span\": \"simple text within div\",\n \"toplevel-div:span_1\": \"simple text within div 2\",\n \"second-level-div\": [\n \" {1}\\n {2} \",\n \"great grandchild text within div\",\n \"great grandchild text within div without id\"\n ],\n \"div_12:ul:li\": \"line item without id 1\",\n \"div_12:ul:li_1\": \"line item without id 2\",\n \"div_12:ul:li_2\": \"line item without id 3\",\n \"line-items\": [\n \" {1}\\n {2}\\n {3} \",\n \"line item with id 1\",\n \"line item with id 2\",\n \"line item with id 3\"\n ],\n \"p_13\": [\n \"A paragraph with {1} is converted to {2}.\",\n \"parameters\",\n \"<i18n-format>\"\n ],\n \"paragraph\": [\n \"A paragraph with {1} is converted to {2}.\",\n \"id\",\n \"<i18n-format>\"\n ],\n \"text_15\": \" outermost text at the end \"\n}",
"/template-default-lang/locales/null-template-default-lang-element.ja.json": "",
"/template-default-lang/locales/null-template-default-lang-element.zh-Hans-CN.json": "{\n \"meta\": {},\n \"model\": {},\n \"text\": \"zh-Hans-CN outermost text at the beginning \",\n \"h1_3\": \"zh-Hans-CN outermost header 1\",\n \"text_4\": \"zh-Hans-CN outermost text in the middle \",\n \"span_5\": \"zh-Hans-CN simple text without id\",\n \"span_6\": \"zh-Hans-CN simple text without id 2\",\n \"label-1\": \"zh-Hans-CN simple text with id\",\n \"label-2\": \"zh-Hans-CN simple text with id 2\",\n \"div_9:span\": \"zh-Hans-CN simple text within div\",\n \"div_9:span_1\": \"zh-Hans-CN simple text within div 2\",\n \"div_9:div_2:div\": \"zh-Hans-CN great grandchild text within div\",\n \"div_10:text\": \"zh-Hans-CN simple text as the first element in div \",\n \"div_10:span_1\": \"zh-Hans-CN simple text within div\",\n \"div_10:text_2\": \"zh-Hans-CN simple text in the middle of div \",\n \"div_10:span_3\": \"zh-Hans-CN simple text within div 2\",\n \"div_10:div_4:div\": \"zh-Hans-CN great grandchild text within div\",\n \"div_10:text_5\": \"zh-Hans-CN simple text at the last element in div \",\n \"toplevel-div:span\": \"zh-Hans-CN simple text within div\",\n \"toplevel-div:span_1\": \"zh-Hans-CN simple text within div 2\",\n \"third-level-div\": \"zh-Hans-CN great grandchild text within div\",\n \"second-level-div:div_1\": \"zh-Hans-CN great grandchild text within div without id\",\n \"div_12:ul:li\": \"zh-Hans-CN line item without id 1\",\n \"div_12:ul:li_1\": \"zh-Hans-CN line item without id 2\",\n \"div_12:ul:li_2\": \"zh-Hans-CN line item without id 3\",\n \"line-items:li\": \"zh-Hans-CN line item with id 1\",\n \"line-items:li_1\": \"zh-Hans-CN line item with id 2\",\n \"line-items:li_2\": \"zh-Hans-CN line item with id 3\",\n \"p_13\": [\n \"zh-Hans-CN A paragraph with {1} is converted to {2}.\",\n \"zh-Hans-CN parameters\",\n \"zh-Hans-CN <i18n-format>\"\n ],\n \"paragraph\": [\n \"zh-Hans-CN A paragraph with {1} is converted to {2}.\",\n \"zh-Hans-CN id\",\n \"zh-Hans-CN <i18n-format>\"\n ],\n \"text_15\": \"zh-Hans-CN outermost text at the end \"\n}",
"/template-default-lang/locales/template-default-lang-element.zh-Hans-CN.json": "{\n \"meta\": {},\n \"model\": {},\n \"text\": \" zh-Hans-CN outermost text at the beginning \",\n \"h1_3\": \"zh-Hans-CN outermost header 1\",\n \"text_4\": \" zh-Hans-CN outermost text in the middle \",\n \"span_5\": \"zh-Hans-CN simple text without id\",\n \"span_6\": \"zh-Hans-CN simple text without id 2\",\n \"label-1\": \"zh-Hans-CN simple text with id\",\n \"label-2\": \"zh-Hans-CN simple text with id 2\",\n \"div_9:span\": \"zh-Hans-CN simple text within div\",\n \"div_9:span_1\": \"zh-Hans-CN simple text within div 2\",\n \"div_9:div_2:div\": \"zh-Hans-CN great grandchild text within div\",\n \"div_10:text\": \" zh-Hans-CN simple text as the first element in div \",\n \"div_10:span_1\": \"zh-Hans-CN simple text within div\",\n \"div_10:text_2\": \" zh-Hans-CN simple text in the middle of div \",\n \"div_10:span_3\": \"zh-Hans-CN simple text within div 2\",\n \"div_10:div_4:div\": \"zh-Hans-CN great grandchild text within div\",\n \"div_10:text_5\": \" zh-Hans-CN simple text at the last element in div \",\n \"toplevel-div:span\": \"zh-Hans-CN simple text within div\",\n \"toplevel-div:span_1\": \"zh-Hans-CN simple text within div 2\",\n \"third-level-div\": \"zh-Hans-CN great grandchild text within div\",\n \"second-level-div:div_1\": \"zh-Hans-CN great grandchild text within div without id\",\n \"div_12:ul:li\": \"zh-Hans-CN line item without id 1\",\n \"div_12:ul:li_1\": \"zh-Hans-CN line item without id 2\",\n \"div_12:ul:li_2\": \"zh-Hans-CN line item without id 3\",\n \"line-items:li\": \"zh-Hans-CN line item with id 1\",\n \"line-items:li_1\": \"zh-Hans-CN line item with id 2\",\n \"line-items:li_2\": \"zh-Hans-CN line item with id 3\",\n \"p_13\": [\n \"zh-Hans-CN A paragraph with {1} is converted to {2}.\",\n \"zh-Hans-CN parameters\",\n \"zh-Hans-CN <i18n-format>\"\n ],\n \"paragraph\": [\n \"zh-Hans-CN A paragraph with {1} is converted to {2}.\",\n \"zh-Hans-CN id\",\n \"zh-Hans-CN <i18n-format>\"\n ],\n \"text_15\": \" zh-Hans-CN outermost text at the end \"\n}",
"/template-default-lang/null-template-default-lang-element.json": "{\n \"meta\": {},\n \"model\": {},\n \"text\": \" outermost text at the beginning \",\n \"h1_3\": \"outermost header 1\",\n \"text_4\": \" outermost text in the middle \",\n \"span_5\": \"simple text without id\",\n \"span_6\": \"simple text without id 2\",\n \"label-1\": \"simple text with id\",\n \"label-2\": \"simple text with id 2\",\n \"div_9:span\": \"simple text within div\",\n \"div_9:span_1\": \"simple text within div 2\",\n \"div_9:div_2:div\": \"great grandchild text within div\",\n \"div_10:text\": \" simple text as the first element in div \",\n \"div_10:span_1\": \"simple text within div\",\n \"div_10:text_2\": \" simple text in the middle of div \",\n \"div_10:span_3\": \"simple text within div 2\",\n \"div_10:div_4:div\": \"great grandchild text within div\",\n \"div_10:text_5\": \" simple text at the last element in div \",\n \"toplevel-div:span\": \"simple text within div\",\n \"toplevel-div:span_1\": \"simple text within div 2\",\n \"third-level-div\": \"great grandchild text within div\",\n \"second-level-div:div_1\": \"great grandchild text within div without id\",\n \"div_12:ul:li\": \"line item without id 1\",\n \"div_12:ul:li_1\": \"line item without id 2\",\n \"div_12:ul:li_2\": \"line item without id 3\",\n \"line-items:li\": \"line item with id 1\",\n \"line-items:li_1\": \"line item with id 2\",\n \"line-items:li_2\": \"line item with id 3\",\n \"p_13\": [\n \"A paragraph with {1} is converted to {2}.\",\n \"parameters\",\n \"<i18n-format>\"\n ],\n \"paragraph\": [\n \"A paragraph with {1} is converted to {2}.\",\n \"id\",\n \"<i18n-format>\"\n ],\n \"text_15\": \" outermost text at the end \"\n}",
"/template-default-lang/template-default-lang-element.json": "{\n \"meta\": {},\n \"model\": {},\n \"text\": \" fr outermost text at the beginning \",\n \"h1_3\": \"fr outermost header 1\",\n \"text_4\": \" fr outermost text in the middle \",\n \"span_5\": \"fr simple text without id\",\n \"span_6\": \"fr simple text without id 2\",\n \"label-1\": \"fr simple text with id\",\n \"label-2\": \"fr simple text with id 2\",\n \"div_9:span\": \"fr simple text within div\",\n \"div_9:span_1\": \"fr simple text within div 2\",\n \"div_9:div_2:div\": \"fr great grandchild text within div\",\n \"div_10:text\": \" fr simple text as the first element in div \",\n \"div_10:span_1\": \"fr simple text within div\",\n \"div_10:text_2\": \" fr simple text in the middle of div \",\n \"div_10:span_3\": \"fr simple text within div 2\",\n \"div_10:div_4:div\": \"fr great grandchild text within div\",\n \"div_10:text_5\": \" fr simple text at the last element in div \",\n \"toplevel-div:span\": \"fr simple text within div\",\n \"toplevel-div:span_1\": \"fr simple text within div 2\",\n \"third-level-div\": \"fr great grandchild text within div\",\n \"second-level-div:div_1\": \"fr great grandchild text within div without id\",\n \"div_12:ul:li\": \"fr line item without id 1\",\n \"div_12:ul:li_1\": \"fr line item without id 2\",\n \"div_12:ul:li_2\": \"fr line item without id 3\",\n \"line-items:li\": \"fr line item with id 1\",\n \"line-items:li_1\": \"fr line item with id 2\",\n \"line-items:li_2\": \"fr line item with id 3\",\n \"p_13\": [\n \"fr A paragraph with {1} is converted to {2}.\",\n \"fr parameters\",\n \"fr <i18n-format>\"\n ],\n \"paragraph\": [\n \"fr A paragraph with {1} is converted to {2}.\",\n \"fr id\",\n \"fr <i18n-format>\"\n ],\n \"text_15\": \" fr outermost text at the end \"\n}"
};
</script>
<script type="module">
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
/*!
* @license https://github.com/t2ym/i18n-behavior/blob/master/LICENSE.md
* Copyright (c) 2016, Tetsuya Mori <t2y3141592@gmail.com>. All rights reserved.
*/
if (!Number.isNaN) {
// polyfill Number.isNaN for IE11
Number.isNaN = function (value) {
return typeof value === 'number' && isNaN(value);
};
}
// Inheritance of test parameters
var p = Object.setPrototypeOf || function (target, base) {
var obj = Object.create(base);
for (var p in target) {
obj[p] = target[p];
}
return obj;
};
var g = Object.getPrototypeOf;
var _name = 'suite';
var suiteMap = { null: {} };
var s = function (name, baseName, extension) {
if (suiteMap[name]) {
throw new Error('duplicate suite name ' + name);
}
if (!suiteMap[baseName]) {
throw new Error('inexistent base suite name ' + baseName);
}
extension[_name] = name;
extension = p(extension, suiteMap[baseName]);
suiteMap[name] = extension;
return extension;
};
// Utility functions
function updateProperty (element, properties) {
for (var name in properties) {
var path = name.split(/[.]/);
if (path.length === 1) {
element[name] = properties[name];
}
else {
var cursor = element;
var p = path.shift();
while (p) {
if (path.length < 1) {
cursor[p] = properties[name];
element.notifyPath(name, properties[name], true);
break;
}
else if (p === 'PolymerDom') {
cursor = dom(cursor);
}
else if (p === 'html') {
cursor = document.querySelector('html');
}
else {
cursor = cursor[p];
}
p = path.shift();
}
}
}
}
function getProperty (target, name) {
var path = name.split(/[.]/);
if (path.length === 1) {
return target[name];
}
else {
var cursor = target;
var p = path.shift();
while (p) {
//console.log(p, cursor);
if (path.length < 1) {
if (p === 'raw' ||
p === 'text') {
return cursor;
}
else if (p === 'trim') {
return cursor.trim();
}
if (p === 'data') {
cursor = cursor[p];
cursor = cursor.replace(/^[\s]{1,}/g, ' ').replace(/[\s]{1,}$/g, ' ');
return cursor;
}
else {
return cursor[p];
}
}
else if (p === 'PolymerDom') {
cursor = dom(cursor);
}
else if (p === 'previousTextSibling') {
do {
cursor = cursor.previousSibling;
} while (cursor.nodeType === cursor.COMMENT_NODE ||
(cursor.nodeType === cursor.TEXT_NODE && cursor.data.match(/^[\s]*$/)));
}
else if (p === 'nextTextSibling') {
do {
cursor = cursor.nextSibling;
} while (cursor.nodeType === cursor.COMMENT_NODE ||
(cursor.nodeType === cursor.TEXT_NODE && cursor.data.match(/^[\s]*$/)));
}
else if (p === 'effectiveChildNodes') {
cursor = cursor.getEffectiveChildNodes();
}
else if (p === 'nonWS') {
cursor = Array.prototype.filter.call(cursor, function (item) {
return (item.nodeType !== item.TEXT_NODE &&
item.nodeType !== item.COMMENT_NODE) ||
(item.nodeType === item.TEXT_NODE &&
!item.data.match(/^[\s]*$/));
});
}
else {
cursor = cursor[p];
}
p = path.shift();
}
}
}
function deepMap (target, source, map) {
var value;
for (var prop in source) {
value = source[prop];
switch (typeof value) {
case 'string':
case 'number':
case 'boolean':
if (typeof target === 'object') {
target[prop] = map(value, prop);
}
break;
case 'object':
if (typeof target === 'object') {
if (Array.isArray(value)) {
target[prop] = target[prop] || [];
deepMap(target[prop], value, map);
}
else {
target[prop] = target[prop] || {};
deepMap(target[prop], value, map);
}
}
break;
case 'function':
case 'symbol':
case 'undefined':
if (typeof target === 'object') {
target[prop] = value;
}
break;
default:
if (typeof target === 'object') {
target[prop] = value;
}
break;
}
}
}
function translate (lang, path, text) {
var result;
switch (lang) {
case '':
case 'en':
case null:
case undefined:
result = text;
break;
default:
if (!path || path.match(/(textContent|[.]data|[.]text|[.]trim)$/)) {
result = {};
deepMap(result, { text: text }, function (value, prop) {
if (typeof value === 'string' &&
!value.match(/^({{[^{}]*}}|\[\[[^\[\]]*\]\])$/) &&
!value.match(/^[0-9]{1,}$/) &&
prop !== 'type') {
return path && path.match(/[.]trim$/) ? (lang + ' ' + value).trim() : lang + ' ' + value;
}
return value;
});
result = result.text;
}
else {
result = text;
}
}
//console.log('translate (' + lang + ', ' + path + ', ' + JSON.stringify(text, null, 2) + ') = ' + JSON.stringify(result, null, 2));
return result;
}
function minifyText (text) {
if (text && typeof text === 'string') {
text = text.replace(/[\s]{1,}/g, ' ');
}
return text;
}
var isFakeServer = typeof window === 'object' &&
typeof window.location.href === 'string' &&
window.location.href.indexOf('xhr=fake') > 0 &&
typeof window.fakeServerContents === 'object';
var isSuppressingSuiteParams = typeof window === 'object' &&
typeof window.location.href === 'string' &&
window.location.href.indexOf('suppress=true') > 0;
function setupFakeServer (e) {
if (isFakeServer) {
e.server = sinon.fakeServer.create();
e.server.autoRespond = true;
//e.server.autoRespondAfter = 100;
e.server.respondImmediately = true;
e.server.respondWith(/\/test\/[-\w]+(\/.*[.]json)$/, function (xhr, urlPath) {
if (fakeServerContents.hasOwnProperty(urlPath)) {
//console.log('fake-server: 200 ' + urlPath);
xhr.respond(200, { 'Content-Type': 'application/json' }, fakeServerContents[urlPath])
}
else {
//console.log('fake-server: 404 ' + urlPath);
xhr.respond(404, {}, '');
}
});
}
}
function teardownFakeServer (e) {
if (isFakeServer) {
e.server.restore();
}
}
function setupFixture (params, fixtureModel) {
var fixtureName = params.fixture;
var e = document.querySelector('#' + fixtureName);
var runningTest = document.querySelectorAll('.running-test');
var title = document.querySelector('#test-name');
var currentPath = window.location.pathname.split('/');
if (!e) {
throw new Error('Fixture element with id = ' + fixtureName + ' not found');
}
if (title) {
title.textContent =
(currentPath.length >= 2 ? currentPath[currentPath.length - 2] : '') +
(currentPath.length >= 1 ? '/' + currentPath[currentPath.length - 1].replace(/-test[.]html$/, '') + '/': '') +
params.suite;
}
//console.log('setupFixture: suite = ' + params.suite);
if (e.is === 'i18n-dom-bind') {
e.parentElement.classList.add('running-test');
Array.prototype.forEach.call(runningTest, function (node) {
if (node !== e.parentElement) {
node.classList.remove('running-test');
}
});
return new Promise(function (resolve, reject) {
e.addEventListener('dom-change', function setupFixtureDomChange (ev) {
if (dom(ev).rootTarget === e) {
//console.log('setupFixture dom-change');
e.removeEventListener('dom-change', setupFixtureDomChange);
try {
if (fixtureModel &&
typeof fixtureModel.lang === 'string' &&
fixtureModel.lang !== 'en') {
//console.log('setupFixture: waiting for lang-updated');
e.addEventListener('lang-updated', function setupFixtureLangDomChange (event) {
//console.log('setupFixtureLangDomChange');
if (event.target === e &&
e.effectiveLang === fixtureModel.lang) {
//console.log('setupFixtureLangDomChange lang = ' + event.detail.lang + ' effectiveLang = ' + e.effectiveLang);
e.removeEventListener('lang-updated', setupFixtureLangDomChange);
e.render();
resolve(e);
}
});
for (var p in fixtureModel) {
e[p] = fixtureModel[p];
}
e.params = params;
}
else {
for (var p in fixtureModel) {
e[p] = fixtureModel[p];
}
e.params = params;
//console.log('setupFixture: resolving');
e.render();
resolve(e);
}
}
catch (ex) {
reject(ex);
}
}
});
if (e._children) {
e.render();
}
});
}
else {
e.classList.add('running-test');
Array.prototype.forEach.call(runningTest, function (node) {
if (node !== e) {
node.classList.remove('running-test');
}
});
setupFakeServer(e);
return new Promise(function (resolve, reject) {
//console.log('setupFixture: name = ' + fixtureName + ' model = ' + JSON.stringify(fixtureModel, null, 2));
var element = fixture(fixtureName, fixtureModel);
//console.log('setupFixture: name = ' + fixtureName +
// ' element.lang = ' + element.lang +
// ' getAttribute("lang") = ' + element.getAttribute('lang') +
// ' element._lang = ' + element._lang);
if (element) {
if (fixtureModel &&
typeof fixtureModel.lang === 'string' &&
fixtureModel.lang !== 'en' &&
fixtureModel.lang !== element.effectiveLang) {
//console.log('setupFixture: waiting for lang-updated');
element.addEventListener('lang-updated', function setupFixtureLangUpdated (event) {
//console.log('setupFixtureLangUpdated');
if (event.target === element &&
element.effectiveLang === fixtureModel.lang) {
//console.log('setupFixtureLangUpdated lang = ' + event.detail.lang + ' effectiveLang = ' + element.effectiveLang);
element.removeEventListener('lang-updated', setupFixtureLangUpdated);
resolve(element);
}
});
}
else {
//console.log('setupFixture: element ready without lang-updated');
resolve(element);
}
}
else {
reject(new Error('setupFixture returns null for ' +
fixtureName + ' ' + JSON.stringify(fixtureModel,null,2)));
}
});
}
}
function restoreFixture (fixtureName) {
var e = document.querySelector('#' + fixtureName);
if (!e) {
throw new Error('Fixture element with id = ' + fixtureName + ' not found');
}
if (e.is === 'i18n-dom-bind') {
if (e._intervalId) {
clearInterval(e._intervalId);
}
Array.prototype.forEach.call(document.querySelectorAll('[is="i18n-dom-bind"]'),
function (node) {
node.observeHtmlLang = true;
}
);
}
else {
teardownFakeServer(e);
e.restore();
}
}
function getLocalDomRoot (e) {
if (e.is === 'i18n-dom-bind') {
return e.parentElement;
}
else if (e) {
return e.root;
}
else {
return null;
}
}
function suitesRunner (suites) {
suites.forEach(function (params) {
suite(params.suite, function () {
var el;
var p;
var n;
var i, j;
var expected;
var results;
var node;
var rawValue = params.rawValue;
var fixtureElement;
var noProperties;
var lang = params.assign && params.assign.lang ? params.assign.lang : 'en';
var event = params.event ? params.event : 'lang-updated';
var defTimeout = 300000;
var timeout = params.timeout ? (params.timeout < defTimeout ? defTimeout : params.timeout) : defTimeout;
this.timeout(timeout);
(params.setup ? setup : suiteSetup)(function () {
return setupFixture(params, params.fixtureModel)
.then(function (element) {
el = element;
//console.log('setup: element.lang = ' + element.lang);
return new Promise(function (resolve, reject) {
//console.log(params.suite, 'waiting for ' + event);
if (params &&
(params.event ||
params.assign && (params.assign.lang || params.assign['html.lang']))) {
el.addEventListener(event, function fixtureSetup (e) {
if (el === dom(e).rootTarget &&
el.lang === params.lang &&
el.effectiveLang === params.effectiveLang) {
el.removeEventListener(event, fixtureSetup);
//console.log('setup: updateProperty resolving on ' + event);
resolve(el);
}
else {
console.log(params.suite + ' skipping uninteresting event ' + event +
' "' + el.lang + '" "' + params.lang + '" "' + el.effectiveLang + '" "' + params.effectiveLang + '"');
}
});
//console.log('setup: updateProperty ' + JSON.stringify(params.assign, null, 2));
updateProperty(el, params.assign);
}
else {
//console.log('setup: updateProperty ' + JSON.stringify(params.assign, null, 2));
//console.log('setup: updateProperty resolving without ' + event);
updateProperty(el, params.assign);
resolve(el);
}
});
}, function (error) {
throw new Error(error);
});
});
test('{lang, effectiveLang, templateDefaultLang, observeHtmlLang' +
(params.text ? ', text' : '') +
(params.model ? ', model' : '') +
(params.localDOM ? ', local DOM' : '') +
'} properties are set as {' +
(isSuppressingSuiteParams ? '' :
[ params.lang, params.effectiveLang, params.templateDefaultLang, params.observeHtmlLang].join(', ') +
(params.text ? ', ' + JSON.stringify(params.text, null, 2) : '') +
(params.model ? ', ' + JSON.stringify(params.model, null, 2) : '') +
(!params.setup && params.localDOM ? ', ' + JSON.stringify(params.localDOM, null, 2) : '')) +
'}' +
(params.assign && params.assign.lang ? ' for ' + params.assign.lang : ''), function () {
assert.isString(el.lang, 'lang property is a string');
assert.equal(el.lang, params.lang, 'lang property is set');
assert.isString(el.effectiveLang, 'effectiveLang property is a string');
assert.equal(el.effectiveLang, params.effectiveLang, 'effectiveLang property is set');
assert.isString(el.templateDefaultLang, 'templateDefaultLang property is a string');
assert.equal(el.templateDefaultLang, params.templateDefaultLang, 'templateDefaultLang property is set');
assert.isBoolean(el.observeHtmlLang, 'observeHtmlLang property is a Boolean');
assert.equal(el.observeHtmlLang, params.observeHtmlLang, 'observeHtmlLang property is set');
if (params.text) {
expected = deepMap(deepcopy(params.text), params.text, minifyText);
noProperties = true;
assert.isObject(el.text, 'text property is an object');
//console.log(JSON.stringify(e.detail, null, 2));
//console.log(JSON.stringify(el.text, null, 2));
for (p in expected) {
noProperties = false;
assert.deepEqual(deepMap(deepcopy(el.text[p]), el.text[p], minifyText),
params.rawText ? expected[p] : translate(params.effectiveLang, null, expected[p]),
'text.' + p + ' property is set for ' + params.effectiveLang);
}
if (noProperties) {
assert.deepEqual(deepMap(deepcopy(el.text), el.text, minifyText),
expected,
'text property is set');
}
}
if (params.model) {
noProperties = true;
assert.isObject(el.model, 'model property is an object');
for (p in params.model) {
noProperties = false;
//console.log('model.' + p + ' = ' + JSON.stringify(el.model[p]));
//console.log('expected model.' + p + ' = ' + JSON.stringify(translate(el.effectiveLang, null, params.model[p])));
assert.deepEqual(el.model[p],
params.rawText ? params.model[p] : translate(params.effectiveLang, null, params.model[p]),
'model.' + p + ' property is set for ' + params.effectiveLang);
}
if (noProperties) {
assert.deepEqual(el.model, params.model, 'model property is set');
}
}
if (!params.setup && params.localDOM) {
params.localDOM.forEach(function (childPath) {
var completeStatus;
var nodes = dom(getLocalDomRoot(el)).querySelectorAll(childPath.select);
assert.ok(nodes.length > 0, childPath.select + ' is defined');
for (var p in childPath) {
if (p === 'select') {
continue;
}
//console.log(p + ' is set as ' + childPath[p]);
if (Array.isArray(childPath[p])) {
//console.log(nodes);
Array.prototype.forEach.call(childPath[p], function (path, i, a) {
assert.equal(minifyText(getProperty(nodes[i], p)),
minifyText(params.rawText ? path : translate(params.effectiveLang, p, path)),
p + ' is set as ' + minifyText(params.rawText ? path : translate(params.effectiveLang, p, path)));
});
}
else {
//console.log(nodes[0]);
assert.equal(minifyText(getProperty(nodes[0], p)),
minifyText(params.rawText ? childPath[p] : translate(params.effectiveLang, p, childPath[p])),
p + ' is set as ' + translate(params.rawText ? childPath[p] : params.effectiveLang, p, childPath[p]));
}
}
//console.log(childPath);
});
}
});
/*
if (params.text) {
test('text' + ' property is set as ' + JSON.stringify(params.text,null,2) +
(params.assign && params.assign.lang ? ' for ' + params.assign.lang : ''), function () {
expected = deepMap(deepcopy(params.text), params.text, minifyText);
noProperties = true;
assert.isObject(el.text, 'text property is an object');
//console.log(JSON.stringify(e.detail, null, 2));
//console.log(JSON.stringify(el.text, null, 2));
for (p in expected) {
noProperties = false;
assert.deepEqual(deepMap(deepcopy(el.text[p]), el.text[p], minifyText),
params.rawText ? expected[p] : translate(params.effectiveLang, null, expected[p]),
'text.' + p + ' property is set for ' + params.effectiveLang);
}
if (noProperties) {
assert.deepEqual(deepMap(deepcopy(el.text), el.text, minifyText),
expected,
'text property is set');
}
});
}
if (params.model) {
test('model' + ' property is set as ' + JSON.stringify(params.model,null,2) +
(params.assign && params.assign.lang ? ' for ' + params.assign.lang : ''), function () {
noProperties = true;
assert.isObject(el.model, 'model property is an object');
for (p in params.model) {
noProperties = false;
//console.log('model.' + p + ' = ' + JSON.stringify(el.model[p]));
//console.log('expected model.' + p + ' = ' + JSON.stringify(translate(el.effectiveLang, null, params.model[p])));
assert.deepEqual(el.model[p],
params.rawText ? params.model[p] : translate(params.effectiveLang, null, params.model[p]),
'model.' + p + ' property is set for ' + params.effectiveLang);
}
if (noProperties) {
assert.deepEqual(el.model, params.model, 'model property is set');
}
});
}
*/
if (params.setup && params.localDOM) {
test('local DOM ' + (isSuppressingSuiteParams ? '{}' : JSON.stringify(params.localDOM, null, 2)) + ' is set' +
(params.assign && params.assign.lang ? ' for ' + params.assign.lang : ''), function () {
params.localDOM.forEach(function (childPath) {
var completeStatus;
var nodes = dom(getLocalDomRoot(el)).querySelectorAll(childPath.select);
assert.ok(nodes.length > 0, childPath.select + ' is defined');
for (var p in childPath) {
if (p === 'select') {
continue;
}
//console.log(p + ' is set as ' + childPath[p]);
if (Array.isArray(childPath[p])) {
//console.log(nodes);
Array.prototype.forEach.call(childPath[p], function (path, i, a) {
assert.equal(minifyText(getProperty(nodes[i], p)),
minifyText(params.rawText ? path : translate(params.effectiveLang, p, path)),
p + ' is set as ' + minifyText(params.rawText ? path : translate(params.effectiveLang, p, path)));
});
}
else {
//console.log(nodes[0]);
assert.equal(minifyText(getProperty(nodes[0], p)),
minifyText(params.rawText ? childPath[p] : translate(params.effectiveLang, p, childPath[p])),
p + ' is set as ' + translate(params.rawText ? childPath[p] : params.effectiveLang, p, childPath[p]));
}
}
//console.log(childPath);
});
});
}
if (params.lightDOM) {
test('light DOM ' + (isSuppressingSuiteParams ? '{}' : JSON.stringify(params.lightDOM, null, 2)) + ' is set' +
(params.assign && params.assign.lang ? ' for ' + params.assign.lang : ''), function () {
params.lightDOM.forEach(function (childPath) {
var completeStatus;
var nodes = dom(el).querySelectorAll(childPath.select);
assert.ok(nodes.length > 0, childPath.select + ' is defined');
for (var p in childPath) {
if (p === 'select') {
continue;
}
//console.log(p + ' is set as ' + childPath[p]);
if (Array.isArray(childPath[p])) {
//console.log(nodes);
Array.prototype.forEach.call(childPath[p], function (path, i, a) {
assert.equal(getProperty(nodes[i], p), translate(params.effectiveLang, p, path), p + ' is set as ' + translate(params.effectiveLang, p, path));
});
}
else {
//console.log(nodes[0]);
assert.equal(getProperty(nodes[0], p), translate(params.effectiveLang, p, childPath[p]), p + ' is set as ' + translate(params.effectiveLang, p, childPath[p]));
}
}
//console.log(childPath);
});
});
}
(params.setup ? teardown : suiteTeardown)(function () {
restoreFixture(params.fixture);
});
});
});
}
</script>
<style>
.test-container.running-test {
display: block;
}
.test-container:not(.running-test) {
display: none;
}
</style>
</head>
<body><div hidden="" by-vulcanize=""><script>(function () {
function resolve() {
document.body.removeAttribute('unresolved');
}
if (window.WebComponents) {
addEventListener('WebComponentsReady', resolve);
} else {
if (document.readyState === 'interactive' || document.readyState === 'complete') {
resolve();
} else {
addEventListener('DOMContentLoaded', resolve);
}
}
}());window.Polymer = {
Settings: function () {
var settings = window.Polymer || {};
if (!settings.noUrlSettings) {
var parts = location.search.slice(1).split('&');
for (var i = 0, o; i < parts.length && (o = parts[i]); i++) {
o = o.split('=');
o[0] && (settings[o[0]] = o[1] || true);
}
}
settings.wantShadow = settings.dom === 'shadow';
settings.hasShadow = Boolean(Element.prototype.createShadowRoot);
settings.nativeShadow = settings.hasShadow && !window.ShadowDOMPolyfill;
settings.useShadow = settings.wantShadow && settings.hasShadow;
settings.hasNativeImports = Boolean('import' in document.createElement('link'));
settings.useNativeImports = settings.hasNativeImports;
settings.useNativeCustomElements = !window.CustomElements || window.CustomElements.useNative;
settings.useNativeShadow = settings.useShadow && settings.nativeShadow;
settings.usePolyfillProto = !settings.useNativeCustomElements && !Object.__proto__;
settings.hasNativeCSSProperties = !navigator.userAgent.match('AppleWebKit/601') && window.CSS && CSS.supports && CSS.supports('box-shadow', '0 0 0 var(--foo)');
settings.useNativeCSSProperties = settings.hasNativeCSSProperties && settings.lazyRegister && settings.useNativeCSSProperties;
return settings;
}()
};(function () {
var userPolymer = window.Polymer;
window.Polymer = function (prototype) {
if (typeof prototype === 'function') {
prototype = prototype.prototype;
}
if (!prototype) {
prototype = {};
}
var factory = desugar(prototype);
prototype = factory.prototype;
var options = { prototype: prototype };
if (prototype.extends) {
options.extends = prototype.extends;
}
Polymer.telemetry._registrate(prototype);
document.registerElement(prototype.is, options);
return factory;
};
var desugar = function (prototype) {
var base = Polymer.Base;
if (prototype.extends) {
base = Polymer.Base._getExtendedPrototype(prototype.extends);
}
prototype = Polymer.Base.chainObject(prototype, base);
prototype.registerCallback();
return prototype.constructor;
};
if (userPolymer) {
for (var i in userPolymer) {
Polymer[i] = userPolymer[i];
}
}
Polymer.Class = desugar;
}());
Polymer.telemetry = {
registrations: [],
_regLog: function (prototype) {
console.log('[' + prototype.is + ']: registered');
},
_registrate: function (prototype) {
this.registrations.push(prototype);
Polymer.log && this._regLog(prototype);
},
dumpRegistrations: function () {
this.registrations.forEach(this._regLog);
}
};Object.defineProperty(window, 'currentImport', {
enumerable: true,
configurable: true,
get: function () {
return (document._currentScript || document.currentScript).ownerDocument;
}
});Polymer.RenderStatus = {
_ready: false,
_callbacks: [],
whenReady: function (cb) {
if (this._ready) {
cb();
} else {
this._callbacks.push(cb);
}
},
_makeReady: function () {
this._ready = true;
for (var i = 0; i < this._callbacks.length; i++) {
this._callbacks[i]();
}
this._callbacks = [];
},
_catchFirstRender: function () {
requestAnimationFrame(function () {
Polymer.RenderStatus._makeReady();
});
},
_afterNextRenderQueue: [],
_waitingNextRender: false,
afterNextRender: function (element, fn, args) {
this._watchNextRender();
this._afterNextRenderQueue.push([
element,
fn,
args
]);
},
hasRendered: function () {
return this._ready;
},
_watchNextRender: function () {
if (!this._waitingNextRender) {
this._waitingNextRender = true;
var fn = function () {
Polymer.RenderStatus._flushNextRender();
};
if (!this._ready) {
this.whenReady(fn);
} else {
requestAnimationFrame(fn);
}
}
},
_flushNextRender: function () {
var self = this;
setTimeout(function () {
self._flushRenderCallbacks(self._afterNextRenderQueue);
self._afterNextRenderQueue = [];
self._waitingNextRender = false;
});
},
_flushRenderCallbacks: function (callbacks) {
for (var i = 0, h; i < callbacks.length; i++) {
h = callbacks[i];
h[1].apply(h[0], h[2] || Polymer.nar);
}
}
};
if (window.HTMLImports) {
HTMLImports.whenReady(function () {
Polymer.RenderStatus._catchFirstRender();
});
} else {
Polymer.RenderStatus._catchFirstRender();
}
Polymer.ImportStatus = Polymer.RenderStatus;
Polymer.ImportStatus.whenLoaded = Polymer.ImportStatus.whenReady;(function () {
'use strict';
var settings = Polymer.Settings;
Polymer.Base = {
__isPolymerInstance__: true,
_addFeature: function (feature) {
this.extend(this, feature);
},
registerCallback: function () {
if (settings.lazyRegister === 'max') {
if (this.beforeRegister) {
this.beforeRegister();
}
} else {
this._desugarBehaviors();
this._doBehavior('beforeRegister');
}
this._registerFeatures();
if (!settings.lazyRegister) {
this.ensureRegisterFinished();
}
},
createdCallback: function () {
if (!this.__hasRegisterFinished) {
this._ensureRegisterFinished(this.__proto__);
}
Polymer.telemetry.instanceCount++;
this.root = this;
this._doBehavior('created');
this._initFeatures();
},
ensureRegisterFinished: function () {
this._ensureRegisterFinished(this);
},
_ensureRegisterFinished: function (proto) {
if (proto.__hasRegisterFinished !== proto.is || !proto.is) {
if (settings.lazyRegister === 'max') {
proto._desugarBehaviors();
proto._doBehaviorOnly('beforeRegister');
}
proto.__hasRegisterFinished = proto.is;
if (proto._finishRegisterFeatures) {
proto._finishRegisterFeatures();
}
proto._doBehavior('registered');
if (settings.usePolyfillProto && proto !== this) {
proto.extend(this, proto);
}
}
},
attachedCallback: function () {
var self = this;
Polymer.RenderStatus.whenReady(function () {
self.isAttached = true;
self._doBehavior('attached');
});
},
detachedCallback: function () {
var self = this;
Polymer.RenderStatus.whenReady(function () {
self.isAttached = false;
self._doBehavior('detached');
});
},
attributeChangedCallback: function (name, oldValue, newValue) {
this._attributeChangedImpl(name);
this._doBehavior('attributeChanged', [
name,
oldValue,
newValue
]);
},
_attributeChangedImpl: function (name) {
this._setAttributeToProperty(this, name);
},
extend: function (target, source) {
if (target && source) {
var n$ = Object.getOwnPropertyNames(source);
for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
this.copyOwnProperty(n, source, target);
}
}
return target || source;
},
mixin: function (target, source) {
for (var i in source) {
target[i] = source[i];
}
return target;
},
copyOwnProperty: function (name, source, target) {
var pd = Object.getOwnPropertyDescriptor(source, name);
if (pd) {
Object.defineProperty(target, name, pd);
}
},
_logger: function (level, args) {
if (args.length === 1 && Array.isArray(args[0])) {
args = args[0];
}
switch (level) {
case 'log':
case 'warn':
case 'error':
console[level].apply(console, args);
break;
}
},
_log: function () {
var args = Array.prototype.slice.call(arguments, 0);
this._logger('log', args);
},
_warn: function () {
var args = Array.prototype.slice.call(arguments, 0);
this._logger('warn', args);
},
_error: function () {
var args = Array.prototype.slice.call(arguments, 0);
this._logger('error', args);
},
_logf: function () {
return this._logPrefix.concat(this.is).concat(Array.prototype.slice.call(arguments, 0));
}
};
Polymer.Base._logPrefix = function () {
var color = window.chrome && !/edge/i.test(navigator.userAgent) || /firefox/i.test(navigator.userAgent);
return color ? [
'%c[%s::%s]:',
'font-weight: bold; background-color:#EEEE00;'
] : ['[%s::%s]:'];
}();
Polymer.Base.chainObject = function (object, inherited) {
if (object && inherited && object !== inherited) {
if (!Object.__proto__) {
object = Polymer.Base.extend(Object.create(inherited), object);
}
object.__proto__ = inherited;
}
return object;
};
Polymer.Base = Polymer.Base.chainObject(Polymer.Base, HTMLElement.prototype);
if (window.CustomElements) {
Polymer.instanceof = CustomElements.instanceof;
} else {
Polymer.instanceof = function (obj, ctor) {
return obj instanceof ctor;
};
}
Polymer.isInstance = function (obj) {
return Boolean(obj && obj.__isPolymerInstance__);
};
Polymer.telemetry.instanceCount = 0;
}());(function () {
var modules = {};
var lcModules = {};
var findModule = function (id) {
return modules[id] || lcModules[id.toLowerCase()];
};
var DomModule = function () {
return document.createElement('dom-module');
};
DomModule.prototype = Object.create(HTMLElement.prototype);
Polymer.Base.extend(DomModule.prototype, {
constructor: DomModule,
createdCallback: function () {
this.register();
},
register: function (id) {
id = id || this.id || this.getAttribute('name') || this.getAttribute('is');
if (id) {
this.id = id;
modules[id] = this;
lcModules[id.toLowerCase()] = this;
}
},
import: function (id, selector) {
if (id) {
var m = findModule(id);
if (!m) {
forceDomModulesUpgrade();
m = findModule(id);
}
if (m && selector) {
m = m.querySelector(selector);
}
return m;
}
}
});
var cePolyfill = window.CustomElements && !CustomElements.useNative;
document.registerElement('dom-module', DomModule);
function forceDomModulesUpgrade() {
if (cePolyfill) {
var script = document._currentScript || document.currentScript;
var doc = script && script.ownerDocument || document;
var modules = doc.querySelectorAll('dom-module');
for (var i = modules.length - 1, m; i >= 0 && (m = modules[i]); i--) {
if (m.__upgraded__) {
return;
} else {
CustomElements.upgrade(m);
}
}
}
}
}());Polymer.Base._addFeature({
_prepIs: function () {
if (!this.is) {
var module = (document._currentScript || document.currentScript).parentNode;
if (module.localName === 'dom-module') {
var id = module.id || module.getAttribute('name') || module.getAttribute('is');
this.is = id;
}
}
if (this.is) {
this.is = this.is.toLowerCase();
}
}
});Polymer.Base._addFeature({
behaviors: [],
_desugarBehaviors: function () {
if (this.behaviors.length) {
this.behaviors = this._desugarSomeBehaviors(this.behaviors);
}
},
_desugarSomeBehaviors: function (behaviors) {
var behaviorSet = [];
behaviors = this._flattenBehaviorsList(behaviors);
for (var i = behaviors.length - 1; i >= 0; i--) {
var b = behaviors[i];
if (behaviorSet.indexOf(b) === -1) {
this._mixinBehavior(b);
behaviorSet.unshift(b);
}
}
return behaviorSet;
},
_flattenBehaviorsList: function (behaviors) {
var flat = [];
for (var i = 0; i < behaviors.length; i++) {
var b = behaviors[i];
if (b instanceof Array) {
flat = flat.concat(this._flattenBehaviorsList(b));
} else if (b) {
flat.push(b);
} else {
this._warn(this._logf('_flattenBehaviorsList', 'behavior is null, check for missing or 404 import'));
}
}
return flat;
},
_mixinBehavior: function (b) {
var n$ = Object.getOwnPropertyNames(b);
for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
if (!Polymer.Base._behaviorProperties[n] && !this.hasOwnProperty(n)) {
this.copyOwnProperty(n, b, this);
}
}
},
_prepBehaviors: function () {
this._prepFlattenedBehaviors(this.behaviors);
},
_prepFlattenedBehaviors: function (behaviors) {
for (var i = 0, l = behaviors.length; i < l; i++) {
this._prepBehavior(behaviors[i]);
}
this._prepBehavior(this);
},
_doBehavior: function (name, args) {
for (var i = 0; i < this.behaviors.length; i++) {
this._invokeBehavior(this.behaviors[i], name, args);
}
this._invokeBehavior(this, name, args);
},
_doBehaviorOnly: function (name, args) {
for (var i = 0; i < this.behaviors.length; i++) {
this._invokeBehavior(this.behaviors[i], name, args);
}
},
_invokeBehavior: function (b, name, args) {
var fn = b[name];
if (fn) {
fn.apply(this, args || Polymer.nar);
}
},
_marshalBehaviors: function () {
for (var i = 0; i < this.behaviors.length; i++) {
this._marshalBehavior(this.behaviors[i]);
}
this._marshalBehavior(this);
}
});
Polymer.Base._behaviorProperties = {
hostAttributes: true,
beforeRegister: true,
registered: true,
properties: true,
observers: true,
listeners: true,
created: true,
attached: true,
detached: true,
attributeChanged: true,
ready: true
};Polymer.Base._addFeature({
_getExtendedPrototype: function (tag) {
return this._getExtendedNativePrototype(tag);
},
_nativePrototypes: {},
_getExtendedNativePrototype: function (tag) {
var p = this._nativePrototypes[tag];
if (!p) {
var np = this.getNativePrototype(tag);
p = this.extend(Object.create(np), Polymer.Base);
this._nativePrototypes[tag] = p;
}
return p;
},
getNativePrototype: function (tag) {
return Object.getPrototypeOf(document.createElement(tag));
}
});Polymer.Base._addFeature({
_prepConstructor: function () {
this._factoryArgs = this.extends ? [
this.extends,
this.is
] : [this.is];
var ctor = function () {
return this._factory(arguments);
};
if (this.hasOwnProperty('extends')) {
ctor.extends = this.extends;
}
Object.defineProperty(this, 'constructor', {
value: ctor,
writable: true,
configurable: true
});
ctor.prototype = this;
},
_factory: function (args) {
var elt = document.createElement.apply(document, this._factoryArgs);
if (this.factoryImpl) {
this.factoryImpl.apply(elt, args);
}
return elt;
}
});Polymer.nob = Object.create(null);
Polymer.Base._addFeature({
properties: {},
getPropertyInfo: function (property) {
var info = this._getPropertyInfo(property, this.properties);
if (!info) {
for (var i = 0; i < this.behaviors.length; i++) {
info = this._getPropertyInfo(property, this.behaviors[i].properties);
if (info) {
return info;
}
}
}
return info || Polymer.nob;
},
_getPropertyInfo: function (property, properties) {
var p = properties && properties[property];
if (typeof p === 'function') {
p = properties[property] = { type: p };
}
if (p) {
p.defined = true;
}
return p;
},
_prepPropertyInfo: function () {
this._propertyInfo = {};
for (var i = 0; i < this.behaviors.length; i++) {
this._addPropertyInfo(this._propertyInfo, this.behaviors[i].properties);
}
this._addPropertyInfo(this._propertyInfo, this.properties);
this._addPropertyInfo(this._propertyInfo, this._propertyEffects);
},
_addPropertyInfo: function (target, source) {
if (source) {
var t, s;
for (var i in source) {
t = target[i];
s = source[i];
if (i[0] === '_' && !s.readOnly) {
continue;
}
if (!target[i]) {
target[i] = {
type: typeof s === 'function' ? s : s.type,
readOnly: s.readOnly,
attribute: Polymer.CaseMap.camelToDashCase(i)
};
} else {
if (!t.type) {
t.type = s.type;
}
if (!t.readOnly) {
t.readOnly = s.readOnly;
}
}
}
}
}
});Polymer.CaseMap = {
_caseMap: {},
_rx: {
dashToCamel: /-[a-z]/g,
camelToDash: /([A-Z])/g
},
dashToCamelCase: function (dash) {
return this._caseMap[dash] || (this._caseMap[dash] = dash.indexOf('-') < 0 ? dash : dash.replace(this._rx.dashToCamel, function (m) {
return m[1].toUpperCase();
}));
},
camelToDashCase: function (camel) {
return this._caseMap[camel] || (this._caseMap[camel] = camel.replace(this._rx.camelToDash, '-$1').toLowerCase());
}
};Polymer.Base._addFeature({
_addHostAttributes: function (attributes) {
if (!this._aggregatedAttributes) {
this._aggregatedAttributes = {};
}
if (attributes) {
this.mixin(this._aggregatedAttributes, attributes);
}
},
_marshalHostAttributes: function () {
if (this._aggregatedAttributes) {
this._applyAttributes(this, this._aggregatedAttributes);
}
},
_applyAttributes: function (node, attr$) {
for (var n in attr$) {
if (!this.hasAttribute(n) && n !== 'class') {
var v = attr$[n];
this.serializeValueToAttribute(v, n, this);
}
}
},
_marshalAttributes: function () {
this._takeAttributesToModel(this);
},
_takeAttributesToModel: function (model) {
if (this.hasAttributes()) {
for (var i in this._propertyInfo) {
var info = this._propertyInfo[i];
if (this.hasAttribute(info.attribute)) {
this._setAttributeToProperty(model, info.attribute, i, info);
}
}
}
},
_setAttributeToProperty: function (model, attribute, property, info) {
if (!this._serializing) {
property = property || Polymer.CaseMap.dashToCamelCase(attribute);
info = info || this._propertyInfo && this._propertyInfo[property];
if (info && !info.readOnly) {
var v = this.getAttribute(attribute);
model[property] = this.deserialize(v, info.type);
}
}
},
_serializing: false,
reflectPropertyToAttribute: function (property, attribute, value) {
this._serializing = true;
value = value === undefined ? this[property] : value;
this.serializeValueToAttribute(value, attribute || Polymer.CaseMap.camelToDashCase(property));
this._serializing = false;
},
serializeValueToAttribute: function (value, attribute, node) {
var str = this.serialize(value);
node = node || this;
if (str === undefined) {
node.removeAttribute(attribute);
} else {
node.setAttribute(attribute, str);
}
},
deserialize: function (value, type) {
switch (type) {
case Number:
value = Number(value);
break;
case Boolean:
value = value != null;
break;
case Object:
try {
value = JSON.parse(value);
} catch (x) {
}
break;
case Array:
try {
value = JSON.parse(value);
} catch (x) {
value = null;
console.warn('Polymer::Attributes: couldn`t decode Array as JSON');
}
break;
case Date:
value = new Date(value);
break;
case String:
default:
break;
}
return value;
},
serialize: function (value) {
switch (typeof value) {
case 'boolean':
return value ? '' : undefined;
case 'object':
if (value instanceof Date) {
return value.toString();
} else if (value) {
try {
return JSON.stringify(value);
} catch (x) {
return '';
}
}
default:
return value != null ? value : undefined;
}
}
});Polymer.version = "1.6.1";Polymer.Base._addFeature({
_registerFeatures: function () {
this._prepIs();
this._prepBehaviors();
this._prepConstructor();
this._prepPropertyInfo();
},
_prepBehavior: function (b) {
this._addHostAttributes(b.hostAttributes);
},
_marshalBehavior: function (b) {
},
_initFeatures: function () {
this._marshalHostAttributes();
this._marshalBehaviors();
}
});</script>
<script type="module">
import { Base } from '@polymer/polymer/polymer-legacy.js';
import { DomModule as DomModule$0 } from '@polymer/polymer/lib/elements/dom-module.js';
import { dom as dom$0, flush as flush$0, DomApi as DomApi$0, addDebouncer as addDebouncer$0 } from '@polymer/polymer/lib/legacy/polymer.dom.js';
import { useNativeCustomElements, useShadow as useShadow$0 } from '@polymer/polymer/lib/utils/settings.js';
import { calculateSplices as calculateSplices$0 } from '@polymer/polymer/lib/utils/array-splice.js';
import * as async from '@polymer/polymer/lib/utils/async.js';
Base._addFeature({
_prepTemplate: function () {
if (this._template === undefined) {
this._template = DomModule$0.import(this.is, 'template');
}
if (this._template && this._template.hasAttribute('is')) {
this._warn(this._logf('_prepTemplate', 'top-level Polymer template ' + 'must not be a type-extension, found', this._template, 'Move inside simple <template>.'));
}
if (this._template && !this._template.content && window.HTMLTemplateElement && HTMLTemplateElement.decorate) {
HTMLTemplateElement.decorate(this._template);
}
},
_stampTemplate: function () {
if (this._template) {
this.root = this.instanceTemplate(this._template);
}
},
instanceTemplate: function (template) {
var dom = document.importNode(template._content || template.content, true);
return dom;
}
});
var baseAttachedCallback = Base.attachedCallback;
Base._addFeature({
_hostStack: [],
ready: function () {
},
_registerHost: function (host) {
this.dataHost = host = host || Base._hostStack[Base._hostStack.length - 1];
if (host && host._clients) {
host._clients.push(this);
}
this._clients = null;
this._clientsReadied = false;
},
_beginHosting: function () {
Base._hostStack.push(this);
if (!this._clients) {
this._clients = [];
}
},
_endHosting: function () {
Base._hostStack.pop();
},
_tryReady: function () {
this._readied = false;
if (this._canReady()) {
this._ready();
}
},
_canReady: function () {
return !this.dataHost || this.dataHost._clientsReadied;
},
_ready: function () {
this._beforeClientsReady();
if (this._template) {
this._setupRoot();
this._readyClients();
}
this._clientsReadied = true;
this._clients = null;
this._afterClientsReady();
this._readySelf();
},
_readyClients: function () {
this._beginDistribute();
var c$ = this._clients;
if (c$) {
for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
c._ready();
}
}
this._finishDistribute();
},
_readySelf: function () {
this._doBehavior('ready');
this._readied = true;
if (this._attachedPending) {
this._attachedPending = false;
this.attachedCallback();
}
},
_beforeClientsReady: function () {
},
_afterClientsReady: function () {
},
_beforeAttached: function () {
},
attachedCallback: function () {
if (this._readied) {
this._beforeAttached();
baseAttachedCallback.call(this);
} else {
this._attachedPending = true;
}
}
});
export const ArraySplice = function () {
function newSplice(index, removed, addedCount) {
return {
index: index,
removed: removed,
addedCount: addedCount
};
}
var EDIT_LEAVE = 0;
var EDIT_UPDATE = 1;
var EDIT_ADD = 2;
var EDIT_DELETE = 3;
function ArraySplice() {
}
ArraySplice.prototype = {
calcEditDistances: function (current, currentStart, currentEnd, old, oldStart, oldEnd) {
var rowCount = oldEnd - oldStart + 1;
var columnCount = currentEnd - currentStart + 1;
var distances = new Array(rowCount);
for (var i = 0; i < rowCount; i++) {
distances[i] = new Array(columnCount);
distances[i][0] = i;
}
for (var j = 0; j < columnCount; j++)
distances[0][j] = j;
for (i = 1; i < rowCount; i++) {
for (j = 1; j < columnCount; j++) {
if (this.equals(current[currentStart + j - 1], old[oldStart + i - 1]))
distances[i][j] = distances[i - 1][j - 1];
else {
var north = distances[i - 1][j] + 1;
var west = distances[i][j - 1] + 1;
distances[i][j] = north < west ? north : west;
}
}
}
return distances;
},
spliceOperationsFromEditDistances: function (distances) {
var i = distances.length - 1;
var j = distances[0].length - 1;
var current = distances[i][j];
var edits = [];
while (i > 0 || j > 0) {
if (i == 0) {
edits.push(EDIT_ADD);
j--;
continue;
}
if (j == 0) {
edits.push(EDIT_DELETE);
i--;
continue;
}
var northWest = distances[i - 1][j - 1];
var west = distances[i - 1][j];
var north = distances[i][j - 1];
var min;
if (west < north)
min = west < northWest ? west : northWest;
else
min = north < northWest ? north : northWest;
if (min == northWest) {
if (northWest == current) {
edits.push(EDIT_LEAVE);
} else {
edits.push(EDIT_UPDATE);
current = northWest;
}
i--;
j--;
} else if (min == west) {
edits.push(EDIT_DELETE);
i--;
current = west;
} else {
edits.push(EDIT_ADD);
j--;
current = north;
}
}
edits.reverse();
return edits;
},
calcSplices: function (current, currentStart, currentEnd, old, oldStart, oldEnd) {
var prefixCount = 0;
var suffixCount = 0;
var minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
if (currentStart == 0 && oldStart == 0)
prefixCount = this.sharedPrefix(current, old, minLength);
if (currentEnd == current.length && oldEnd == old.length)
suffixCount = this.sharedSuffix(current, old, minLength - prefixCount);
currentStart += prefixCount;
oldStart += prefixCount;
currentEnd -= suffixCount;
oldEnd -= suffixCount;
if (currentEnd - currentStart == 0 && oldEnd - oldStart == 0)
return [];
if (currentStart == currentEnd) {
var splice = newSplice(currentStart, [], 0);
while (oldStart < oldEnd)
splice.removed.push(old[oldStart++]);
return [splice];
} else if (oldStart == oldEnd)
return [newSplice(currentStart, [], currentEnd - currentStart)];
var ops = this.spliceOperationsFromEditDistances(this.calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd));
splice = undefined;
var splices = [];
var index = currentStart;
var oldIndex = oldStart;
for (var i = 0; i < ops.length; i++) {
switch (ops[i]) {
case EDIT_LEAVE:
if (splice) {
splices.push(splice);
splice = undefined;
}
index++;
oldIndex++;
break;
case EDIT_UPDATE:
if (!splice)
splice = newSplice(index, [], 0);
splice.addedCount++;
index++;
splice.removed.push(old[oldIndex]);
oldIndex++;
break;
case EDIT_ADD:
if (!splice)
splice = newSplice(index, [], 0);
splice.addedCount++;
index++;
break;
case EDIT_DELETE:
if (!splice)
splice = newSplice(index, [], 0);
splice.removed.push(old[oldIndex]);
oldIndex++;
break;
}
}
if (splice) {
splices.push(splice);
}
return splices;
},
sharedPrefix: function (current, old, searchLength) {
for (var i = 0; i < searchLength; i++)
if (!this.equals(current[i], old[i]))
return i;
return searchLength;
},
sharedSuffix: function (current, old, searchLength) {
var index1 = current.length;
var index2 = old.length;
var count = 0;
while (count < searchLength && this.equals(current[--index1], old[--index2]))
count++;
return count;
},
calculateSplices: function (current, previous) {
return this.calcSplices(current, 0, current.length, previous, 0, previous.length);
},
equals: function (currentValue, previousValue) {
return currentValue === previousValue;
}
};
return new ArraySplice();
}();
export const domInnerHTML = function () {
var escapeAttrRegExp = /[&\u00A0"]/g;
var escapeDataRegExp = /[&\u00A0<>]/g;
function escapeReplace(c) {
switch (c) {
case '&':
return '&';
case '<':
return '<';
case '>':
return '>';
case '"':
return '"';
case '\xA0':
return ' ';
}
}
function escapeAttr(s) {
return s.replace(escapeAttrRegExp, escapeReplace);
}
function escapeData(s) {
return s.replace(escapeDataRegExp, escapeReplace);
}
function makeSet(arr) {
var set = {};
for (var i = 0; i < arr.length; i++) {
set[arr[i]] = true;
}
return set;
}
var voidElements = makeSet([
'area',
'base',
'br',
'col',
'command',
'embed',
'hr',
'img',
'input',
'keygen',
'link',
'meta',
'param',
'source',
'track',
'wbr'
]);
var plaintextParents = makeSet([
'style',
'script',
'xmp',
'iframe',
'noembed',
'noframes',
'plaintext',
'noscript'
]);
function getOuterHTML(node, parentNode, composed) {
switch (node.nodeType) {
case Node.ELEMENT_NODE:
var tagName = node.localName;
var s = '<' + tagName;
var attrs = node.attributes;
for (var i = 0, attr; attr = attrs[i]; i++) {
s += ' ' + attr.name + '="' + escapeAttr(attr.value) + '"';
}
s += '>';
if (voidElements[tagName]) {
return s;
}
return s + getInnerHTML(node, composed) + '</' + tagName + '>';
case Node.TEXT_NODE:
var data = node.data;
if (parentNode && plaintextParents[parentNode.localName]) {
return data;
}
return escapeData(data);
case Node.COMMENT_NODE:
return '<!--' + node.data + '-->';
default:
console.error(node);
throw new Error('not implemented');
}
}
function getInnerHTML(node, composed) {
if (node instanceof HTMLTemplateElement)
node = node.content;
var s = '';
var c$ = dom$0(node).childNodes;
for (var i = 0, l = c$.length, child; i < l && (child = c$[i]); i++) {
s += getOuterHTML(child, node, composed);
}
return s;
}
return { getInnerHTML: getInnerHTML };
}();
var nativeInsertBefore = Element.prototype.insertBefore;
var nativeAppendChild = Element.prototype.appendChild;
var nativeRemoveChild = Element.prototype.removeChild;
export const TreeApi = {
arrayCopyChildNodes: function (parent) {
var copy = [], i = 0;
for (var n = parent.firstChild; n; n = n.nextSibling) {
copy[i++] = n;
}
return copy;
},
arrayCopyChildren: function (parent) {
var copy = [], i = 0;
for (var n = parent.firstElementChild; n; n = n.nextElementSibling) {
copy[i++] = n;
}
return copy;
},
arrayCopy: function (a$) {
var l = a$.length;
var copy = new Array(l);
for (var i = 0; i < l; i++) {
copy[i] = a$[i];
}
return copy;
}
};
TreeApi.Logical = {
hasParentNode: function (node) {
return Boolean(node.__dom && node.__dom.parentNode);
},
hasChildNodes: function (node) {
return Boolean(node.__dom && node.__dom.childNodes !== undefined);
},
getChildNodes: function (node) {
return this.hasChildNodes(node) ? this._getChildNodes(node) : node.childNodes;
},
_getChildNodes: function (node) {
if (!node.__dom.childNodes) {
node.__dom.childNodes = [];
for (var n = node.__dom.firstChild; n; n = n.__dom.nextSibling) {
node.__dom.childNodes.push(n);
}
}
return node.__dom.childNodes;
},
getParentNode: function (node) {
return node.__dom && node.__dom.parentNode !== undefined ? node.__dom.parentNode : node.parentNode;
},
getFirstChild: function (node) {
return node.__dom && node.__dom.firstChild !== undefined ? node.__dom.firstChild : node.firstChild;
},
getLastChild: function (node) {
return node.__dom && node.__dom.lastChild !== undefined ? node.__dom.lastChild : node.lastChild;
},
getNextSibling: function (node) {
return node.__dom && node.__dom.nextSibling !== undefined ? node.__dom.nextSibling : node.nextSibling;
},
getPreviousSibling: function (node) {
return node.__dom && node.__dom.previousSibling !== undefined ? node.__dom.previousSibling : node.previousSibling;
},
getFirstElementChild: function (node) {
return node.__dom && node.__dom.firstChild !== undefined ? this._getFirstElementChild(node) : node.firstElementChild;
},
_getFirstElementChild: function (node) {
var n = node.__dom.firstChild;
while (n && n.nodeType !== Node.ELEMENT_NODE) {
n = n.__dom.nextSibling;
}
return n;
},
getLastElementChild: function (node) {
return node.__dom && node.__dom.lastChild !== undefined ? this._getLastElementChild(node) : node.lastElementChild;
},
_getLastElementChild: function (node) {
var n = node.__dom.lastChild;
while (n && n.nodeType !== Node.ELEMENT_NODE) {
n = n.__dom.previousSibling;
}
return n;
},
getNextElementSibling: function (node) {
return node.__dom && node.__dom.nextSibling !== undefined ? this._getNextElementSibling(node) : node.nextElementSibling;
},
_getNextElementSibling: function (node) {
var n = node.__dom.nextSibling;
while (n && n.nodeType !== Node.ELEMENT_NODE) {
n = n.__dom.nextSibling;
}
return n;
},
getPreviousElementSibling: function (node) {
return node.__dom && node.__dom.previousSibling !== undefined ? this._getPreviousElementSibling(node) : node.previousElementSibling;
},
_getPreviousElementSibling: function (node) {
var n = node.__dom.previousSibling;
while (n && n.nodeType !== Node.ELEMENT_NODE) {
n = n.__dom.previousSibling;
}
return n;
},
saveChildNodes: function (node) {
if (!this.hasChildNodes(node)) {
node.__dom = node.__dom || {};
node.__dom.firstChild = node.firstChild;
node.__dom.lastChild = node.lastChild;
node.__dom.childNodes = [];
for (var n = node.firstChild; n; n = n.nextSibling) {
n.__dom = n.__dom || {};
n.__dom.parentNode = node;
node.__dom.childNodes.push(n);
n.__dom.nextSibling = n.nextSibling;
n.__dom.previousSibling = n.previousSibling;
}
}
},
recordInsertBefore: function (node, container, ref_node) {
container.__dom.childNodes = null;
if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
for (var n = node.firstChild; n; n = n.nextSibling) {
this._linkNode(n, container, ref_node);
}
} else {
this._linkNode(node, container, ref_node);
}
},
_linkNode: function (node, container, ref_node) {
node.__dom = node.__dom || {};
container.__dom = container.__dom || {};
if (ref_node) {
ref_node.__dom = ref_node.__dom || {};
}
node.__dom.previousSibling = ref_node ? ref_node.__dom.previousSibling : container.__dom.lastChild;
if (node.__dom.previousSibling) {
node.__dom.previousSibling.__dom.nextSibling = node;
}
node.__dom.nextSibling = ref_node || null;
if (node.__dom.nextSibling) {
node.__dom.nextSibling.__dom.previousSibling = node;
}
node.__dom.parentNode = container;
if (ref_node) {
if (ref_node === container.__dom.firstChild) {
container.__dom.firstChild = node;
}
} else {
container.__dom.lastChild = node;
if (!container.__dom.firstChild) {
container.__dom.firstChild = node;
}
}
container.__dom.childNodes = null;
},
recordRemoveChild: function (node, container) {
node.__dom = node.__dom || {};
container.__dom = container.__dom || {};
if (node === container.__dom.firstChild) {
container.__dom.firstChild = node.__dom.nextSibling;
}
if (node === container.__dom.lastChild) {
container.__dom.lastChild = node.__dom.previousSibling;
}
var p = node.__dom.previousSibling;
var n = node.__dom.nextSibling;
if (p) {
p.__dom.nextSibling = n;
}
if (n) {
n.__dom.previousSibling = p;
}
node.__dom.parentNode = node.__dom.previousSibling = node.__dom.nextSibling = undefined;
container.__dom.childNodes = null;
}
};
TreeApi.Composed = {
getChildNodes: function (node) {
return TreeApi.arrayCopyChildNodes(node);
},
getParentNode: function (node) {
return node.parentNode;
},
clearChildNodes: function (node) {
node.textContent = '';
},
insertBefore: function (parentNode, newChild, refChild) {
return nativeInsertBefore.call(parentNode, newChild, refChild || null);
},
appendChild: function (parentNode, newChild) {
return nativeAppendChild.call(parentNode, newChild);
},
removeChild: function (parentNode, node) {
return nativeRemoveChild.call(parentNode, node);
}
};
export const DomApi = function () {
'use strict';
var Settings = undefined;
var TreeApi = TreeApi;
var DomApi = function (node) {
this.node = needsToWrap ? DomApi.wrap(node) : node;
};
var needsToWrap = Settings.hasShadow && !Settings.nativeShadow;
DomApi.wrap = window.wrap ? window.wrap : function (node) {
return node;
};
DomApi.prototype = {
flush: function () {
flush$0();
},
deepContains: function (node) {
if (this.node.contains(node)) {
return true;
}
var n = node;
var doc = node.ownerDocument;
while (n && n !== doc && n !== this.node) {
n = dom$0(n).parentNode || n.host;
}
return n === this.node;
},
queryDistributedElements: function (selector) {
var c$ = this.getEffectiveChildNodes();
var list = [];
for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
if (c.nodeType === Node.ELEMENT_NODE && DomApi.matchesSelector.call(c, selector)) {
list.push(c);
}
}
return list;
},
getEffectiveChildNodes: function () {
var list = [];
var c$ = this.childNodes;
for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
if (c.localName === CONTENT) {
var d$ = dom(c).getDistributedNodes();
for (var j = 0; j < d$.length; j++) {
list.push(d$[j]);
}
} else {
list.push(c);
}
}
return list;
},
observeNodes: function (callback) {
if (callback) {
if (!this.observer) {
this.observer = this.node.localName === CONTENT ? new DomApi.DistributedNodesObserver(this) : new DomApi.EffectiveNodesObserver(this);
}
return this.observer.addListener(callback);
}
},
unobserveNodes: function (handle) {
if (this.observer) {
this.observer.removeListener(handle);
}
},
notifyObserver: function () {
if (this.observer) {
this.observer.notify();
}
},
_query: function (matcher, node, halter) {
node = node || this.node;
var list = [];
this._queryElements(TreeApi.Logical.getChildNodes(node), matcher, halter, list);
return list;
},
_queryElements: function (elements, matcher, halter, list) {
for (var i = 0, l = elements.length, c; i < l && (c = elements[i]); i++) {
if (c.nodeType === Node.ELEMENT_NODE) {
if (this._queryElement(c, matcher, halter, list)) {
return true;
}
}
}
},
_queryElement: function (node, matcher, halter, list) {
var result = matcher(node);
if (result) {
list.push(node);
}
if (halter && halter(result)) {
return result;
}
this._queryElements(TreeApi.Logical.getChildNodes(node), matcher, halter, list);
}
};
var CONTENT = DomApi.CONTENT = 'content';
var dom = DomApi.factory = function (node) {
node = node || document;
if (!node.__domApi) {
node.__domApi = new DomApi.ctor(node);
}
return node.__domApi;
};
DomApi.hasApi = function (node) {
return Boolean(node.__domApi);
};
DomApi.ctor = DomApi;
Polymer.dom = function (obj, patch) {
if (obj instanceof Event) {
return EventApi.factory(obj);
} else {
return DomApi.factory(obj, patch);
}
};
var p = Element.prototype;
DomApi.matchesSelector = p.matches || p.matchesSelector || p.mozMatchesSelector || p.msMatchesSelector || p.oMatchesSelector || p.webkitMatchesSelector;
return DomApi;
}();
var Settings = undefined;
var DomApi = DomApi$0;
var dom = DomApi.factory;
var TreeApi = TreeApi;
var getInnerHTML = domInnerHTML.getInnerHTML;
var CONTENT = DomApi.CONTENT;
if (Settings.useShadow) {
return;
}
var nativeCloneNode = Element.prototype.cloneNode;
var nativeImportNode = Document.prototype.importNode;
Base.extend(DomApi.prototype, {
_lazyDistribute: function (host) {
if (host.shadyRoot && host.shadyRoot._distributionClean) {
host.shadyRoot._distributionClean = false;
addDebouncer$0(host.debounce('_distribute', host._distributeContent));
}
},
appendChild: function (node) {
return this.insertBefore(node);
},
insertBefore: function (node, ref_node) {
if (ref_node && TreeApi.Logical.getParentNode(ref_node) !== this.node) {
throw Error('The ref_node to be inserted before is not a child ' + 'of this node');
}
if (node.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) {
var parent = TreeApi.Logical.getParentNode(node);
if (parent) {
if (DomApi.hasApi(parent)) {
dom(parent).notifyObserver();
}
this._removeNode(node);
} else {
this._removeOwnerShadyRoot(node);
}
}
if (!this._addNode(node, ref_node)) {
if (ref_node) {
ref_node = ref_node.localName === CONTENT ? this._firstComposedNode(ref_node) : ref_node;
}
var container = this.node._isShadyRoot ? this.node.host : this.node;
if (ref_node) {
TreeApi.Composed.insertBefore(container, node, ref_node);
} else {
TreeApi.Composed.appendChild(container, node);
}
}
this.notifyObserver();
return node;
},
_addNode: function (node, ref_node) {
var root = this.getOwnerRoot();
if (root) {
var ipAdded = this._maybeAddInsertionPoint(node, this.node);
if (!root._invalidInsertionPoints) {
root._invalidInsertionPoints = ipAdded;
}
this._addNodeToHost(root.host, node);
}
if (TreeApi.Logical.hasChildNodes(this.node)) {
TreeApi.Logical.recordInsertBefore(node, this.node, ref_node);
}
var handled = this._maybeDistribute(node) || this.node.shadyRoot;
if (handled) {
if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
while (node.firstChild) {
TreeApi.Composed.removeChild(node, node.firstChild);
}
} else {
var parent = TreeApi.Composed.getParentNode(node);
if (parent) {
TreeApi.Composed.removeChild(parent, node);
}
}
}
return handled;
},
removeChild: function (node) {
if (TreeApi.Logical.getParentNode(node) !== this.node) {
throw Error('The node to be removed is not a child of this node: ' + node);
}
if (!this._removeNode(node)) {
var container = this.node._isShadyRoot ? this.node.host : this.node;
var parent = TreeApi.Composed.getParentNode(node);
if (container === parent) {
TreeApi.Composed.removeChild(container, node);
}
}
this.notifyObserver();
return node;
},
_removeNode: function (node) {
var logicalParent = TreeApi.Logical.hasParentNode(node) && TreeApi.Logical.getParentNode(node);
var distributed;
var root = this._ownerShadyRootForNode(node);
if (logicalParent) {
distributed = dom(node)._maybeDistributeParent();
TreeApi.Logical.recordRemoveChild(node, logicalParent);
if (root && this._removeDistributedChildren(root, node)) {
root._invalidInsertionPoints = true;
this._lazyDistribute(root.host);
}
}
this._removeOwnerShadyRoot(node);
if (root) {
this._removeNodeFromHost(root.host, node);
}
return distributed;
},
replaceChild: function (node, ref_node) {
this.insertBefore(node, ref_node);
this.removeChild(ref_node);
return node;
},
_hasCachedOwnerRoot: function (node) {
return Boolean(node._ownerShadyRoot !== undefined);
},
getOwnerRoot: function () {
return this._ownerShadyRootForNode(this.node);
},
_ownerShadyRootForNode: function (node) {
if (!node) {
return;
}
var root = node._ownerShadyRoot;
if (root === undefined) {
if (node._isShadyRoot) {
root = node;
} else {
var parent = TreeApi.Logical.getParentNode(node);
if (parent) {
root = parent._isShadyRoot ? parent : this._ownerShadyRootForNode(parent);
} else {
root = null;
}
}
if (root || document.documentElement.contains(node)) {
node._ownerShadyRoot = root;
}
}
return root;
},
_maybeDistribute: function (node) {
var fragContent = node.nodeType === Node.DOCUMENT_FRAGMENT_NODE && !node.__noContent && dom(node).querySelector(CONTENT);
var wrappedContent = fragContent && TreeApi.Logical.getParentNode(fragContent).nodeType !== Node.DOCUMENT_FRAGMENT_NODE;
var hasContent = fragContent || node.localName === CONTENT;
if (hasContent) {
var root = this.getOwnerRoot();
if (root) {
this._lazyDistribute(root.host);
}
}
var needsDist = this._nodeNeedsDistribution(this.node);
if (needsDist) {
this._lazyDistribute(this.node);
}
return needsDist || hasContent && !wrappedContent;
},
_maybeAddInsertionPoint: function (node, parent) {
var added;
if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE && !node.__noContent) {
var c$ = dom(node).querySelectorAll(CONTENT);
for (var i = 0, n, np, na; i < c$.length && (n = c$[i]); i++) {
np = TreeApi.Logical.getParentNode(n);
if (np === node) {
np = parent;
}
na = this._maybeAddInsertionPoint(n, np);
added = added || na;
}
} else if (node.localName === CONTENT) {
TreeApi.Logical.saveChildNodes(parent);
TreeApi.Logical.saveChildNodes(node);
added = true;
}
return added;
},
_updateInsertionPoints: function (host) {
var i$ = host.shadyRoot._insertionPoints = dom(host.shadyRoot).querySelectorAll(CONTENT);
for (var i = 0, c; i < i$.length; i++) {
c = i$[i];
TreeApi.Logical.saveChildNodes(c);
TreeApi.Logical.saveChildNodes(TreeApi.Logical.getParentNode(c));
}
},
_nodeNeedsDistribution: function (node) {
return node && node.shadyRoot && DomApi.hasInsertionPoint(node.shadyRoot);
},
_addNodeToHost: function (host, node) {
if (host._elementAdd) {
host._elementAdd(node);
}
},
_removeNodeFromHost: function (host, node) {
if (host._elementRemove) {
host._elementRemove(node);
}
},
_removeDistributedChildren: function (root, container) {
var hostNeedsDist;
var ip$ = root._insertionPoints;
for (var i = 0; i < ip$.length; i++) {
var content = ip$[i];
if (this._contains(container, content)) {
var dc$ = dom(content).getDistributedNodes();
for (var j = 0; j < dc$.length; j++) {
hostNeedsDist = true;
var node = dc$[j];
var parent = TreeApi.Composed.getParentNode(node);
if (parent) {
TreeApi.Composed.removeChild(parent, node);
}
}
}
}
return hostNeedsDist;
},
_contains: function (container, node) {
while (node) {
if (node == container) {
return true;
}
node = TreeApi.Logical.getParentNode(node);
}
},
_removeOwnerShadyRoot: function (node) {
if (this._hasCachedOwnerRoot(node)) {
var c$ = TreeApi.Logical.getChildNodes(node);
for (var i = 0, l = c$.length, n; i < l && (n = c$[i]); i++) {
this._removeOwnerShadyRoot(n);
}
}
node._ownerShadyRoot = undefined;
},
_firstComposedNode: function (content) {
var n$ = dom(content).getDistributedNodes();
for (var i = 0, l = n$.length, n, p$; i < l && (n = n$[i]); i++) {
p$ = dom(n).getDestinationInsertionPoints();
if (p$[p$.length - 1] === content) {
return n;
}
}
},
querySelector: function (selector) {
var result = this._query(function (n) {
return DomApi.matchesSelector.call(n, selector);
}, this.node, function (n) {
return Boolean(n);
})[0];
return result || null;
},
querySelectorAll: function (selector) {
return this._query(function (n) {
return DomApi.matchesSelector.call(n, selector);
}, this.node);
},
getDestinationInsertionPoints: function () {
return this.node._destinationInsertionPoints || [];
},
getDistributedNodes: function () {
return this.node._distributedNodes || [];
},
_clear: function () {
while (this.childNodes.length) {
this.removeChild(this.childNodes[0]);
}
},
setAttribute: function (name, value) {
this.node.setAttribute(name, value);
this._maybeDistributeParent();
},
removeAttribute: function (name) {
this.node.removeAttribute(name);
this._maybeDistributeParent();
},
_maybeDistributeParent: function () {
if (this._nodeNeedsDistribution(this.parentNode)) {
this._lazyDistribute(this.parentNode);
return true;
}
},
cloneNode: function (deep) {
var n = nativeCloneNode.call(this.node, false);
if (deep) {
var c$ = this.childNodes;
var d = dom(n);
for (var i = 0, nc; i < c$.length; i++) {
nc = dom(c$[i]).cloneNode(true);
d.appendChild(nc);
}
}
return n;
},
importNode: function (externalNode, deep) {
var doc = this.node instanceof Document ? this.node : this.node.ownerDocument;
var n = nativeImportNode.call(doc, externalNode, false);
if (deep) {
var c$ = TreeApi.Logical.getChildNodes(externalNode);
var d = dom(n);
for (var i = 0, nc; i < c$.length; i++) {
nc = dom(doc).importNode(c$[i], true);
d.appendChild(nc);
}
}
return n;
},
_getComposedInnerHTML: function () {
return getInnerHTML(this.node, true);
}
});
Object.defineProperties(DomApi.prototype, {
activeElement: {
get: function () {
var active = document.activeElement;
if (!active) {
return null;
}
var isShadyRoot = !!this.node._isShadyRoot;
if (this.node !== document) {
if (!isShadyRoot) {
return null;
}
if (this.node.host === active || !this.node.host.contains(active)) {
return null;
}
}
var activeRoot = dom(active).getOwnerRoot();
while (activeRoot && activeRoot !== this.node) {
active = activeRoot.host;
activeRoot = dom(active).getOwnerRoot();
}
if (this.node === document) {
return activeRoot ? null : active;
} else {
return activeRoot === this.node ? active : null;
}
},
configurable: true
},
childNodes: {
get: function () {
var c$ = TreeApi.Logical.getChildNodes(this.node);
return Array.isArray(c$) ? c$ : TreeApi.arrayCopyChildNodes(this.node);
},
configurable: true
},
children: {
get: function () {
if (TreeApi.Logical.hasChildNodes(this.node)) {
return Array.prototype.filter.call(this.childNodes, function (n) {
return n.nodeType === Node.ELEMENT_NODE;
});
} else {
return TreeApi.arrayCopyChildren(this.node);
}
},
configurable: true
},
parentNode: {
get: function () {
return TreeApi.Logical.getParentNode(this.node);
},
configurable: true
},
firstChild: {
get: function () {
return TreeApi.Logical.getFirstChild(this.node);
},
configurable: true
},
lastChild: {
get: function () {
return TreeApi.Logical.getLastChild(this.node);
},
configurable: true
},
nextSibling: {
get: function () {
return TreeApi.Logical.getNextSibling(this.node);
},
configurable: true
},
previousSibling: {
get: function () {
return TreeApi.Logical.getPreviousSibling(this.node);
},
configurable: true
},
firstElementChild: {
get: function () {
return TreeApi.Logical.getFirstElementChild(this.node);
},
configurable: true
},
lastElementChild: {
get: function () {
return TreeApi.Logical.getLastElementChild(this.node);
},
configurable: true
},
nextElementSibling: {
get: function () {
return TreeApi.Logical.getNextElementSibling(this.node);
},
configurable: true
},
previousElementSibling: {
get: function () {
return TreeApi.Logical.getPreviousElementSibling(this.node);
},
configurable: true
},
textContent: {
get: function () {
var nt = this.node.nodeType;
if (nt === Node.TEXT_NODE || nt === Node.COMMENT_NODE) {
return this.node.textContent;
} else {
var tc = [];
for (var i = 0, cn = this.childNodes, c; c = cn[i]; i++) {
if (c.nodeType !== Node.COMMENT_NODE) {
tc.push(c.textContent);
}
}
return tc.join('');
}
},
set: function (text) {
var nt = this.node.nodeType;
if (nt === Node.TEXT_NODE || nt === Node.COMMENT_NODE) {
this.node.textContent = text;
} else {
this._clear();
if (text) {
this.appendChild(document.createTextNode(text));
}
}
},
configurable: true
},
innerHTML: {
get: function () {
var nt = this.node.nodeType;
if (nt === Node.TEXT_NODE || nt === Node.COMMENT_NODE) {
return null;
} else {
return getInnerHTML(this.node);
}
},
set: function (text) {
var nt = this.node.nodeType;
if (nt !== Node.TEXT_NODE || nt !== Node.COMMENT_NODE) {
this._clear();
var d = document.createElement('div');
d.innerHTML = text;
var c$ = TreeApi.arrayCopyChildNodes(d);
for (var i = 0; i < c$.length; i++) {
this.appendChild(c$[i]);
}
}
},
configurable: true
}
});
DomApi.hasInsertionPoint = function (root) {
return Boolean(root && root._insertionPoints.length);
};
forwardProperties([
'parentNode',
'firstChild',
'lastChild',
'nextSibling',
'previousSibling',
'firstElementChild',
'lastElementChild',
'nextElementSibling',
'previousElementSibling'
]);
var forwardProperty = function (name) {
Object.defineProperty(DomApi.prototype, name, {
get: function () {
return this.node[name];
},
configurable: true
});
};
var forwardProperties = function (f$) {
for (var i = 0; i < f$.length; i++) {
forwardProperty(f$[i]);
}
};
forwardMethods([
'cloneNode',
'appendChild',
'insertBefore',
'removeChild',
'replaceChild',
'setAttribute',
'removeAttribute',
'querySelector'
]);
var forwardMethod = function (method) {
DomApi.prototype[method] = function () {
return this.node[method].apply(this.node, arguments);
};
};
var forwardMethods = function (m$) {
for (var i = 0; i < m$.length; i++) {
forwardMethod(m$[i]);
}
};
Object.defineProperties(DomApi.prototype, {
activeElement: {
get: function () {
var node = DomApi.wrap(this.node);
var activeElement = node.activeElement;
return node.contains(activeElement) ? activeElement : null;
},
configurable: true
},
childNodes: {
get: function () {
return TreeApi.arrayCopyChildNodes(this.node);
},
configurable: true
},
children: {
get: function () {
return TreeApi.arrayCopyChildren(this.node);
},
configurable: true
},
textContent: {
get: function () {
return this.node.textContent;
},
set: function (value) {
return this.node.textContent = value;
},
configurable: true
},
innerHTML: {
get: function () {
return this.node.innerHTML;
},
set: function (value) {
return this.node.innerHTML = value;
},
configurable: true
}
});
Base.extend(DomApi.prototype, {
querySelectorAll: function (selector) {
return TreeApi.arrayCopy(this.node.querySelectorAll(selector));
},
getOwnerRoot: function () {
var n = this.node;
while (n) {
if (n.nodeType === Node.DOCUMENT_FRAGMENT_NODE && n.host) {
return n;
}
n = n.parentNode;
}
},
importNode: function (externalNode, deep) {
var doc = this.node instanceof Document ? this.node : this.node.ownerDocument;
return doc.importNode(externalNode, deep);
},
getDestinationInsertionPoints: function () {
var n$ = this.node.getDestinationInsertionPoints && this.node.getDestinationInsertionPoints();
return n$ ? TreeApi.arrayCopy(n$) : [];
},
getDistributedNodes: function () {
var n$ = this.node.getDistributedNodes && this.node.getDistributedNodes();
return n$ ? TreeApi.arrayCopy(n$) : [];
}
});
if (!Settings.useShadow) {
return;
}
var DomApi = DomApi$0;
var TreeApi = TreeApi;
var Settings = undefined;
Base.extend(dom$0, {
_flushGuard: 0,
_FLUSH_MAX: 100,
_needsTakeRecords: !useNativeCustomElements,
_debouncers: [],
_staticFlushList: [],
_finishDebouncer: null,
flush: function () {
this._flushGuard = 0;
this._prepareFlush();
while (this._debouncers.length && this._flushGuard < this._FLUSH_MAX) {
while (this._debouncers.length) {
this._debouncers.shift().complete();
}
if (this._finishDebouncer) {
this._finishDebouncer.complete();
}
this._prepareFlush();
this._flushGuard++;
}
if (this._flushGuard >= this._FLUSH_MAX) {
console.warn('Polymer.dom.flush aborted. Flush may not be complete.');
}
},
_prepareFlush: function () {
if (this._needsTakeRecords) {
CustomElements.takeRecords();
}
for (var i = 0; i < this._staticFlushList.length; i++) {
this._staticFlushList[i]();
}
},
addStaticFlush: function (fn) {
this._staticFlushList.push(fn);
},
removeStaticFlush: function (fn) {
var i = this._staticFlushList.indexOf(fn);
if (i >= 0) {
this._staticFlushList.splice(i, 1);
}
},
addDebouncer: function (debouncer) {
this._debouncers.push(debouncer);
this._finishDebouncer = Debounce(this._finishDebouncer, this._finishFlush);
},
_finishFlush: function () {
dom$0._debouncers = [];
}
});
export const EventApi = function () {
'use strict';
var DomApi = DomApi$0.ctor;
var Settings = undefined;
DomApi.Event = function (event) {
this.event = event;
};
if (Settings.useShadow) {
DomApi.Event.prototype = {
get rootTarget() {
return this.event.path[0];
},
get localTarget() {
return this.event.target;
},
get path() {
var path = this.event.path;
if (!Array.isArray(path)) {
path = Array.prototype.slice.call(path);
}
return path;
}
};
} else {
DomApi.Event.prototype = {
get rootTarget() {
return this.event.target;
},
get localTarget() {
var current = this.event.currentTarget;
var currentRoot = current && dom$0(current).getOwnerRoot();
var p$ = this.path;
for (var i = 0; i < p$.length; i++) {
if (dom$0(p$[i]).getOwnerRoot() === currentRoot) {
return p$[i];
}
}
},
get path() {
if (!this.event._path) {
var path = [];
var current = this.rootTarget;
while (current) {
path.push(current);
var insertionPoints = dom$0(current).getDestinationInsertionPoints();
if (insertionPoints.length) {
for (var i = 0; i < insertionPoints.length - 1; i++) {
path.push(insertionPoints[i]);
}
current = insertionPoints[insertionPoints.length - 1];
} else {
current = dom$0(current).parentNode || current.host;
}
}
path.push(window);
this.event._path = path;
}
return this.event._path;
}
};
}
var factory = function (event) {
if (!event.__eventApi) {
event.__eventApi = new DomApi.Event(event);
}
return event.__eventApi;
};
return { factory: factory };
}();
var DomApi = DomApi$0.ctor;
var useShadow = useShadow$0;
Object.defineProperty(DomApi.prototype, 'classList', {
get: function () {
if (!this._classList) {
this._classList = new DomApi.ClassList(this);
}
return this._classList;
},
configurable: true
});
DomApi.ClassList = function (host) {
this.domApi = host;
this.node = host.node;
};
DomApi.ClassList.prototype = {
add: function () {
this.node.classList.add.apply(this.node.classList, arguments);
this._distributeParent();
},
remove: function () {
this.node.classList.remove.apply(this.node.classList, arguments);
this._distributeParent();
},
toggle: function () {
this.node.classList.toggle.apply(this.node.classList, arguments);
this._distributeParent();
},
_distributeParent: function () {
if (!useShadow) {
this.domApi._maybeDistributeParent();
}
},
contains: function () {
return this.node.classList.contains.apply(this.node.classList, arguments);
}
};
if (Settings.useShadow) {
var baseSetup = DomApi.EffectiveNodesObserver.prototype._setup;
var baseCleanup = DomApi.EffectiveNodesObserver.prototype._cleanup;
Base.extend(DomApi.EffectiveNodesObserver.prototype, {
_setup: function () {
if (!this._observer) {
var self = this;
this._mutationHandler = function (mxns) {
if (mxns && mxns.length) {
self._scheduleNotify();
}
};
this._observer = new MutationObserver(this._mutationHandler);
this._boundFlush = function () {
self._flush();
};
dom$0.addStaticFlush(this._boundFlush);
this._observer.observe(this.node, { childList: true });
}
baseSetup.call(this);
},
_cleanup: function () {
this._observer.disconnect();
this._observer = null;
this._mutationHandler = null;
dom$0.removeStaticFlush(this._boundFlush);
baseCleanup.call(this);
},
_flush: function () {
if (this._observer) {
this._mutationHandler(this._observer.takeRecords());
}
},
enableShadowAttributeTracking: function () {
if (this._observer) {
this._makeContentListenersAlwaysNotify();
this._observer.disconnect();
this._observer.observe(this.node, {
childList: true,
attributes: true,
subtree: true
});
var root = this.domApi.getOwnerRoot();
var host = root && root.host;
if (host && dom$0(host).observer) {
dom$0(host).observer.enableShadowAttributeTracking();
}
}
},
_makeContentListenersAlwaysNotify: function () {
for (var i = 0, h; i < this._listeners.length; i++) {
h = this._listeners[i];
h._alwaysNotify = h._isContentListener;
}
}
});
}
DomApi.EffectiveNodesObserver.prototype = {
addListener: function (callback) {
if (!this._isSetup) {
this._setup();
this._isSetup = true;
}
var listener = {
fn: callback,
_nodes: []
};
this._listeners.push(listener);
this._scheduleNotify();
return listener;
},
removeListener: function (handle) {
var i = this._listeners.indexOf(handle);
if (i >= 0) {
this._listeners.splice(i, 1);
handle._nodes = [];
}
if (!this._hasListeners()) {
this._cleanup();
this._isSetup = false;
}
},
_setup: function () {
this._observeContentElements(this.domApi.childNodes);
},
_cleanup: function () {
this._unobserveContentElements(this.domApi.childNodes);
},
_hasListeners: function () {
return Boolean(this._listeners.length);
},
_scheduleNotify: function () {
if (this._debouncer) {
this._debouncer.stop();
}
this._debouncer = Debounce(this._debouncer, this._notify);
this._debouncer.context = this;
addDebouncer$0(this._debouncer);
},
notify: function () {
if (this._hasListeners()) {
this._scheduleNotify();
}
},
_notify: function () {
this._beforeCallListeners();
this._callListeners();
},
_beforeCallListeners: function () {
this._updateContentElements();
},
_updateContentElements: function () {
this._observeContentElements(this.domApi.childNodes);
},
_observeContentElements: function (elements) {
for (var i = 0, n; i < elements.length && (n = elements[i]); i++) {
if (this._isContent(n)) {
n.__observeNodesMap = n.__observeNodesMap || new WeakMap();
if (!n.__observeNodesMap.has(this)) {
n.__observeNodesMap.set(this, this._observeContent(n));
}
}
}
},
_observeContent: function (content) {
var self = this;
var h = dom$0(content).observeNodes(function () {
self._scheduleNotify();
});
h._avoidChangeCalculation = true;
return h;
},
_unobserveContentElements: function (elements) {
for (var i = 0, n, h; i < elements.length && (n = elements[i]); i++) {
if (this._isContent(n)) {
h = n.__observeNodesMap.get(this);
if (h) {
dom$0(n).unobserveNodes(h);
n.__observeNodesMap.delete(this);
}
}
}
},
_isContent: function (node) {
return node.localName === 'content';
},
_callListeners: function () {
var o$ = this._listeners;
var nodes = this._getEffectiveNodes();
for (var i = 0, o; i < o$.length && (o = o$[i]); i++) {
var info = this._generateListenerInfo(o, nodes);
if (info || o._alwaysNotify) {
this._callListener(o, info);
}
}
},
_getEffectiveNodes: function () {
return this.domApi.getEffectiveChildNodes();
},
_generateListenerInfo: function (listener, newNodes) {
if (listener._avoidChangeCalculation) {
return true;
}
var oldNodes = listener._nodes;
var info = {
target: this.node,
addedNodes: [],
removedNodes: []
};
var splices = calculateSplices$0(newNodes, oldNodes);
for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
for (var j = 0, n; j < s.removed.length && (n = s.removed[j]); j++) {
info.removedNodes.push(n);
}
}
for (i = 0, s; i < splices.length && (s = splices[i]); i++) {
for (j = s.index; j < s.index + s.addedCount; j++) {
info.addedNodes.push(newNodes[j]);
}
}
listener._nodes = newNodes;
if (info.addedNodes.length || info.removedNodes.length) {
return info;
}
},
_callListener: function (listener, info) {
return listener.fn.call(this.node, info);
},
enableShadowAttributeTracking: function () {
}
};
DomApi.EffectiveNodesObserver = function (domApi) {
this.domApi = domApi;
this.node = this.domApi.node;
this._listeners = [];
};
var Settings = undefined;
var DomApi = DomApi$0.ctor;
if (Settings.useShadow) {
Base.extend(DomApi.DistributedNodesObserver.prototype, {
_setup: function () {
if (!this._observer) {
var root = this.domApi.getOwnerRoot();
var host = root && root.host;
if (host) {
var self = this;
this._observer = dom$0(host).observeNodes(function () {
self._scheduleNotify();
});
this._observer._isContentListener = true;
if (this._hasAttrSelect()) {
dom$0(host).observer.enableShadowAttributeTracking();
}
}
}
},
_hasAttrSelect: function () {
var select = this.node.getAttribute('select');
return select && select.match(/[[.]+/);
},
_cleanup: function () {
var root = this.domApi.getOwnerRoot();
var host = root && root.host;
if (host) {
dom$0(host).unobserveNodes(this._observer);
}
this._observer = null;
}
});
}
Base.extend(DomApi.DistributedNodesObserver.prototype, {
_setup: function () {
},
_cleanup: function () {
},
_beforeCallListeners: function () {
},
_getEffectiveNodes: function () {
return this.domApi.getDistributedNodes();
}
});
DomApi.DistributedNodesObserver.prototype = Object.create(DomApi.EffectiveNodesObserver.prototype);
DomApi.DistributedNodesObserver = function (domApi) {
DomApi.EffectiveNodesObserver.call(this, domApi);
};
var Settings = undefined;
var DomApi = DomApi$0.ctor;
function upgradeLogicalChildren(children) {
if (needsUpgrade && children) {
for (var i = 0; i < children.length; i++) {
CustomElements.upgrade(children[i]);
}
}
}
var needsUpgrade = window.CustomElements && !CustomElements.useNative;
function notifyInitialDistribution(host) {
if (DomApi.hasApi(host)) {
dom$0(host).notifyObserver();
}
}
function notifyContentObservers(root) {
for (var i = 0, c; i < root._insertionPoints.length; i++) {
c = root._insertionPoints[i];
if (DomApi.hasApi(c)) {
dom$0(c).notifyObserver();
}
}
}
function hostNeedsRedistribution(host) {
var c$ = TreeApi.Logical.getChildNodes(host);
for (var i = 0, c; i < c$.length; i++) {
c = c$[i];
if (c.localName && c.localName === 'content') {
return host.domHost;
}
}
}
function getTopDistributingHost(host) {
while (host && hostNeedsRedistribution(host)) {
host = host.domHost;
}
return host;
}
function isInsertionPoint(node) {
return node.localName == 'content';
}
function isFinalDestination(insertionPoint, node) {
var points = node._destinationInsertionPoints;
return points && points[points.length - 1] === insertionPoint;
}
function maybeRedistributeParent(content, host) {
var parent = TreeApi.Logical.getParentNode(content);
if (parent && parent.shadyRoot && DomApi.hasInsertionPoint(parent.shadyRoot) && parent.shadyRoot._distributionClean) {
parent.shadyRoot._distributionClean = false;
host.shadyRoot._dirtyRoots.push(parent);
}
}
function clearDistributedDestinationInsertionPoints(content) {
var e$ = content._distributedNodes;
if (e$) {
for (var i = 0; i < e$.length; i++) {
var d = e$[i]._destinationInsertionPoints;
if (d) {
d.splice(d.indexOf(content) + 1, d.length);
}
}
}
}
function distributeNodeInto(child, insertionPoint) {
insertionPoint._distributedNodes.push(child);
var points = child._destinationInsertionPoints;
if (!points) {
child._destinationInsertionPoints = [insertionPoint];
} else {
points.push(insertionPoint);
}
}
Base._addFeature({
_prepShady: function () {
this._useContent = this._useContent || Boolean(this._template);
},
_setupShady: function () {
this.shadyRoot = null;
if (!this.__domApi) {
this.__domApi = null;
}
if (!this.__dom) {
this.__dom = null;
}
if (!this._ownerShadyRoot) {
this._ownerShadyRoot = undefined;
}
},
_poolContent: function () {
if (this._useContent) {
TreeApi.Logical.saveChildNodes(this);
}
},
_setupRoot: function () {
if (this._useContent) {
this._createLocalRoot();
if (!this.dataHost) {
upgradeLogicalChildren(TreeApi.Logical.getChildNodes(this));
}
}
},
_createLocalRoot: function () {
this.shadyRoot = this.root;
this.shadyRoot._distributionClean = false;
this.shadyRoot._hasDistributed = false;
this.shadyRoot._isShadyRoot = true;
this.shadyRoot._dirtyRoots = [];
var i$ = this.shadyRoot._insertionPoints = !this._notes || this._notes._hasContent ? this.shadyRoot.querySelectorAll('content') : [];
TreeApi.Logical.saveChildNodes(this.shadyRoot);
for (var i = 0, c; i < i$.length; i++) {
c = i$[i];
TreeApi.Logical.saveChildNodes(c);
TreeApi.Logical.saveChildNodes(c.parentNode);
}
this.shadyRoot.host = this;
},
get domHost() {
var root = dom$0(this).getOwnerRoot();
return root && root.host;
},
distributeContent: function (updateInsertionPoints) {
if (this.shadyRoot) {
this.shadyRoot._invalidInsertionPoints = this.shadyRoot._invalidInsertionPoints || updateInsertionPoints;
var host = getTopDistributingHost(this);
dom$0(this)._lazyDistribute(host);
}
},
_distributeContent: function () {
if (this._useContent && !this.shadyRoot._distributionClean) {
if (this.shadyRoot._invalidInsertionPoints) {
dom$0(this)._updateInsertionPoints(this);
this.shadyRoot._invalidInsertionPoints = false;
}
this._beginDistribute();
this._distributeDirtyRoots();
this._finishDistribute();
}
},
_beginDistribute: function () {
if (this._useContent && DomApi.hasInsertionPoint(this.shadyRoot)) {
this._resetDistribution();
this._distributePool(this.shadyRoot, this._collectPool());
}
},
_distributeDirtyRoots: function () {
var c$ = this.shadyRoot._dirtyRoots;
for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
c._distributeContent();
}
this.shadyRoot._dirtyRoots = [];
},
_finishDistribute: function () {
if (this._useContent) {
this.shadyRoot._distributionClean = true;
if (DomApi.hasInsertionPoint(this.shadyRoot)) {
this._composeTree();
notifyContentObservers(this.shadyRoot);
} else {
if (!this.shadyRoot._hasDistributed) {
TreeApi.Composed.clearChildNodes(this);
this.appendChild(this.shadyRoot);
} else {
var children = this._composeNode(this);
this._updateChildNodes(this, children);
}
}
if (!this.shadyRoot._hasDistributed) {
notifyInitialDistribution(this);
}
this.shadyRoot._hasDistributed = true;
}
},
elementMatches: function (selector, node) {
node = node || this;
return DomApi.matchesSelector.call(node, selector);
},
_resetDistribution: function () {
var children = TreeApi.Logical.getChildNodes(this);
for (var i = 0; i < children.length; i++) {
var child = children[i];
if (child._destinationInsertionPoints) {
child._destinationInsertionPoints = undefined;
}
if (isInsertionPoint(child)) {
clearDistributedDestinationInsertionPoints(child);
}
}
var root = this.shadyRoot;
var p$ = root._insertionPoints;
for (var j = 0; j < p$.length; j++) {
p$[j]._distributedNodes = [];
}
},
_collectPool: function () {
var pool = [];
var children = TreeApi.Logical.getChildNodes(this);
for (var i = 0; i < children.length; i++) {
var child = children[i];
if (isInsertionPoint(child)) {
pool.push.apply(pool, child._distributedNodes);
} else {
pool.push(child);
}
}
return pool;
},
_distributePool: function (node, pool) {
var p$ = node._insertionPoints;
for (var i = 0, l = p$.length, p; i < l && (p = p$[i]); i++) {
this._distributeInsertionPoint(p, pool);
maybeRedistributeParent(p, this);
}
},
_distributeInsertionPoint: function (content, pool) {
var anyDistributed = false;
for (var i = 0, l = pool.length, node; i < l; i++) {
node = pool[i];
if (!node) {
continue;
}
if (this._matchesContentSelect(node, content)) {
distributeNodeInto(node, content);
pool[i] = undefined;
anyDistributed = true;
}
}
if (!anyDistributed) {
var children = TreeApi.Logical.getChildNodes(content);
for (var j = 0; j < children.length; j++) {
distributeNodeInto(children[j], content);
}
}
},
_composeTree: function () {
this._updateChildNodes(this, this._composeNode(this));
var p$ = this.shadyRoot._insertionPoints;
for (var i = 0, l = p$.length, p, parent; i < l && (p = p$[i]); i++) {
parent = TreeApi.Logical.getParentNode(p);
if (!parent._useContent && parent !== this && parent !== this.shadyRoot) {
this._updateChildNodes(parent, this._composeNode(parent));
}
}
},
_composeNode: function (node) {
var children = [];
var c$ = TreeApi.Logical.getChildNodes(node.shadyRoot || node);
for (var i = 0; i < c$.length; i++) {
var child = c$[i];
if (isInsertionPoint(child)) {
var distributedNodes = child._distributedNodes;
for (var j = 0; j < distributedNodes.length; j++) {
var distributedNode = distributedNodes[j];
if (isFinalDestination(child, distributedNode)) {
children.push(distributedNode);
}
}
} else {
children.push(child);
}
}
return children;
},
_updateChildNodes: function (container, children) {
var composed = TreeApi.Composed.getChildNodes(container);
var splices = calculateSplices$0(children, composed);
for (var i = 0, d = 0, s; i < splices.length && (s = splices[i]); i++) {
for (var j = 0, n; j < s.removed.length && (n = s.removed[j]); j++) {
if (TreeApi.Composed.getParentNode(n) === container) {
TreeApi.Composed.removeChild(container, n);
}
composed.splice(s.index + d, 1);
}
d -= s.addedCount;
}
for (var i = 0, s, next; i < splices.length && (s = splices[i]); i++) {
next = composed[s.index];
for (j = s.index, n; j < s.index + s.addedCount; j++) {
n = children[j];
TreeApi.Composed.insertBefore(container, n, next);
composed.splice(j, 0, n);
}
}
},
_matchesContentSelect: function (node, contentElement) {
var select = contentElement.getAttribute('select');
if (!select) {
return true;
}
select = select.trim();
if (!select) {
return true;
}
if (!(node instanceof Element)) {
return false;
}
var validSelectors = /^(:not\()?[*.#[a-zA-Z_|]/;
if (!validSelectors.test(select)) {
return false;
}
return this.elementMatches(select, node);
},
_elementAdd: function () {
},
_elementRemove: function () {
}
});
var TreeApi = TreeApi;
var DomApi = DomApi$0;
if (useShadow$0) {
Base._addFeature({
_poolContent: function () {
},
_beginDistribute: function () {
},
distributeContent: function () {
},
_distributeContent: function () {
},
_finishDistribute: function () {
},
_createLocalRoot: function () {
this.createShadowRoot();
this.shadowRoot.appendChild(this.root);
this.root = this.shadowRoot;
}
});
}
export const Async = {
_currVal: 0,
_lastVal: 0,
_callbacks: [],
_twiddleContent: 0,
_twiddle: document.createTextNode(''),
run: function (callback, waitTime) {
if (waitTime > 0) {
return ~setTimeout(callback, waitTime);
} else {
this._twiddle.textContent = this._twiddleContent++;
this._callbacks.push(callback);
return this._currVal++;
}
},
cancel: function (handle) {
if (handle < 0) {
clearTimeout(~handle);
} else {
var idx = handle - this._lastVal;
if (idx >= 0) {
if (!this._callbacks[idx]) {
throw 'invalid async handle: ' + handle;
}
this._callbacks[idx] = null;
}
}
},
_atEndOfMicrotask: function () {
var len = this._callbacks.length;
for (var i = 0; i < len; i++) {
var cb = this._callbacks[i];
if (cb) {
try {
cb();
} catch (e) {
i++;
this._callbacks.splice(0, i);
this._lastVal += i;
this._twiddle.textContent = this._twiddleContent++;
throw e;
}
}
}
this._callbacks.splice(0, len);
this._lastVal += len;
}
};
new window.MutationObserver(function () {
async._atEndOfMicrotask();
}).observe(async._twiddle, { characterData: true });
export const Debounce = function () {
var Async = async;
var Debouncer = function (context) {
this.context = context;
var self = this;
this.boundComplete = function () {
self.complete();
};
};
Debouncer.prototype = {
go: function (callback, wait) {
var h;
this.finish = function () {
Async.cancel(h);
};
h = Async.run(this.boundComplete, wait);
this.callback = callback;
},
stop: function () {
if (this.finish) {
this.finish();
this.finish = null;
this.callback = null;
}
},
complete: function () {
if (this.finish) {
var callback = this.callback;
this.stop();
callback.call(this.context);
}
}
};
function debounce(debouncer, callback, wait) {
if (debouncer) {
debouncer.stop();
} else {
debouncer = new Debouncer(this);
}
debouncer.go(callback, wait);
return debouncer;
}
return debounce;
}();
Base._addFeature({
_setupDebouncers: function () {
this._debouncers = {};
},
debounce: function (jobName, callback, wait) {
return this._debouncers[jobName] = Debounce.call(this, this._debouncers[jobName], callback, wait);
},
isDebouncerActive: function (jobName) {
var debouncer = this._debouncers[jobName];
return !!(debouncer && debouncer.finish);
},
flushDebouncer: function (jobName) {
var debouncer = this._debouncers[jobName];
if (debouncer) {
debouncer.complete();
}
},
cancelDebouncer: function (jobName) {
var debouncer = this._debouncers[jobName];
if (debouncer) {
debouncer.stop();
}
}
});
export const DomModule = document.createElement('dom-module');
Base._addFeature({
_registerFeatures: function () {
this._prepIs();
this._prepBehaviors();
this._prepConstructor();
this._prepTemplate();
this._prepShady();
this._prepPropertyInfo();
},
_prepBehavior: function (b) {
this._addHostAttributes(b.hostAttributes);
},
_initFeatures: function () {
this._registerHost();
if (this._template) {
this._poolContent();
this._beginHosting();
this._stampTemplate();
this._endHosting();
}
this._marshalHostAttributes();
this._setupDebouncers();
this._marshalBehaviors();
this._tryReady();
},
_marshalBehavior: function (b) {
}
});
</script>
<script type="module">
import { dashToCamelCase, camelToDashCase } from '@polymer/polymer/lib/utils/case-map.js';
import { Base } from '@polymer/polymer/polymer-legacy.js';
import * as resolveUrl$1 from '@polymer/polymer/lib/utils/resolve-url.js';
import { resolveUrl as resolveUrl$0, resolveCss as resolveCss$0 } from '@polymer/polymer/lib/utils/resolve-url.js';
import { DomApi, dom as dom$0, addDebouncer, flush } from '@polymer/polymer/lib/legacy/polymer.dom.js';
import { findOriginalTarget as findOriginalTarget$0, add as add$0, remove as remove$0 } from '@polymer/polymer/lib/utils/gestures.js';
import { useNativeCustomElements, useNativeCSSProperties as useNativeCSSProperties$0 } from '@polymer/polymer/lib/utils/settings.js';
import * as async$0 from '@polymer/polymer/lib/utils/async.js';
import { DomModule } from '@polymer/polymer/lib/elements/dom-module.js';
import { Polymer as Polymer$0 } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { updateStyles as updateStyles$0 } from '@polymer/polymer/lib/mixins/element-mixin.js';
import * as renderStatus from '@polymer/polymer/lib/utils/render-status.js';
import { Templatizer as Templatizer$0 } from '@polymer/polymer/lib/legacy/templatizer-behavior.js';
export const nar = [];
export const Annotations = {
parseAnnotations: function (template) {
var list = [];
var content = template._content || template.content;
this._parseNodeAnnotations(content, list, template.hasAttribute('strip-whitespace'));
return list;
},
_parseNodeAnnotations: function (node, list, stripWhiteSpace) {
return node.nodeType === Node.TEXT_NODE ? this._parseTextNodeAnnotation(node, list) : this._parseElementAnnotations(node, list, stripWhiteSpace);
},
_bindingRegex: function () {
var IDENT = '(?:' + '[a-zA-Z_$][\\w.:$\\-*]*' + ')';
var NUMBER = '(?:' + '[-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?' + ')';
var SQUOTE_STRING = '(?:' + '\'(?:[^\'\\\\]|\\\\.)*\'' + ')';
var DQUOTE_STRING = '(?:' + '"(?:[^"\\\\]|\\\\.)*"' + ')';
var STRING = '(?:' + SQUOTE_STRING + '|' + DQUOTE_STRING + ')';
var ARGUMENT = '(?:' + IDENT + '|' + NUMBER + '|' + STRING + '\\s*' + ')';
var ARGUMENTS = '(?:' + ARGUMENT + '(?:,\\s*' + ARGUMENT + ')*' + ')';
var ARGUMENT_LIST = '(?:' + '\\(\\s*' + '(?:' + ARGUMENTS + '?' + ')' + '\\)\\s*' + ')';
var BINDING = '(' + IDENT + '\\s*' + ARGUMENT_LIST + '?' + ')';
var OPEN_BRACKET = '(\\[\\[|{{)' + '\\s*';
var CLOSE_BRACKET = '(?:]]|}})';
var NEGATE = '(?:(!)\\s*)?';
var EXPRESSION = OPEN_BRACKET + NEGATE + BINDING + CLOSE_BRACKET;
return new RegExp(EXPRESSION, 'g');
}(),
_parseBindings: function (text) {
var re = this._bindingRegex;
var parts = [];
var lastIndex = 0;
var m;
while ((m = re.exec(text)) !== null) {
if (m.index > lastIndex) {
parts.push({ literal: text.slice(lastIndex, m.index) });
}
var mode = m[1][0];
var negate = Boolean(m[2]);
var value = m[3].trim();
var customEvent, notifyEvent, colon;
if (mode == '{' && (colon = value.indexOf('::')) > 0) {
notifyEvent = value.substring(colon + 2);
value = value.substring(0, colon);
customEvent = true;
}
parts.push({
compoundIndex: parts.length,
value: value,
mode: mode,
negate: negate,
event: notifyEvent,
customEvent: customEvent
});
lastIndex = re.lastIndex;
}
if (lastIndex && lastIndex < text.length) {
var literal = text.substring(lastIndex);
if (literal) {
parts.push({ literal: literal });
}
}
if (parts.length) {
return parts;
}
},
_literalFromParts: function (parts) {
var s = '';
for (var i = 0; i < parts.length; i++) {
var literal = parts[i].literal;
s += literal || '';
}
return s;
},
_parseTextNodeAnnotation: function (node, list) {
var parts = this._parseBindings(node.textContent);
if (parts) {
node.textContent = this._literalFromParts(parts) || ' ';
var annote = {
bindings: [{
kind: 'text',
name: 'textContent',
parts: parts,
isCompound: parts.length !== 1
}]
};
list.push(annote);
return annote;
}
},
_parseElementAnnotations: function (element, list, stripWhiteSpace) {
var annote = {
bindings: [],
events: []
};
if (element.localName === 'content') {
list._hasContent = true;
}
this._parseChildNodesAnnotations(element, annote, list, stripWhiteSpace);
if (element.attributes) {
this._parseNodeAttributeAnnotations(element, annote, list);
if (this.prepElement) {
this.prepElement(element);
}
}
if (annote.bindings.length || annote.events.length || annote.id) {
list.push(annote);
}
return annote;
},
_parseChildNodesAnnotations: function (root, annote, list, stripWhiteSpace) {
if (root.firstChild) {
var node = root.firstChild;
var i = 0;
while (node) {
var next = node.nextSibling;
if (node.localName === 'template' && !node.hasAttribute('preserve-content')) {
this._parseTemplate(node, i, list, annote);
}
if (node.nodeType === Node.TEXT_NODE) {
var n = next;
while (n && n.nodeType === Node.TEXT_NODE) {
node.textContent += n.textContent;
next = n.nextSibling;
root.removeChild(n);
n = next;
}
if (stripWhiteSpace && !node.textContent.trim()) {
root.removeChild(node);
i--;
}
}
if (node.parentNode) {
var childAnnotation = this._parseNodeAnnotations(node, list, stripWhiteSpace);
if (childAnnotation) {
childAnnotation.parent = annote;
childAnnotation.index = i;
}
}
node = next;
i++;
}
}
},
_parseTemplate: function (node, index, list, parent) {
var content = document.createDocumentFragment();
content._notes = this.parseAnnotations(node);
content.appendChild(node.content);
list.push({
bindings: nar,
events: nar,
templateContent: content,
parent: parent,
index: index
});
},
_parseNodeAttributeAnnotations: function (node, annotation) {
var attrs = Array.prototype.slice.call(node.attributes);
for (var i = attrs.length - 1, a; a = attrs[i]; i--) {
var n = a.name;
var v = a.value;
var b;
if (n.slice(0, 3) === 'on-') {
node.removeAttribute(n);
annotation.events.push({
name: n.slice(3),
value: v
});
} else if (b = this._parseNodeAttributeAnnotation(node, n, v)) {
annotation.bindings.push(b);
} else if (n === 'id') {
annotation.id = v;
}
}
},
_parseNodeAttributeAnnotation: function (node, name, value) {
var parts = this._parseBindings(value);
if (parts) {
var origName = name;
var kind = 'property';
if (name[name.length - 1] == '$') {
name = name.slice(0, -1);
kind = 'attribute';
}
var literal = this._literalFromParts(parts);
if (literal && kind == 'attribute') {
node.setAttribute(name, literal);
}
if (node.localName === 'input' && origName === 'value') {
node.setAttribute(origName, '');
}
node.removeAttribute(origName);
var propertyName = dashToCamelCase(name);
if (kind === 'property') {
name = propertyName;
}
return {
kind: kind,
name: name,
propertyName: propertyName,
parts: parts,
literal: literal,
isCompound: parts.length !== 1
};
}
},
findAnnotatedNode: function (root, annote) {
var parent = annote.parent && Annotations.findAnnotatedNode(root, annote.parent);
if (parent) {
for (var n = parent.firstChild, i = 0; n; n = n.nextSibling) {
if (annote.index === i++) {
return n;
}
}
} else {
return root;
}
}
};
function resolveCss(cssText, ownerDocument) {
return cssText.replace(CSS_URL_RX, function (m, pre, url, post) {
return pre + '\'' + resolve(url.replace(/["']/g, ''), ownerDocument) + '\'' + post;
});
}
function resolveAttrs(element, ownerDocument) {
for (var name in URL_ATTRS) {
var a$ = URL_ATTRS[name];
for (var i = 0, l = a$.length, a, at, v; i < l && (a = a$[i]); i++) {
if (name === '*' || element.localName === name) {
at = element.attributes[a];
v = at && at.value;
if (v && v.search(BINDING_RX) < 0) {
at.value = a === 'style' ? resolveCss(v, ownerDocument) : resolve(v, ownerDocument);
}
}
}
}
}
function resolve(url, ownerDocument) {
if (url && ABS_URL.test(url)) {
return url;
}
var resolver = getUrlResolver(ownerDocument);
resolver.href = url;
return resolver.href || url;
}
var tempDoc;
var tempDocBase;
function resolveUrl(url, baseUri) {
if (!tempDoc) {
tempDoc = document.implementation.createHTMLDocument('temp');
tempDocBase = tempDoc.createElement('base');
tempDoc.head.appendChild(tempDocBase);
}
tempDocBase.href = baseUri;
return resolve(url, tempDoc);
}
function getUrlResolver(ownerDocument) {
return ownerDocument.__urlResolver || (ownerDocument.__urlResolver = ownerDocument.createElement('a'));
}
var CSS_URL_RX = /(url\()([^)]*)(\))/g;
var URL_ATTRS = {
'*': [
'href',
'src',
'style',
'url'
],
form: ['action']
};
var ABS_URL = /(^\/)|(^#)|(^[\w-\d]*:)/;
var BINDING_RX = /\{\{|\[\[/;
export const ResolveUrl = {
resolveCss: resolveCss,
resolveAttrs: resolveAttrs,
resolveUrl: resolveUrl
};
Base._addFeature({
_prepAnnotations: function () {
if (!this._template) {
this._notes = [];
} else {
var self = this;
Annotations.prepElement = function (element) {
self._prepElement(element);
};
if (this._template._content && this._template._content._notes) {
this._notes = this._template._content._notes;
} else {
this._notes = Annotations.parseAnnotations(this._template);
this._processAnnotations(this._notes);
}
Annotations.prepElement = null;
}
},
_processAnnotations: function (notes) {
for (var i = 0; i < notes.length; i++) {
var note = notes[i];
for (var j = 0; j < note.bindings.length; j++) {
var b = note.bindings[j];
for (var k = 0; k < b.parts.length; k++) {
var p = b.parts[k];
if (!p.literal) {
var signature = this._parseMethod(p.value);
if (signature) {
p.signature = signature;
} else {
p.model = this._modelForPath(p.value);
}
}
}
}
if (note.templateContent) {
this._processAnnotations(note.templateContent._notes);
var pp = note.templateContent._parentProps = this._discoverTemplateParentProps(note.templateContent._notes);
var bindings = [];
for (var prop in pp) {
var name = '_parent_' + prop;
bindings.push({
index: note.index,
kind: 'property',
name: name,
propertyName: name,
parts: [{
mode: '{',
model: prop,
value: prop
}]
});
}
note.bindings = note.bindings.concat(bindings);
}
}
},
_discoverTemplateParentProps: function (notes) {
var pp = {};
for (var i = 0, n; i < notes.length && (n = notes[i]); i++) {
for (var j = 0, b$ = n.bindings, b; j < b$.length && (b = b$[j]); j++) {
for (var k = 0, p$ = b.parts, p; k < p$.length && (p = p$[k]); k++) {
if (p.signature) {
var args = p.signature.args;
for (var kk = 0; kk < args.length; kk++) {
var model = args[kk].model;
if (model) {
pp[model] = true;
}
}
if (p.signature.dynamicFn) {
pp[p.signature.method] = true;
}
} else {
if (p.model) {
pp[p.model] = true;
}
}
}
}
if (n.templateContent) {
var tpp = n.templateContent._parentProps;
Base.mixin(pp, tpp);
}
}
return pp;
},
_prepElement: function (element) {
resolveUrl$1.resolveAttrs(element, this._template.ownerDocument);
},
_findAnnotatedNode: Annotations.findAnnotatedNode,
_marshalAnnotationReferences: function () {
if (this._template) {
this._marshalIdNodes();
this._marshalAnnotatedNodes();
this._marshalAnnotatedListeners();
}
},
_configureAnnotationReferences: function () {
var notes = this._notes;
var nodes = this._nodes;
for (var i = 0; i < notes.length; i++) {
var note = notes[i];
var node = nodes[i];
this._configureTemplateContent(note, node);
this._configureCompoundBindings(note, node);
}
},
_configureTemplateContent: function (note, node) {
if (note.templateContent) {
node._content = note.templateContent;
}
},
_configureCompoundBindings: function (note, node) {
var bindings = note.bindings;
for (var i = 0; i < bindings.length; i++) {
var binding = bindings[i];
if (binding.isCompound) {
var storage = node.__compoundStorage__ || (node.__compoundStorage__ = {});
var parts = binding.parts;
var literals = new Array(parts.length);
for (var j = 0; j < parts.length; j++) {
literals[j] = parts[j].literal;
}
var name = binding.name;
storage[name] = literals;
if (binding.literal && binding.kind == 'property') {
if (node._configValue) {
node._configValue(name, binding.literal);
} else {
node[name] = binding.literal;
}
}
}
}
},
_marshalIdNodes: function () {
this.$ = {};
for (var i = 0, l = this._notes.length, a; i < l && (a = this._notes[i]); i++) {
if (a.id) {
this.$[a.id] = this._findAnnotatedNode(this.root, a);
}
}
},
_marshalAnnotatedNodes: function () {
if (this._notes && this._notes.length) {
var r = new Array(this._notes.length);
for (var i = 0; i < this._notes.length; i++) {
r[i] = this._findAnnotatedNode(this.root, this._notes[i]);
}
this._nodes = r;
}
},
_marshalAnnotatedListeners: function () {
for (var i = 0, l = this._notes.length, a; i < l && (a = this._notes[i]); i++) {
if (a.events && a.events.length) {
var node = this._findAnnotatedNode(this.root, a);
for (var j = 0, e$ = a.events, e; j < e$.length && (e = e$[j]); j++) {
this.listen(node, e.name, e.value);
}
}
}
}
});Base._addFeature({
listeners: {},
_listenListeners: function (listeners) {
var node, name, eventName;
for (eventName in listeners) {
if (eventName.indexOf('.') < 0) {
node = this;
name = eventName;
} else {
name = eventName.split('.');
node = this.$[name[0]];
name = name[1];
}
this.listen(node, name, listeners[eventName]);
}
},
listen: function (node, eventName, methodName) {
var handler = this._recallEventHandler(this, eventName, node, methodName);
if (!handler) {
handler = this._createEventHandler(node, eventName, methodName);
}
if (handler._listening) {
return;
}
this._listen(node, eventName, handler);
handler._listening = true;
},
_boundListenerKey: function (eventName, methodName) {
return eventName + ':' + methodName;
},
_recordEventHandler: function (host, eventName, target, methodName, handler) {
var hbl = host.__boundListeners;
if (!hbl) {
hbl = host.__boundListeners = new WeakMap();
}
var bl = hbl.get(target);
if (!bl) {
bl = {};
hbl.set(target, bl);
}
var key = this._boundListenerKey(eventName, methodName);
bl[key] = handler;
},
_recallEventHandler: function (host, eventName, target, methodName) {
var hbl = host.__boundListeners;
if (!hbl) {
return;
}
var bl = hbl.get(target);
if (!bl) {
return;
}
var key = this._boundListenerKey(eventName, methodName);
return bl[key];
},
_createEventHandler: function (node, eventName, methodName) {
var host = this;
var handler = function (e) {
if (host[methodName]) {
host[methodName](e, e.detail);
} else {
host._warn(host._logf('_createEventHandler', 'listener method `' + methodName + '` not defined'));
}
};
handler._listening = false;
this._recordEventHandler(host, eventName, node, methodName, handler);
return handler;
},
unlisten: function (node, eventName, methodName) {
var handler = this._recallEventHandler(this, eventName, node, methodName);
if (handler) {
this._unlisten(node, eventName, handler);
handler._listening = false;
}
},
_listen: function (node, eventName, handler) {
node.addEventListener(eventName, handler);
},
_unlisten: function (node, eventName, handler) {
node.removeEventListener(eventName, handler);
}
});
var wrap = DomApi.wrap;
var HAS_NATIVE_TA = typeof document.head.style.touchAction === 'string';
var GESTURE_KEY = '__polymerGestures';
var HANDLED_OBJ = '__polymerGesturesHandled';
var TOUCH_ACTION = '__polymerGesturesTouchAction';
var TAP_DISTANCE = 25;
var TRACK_DISTANCE = 5;
var TRACK_LENGTH = 2;
var MOUSE_TIMEOUT = 2500;
var MOUSE_EVENTS = [
'mousedown',
'mousemove',
'mouseup',
'click'
];
var MOUSE_WHICH_TO_BUTTONS = [
0,
1,
4,
2
];
var MOUSE_HAS_BUTTONS = function () {
try {
return new MouseEvent('test', { buttons: 1 }).buttons === 1;
} catch (e) {
return false;
}
}();
var IS_TOUCH_ONLY = navigator.userAgent.match(/iP(?:[oa]d|hone)|Android/);
var mouseCanceller = function (mouseEvent) {
var sc = mouseEvent.sourceCapabilities;
if (sc && !sc.firesTouchEvents) {
return;
}
mouseEvent[HANDLED_OBJ] = { skip: true };
if (mouseEvent.type === 'click') {
var path = dom$0(mouseEvent).path;
for (var i = 0; i < path.length; i++) {
if (path[i] === POINTERSTATE.mouse.target) {
return;
}
}
mouseEvent.preventDefault();
mouseEvent.stopPropagation();
}
};
function setupTeardownMouseCanceller(setup) {
for (var i = 0, en; i < MOUSE_EVENTS.length; i++) {
en = MOUSE_EVENTS[i];
if (setup) {
document.addEventListener(en, mouseCanceller, true);
} else {
document.removeEventListener(en, mouseCanceller, true);
}
}
}
function ignoreMouse() {
if (IS_TOUCH_ONLY) {
return;
}
if (!POINTERSTATE.mouse.mouseIgnoreJob) {
setupTeardownMouseCanceller(true);
}
var unset = function () {
setupTeardownMouseCanceller();
POINTERSTATE.mouse.target = null;
POINTERSTATE.mouse.mouseIgnoreJob = null;
};
POINTERSTATE.mouse.mouseIgnoreJob = Polymer.Debounce(POINTERSTATE.mouse.mouseIgnoreJob, unset, MOUSE_TIMEOUT);
}
function hasLeftMouseButton(ev) {
var type = ev.type;
if (MOUSE_EVENTS.indexOf(type) === -1) {
return false;
}
if (type === 'mousemove') {
var buttons = ev.buttons === undefined ? 1 : ev.buttons;
if (ev instanceof window.MouseEvent && !MOUSE_HAS_BUTTONS) {
buttons = MOUSE_WHICH_TO_BUTTONS[ev.which] || 0;
}
return Boolean(buttons & 1);
} else {
var button = ev.button === undefined ? 0 : ev.button;
return button === 0;
}
}
function isSyntheticClick(ev) {
if (ev.type === 'click') {
if (ev.detail === 0) {
return true;
}
var t = findOriginalTarget$0(ev);
var bcr = t.getBoundingClientRect();
var x = ev.pageX, y = ev.pageY;
return !(x >= bcr.left && x <= bcr.right && (y >= bcr.top && y <= bcr.bottom));
}
return false;
}
var POINTERSTATE = {
mouse: {
target: null,
mouseIgnoreJob: null
},
touch: {
x: 0,
y: 0,
id: -1,
scrollDecided: false
}
};
function firstTouchAction(ev) {
var path = dom$0(ev).path;
var ta = 'auto';
for (var i = 0, n; i < path.length; i++) {
n = path[i];
if (n[TOUCH_ACTION]) {
ta = n[TOUCH_ACTION];
break;
}
}
return ta;
}
function trackDocument(stateObj, movefn, upfn) {
stateObj.movefn = movefn;
stateObj.upfn = upfn;
document.addEventListener('mousemove', movefn);
document.addEventListener('mouseup', upfn);
}
function untrackDocument(stateObj) {
document.removeEventListener('mousemove', stateObj.movefn);
document.removeEventListener('mouseup', stateObj.upfn);
stateObj.movefn = null;
stateObj.upfn = null;
}
var Gestures = {
gestures: {},
recognizers: [],
deepTargetFind: function (x, y) {
var node = document.elementFromPoint(x, y);
var next = node;
while (next && next.shadowRoot) {
next = next.shadowRoot.elementFromPoint(x, y);
if (next) {
node = next;
}
}
return node;
},
findOriginalTarget: function (ev) {
if (ev.path) {
return ev.path[0];
}
return ev.target;
},
handleNative: function (ev) {
var handled;
var type = ev.type;
var node = wrap(ev.currentTarget);
var gobj = node[GESTURE_KEY];
if (!gobj) {
return;
}
var gs = gobj[type];
if (!gs) {
return;
}
if (!ev[HANDLED_OBJ]) {
ev[HANDLED_OBJ] = {};
if (type.slice(0, 5) === 'touch') {
var t = ev.changedTouches[0];
if (type === 'touchstart') {
if (ev.touches.length === 1) {
POINTERSTATE.touch.id = t.identifier;
}
}
if (POINTERSTATE.touch.id !== t.identifier) {
return;
}
if (!HAS_NATIVE_TA) {
if (type === 'touchstart' || type === 'touchmove') {
Gestures.handleTouchAction(ev);
}
}
if (type === 'touchend') {
POINTERSTATE.mouse.target = dom$0(ev).rootTarget;
ignoreMouse();
}
}
}
handled = ev[HANDLED_OBJ];
if (handled.skip) {
return;
}
var recognizers = Gestures.recognizers;
for (var i = 0, r; i < recognizers.length; i++) {
r = recognizers[i];
if (gs[r.name] && !handled[r.name]) {
if (r.flow && r.flow.start.indexOf(ev.type) > -1 && r.reset) {
r.reset();
}
}
}
for (i = 0, r; i < recognizers.length; i++) {
r = recognizers[i];
if (gs[r.name] && !handled[r.name]) {
handled[r.name] = true;
r[type](ev);
}
}
},
handleTouchAction: function (ev) {
var t = ev.changedTouches[0];
var type = ev.type;
if (type === 'touchstart') {
POINTERSTATE.touch.x = t.clientX;
POINTERSTATE.touch.y = t.clientY;
POINTERSTATE.touch.scrollDecided = false;
} else if (type === 'touchmove') {
if (POINTERSTATE.touch.scrollDecided) {
return;
}
POINTERSTATE.touch.scrollDecided = true;
var ta = firstTouchAction(ev);
var prevent = false;
var dx = Math.abs(POINTERSTATE.touch.x - t.clientX);
var dy = Math.abs(POINTERSTATE.touch.y - t.clientY);
if (!ev.cancelable) {
} else if (ta === 'none') {
prevent = true;
} else if (ta === 'pan-x') {
prevent = dy > dx;
} else if (ta === 'pan-y') {
prevent = dx > dy;
}
if (prevent) {
ev.preventDefault();
} else {
Gestures.prevent('track');
}
}
},
add: function (node, evType, handler) {
node = wrap(node);
var recognizer = this.gestures[evType];
var deps = recognizer.deps;
var name = recognizer.name;
var gobj = node[GESTURE_KEY];
if (!gobj) {
node[GESTURE_KEY] = gobj = {};
}
for (var i = 0, dep, gd; i < deps.length; i++) {
dep = deps[i];
if (IS_TOUCH_ONLY && MOUSE_EVENTS.indexOf(dep) > -1) {
continue;
}
gd = gobj[dep];
if (!gd) {
gobj[dep] = gd = { _count: 0 };
}
if (gd._count === 0) {
node.addEventListener(dep, this.handleNative);
}
gd[name] = (gd[name] || 0) + 1;
gd._count = (gd._count || 0) + 1;
}
node.addEventListener(evType, handler);
if (recognizer.touchAction) {
this.setTouchAction(node, recognizer.touchAction);
}
},
remove: function (node, evType, handler) {
node = wrap(node);
var recognizer = this.gestures[evType];
var deps = recognizer.deps;
var name = recognizer.name;
var gobj = node[GESTURE_KEY];
if (gobj) {
for (var i = 0, dep, gd; i < deps.length; i++) {
dep = deps[i];
gd = gobj[dep];
if (gd && gd[name]) {
gd[name] = (gd[name] || 1) - 1;
gd._count = (gd._count || 1) - 1;
if (gd._count === 0) {
node.removeEventListener(dep, this.handleNative);
}
}
}
}
node.removeEventListener(evType, handler);
},
register: function (recog) {
this.recognizers.push(recog);
for (var i = 0; i < recog.emits.length; i++) {
this.gestures[recog.emits[i]] = recog;
}
},
findRecognizerByEvent: function (evName) {
for (var i = 0, r; i < this.recognizers.length; i++) {
r = this.recognizers[i];
for (var j = 0, n; j < r.emits.length; j++) {
n = r.emits[j];
if (n === evName) {
return r;
}
}
}
return null;
},
setTouchAction: function (node, value) {
if (HAS_NATIVE_TA) {
node.style.touchAction = value;
}
node[TOUCH_ACTION] = value;
},
fire: function (target, type, detail) {
var ev = Base.fire(type, detail, {
node: target,
bubbles: true,
cancelable: true
});
if (ev.defaultPrevented) {
var preventer = detail.preventer || detail.sourceEvent;
if (preventer && preventer.preventDefault) {
preventer.preventDefault();
}
}
},
prevent: function (evName) {
var recognizer = this.findRecognizerByEvent(evName);
if (recognizer.info) {
recognizer.info.prevent = true;
}
},
resetMouseCanceller: function () {
if (POINTERSTATE.mouse.mouseIgnoreJob) {
POINTERSTATE.mouse.mouseIgnoreJob.complete();
}
}
};
Gestures.register({
name: 'downup',
deps: [
'mousedown',
'touchstart',
'touchend'
],
flow: {
start: [
'mousedown',
'touchstart'
],
end: [
'mouseup',
'touchend'
]
},
emits: [
'down',
'up'
],
info: {
movefn: null,
upfn: null
},
reset: function () {
untrackDocument(this.info);
},
mousedown: function (e) {
if (!hasLeftMouseButton(e)) {
return;
}
var t = findOriginalTarget$0(e);
var self = this;
var movefn = function movefn(e) {
if (!hasLeftMouseButton(e)) {
self.fire('up', t, e);
untrackDocument(self.info);
}
};
var upfn = function upfn(e) {
if (hasLeftMouseButton(e)) {
self.fire('up', t, e);
}
untrackDocument(self.info);
};
trackDocument(this.info, movefn, upfn);
this.fire('down', t, e);
},
touchstart: function (e) {
this.fire('down', findOriginalTarget$0(e), e.changedTouches[0], e);
},
touchend: function (e) {
this.fire('up', findOriginalTarget$0(e), e.changedTouches[0], e);
},
fire: function (type, target, event, preventer) {
Gestures.fire(target, type, {
x: event.clientX,
y: event.clientY,
sourceEvent: event,
preventer: preventer,
prevent: function (e) {
return Gestures.prevent(e);
}
});
}
});
Gestures.register({
name: 'track',
touchAction: 'none',
deps: [
'mousedown',
'touchstart',
'touchmove',
'touchend'
],
flow: {
start: [
'mousedown',
'touchstart'
],
end: [
'mouseup',
'touchend'
]
},
emits: ['track'],
info: {
x: 0,
y: 0,
state: 'start',
started: false,
moves: [],
addMove: function (move) {
if (this.moves.length > TRACK_LENGTH) {
this.moves.shift();
}
this.moves.push(move);
},
movefn: null,
upfn: null,
prevent: false
},
reset: function () {
this.info.state = 'start';
this.info.started = false;
this.info.moves = [];
this.info.x = 0;
this.info.y = 0;
this.info.prevent = false;
untrackDocument(this.info);
},
hasMovedEnough: function (x, y) {
if (this.info.prevent) {
return false;
}
if (this.info.started) {
return true;
}
var dx = Math.abs(this.info.x - x);
var dy = Math.abs(this.info.y - y);
return dx >= TRACK_DISTANCE || dy >= TRACK_DISTANCE;
},
mousedown: function (e) {
if (!hasLeftMouseButton(e)) {
return;
}
var t = findOriginalTarget$0(e);
var self = this;
var movefn = function movefn(e) {
var x = e.clientX, y = e.clientY;
if (self.hasMovedEnough(x, y)) {
self.info.state = self.info.started ? e.type === 'mouseup' ? 'end' : 'track' : 'start';
if (self.info.state === 'start') {
Gestures.prevent('tap');
}
self.info.addMove({
x: x,
y: y
});
if (!hasLeftMouseButton(e)) {
self.info.state = 'end';
untrackDocument(self.info);
}
self.fire(t, e);
self.info.started = true;
}
};
var upfn = function upfn(e) {
if (self.info.started) {
movefn(e);
}
untrackDocument(self.info);
};
trackDocument(this.info, movefn, upfn);
this.info.x = e.clientX;
this.info.y = e.clientY;
},
touchstart: function (e) {
var ct = e.changedTouches[0];
this.info.x = ct.clientX;
this.info.y = ct.clientY;
},
touchmove: function (e) {
var t = findOriginalTarget$0(e);
var ct = e.changedTouches[0];
var x = ct.clientX, y = ct.clientY;
if (this.hasMovedEnough(x, y)) {
if (this.info.state === 'start') {
Gestures.prevent('tap');
}
this.info.addMove({
x: x,
y: y
});
this.fire(t, ct);
this.info.state = 'track';
this.info.started = true;
}
},
touchend: function (e) {
var t = findOriginalTarget$0(e);
var ct = e.changedTouches[0];
if (this.info.started) {
this.info.state = 'end';
this.info.addMove({
x: ct.clientX,
y: ct.clientY
});
this.fire(t, ct, e);
}
},
fire: function (target, touch, preventer) {
var secondlast = this.info.moves[this.info.moves.length - 2];
var lastmove = this.info.moves[this.info.moves.length - 1];
var dx = lastmove.x - this.info.x;
var dy = lastmove.y - this.info.y;
var ddx, ddy = 0;
if (secondlast) {
ddx = lastmove.x - secondlast.x;
ddy = lastmove.y - secondlast.y;
}
return Gestures.fire(target, 'track', {
state: this.info.state,
x: touch.clientX,
y: touch.clientY,
dx: dx,
dy: dy,
ddx: ddx,
ddy: ddy,
sourceEvent: touch,
preventer: preventer,
hover: function () {
return Gestures.deepTargetFind(touch.clientX, touch.clientY);
}
});
}
});
Gestures.register({
name: 'tap',
deps: [
'mousedown',
'click',
'touchstart',
'touchend'
],
flow: {
start: [
'mousedown',
'touchstart'
],
end: [
'click',
'touchend'
]
},
emits: ['tap'],
info: {
x: NaN,
y: NaN,
prevent: false
},
reset: function () {
this.info.x = NaN;
this.info.y = NaN;
this.info.prevent = false;
},
save: function (e) {
this.info.x = e.clientX;
this.info.y = e.clientY;
},
mousedown: function (e) {
if (hasLeftMouseButton(e)) {
this.save(e);
}
},
click: function (e) {
if (hasLeftMouseButton(e)) {
this.forward(e);
}
},
touchstart: function (e) {
this.save(e.changedTouches[0], e);
},
touchend: function (e) {
this.forward(e.changedTouches[0], e);
},
forward: function (e, preventer) {
var dx = Math.abs(e.clientX - this.info.x);
var dy = Math.abs(e.clientY - this.info.y);
var t = findOriginalTarget$0(e);
if (isNaN(dx) || isNaN(dy) || dx <= TAP_DISTANCE && dy <= TAP_DISTANCE || isSyntheticClick(e)) {
if (!this.info.prevent) {
Gestures.fire(t, 'tap', {
x: e.clientX,
y: e.clientY,
sourceEvent: e,
preventer: preventer
});
}
}
}
});
var DIRECTION_MAP = {
x: 'pan-x',
y: 'pan-y',
none: 'none',
all: 'auto'
};
Base._addFeature({
_setupGestures: function () {
this.__polymerGestures = null;
},
_listen: function (node, eventName, handler) {
if (Gestures.gestures[eventName]) {
add$0(node, eventName, handler);
} else {
node.addEventListener(eventName, handler);
}
},
_unlisten: function (node, eventName, handler) {
if (Gestures.gestures[eventName]) {
remove$0(node, eventName, handler);
} else {
node.removeEventListener(eventName, handler);
}
},
setScrollDirection: function (direction, node) {
node = node || this;
Gestures.setTouchAction(node, DIRECTION_MAP[direction] || 'auto');
}
});
export { Gestures };
if (!useNativeCustomElements) {
var importHref = Base.importHref;
Base.importHref = function (href, onload, onerror, optAsync) {
CustomElements.ready = false;
var loadFn = function (e) {
CustomElements.upgradeDocumentTree(document);
CustomElements.ready = true;
if (onload) {
return onload.call(this, e);
}
};
return importHref.call(this, href, loadFn, onerror, optAsync);
};
}
Base._addFeature({
$$: function (slctr) {
return dom$0(this.root).querySelector(slctr);
},
toggleClass: function (name, bool, node) {
node = node || this;
if (arguments.length == 1) {
bool = !node.classList.contains(name);
}
if (bool) {
dom$0(node).classList.add(name);
} else {
dom$0(node).classList.remove(name);
}
},
toggleAttribute: function (name, bool, node) {
node = node || this;
if (arguments.length == 1) {
bool = !node.hasAttribute(name);
}
if (bool) {
dom$0(node).setAttribute(name, '');
} else {
dom$0(node).removeAttribute(name);
}
},
classFollows: function (name, toElement, fromElement) {
if (fromElement) {
dom$0(fromElement).classList.remove(name);
}
if (toElement) {
dom$0(toElement).classList.add(name);
}
},
attributeFollows: function (name, toElement, fromElement) {
if (fromElement) {
dom$0(fromElement).removeAttribute(name);
}
if (toElement) {
dom$0(toElement).setAttribute(name, '');
}
},
getEffectiveChildNodes: function () {
return dom$0(this).getEffectiveChildNodes();
},
getEffectiveChildren: function () {
var list = dom$0(this).getEffectiveChildNodes();
return list.filter(function (n) {
return n.nodeType === Node.ELEMENT_NODE;
});
},
getEffectiveTextContent: function () {
var cn = this.getEffectiveChildNodes();
var tc = [];
for (var i = 0, c; c = cn[i]; i++) {
if (c.nodeType !== Node.COMMENT_NODE) {
tc.push(dom$0(c).textContent);
}
}
return tc.join('');
},
queryEffectiveChildren: function (slctr) {
var e$ = dom$0(this).queryDistributedElements(slctr);
return e$ && e$[0];
},
queryAllEffectiveChildren: function (slctr) {
return dom$0(this).queryDistributedElements(slctr);
},
getContentChildNodes: function (slctr) {
var content = dom$0(this.root).querySelector(slctr || 'content');
return content ? dom$0(content).getDistributedNodes() : [];
},
getContentChildren: function (slctr) {
return this.getContentChildNodes(slctr).filter(function (n) {
return n.nodeType === Node.ELEMENT_NODE;
});
},
fire: function (type, detail, options) {
options = options || Polymer.nob;
var node = options.node || this;
detail = detail === null || detail === undefined ? {} : detail;
var bubbles = options.bubbles === undefined ? true : options.bubbles;
var cancelable = Boolean(options.cancelable);
var useCache = options._useCache;
var event = this._getEvent(type, bubbles, cancelable, useCache);
event.detail = detail;
if (useCache) {
this.__eventCache[type] = null;
}
node.dispatchEvent(event);
if (useCache) {
this.__eventCache[type] = event;
}
return event;
},
__eventCache: {},
_getEvent: function (type, bubbles, cancelable, useCache) {
var event = useCache && this.__eventCache[type];
if (!event || (event.bubbles != bubbles || event.cancelable != cancelable)) {
event = new Event(type, {
bubbles: Boolean(bubbles),
cancelable: cancelable
});
}
return event;
},
async: function (callback, waitTime) {
var self = this;
return async$0.run(function () {
callback.call(self);
}, waitTime);
},
cancelAsync: function (handle) {
async$0.cancel(handle);
},
arrayDelete: function (path, item) {
var index;
if (Array.isArray(path)) {
index = path.indexOf(item);
if (index >= 0) {
return path.splice(index, 1);
}
} else {
var arr = this._get(path);
index = arr.indexOf(item);
if (index >= 0) {
return this.splice(path, index, 1);
}
}
},
transform: function (transform, node) {
node = node || this;
node.style.webkitTransform = transform;
node.style.transform = transform;
},
translate3d: function (x, y, z, node) {
node = node || this;
this.transform('translate3d(' + x + ',' + y + ',' + z + ')', node);
},
importHref: function (href, onload, onerror, optAsync) {
var link = document.createElement('link');
link.rel = 'import';
link.href = href;
var list = Base.importHref.imported = Base.importHref.imported || {};
var cached = list[link.href];
var imprt = cached || link;
var self = this;
if (onload) {
var loadListener = function (e) {
e.target.__firedLoad = true;
e.target.removeEventListener('load', loadListener);
return onload.call(self, e);
};
imprt.addEventListener('load', loadListener);
}
if (onerror) {
var errorListener = function (e) {
e.target.__firedError = true;
e.target.removeEventListener('error', errorListener);
return onerror.call(self, e);
};
imprt.addEventListener('error', errorListener);
}
if (cached) {
if (cached.__firedLoad) {
cached.dispatchEvent(new Event('load'));
}
if (cached.__firedError) {
cached.dispatchEvent(new Event('error'));
}
} else {
list[link.href] = link;
optAsync = Boolean(optAsync);
if (optAsync) {
link.setAttribute('async', '');
}
document.head.appendChild(link);
}
return imprt;
},
create: function (tag, props) {
var elt = document.createElement(tag);
if (props) {
for (var n in props) {
elt[n] = props[n];
}
}
return elt;
},
isLightDescendant: function (node) {
return this !== node && this.contains(node) && dom$0(this).getOwnerRoot() === dom$0(node).getOwnerRoot();
},
isLocalDescendant: function (node) {
return this.root === dom$0(node).getOwnerRoot();
}
});
export const Bind = {
prepareModel: function (model) {
Base.mixin(model, this._modelApi);
},
_modelApi: {
_notifyChange: function (source, event, value) {
value = value === undefined ? this[source] : value;
event = event || camelToDashCase(source) + '-changed';
this.fire(event, { value: value }, {
bubbles: false,
cancelable: false,
_useCache: true
});
},
_propertySetter: function (property, value, effects, fromAbove) {
var old = this.__data__[property];
if (old !== value && (old === old || value === value)) {
this.__data__[property] = value;
if (typeof value == 'object') {
this._clearPath(property);
}
if (this._propertyChanged) {
this._propertyChanged(property, value, old);
}
if (effects) {
this._effectEffects(property, value, effects, old, fromAbove);
}
}
return old;
},
__setProperty: function (property, value, quiet, node) {
node = node || this;
var effects = node._propertyEffects && node._propertyEffects[property];
if (effects) {
node._propertySetter(property, value, effects, quiet);
} else if (node[property] !== value) {
node[property] = value;
}
},
_effectEffects: function (property, value, effects, old, fromAbove) {
for (var i = 0, l = effects.length, fx; i < l && (fx = effects[i]); i++) {
fx.fn.call(this, property, this[property], fx.effect, old, fromAbove);
}
},
_clearPath: function (path) {
for (var prop in this.__data__) {
if (prop.indexOf(path + '.') === 0) {
this.__data__[prop] = undefined;
}
}
}
},
ensurePropertyEffects: function (model, property) {
if (!model._propertyEffects) {
model._propertyEffects = {};
}
var fx = model._propertyEffects[property];
if (!fx) {
fx = model._propertyEffects[property] = [];
}
return fx;
},
addPropertyEffect: function (model, property, kind, effect) {
var fx = this.ensurePropertyEffects(model, property);
var propEffect = {
kind: kind,
effect: effect,
fn: Bind['_' + kind + 'Effect']
};
fx.push(propEffect);
return propEffect;
},
createBindings: function (model) {
var fx$ = model._propertyEffects;
if (fx$) {
for (var n in fx$) {
var fx = fx$[n];
fx.sort(this._sortPropertyEffects);
this._createAccessors(model, n, fx);
}
}
},
_sortPropertyEffects: function () {
var EFFECT_ORDER = {
'compute': 0,
'annotation': 1,
'annotatedComputation': 2,
'reflect': 3,
'notify': 4,
'observer': 5,
'complexObserver': 6,
'function': 7
};
return function (a, b) {
return EFFECT_ORDER[a.kind] - EFFECT_ORDER[b.kind];
};
}(),
_createAccessors: function (model, property, effects) {
var defun = {
get: function () {
return this.__data__[property];
}
};
var setter = function (value) {
this._propertySetter(property, value, effects);
};
var info = model.getPropertyInfo && model.getPropertyInfo(property);
if (info && info.readOnly) {
if (!info.computed) {
model['_set' + this.upper(property)] = setter;
}
} else {
defun.set = setter;
}
Object.defineProperty(model, property, defun);
},
upper: function (name) {
return name[0].toUpperCase() + name.substring(1);
},
_addAnnotatedListener: function (model, index, property, path, event, negated) {
if (!model._bindListeners) {
model._bindListeners = [];
}
var fn = this._notedListenerFactory(property, path, this._isStructured(path), negated);
var eventName = event || camelToDashCase(property) + '-changed';
model._bindListeners.push({
index: index,
property: property,
path: path,
changedFn: fn,
event: eventName
});
},
_isStructured: function (path) {
return path.indexOf('.') > 0;
},
_isEventBogus: function (e, target) {
return e.path && e.path[0] !== target;
},
_notedListenerFactory: function (property, path, isStructured, negated) {
return function (target, value, targetPath) {
if (targetPath) {
this._notifyPath(this._fixPath(path, property, targetPath), value);
} else {
value = target[property];
if (negated) {
value = !value;
}
if (!isStructured) {
this[path] = value;
} else {
if (this.__data__[path] != value) {
this.set(path, value);
}
}
}
};
},
prepareInstance: function (inst) {
inst.__data__ = Object.create(null);
},
setupBindListeners: function (inst) {
var b$ = inst._bindListeners;
for (var i = 0, l = b$.length, info; i < l && (info = b$[i]); i++) {
var node = inst._nodes[info.index];
this._addNotifyListener(node, inst, info.event, info.changedFn);
}
},
_addNotifyListener: function (element, context, event, changedFn) {
element.addEventListener(event, function (e) {
return context._notifyListener(changedFn, e);
});
}
};
Base.extend(Bind, {
_shouldAddListener: function (effect) {
return effect.name && effect.kind != 'attribute' && effect.kind != 'text' && !effect.isCompound && effect.parts[0].mode === '{';
},
_annotationEffect: function (source, value, effect) {
if (source != effect.value) {
value = this._get(effect.value);
this.__data__[effect.value] = value;
}
this._applyEffectValue(effect, value);
},
_reflectEffect: function (source, value, effect) {
this.reflectPropertyToAttribute(source, effect.attribute, value);
},
_notifyEffect: function (source, value, effect, old, fromAbove) {
if (!fromAbove) {
this._notifyChange(source, effect.event, value);
}
},
_functionEffect: function (source, value, fn, old, fromAbove) {
fn.call(this, source, value, old, fromAbove);
},
_observerEffect: function (source, value, effect, old) {
var fn = this[effect.method];
if (fn) {
fn.call(this, value, old);
} else {
this._warn(this._logf('_observerEffect', 'observer method `' + effect.method + '` not defined'));
}
},
_complexObserverEffect: function (source, value, effect) {
var fn = this[effect.method];
if (fn) {
var args = Bind._marshalArgs(this.__data__, effect, source, value);
if (args) {
fn.apply(this, args);
}
} else if (effect.dynamicFn) {
} else {
this._warn(this._logf('_complexObserverEffect', 'observer method `' + effect.method + '` not defined'));
}
},
_computeEffect: function (source, value, effect) {
var fn = this[effect.method];
if (fn) {
var args = Bind._marshalArgs(this.__data__, effect, source, value);
if (args) {
var computedvalue = fn.apply(this, args);
this.__setProperty(effect.name, computedvalue);
}
} else if (effect.dynamicFn) {
} else {
this._warn(this._logf('_computeEffect', 'compute method `' + effect.method + '` not defined'));
}
},
_annotatedComputationEffect: function (source, value, effect) {
var computedHost = this._rootDataHost || this;
var fn = computedHost[effect.method];
if (fn) {
var args = Bind._marshalArgs(this.__data__, effect, source, value);
if (args) {
var computedvalue = fn.apply(computedHost, args);
this._applyEffectValue(effect, computedvalue);
}
} else if (effect.dynamicFn) {
} else {
computedHost._warn(computedHost._logf('_annotatedComputationEffect', 'compute method `' + effect.method + '` not defined'));
}
},
_marshalArgs: function (model, effect, path, value) {
var values = [];
var args = effect.args;
var bailoutEarly = args.length > 1 || effect.dynamicFn;
for (var i = 0, l = args.length; i < l; i++) {
var arg = args[i];
var name = arg.name;
var v;
if (arg.literal) {
v = arg.value;
} else if (path === name) {
v = value;
} else {
v = model[name];
if (v === undefined && arg.structured) {
v = Base._get(name, model);
}
}
if (bailoutEarly && v === undefined) {
return;
}
if (arg.wildcard) {
var matches = path.indexOf(name + '.') === 0;
values[i] = {
path: matches ? path : name,
value: matches ? value : v,
base: v
};
} else {
values[i] = v;
}
}
return values;
}
});Base._addFeature({
_addPropertyEffect: function (property, kind, effect) {
var prop = Bind.addPropertyEffect(this, property, kind, effect);
prop.pathFn = this['_' + prop.kind + 'PathEffect'];
},
_prepEffects: function () {
Bind.prepareModel(this);
this._addAnnotationEffects(this._notes);
},
_prepBindings: function () {
Bind.createBindings(this);
},
_addPropertyEffects: function (properties) {
if (properties) {
for (var p in properties) {
var prop = properties[p];
if (prop.observer) {
this._addObserverEffect(p, prop.observer);
}
if (prop.computed) {
prop.readOnly = true;
this._addComputedEffect(p, prop.computed);
}
if (prop.notify) {
this._addPropertyEffect(p, 'notify', { event: camelToDashCase(p) + '-changed' });
}
if (prop.reflectToAttribute) {
var attr = camelToDashCase(p);
if (attr[0] === '-') {
this._warn(this._logf('_addPropertyEffects', 'Property ' + p + ' cannot be reflected to attribute ' + attr + ' because "-" is not a valid starting attribute name. Use a lowercase first letter for the property instead.'));
} else {
this._addPropertyEffect(p, 'reflect', { attribute: attr });
}
}
if (prop.readOnly) {
Bind.ensurePropertyEffects(this, p);
}
}
}
},
_addComputedEffect: function (name, expression) {
var sig = this._parseMethod(expression);
var dynamicFn = sig.dynamicFn;
for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) {
this._addPropertyEffect(arg.model, 'compute', {
method: sig.method,
args: sig.args,
trigger: arg,
name: name,
dynamicFn: dynamicFn
});
}
if (dynamicFn) {
this._addPropertyEffect(sig.method, 'compute', {
method: sig.method,
args: sig.args,
trigger: null,
name: name,
dynamicFn: dynamicFn
});
}
},
_addObserverEffect: function (property, observer) {
this._addPropertyEffect(property, 'observer', {
method: observer,
property: property
});
},
_addComplexObserverEffects: function (observers) {
if (observers) {
for (var i = 0, o; i < observers.length && (o = observers[i]); i++) {
this._addComplexObserverEffect(o);
}
}
},
_addComplexObserverEffect: function (observer) {
var sig = this._parseMethod(observer);
if (!sig) {
throw new Error('Malformed observer expression \'' + observer + '\'');
}
var dynamicFn = sig.dynamicFn;
for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) {
this._addPropertyEffect(arg.model, 'complexObserver', {
method: sig.method,
args: sig.args,
trigger: arg,
dynamicFn: dynamicFn
});
}
if (dynamicFn) {
this._addPropertyEffect(sig.method, 'complexObserver', {
method: sig.method,
args: sig.args,
trigger: null,
dynamicFn: dynamicFn
});
}
},
_addAnnotationEffects: function (notes) {
for (var i = 0, note; i < notes.length && (note = notes[i]); i++) {
var b$ = note.bindings;
for (var j = 0, binding; j < b$.length && (binding = b$[j]); j++) {
this._addAnnotationEffect(binding, i);
}
}
},
_addAnnotationEffect: function (note, index) {
if (Bind._shouldAddListener(note)) {
Bind._addAnnotatedListener(this, index, note.name, note.parts[0].value, note.parts[0].event, note.parts[0].negate);
}
for (var i = 0; i < note.parts.length; i++) {
var part = note.parts[i];
if (part.signature) {
this._addAnnotatedComputationEffect(note, part, index);
} else if (!part.literal) {
if (note.kind === 'attribute' && note.name[0] === '-') {
this._warn(this._logf('_addAnnotationEffect', 'Cannot set attribute ' + note.name + ' because "-" is not a valid attribute starting character'));
} else {
this._addPropertyEffect(part.model, 'annotation', {
kind: note.kind,
index: index,
name: note.name,
propertyName: note.propertyName,
value: part.value,
isCompound: note.isCompound,
compoundIndex: part.compoundIndex,
event: part.event,
customEvent: part.customEvent,
negate: part.negate
});
}
}
}
},
_addAnnotatedComputationEffect: function (note, part, index) {
var sig = part.signature;
if (sig.static) {
this.__addAnnotatedComputationEffect('__static__', index, note, part, null);
} else {
for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) {
if (!arg.literal) {
this.__addAnnotatedComputationEffect(arg.model, index, note, part, arg);
}
}
if (sig.dynamicFn) {
this.__addAnnotatedComputationEffect(sig.method, index, note, part, null);
}
}
},
__addAnnotatedComputationEffect: function (property, index, note, part, trigger) {
this._addPropertyEffect(property, 'annotatedComputation', {
index: index,
isCompound: note.isCompound,
compoundIndex: part.compoundIndex,
kind: note.kind,
name: note.name,
negate: part.negate,
method: part.signature.method,
args: part.signature.args,
trigger: trigger,
dynamicFn: part.signature.dynamicFn
});
},
_parseMethod: function (expression) {
var m = expression.match(/([^\s]+?)\(([\s\S]*)\)/);
if (m) {
var sig = {
method: m[1],
static: true
};
if (this.getPropertyInfo(sig.method) !== Polymer.nob) {
sig.static = false;
sig.dynamicFn = true;
}
if (m[2].trim()) {
var args = m[2].replace(/\\,/g, ',').split(',');
return this._parseArgs(args, sig);
} else {
sig.args = nar;
return sig;
}
}
},
_parseArgs: function (argList, sig) {
sig.args = argList.map(function (rawArg) {
var arg = this._parseArg(rawArg);
if (!arg.literal) {
sig.static = false;
}
return arg;
}, this);
return sig;
},
_parseArg: function (rawArg) {
var arg = rawArg.trim().replace(/,/g, ',').replace(/\\(.)/g, '$1');
var a = { name: arg };
var fc = arg[0];
if (fc === '-') {
fc = arg[1];
}
if (fc >= '0' && fc <= '9') {
fc = '#';
}
switch (fc) {
case '\'':
case '"':
a.value = arg.slice(1, -1);
a.literal = true;
break;
case '#':
a.value = Number(arg);
a.literal = true;
break;
}
if (!a.literal) {
a.model = this._modelForPath(arg);
a.structured = arg.indexOf('.') > 0;
if (a.structured) {
a.wildcard = arg.slice(-2) == '.*';
if (a.wildcard) {
a.name = arg.slice(0, -2);
}
}
}
return a;
},
_marshalInstanceEffects: function () {
Bind.prepareInstance(this);
if (this._bindListeners) {
Bind.setupBindListeners(this);
}
},
_applyEffectValue: function (info, value) {
var node = this._nodes[info.index];
var property = info.name;
value = this._computeFinalAnnotationValue(node, property, value, info);
if (info.kind == 'attribute') {
this.serializeValueToAttribute(value, property, node);
} else {
var pinfo = node._propertyInfo && node._propertyInfo[property];
if (pinfo && pinfo.readOnly) {
return;
}
this.__setProperty(property, value, false, node);
}
},
_computeFinalAnnotationValue: function (node, property, value, info) {
if (info.negate) {
value = !value;
}
if (info.isCompound) {
var storage = node.__compoundStorage__[property];
storage[info.compoundIndex] = value;
value = storage.join('');
}
if (info.kind !== 'attribute') {
if (property === 'className') {
value = this._scopeElementClass(node, value);
}
if (property === 'textContent' || node.localName == 'input' && property == 'value') {
value = value == undefined ? '' : value;
}
}
return value;
},
_executeStaticEffects: function () {
if (this._propertyEffects && this._propertyEffects.__static__) {
this._effectEffects('__static__', null, this._propertyEffects.__static__);
}
}
});
var usePolyfillProto = undefined.usePolyfillProto;
Base._addFeature({
_setupConfigure: function (initialConfig) {
this._config = {};
this._handlers = [];
this._aboveConfig = null;
if (initialConfig) {
for (var i in initialConfig) {
if (initialConfig[i] !== undefined) {
this._config[i] = initialConfig[i];
}
}
}
},
_marshalAttributes: function () {
this._takeAttributesToModel(this._config);
},
_attributeChangedImpl: function (name) {
var model = this._clientsReadied ? this : this._config;
this._setAttributeToProperty(model, name);
},
_configValue: function (name, value) {
var info = this._propertyInfo[name];
if (!info || !info.readOnly) {
this._config[name] = value;
}
},
_beforeClientsReady: function () {
this._configure();
},
_configure: function () {
this._configureAnnotationReferences();
this._configureInstanceProperties();
this._aboveConfig = this.mixin({}, this._config);
var config = {};
for (var i = 0; i < this.behaviors.length; i++) {
this._configureProperties(this.behaviors[i].properties, config);
}
this._configureProperties(this.properties, config);
this.mixin(config, this._aboveConfig);
this._config = config;
if (this._clients && this._clients.length) {
this._distributeConfig(this._config);
}
},
_configureInstanceProperties: function () {
for (var i in this._propertyEffects) {
if (!usePolyfillProto && this.hasOwnProperty(i)) {
this._configValue(i, this[i]);
delete this[i];
}
}
},
_configureProperties: function (properties, config) {
for (var i in properties) {
var c = properties[i];
if (c.value !== undefined) {
var value = c.value;
if (typeof value == 'function') {
value = value.call(this, this._config);
}
config[i] = value;
}
}
},
_distributeConfig: function (config) {
var fx$ = this._propertyEffects;
if (fx$) {
for (var p in config) {
var fx = fx$[p];
if (fx) {
for (var i = 0, l = fx.length, x; i < l && (x = fx[i]); i++) {
if (x.kind === 'annotation') {
var node = this._nodes[x.effect.index];
var name = x.effect.propertyName;
var isAttr = x.effect.kind == 'attribute';
var hasEffect = node._propertyEffects && node._propertyEffects[name];
if (node._configValue && (hasEffect || !isAttr)) {
var value = p === x.effect.value ? config[p] : this._get(x.effect.value, config);
value = this._computeFinalAnnotationValue(node, name, value, x.effect);
if (isAttr) {
value = node.deserialize(this.serialize(value), node._propertyInfo[name].type);
}
node._configValue(name, value);
}
}
}
}
}
}
},
_afterClientsReady: function () {
this._executeStaticEffects();
this._applyConfig(this._config, this._aboveConfig);
this._flushHandlers();
},
_applyConfig: function (config, aboveConfig) {
for (var n in config) {
if (this[n] === undefined) {
this.__setProperty(n, config[n], n in aboveConfig);
}
}
},
_notifyListener: function (fn, e) {
if (!Bind._isEventBogus(e, e.target)) {
var value, path;
if (e.detail) {
value = e.detail.value;
path = e.detail.path;
}
if (!this._clientsReadied) {
this._queueHandler([
fn,
e.target,
value,
path
]);
} else {
return fn.call(this, e.target, value, path);
}
}
},
_queueHandler: function (args) {
this._handlers.push(args);
},
_flushHandlers: function () {
var h$ = this._handlers;
for (var i = 0, l = h$.length, h; i < l && (h = h$[i]); i++) {
h[0].call(this, h[1], h[2], h[3]);
}
this._handlers = [];
}
});
Base._addFeature({
notifyPath: function (path, value, fromAbove) {
var info = {};
var v = this._get(path, this, info);
if (arguments.length === 1) {
value = v;
}
if (info.path) {
this._notifyPath(info.path, value, fromAbove);
}
},
_notifyPath: function (path, value, fromAbove) {
var old = this._propertySetter(path, value);
if (old !== value && (old === old || value === value)) {
this._pathEffector(path, value);
if (!fromAbove) {
this._notifyPathUp(path, value);
}
return true;
}
},
_getPathParts: function (path) {
if (Array.isArray(path)) {
var parts = [];
for (var i = 0; i < path.length; i++) {
var args = path[i].toString().split('.');
for (var j = 0; j < args.length; j++) {
parts.push(args[j]);
}
}
return parts;
} else {
return path.toString().split('.');
}
},
set: function (path, value, root) {
var prop = root || this;
var parts = this._getPathParts(path);
var array;
var last = parts[parts.length - 1];
if (parts.length > 1) {
for (var i = 0; i < parts.length - 1; i++) {
var part = parts[i];
if (array && part[0] == '#') {
prop = undefined.get(array).getItem(part);
} else {
prop = prop[part];
if (array && parseInt(part, 10) == part) {
parts[i] = undefined.get(array).getKey(prop);
}
}
if (!prop) {
return;
}
array = Array.isArray(prop) ? prop : null;
}
if (array) {
var coll = undefined.get(array);
var old, key;
if (last[0] == '#') {
key = last;
old = coll.getItem(key);
last = array.indexOf(old);
coll.setItem(key, value);
} else if (parseInt(last, 10) == last) {
old = prop[last];
key = coll.getKey(old);
parts[i] = key;
coll.setItem(key, value);
}
}
prop[last] = value;
if (!root) {
this._notifyPath(parts.join('.'), value);
}
} else {
prop[path] = value;
}
},
get: function (path, root) {
return this._get(path, root);
},
_get: function (path, root, info) {
var prop = root || this;
var parts = this._getPathParts(path);
var array;
for (var i = 0; i < parts.length; i++) {
if (!prop) {
return;
}
var part = parts[i];
if (array && part[0] == '#') {
prop = undefined.get(array).getItem(part);
} else {
prop = prop[part];
if (info && array && parseInt(part, 10) == part) {
parts[i] = undefined.get(array).getKey(prop);
}
}
array = Array.isArray(prop) ? prop : null;
}
if (info) {
info.path = parts.join('.');
}
return prop;
},
_pathEffector: function (path, value) {
var model = this._modelForPath(path);
var fx$ = this._propertyEffects && this._propertyEffects[model];
if (fx$) {
for (var i = 0, fx; i < fx$.length && (fx = fx$[i]); i++) {
var fxFn = fx.pathFn;
if (fxFn) {
fxFn.call(this, path, value, fx.effect);
}
}
}
if (this._boundPaths) {
this._notifyBoundPaths(path, value);
}
},
_annotationPathEffect: function (path, value, effect) {
if (effect.value === path || effect.value.indexOf(path + '.') === 0) {
Bind._annotationEffect.call(this, path, value, effect);
} else if (path.indexOf(effect.value + '.') === 0 && !effect.negate) {
var node = this._nodes[effect.index];
if (node && node._notifyPath) {
var p = this._fixPath(effect.name, effect.value, path);
node._notifyPath(p, value, true);
}
}
},
_complexObserverPathEffect: function (path, value, effect) {
if (this._pathMatchesEffect(path, effect)) {
Bind._complexObserverEffect.call(this, path, value, effect);
}
},
_computePathEffect: function (path, value, effect) {
if (this._pathMatchesEffect(path, effect)) {
Bind._computeEffect.call(this, path, value, effect);
}
},
_annotatedComputationPathEffect: function (path, value, effect) {
if (this._pathMatchesEffect(path, effect)) {
Bind._annotatedComputationEffect.call(this, path, value, effect);
}
},
_pathMatchesEffect: function (path, effect) {
var effectArg = effect.trigger.name;
return effectArg == path || effectArg.indexOf(path + '.') === 0 || effect.trigger.wildcard && path.indexOf(effectArg + '.') === 0;
},
linkPaths: function (to, from) {
this._boundPaths = this._boundPaths || {};
if (from) {
this._boundPaths[to] = from;
} else {
this.unlinkPaths(to);
}
},
unlinkPaths: function (path) {
if (this._boundPaths) {
delete this._boundPaths[path];
}
},
_notifyBoundPaths: function (path, value) {
for (var a in this._boundPaths) {
var b = this._boundPaths[a];
if (path.indexOf(a + '.') == 0) {
this._notifyPath(this._fixPath(b, a, path), value);
} else if (path.indexOf(b + '.') == 0) {
this._notifyPath(this._fixPath(a, b, path), value);
}
}
},
_fixPath: function (property, root, path) {
return property + path.slice(root.length);
},
_notifyPathUp: function (path, value) {
var rootName = this._modelForPath(path);
var dashCaseName = camelToDashCase(rootName);
var eventName = dashCaseName + this._EVENT_CHANGED;
this.fire(eventName, {
path: path,
value: value
}, {
bubbles: false,
_useCache: true
});
},
_modelForPath: function (path) {
var dot = path.indexOf('.');
return dot < 0 ? path : path.slice(0, dot);
},
_EVENT_CHANGED: '-changed',
notifySplices: function (path, splices) {
var info = {};
var array = this._get(path, this, info);
this._notifySplices(array, info.path, splices);
},
_notifySplices: function (array, path, splices) {
var change = {
keySplices: undefined.applySplices(array, splices),
indexSplices: splices
};
var splicesPath = path + '.splices';
this._notifyPath(splicesPath, change);
this._notifyPath(path + '.length', array.length);
this.__data__[splicesPath] = {
keySplices: null,
indexSplices: null
};
},
_notifySplice: function (array, path, index, added, removed) {
this._notifySplices(array, path, [{
index: index,
addedCount: added,
removed: removed,
object: array,
type: 'splice'
}]);
},
push: function (path) {
var info = {};
var array = this._get(path, this, info);
var args = Array.prototype.slice.call(arguments, 1);
var len = array.length;
var ret = array.push.apply(array, args);
if (args.length) {
this._notifySplice(array, info.path, len, args.length, []);
}
return ret;
},
pop: function (path) {
var info = {};
var array = this._get(path, this, info);
var hadLength = Boolean(array.length);
var args = Array.prototype.slice.call(arguments, 1);
var ret = array.pop.apply(array, args);
if (hadLength) {
this._notifySplice(array, info.path, array.length, 0, [ret]);
}
return ret;
},
splice: function (path, start) {
var info = {};
var array = this._get(path, this, info);
if (start < 0) {
start = array.length - Math.floor(-start);
} else {
start = Math.floor(start);
}
if (!start) {
start = 0;
}
var args = Array.prototype.slice.call(arguments, 1);
var ret = array.splice.apply(array, args);
var addedCount = Math.max(args.length - 2, 0);
if (addedCount || ret.length) {
this._notifySplice(array, info.path, start, addedCount, ret);
}
return ret;
},
shift: function (path) {
var info = {};
var array = this._get(path, this, info);
var hadLength = Boolean(array.length);
var args = Array.prototype.slice.call(arguments, 1);
var ret = array.shift.apply(array, args);
if (hadLength) {
this._notifySplice(array, info.path, 0, 0, [ret]);
}
return ret;
},
unshift: function (path) {
var info = {};
var array = this._get(path, this, info);
var args = Array.prototype.slice.call(arguments, 1);
var ret = array.unshift.apply(array, args);
if (args.length) {
this._notifySplice(array, info.path, 0, args.length, []);
}
return ret;
},
prepareModelNotifyPath: function (model) {
this.mixin(model, {
fire: Base.fire,
_getEvent: Base._getEvent,
__eventCache: Base.__eventCache,
notifyPath: Base.notifyPath,
_get: Base._get,
_EVENT_CHANGED: Base._EVENT_CHANGED,
_notifyPath: Base._notifyPath,
_notifyPathUp: Base._notifyPathUp,
_pathEffector: Base._pathEffector,
_annotationPathEffect: Base._annotationPathEffect,
_complexObserverPathEffect: Base._complexObserverPathEffect,
_annotatedComputationPathEffect: Base._annotatedComputationPathEffect,
_computePathEffect: Base._computePathEffect,
_modelForPath: Base._modelForPath,
_pathMatchesEffect: Base._pathMatchesEffect,
_notifyBoundPaths: Base._notifyBoundPaths,
_getPathParts: Base._getPathParts
});
}
});
Base._addFeature({
resolveUrl: function (url) {
var module = DomModule.import(this.is);
var root = '';
if (module) {
var assetPath = module.getAttribute('assetpath') || '';
root = resolveUrl$0(assetPath, module.ownerDocument.baseURI);
}
return resolveUrl$0(url, root);
}
});
export const CssParse = function () {
return {
parse: function (text) {
text = this._clean(text);
return this._parseCss(this._lex(text), text);
},
_clean: function (cssText) {
return cssText.replace(this._rx.comments, '').replace(this._rx.port, '');
},
_lex: function (text) {
var root = {
start: 0,
end: text.length
};
var n = root;
for (var i = 0, l = text.length; i < l; i++) {
switch (text[i]) {
case this.OPEN_BRACE:
if (!n.rules) {
n.rules = [];
}
var p = n;
var previous = p.rules[p.rules.length - 1];
n = {
start: i + 1,
parent: p,
previous: previous
};
p.rules.push(n);
break;
case this.CLOSE_BRACE:
n.end = i + 1;
n = n.parent || root;
break;
}
}
return root;
},
_parseCss: function (node, text) {
var t = text.substring(node.start, node.end - 1);
node.parsedCssText = node.cssText = t.trim();
if (node.parent) {
var ss = node.previous ? node.previous.end : node.parent.start;
t = text.substring(ss, node.start - 1);
t = this._expandUnicodeEscapes(t);
t = t.replace(this._rx.multipleSpaces, ' ');
t = t.substring(t.lastIndexOf(';') + 1);
var s = node.parsedSelector = node.selector = t.trim();
node.atRule = s.indexOf(this.AT_START) === 0;
if (node.atRule) {
if (s.indexOf(this.MEDIA_START) === 0) {
node.type = this.types.MEDIA_RULE;
} else if (s.match(this._rx.keyframesRule)) {
node.type = this.types.KEYFRAMES_RULE;
node.keyframesName = node.selector.split(this._rx.multipleSpaces).pop();
}
} else {
if (s.indexOf(this.VAR_START) === 0) {
node.type = this.types.MIXIN_RULE;
} else {
node.type = this.types.STYLE_RULE;
}
}
}
var r$ = node.rules;
if (r$) {
for (var i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) {
this._parseCss(r, text);
}
}
return node;
},
_expandUnicodeEscapes: function (s) {
return s.replace(/\\([0-9a-f]{1,6})\s/gi, function () {
var code = arguments[1], repeat = 6 - code.length;
while (repeat--) {
code = '0' + code;
}
return '\\' + code;
});
},
stringify: function (node, preserveProperties, text) {
text = text || '';
var cssText = '';
if (node.cssText || node.rules) {
var r$ = node.rules;
if (r$ && !this._hasMixinRules(r$)) {
for (var i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) {
cssText = this.stringify(r, preserveProperties, cssText);
}
} else {
cssText = preserveProperties ? node.cssText : this.removeCustomProps(node.cssText);
cssText = cssText.trim();
if (cssText) {
cssText = ' ' + cssText + '\n';
}
}
}
if (cssText) {
if (node.selector) {
text += node.selector + ' ' + this.OPEN_BRACE + '\n';
}
text += cssText;
if (node.selector) {
text += this.CLOSE_BRACE + '\n\n';
}
}
return text;
},
_hasMixinRules: function (rules) {
return rules[0].selector.indexOf(this.VAR_START) === 0;
},
removeCustomProps: function (cssText) {
cssText = this.removeCustomPropAssignment(cssText);
return this.removeCustomPropApply(cssText);
},
removeCustomPropAssignment: function (cssText) {
return cssText.replace(this._rx.customProp, '').replace(this._rx.mixinProp, '');
},
removeCustomPropApply: function (cssText) {
return cssText.replace(this._rx.mixinApply, '').replace(this._rx.varApply, '');
},
types: {
STYLE_RULE: 1,
KEYFRAMES_RULE: 7,
MEDIA_RULE: 4,
MIXIN_RULE: 1000
},
OPEN_BRACE: '{',
CLOSE_BRACE: '}',
_rx: {
comments: /\/\*[^*]*\*+([^\/*][^*]*\*+)*\//gim,
port: /@import[^;]*;/gim,
customProp: /(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?(?:[;\n]|$)/gim,
mixinProp: /(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?{[^}]*?}(?:[;\n]|$)?/gim,
mixinApply: /@apply\s*\(?[^);]*\)?\s*(?:[;\n]|$)?/gim,
varApply: /[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim,
keyframesRule: /^@[^\s]*keyframes/,
multipleSpaces: /\s+/g
},
VAR_START: '--',
MEDIA_START: '@media',
AT_START: '@'
};
}();
export const StyleUtil = function () {
var settings = undefined;
return {
NATIVE_VARIABLES: useNativeCSSProperties$0,
MODULE_STYLES_SELECTOR: 'style, link[rel=import][type~=css], template',
INCLUDE_ATTR: 'include',
toCssText: function (rules, callback) {
if (typeof rules === 'string') {
rules = this.parser.parse(rules);
}
if (callback) {
this.forEachRule(rules, callback);
}
return this.parser.stringify(rules, this.NATIVE_VARIABLES);
},
forRulesInStyles: function (styles, styleRuleCallback, keyframesRuleCallback) {
if (styles) {
for (var i = 0, l = styles.length, s; i < l && (s = styles[i]); i++) {
this.forEachRuleInStyle(s, styleRuleCallback, keyframesRuleCallback);
}
}
},
forActiveRulesInStyles: function (styles, styleRuleCallback, keyframesRuleCallback) {
if (styles) {
for (var i = 0, l = styles.length, s; i < l && (s = styles[i]); i++) {
this.forEachRuleInStyle(s, styleRuleCallback, keyframesRuleCallback, true);
}
}
},
rulesForStyle: function (style) {
if (!style.__cssRules && style.textContent) {
style.__cssRules = this.parser.parse(style.textContent);
}
return style.__cssRules;
},
isKeyframesSelector: function (rule) {
return rule.parent && rule.parent.type === this.ruleTypes.KEYFRAMES_RULE;
},
forEachRuleInStyle: function (style, styleRuleCallback, keyframesRuleCallback, onlyActiveRules) {
var rules = this.rulesForStyle(style);
var styleCallback, keyframeCallback;
if (styleRuleCallback) {
styleCallback = function (rule) {
styleRuleCallback(rule, style);
};
}
if (keyframesRuleCallback) {
keyframeCallback = function (rule) {
keyframesRuleCallback(rule, style);
};
}
this.forEachRule(rules, styleCallback, keyframeCallback, onlyActiveRules);
},
forEachRule: function (node, styleRuleCallback, keyframesRuleCallback, onlyActiveRules) {
if (!node) {
return;
}
var skipRules = false;
if (onlyActiveRules) {
if (node.type === this.ruleTypes.MEDIA_RULE) {
var matchMedia = node.selector.match(this.rx.MEDIA_MATCH);
if (matchMedia) {
if (!window.matchMedia(matchMedia[1]).matches) {
skipRules = true;
}
}
}
}
if (node.type === this.ruleTypes.STYLE_RULE) {
styleRuleCallback(node);
} else if (keyframesRuleCallback && node.type === this.ruleTypes.KEYFRAMES_RULE) {
keyframesRuleCallback(node);
} else if (node.type === this.ruleTypes.MIXIN_RULE) {
skipRules = true;
}
var r$ = node.rules;
if (r$ && !skipRules) {
for (var i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) {
this.forEachRule(r, styleRuleCallback, keyframesRuleCallback, onlyActiveRules);
}
}
},
applyCss: function (cssText, moniker, target, contextNode) {
var style = this.createScopeStyle(cssText, moniker);
return this.applyStyle(style, target, contextNode);
},
applyStyle: function (style, target, contextNode) {
target = target || document.head;
var after = contextNode && contextNode.nextSibling || target.firstChild;
this.__lastHeadApplyNode = style;
return target.insertBefore(style, after);
},
createScopeStyle: function (cssText, moniker) {
var style = document.createElement('style');
if (moniker) {
style.setAttribute('scope', moniker);
}
style.textContent = cssText;
return style;
},
__lastHeadApplyNode: null,
applyStylePlaceHolder: function (moniker) {
var placeHolder = document.createComment(' Shady DOM styles for ' + moniker + ' ');
var after = this.__lastHeadApplyNode ? this.__lastHeadApplyNode.nextSibling : null;
var scope = document.head;
scope.insertBefore(placeHolder, after || scope.firstChild);
this.__lastHeadApplyNode = placeHolder;
return placeHolder;
},
cssFromModules: function (moduleIds, warnIfNotFound) {
var modules = moduleIds.trim().split(' ');
var cssText = '';
for (var i = 0; i < modules.length; i++) {
cssText += this.cssFromModule(modules[i], warnIfNotFound);
}
return cssText;
},
cssFromModule: function (moduleId, warnIfNotFound) {
var m = DomModule.import(moduleId);
if (m && !m._cssText) {
m._cssText = this.cssFromElement(m);
}
if (!m && warnIfNotFound) {
console.warn('Could not find style data in module named', moduleId);
}
return m && m._cssText || '';
},
cssFromElement: function (element) {
var cssText = '';
var content = element.content || element;
var e$ = Polymer.TreeApi.arrayCopy(content.querySelectorAll(this.MODULE_STYLES_SELECTOR));
for (var i = 0, e; i < e$.length; i++) {
e = e$[i];
if (e.localName === 'template') {
cssText += this.cssFromElement(e);
} else {
if (e.localName === 'style') {
var include = e.getAttribute(this.INCLUDE_ATTR);
if (include) {
cssText += this.cssFromModules(include, true);
}
e = e.__appliedElement || e;
e.parentNode.removeChild(e);
cssText += this.resolveCss(e.textContent, element.ownerDocument);
} else if (e.import && e.import.body) {
cssText += this.resolveCss(e.import.body.textContent, e.import);
}
}
}
return cssText;
},
isTargetedBuild: function (buildType) {
return settings.useNativeShadow ? buildType === 'shadow' : buildType === 'shady';
},
cssBuildTypeForModule: function (module) {
var dm = DomModule.import(module);
if (dm) {
return this.getCssBuildType(dm);
}
},
getCssBuildType: function (element) {
return element.getAttribute('css-build');
},
_findMatchingParen: function (text, start) {
var level = 0;
for (var i = start, l = text.length; i < l; i++) {
switch (text[i]) {
case '(':
level++;
break;
case ')':
if (--level === 0) {
return i;
}
break;
}
}
return -1;
},
processVariableAndFallback: function (str, callback) {
var start = str.indexOf('var(');
if (start === -1) {
return callback(str, '', '', '');
}
var end = this._findMatchingParen(str, start + 3);
var inner = str.substring(start + 4, end);
var prefix = str.substring(0, start);
var suffix = this.processVariableAndFallback(str.substring(end + 1), callback);
var comma = inner.indexOf(',');
if (comma === -1) {
return callback(prefix, inner.trim(), '', suffix);
}
var value = inner.substring(0, comma).trim();
var fallback = inner.substring(comma + 1).trim();
return callback(prefix, value, fallback, suffix);
},
rx: {
VAR_ASSIGN: /(?:^|[;\s{]\s*)(--[\w-]*?)\s*:\s*(?:([^;{]*)|{([^}]*)})(?:(?=[;\s}])|$)/gi,
MIXIN_MATCH: /(?:^|\W+)@apply\s*\(?([^);\n]*)\)?/gi,
VAR_CONSUMED: /(--[\w-]+)\s*([:,;)]|$)/gi,
ANIMATION_MATCH: /(animation\s*:)|(animation-name\s*:)/,
MEDIA_MATCH: /@media[^(]*(\([^)]*\))/,
IS_VAR: /^--/,
BRACKETED: /\{[^}]*\}/g,
HOST_PREFIX: '(?:^|[^.#[:])',
HOST_SUFFIX: '($|[.:[\\s>+~])'
},
resolveCss: resolveCss$0,
parser: CssParse,
ruleTypes: CssParse.types
};
}();
export const StyleTransformer = function () {
var styleUtil = StyleUtil;
var settings = undefined;
var api = {
dom: function (node, scope, useAttr, shouldRemoveScope) {
this._transformDom(node, scope || '', useAttr, shouldRemoveScope);
},
_transformDom: function (node, selector, useAttr, shouldRemoveScope) {
if (node.setAttribute) {
this.element(node, selector, useAttr, shouldRemoveScope);
}
var c$ = dom$0(node).childNodes;
for (var i = 0; i < c$.length; i++) {
this._transformDom(c$[i], selector, useAttr, shouldRemoveScope);
}
},
element: function (element, scope, useAttr, shouldRemoveScope) {
if (useAttr) {
if (shouldRemoveScope) {
element.removeAttribute(SCOPE_NAME);
} else {
element.setAttribute(SCOPE_NAME, scope);
}
} else {
if (scope) {
if (element.classList) {
if (shouldRemoveScope) {
element.classList.remove(SCOPE_NAME);
element.classList.remove(scope);
} else {
element.classList.add(SCOPE_NAME);
element.classList.add(scope);
}
} else if (element.getAttribute) {
var c = element.getAttribute(CLASS);
if (shouldRemoveScope) {
if (c) {
element.setAttribute(CLASS, c.replace(SCOPE_NAME, '').replace(scope, ''));
}
} else {
element.setAttribute(CLASS, (c ? c + ' ' : '') + SCOPE_NAME + ' ' + scope);
}
}
}
}
},
elementStyles: function (element, callback) {
var styles = element._styles;
var cssText = '';
var cssBuildType = element.__cssBuild;
for (var i = 0, l = styles.length, s; i < l && (s = styles[i]); i++) {
var rules = styleUtil.rulesForStyle(s);
cssText += settings.useNativeShadow || cssBuildType === 'shady' ? styleUtil.toCssText(rules, callback) : this.css(rules, element.is, element.extends, callback, element._scopeCssViaAttr) + '\n\n';
}
return cssText.trim();
},
css: function (rules, scope, ext, callback, useAttr) {
var hostScope = this._calcHostScope(scope, ext);
scope = this._calcElementScope(scope, useAttr);
var self = this;
return styleUtil.toCssText(rules, function (rule) {
if (!rule.isScoped) {
self.rule(rule, scope, hostScope);
rule.isScoped = true;
}
if (callback) {
callback(rule, scope, hostScope);
}
});
},
_calcElementScope: function (scope, useAttr) {
if (scope) {
return useAttr ? CSS_ATTR_PREFIX + scope + CSS_ATTR_SUFFIX : CSS_CLASS_PREFIX + scope;
} else {
return '';
}
},
_calcHostScope: function (scope, ext) {
return ext ? '[is=' + scope + ']' : scope;
},
rule: function (rule, scope, hostScope) {
this._transformRule(rule, this._transformComplexSelector, scope, hostScope);
},
_transformRule: function (rule, transformer, scope, hostScope) {
rule.selector = rule.transformedSelector = this._transformRuleCss(rule, transformer, scope, hostScope);
},
_transformRuleCss: function (rule, transformer, scope, hostScope) {
var p$ = rule.selector.split(COMPLEX_SELECTOR_SEP);
if (!styleUtil.isKeyframesSelector(rule)) {
for (var i = 0, l = p$.length, p; i < l && (p = p$[i]); i++) {
p$[i] = transformer.call(this, p, scope, hostScope);
}
}
return p$.join(COMPLEX_SELECTOR_SEP);
},
_transformComplexSelector: function (selector, scope, hostScope) {
var stop = false;
var hostContext = false;
var self = this;
selector = selector.trim();
selector = selector.replace(CONTENT_START, HOST + ' $1');
selector = selector.replace(SIMPLE_SELECTOR_SEP, function (m, c, s) {
if (!stop) {
var info = self._transformCompoundSelector(s, c, scope, hostScope);
stop = stop || info.stop;
hostContext = hostContext || info.hostContext;
c = info.combinator;
s = info.value;
} else {
s = s.replace(SCOPE_JUMP, ' ');
}
return c + s;
});
if (hostContext) {
selector = selector.replace(HOST_CONTEXT_PAREN, function (m, pre, paren, post) {
return pre + paren + ' ' + hostScope + post + COMPLEX_SELECTOR_SEP + ' ' + pre + hostScope + paren + post;
});
}
return selector;
},
_transformCompoundSelector: function (selector, combinator, scope, hostScope) {
var jumpIndex = selector.search(SCOPE_JUMP);
var hostContext = false;
if (selector.indexOf(HOST_CONTEXT) >= 0) {
hostContext = true;
} else if (selector.indexOf(HOST) >= 0) {
selector = this._transformHostSelector(selector, hostScope);
} else if (jumpIndex !== 0) {
selector = scope ? this._transformSimpleSelector(selector, scope) : selector;
}
if (selector.indexOf(CONTENT) >= 0) {
combinator = '';
}
var stop;
if (jumpIndex >= 0) {
selector = selector.replace(SCOPE_JUMP, ' ');
stop = true;
}
return {
value: selector,
combinator: combinator,
stop: stop,
hostContext: hostContext
};
},
_transformSimpleSelector: function (selector, scope) {
var p$ = selector.split(PSEUDO_PREFIX);
p$[0] += scope;
return p$.join(PSEUDO_PREFIX);
},
_transformHostSelector: function (selector, hostScope) {
var m = selector.match(HOST_PAREN);
var paren = m && m[2].trim() || '';
if (paren) {
if (!paren[0].match(SIMPLE_SELECTOR_PREFIX)) {
var typeSelector = paren.split(SIMPLE_SELECTOR_PREFIX)[0];
if (typeSelector === hostScope) {
return paren;
} else {
return SELECTOR_NO_MATCH;
}
} else {
return selector.replace(HOST_PAREN, function (m, host, paren) {
return hostScope + paren;
});
}
} else {
return selector.replace(HOST, hostScope);
}
},
documentRule: function (rule) {
rule.selector = rule.parsedSelector;
this.normalizeRootSelector(rule);
if (!settings.useNativeShadow) {
this._transformRule(rule, this._transformDocumentSelector);
}
},
normalizeRootSelector: function (rule) {
if (rule.selector === ROOT) {
rule.selector = 'html';
}
},
_transformDocumentSelector: function (selector) {
return selector.match(SCOPE_JUMP) ? this._transformComplexSelector(selector, SCOPE_DOC_SELECTOR) : this._transformSimpleSelector(selector.trim(), SCOPE_DOC_SELECTOR);
},
SCOPE_NAME: 'style-scope'
};
var SCOPE_NAME = api.SCOPE_NAME;
var SCOPE_DOC_SELECTOR = ':not([' + SCOPE_NAME + '])' + ':not(.' + SCOPE_NAME + ')';
var COMPLEX_SELECTOR_SEP = ',';
var SIMPLE_SELECTOR_SEP = /(^|[\s>+~]+)((?:\[.+?\]|[^\s>+~=\[])+)/g;
var SIMPLE_SELECTOR_PREFIX = /[[.:#*]/;
var HOST = ':host';
var ROOT = ':root';
var HOST_PAREN = /(:host)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/;
var HOST_CONTEXT = ':host-context';
var HOST_CONTEXT_PAREN = /(.*)(?::host-context)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))(.*)/;
var CONTENT = '::content';
var SCOPE_JUMP = /::content|::shadow|\/deep\//;
var CSS_CLASS_PREFIX = '.';
var CSS_ATTR_PREFIX = '[' + SCOPE_NAME + '~=';
var CSS_ATTR_SUFFIX = ']';
var PSEUDO_PREFIX = ':';
var CLASS = 'class';
var CONTENT_START = new RegExp('^(' + CONTENT + ')');
var SELECTOR_NO_MATCH = 'should_not_match';
return api;
}();
export const StyleExtends = function () {
var styleUtil = StyleUtil;
return {
hasExtends: function (cssText) {
return Boolean(cssText.match(this.rx.EXTEND));
},
transform: function (style) {
var rules = styleUtil.rulesForStyle(style);
var self = this;
styleUtil.forEachRule(rules, function (rule) {
self._mapRuleOntoParent(rule);
if (rule.parent) {
var m;
while (m = self.rx.EXTEND.exec(rule.cssText)) {
var extend = m[1];
var extendor = self._findExtendor(extend, rule);
if (extendor) {
self._extendRule(rule, extendor);
}
}
}
rule.cssText = rule.cssText.replace(self.rx.EXTEND, '');
});
return styleUtil.toCssText(rules, function (rule) {
if (rule.selector.match(self.rx.STRIP)) {
rule.cssText = '';
}
}, true);
},
_mapRuleOntoParent: function (rule) {
if (rule.parent) {
var map = rule.parent.map || (rule.parent.map = {});
var parts = rule.selector.split(',');
for (var i = 0, p; i < parts.length; i++) {
p = parts[i];
map[p.trim()] = rule;
}
return map;
}
},
_findExtendor: function (extend, rule) {
return rule.parent && rule.parent.map && rule.parent.map[extend] || this._findExtendor(extend, rule.parent);
},
_extendRule: function (target, source) {
if (target.parent !== source.parent) {
this._cloneAndAddRuleToParent(source, target.parent);
}
target.extends = target.extends || [];
target.extends.push(source);
source.selector = source.selector.replace(this.rx.STRIP, '');
source.selector = (source.selector && source.selector + ',\n') + target.selector;
if (source.extends) {
source.extends.forEach(function (e) {
this._extendRule(target, e);
}, this);
}
},
_cloneAndAddRuleToParent: function (rule, parent) {
rule = Object.create(rule);
rule.parent = parent;
if (rule.extends) {
rule.extends = rule.extends.slice();
}
parent.rules.push(rule);
},
rx: {
EXTEND: /@extends\(([^)]*)\)\s*?;/gim,
STRIP: /%[^,]*$/
}
};
}();
export const ApplyShim = function () {
'use strict';
var styleUtil = StyleUtil;
var MIXIN_MATCH = styleUtil.rx.MIXIN_MATCH;
var VAR_ASSIGN = styleUtil.rx.VAR_ASSIGN;
var BAD_VAR = /var\(\s*(--[^,]*),\s*(--[^)]*)\)/g;
var APPLY_NAME_CLEAN = /;\s*/m;
var INITIAL_INHERIT = /^\s*(initial)|(inherit)\s*$/;
var MIXIN_VAR_SEP = '_-_';
var mixinMap = {};
function mapSet(name, props) {
name = name.trim();
mixinMap[name] = {
properties: props,
dependants: {}
};
}
function mapGet(name) {
name = name.trim();
return mixinMap[name];
}
function replaceInitialOrInherit(property, value) {
var match = INITIAL_INHERIT.exec(value);
if (match) {
if (match[1]) {
value = ApplyShim._getInitialValueForProperty(property);
} else {
value = 'apply-shim-inherit';
}
}
return value;
}
function cssTextToMap(text) {
var props = text.split(';');
var property, value;
var out = {};
for (var i = 0, p, sp; i < props.length; i++) {
p = props[i];
if (p) {
sp = p.split(':');
if (sp.length > 1) {
property = sp[0].trim();
value = replaceInitialOrInherit(property, sp.slice(1).join(':'));
out[property] = value;
}
}
}
return out;
}
function invalidateMixinEntry(mixinEntry) {
var currentProto = ApplyShim.__currentElementProto;
var currentElementName = currentProto && currentProto.is;
for (var elementName in mixinEntry.dependants) {
if (elementName !== currentElementName) {
mixinEntry.dependants[elementName].__applyShimInvalid = true;
}
}
}
function produceCssProperties(matchText, propertyName, valueProperty, valueMixin) {
if (valueProperty) {
styleUtil.processVariableAndFallback(valueProperty, function (prefix, value) {
if (value && mapGet(value)) {
valueMixin = '@apply ' + value + ';';
}
});
}
if (!valueMixin) {
return matchText;
}
var mixinAsProperties = consumeCssProperties(valueMixin);
var prefix = matchText.slice(0, matchText.indexOf('--'));
var mixinValues = cssTextToMap(mixinAsProperties);
var combinedProps = mixinValues;
var mixinEntry = mapGet(propertyName);
var oldProps = mixinEntry && mixinEntry.properties;
if (oldProps) {
combinedProps = Object.create(oldProps);
combinedProps = Base.mixin(combinedProps, mixinValues);
} else {
mapSet(propertyName, combinedProps);
}
var out = [];
var p, v;
var needToInvalidate = false;
for (p in combinedProps) {
v = mixinValues[p];
if (v === undefined) {
v = 'initial';
}
if (oldProps && !(p in oldProps)) {
needToInvalidate = true;
}
out.push(propertyName + MIXIN_VAR_SEP + p + ': ' + v);
}
if (needToInvalidate) {
invalidateMixinEntry(mixinEntry);
}
if (mixinEntry) {
mixinEntry.properties = combinedProps;
}
if (valueProperty) {
prefix = matchText + ';' + prefix;
}
return prefix + out.join('; ') + ';';
}
function fixVars(matchText, varA, varB) {
return 'var(' + varA + ',' + 'var(' + varB + '));';
}
function atApplyToCssProperties(mixinName, fallbacks) {
mixinName = mixinName.replace(APPLY_NAME_CLEAN, '');
var vars = [];
var mixinEntry = mapGet(mixinName);
if (!mixinEntry) {
mapSet(mixinName, {});
mixinEntry = mapGet(mixinName);
}
if (mixinEntry) {
var currentProto = ApplyShim.__currentElementProto;
if (currentProto) {
mixinEntry.dependants[currentProto.is] = currentProto;
}
var p, parts, f;
for (p in mixinEntry.properties) {
f = fallbacks && fallbacks[p];
parts = [
p,
': var(',
mixinName,
MIXIN_VAR_SEP,
p
];
if (f) {
parts.push(',', f);
}
parts.push(')');
vars.push(parts.join(''));
}
}
return vars.join('; ');
}
function consumeCssProperties(text) {
var m;
while (m = MIXIN_MATCH.exec(text)) {
var matchText = m[0];
var mixinName = m[1];
var idx = m.index;
var applyPos = idx + matchText.indexOf('@apply');
var afterApplyPos = idx + matchText.length;
var textBeforeApply = text.slice(0, applyPos);
var textAfterApply = text.slice(afterApplyPos);
var defaults = cssTextToMap(textBeforeApply);
var replacement = atApplyToCssProperties(mixinName, defaults);
text = [
textBeforeApply,
replacement,
textAfterApply
].join('');
MIXIN_MATCH.lastIndex = idx + replacement.length;
}
return text;
}
var ApplyShim = {
_measureElement: null,
_map: mixinMap,
_separator: MIXIN_VAR_SEP,
transform: function (styles, elementProto) {
this.__currentElementProto = elementProto;
styleUtil.forRulesInStyles(styles, this._boundTransformRule);
elementProto.__applyShimInvalid = false;
this.__currentElementProto = null;
},
transformRule: function (rule) {
rule.cssText = this.transformCssText(rule.parsedCssText);
if (rule.selector === ':root') {
rule.selector = ':host > *';
}
},
transformCssText: function (cssText) {
cssText = cssText.replace(BAD_VAR, fixVars);
cssText = cssText.replace(VAR_ASSIGN, produceCssProperties);
return consumeCssProperties(cssText);
},
_getInitialValueForProperty: function (property) {
if (!this._measureElement) {
this._measureElement = document.createElement('meta');
this._measureElement.style.all = 'initial';
document.head.appendChild(this._measureElement);
}
return window.getComputedStyle(this._measureElement).getPropertyValue(property);
}
};
ApplyShim._boundTransformRule = ApplyShim.transformRule.bind(ApplyShim);
return ApplyShim;
}();
var prepElement = Base._prepElement;
var nativeShadow = undefined.useNativeShadow;
var styleUtil = StyleUtil;
var styleTransformer = StyleTransformer;
var styleExtends = StyleExtends;
var applyShim = ApplyShim;
var settings = undefined;
Base._addFeature({
_prepElement: function (element) {
if (this._encapsulateStyle && this.__cssBuild !== 'shady') {
styleTransformer.element(element, this.is, this._scopeCssViaAttr);
}
prepElement.call(this, element);
},
_prepStyles: function () {
if (this._encapsulateStyle === undefined) {
this._encapsulateStyle = !nativeShadow;
}
if (!nativeShadow) {
this._scopeStyle = styleUtil.applyStylePlaceHolder(this.is);
}
this.__cssBuild = styleUtil.cssBuildTypeForModule(this.is);
},
_prepShimStyles: function () {
if (this._template) {
var hasTargetedCssBuild = styleUtil.isTargetedBuild(this.__cssBuild);
if (settings.useNativeCSSProperties && this.__cssBuild === 'shadow' && hasTargetedCssBuild) {
return;
}
this._styles = this._styles || this._collectStyles();
if (settings.useNativeCSSProperties && !this.__cssBuild) {
applyShim.transform(this._styles, this);
}
var cssText = settings.useNativeCSSProperties && hasTargetedCssBuild ? this._styles.length && this._styles[0].textContent.trim() : styleTransformer.elementStyles(this);
this._prepStyleProperties();
if (!this._needsStyleProperties() && cssText) {
styleUtil.applyCss(cssText, this.is, nativeShadow ? this._template.content : null, this._scopeStyle);
}
} else {
this._styles = [];
}
},
_collectStyles: function () {
var styles = [];
var cssText = '', m$ = this.styleModules;
if (m$) {
for (var i = 0, l = m$.length, m; i < l && (m = m$[i]); i++) {
cssText += styleUtil.cssFromModule(m);
}
}
cssText += styleUtil.cssFromModule(this.is);
var p = this._template && this._template.parentNode;
if (this._template && (!p || p.id.toLowerCase() !== this.is)) {
cssText += styleUtil.cssFromElement(this._template);
}
if (cssText) {
var style = document.createElement('style');
style.textContent = cssText;
if (styleExtends.hasExtends(style.textContent)) {
cssText = styleExtends.transform(style);
}
styles.push(style);
}
return styles;
},
_elementAdd: function (node) {
if (this._encapsulateStyle) {
if (node.__styleScoped) {
node.__styleScoped = false;
} else {
styleTransformer.dom(node, this.is, this._scopeCssViaAttr);
}
}
},
_elementRemove: function (node) {
if (this._encapsulateStyle) {
styleTransformer.dom(node, this.is, this._scopeCssViaAttr, true);
}
},
scopeSubtree: function (container, shouldObserve) {
if (nativeShadow) {
return;
}
var self = this;
var scopify = function (node) {
if (node.nodeType === Node.ELEMENT_NODE) {
var className = node.getAttribute('class');
node.setAttribute('class', self._scopeElementClass(node, className));
var n$ = node.querySelectorAll('*');
for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
className = n.getAttribute('class');
n.setAttribute('class', self._scopeElementClass(n, className));
}
}
};
scopify(container);
if (shouldObserve) {
var mo = new MutationObserver(function (mxns) {
for (var i = 0, m; i < mxns.length && (m = mxns[i]); i++) {
if (m.addedNodes) {
for (var j = 0; j < m.addedNodes.length; j++) {
scopify(m.addedNodes[j]);
}
}
}
});
mo.observe(container, {
childList: true,
subtree: true
});
return mo;
}
}
});
export const StyleProperties = function () {
'use strict';
var matchesSelector = DomApi.matchesSelector;
var styleUtil = StyleUtil;
var styleTransformer = StyleTransformer;
var IS_IE = navigator.userAgent.match('Trident');
var settings = undefined;
return {
decorateStyles: function (styles, scope) {
var self = this, props = {}, keyframes = [], ruleIndex = 0;
var scopeSelector = styleTransformer._calcHostScope(scope.is, scope.extends);
styleUtil.forRulesInStyles(styles, function (rule, style) {
self.decorateRule(rule);
rule.index = ruleIndex++;
self.whenHostOrRootRule(scope, rule, style, function (info) {
if (rule.parent.type === styleUtil.ruleTypes.MEDIA_RULE) {
scope.__notStyleScopeCacheable = true;
}
if (info.isHost) {
var hostContextOrFunction = info.selector.split(' ').some(function (s) {
return s.indexOf(scopeSelector) === 0 && s.length !== scopeSelector.length;
});
scope.__notStyleScopeCacheable = scope.__notStyleScopeCacheable || hostContextOrFunction;
}
});
self.collectPropertiesInCssText(rule.propertyInfo.cssText, props);
}, function onKeyframesRule(rule) {
keyframes.push(rule);
});
styles._keyframes = keyframes;
var names = [];
for (var i in props) {
names.push(i);
}
return names;
},
decorateRule: function (rule) {
if (rule.propertyInfo) {
return rule.propertyInfo;
}
var info = {}, properties = {};
var hasProperties = this.collectProperties(rule, properties);
if (hasProperties) {
info.properties = properties;
rule.rules = null;
}
info.cssText = this.collectCssText(rule);
rule.propertyInfo = info;
return info;
},
collectProperties: function (rule, properties) {
var info = rule.propertyInfo;
if (info) {
if (info.properties) {
Base.mixin(properties, info.properties);
return true;
}
} else {
var m, rx = this.rx.VAR_ASSIGN;
var cssText = rule.parsedCssText;
var value;
var any;
while (m = rx.exec(cssText)) {
value = (m[2] || m[3]).trim();
if (value !== 'inherit') {
properties[m[1].trim()] = value;
}
any = true;
}
return any;
}
},
collectCssText: function (rule) {
return this.collectConsumingCssText(rule.parsedCssText);
},
collectConsumingCssText: function (cssText) {
return cssText.replace(this.rx.BRACKETED, '').replace(this.rx.VAR_ASSIGN, '');
},
collectPropertiesInCssText: function (cssText, props) {
var m;
while (m = this.rx.VAR_CONSUMED.exec(cssText)) {
var name = m[1];
if (m[2] !== ':') {
props[name] = true;
}
}
},
reify: function (props) {
var names = Object.getOwnPropertyNames(props);
for (var i = 0, n; i < names.length; i++) {
n = names[i];
props[n] = this.valueForProperty(props[n], props);
}
},
valueForProperty: function (property, props) {
if (property) {
if (property.indexOf(';') >= 0) {
property = this.valueForProperties(property, props);
} else {
var self = this;
var fn = function (prefix, value, fallback, suffix) {
var propertyValue = self.valueForProperty(props[value], props);
if (!propertyValue || propertyValue === 'initial') {
propertyValue = self.valueForProperty(props[fallback] || fallback, props) || fallback;
} else if (propertyValue === 'apply-shim-inherit') {
propertyValue = 'inherit';
}
return prefix + (propertyValue || '') + suffix;
};
property = styleUtil.processVariableAndFallback(property, fn);
}
}
return property && property.trim() || '';
},
valueForProperties: function (property, props) {
var parts = property.split(';');
for (var i = 0, p, m; i < parts.length; i++) {
if (p = parts[i]) {
this.rx.MIXIN_MATCH.lastIndex = 0;
m = this.rx.MIXIN_MATCH.exec(p);
if (m) {
p = this.valueForProperty(props[m[1]], props);
} else {
var colon = p.indexOf(':');
if (colon !== -1) {
var pp = p.substring(colon);
pp = pp.trim();
pp = this.valueForProperty(pp, props) || pp;
p = p.substring(0, colon) + pp;
}
}
parts[i] = p && p.lastIndexOf(';') === p.length - 1 ? p.slice(0, -1) : p || '';
}
}
return parts.join(';');
},
applyProperties: function (rule, props) {
var output = '';
if (!rule.propertyInfo) {
this.decorateRule(rule);
}
if (rule.propertyInfo.cssText) {
output = this.valueForProperties(rule.propertyInfo.cssText, props);
}
rule.cssText = output;
},
applyKeyframeTransforms: function (rule, keyframeTransforms) {
var input = rule.cssText;
var output = rule.cssText;
if (rule.hasAnimations == null) {
rule.hasAnimations = this.rx.ANIMATION_MATCH.test(input);
}
if (rule.hasAnimations) {
var transform;
if (rule.keyframeNamesToTransform == null) {
rule.keyframeNamesToTransform = [];
for (var keyframe in keyframeTransforms) {
transform = keyframeTransforms[keyframe];
output = transform(input);
if (input !== output) {
input = output;
rule.keyframeNamesToTransform.push(keyframe);
}
}
} else {
for (var i = 0; i < rule.keyframeNamesToTransform.length; ++i) {
transform = keyframeTransforms[rule.keyframeNamesToTransform[i]];
input = transform(input);
}
output = input;
}
}
rule.cssText = output;
},
propertyDataFromStyles: function (styles, element) {
var props = {}, self = this;
var o = [];
styleUtil.forActiveRulesInStyles(styles, function (rule) {
if (!rule.propertyInfo) {
self.decorateRule(rule);
}
var selectorToMatch = rule.transformedSelector || rule.parsedSelector;
if (element && rule.propertyInfo.properties && selectorToMatch) {
if (matchesSelector.call(element, selectorToMatch)) {
self.collectProperties(rule, props);
addToBitMask(rule.index, o);
}
}
});
return {
properties: props,
key: o
};
},
whenHostOrRootRule: function (scope, rule, style, callback) {
if (!rule.propertyInfo) {
self.decorateRule(rule);
}
if (!rule.propertyInfo.properties) {
return;
}
var hostScope = scope.is ? styleTransformer._calcHostScope(scope.is, scope.extends) : 'html';
var parsedSelector = rule.parsedSelector;
var isRoot = parsedSelector === ':root';
var isHost = parsedSelector.indexOf(':host') === 0;
var cssBuild = scope.__cssBuild || style.__cssBuild;
if (cssBuild === 'shady') {
isRoot = parsedSelector === hostScope + ' > *.' + hostScope || parsedSelector.indexOf('html') !== -1;
isHost = !isRoot && parsedSelector.indexOf(hostScope) === 0;
}
if (cssBuild === 'shadow') {
isRoot = parsedSelector === ':host > *' || parsedSelector === 'html';
isHost = isHost && !isRoot;
}
if (!isRoot && !isHost) {
return;
}
var selectorToMatch = hostScope;
if (isHost) {
if (settings.useNativeShadow && !rule.transformedSelector) {
rule.transformedSelector = styleTransformer._transformRuleCss(rule, styleTransformer._transformComplexSelector, scope.is, hostScope);
}
selectorToMatch = rule.transformedSelector || rule.parsedSelector;
}
callback({
selector: selectorToMatch,
isHost: isHost,
isRoot: isRoot
});
},
hostAndRootPropertiesForScope: function (scope) {
var hostProps = {}, rootProps = {}, self = this;
styleUtil.forActiveRulesInStyles(scope._styles, function (rule, style) {
self.whenHostOrRootRule(scope, rule, style, function (info) {
var element = scope._element || scope;
if (matchesSelector.call(element, info.selector)) {
if (info.isHost) {
self.collectProperties(rule, hostProps);
} else {
self.collectProperties(rule, rootProps);
}
}
});
});
return {
rootProps: rootProps,
hostProps: hostProps
};
},
transformStyles: function (element, properties, scopeSelector) {
var self = this;
var hostSelector = styleTransformer._calcHostScope(element.is, element.extends);
var rxHostSelector = element.extends ? '\\' + hostSelector.slice(0, -1) + '\\]' : hostSelector;
var hostRx = new RegExp(this.rx.HOST_PREFIX + rxHostSelector + this.rx.HOST_SUFFIX);
var keyframeTransforms = this._elementKeyframeTransforms(element, scopeSelector);
return styleTransformer.elementStyles(element, function (rule) {
self.applyProperties(rule, properties);
if (!settings.useNativeShadow && !StyleUtil.isKeyframesSelector(rule) && rule.cssText) {
self.applyKeyframeTransforms(rule, keyframeTransforms);
self._scopeSelector(rule, hostRx, hostSelector, element._scopeCssViaAttr, scopeSelector);
}
});
},
_elementKeyframeTransforms: function (element, scopeSelector) {
var keyframesRules = element._styles._keyframes;
var keyframeTransforms = {};
if (!settings.useNativeShadow && keyframesRules) {
for (var i = 0, keyframesRule = keyframesRules[i]; i < keyframesRules.length; keyframesRule = keyframesRules[++i]) {
this._scopeKeyframes(keyframesRule, scopeSelector);
keyframeTransforms[keyframesRule.keyframesName] = this._keyframesRuleTransformer(keyframesRule);
}
}
return keyframeTransforms;
},
_keyframesRuleTransformer: function (keyframesRule) {
return function (cssText) {
return cssText.replace(keyframesRule.keyframesNameRx, keyframesRule.transformedKeyframesName);
};
},
_scopeKeyframes: function (rule, scopeId) {
rule.keyframesNameRx = new RegExp(rule.keyframesName, 'g');
rule.transformedKeyframesName = rule.keyframesName + '-' + scopeId;
rule.transformedSelector = rule.transformedSelector || rule.selector;
rule.selector = rule.transformedSelector.replace(rule.keyframesName, rule.transformedKeyframesName);
},
_scopeSelector: function (rule, hostRx, hostSelector, viaAttr, scopeId) {
rule.transformedSelector = rule.transformedSelector || rule.selector;
var selector = rule.transformedSelector;
var scope = viaAttr ? '[' + styleTransformer.SCOPE_NAME + '~=' + scopeId + ']' : '.' + scopeId;
var parts = selector.split(',');
for (var i = 0, l = parts.length, p; i < l && (p = parts[i]); i++) {
parts[i] = p.match(hostRx) ? p.replace(hostSelector, scope) : scope + ' ' + p;
}
rule.selector = parts.join(',');
},
applyElementScopeSelector: function (element, selector, old, viaAttr) {
var c = viaAttr ? element.getAttribute(styleTransformer.SCOPE_NAME) : element.getAttribute('class') || '';
var v = old ? c.replace(old, selector) : (c ? c + ' ' : '') + this.XSCOPE_NAME + ' ' + selector;
if (c !== v) {
if (viaAttr) {
element.setAttribute(styleTransformer.SCOPE_NAME, v);
} else {
element.setAttribute('class', v);
}
}
},
applyElementStyle: function (element, properties, selector, style) {
var cssText = style ? style.textContent || '' : this.transformStyles(element, properties, selector);
var s = element._customStyle;
if (s && !settings.useNativeShadow && s !== style) {
s._useCount--;
if (s._useCount <= 0 && s.parentNode) {
s.parentNode.removeChild(s);
}
}
if (settings.useNativeShadow) {
if (element._customStyle) {
element._customStyle.textContent = cssText;
style = element._customStyle;
} else if (cssText) {
style = styleUtil.applyCss(cssText, selector, element.root, element._scopeStyle);
}
} else {
if (!style) {
if (cssText) {
style = styleUtil.applyCss(cssText, selector, null, element._scopeStyle);
}
} else if (!style.parentNode) {
styleUtil.applyStyle(style, null, element._scopeStyle);
}
}
if (style) {
style._useCount = style._useCount || 0;
if (element._customStyle != style) {
style._useCount++;
}
element._customStyle = style;
}
if (IS_IE) {
style.textContent = style.textContent;
}
return style;
},
mixinCustomStyle: function (props, customStyle) {
var v;
for (var i in customStyle) {
v = customStyle[i];
if (v || v === 0) {
props[i] = v;
}
}
},
updateNativeStyleProperties: function (element, properties) {
var oldPropertyNames = element.__customStyleProperties;
if (oldPropertyNames) {
for (var i = 0; i < oldPropertyNames.length; i++) {
element.style.removeProperty(oldPropertyNames[i]);
}
}
var propertyNames = [];
for (var p in properties) {
if (properties[p] !== null) {
element.style.setProperty(p, properties[p]);
propertyNames.push(p);
}
}
element.__customStyleProperties = propertyNames;
},
rx: styleUtil.rx,
XSCOPE_NAME: 'x-scope'
};
function addToBitMask(n, bits) {
var o = parseInt(n / 32);
var v = 1 << n % 32;
bits[o] = (bits[o] || 0) | v;
}
}();
export const StyleCache = function () {
this.cache = {};
};
StyleCache.prototype = {
MAX: 100,
store: function (is, data, keyValues, keyStyles) {
data.keyValues = keyValues;
data.styles = keyStyles;
var s$ = this.cache[is] = this.cache[is] || [];
s$.push(data);
if (s$.length > this.MAX) {
s$.shift();
}
},
retrieve: function (is, keyValues, keyStyles) {
var cache = this.cache[is];
if (cache) {
for (var i = cache.length - 1, data; i >= 0; i--) {
data = cache[i];
if (keyStyles === data.styles && this._objectsEqual(keyValues, data.keyValues)) {
return data;
}
}
}
},
clear: function () {
this.cache = {};
},
_objectsEqual: function (target, source) {
var t, s;
for (var i in target) {
t = target[i], s = source[i];
if (!(typeof t === 'object' && t ? this._objectsStrictlyEqual(t, s) : t === s)) {
return false;
}
}
if (Array.isArray(target)) {
return target.length === source.length;
}
return true;
},
_objectsStrictlyEqual: function (target, source) {
return this._objectsEqual(target, source) && this._objectsEqual(source, target);
}
};
export const StyleDefaults = function () {
var styleProperties = StyleProperties;
var StyleCache = StyleCache;
var nativeVariables = useNativeCSSProperties$0;
var api = {
_styles: [],
_properties: null,
customStyle: {},
_styleCache: new StyleCache(),
_element: DomApi.wrap(document.documentElement),
addStyle: function (style) {
this._styles.push(style);
this._properties = null;
},
get _styleProperties() {
if (!this._properties) {
styleProperties.decorateStyles(this._styles, this);
this._styles._scopeStyleProperties = null;
this._properties = styleProperties.hostAndRootPropertiesForScope(this).rootProps;
styleProperties.mixinCustomStyle(this._properties, this.customStyle);
styleProperties.reify(this._properties);
}
return this._properties;
},
hasStyleProperties: function () {
return Boolean(this._properties);
},
_needsStyleProperties: function () {
},
_computeStyleProperties: function () {
return this._styleProperties;
},
updateStyles: function (properties) {
this._properties = null;
if (properties) {
Base.mixin(this.customStyle, properties);
}
this._styleCache.clear();
for (var i = 0, s; i < this._styles.length; i++) {
s = this._styles[i];
s = s.__importElement || s;
s._apply();
}
if (nativeVariables) {
styleProperties.updateNativeStyleProperties(document.documentElement, this.customStyle);
}
}
};
return api;
}();
var serializeValueToAttribute = Base.serializeValueToAttribute;
var propertyUtils = StyleProperties;
var styleTransformer = StyleTransformer;
var styleDefaults = StyleDefaults;
var nativeShadow = undefined.useNativeShadow;
var nativeVariables = useNativeCSSProperties$0;
Base._addFeature({
_prepStyleProperties: function () {
if (!nativeVariables) {
this._ownStylePropertyNames = this._styles && this._styles.length ? propertyUtils.decorateStyles(this._styles, this) : null;
}
},
customStyle: null,
getComputedStyleValue: function (property) {
return !nativeVariables && this._styleProperties && this._styleProperties[property] || getComputedStyle(this).getPropertyValue(property);
},
_setupStyleProperties: function () {
this.customStyle = {};
this._styleCache = null;
this._styleProperties = null;
this._scopeSelector = null;
this._ownStyleProperties = null;
this._customStyle = null;
},
_needsStyleProperties: function () {
return Boolean(!nativeVariables && this._ownStylePropertyNames && this._ownStylePropertyNames.length);
},
_validateApplyShim: function () {
if (this.__applyShimInvalid) {
ApplyShim.transform(this._styles, this.__proto__);
var cssText = styleTransformer.elementStyles(this);
if (nativeShadow) {
var templateStyle = this._template.content.querySelector('style');
if (templateStyle) {
templateStyle.textContent = cssText;
}
} else {
var shadyStyle = this._scopeStyle && this._scopeStyle.nextSibling;
if (shadyStyle) {
shadyStyle.textContent = cssText;
}
}
}
},
_beforeAttached: function () {
if ((!this._scopeSelector || this.__stylePropertiesInvalid) && this._needsStyleProperties()) {
this.__stylePropertiesInvalid = false;
this._updateStyleProperties();
}
},
_findStyleHost: function () {
var e = this, root;
while (root = dom$0(e).getOwnerRoot()) {
if (Polymer.isInstance(root.host)) {
return root.host;
}
e = root.host;
}
return styleDefaults;
},
_updateStyleProperties: function () {
var info, scope = this._findStyleHost();
if (!scope._styleProperties) {
scope._computeStyleProperties();
}
if (!scope._styleCache) {
scope._styleCache = new StyleCache();
}
var scopeData = propertyUtils.propertyDataFromStyles(scope._styles, this);
var scopeCacheable = !this.__notStyleScopeCacheable;
if (scopeCacheable) {
scopeData.key.customStyle = this.customStyle;
info = scope._styleCache.retrieve(this.is, scopeData.key, this._styles);
}
var scopeCached = Boolean(info);
if (scopeCached) {
this._styleProperties = info._styleProperties;
} else {
this._computeStyleProperties(scopeData.properties);
}
this._computeOwnStyleProperties();
if (!scopeCached) {
info = styleCache.retrieve(this.is, this._ownStyleProperties, this._styles);
}
var globalCached = Boolean(info) && !scopeCached;
var style = this._applyStyleProperties(info);
if (!scopeCached) {
style = style && nativeShadow ? style.cloneNode(true) : style;
info = {
style: style,
_scopeSelector: this._scopeSelector,
_styleProperties: this._styleProperties
};
if (scopeCacheable) {
scopeData.key.customStyle = {};
this.mixin(scopeData.key.customStyle, this.customStyle);
scope._styleCache.store(this.is, info, scopeData.key, this._styles);
}
if (!globalCached) {
styleCache.store(this.is, Object.create(info), this._ownStyleProperties, this._styles);
}
}
},
_computeStyleProperties: function (scopeProps) {
var scope = this._findStyleHost();
if (!scope._styleProperties) {
scope._computeStyleProperties();
}
var props = Object.create(scope._styleProperties);
var hostAndRootProps = propertyUtils.hostAndRootPropertiesForScope(this);
this.mixin(props, hostAndRootProps.hostProps);
scopeProps = scopeProps || propertyUtils.propertyDataFromStyles(scope._styles, this).properties;
this.mixin(props, scopeProps);
this.mixin(props, hostAndRootProps.rootProps);
propertyUtils.mixinCustomStyle(props, this.customStyle);
propertyUtils.reify(props);
this._styleProperties = props;
},
_computeOwnStyleProperties: function () {
var props = {};
for (var i = 0, n; i < this._ownStylePropertyNames.length; i++) {
n = this._ownStylePropertyNames[i];
props[n] = this._styleProperties[n];
}
this._ownStyleProperties = props;
},
_scopeCount: 0,
_applyStyleProperties: function (info) {
var oldScopeSelector = this._scopeSelector;
this._scopeSelector = info ? info._scopeSelector : this.is + '-' + this.__proto__._scopeCount++;
var style = propertyUtils.applyElementStyle(this, this._styleProperties, this._scopeSelector, info && info.style);
if (!nativeShadow) {
propertyUtils.applyElementScopeSelector(this, this._scopeSelector, oldScopeSelector, this._scopeCssViaAttr);
}
return style;
},
serializeValueToAttribute: function (value, attribute, node) {
node = node || this;
if (attribute === 'class' && !nativeShadow) {
var host = node === this ? this.domHost || this.dataHost : this;
if (host) {
value = host._scopeElementClass(node, value);
}
}
node = this.shadyRoot && this.shadyRoot._hasDistributed ? dom$0(node) : node;
serializeValueToAttribute.call(this, value, attribute, node);
},
_scopeElementClass: function (element, selector) {
if (!nativeShadow && !this._scopeCssViaAttr) {
selector = (selector ? selector + ' ' : '') + SCOPE_NAME + ' ' + this.is + (element._scopeSelector ? ' ' + XSCOPE_NAME + ' ' + element._scopeSelector : '');
}
return selector;
},
updateStyles: function (properties) {
if (properties) {
this.mixin(this.customStyle, properties);
}
if (nativeVariables) {
propertyUtils.updateNativeStyleProperties(this, this.customStyle);
} else {
if (this.isAttached) {
if (this._needsStyleProperties()) {
this._updateStyleProperties();
} else {
this._styleProperties = null;
}
} else {
this.__stylePropertiesInvalid = true;
}
if (this._styleCache) {
this._styleCache.clear();
}
this._updateRootStyles();
}
},
_updateRootStyles: function (root) {
root = root || this.root;
var c$ = dom$0(root)._query(function (e) {
return e.shadyRoot || e.shadowRoot;
});
for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
if (c.updateStyles) {
c.updateStyles();
}
}
}
});
export const updateStyles = function (properties) {
styleDefaults.updateStyles(properties);
Base._updateRootStyles(document);
};
var styleCache = new StyleCache();
export { styleCache as customStyleCache };
var SCOPE_NAME = styleTransformer.SCOPE_NAME;
var XSCOPE_NAME = propertyUtils.XSCOPE_NAME;
Base._addFeature({
_registerFeatures: function () {
this._prepIs();
this._prepConstructor();
this._prepStyles();
},
_finishRegisterFeatures: function () {
this._prepTemplate();
this._prepShimStyles();
this._prepAnnotations();
this._prepEffects();
this._prepBehaviors();
this._prepPropertyInfo();
this._prepBindings();
this._prepShady();
},
_prepBehavior: function (b) {
this._addPropertyEffects(b.properties);
this._addComplexObserverEffects(b.observers);
this._addHostAttributes(b.hostAttributes);
},
_initFeatures: function () {
this._setupGestures();
this._setupConfigure();
this._setupStyleProperties();
this._setupDebouncers();
this._setupShady();
this._registerHost();
if (this._template) {
this._validateApplyShim();
this._poolContent();
this._beginHosting();
this._stampTemplate();
this._endHosting();
this._marshalAnnotationReferences();
}
this._marshalInstanceEffects();
this._marshalBehaviors();
this._marshalHostAttributes();
this._marshalAttributes();
this._tryReady();
},
_marshalBehavior: function (b) {
if (b.listeners) {
this._listenListeners(b.listeners);
}
}
});
var propertyUtils = StyleProperties;
var styleUtil = StyleUtil;
var cssParse = CssParse;
var styleDefaults = StyleDefaults;
var styleTransformer = StyleTransformer;
var applyShim = ApplyShim;
var debounce = Polymer.Debounce;
var settings = undefined;
var updateDebouncer;
Polymer$0({
is: 'custom-style',
extends: 'style',
_template: null,
properties: { include: String },
ready: function () {
this.__appliedElement = this.__appliedElement || this;
this.__cssBuild = styleUtil.getCssBuildType(this);
if (this.__appliedElement !== this) {
this.__appliedElement.__cssBuild = this.__cssBuild;
}
this._tryApply();
},
attached: function () {
this._tryApply();
},
_tryApply: function () {
if (!this._appliesToDocument) {
if (this.parentNode && this.parentNode.localName !== 'dom-module') {
this._appliesToDocument = true;
var e = this.__appliedElement;
if (!settings.useNativeCSSProperties) {
this.__needsUpdateStyles = styleDefaults.hasStyleProperties();
styleDefaults.addStyle(e);
}
if (e.textContent || this.include) {
this._apply(true);
} else {
var self = this;
var observer = new MutationObserver(function () {
observer.disconnect();
self._apply(true);
});
observer.observe(e, { childList: true });
}
}
}
},
_updateStyles: function () {
updateStyles$0();
},
_apply: function (initialApply) {
var e = this.__appliedElement;
if (this.include) {
e.textContent = styleUtil.cssFromModules(this.include, true) + e.textContent;
}
if (!e.textContent) {
return;
}
var buildType = this.__cssBuild;
var targetedBuild = styleUtil.isTargetedBuild(buildType);
if (settings.useNativeCSSProperties && targetedBuild) {
return;
}
var styleRules = styleUtil.rulesForStyle(e);
if (!targetedBuild) {
styleUtil.forEachRule(styleRules, function (rule) {
styleTransformer.documentRule(rule);
if (settings.useNativeCSSProperties && !buildType) {
applyShim.transformRule(rule);
}
});
}
if (settings.useNativeCSSProperties) {
e.textContent = styleUtil.toCssText(styleRules);
} else {
var self = this;
var fn = function fn() {
self._flushCustomProperties();
};
if (initialApply) {
renderStatus.whenReady(fn);
} else {
fn();
}
}
},
_flushCustomProperties: function () {
if (this.__needsUpdateStyles) {
this.__needsUpdateStyles = false;
updateDebouncer = debounce(updateDebouncer, this._updateStyles);
} else {
this._applyCustomProperties();
}
},
_applyCustomProperties: function () {
var element = this.__appliedElement;
this._computeStyleProperties();
var props = this._styleProperties;
var rules = styleUtil.rulesForStyle(element);
if (!rules) {
return;
}
element.textContent = styleUtil.toCssText(rules, function (rule) {
var css = rule.cssText = rule.parsedCssText;
if (rule.propertyInfo && rule.propertyInfo.cssText) {
css = cssParse.removeCustomPropAssignment(css);
rule.cssText = propertyUtils.valueForProperties(css, props);
}
});
}
});
export const Templatizer = {
properties: { __hideTemplateChildren__: { observer: '_showHideChildren' } },
_instanceProps: Polymer.nob,
_parentPropPrefix: '_parent_',
templatize: function (template) {
this._templatized = template;
if (!template._content) {
template._content = template.content;
}
if (template._content._ctor) {
this.ctor = template._content._ctor;
this._prepParentProperties(this.ctor.prototype, template);
return;
}
var archetype = Object.create(Base);
this._customPrepAnnotations(archetype, template);
this._prepParentProperties(archetype, template);
archetype._prepEffects();
this._customPrepEffects(archetype);
archetype._prepBehaviors();
archetype._prepPropertyInfo();
archetype._prepBindings();
archetype._notifyPathUp = this._notifyPathUpImpl;
archetype._scopeElementClass = this._scopeElementClassImpl;
archetype.listen = this._listenImpl;
archetype._showHideChildren = this._showHideChildrenImpl;
archetype.__setPropertyOrig = this.__setProperty;
archetype.__setProperty = this.__setPropertyImpl;
var _constructor = this._constructorImpl;
var ctor = function TemplateInstance(model, host) {
_constructor.call(this, model, host);
};
ctor.prototype = archetype;
archetype.constructor = ctor;
template._content._ctor = ctor;
this.ctor = ctor;
},
_getRootDataHost: function () {
return this.dataHost && this.dataHost._rootDataHost || this.dataHost;
},
_showHideChildrenImpl: function (hide) {
var c = this._children;
for (var i = 0; i < c.length; i++) {
var n = c[i];
if (Boolean(hide) != Boolean(n.__hideTemplateChildren__)) {
if (n.nodeType === Node.TEXT_NODE) {
if (hide) {
n.__polymerTextContent__ = n.textContent;
n.textContent = '';
} else {
n.textContent = n.__polymerTextContent__;
}
} else if (n.style) {
if (hide) {
n.__polymerDisplay__ = n.style.display;
n.style.display = 'none';
} else {
n.style.display = n.__polymerDisplay__;
}
}
}
n.__hideTemplateChildren__ = hide;
}
},
__setPropertyImpl: function (property, value, fromAbove, node) {
if (node && node.__hideTemplateChildren__ && property == 'textContent') {
property = '__polymerTextContent__';
}
this.__setPropertyOrig(property, value, fromAbove, node);
},
_debounceTemplate: function (fn) {
addDebouncer(this.debounce('_debounceTemplate', fn));
},
_flushTemplates: function () {
flush();
},
_customPrepEffects: function (archetype) {
var parentProps = archetype._parentProps;
for (var prop in parentProps) {
archetype._addPropertyEffect(prop, 'function', this._createHostPropEffector(prop));
}
for (prop in this._instanceProps) {
archetype._addPropertyEffect(prop, 'function', this._createInstancePropEffector(prop));
}
},
_customPrepAnnotations: function (archetype, template) {
archetype._template = template;
var c = template._content;
if (!c._notes) {
var rootDataHost = archetype._rootDataHost;
if (rootDataHost) {
Annotations.prepElement = function () {
rootDataHost._prepElement();
};
}
c._notes = Annotations.parseAnnotations(template);
Annotations.prepElement = null;
this._processAnnotations(c._notes);
}
archetype._notes = c._notes;
archetype._parentProps = c._parentProps;
},
_prepParentProperties: function (archetype, template) {
var parentProps = this._parentProps = archetype._parentProps;
if (this._forwardParentProp && parentProps) {
var proto = archetype._parentPropProto;
var prop;
if (!proto) {
for (prop in this._instanceProps) {
delete parentProps[prop];
}
proto = archetype._parentPropProto = Object.create(null);
if (template != this) {
Bind.prepareModel(proto);
Base.prepareModelNotifyPath(proto);
}
for (prop in parentProps) {
var parentProp = this._parentPropPrefix + prop;
var effects = [
{
kind: 'function',
effect: this._createForwardPropEffector(prop),
fn: Bind._functionEffect
},
{
kind: 'notify',
fn: Bind._notifyEffect,
effect: { event: camelToDashCase(parentProp) + '-changed' }
}
];
Bind._createAccessors(proto, parentProp, effects);
}
}
var self = this;
if (template != this) {
Bind.prepareInstance(template);
template._forwardParentProp = function (source, value) {
self._forwardParentProp(source, value);
};
}
this._extendTemplate(template, proto);
template._pathEffector = function (path, value, fromAbove) {
return self._pathEffectorImpl(path, value, fromAbove);
};
}
},
_createForwardPropEffector: function (prop) {
return function (source, value) {
this._forwardParentProp(prop, value);
};
},
_createHostPropEffector: function (prop) {
var prefix = this._parentPropPrefix;
return function (source, value) {
this.dataHost._templatized[prefix + prop] = value;
};
},
_createInstancePropEffector: function (prop) {
return function (source, value, old, fromAbove) {
if (!fromAbove) {
this.dataHost._forwardInstanceProp(this, prop, value);
}
};
},
_extendTemplate: function (template, proto) {
var n$ = Object.getOwnPropertyNames(proto);
if (proto._propertySetter) {
template._propertySetter = proto._propertySetter;
}
for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
var val = template[n];
var pd = Object.getOwnPropertyDescriptor(proto, n);
Object.defineProperty(template, n, pd);
if (val !== undefined) {
template._propertySetter(n, val);
}
}
},
_showHideChildren: function (hidden) {
},
_forwardInstancePath: function (inst, path, value) {
},
_forwardInstanceProp: function (inst, prop, value) {
},
_notifyPathUpImpl: function (path, value) {
var dataHost = this.dataHost;
var dot = path.indexOf('.');
var root = dot < 0 ? path : path.slice(0, dot);
dataHost._forwardInstancePath.call(dataHost, this, path, value);
if (root in dataHost._parentProps) {
dataHost._templatized._notifyPath(dataHost._parentPropPrefix + path, value);
}
},
_pathEffectorImpl: function (path, value, fromAbove) {
if (this._forwardParentPath) {
if (path.indexOf(this._parentPropPrefix) === 0) {
var subPath = path.substring(this._parentPropPrefix.length);
var model = this._modelForPath(subPath);
if (model in this._parentProps) {
this._forwardParentPath(subPath, value);
}
}
}
Base._pathEffector.call(this._templatized, path, value, fromAbove);
},
_constructorImpl: function (model, host) {
this._rootDataHost = host._getRootDataHost();
this._setupConfigure(model);
this._registerHost(host);
this._beginHosting();
this.root = this.instanceTemplate(this._template);
this.root.__noContent = !this._notes._hasContent;
this.root.__styleScoped = true;
this._endHosting();
this._marshalAnnotatedNodes();
this._marshalInstanceEffects();
this._marshalAnnotatedListeners();
var children = [];
for (var n = this.root.firstChild; n; n = n.nextSibling) {
children.push(n);
n._templateInstance = this;
}
this._children = children;
if (host.__hideTemplateChildren__) {
this._showHideChildren(true);
}
this._tryReady();
},
_listenImpl: function (node, eventName, methodName) {
var model = this;
var host = this._rootDataHost;
var handler = host._createEventHandler(node, eventName, methodName);
var decorated = function (e) {
e.model = model;
handler(e);
};
host._listen(node, eventName, decorated);
},
_scopeElementClassImpl: function (node, value) {
var host = this._rootDataHost;
if (host) {
return host._scopeElementClass(node, value);
}
return value;
},
stamp: function (model) {
model = model || {};
if (this._parentProps) {
var templatized = this._templatized;
for (var prop in this._parentProps) {
if (model[prop] === undefined) {
model[prop] = templatized[this._parentPropPrefix + prop];
}
}
}
return new this.ctor(model, this);
},
modelForElement: function (el) {
var model;
while (el) {
if (model = el._templateInstance) {
if (model.dataHost != this) {
el = model.dataHost;
} else {
return model;
}
} else {
el = el.parentNode;
}
}
}
};
Polymer$0({
is: 'dom-template',
extends: 'template',
_template: null,
behaviors: [Templatizer$0],
ready: function () {
this.templatize(this);
}
});
export const _collections = new WeakMap();
export const Collection = function (userArray) {
_collections.set(userArray, this);
this.userArray = userArray;
this.store = userArray.slice();
this.initMap();
};
undefined.prototype = {
constructor: undefined,
initMap: function () {
var omap = this.omap = new WeakMap();
var pmap = this.pmap = {};
var s = this.store;
for (var i = 0; i < s.length; i++) {
var item = s[i];
if (item && typeof item == 'object') {
omap.set(item, i);
} else {
pmap[item] = i;
}
}
},
add: function (item) {
var key = this.store.push(item) - 1;
if (item && typeof item == 'object') {
this.omap.set(item, key);
} else {
this.pmap[item] = key;
}
return '#' + key;
},
removeKey: function (key) {
if (key = this._parseKey(key)) {
this._removeFromMap(this.store[key]);
delete this.store[key];
}
},
_removeFromMap: function (item) {
if (item && typeof item == 'object') {
this.omap.delete(item);
} else {
delete this.pmap[item];
}
},
remove: function (item) {
var key = this.getKey(item);
this.removeKey(key);
return key;
},
getKey: function (item) {
var key;
if (item && typeof item == 'object') {
key = this.omap.get(item);
} else {
key = this.pmap[item];
}
if (key != undefined) {
return '#' + key;
}
},
getKeys: function () {
return Object.keys(this.store).map(function (key) {
return '#' + key;
});
},
_parseKey: function (key) {
if (key && key[0] == '#') {
return key.slice(1);
}
},
setItem: function (key, item) {
if (key = this._parseKey(key)) {
var old = this.store[key];
if (old) {
this._removeFromMap(old);
}
if (item && typeof item == 'object') {
this.omap.set(item, key);
} else {
this.pmap[item] = key;
}
this.store[key] = item;
}
},
getItem: function (key) {
if (key = this._parseKey(key)) {
return this.store[key];
}
},
getItems: function () {
var items = [], store = this.store;
for (var key in store) {
items.push(store[key]);
}
return items;
},
_applySplices: function (splices) {
var keyMap = {}, key;
for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
s.addedKeys = [];
for (var j = 0; j < s.removed.length; j++) {
key = this.getKey(s.removed[j]);
keyMap[key] = keyMap[key] ? null : -1;
}
for (j = 0; j < s.addedCount; j++) {
var item = this.userArray[s.index + j];
key = this.getKey(item);
key = key === undefined ? this.add(item) : key;
keyMap[key] = keyMap[key] ? null : 1;
s.addedKeys.push(key);
}
}
var removed = [];
var added = [];
for (key in keyMap) {
if (keyMap[key] < 0) {
this.removeKey(key);
removed.push(key);
}
if (keyMap[key] > 0) {
added.push(key);
}
}
return [{
removed: removed,
added: added
}];
}
};
undefined.get = function (userArray) {
return _collections.get(userArray) || new undefined(userArray);
};
undefined.applySplices = function (userArray, splices) {
var coll = _collections.get(userArray);
return coll ? coll._applySplices(splices) : null;
};Polymer$0({
is: 'dom-repeat',
extends: 'template',
_template: null,
properties: {
items: { type: Array },
as: {
type: String,
value: 'item'
},
indexAs: {
type: String,
value: 'index'
},
sort: {
type: Function,
observer: '_sortChanged'
},
filter: {
type: Function,
observer: '_filterChanged'
},
observe: {
type: String,
observer: '_observeChanged'
},
delay: Number,
renderedItemCount: {
type: Number,
notify: true,
readOnly: true
},
initialCount: {
type: Number,
observer: '_initializeChunking'
},
targetFramerate: {
type: Number,
value: 20
},
_targetFrameTime: {
type: Number,
computed: '_computeFrameTime(targetFramerate)'
}
},
behaviors: [Templatizer$0],
observers: ['_itemsChanged(items.*)'],
created: function () {
this._instances = [];
this._pool = [];
this._limit = Infinity;
var self = this;
this._boundRenderChunk = function () {
self._renderChunk();
};
},
detached: function () {
this.__isDetached = true;
for (var i = 0; i < this._instances.length; i++) {
this._detachInstance(i);
}
},
attached: function () {
if (this.__isDetached) {
this.__isDetached = false;
var parent = dom$0(dom$0(this).parentNode);
for (var i = 0; i < this._instances.length; i++) {
this._attachInstance(i, parent);
}
}
},
ready: function () {
this._instanceProps = { __key__: true };
this._instanceProps[this.as] = true;
this._instanceProps[this.indexAs] = true;
if (!this.ctor) {
this.templatize(this);
}
},
_sortChanged: function (sort) {
var dataHost = this._getRootDataHost();
this._sortFn = sort && (typeof sort == 'function' ? sort : function () {
return dataHost[sort].apply(dataHost, arguments);
});
this._needFullRefresh = true;
if (this.items) {
this._debounceTemplate(this._render);
}
},
_filterChanged: function (filter) {
var dataHost = this._getRootDataHost();
this._filterFn = filter && (typeof filter == 'function' ? filter : function () {
return dataHost[filter].apply(dataHost, arguments);
});
this._needFullRefresh = true;
if (this.items) {
this._debounceTemplate(this._render);
}
},
_computeFrameTime: function (rate) {
return Math.ceil(1000 / rate);
},
_initializeChunking: function () {
if (this.initialCount) {
this._limit = this.initialCount;
this._chunkCount = this.initialCount;
this._lastChunkTime = performance.now();
}
},
_tryRenderChunk: function () {
if (this.items && this._limit < this.items.length) {
this.debounce('renderChunk', this._requestRenderChunk);
}
},
_requestRenderChunk: function () {
requestAnimationFrame(this._boundRenderChunk);
},
_renderChunk: function () {
var currChunkTime = performance.now();
var ratio = this._targetFrameTime / (currChunkTime - this._lastChunkTime);
this._chunkCount = Math.round(this._chunkCount * ratio) || 1;
this._limit += this._chunkCount;
this._lastChunkTime = currChunkTime;
this._debounceTemplate(this._render);
},
_observeChanged: function () {
this._observePaths = this.observe && this.observe.replace('.*', '.').split(' ');
},
_itemsChanged: function (change) {
if (change.path == 'items') {
if (Array.isArray(this.items)) {
this.collection = undefined.get(this.items);
} else if (!this.items) {
this.collection = null;
} else {
this._error(this._logf('dom-repeat', 'expected array for `items`,' + ' found', this.items));
}
this._keySplices = [];
this._indexSplices = [];
this._needFullRefresh = true;
this._initializeChunking();
this._debounceTemplate(this._render);
} else if (change.path == 'items.splices') {
this._keySplices = this._keySplices.concat(change.value.keySplices);
this._indexSplices = this._indexSplices.concat(change.value.indexSplices);
this._debounceTemplate(this._render);
} else {
var subpath = change.path.slice(6);
this._forwardItemPath(subpath, change.value);
this._checkObservedPaths(subpath);
}
},
_checkObservedPaths: function (path) {
if (this._observePaths) {
path = path.substring(path.indexOf('.') + 1);
var paths = this._observePaths;
for (var i = 0; i < paths.length; i++) {
if (path.indexOf(paths[i]) === 0) {
this._needFullRefresh = true;
if (this.delay) {
this.debounce('render', this._render, this.delay);
} else {
this._debounceTemplate(this._render);
}
return;
}
}
}
},
render: function () {
this._needFullRefresh = true;
this._debounceTemplate(this._render);
this._flushTemplates();
},
_render: function () {
if (this._needFullRefresh) {
this._applyFullRefresh();
this._needFullRefresh = false;
} else if (this._keySplices.length) {
if (this._sortFn) {
this._applySplicesUserSort(this._keySplices);
} else {
if (this._filterFn) {
this._applyFullRefresh();
} else {
this._applySplicesArrayOrder(this._indexSplices);
}
}
} else {
}
this._keySplices = [];
this._indexSplices = [];
var keyToIdx = this._keyToInstIdx = {};
for (var i = this._instances.length - 1; i >= 0; i--) {
var inst = this._instances[i];
if (inst.isPlaceholder && i < this._limit) {
inst = this._insertInstance(i, inst.__key__);
} else if (!inst.isPlaceholder && i >= this._limit) {
inst = this._downgradeInstance(i, inst.__key__);
}
keyToIdx[inst.__key__] = i;
if (!inst.isPlaceholder) {
inst.__setProperty(this.indexAs, i, true);
}
}
this._pool.length = 0;
this._setRenderedItemCount(this._instances.length);
this.fire('dom-change');
this._tryRenderChunk();
},
_applyFullRefresh: function () {
var c = this.collection;
var keys;
if (this._sortFn) {
keys = c ? c.getKeys() : [];
} else {
keys = [];
var items = this.items;
if (items) {
for (var i = 0; i < items.length; i++) {
keys.push(c.getKey(items[i]));
}
}
}
var self = this;
if (this._filterFn) {
keys = keys.filter(function (a) {
return self._filterFn(c.getItem(a));
});
}
if (this._sortFn) {
keys.sort(function (a, b) {
return self._sortFn(c.getItem(a), c.getItem(b));
});
}
for (i = 0; i < keys.length; i++) {
var key = keys[i];
var inst = this._instances[i];
if (inst) {
inst.__key__ = key;
if (!inst.isPlaceholder && i < this._limit) {
inst.__setProperty(this.as, c.getItem(key), true);
}
} else if (i < this._limit) {
this._insertInstance(i, key);
} else {
this._insertPlaceholder(i, key);
}
}
for (var j = this._instances.length - 1; j >= i; j--) {
this._detachAndRemoveInstance(j);
}
},
_numericSort: function (a, b) {
return a - b;
},
_applySplicesUserSort: function (splices) {
var c = this.collection;
var keyMap = {};
var key;
for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
for (var j = 0; j < s.removed.length; j++) {
key = s.removed[j];
keyMap[key] = keyMap[key] ? null : -1;
}
for (j = 0; j < s.added.length; j++) {
key = s.added[j];
keyMap[key] = keyMap[key] ? null : 1;
}
}
var removedIdxs = [];
var addedKeys = [];
for (key in keyMap) {
if (keyMap[key] === -1) {
removedIdxs.push(this._keyToInstIdx[key]);
}
if (keyMap[key] === 1) {
addedKeys.push(key);
}
}
if (removedIdxs.length) {
removedIdxs.sort(this._numericSort);
for (i = removedIdxs.length - 1; i >= 0; i--) {
var idx = removedIdxs[i];
if (idx !== undefined) {
this._detachAndRemoveInstance(idx);
}
}
}
var self = this;
if (addedKeys.length) {
if (this._filterFn) {
addedKeys = addedKeys.filter(function (a) {
return self._filterFn(c.getItem(a));
});
}
addedKeys.sort(function (a, b) {
return self._sortFn(c.getItem(a), c.getItem(b));
});
var start = 0;
for (i = 0; i < addedKeys.length; i++) {
start = this._insertRowUserSort(start, addedKeys[i]);
}
}
},
_insertRowUserSort: function (start, key) {
var c = this.collection;
var item = c.getItem(key);
var end = this._instances.length - 1;
var idx = -1;
while (start <= end) {
var mid = start + end >> 1;
var midKey = this._instances[mid].__key__;
var cmp = this._sortFn(c.getItem(midKey), item);
if (cmp < 0) {
start = mid + 1;
} else if (cmp > 0) {
end = mid - 1;
} else {
idx = mid;
break;
}
}
if (idx < 0) {
idx = end + 1;
}
this._insertPlaceholder(idx, key);
return idx;
},
_applySplicesArrayOrder: function (splices) {
for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
for (var j = 0; j < s.removed.length; j++) {
this._detachAndRemoveInstance(s.index);
}
for (j = 0; j < s.addedKeys.length; j++) {
this._insertPlaceholder(s.index + j, s.addedKeys[j]);
}
}
},
_detachInstance: function (idx) {
var inst = this._instances[idx];
if (!inst.isPlaceholder) {
for (var i = 0; i < inst._children.length; i++) {
var el = inst._children[i];
dom$0(inst.root).appendChild(el);
}
return inst;
}
},
_attachInstance: function (idx, parent) {
var inst = this._instances[idx];
if (!inst.isPlaceholder) {
parent.insertBefore(inst.root, this);
}
},
_detachAndRemoveInstance: function (idx) {
var inst = this._detachInstance(idx);
if (inst) {
this._pool.push(inst);
}
this._instances.splice(idx, 1);
},
_insertPlaceholder: function (idx, key) {
this._instances.splice(idx, 0, {
isPlaceholder: true,
__key__: key
});
},
_stampInstance: function (idx, key) {
var model = { __key__: key };
model[this.as] = this.collection.getItem(key);
model[this.indexAs] = idx;
return this.stamp(model);
},
_insertInstance: function (idx, key) {
var inst = this._pool.pop();
if (inst) {
inst.__setProperty(this.as, this.collection.getItem(key), true);
inst.__setProperty('__key__', key, true);
} else {
inst = this._stampInstance(idx, key);
}
var beforeRow = this._instances[idx + 1];
var beforeNode = beforeRow && !beforeRow.isPlaceholder ? beforeRow._children[0] : this;
var parentNode = dom$0(this).parentNode;
dom$0(parentNode).insertBefore(inst.root, beforeNode);
this._instances[idx] = inst;
return inst;
},
_downgradeInstance: function (idx, key) {
var inst = this._detachInstance(idx);
if (inst) {
this._pool.push(inst);
}
inst = {
isPlaceholder: true,
__key__: key
};
this._instances[idx] = inst;
return inst;
},
_showHideChildren: function (hidden) {
for (var i = 0; i < this._instances.length; i++) {
this._instances[i]._showHideChildren(hidden);
}
},
_forwardInstanceProp: function (inst, prop, value) {
if (prop == this.as) {
var idx;
if (this._sortFn || this._filterFn) {
idx = this.items.indexOf(this.collection.getItem(inst.__key__));
} else {
idx = inst[this.indexAs];
}
this.set('items.' + idx, value);
}
},
_forwardInstancePath: function (inst, path, value) {
if (path.indexOf(this.as + '.') === 0) {
this._notifyPath('items.' + inst.__key__ + '.' + path.slice(this.as.length + 1), value);
}
},
_forwardParentProp: function (prop, value) {
var i$ = this._instances;
for (var i = 0, inst; i < i$.length && (inst = i$[i]); i++) {
if (!inst.isPlaceholder) {
inst.__setProperty(prop, value, true);
}
}
},
_forwardParentPath: function (path, value) {
var i$ = this._instances;
for (var i = 0, inst; i < i$.length && (inst = i$[i]); i++) {
if (!inst.isPlaceholder) {
inst._notifyPath(path, value, true);
}
}
},
_forwardItemPath: function (path, value) {
if (this._keyToInstIdx) {
var dot = path.indexOf('.');
var key = path.substring(0, dot < 0 ? path.length : dot);
var idx = this._keyToInstIdx[key];
var inst = this._instances[idx];
if (inst && !inst.isPlaceholder) {
if (dot >= 0) {
path = this.as + '.' + path.substring(dot + 1);
inst._notifyPath(path, value, true);
} else {
inst.__setProperty(this.as, value, true);
}
}
}
},
itemForElement: function (el) {
var instance = this.modelForElement(el);
return instance && instance[this.as];
},
keyForElement: function (el) {
var instance = this.modelForElement(el);
return instance && instance.__key__;
},
indexForElement: function (el) {
var instance = this.modelForElement(el);
return instance && instance[this.indexAs];
}
});Polymer$0({
is: 'array-selector',
_template: null,
properties: {
items: {
type: Array,
observer: 'clearSelection'
},
multi: {
type: Boolean,
value: false,
observer: 'clearSelection'
},
selected: {
type: Object,
notify: true
},
selectedItem: {
type: Object,
notify: true
},
toggle: {
type: Boolean,
value: false
}
},
clearSelection: function () {
if (Array.isArray(this.selected)) {
for (var i = 0; i < this.selected.length; i++) {
this.unlinkPaths('selected.' + i);
}
} else {
this.unlinkPaths('selected');
this.unlinkPaths('selectedItem');
}
if (this.multi) {
if (!this.selected || this.selected.length) {
this.selected = [];
this._selectedColl = undefined.get(this.selected);
}
} else {
this.selected = null;
this._selectedColl = null;
}
this.selectedItem = null;
},
isSelected: function (item) {
if (this.multi) {
return this._selectedColl.getKey(item) !== undefined;
} else {
return this.selected == item;
}
},
deselect: function (item) {
if (this.multi) {
if (this.isSelected(item)) {
var skey = this._selectedColl.getKey(item);
this.arrayDelete('selected', item);
this.unlinkPaths('selected.' + skey);
}
} else {
this.selected = null;
this.selectedItem = null;
this.unlinkPaths('selected');
this.unlinkPaths('selectedItem');
}
},
select: function (item) {
var icol = undefined.get(this.items);
var key = icol.getKey(item);
if (this.multi) {
if (this.isSelected(item)) {
if (this.toggle) {
this.deselect(item);
}
} else {
this.push('selected', item);
var skey = this._selectedColl.getKey(item);
this.linkPaths('selected.' + skey, 'items.' + key);
}
} else {
if (this.toggle && item == this.selected) {
this.deselect();
} else {
this.selected = item;
this.selectedItem = item;
this.linkPaths('selected', 'items.' + key);
this.linkPaths('selectedItem', 'items.' + key);
}
}
}
});Polymer$0({
is: 'dom-if',
extends: 'template',
_template: null,
properties: {
'if': {
type: Boolean,
value: false,
observer: '_queueRender'
},
restamp: {
type: Boolean,
value: false,
observer: '_queueRender'
}
},
behaviors: [Templatizer$0],
_queueRender: function () {
this._debounceTemplate(this._render);
},
detached: function () {
if (!this.parentNode || this.parentNode.nodeType == Node.DOCUMENT_FRAGMENT_NODE && (!undefined.hasShadow || !(this.parentNode instanceof ShadowRoot))) {
this._teardownInstance();
}
},
attached: function () {
if (this.if && this.ctor) {
this.async(this._ensureInstance);
}
},
render: function () {
this._flushTemplates();
},
_render: function () {
if (this.if) {
if (!this.ctor) {
this.templatize(this);
}
this._ensureInstance();
this._showHideChildren();
} else if (this.restamp) {
this._teardownInstance();
}
if (!this.restamp && this._instance) {
this._showHideChildren();
}
if (this.if != this._lastIf) {
this.fire('dom-change');
this._lastIf = this.if;
}
},
_ensureInstance: function () {
var parentNode = dom$0(this).parentNode;
if (parentNode) {
var parent = dom$0(parentNode);
if (!this._instance) {
this._instance = this.stamp();
var root = this._instance.root;
parent.insertBefore(root, this);
} else {
var c$ = this._instance._children;
if (c$ && c$.length) {
var lastChild = dom$0(this).previousSibling;
if (lastChild !== c$[c$.length - 1]) {
for (var i = 0, n; i < c$.length && (n = c$[i]); i++) {
parent.insertBefore(n, this);
}
}
}
}
}
},
_teardownInstance: function () {
if (this._instance) {
var c$ = this._instance._children;
if (c$ && c$.length) {
var parent = dom$0(dom$0(c$[0]).parentNode);
for (var i = 0, n; i < c$.length && (n = c$[i]); i++) {
parent.removeChild(n);
}
}
this._instance = null;
}
},
_showHideChildren: function () {
var hidden = this.__hideTemplateChildren__ || !this.if;
if (this._instance) {
this._instance._showHideChildren(hidden);
}
},
_forwardParentProp: function (prop, value) {
if (this._instance) {
this._instance.__setProperty(prop, value, true);
}
},
_forwardParentPath: function (path, value) {
if (this._instance) {
this._instance._notifyPath(path, value, true);
}
}
});Polymer$0({
is: 'dom-bind',
extends: 'template',
_template: null,
created: function () {
var self = this;
renderStatus.whenReady(function () {
if (document.readyState == 'loading') {
document.addEventListener('DOMContentLoaded', function () {
self._markImportsReady();
});
} else {
self._markImportsReady();
}
});
},
_ensureReady: function () {
if (!this._readied) {
this._readySelf();
}
},
_markImportsReady: function () {
this._importsReady = true;
this._ensureReady();
},
_registerFeatures: function () {
this._prepConstructor();
},
_insertChildren: function () {
var parentDom = dom$0(dom$0(this).parentNode);
parentDom.insertBefore(this.root, this);
},
_removeChildren: function () {
if (this._children) {
for (var i = 0; i < this._children.length; i++) {
this.root.appendChild(this._children[i]);
}
}
},
_initFeatures: function () {
},
_scopeElementClass: function (element, selector) {
if (this.dataHost) {
return this.dataHost._scopeElementClass(element, selector);
} else {
return selector;
}
},
_configureInstanceProperties: function () {
},
_prepConfigure: function () {
var config = {};
for (var prop in this._propertyEffects) {
config[prop] = this[prop];
}
var setupConfigure = this._setupConfigure;
this._setupConfigure = function () {
setupConfigure.call(this, config);
};
},
attached: function () {
if (this._importsReady) {
this.render();
}
},
detached: function () {
this._removeChildren();
},
render: function () {
this._ensureReady();
if (!this._children) {
this._template = this;
this._prepAnnotations();
this._prepEffects();
this._prepBehaviors();
this._prepConfigure();
this._prepBindings();
this._prepPropertyInfo();
Base._initFeatures.call(this);
this._children = Polymer.TreeApi.arrayCopyChildNodes(this.root);
}
this._insertChildren();
this.fire('dom-change');
}
});
</script>
<script>/**
@license
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
function MakePromise (asap) {
function Promise(fn) {
if (typeof this !== 'object' || typeof fn !== 'function') throw new TypeError();
this._state = null;
this._value = null;
this._deferreds = []
doResolve(fn, resolve.bind(this), reject.bind(this));
}
function handle(deferred) {
var me = this;
if (this._state === null) {
this._deferreds.push(deferred);
return
}
asap(function() {
var cb = me._state ? deferred.onFulfilled : deferred.onRejected
if (typeof cb !== 'function') {
(me._state ? deferred.resolve : deferred.reject)(me._value);
return;
}
var ret;
try {
ret = cb(me._value);
}
catch (e) {
deferred.reject(e);
return;
}
deferred.resolve(ret);
})
}
function resolve(newValue) {
try { //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
if (newValue === this) throw new TypeError();
if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
var then = newValue.then;
if (typeof then === 'function') {
doResolve(then.bind(newValue), resolve.bind(this), reject.bind(this));
return;
}
}
this._state = true;
this._value = newValue;
finale.call(this);
} catch (e) { reject.call(this, e); }
}
function reject(newValue) {
this._state = false;
this._value = newValue;
finale.call(this);
}
function finale() {
for (var i = 0, len = this._deferreds.length; i < len; i++) {
handle.call(this, this._deferreds[i]);
}
this._deferreds = null;
}
/**
* Take a potentially misbehaving resolver function and make sure
* onFulfilled and onRejected are only called once.
*
* Makes no guarantees about asynchrony.
*/
function doResolve(fn, onFulfilled, onRejected) {
var done = false;
try {
fn(function (value) {
if (done) return;
done = true;
onFulfilled(value);
}, function (reason) {
if (done) return;
done = true;
onRejected(reason);
})
} catch (ex) {
if (done) return;
done = true;
onRejected(ex);
}
}
Promise.prototype['catch'] = function (onRejected) {
return this.then(null, onRejected);
};
Promise.prototype.then = function(onFulfilled, onRejected) {
var me = this;
return new Promise(function(resolve, reject) {
handle.call(me, {
onFulfilled: onFulfilled,
onRejected: onRejected,
resolve: resolve,
reject: reject
});
})
};
Promise.resolve = function (value) {
if (value && typeof value === 'object' && value.constructor === Promise) {
return value;
}
return new Promise(function (resolve) {
resolve(value);
});
};
Promise.reject = function (value) {
return new Promise(function (resolve, reject) {
reject(value);
});
};
return Promise;
}
if (typeof module !== 'undefined') {
module.exports = MakePromise;
}
</script><script type="module">
import { Base } from '@polymer/polymer/polymer-legacy.js';
if (!window.Promise) {
window.Promise = MakePromise(Base.async);
}
</script>
<script>/**
@license
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
Promise.all = Promise.all || function () {
var args = Array.prototype.slice.call(arguments.length === 1 && Array.isArray(arguments[0]) ? arguments[0] : arguments);
return new Promise(function (resolve, reject) {
if (args.length === 0) return resolve([]);
var remaining = args.length;
function res(i, val) {
try {
if (val && (typeof val === 'object' || typeof val === 'function')) {
var then = val.then;
if (typeof then === 'function') {
then.call(val, function (val) { res(i, val) }, reject);
return;
}
}
args[i] = val;
if (--remaining === 0) {
resolve(args);
}
} catch (ex) {
reject(ex);
}
}
for (var i = 0; i < args.length; i++) {
res(i, args[i]);
}
});
};
Promise.race = Promise.race || function(values) {
// TODO(bradfordcsmith): To be consistent with the ECMAScript spec, this
// method should take any iterable, not just an array.
var forcedArray = /** @type {!Array<!Thenable>} */ (values);
return new Promise(function (resolve, reject) {
for(var i = 0, len = forcedArray.length; i < len; i++) {
forcedArray[i].then(resolve, reject);
}
});
};
</script>
<script>
(function () {
var _bindingRegex_patch = {
// Issue with https://github.com/Polymer/polymer/issues/3349
_bindingRegex_1_2_4: (function() {
var IDENT = '(?:' + '[a-zA-Z_$][\\w.:$-*]*' + ')';
var NUMBER = '(?:' + '[-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?' + ')';
var SQUOTE_STRING = '(?:' + '\'(?:[^\'\\\\]|\\\\.)*\'' + ')';
var DQUOTE_STRING = '(?:' + '"(?:[^"\\\\]|\\\\.)*"' + ')';
var STRING = '(?:' + SQUOTE_STRING + '|' + DQUOTE_STRING + ')';
var ARGUMENT = '(?:' + IDENT + '|' + NUMBER + '|' + STRING + '\\s*' + ')';
var ARGUMENTS = '(?:' + ARGUMENT + '(?:,\\s*' + ARGUMENT + ')*' + ')';
var ARGUMENT_LIST = '(?:' + '\\(\\s*' +
'(?:' + ARGUMENTS + '?' + ')' +
'\\)\\s*' + ')';
var BINDING = '(' + IDENT + '\\s*' + ARGUMENT_LIST + '?' + ')'; // Group 3
var OPEN_BRACKET = '(\\[\\[|{{)' + '\\s*';
var CLOSE_BRACKET = '(?:]]|}})';
var NEGATE = '(?:(!)\\s*)?'; // Group 2
var EXPRESSION = OPEN_BRACKET + NEGATE + BINDING + CLOSE_BRACKET;
return new RegExp(EXPRESSION, "g");
})(),
// Fix from https://github.com/TimvdLippe/polymer/blob/fix-binding-with-dash/src/lib/annotations/annotations.html
_bindingRegex_1_2_4_patched: (function() {
var IDENT = '(?:' + '[a-zA-Z_\\$][\\w\\.:\\$\\-\\*]*' + ')';
var NUMBER = '(?:' + '[-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?' + ')';
var SQUOTE_STRING = '(?:' + '\'(?:[^\'\\\\]|\\\\.)*\'' + ')';
var DQUOTE_STRING = '(?:' + '"(?:[^"\\\\]|\\\\.)*"' + ')';
var STRING = '(?:' + SQUOTE_STRING + '|' + DQUOTE_STRING + ')';
var ARGUMENT = '(?:' + IDENT + '|' + NUMBER + '|' + STRING + '\\s*' + ')';
var ARGUMENTS = '(?:' + ARGUMENT + '(?:,\\s*' + ARGUMENT + ')*' + ')';
var ARGUMENT_LIST = '(?:' + '\\(\\s*' +
'(?:' + ARGUMENTS + '?' + ')' +
'\\)\\s*' + ')';
var BINDING = '(' + IDENT + '\\s*' + ARGUMENT_LIST + '?' + ')'; // Group 3
var OPEN_BRACKET = '(\\[\\[|{{)' + '\\s*';
var CLOSE_BRACKET = '(?:]]|}})';
var NEGATE = '(?:(!)\\s*)?'; // Group 2
var EXPRESSION = OPEN_BRACKET + NEGATE + BINDING + CLOSE_BRACKET;
return new RegExp(EXPRESSION, "g");
})()
};
if (Polymer.Annotations._bindingRegex.toString() ===
_bindingRegex_patch._bindingRegex_1_2_4.toString()) {
console.log('Fixing Polymer issue#3349 by patching Polymer.Annotations._bindingRegex for Polymer 1.2.4');
Polymer.Annotations._bindingRegex = _bindingRegex_patch._bindingRegex_1_2_4_patched;
}
})();
</script>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { Base } from '@polymer/polymer/polymer-legacy.js';
Polymer({
is: 'iron-request',
hostAttributes: {
hidden: true
},
properties: {
/**
* A reference to the XMLHttpRequest instance used to generate the
* network request.
*
* @type {XMLHttpRequest}
*/
xhr: {
type: Object,
notify: true,
readOnly: true,
value: function() {
return new XMLHttpRequest();
}
},
/**
* A reference to the parsed response body, if the `xhr` has completely
* resolved.
*
* @type {*}
* @default null
*/
response: {
type: Object,
notify: true,
readOnly: true,
value: function() {
return null;
}
},
/**
* A reference to the status code, if the `xhr` has completely resolved.
*/
status: {
type: Number,
notify: true,
readOnly: true,
value: 0
},
/**
* A reference to the status text, if the `xhr` has completely resolved.
*/
statusText: {
type: String,
notify: true,
readOnly: true,
value: ''
},
/**
* A promise that resolves when the `xhr` response comes back, or rejects
* if there is an error before the `xhr` completes.
*
* @type {Promise}
*/
completes: {
type: Object,
readOnly: true,
notify: true,
value: function() {
return new Promise(function (resolve, reject) {
this.resolveCompletes = resolve;
this.rejectCompletes = reject;
}.bind(this));
}
},
/**
* An object that contains progress information emitted by the XHR if
* available.
*
* @default {}
*/
progress: {
type: Object,
notify: true,
readOnly: true,
value: function() {
return {};
}
},
/**
* Aborted will be true if an abort of the request is attempted.
*/
aborted: {
type: Boolean,
notify: true,
readOnly: true,
value: false,
},
/**
* Errored will be true if the browser fired an error event from the
* XHR object (mainly network errors).
*/
errored: {
type: Boolean,
notify: true,
readOnly: true,
value: false
},
/**
* TimedOut will be true if the XHR threw a timeout event.
*/
timedOut: {
type: Boolean,
notify: true,
readOnly: true,
value: false
}
},
/**
* Succeeded is true if the request succeeded. The request succeeded if it
* loaded without error, wasn't aborted, and the status code is ≥ 200, and
* < 300, or if the status code is 0.
*
* The status code 0 is accepted as a success because some schemes - e.g.
* file:// - don't provide status codes.
*
* @return {boolean}
*/
get succeeded() {
if (this.errored || this.aborted || this.timedOut) {
return false;
}
var status = this.xhr.status || 0;
// Note: if we are using the file:// protocol, the status code will be 0
// for all outcomes (successful or otherwise).
return status === 0 ||
(status >= 200 && status < 300);
},
/**
* Sends an HTTP request to the server and returns the XHR object.
*
* The handling of the `body` parameter will vary based on the Content-Type
* header. See the docs for iron-ajax's `body` param for details.
*
* @param {{
* url: string,
* method: (string|undefined),
* async: (boolean|undefined),
* body: (ArrayBuffer|ArrayBufferView|Blob|Document|FormData|null|string|undefined|Object),
* headers: (Object|undefined),
* handleAs: (string|undefined),
* jsonPrefix: (string|undefined),
* withCredentials: (boolean|undefined)}} options -
* url The url to which the request is sent.
* method The HTTP method to use, default is GET.
* async By default, all requests are sent asynchronously. To send synchronous requests,
* set to false.
* body The content for the request body for POST method.
* headers HTTP request headers.
* handleAs The response type. Default is 'text'.
* withCredentials Whether or not to send credentials on the request. Default is false.
* timeout: (Number|undefined)
* @return {Promise}
*/
send: function (options) {
var xhr = this.xhr;
if (xhr.readyState > 0) {
return null;
}
xhr.addEventListener('progress', function (progress) {
this._setProgress({
lengthComputable: progress.lengthComputable,
loaded: progress.loaded,
total: progress.total
});
}.bind(this))
xhr.addEventListener('error', function (error) {
this._setErrored(true);
this._updateStatus();
this.rejectCompletes(error);
}.bind(this));
xhr.addEventListener('timeout', function (error) {
this._setTimedOut(true);
this._updateStatus();
this.rejectCompletes(error);
}.bind(this));
xhr.addEventListener('abort', function () {
this._updateStatus();
this.rejectCompletes(new Error('Request aborted.'));
}.bind(this));
// Called after all of the above.
xhr.addEventListener('loadend', function () {
this._updateStatus();
this._setResponse(this.parseResponse());
if (!this.succeeded) {
this.rejectCompletes(new Error('The request failed with status code: ' + this.xhr.status));
return;
}
this.resolveCompletes(this);
}.bind(this));
this.url = options.url;
xhr.open(
options.method || 'GET',
options.url,
options.async !== false
);
var acceptType = {
'json': 'application/json',
'text': 'text/plain',
'html': 'text/html',
'xml': 'application/xml',
'arraybuffer': 'application/octet-stream'
}[options.handleAs];
var headers = options.headers || Object.create(null);
var newHeaders = Object.create(null);
for (var key in headers) {
newHeaders[key.toLowerCase()] = headers[key];
}
headers = newHeaders;
if (acceptType && !headers['accept']) {
headers['accept'] = acceptType;
}
Object.keys(headers).forEach(function (requestHeader) {
if (/[A-Z]/.test(requestHeader)) {
Base._error('Headers must be lower case, got', requestHeader);
}
xhr.setRequestHeader(
requestHeader,
headers[requestHeader]
);
}, this);
if (options.async !== false) {
if (options.async) {
xhr.timeout = options.timeout;
}
var handleAs = options.handleAs;
// If a JSON prefix is present, the responseType must be 'text' or the
// browser won’t be able to parse the response.
if (!!options.jsonPrefix || !handleAs) {
handleAs = 'text';
}
// In IE, `xhr.responseType` is an empty string when the response
// returns. Hence, caching it as `xhr._responseType`.
xhr.responseType = xhr._responseType = handleAs;
// Cache the JSON prefix, if it exists.
if (!!options.jsonPrefix) {
xhr._jsonPrefix = options.jsonPrefix;
}
}
xhr.withCredentials = !!options.withCredentials;
var body = this._encodeBodyObject(options.body, headers['content-type']);
xhr.send(
/** @type {ArrayBuffer|ArrayBufferView|Blob|Document|FormData|
null|string|undefined} */
(body));
return this.completes;
},
/**
* Attempts to parse the response body of the XHR. If parsing succeeds,
* the value returned will be deserialized based on the `responseType`
* set on the XHR.
*
* @return {*} The parsed response,
* or undefined if there was an empty response or parsing failed.
*/
parseResponse: function () {
var xhr = this.xhr;
var responseType = xhr.responseType || xhr._responseType;
var preferResponseText = !this.xhr.responseType;
var prefixLen = (xhr._jsonPrefix && xhr._jsonPrefix.length) || 0;
try {
switch (responseType) {
case 'json':
// If the xhr object doesn't have a natural `xhr.responseType`,
// we can assume that the browser hasn't parsed the response for us,
// and so parsing is our responsibility. Likewise if response is
// undefined, as there's no way to encode undefined in JSON.
if (preferResponseText || xhr.response === undefined) {
// Try to emulate the JSON section of the response body section of
// the spec: https://xhr.spec.whatwg.org/#response-body
// That is to say, we try to parse as JSON, but if anything goes
// wrong return null.
try {
return JSON.parse(xhr.responseText);
} catch (_) {
return null;
}
}
return xhr.response;
case 'xml':
return xhr.responseXML;
case 'blob':
case 'document':
case 'arraybuffer':
return xhr.response;
case 'text':
default: {
// If `prefixLen` is set, it implies the response should be parsed
// as JSON once the prefix of length `prefixLen` is stripped from
// it. Emulate the behavior above where null is returned on failure
// to parse.
if (prefixLen) {
try {
return JSON.parse(xhr.responseText.substring(prefixLen));
} catch (_) {
return null;
}
}
return xhr.responseText;
}
}
} catch (e) {
this.rejectCompletes(new Error('Could not parse response. ' + e.message));
}
},
/**
* Aborts the request.
*/
abort: function () {
this._setAborted(true);
this.xhr.abort();
},
/**
* @param {*} body The given body of the request to try and encode.
* @param {?string} contentType The given content type, to infer an encoding
* from.
* @return {*} Either the encoded body as a string, if successful,
* or the unaltered body object if no encoding could be inferred.
*/
_encodeBodyObject: function(body, contentType) {
if (typeof body == 'string') {
return body; // Already encoded.
}
var bodyObj = /** @type {Object} */ (body);
switch(contentType) {
case('application/json'):
return JSON.stringify(bodyObj);
case('application/x-www-form-urlencoded'):
return this._wwwFormUrlEncode(bodyObj);
}
return body;
},
/**
* @param {Object} object The object to encode as x-www-form-urlencoded.
* @return {string} .
*/
_wwwFormUrlEncode: function(object) {
if (!object) {
return '';
}
var pieces = [];
Object.keys(object).forEach(function(key) {
// TODO(rictic): handle array values here, in a consistent way with
// iron-ajax params.
pieces.push(
this._wwwFormUrlEncodePiece(key) + '=' +
this._wwwFormUrlEncodePiece(object[key]));
}, this);
return pieces.join('&');
},
/**
* @param {*} str A key or value to encode as x-www-form-urlencoded.
* @return {string} .
*/
_wwwFormUrlEncodePiece: function(str) {
// Spec says to normalize newlines to \r\n and replace %20 spaces with +.
// jQuery does this as well, so this is likely to be widely compatible.
if (str === null) {
return '';
}
return encodeURIComponent(str.toString().replace(/\r?\n/g, '\r\n'))
.replace(/%20/g, '+');
},
/**
* Updates the status code and status text.
*/
_updateStatus: function() {
this._setStatus(this.xhr.status);
this._setStatusText((this.xhr.statusText === undefined) ? '' : this.xhr.statusText);
}
});
</script>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { Base } from '@polymer/polymer/polymer-legacy.js';
Polymer({
is: 'iron-ajax',
/**
* Fired when a request is sent.
*
* @event request
* @event iron-ajax-request
*/
/**
* Fired when a response is received.
*
* @event response
* @event iron-ajax-response
*/
/**
* Fired when an error is received.
*
* @event error
* @event iron-ajax-error
*/
hostAttributes: {
hidden: true
},
properties: {
/**
* The URL target of the request.
*/
url: {
type: String
},
/**
* An object that contains query parameters to be appended to the
* specified `url` when generating a request. If you wish to set the body
* content when making a POST request, you should use the `body` property
* instead.
*/
params: {
type: Object,
value: function() {
return {};
}
},
/**
* The HTTP method to use such as 'GET', 'POST', 'PUT', or 'DELETE'.
* Default is 'GET'.
*/
method: {
type: String,
value: 'GET'
},
/**
* HTTP request headers to send.
*
* Example:
*
* <iron-ajax
* auto
* url="http://somesite.com"
* headers='{"X-Requested-With": "XMLHttpRequest"}'
* handle-as="json"></iron-ajax>
*
* Note: setting a `Content-Type` header here will override the value
* specified by the `contentType` property of this element.
*/
headers: {
type: Object,
value: function() {
return {};
}
},
/**
* Content type to use when sending data. If the `contentType` property
* is set and a `Content-Type` header is specified in the `headers`
* property, the `headers` property value will take precedence.
*
* Varies the handling of the `body` param.
*/
contentType: {
type: String,
value: null
},
/**
* Body content to send with the request, typically used with "POST"
* requests.
*
* If body is a string it will be sent unmodified.
*
* If Content-Type is set to a value listed below, then
* the body will be encoded accordingly.
*
* * `content-type="application/json"`
* * body is encoded like `{"foo":"bar baz","x":1}`
* * `content-type="application/x-www-form-urlencoded"`
* * body is encoded like `foo=bar+baz&x=1`
*
* Otherwise the body will be passed to the browser unmodified, and it
* will handle any encoding (e.g. for FormData, Blob, ArrayBuffer).
*
* @type (ArrayBuffer|ArrayBufferView|Blob|Document|FormData|null|string|undefined|Object)
*/
body: {
type: Object,
value: null
},
/**
* Toggle whether XHR is synchronous or asynchronous. Don't change this
* to true unless You Know What You Are Doing™.
*/
sync: {
type: Boolean,
value: false
},
/**
* Specifies what data to store in the `response` property, and
* to deliver as `event.detail.response` in `response` events.
*
* One of:
*
* `text`: uses `XHR.responseText`.
*
* `xml`: uses `XHR.responseXML`.
*
* `json`: uses `XHR.responseText` parsed as JSON.
*
* `arraybuffer`: uses `XHR.response`.
*
* `blob`: uses `XHR.response`.
*
* `document`: uses `XHR.response`.
*/
handleAs: {
type: String,
value: 'json'
},
/**
* Set the withCredentials flag on the request.
*/
withCredentials: {
type: Boolean,
value: false
},
/**
* Set the timeout flag on the request.
*/
timeout: {
type: Number,
value: 0
},
/**
* If true, automatically performs an Ajax request when either `url` or
* `params` changes.
*/
auto: {
type: Boolean,
value: false
},
/**
* If true, error messages will automatically be logged to the console.
*/
verbose: {
type: Boolean,
value: false
},
/**
* The most recent request made by this iron-ajax element.
*/
lastRequest: {
type: Object,
notify: true,
readOnly: true
},
/**
* True while lastRequest is in flight.
*/
loading: {
type: Boolean,
notify: true,
readOnly: true
},
/**
* lastRequest's response.
*
* Note that lastResponse and lastError are set when lastRequest finishes,
* so if loading is true, then lastResponse and lastError will correspond
* to the result of the previous request.
*
* The type of the response is determined by the value of `handleAs` at
* the time that the request was generated.
*
* @type {Object}
*/
lastResponse: {
type: Object,
notify: true,
readOnly: true
},
/**
* lastRequest's error, if any.
*
* @type {Object}
*/
lastError: {
type: Object,
notify: true,
readOnly: true
},
/**
* An Array of all in-flight requests originating from this iron-ajax
* element.
*/
activeRequests: {
type: Array,
notify: true,
readOnly: true,
value: function() {
return [];
}
},
/**
* Length of time in milliseconds to debounce multiple automatically generated requests.
*/
debounceDuration: {
type: Number,
value: 0,
notify: true
},
/**
* Prefix to be stripped from a JSON response before parsing it.
*
* In order to prevent an attack using CSRF with Array responses
* (http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx/)
* many backends will mitigate this by prefixing all JSON response bodies
* with a string that would be nonsensical to a JavaScript parser.
*
*/
jsonPrefix: {
type: String,
value: ''
},
/**
* By default, iron-ajax's events do not bubble. Setting this attribute will cause its
* request and response events as well as its iron-ajax-request, -response, and -error
* events to bubble to the window object. The vanilla error event never bubbles when
* using shadow dom even if this.bubbles is true because a scoped flag is not passed with
* it (first link) and because the shadow dom spec did not used to allow certain events,
* including events named error, to leak outside of shadow trees (second link).
* https://www.w3.org/TR/shadow-dom/#scoped-flag
* https://www.w3.org/TR/2015/WD-shadow-dom-20151215/#events-that-are-not-leaked-into-ancestor-trees
*/
bubbles: {
type: Boolean,
value: false
},
_boundHandleResponse: {
type: Function,
value: function() {
return this._handleResponse.bind(this);
}
}
},
observers: [
'_requestOptionsChanged(url, method, params.*, headers, contentType, ' +
'body, sync, handleAs, jsonPrefix, withCredentials, timeout, auto)'
],
/**
* The query string that should be appended to the `url`, serialized from
* the current value of `params`.
*
* @return {string}
*/
get queryString () {
var queryParts = [];
var param;
var value;
for (param in this.params) {
value = this.params[param];
param = window.encodeURIComponent(param);
if (Array.isArray(value)) {
for (var i = 0; i < value.length; i++) {
queryParts.push(param + '=' + window.encodeURIComponent(value[i]));
}
} else if (value !== null) {
queryParts.push(param + '=' + window.encodeURIComponent(value));
} else {
queryParts.push(param);
}
}
return queryParts.join('&');
},
/**
* The `url` with query string (if `params` are specified), suitable for
* providing to an `iron-request` instance.
*
* @return {string}
*/
get requestUrl() {
var queryString = this.queryString;
var url = this.url || '';
if (queryString) {
var bindingChar = url.indexOf('?') >= 0 ? '&' : '?';
return url + bindingChar + queryString;
}
return url;
},
/**
* An object that maps header names to header values, first applying the
* the value of `Content-Type` and then overlaying the headers specified
* in the `headers` property.
*
* @return {Object}
*/
get requestHeaders() {
var headers = {};
var contentType = this.contentType;
if (contentType == null && (typeof this.body === 'string')) {
contentType = 'application/x-www-form-urlencoded';
}
if (contentType) {
headers['content-type'] = contentType;
}
var header;
if (this.headers instanceof Object) {
for (header in this.headers) {
headers[header] = this.headers[header].toString();
}
}
return headers;
},
/**
* Request options suitable for generating an `iron-request` instance based
* on the current state of the `iron-ajax` instance's properties.
*
* @return {{
* url: string,
* method: (string|undefined),
* async: (boolean|undefined),
* body: (ArrayBuffer|ArrayBufferView|Blob|Document|FormData|null|string|undefined|Object),
* headers: (Object|undefined),
* handleAs: (string|undefined),
* jsonPrefix: (string|undefined),
* withCredentials: (boolean|undefined)}}
*/
toRequestOptions: function() {
return {
url: this.requestUrl || '',
method: this.method,
headers: this.requestHeaders,
body: this.body,
async: !this.sync,
handleAs: this.handleAs,
jsonPrefix: this.jsonPrefix,
withCredentials: this.withCredentials,
timeout: this.timeout
};
},
/**
* Performs an AJAX request to the specified URL.
*
* @return {!IronRequestElement}
*/
generateRequest: function() {
var request = /** @type {!IronRequestElement} */ (document.createElement('iron-request'));
var requestOptions = this.toRequestOptions();
this.push('activeRequests', request);
request.completes.then(
this._boundHandleResponse
).catch(
this._handleError.bind(this, request)
).then(
this._discardRequest.bind(this, request)
);
request.send(requestOptions);
this._setLastRequest(request);
this._setLoading(true);
this.fire('request', {
request: request,
options: requestOptions
}, {bubbles: this.bubbles});
this.fire('iron-ajax-request', {
request: request,
options: requestOptions
}, {bubbles: this.bubbles});
return request;
},
_handleResponse: function(request) {
if (request === this.lastRequest) {
this._setLastResponse(request.response);
this._setLastError(null);
this._setLoading(false);
}
this.fire('response', request, {bubbles: this.bubbles});
this.fire('iron-ajax-response', request, {bubbles: this.bubbles});
},
_handleError: function(request, error) {
if (this.verbose) {
Base._error(error);
}
if (request === this.lastRequest) {
this._setLastError({
request: request,
error: error,
status: request.xhr.status,
statusText: request.xhr.statusText,
response: request.xhr.response
});
this._setLastResponse(null);
this._setLoading(false);
}
// Tests fail if this goes after the normal this.fire('error', ...)
this.fire('iron-ajax-error', {
request: request,
error: error
}, {bubbles: this.bubbles});
this.fire('error', {
request: request,
error: error
}, {bubbles: this.bubbles});
},
_discardRequest: function(request) {
var requestIndex = this.activeRequests.indexOf(request);
if (requestIndex > -1) {
this.splice('activeRequests', requestIndex, 1);
}
},
_requestOptionsChanged: function() {
this.debounce('generate-request', function() {
if (this.url == null) {
return;
}
if (this.auto) {
this.generateRequest();
}
}, this.debounceDuration);
},
});
</script>
<dom-module id="i18n-number" assetpath="../../../i18n-number/">
<template strip-whitespace="">
<span id="number"></span>
</template>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
var intlLibraryScript;
var intlLibraryLoadingStatus = 'initializing';
/**
* Set up Intl polyfill if required
*/
function _setupIntlPolyfill () {
// Polyfill Intl if required
var intlLibraryUrl = this.resolveUrl('../intl/dist/Intl.min.js');
if (window.Intl) {
if (window.IntlPolyfill && window.Intl === window.IntlPolyfill) {
intlLibraryLoadingStatus = 'loaded';
}
else {
intlLibraryLoadingStatus = 'native';
}
}
else {
intlLibraryLoadingStatus = 'loading';
intlLibraryScript = document.createElement('script');
intlLibraryScript.setAttribute('src', intlLibraryUrl);
intlLibraryScript.setAttribute('id', 'intl-js-library');
intlLibraryScript.addEventListener('load', function intlLibraryLoaded (e) {
intlLibraryLoadingStatus = 'loaded';
e.target.removeEventListener('load', intlLibraryLoaded);
return false;
});
var s = document.querySelector('script') || document.body;
s.parentNode.insertBefore(intlLibraryScript, s);
}
}
/**
* Set up polyfill locale of Intl if required
*
* @param {String} locale Target locale to polyfill
* @param {Function} callback Callback function to handle locale load
* @return {Boolean} true if supported; false if callback will be called
*/
function _setupIntlPolyfillLocale (locale, callback) {
if (!window.IntlPolyfill) {
switch (intlLibraryLoadingStatus) {
case 'loading':
if (intlLibraryScript) {
var libraryLoadedBindThis = function (e) {
_setupIntlPolyfillLocale.call(this, locale, callback);
e.target.removeEventListener('load', libraryLoadedBindThis);
}.bind(this);
intlLibraryScript.addEventListener('load', libraryLoadedBindThis);
return false;
}
else {
console.error('Intl.js is not being loaded');
}
break;
// impossible cases
case 'initializing':
case 'loaded':
case 'native':
default:
/* istanbul ignore next: these cases are impossible */
break;
}
}
else {
if (intlLibraryLoadingStatus !== 'native') {
var supported = Intl.NumberFormat.supportedLocalesOf(locale, { localeMatcher: 'lookup' });
var script;
var intlScript;
if (supported.length === 0) {
// load the locale
var fallbackLanguages = _enumerateFallbackLanguages(locale);
locale = fallbackLanguages.shift();
script = document.querySelector('script#intl-js-locale-' + locale);
if (!script) {
script = document.createElement('script');
script.setAttribute('id', 'intl-js-locale-' + locale);
script.setAttribute('src', this.resolveUrl('../intl/locale-data/jsonp/' + locale + '.js'));
var intlLocaleLoadedBindThis = function (e) {
if (e.target === script) {
e.target.removeEventListener('load', intlLocaleLoadedBindThis);
callback.call(this, locale);
}
return false;
}.bind(this);
var intlLocaleLoadErrorBindThis = function (e) {
if (e.target === script) {
e.target.removeEventListener('error', intlLocaleLoadErrorBindThis);
script.setAttribute('loaderror','');
locale = fallbackLanguages.shift();
if (!locale) {
locale = this.DEFAULT_LANG;
}
var fallbackSupport = Intl.NumberFormat.supportedLocalesOf(locale, { localeMatcher: 'lookup'});
if (fallbackSupport.length > 0) {
callback.call(this, locale);
}
else {
_setupIntlPolyfillLocale.call(this, locale, callback);
}
return false;
}
}.bind(this);
script.addEventListener('load', intlLocaleLoadedBindThis);
script.addEventListener('error', intlLocaleLoadErrorBindThis);
intlScript = document.querySelector('script#intl-js-library') || document.body;
intlScript.parentNode.insertBefore(script, intlScript.nextSibling);
}
else if (!script.hasAttribute('loaderror')) {
// already loading
var anotherIntlLocaleLoadedBindThis = function (e) {
if (e.target === script) {
callback.call(this, locale);
e.target.removeEventListener('load', anotherIntlLocaleLoadedBindThis);
return false;
}
}.bind(this);
var anotherIntlLocaleLoadErrorBindThis = function (e) {
if (e.target === script) {
e.target.removeEventListener('error', anotherIntlLocaleLoadErrorBindThis);
locale = fallbackLanguages.shift();
if (!locale) {
locale = this.DEFAULT_LANG;
}
var fallbackSupport = Intl.NumberFormat.supportedLocalesOf(locale, { localeMatcher: 'lookup'});
if (fallbackSupport.length > 0) {
callback.call(this, locale);
}
else {
_setupIntlPolyfillLocale.call(this, locale, callback);
}
return false;
}
}.bind(this);
script.addEventListener('load', anotherIntlLocaleLoadedBindThis);
script.addEventListener('error', anotherIntlLocaleLoadErrorBindThis);
}
else {
var enSupport = Intl.NumberFormat.supportedLocalesOf(this.DEFAULT_LANG, { localeMatcher: 'lookup'});
if (enSupport.length > 0) {
callback.call(this, this.DEFAULT_LANG);
}
else {
_setupIntlPolyfillLocale.call(this, this.DEFAULT_LANG, callback);
}
}
return false;
}
}
}
return true;
}
/**
* Enumerate fallback locales for the target locale.
*
* Subset implementation of BCP47 (https://tools.ietf.org/html/bcp47).
*
* ### Examples:
*
*| Target Locale | Fallback 1 | Fallback 2 | Fallback 3 |
*|:--------------|:-----------|:-----------|:-----------|
*| ru | N/A | N/A | N/A |
*| en-GB | en | N/A | N/A |
*| en-Latn-GB | en-GB | en-Latn | en |
*| fr-CA | fr | N/A | N/A |
*| zh-Hans-CN | zh-Hans | zh | N/A |
*| zh-CN | zh-Hans | zh | N/A |
*| zh-TW | zh-Hant | zh | N/A |
*
* #### Note:
*
* For zh language, the script Hans or Hant is supplied as its default script when a country/region code is supplied.
*
* @param {string} lang Target locale.
* @return {Array} List of fallback locales including the target locale at the index 0.
*/
function _enumerateFallbackLanguages (lang) {
var result = [];
var parts;
var match;
var isExtLangCode = 0;
var extLangCode;
var isScriptCode = 0;
var scriptCode;
var isCountryCode = 0;
var countryCode;
var n;
if (!lang || lang.length === 0) {
result.push('');
}
else {
parts = lang.split(/[-_]/);
// normalize ISO-639-1 language codes
if (parts.length > 0 &&
parts[0].match(/^[A-Za-z]{2,3}$/)) {
// language codes have to be lowercased
// e.g. JA -> ja, FR -> fr
// TODO: normalize 3-letter codes to 2-letter codes
parts[0] = parts[0].toLowerCase();
}
// normalize ISO-639-3 extension language codes
if (parts.length >= 2 &&
parts[1].match(/^[A-Za-z]{3}$/) &&
!parts[1].match(/^[Cc][Hh][SsTt]$/)) { // exclude CHS,CHT
// extension language codes have to be lowercased
// e.g. YUE -> yue
isExtLangCode = 1;
extLangCode = parts[1] = parts[1].toLowerCase();
}
// normalize ISO-15924 script codes
if (parts.length >= isExtLangCode + 2 &&
(match = parts[isExtLangCode + 1].match(/^([A-Za-z])([A-Za-z]{3})$/))) {
// script codes have to be capitalized only at the first character
// e.g. HANs -> Hans, lAtN -> Latn
isScriptCode = 1;
scriptCode = parts[isExtLangCode + 1] = match[1].toUpperCase() + match[2].toLowerCase();
}
// normalize ISO-3166-1 country/region codes
if (parts.length >= isExtLangCode + isScriptCode + 2 &&
(match = parts[isExtLangCode + isScriptCode + 1].match(/^[A-Za-z0-9]{2,3}$/))) {
// country/region codes have to be capitalized
// e.g. cn -> CN, jP -> JP
isCountryCode = 1;
countryCode = parts[isExtLangCode + isScriptCode + 1] = match[0].toUpperCase();
}
// extensions have to be in lowercases
// e.g. U-cA-Buddhist -> u-ca-buddhist, X-LiNux -> x-linux
if (parts.length >= isExtLangCode + isScriptCode + isCountryCode + 2) {
for (n = isExtLangCode + isScriptCode + isCountryCode + 1; n < parts.length; n++) {
parts[n] = parts[n].toLowerCase();
}
}
// enumerate fallback languages
while (parts.length > 0) {
// normalize delimiters as -
// e.g. ja_JP -> ja-JP
result.push(parts.join('-'));
if (isScriptCode &&
isCountryCode &&
parts.length == isExtLangCode + isScriptCode + 2) {
// script code can be omitted to default
// e.g. en-Latn-GB -> en-GB, zh-Hans-CN -> zh-CN
parts.splice(isExtLangCode + isScriptCode, 1);
result.push(parts.join('-'));
parts.splice(isExtLangCode + isScriptCode, 0, scriptCode);
}
if (isExtLangCode &&
isCountryCode &&
parts.length == isExtLangCode + isScriptCode + 2) {
// ext lang code can be omitted to default
// e.g. zh-yue-Hans-CN -> zh-Hans-CN
parts.splice(isExtLangCode, 1);
result.push(parts.join('-'));
parts.splice(isExtLangCode, 0, extLangCode);
}
if (isExtLangCode &&
isScriptCode &&
parts.length == isExtLangCode + isScriptCode + 1) {
// ext lang code can be omitted to default
// e.g. zh-yue-Hans -> zh-Hans
parts.splice(isExtLangCode, 1);
result.push(parts.join('-'));
parts.splice(isExtLangCode, 0, extLangCode);
}
if (!isScriptCode &&
!isExtLangCode &&
isCountryCode &&
parts.length == 2) {
// default script code can be added in certain cases with country codes
// e.g. zh-CN -> zh-Hans-CN, zh-TW -> zh-Hant-TW
switch (result[result.length - 1]) {
case 'zh-CN':
case 'zh-CHS':
result.push('zh-Hans');
break;
case 'zh-TW':
case 'zh-SG':
case 'zh-HK':
case 'zh-CHT':
result.push('zh-Hant');
break;
default:
break;
}
}
parts.pop();
}
}
return result;
}
Polymer({
is: 'i18n-number',
/**
* Fired whenever the formatted text is rendered.
*
* @event rendered
*/
properties: {
/**
* The locale for the formatted number.
* The typical value is bound to `{{effectiveLang}}` when the containing element has
* `BehaviorsStore.I18nBehavior`.
*/
lang: {
type: String,
value: 'en',
observer: '_langChanged',
reflectToAttribute: true
},
/**
* Options object for Intl.NumberFormat
* (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat)
*/
options: {
type: Object,
observer: '_optionsChanged',
notify: true
},
/**
* Raw string synchronized with textContent
*/
raw: {
type: String,
observer: '_rawChanged'
},
/**
* Offset for number
*
* Note: number = rawNumber - offset
*/
offset: {
type: Number,
value: 0,
observer: '_offsetChanged'
},
/**
* Raw number parsed from raw
*/
rawNumber: {
type: Number,
notify: true
},
/**
* Number calculated from rawNumber and offset
*/
number: {
type: Number,
notify: true
},
/**
* Formatted string rendered for UI
*
* Note:
* - While Intl.js Polyfill locale module is being loaded, the value is set as `undefined` until load completion.
*/
formatted: {
type: String,
notify: true
}
},
observers: [
'_onOptionsPropertyChanged(options.*)'
],
/**
* Default locale constant 'en'
*/
DEFAULT_LANG: 'en',
/**
* Start loading Intl polyfill before its registration
*/
beforeRegister: function () {
_setupIntlPolyfill.call(this);
},
ready: function () {
this._setupObservers();
this.raw = this.textNode.data;
if (!this.lang) {
// Polyfill non-functional default value for lang property in Safari 7
this.lang = this.DEFAULT_LANG;
}
},
attached: function () {
this.raw = this.textNode.data;
},
/**
* Set up observers of textContent mutations
*/
_setupObservers: function () {
this.textNode = dom(this).childNodes[0];
if (!this.textNode) {
dom(this).appendChild(document.createTextNode(''));
this.textNode = dom(this).childNodes[0];
}
this.observer = new MutationObserver(this._textMutated.bind(this));
this.observer.observe(this.textNode, { characterData: true });
var desc = Object.getOwnPropertyDescriptor(this, 'lang');
if (desc && typeof desc.set !== 'function') {
// Fix #3. Emulate lang's observer since Safari 7 overrides lang property
this.observer.observe(this, { attributes: true, attributeFilter: [ 'lang' ] });
}
this.nodeObserver = dom(this).observeNodes(function (info) {
if (info.addedNodes[0] &&
info.addedNodes[0].nodeType === info.addedNodes[0].TEXT_NODE) {
this.textNode = info.addedNodes[0];
this.raw = this.textNode.data;
//console.log('i18n-number: text node added with ' + this.raw);
this.observer.observe(this.textNode, { characterData: true });
}
}.bind(this));
},
/**
* MutationObserver callback of the child text node to re-render on text mutations.
*
* @param {Array} mutations Array of MutationRecord (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver).
*/
_textMutated: function (mutations) {
mutations.forEach(function(mutation) {
switch (mutation.type) {
case 'characterData':
//console.log('i18n-number: _textMutated: raw = ' + mutation.target.data);
if (this.raw !== mutation.target.data) {
this.raw = mutation.target.data;
}
break;
case 'attributes':
if (mutation.attributeName === 'lang') {
this._langChanged(this.lang);
}
break;
default:
/* istanbul ignore next: mutation.type is characterData or attributes */
break;
}
}, this);
},
/**
* Observer of `raw` property to re-render the formatted number.
*
* @param {string} raw New raw number string.
*/
_rawChanged: function (raw) {
if (this.textNode) {
if (raw !== this.textNode.data) {
this.textNode.data = raw;
}
//console.log('i18n-number: _rawChanged: raw = ' + raw);
this._render(this.lang, this.options, raw, this.offset);
}
},
/**
* Observer of `lang` property to re-render the formatted number.
*
* @param {string} lang New locale.
*/
_langChanged: function (lang) {
if (!lang) {
this.lang = this.DEFAULT_LANG;
lang = this.lang;
}
if (this.textNode) {
//console.log('i18n-number: _langChanged: lang = ' + lang);
this._render(lang, this.options, this.raw, this.offset);
}
},
/**
* Observer of `options` property to re-render the formatted number.
*
* @param {Object} options New options for Intl.NumberFormat.
*/
_optionsChanged: function (options) {
if (this.textNode) {
//console.log('i18n-number: _optionsChanged: options = ' + JSON.stringify(options));
this._render(this.lang, options, this.raw, this.offset);
}
},
/**
* Observer of `options` sub-properties to re-render the formatted number.
*/
_onOptionsPropertyChanged: function (/* changeRecord */) {
if (this.textNode) {
//console.log('_onOptionsPropertyChanged: path = ' + changeRecord.path + ' value = ' + JSON.stringify(changeRecord.value));
this._render(this.lang, this.options, this.raw, this.offset);
}
},
/**
* Observer of `offset` property to re-render the formatted number.
*
* @param {number} offset New offset.
*/
_offsetChanged: function (offset) {
if (this.textNode) {
//console.log('i18n-number: _offsetChanged: offset = ' + offset);
this._render(this.lang, this.options, this.raw, offset);
}
},
/**
* Formats the number
*
* @param {string} lang Locale for formatting.
* @param {Object} options Options for Intl.NumberFormat.
* @param {number} number Number to format.
* @return {string} Formatted number string.
*/
_formatNumber: function (lang, options, number) {
if (!lang) {
lang = this.DEFAULT_LANG;
}
switch (intlLibraryLoadingStatus) {
case 'loaded':
case 'loading':
default:
try {
if (_setupIntlPolyfillLocale.call(this, lang, function (locale) {
this.effectiveLang = locale;
this._render.call(this, locale, this.options, this.raw, this.offset);
}.bind(this))) {
return new Intl.NumberFormat(lang, options).format(number);
}
else {
// waiting for callback
return undefined;
}
}
catch (e) {
return number.toString();
}
/* istanbul ignore next: unreachable code due to returns in the same case */
break;
case 'native':
// native
try {
return new Intl.NumberFormat(lang, options).format(number);
}
catch (e) {
return number.toString();
}
/* istanbul ignore next: unreachable code due to returns in the same case */
break;
}
},
/**
* Renders the formatted number
*
* @param {string} lang Locale for formatting.
* @param {Object} options Options for Intl.NumberFormat.
* @param {string} raw Raw number string.
* @param {number} offset Offset for number.
*/
_render: function (lang, options, raw, offset) {
// TODO: rendering may be done redundantly on property initializations
raw = raw.trim();
if (!raw && !this.formatted) {
//console.log('i18n-number: skipping _render as raw is null');
return;
}
if (raw) {
this.rawNumber = Number(raw);
this.number = this.rawNumber - offset;
this.formatted = this._formatNumber(lang, options, this.number);
}
else {
this.rawNumber = undefined;
this.number = undefined;
this.formatted = '';
}
this.$.number.textContent = this.formatted ? this.formatted : '';
//console.log('i18n-number: _render ' + this.formatted);
if (typeof this.formatted !== 'undefined') {
this.fire('rendered');
}
},
/**
* Renders the formatted number with the current parameters
*
* Note: (As of Polymer 1.2.3)
* Explicit render() call is needed whenever the observer
* `_onOptionsPropertyChanged(options.*)` is NOT invoked
* after a property of `options` is changed. An explicit call
* `this.notifyPath('options', this.options, true)` can also
* trigger re-rendering.
*
* If the changed property of `options` is bound in an annotation
* like `{{options.currency}}`, the observer `_onOptionsPropertyChanged(options.*)`
* is automatically called whenever the property value is changed
* and thus no explicit call of `render()` or `notifyPath()` is
* required.
*/
render: function () {
this._render(this.lang, this.options, this.raw, this.offset);
}
});
</script>
</dom-module><script>var _cp=[function(e,t){return"other"},function(e,t){return t?"other":1==e?"one":"other"},function(e,t){return t?"other":0==e||1==e?"one":"other"},function(e,t){var r=String(e).split("."),n=!r[1];return t?"other":1==e&&n?"one":"other"}];!function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t:e.plurals=t}(this,{af:_cp[1],ak:_cp[2],am:function(e,t){return t?"other":e>=0&&1>=e?"one":"other"},ar:function(e,t){var r=String(e).split("."),n=Number(r[0])==e,o=n&&r[0].slice(-2);return t?"other":0==e?"zero":1==e?"one":2==e?"two":o>=3&&10>=o?"few":o>=11&&99>=o?"many":"other"},as:function(e,t){return t?1==e||5==e||7==e||8==e||9==e||10==e?"one":2==e||3==e?"two":4==e?"few":6==e?"many":"other":e>=0&&1>=e?"one":"other"},asa:_cp[1],ast:_cp[3],az:function(e,t){var r=String(e).split("."),n=r[0],o=n.slice(-1),c=n.slice(-2),i=n.slice(-3);return t?1==o||2==o||5==o||7==o||8==o||20==c||50==c||70==c||80==c?"one":3==o||4==o||100==i||200==i||300==i||400==i||500==i||600==i||700==i||800==i||900==i?"few":0==n||6==o||40==c||60==c||90==c?"many":"other":1==e?"one":"other"},be:function(e,t){var r=String(e).split("."),n=Number(r[0])==e,o=n&&r[0].slice(-1),c=n&&r[0].slice(-2);return t?2!=o&&3!=o||12==c||13==c?"other":"few":1==o&&11!=c?"one":o>=2&&4>=o&&(12>c||c>14)?"few":n&&0==o||o>=5&&9>=o||c>=11&&14>=c?"many":"other"},bem:_cp[1],bez:_cp[1],bg:_cp[1],bh:_cp[2],bm:_cp[0],bn:function(e,t){return t?1==e||5==e||7==e||8==e||9==e||10==e?"one":2==e||3==e?"two":4==e?"few":6==e?"many":"other":e>=0&&1>=e?"one":"other"},bo:_cp[0],br:function(e,t){var r=String(e).split("."),n=Number(r[0])==e,o=n&&r[0].slice(-1),c=n&&r[0].slice(-2),i=n&&r[0].slice(-6);return t?"other":1==o&&11!=c&&71!=c&&91!=c?"one":2==o&&12!=c&&72!=c&&92!=c?"two":(3==o||4==o||9==o)&&(10>c||c>19)&&(70>c||c>79)&&(90>c||c>99)?"few":0!=e&&n&&0==i?"many":"other"},brx:_cp[1],bs:function(e,t){var r=String(e).split("."),n=r[0],o=r[1]||"",c=!r[1],i=n.slice(-1),u=n.slice(-2),p=o.slice(-1),h=o.slice(-2);return t?"other":c&&1==i&&11!=u||1==p&&11!=h?"one":c&&i>=2&&4>=i&&(12>u||u>14)||p>=2&&4>=p&&(12>h||h>14)?"few":"other"},ca:function(e,t){var r=String(e).split("."),n=!r[1];return t?1==e||3==e?"one":2==e?"two":4==e?"few":"other":1==e&&n?"one":"other"},ce:_cp[1],cgg:_cp[1],chr:_cp[1],ckb:_cp[1],cs:function(e,t){var r=String(e).split("."),n=r[0],o=!r[1];return t?"other":1==e&&o?"one":n>=2&&4>=n&&o?"few":o?"other":"many"},cy:function(e,t){return t?0==e||7==e||8==e||9==e?"zero":1==e?"one":2==e?"two":3==e||4==e?"few":5==e||6==e?"many":"other":0==e?"zero":1==e?"one":2==e?"two":3==e?"few":6==e?"many":"other"},da:function(e,t){var r=String(e).split("."),n=r[0],o=Number(r[0])==e;return t?"other":1!=e&&(o||0!=n&&1!=n)?"other":"one"},de:_cp[3],dsb:function(e,t){var r=String(e).split("."),n=r[0],o=r[1]||"",c=!r[1],i=n.slice(-2),u=o.slice(-2);return t?"other":c&&1==i||1==u?"one":c&&2==i||2==u?"two":c&&(3==i||4==i)||3==u||4==u?"few":"other"},dv:_cp[1],dz:_cp[0],ee:_cp[1],el:_cp[1],en:function(e,t){var r=String(e).split("."),n=!r[1],o=Number(r[0])==e,c=o&&r[0].slice(-1),i=o&&r[0].slice(-2);return t?1==c&&11!=i?"one":2==c&&12!=i?"two":3==c&&13!=i?"few":"other":1==e&&n?"one":"other"},eo:_cp[1],es:_cp[1],et:_cp[3],eu:_cp[1],fa:function(e,t){return t?"other":e>=0&&1>=e?"one":"other"},ff:function(e,t){return t?"other":e>=0&&2>e?"one":"other"},fi:_cp[3],fil:function(e,t){var r=String(e).split("."),n=r[0],o=r[1]||"",c=!r[1],i=n.slice(-1),u=o.slice(-1);return t?1==e?"one":"other":c&&(1==n||2==n||3==n)||c&&4!=i&&6!=i&&9!=i||!c&&4!=u&&6!=u&&9!=u?"one":"other"},fo:_cp[1],fr:function(e,t){return t?1==e?"one":"other":e>=0&&2>e?"one":"other"},fur:_cp[1],fy:_cp[3],ga:function(e,t){var r=String(e).split("."),n=Number(r[0])==e;return t?1==e?"one":"other":1==e?"one":2==e?"two":n&&e>=3&&6>=e?"few":n&&e>=7&&10>=e?"many":"other"},gd:function(e,t){var r=String(e).split("."),n=Number(r[0])==e;return t?"other":1==e||11==e?"one":2==e||12==e?"two":n&&e>=3&&10>=e||n&&e>=13&&19>=e?"few":"other"},gl:_cp[3],gsw:_cp[1],gu:function(e,t){return t?1==e?"one":2==e||3==e?"two":4==e?"few":6==e?"many":"other":e>=0&&1>=e?"one":"other"},guw:_cp[2],gv:function(e,t){var r=String(e).split("."),n=r[0],o=!r[1],c=n.slice(-1),i=n.slice(-2);return t?"other":o&&1==c?"one":o&&2==c?"two":!o||0!=i&&20!=i&&40!=i&&60!=i&&80!=i?o?"other":"many":"few"},ha:_cp[1],haw:_cp[1],he:function(e,t){var r=String(e).split("."),n=r[0],o=!r[1],c=Number(r[0])==e,i=c&&r[0].slice(-1);return t?"other":1==e&&o?"one":2==n&&o?"two":o&&(0>e||e>10)&&c&&0==i?"many":"other"},hi:function(e,t){return t?1==e?"one":2==e||3==e?"two":4==e?"few":6==e?"many":"other":e>=0&&1>=e?"one":"other"},hr:function(e,t){var r=String(e).split("."),n=r[0],o=r[1]||"",c=!r[1],i=n.slice(-1),u=n.slice(-2),p=o.slice(-1),h=o.slice(-2);return t?"other":c&&1==i&&11!=u||1==p&&11!=h?"one":c&&i>=2&&4>=i&&(12>u||u>14)||p>=2&&4>=p&&(12>h||h>14)?"few":"other"},hsb:function(e,t){var r=String(e).split("."),n=r[0],o=r[1]||"",c=!r[1],i=n.slice(-2),u=o.slice(-2);return t?"other":c&&1==i||1==u?"one":c&&2==i||2==u?"two":c&&(3==i||4==i)||3==u||4==u?"few":"other"},hu:function(e,t){return t?1==e||5==e?"one":"other":1==e?"one":"other"},hy:function(e,t){return t?1==e?"one":"other":e>=0&&2>e?"one":"other"},id:_cp[0],ig:_cp[0],ii:_cp[0],"in":_cp[0],is:function(e,t){var r=String(e).split("."),n=r[0],o=Number(r[0])==e,c=n.slice(-1),i=n.slice(-2);return t?"other":o&&1==c&&11!=i||!o?"one":"other"},it:function(e,t){var r=String(e).split("."),n=!r[1];return t?11==e||8==e||80==e||800==e?"many":"other":1==e&&n?"one":"other"},iu:function(e,t){return t?"other":1==e?"one":2==e?"two":"other"},iw:function(e,t){var r=String(e).split("."),n=r[0],o=!r[1],c=Number(r[0])==e,i=c&&r[0].slice(-1);return t?"other":1==e&&o?"one":2==n&&o?"two":o&&(0>e||e>10)&&c&&0==i?"many":"other"},ja:_cp[0],jbo:_cp[0],jgo:_cp[1],ji:_cp[3],jmc:_cp[1],jv:_cp[0],jw:_cp[0],ka:function(e,t){var r=String(e).split("."),n=r[0],o=n.slice(-2);return t?1==n?"one":0==n||o>=2&&20>=o||40==o||60==o||80==o?"many":"other":1==e?"one":"other"},kab:function(e,t){return t?"other":e>=0&&2>e?"one":"other"},kaj:_cp[1],kcg:_cp[1],kde:_cp[0],kea:_cp[0],kk:function(e,t){var r=String(e).split("."),n=Number(r[0])==e,o=n&&r[0].slice(-1);return t?6==o||9==o||n&&0==o&&0!=e?"many":"other":1==e?"one":"other"},kkj:_cp[1],kl:_cp[1],km:_cp[0],kn:function(e,t){return t?"other":e>=0&&1>=e?"one":"other"},ko:_cp[0],ks:_cp[1],ksb:_cp[1],ksh:function(e,t){return t?"other":0==e?"zero":1==e?"one":"other"},ku:_cp[1],kw:function(e,t){return t?"other":1==e?"one":2==e?"two":"other"},ky:_cp[1],lag:function(e,t){var r=String(e).split("."),n=r[0];return t?"other":0==e?"zero":0!=n&&1!=n||0==e?"other":"one"},lb:_cp[1],lg:_cp[1],lkt:_cp[0],ln:_cp[2],lo:function(e,t){return t&&1==e?"one":"other"},lt:function(e,t){var r=String(e).split("."),n=r[1]||"",o=Number(r[0])==e,c=o&&r[0].slice(-1),i=o&&r[0].slice(-2);return t?"other":1==c&&(11>i||i>19)?"one":c>=2&&9>=c&&(11>i||i>19)?"few":0!=n?"many":"other"},lv:function(e,t){var r=String(e).split("."),n=r[1]||"",o=n.length,c=Number(r[0])==e,i=c&&r[0].slice(-1),u=c&&r[0].slice(-2),p=n.slice(-2),h=n.slice(-1);return t?"other":c&&0==i||u>=11&&19>=u||2==o&&p>=11&&19>=p?"zero":1==i&&11!=u||2==o&&1==h&&11!=p||2!=o&&1==h?"one":"other"},mas:_cp[1],mg:_cp[2],mgo:_cp[1],mk:function(e,t){var r=String(e).split("."),n=r[0],o=r[1]||"",c=!r[1],i=n.slice(-1),u=n.slice(-2),p=o.slice(-1);return t?1==i&&11!=u?"one":2==i&&12!=u?"two":7!=i&&8!=i||17==u||18==u?"other":"many":c&&1==i||1==p?"one":"other"},ml:_cp[1],mn:_cp[1],mo:function(e,t){var r=String(e).split("."),n=!r[1],o=Number(r[0])==e,c=o&&r[0].slice(-2);return t?1==e?"one":"other":1==e&&n?"one":!n||0==e||1!=e&&c>=1&&19>=c?"few":"other"},mr:function(e,t){return t?1==e?"one":2==e||3==e?"two":4==e?"few":"other":e>=0&&1>=e?"one":"other"},ms:function(e,t){return t&&1==e?"one":"other"},mt:function(e,t){var r=String(e).split("."),n=Number(r[0])==e,o=n&&r[0].slice(-2);return t?"other":1==e?"one":0==e||o>=2&&10>=o?"few":o>=11&&19>=o?"many":"other"},my:_cp[0],nah:_cp[1],naq:function(e,t){return t?"other":1==e?"one":2==e?"two":"other"},nb:_cp[1],nd:_cp[1],ne:function(e,t){var r=String(e).split("."),n=Number(r[0])==e;return t?n&&e>=1&&4>=e?"one":"other":1==e?"one":"other"},nl:_cp[3],nn:_cp[1],nnh:_cp[1],no:_cp[1],nqo:_cp[0],nr:_cp[1],nso:_cp[2],ny:_cp[1],nyn:_cp[1],om:_cp[1],or:_cp[1],os:_cp[1],pa:_cp[2],pap:_cp[1],pl:function(e,t){var r=String(e).split("."),n=r[0],o=!r[1],c=n.slice(-1),i=n.slice(-2);return t?"other":1==e&&o?"one":o&&c>=2&&4>=c&&(12>i||i>14)?"few":o&&1!=n&&(0==c||1==c)||o&&c>=5&&9>=c||o&&i>=12&&14>=i?"many":"other"},prg:function(e,t){var r=String(e).split("."),n=r[1]||"",o=n.length,c=Number(r[0])==e,i=c&&r[0].slice(-1),u=c&&r[0].slice(-2),p=n.slice(-2),h=n.slice(-1);return t?"other":c&&0==i||u>=11&&19>=u||2==o&&p>=11&&19>=p?"zero":1==i&&11!=u||2==o&&1==h&&11!=p||2!=o&&1==h?"one":"other"},ps:_cp[1],pt:function(e,t){var r=String(e).split("."),n=Number(r[0])==e;return t?"other":n&&e>=0&&2>=e&&2!=e?"one":"other"},"pt-PT":_cp[3],rm:_cp[1],ro:function(e,t){var r=String(e).split("."),n=!r[1],o=Number(r[0])==e,c=o&&r[0].slice(-2);return t?1==e?"one":"other":1==e&&n?"one":!n||0==e||1!=e&&c>=1&&19>=c?"few":"other"},rof:_cp[1],root:_cp[0],ru:function(e,t){var r=String(e).split("."),n=r[0],o=!r[1],c=n.slice(-1),i=n.slice(-2);return t?"other":o&&1==c&&11!=i?"one":o&&c>=2&&4>=c&&(12>i||i>14)?"few":o&&0==c||o&&c>=5&&9>=c||o&&i>=11&&14>=i?"many":"other"},rwk:_cp[1],sah:_cp[0],saq:_cp[1],sdh:_cp[1],se:function(e,t){return t?"other":1==e?"one":2==e?"two":"other"},seh:_cp[1],ses:_cp[0],sg:_cp[0],sh:function(e,t){var r=String(e).split("."),n=r[0],o=r[1]||"",c=!r[1],i=n.slice(-1),u=n.slice(-2),p=o.slice(-1),h=o.slice(-2);return t?"other":c&&1==i&&11!=u||1==p&&11!=h?"one":c&&i>=2&&4>=i&&(12>u||u>14)||p>=2&&4>=p&&(12>h||h>14)?"few":"other"},shi:function(e,t){var r=String(e).split("."),n=Number(r[0])==e;return t?"other":e>=0&&1>=e?"one":n&&e>=2&&10>=e?"few":"other"},si:function(e,t){var r=String(e).split("."),n=r[0],o=r[1]||"";return t?"other":0==e||1==e||0==n&&1==o?"one":"other"},sk:function(e,t){var r=String(e).split("."),n=r[0],o=!r[1];return t?"other":1==e&&o?"one":n>=2&&4>=n&&o?"few":o?"other":"many"},sl:function(e,t){var r=String(e).split("."),n=r[0],o=!r[1],c=n.slice(-2);return t?"other":o&&1==c?"one":o&&2==c?"two":o&&(3==c||4==c)||!o?"few":"other"},sma:function(e,t){return t?"other":1==e?"one":2==e?"two":"other"},smi:function(e,t){return t?"other":1==e?"one":2==e?"two":"other"},smj:function(e,t){return t?"other":1==e?"one":2==e?"two":"other"},smn:function(e,t){return t?"other":1==e?"one":2==e?"two":"other"},sms:function(e,t){return t?"other":1==e?"one":2==e?"two":"other"},sn:_cp[1],so:_cp[1],sq:function(e,t){var r=String(e).split("."),n=Number(r[0])==e,o=n&&r[0].slice(-1),c=n&&r[0].slice(-2);return t?1==e?"one":4==o&&14!=c?"many":"other":1==e?"one":"other"},sr:function(e,t){var r=String(e).split("."),n=r[0],o=r[1]||"",c=!r[1],i=n.slice(-1),u=n.slice(-2),p=o.slice(-1),h=o.slice(-2);return t?"other":c&&1==i&&11!=u||1==p&&11!=h?"one":c&&i>=2&&4>=i&&(12>u||u>14)||p>=2&&4>=p&&(12>h||h>14)?"few":"other"},ss:_cp[1],ssy:_cp[1],st:_cp[1],sv:function(e,t){var r=String(e).split("."),n=!r[1],o=Number(r[0])==e,c=o&&r[0].slice(-1),i=o&&r[0].slice(-2);return t?1!=c&&2!=c||11==i||12==i?"other":"one":1==e&&n?"one":"other"},sw:_cp[3],syr:_cp[1],ta:_cp[1],te:_cp[1],teo:_cp[1],th:_cp[0],ti:_cp[2],tig:_cp[1],tk:_cp[1],tl:function(e,t){var r=String(e).split("."),n=r[0],o=r[1]||"",c=!r[1],i=n.slice(-1),u=o.slice(-1);return t?1==e?"one":"other":c&&(1==n||2==n||3==n)||c&&4!=i&&6!=i&&9!=i||!c&&4!=u&&6!=u&&9!=u?"one":"other"},tn:_cp[1],to:_cp[0],tr:_cp[1],ts:_cp[1],tzm:function(e,t){var r=String(e).split("."),n=Number(r[0])==e;return t?"other":0==e||1==e||n&&e>=11&&99>=e?"one":"other"},ug:_cp[1],uk:function(e,t){var r=String(e).split("."),n=r[0],o=!r[1],c=Number(r[0])==e,i=c&&r[0].slice(-1),u=c&&r[0].slice(-2),p=n.slice(-1),h=n.slice(-2);return t?3==i&&13!=u?"few":"other":o&&1==p&&11!=h?"one":o&&p>=2&&4>=p&&(12>h||h>14)?"few":o&&0==p||o&&p>=5&&9>=p||o&&h>=11&&14>=h?"many":"other"},ur:_cp[3],uz:_cp[1],ve:_cp[1],vi:function(e,t){return t&&1==e?"one":"other"},vo:_cp[1],vun:_cp[1],wa:_cp[2],wae:_cp[1],wo:_cp[0],xh:_cp[1],xog:_cp[1],yi:_cp[3],yo:_cp[0],zh:_cp[0],zu:function(e,t){return t?"other":e>=0&&1>=e?"one":"other"}});</script>
<dom-module id="i18n-format" assetpath="../../../i18n-format/">
<template>
</template>
</dom-module>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
Polymer({
is: 'i18n-format',
/**
* Fired whenever the formatted text is rendered.
*
* @event rendered
*/
properties: {
/**
* The locale for the template text.
* The typical value is bound to `{{effectiveLang}}` when the containing element has
* `BehaviorsStore.I18nBehavior`.
*/
lang: {
type: String,
value: 'en',
reflectToAttribute: true,
observer: '_langChanged'
},
/**
* The parameter attribute name to identify parameters.
* No need to change in a normal usage.
*/
paramAttribute: {
type: String,
value: 'param',
observer: '_paramAttributeChanged'
},
/**
* The parameter format in the template text.
* The `'n'` in the format means n-th parameter.
* No need to change in a normal usage.
*/
paramFormat: {
type: String,
value: '{n}',
observer: '_paramFormatChanged'
},
/**
* When the boolean attribute `observe-params` is specified,
* the template is re-rendered on every parameter mutation.
* If not specified, the template is re-rendered only on `lang` changes and template text changes.
*
* Note: If true, re-rendering may be performed muiltiple times redundantly on a locale change.
*/
observeParams: {
type: Boolean,
value: true // TODO: optimize re-rendering
}
},
/**
* Default locale constant 'en'
*/
DEFAULT_LANG: 'en',
ready: function () {
this._setupParams();
if (!this.lang) {
// Polyfill non-functional default value for lang property in Safari 7
this.lang = this.DEFAULT_LANG;
}
},
attached: function () {
this.render();
},
/**
* Traverse the local DOM and set up parameters and observers.
*/
_setupParams: function () {
var n;
this.elements = Array.prototype.filter.call(
dom(this).childNodes,
function (node) {
return node.nodeType === node.ELEMENT_NODE;
}
);
var needParamObservation = this.observeParams &&
this.elements.length > 0 &&
this.elements[0].tagName.toLowerCase() === 'json-data';
this.observer = new MutationObserver(this._templateMutated.bind(this));
var desc = Object.getOwnPropertyDescriptor(this, 'lang');
if (desc && typeof desc.set !== 'function') {
// Fix #1. Emulate lang's observer since Safari 7 overrides lang property
this.observer.observe(this, { attributes: true, attributeFilter: [ 'lang' ] });
}
for (n = 0; n < this.elements.length; n++) {
if (n === 0) {
this.templateElement = this.elements[n];
this.templateTextNode = dom(this.templateElement).childNodes[0];
this.observer.observe(this.templateTextNode, { characterData: true });
}
else {
if (!this.elements[n].hasAttribute(this.paramAttribute)) {
this.elements[n].setAttribute(this.paramAttribute, '' + n);
}
if (needParamObservation) {
// TODO: childNodes[0] may not be a text node
this.observer.observe(dom(this.elements[n]).childNodes[0], { characterData: true });
if (this.elements[n].tagName.toLowerCase() === 'i18n-number') {
this.listen(this.elements[n], 'rendered', 'render');
}
}
}
}
//console.log('i18n-format: _setupParams: elements = ' + this.elements);
},
/**
* MutationObserver callback of child text nodes to re-render on template text or parameter mutations.
*
* @param {Array} mutations Array of MutationRecord (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver).
*/
_templateMutated: function (mutations) {
mutations.forEach(function(mutation) {
switch (mutation.type) {
case 'characterData':
//console.log('i18n-format: ' + this.id + '._templateMutated(): characterData: tag = ' +
// Polymer.dom(mutation.target).parentNode.tagName.toLowerCase() +
// ' data = ' + mutation.target.data);
if (dom(mutation.target).parentNode.tagName.toLowerCase() !== 'i18n-number') {
this.render();
}
else if (typeof dom(mutation.target).parentNode.formatted !== 'undefined') {
this.render();
}
break;
case 'attributes':
if (mutation.attributeName === 'lang') {
this._langChanged(this.lang);
}
break;
default:
/* istanbul ignore next: mutation.type is always characterData or attributes */
break;
}
}, this);
},
/**
* Observer of `lang` property to re-render the template text.
*
* @param {string} lang New locale.
*/
_langChanged: function (lang /*, oldLang */) {
//console.log('i18n-format: ' + this.id + '._langChanged() lang = ' + lang + ' oldLang = ' + oldLang);
if (this.elements &&
lang !== undefined &&
lang !== null &&
!lang.match(/^{{.*}}$/) &&
!lang.match(/^\[\[.*\]\]$/)) {
this.render();
}
//else {
// console.log('i18n-format: skipping render()');
//}
},
/**
* Observer of `paramFormat` property to re-render the template text.
*
* @param {string} paramFormat New paramFormat.
* @param {string} oldParamFormat Old paramFormat.
*/
_paramFormatChanged: function (paramFormat, oldParamFormat) {
//console.log('i18n-format: ' + this.id + '._paramFormatChanged() new = ' + paramFormat + ' old = ' + oldParamFormat);
if (this.elements &&
oldParamFormat !== undefined &&
paramFormat &&
this.lang !== undefined &&
this.lang !== null &&
!this.lang.match(/^{{.*}}$/) &&
!this.lang.match(/^\[\[.*\]\]$/)) {
this.lastTemplateText = undefined;
this.render();
}
},
/**
* Observer of `paramAttribute` property to reset parameter attributes.
*
* @param {string} paramAttribute New paramAttribute.
* @param {string} oldParamAttribute Old paramAttribute.
*/
_paramAttributeChanged: function (paramAttribute, oldParamAttribute) {
//console.log('i18n-format: ' + this.id + '._paramAttributeChanged() new = ' + paramAttribute + ' old = ' + oldParamAttribute);
var n;
if (this.elements &&
oldParamAttribute !== undefined &&
paramAttribute &&
this.lang !== undefined &&
this.lang !== null &&
!this.lang.match(/^{{.*}}$/) &&
!this.lang.match(/^\[\[.*\]\]$/)) {
for (n = 1; n < this.elements.length; n++) {
this.elements[n].removeAttribute(oldParamAttribute);
if (!this.elements[n].hasAttribute(paramAttribute)) {
this.elements[n].setAttribute(paramAttribute, '' + n);
}
}
this.lastTemplateText = undefined;
this.render();
}
},
/**
* Detect the CLDR plural category of a number
* with [`make-plural` library](https://github.com/eemeli/make-plural.js).
*
* @param {number} n The number to get the plural category for.
* @return {string} Plural category of the number.
*/
_getPluralCategory: function (n) {
var category = 'other';
var lang = this.lang || this.DEFAULT_LANG;
lang = lang.split(/[-_]/)[0];
if (window.plurals[lang]) {
category = window.plurals[lang](n);
}
else {
category = window.plurals.en(n);
}
//console.log('i18n-format: _getPluralCategory(' + n + ') = ' + category);
return category;
},
/**
* Select a template text by parameters.
*
* @return {string} Selected template text.
*/
_selectTemplateText: function () {
var templateText = '';
if (!this.templateElement) {
return templateText;
}
else if (this.templateElement.tagName.toLowerCase() === 'json-data') {
var templateObject;
try {
templateObject = JSON.parse(this.templateTextNode.data);
}
catch (ex) {
if (this.templateTextNode.data) {
console.warn('i18n-format: parse error in json-data');
}
return templateText;
}
var n;
for (n = 1;
typeof templateObject === 'object' && n < this.elements.length;
n++) {
var param = this.elements[n];
if (param.tagName.toLowerCase() === 'i18n-number') {
// plural selector
var category = this._getPluralCategory(param.number);
if (typeof param.number === 'undefined' ||
typeof param.formatted === 'undefined') {
// i18n-number is not ready
//console.log('i18n-format: i18n-number is not ready');
templateObject = undefined;
}
else if (templateObject[param.rawNumber]) {
templateObject = templateObject[param.rawNumber];
}
else if (templateObject[category]) {
// plural category matched
templateObject = templateObject[category];
}
else if (templateObject.other) {
// other
templateObject = templateObject.other;
}
else {
// default
templateObject = '';
console.warn('i18n-format: cannot find a template');
}
}
else {
// string selector
if (templateObject[param.textContent]) {
// template found
templateObject = templateObject[param.textContent];
}
else if (templateObject.other) {
// other
templateObject = templateObject.other;
}
else {
// default
templateObject = '';
console.warn('i18n-format: cannot find a template');
}
}
}
if (typeof templateObject === 'string') {
templateText = templateObject;
}
else if (typeof templateObject === 'undefined') {
templateText = undefined;
}
else {
templateText = '';
console.warn('i18n-format: cannot find a template');
}
}
else {
templateText = this.templateTextNode.data;
}
return templateText;
},
/**
* Render the template text.
*/
render: function () {
var templateText = this._selectTemplateText();
var tmpNode = document.createElement('span');
var paramPlaceholder;
var childNodes = [];
var i;
if (templateText === this.lastTemplateText) {
//console.log('i18n-format: skipping rendering as the templateText has not changed');
return;
}
else if (typeof templateText === 'undefined') {
return;
}
else {
this.lastTemplateText = templateText;
//console.log('i18n-format: ' + this.id + '.render() templateText = ' + templateText);
}
i = 1;
while (i < this.elements.length) {
paramPlaceholder = this.paramFormat.replace('n', i);
templateText = templateText.replace(paramPlaceholder,
'<content select="[' + this.paramAttribute + '=\'' + i + '\']"></content>');
i++;
}
tmpNode.innerHTML = templateText;
dom(this.root).innerHTML = '';
// References of childNodes have to be copied for Shady DOM compatibility
for (i = 0; i < tmpNode.childNodes.length; i++) {
childNodes[i] = tmpNode.childNodes[i];
}
for (i = 0; i < childNodes.length; i++) {
// each node has to be appended via Polymer.dom()
dom(this.root).appendChild(childNodes[i]);
}
this.fire('rendered');
}
});
</script>
<dom-module id="iron-localstorage" assetpath="../../../iron-localstorage/"></dom-module>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { Base } from '@polymer/polymer/polymer-legacy.js';
Polymer({
is: 'iron-localstorage',
properties: {
/**
* localStorage item key
*/
name: {
type: String,
value: ''
},
/**
* The data associated with this storage.
* If set to null item will be deleted.
* @type {*}
*/
value: {
type: Object,
notify: true
},
/**
* If true: do not convert value to JSON on save/load
*/
useRaw: {
type: Boolean,
value: false
},
/**
* Value will not be saved automatically if true. You'll have to do it manually with `save()`
*/
autoSaveDisabled: {
type: Boolean,
value: false
},
/**
* Last error encountered while saving/loading items
*/
errorMessage: {
type: String,
notify: true
},
/** True if value has been loaded */
_loaded: {
type: Boolean,
value: false
}
},
observers: [
'_debounceReload(name,useRaw)',
'_trySaveValue(autoSaveDisabled)',
'_trySaveValue(value.*)'
],
ready: function() {
this._boundHandleStorage = this._handleStorage.bind(this);
},
attached: function() {
window.addEventListener('storage', this._boundHandleStorage);
},
detached: function() {
window.removeEventListener('storage', this._boundHandleStorage);
},
_handleStorage: function(ev) {
if (ev.key == this.name) {
this._load(true);
}
},
_trySaveValue: function() {
if (this._doNotSave) {
return;
}
if (this._loaded && !this.autoSaveDisabled) {
this.debounce('save', this.save);
}
},
_debounceReload: function() {
this.debounce('reload', this.reload);
},
/**
* Loads the value again. Use if you modify
* localStorage using DOM calls, and want to
* keep this element in sync.
*/
reload: function() {
this._loaded = false;
this._load();
},
/**
* loads value from local storage
* @param {boolean=} externalChange true if loading changes from a different window
*/
_load: function(externalChange) {
try {
var v = window.localStorage.getItem(this.name);
} catch (ex) {
this.errorMessage = ex.message;
this._error("Could not save to localStorage. Try enabling cookies for this page.", ex);
};
if (v === null) {
this._loaded = true;
this._doNotSave = true; // guard for save watchers
this.value = null;
this._doNotSave = false;
this.fire('iron-localstorage-load-empty', { externalChange: externalChange});
} else {
if (!this.useRaw) {
try { // parse value as JSON
v = JSON.parse(v);
} catch(x) {
this.errorMessage = "Could not parse local storage value";
Base._error("could not parse local storage value", v);
v = null;
}
}
this._loaded = true;
this._doNotSave = true;
this.value = v;
this._doNotSave = false;
this.fire('iron-localstorage-load', { externalChange: externalChange});
}
},
/**
* Saves the value to localStorage. Call to save if autoSaveDisabled is set.
* If `value` is null or undefined, deletes localStorage.
*/
save: function() {
var v = this.useRaw ? this.value : JSON.stringify(this.value);
try {
if (this.value === null || this.value === undefined) {
window.localStorage.removeItem(this.name);
} else {
window.localStorage.setItem(this.name, /** @type {string} */ (v));
}
}
catch(ex) {
// Happens in Safari incognito mode,
this.errorMessage = ex.message;
Base._error("Could not save to localStorage. Incognito mode may be blocking this action", ex);
}
}
/**
* Fired when value loads from localStorage.
*
* @event iron-localstorage-load
* @param {{externalChange:boolean}} detail -
* externalChange: true if change occured in different window.
*/
/**
* Fired when loaded value does not exist.
* Event handler can be used to initialize default value.
*
* @event iron-localstorage-load-empty
* @param {{externalChange:boolean}} detail -
* externalChange: true if change occured in different window.
*/
});
</script>
<dom-module id="i18n-preference" assetpath="../../">
<template>
<iron-localstorage id="storage" name="i18n-behavior-preference">
</iron-localstorage>
</template>
</dom-module>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
(function(document) {
'use strict';
// html element of this document
var html = document.querySelector('html');
// app global default language
var defaultLang = html.hasAttribute('lang') ? html.getAttribute('lang') : '';
Polymer({
is: 'i18n-preference',
properties: {
/**
* Persistence of preference
*/
persist: {
type: Boolean,
value: false,
reflectToAttribute: true,
notify: true,
observer: '_onPersistChange'
}
},
listeners: {
'storage.iron-localstorage-load-empty': '_onLoadEmptyStorage',
'storage.iron-localstorage-load': '_onLoadStorage',
'storage.value-changed': '_onStorageValueChange'
},
/**
* Ready callback to initialize this.lang
*/
ready: function () {
if (this.persist) {
// delay this.lang update
}
else {
//this.$.storage.value = undefined;
}
this.isReady = true;
},
/**
* Attached callback to initialize html.lang and its observation
*/
attached: function () {
this._observe();
if (this.persist) {
// delay html.lang update
}
else {
if (!html.hasAttribute('preferred')) {
html.setAttribute('lang', navigator.language || navigator.browserLanguage);
}
}
},
/**
* Detached callback to diconnect html.lang observation
*/
detached: function () {
this._disconnect();
},
/**
* Initialize an empty localstorage
*/
_onLoadEmptyStorage: function () {
if (this.isReady) {
if (this.persist) {
if (this.isInitialized) {
// store html.lang value
this.$.storage.value = html.getAttribute('lang');
}
else {
if (html.hasAttribute('preferred')) {
this.$.storage.value = html.getAttribute('lang');
}
else {
this.$.storage.value = navigator.language || navigator.browserLanguage;
if (html.getAttribute('lang') !== this.$.storage.value) {
html.setAttribute('lang', this.$.storage.value);
}
}
this.isInitialized = true;
}
}
else {
// leave the empty storage as it is
}
}
},
/**
* Handle the loaded storage value
*/
_onLoadStorage: function () {
if (this.isReady) {
if (this.persist) {
// preferred attribute in html to put higher priority
// in the default html language than navigator.language
if (html.hasAttribute('preferred')) {
if (this.$.storage.value !== defaultLang) {
// overwrite the storage by the app default language
this.$.storage.value = defaultLang;
}
}
else {
// load the value from the storage
html.setAttribute('lang', this.$.storage.value);
}
}
else {
// empty the storage
this.$.storage.value = undefined;
}
}
},
/**
* Handle persist changes
*
* @param {Boolean} value new this.persist value
*/
_onPersistChange: function (value) {
if (this.isReady) {
if (value) {
if (this.$.storage.value !== html.getAttribute('lang')) {
// save to the storage
this.$.storage.value = html.getAttribute('lang');
}
}
else {
// empty the storage
this.$.storage.value = undefined;
}
}
},
/**
* Handle storage value changes
*
* @param {Event} e value-changed event on the storage
*/
_onStorageValueChange: function (e) {
var value = e.detail.value;
if (this.isReady) {
if (this.persist) {
if (value) {
if (value !== html.getAttribute('lang')) {
// save to the lang
html.setAttribute('lang', value);
}
}
else {
// update the storage
this.$.storage.value = html.getAttribute('lang');
}
}
else {
if (value) {
// empty the storage
this.$.storage.value = undefined;
}
}
}
},
/**
* Handle value changes on localstorage
*
* @param {MutationRecord[]} mutations Array of MutationRecords for html.lang
*
* Note:
* - Bound to this element
*/
_htmlLangMutationObserverCallback: function (mutations) {
mutations.forEach(function(mutation) {
switch (mutation.type) {
case 'attributes':
if (mutation.attributeName === 'lang') {
if (this.$.storage.value !== mutation.target.getAttribute('lang')) {
this.$.storage.value = mutation.target.getAttribute('lang');
}
}
break;
default:
break;
}
}.bind(this));
},
/**
* Set up html.lang mutation observer
*/
_observe: function () {
// observe html lang mutations
if (!this._htmlLangMutationObserver) {
this._htmlLangMutationObserverCallbackBindThis =
this._htmlLangMutationObserverCallback.bind(this);
this._htmlLangMutationObserver =
new MutationObserver(this._htmlLangMutationObserverCallbackBindThis);
}
this._htmlLangMutationObserver.observe(html, { attributes: true });
},
/**
* Disconnect html.lang mutation observer
*/
_disconnect: function () {
if (this._htmlLangMutationObserver) {
this._htmlLangMutationObserver.disconnect();
}
}
});
})(document);
</script>
<dom-module id="i18n-attr-repo" assetpath="../../">
<template>
<template id="standard">
<input placeholder="" value="type=button|submit">
<any-elements title="" aria-label="$" aria-valuetext="$"></any-elements>
<paper-input label="" error-message="" placeholder=""></paper-input>
<paper-textarea label="" error-message="" placeholder=""></paper-textarea>
<paper-dropdown-menu label=""></paper-dropdown-menu>
<paper-toast text=""></paper-toast>
<paper-badge label=""></paper-badge>
<google-chart options="" cols="" rows="" data=""></google-chart>
<google-signin label-signin="" label-signout="" label-additional=""></google-signin>
<platinum-push-messaging title="" message=""></platinum-push-messaging>
<json-data any-attributes=""></json-data>
</template>
</template>
</dom-module>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
// shared data
var sharedData = {};
Polymer({
is: 'i18n-attr-repo',
ready: function () {
this.data = sharedData;
var customAttributes = dom(this).querySelector('template#custom');
// traverse custom attributes repository
if (customAttributes) {
this._traverseTemplateTree(customAttributes._content || customAttributes.content);
}
if (this.data.__ready__) {
return; // traverse standard attributes only once
}
this.data.__ready__ = true;
this._traverseTemplateTree(this.$.standard._content || this.$.standard.content);
},
/**
* Judge if a specific attribute of an element requires localization.
*
* @param {HTMLElement} element Target element.
* @param {string} attr Target attribute name.
* @return {string or boolean} true - property, '$' - attribute, false - not targeted, 'type-name' - type name
*/
isLocalizableAttribute: function (element, attr) {
var tagName = element.tagName.toLowerCase();
attr = attr.replace(/\$$/, '');
if (this.data['any-elements'] &&
this.data['any-elements'][attr]) {
return this.data['any-elements'][attr];
}
else if (this.data[tagName]) {
return this.data[tagName]['any-attributes'] ||
this._getType(element, this.data[tagName][attr]);
}
else {
return false;
}
},
/**
* Get the type name or '$' for a specific attribute of an element from the attributes repository
*
* @param {HTMLElement} element Target element.
* @param {object} value this.data[tagName][attr]
* @return {string or boolean} true - property, '$' - attribute, false - not targeted, 'type-name' - type name
*/
_getType: function (element, value) {
var selector;
var result;
if (typeof value === 'object') {
for (selector in value) {
if (selector) {
if (this._matchAttribute(element, selector)) {
result = this._getType(element, value[selector]);
if (result) {
return result;
}
}
}
}
if (value['']) {
if (this._matchAttribute(element, '')) {
result = this._getType(element, value['']);
if (result) {
return result;
}
}
}
return false;
}
else {
return value;
}
},
/**
* Get the type name or '$' for a specific attribute of an element from the attributes repository
*
* Format for selectors:
* - `attr=value` - Value of `attr` matches Regex `^value$`
* - `!boolean-attr` - Boolean attribute does not exist
* - `boolean-attr` - Boolean attribute exists with empty value
* - empty string `''` - Always matches
*
* @param {HTMLElement} element Target element.
* @param {string} selector Matching condition for target attribute.
* @return {boolean} true - matching, false - not matching
*/
_matchAttribute: function (element, selector) {
var value;
var match;
// default ''
if (selector === '') {
return true;
}
// attr=value Regex ^value$
match = selector.match(/^([^!=]*)=(.*)$/);
if (match) {
if (element.hasAttribute(match[1])) {
value = element.getAttribute(match[1]);
return !!value.match(new RegExp('^' + match[2] + '$'));
}
else {
return false;
}
}
// !boolean-attr
match = selector.match(/^!([^!=]*)$/);
if (match) {
return !element.hasAttribute(match[1]);
}
// boolean-attr or empty-attr
match = selector.match(/^([^!=]*)$/);
if (match) {
if (element.hasAttribute(match[1])) {
value = element.getAttribute(match[1]);
return !value;
}
else {
return false;
}
}
// no matching
return false;
},
/**
* Comparator for attribute selectors
*
* @param {string} s1 selector 1
* @param {string} s2 selector 2
* @return {number} comparison result as -1, 0, or 1
*/
_compareSelectors: function (s1, s2) {
var name1 = s1.replace(/^!/, '').replace(/=.*$/, '').toLowerCase();
var name2 = s2.replace(/^!/, '').replace(/=.*$/, '').toLowerCase();
return name1.localeCompare(name2);
},
/**
* Add a new localizable attribute of an element to the repository.
*
* Format for selector values for defining I18N-target attributes:
* - `attr1=value1,attr2=value2,boolean-attr,!boolean-attr` - Attribute value matching condition for property
* - `attr1=value1,attr2=value2,$` - Attribute value matching condition for attribute
* - `boolean-attr=` - Boolean attribute condition
* - `attr1=value1,type` - Attribute value condition with type name (type is currently ineffective)
*
* @param {string} element Target element name.
* @param {string} attr Target attribute name.
* @param {?*} value Selector value
*/
setLocalizableAttribute: function (element, attr, value) {
this.data[element] = this.data[element] || {};
var cursor = this.data[element];
var prev = attr;
var type = true;
var selectors = [];
if (typeof value === 'string' && value) {
selectors = value.split(',');
if (selectors[selectors.length - 1].match(/^[^!=][^=]*$/)) {
type = selectors.pop();
}
selectors = selectors.map(function (selector) {
return selector.replace(/=$/, '');
});
selectors.sort(this._compareSelectors);
while (selectors[0] === '') {
selectors.shift();
}
}
selectors.forEach(function (selector, index) {
if (typeof cursor[prev] !== 'object') {
cursor[prev] = cursor[prev] ? { '': cursor[prev] } : {};
}
cursor[prev][selector] = cursor[prev][selector] || {};
cursor = cursor[prev];
prev = selector;
});
if (typeof cursor[prev] === 'object' &&
cursor[prev] &&
Object.keys(cursor[prev]).length) {
cursor = cursor[prev];
prev = '';
}
cursor[prev] = type;
},
/**
* Pick up localizable attributes description for a custom element
* from `text-attr` attribute and register them to the repository.
* The `text-attr` attribute is used in the template of a custom
* element to declare localizable attributes of its own element.
*
* Format:
*
* Type 1: `<template text-attr="localizable-attr1 attr2">`
*
* Type 2: `<template text-attr localizable-attr1 attr2="value2">`
*
* @param {string} element Target element name.
* @param {HTMLTemplateElement} template Template of the element.
*/
registerLocalizableAttributes: function (element, template) {
if (!element) {
element = template.getAttribute('id');
}
if (element) {
var attrs = (template.getAttribute('text-attr') || '').split(' ');
var textAttr = false;
attrs.forEach(function (attr) {
if (attr) {
this.setLocalizableAttribute(element, attr, true);
}
}, this);
Array.prototype.forEach.call(template.attributes, function (attr) {
switch (attr.name) {
case 'id':
case 'lang':
case 'localizable-text':
case 'assetpath':
break;
case 'text-attr':
textAttr = true;
break;
default:
if (textAttr) {
this.setLocalizableAttribute(element, attr.name, attr.value);
}
break;
}
}.bind(this));
}
},
/**
* Traverse the template of `i18n-attr-repo` in the ready() callback
* and construct the localizable attributes repository object. The method calls itself
* recursively for traversal.
*
* @param {HTMLElement} node The target HTML node for traversing.
*/
_traverseTemplateTree: function (node) {
var name;
if (node.nodeType === node.ELEMENT_NODE) {
name = node.nodeName.toLowerCase();
Array.prototype.forEach.call(node.attributes, function (attribute) {
this.data[name] = this.data[name] || {};
this.setLocalizableAttribute(name, attribute.name, attribute.value);
}, this);
}
if (node.childNodes.length > 0) {
for (var i = 0; i < node.childNodes.length; i++) {
this._traverseTemplateTree(node.childNodes[i]);
}
}
}
});
</script><script>/*!
* @license deepcopy.js Copyright(c) 2013 sasa+1
* https://github.com/sasaplus1/deepcopy.js
* Released under the MIT license.
*/
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.deepcopy=e():t.deepcopy=e()}(this,function(){return function(t){function e(o){if(n[o])return n[o].exports;var r=n[o]={exports:{},id:o,loaded:!1};return t[o].call(r.exports,r,r.exports,e),r.loaded=!0,r.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){"use strict";t.exports=n(3)},function(t,e){"use strict";function n(t,e){if("[object Array]"!==o.call(t))throw new TypeError("array must be an Array");var n=void 0,r=void 0,u=void 0;for(n=0,r=t.length;r>n;++n)if(u=t[n],u===e||u!==u&&e!==e)return n;return-1}e.__esModule=!0;var o=Object.prototype.toString,r="undefined"!=typeof Buffer?function(t){return Buffer.isBuffer(t)}:function(){return!1},u="function"==typeof Object.keys?function(t){return Object.keys(t)}:function(t){var e=typeof t;if(null===t||"function"!==e&&"object"!==e)throw new TypeError("obj must be an Object");var n=[],o=void 0;for(o in t)Object.prototype.hasOwnProperty.call(t,o)&&n.push(o);return n},i="function"==typeof Symbol?function(t){return Object.getOwnPropertySymbols(t)}:function(){return[]};e.getKeys=u,e.getSymbols=i,e.indexOf=n,e.isBuffer=r},function(t,e,n){"use strict";function o(t,e){var n=u(t);return null!==n?n:r(t,e)}function r(t,e){if("function"!=typeof e)throw new TypeError("customizer is must be a Function");if("function"==typeof t){var n=String(t);return/^\s*function\s*\S*\([^\)]*\)\s*{\s*\[native code\]\s*}/.test(n)?t:new Function("return "+String(n))()}var o=c.call(t);if("[object Array]"===o)return[];if("[object Object]"===o&&t.constructor===Object)return{};if("[object Date]"===o)return new Date(t.getTime());if("[object RegExp]"===o){var r=String(t),u=r.lastIndexOf("/");return new RegExp(r.slice(1,u),r.slice(u+1))}if((0,i.isBuffer)(t)){var f=new Buffer(t.length);return t.copy(f),f}var l=e(t);return void 0!==l?l:null}function u(t){var e=typeof t;return null!==t&&"object"!==e&&"function"!==e?t:null}e.__esModule=!0,e.copyValue=e.copyCollection=e.copy=void 0;var i=n(1),c=Object.prototype.toString;e.copy=o,e.copyCollection=r,e.copyValue=u},function(t,e,n){"use strict";function o(t){}function r(t){var e=arguments.length<=1||void 0===arguments[1]?o:arguments[1];if(null===t)return null;var n=(0,i.copyValue)(t);if(null!==n)return n;var r=(0,i.copyCollection)(t,e),c=null!==r?r:t,f=[t],l=[c];return u(t,e,c,f,l)}function u(t,e,n,o,r){if(null===t)return null;var f=(0,i.copyValue)(t);if(null!==f)return f;var l=(0,c.getKeys)(t).concat((0,c.getSymbols)(t)),p=void 0,s=void 0,a=void 0,y=void 0,d=void 0,v=void 0,b=void 0,j=void 0;for(p=0,s=l.length;s>p;++p)a=l[p],y=t[a],d=(0,c.indexOf)(o,y),v=void 0,b=void 0,j=void 0,-1===d?(v=(0,i.copy)(y,e),b=null!==v?v:y,null!==y&&/^(?:function|object)$/.test(typeof y)&&(o.push(y),r.push(b))):j=r[d],n[a]=j||u(y,e,b,o,r);return n}e.__esModule=!0;var i=n(2),c=n(1);e["default"]=r,t.exports=e["default"]}])});</script><script type="module">
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
import { Base } from '@polymer/polymer/polymer-legacy.js';
import { DomModule } from '@polymer/polymer/lib/elements/dom-module.js';
import { Polymer as Polymer$0 } from '@polymer/polymer/lib/legacy/polymer-fn.js';
/* jshint -W100 */
(function(document) {
'use strict';
var html = document.querySelector('html');
if (window.ShadowDOMPolyfill) {
// Fix #38. Add reflectToAttribute effect on html.lang property
// for supplementing Shadow DOM MutationObserver polyfill
Object.defineProperty(html, 'lang', {
get: function () {
return this.getAttribute('lang');
},
set: function (value) {
this.setAttribute('lang', value);
}
});
}
// Safari 7 predefines non-configurable standard properties
// Note: They become configurable with ShadowDOMPolyfill, which wraps them.
var isStandardPropertyConfigurable = (function () {
var langPropertyDescriptor = Object.getOwnPropertyDescriptor(document.createElement('span'), 'lang');
return !langPropertyDescriptor || langPropertyDescriptor.configurable;
})();
// Polymer 1.4.0 on Safari 7 inserts extra unexpected whitepace node at the beginning of template
var extraWhiteSpaceNode = !isStandardPropertyConfigurable;
// app global bundle storage
var bundles = { '': {} }; // with an empty default bundle
// app global default language
var defaultLang = html.hasAttribute('lang') ? html.getAttribute('lang') : '';
// shared fetching instances for bundles
var bundleFetchingInstances = {};
// path for start URL
var startUrl = (function () {
var path = window.location.pathname;
if (document.querySelector('meta[name=app-root]') &&
document.querySelector('meta[name=app-root]').getAttribute('content')) {
// <meta name="app-root" content="/"> to customize application root
path = document.querySelector('meta[name=app-root]').getAttribute('content');
}
else if (document.querySelector('link[rel=manifest]') &&
document.querySelector('link[rel=manifest]').getAttribute('href') &&
document.querySelector('link[rel=manifest]').getAttribute('href').match(/^\//)) {
// assume manifest is located at the application root folder
path = document.querySelector('link[rel=manifest]').getAttribute('href');
}
return path.replace(/\/[^\/]*$/,'/');
})();
// path for locales from <html locales-path="locales">
var localesPath = html.hasAttribute('locales-path') ?
html.getAttribute('locales-path') : 'locales';
var attributesRepository = document.createElement('i18n-attr-repo');
// set up userPreference
var userPreference = document.querySelector('i18n-preference');
if (!userPreference) {
userPreference = document.createElement('i18n-preference');
// append to body
document.querySelector('body').appendChild(userPreference);
}
// debug log when <html debug> attribute exists
var debuglog = html.hasAttribute('debug') ?
function (arg) {
console.log(arg);
} :
function () {};
window.BehaviorsStore = window.BehaviorsStore || {};
/**
* Apply `BehaviorsStore.I18nControllerBehavior` to manipulate internal variables for I18N
*
* Note: This behavior is not for normal custom elements to apply I18N. UI is not expected.
*/
BehaviorsStore.I18nControllerBehavior = {
properties: {
/**
* Flag for detection of `I18nControllerBehavior`
*
* `true` if I18nControllerBehavior is applied
*
* Note: Module-specific JSON resources are NOT fetched for `I18nControllerBehavior`
*/
isI18nController: {
type: Boolean,
value: true,
readOnly: true
},
/**
* HTML element object for the current document
*/
html: {
type: Object,
value: html
},
/**
* Master bundles object for storing all the localized and default resources
*/
masterBundles: {
type: Object,
value: bundles
},
/**
* Default lang for the document, i.e., the initial value of `<html lang>` attribute
*/
defaultLang: {
type: String,
value: defaultLang,
readOnly: true
},
/**
* List of elements which are fetching bundles
*/
bundleFetchingInstances: {
type: Object,
value: bundleFetchingInstances
},
/**
* Root URL path of the application ends with '/' to fetch bundles
*/
startUrl: {
type: String,
value: startUrl,
readOnly: true
},
/**
* Path for locales
*
* Default value is `'locales'`
*/
localesPath: {
type: String,
value: localesPath,
readOnly: true
},
/**
* <i18n-attr-repo> element to store attributes repository
*/
attributesRepository: {
type: Object,
value: attributesRepository,
readOnly: true
},
/**
* <i18n-preference> element
*/
userPreference: {
type: Object,
value: userPreference,
readOnly: true
}
}
};
/**
* Apply `BehaviorsStore.I18nBehavior` to implement localizable elements.
*
* <dom-module id="custom-element">
* <template>
* <span>Hard-coded UI texts are automatically made localizable</span>
* </template>
* <script>
* Polymer({
* is: 'custom-element',
* behaviors: [
* BehaviorsStore.I18nBehavior // Add this behavior
* ]
* });
* </script>
* </dom-module>
*
* `I18nBehavior` automatically extracts UI texts from `template` and
* binds them to localizable variables in `this.text` object.
*
* According to the `lang` attribute value, `this.text`, and thus the bound UI texts,
* dynamically mutates by loading localized values from a JSON file in the `locales` directory.
* By default, `lang` attribute values of all the localizable elements with `I18nBehavior` are
* automatically updated according to `<html lang>` attribute value.
*
* The UI text externalization can be processed at build time as well by `gulp-*` task
* so that `I18nBehavior` can immediately recognize the extracted texts in JSON and
* skip run-time externalization.
*
* Run-time externalization is suitable for development and debugging
* since the code changes are immediately reflected at reloading without build-time preprocesses.
* In contrast, build-time externalization is suitable for production builds
* since it eliminates run-time externalization overheads.
*
* ### Steps to localize a custom element
*
* 1. [JavaScript] Add `BehaviorsStore.I18nBehavior` to `behaviors`
* 1. [gulp] Add `gulp-*` filter for `custom-element.html` and generate `custom-element.json`
* 1. [locales] Put `custom-element.lang.json` in `locales` directory
* 1. [translation] Translate `locales/custom-element.lang.json`
*
* - - -
*
* ### Directory structure of bundle files
*
* Normal bundles (`/element-root/locales/element-name.*.json`) for elements
* are stored under their root directories.
*
* Shared bundles (`/locales/bundle.*.json`) are generated at build time
* by merging all the targeted bundles of the localizable elements.
*
* Once the shared bundles are loaded, there should be no need to search for
* normal bundles per element unless the element is intentionally excluded
* from the shared bundles.
*
* ```
* /bundle.json
* /locales/bundle.ja.json
* /bundle.fr.json
* /bundle.zh-Hans.json
*
* /elements/my-list/my-list.json
* /locales/my-list.ja.json
* /my-list.zh-Hans.json
*
* /google-chart-demo/google-chart-demo.json
* /locales/google-chart-demo.ja.json
* /google-chart-demo.fr.json
* ```
*
* - - -
*
* ### Localizable `<template is="i18n-dom-bind" id="app">` element
*
* `<template is="i18n-dom-bind">` template element extends
* `<template is="dom-bind">` template element with all the capabilities of
* `I18nBehavior`.
*
* The `id` attribute value is used for naming bundle files instead of the element name.
*
* The bundle files are stored at the locales directory under the application root.
*
* ```
* /app.json
* /locales/app.ja.json
* /app.fr.json
* /app.zh-Hans.json
* ```
*
* - - -
*
* ### TODOs
*
* - Support user locale preference per user
*
* @polymerBehavior BehaviorsStore.I18nBehavior
* @group I18nBehavior
* @hero hero.svg
* @demo demo/index.html
*/
BehaviorsStore.I18nBehavior = {
/**
* Fired when the text message bundle object (`this.text`) is updated after `this.lang` is changed.
*
* @event lang-updated
*/
/**
* Fired when a shared bundle is fetched.
*
* @event bundle-fetched
*/
properties: {
/**
* The locale of the element.
* The default value is copied from `<html lang>` attribute of the current page.
* If `<html lang>` is not specified, `''` is set to use the template default language.
*
* The value is synchronized with `<html lang>` attribute of the current page by default.
*
* ### Note:
* - The value may not reflect the current UI locale until the localized texts are loaded.
*/
lang: {
type: String,
value: defaultLang,
reflectToAttribute: true,
observer: '_langChanged'
},
/**
* Text message bundle object for the current locale.
* The object is shared among all the instances of the same element.
* The value is updated when `lang-updated` event is fired.
*/
text: {
type: Object,
computed: '_getBundle(lang)'
},
/**
* Data model bundle object for the current locale.
* The data are bound to localizable attribute values in the element template.
* The object is cloned from `this.text.model` per instance.
* The value is NOT automatically updated in sync with `this.text`.
*
* How to manually update the model object when `lang-updated` event is fired:
* ```
* this.model = deepcopy(this.text.model);
* ```
*/
model: {
type: Object,
notify: true
},
/**
* The locale of the hard-coded texts in the element's template.
* The read-only value can be specified by the `lang` attribute of the element's `template`.
* The default value is 'en' if not specified in the `template` element.
*
* ```
* <dom-module id="custom-element">
* <template lang="en">
* <span>Hard-coded text in English</span>
* </template>
* <dom-module>
* ```
*/
templateDefaultLang: {
type: String,
value: 'en'
},
/**
* The effective locale of the element.
* The value is updated when the localized texts are loaded and `lang-updated` event is fired.
*/
effectiveLang: {
type: String
},
/**
* Boolean flag to synchronize with the value of `<html lang>` attribute.
*/
observeHtmlLang: {
type: Boolean,
value: true,
observer: '_observeHtmlLangChanged'
}
},
listeners: {
'lang-updated': '_updateEffectiveLang'
},
/*
bundles =
{
"": {},
"en": {
"my-list": {
"p_2": "You now have:",
"model": {
"list": {
"items": [
"item 1", "item 2"
]
}
}
},
"google-chart-demo": {
"simple-chart-desc": [
"template {1} string", "param 1"
]
"model": {
"simple-chart": {
"options": { "title": "Simple Chart" },
"rows": []
}
}
}
},
"ja": {
"my-list": {},
"google-chart-demo": {}
}
}
bundles[lang]
/bundle.json - fallback
/locales/bundle.en.json
/bundle.ja.json
/bundle.fr.json
/bundle.zh-Hans.json
bundles[lang][is]
/elements/my-list/my-list.json - fallback
/locales/my-list.en.json
/my-list.ja.json
/my-list.zh-Hans.json
/google-chart-demo/google-chart-demo.json - fallback
/locales/google-chart-demo.en.json
/google-chart-demo.ja.json
/google-chart-demo.zh-Hans.json
app/elements/my-list/my-list.json
/locales/my-list.fr.json
/my-list.ja.json
/my-list.zh-Hans.json
dist/elements/my-list/my-list.json
/locales/my-list.fr.json
/my-list.ja.json
/my-list.zh-Hans.json
*/
/**
* The backend logic for `this.text` object.
*
* @param {string} lang Locale for the text message bundle.
* @return {Object} Text message bundle for the locale.
*/
_getBundle: function (lang) {
//console.log('_getBundle called for ' + this.is + ' with lang = ' + lang);
var resolved;
var id = this.is === 'i18n-dom-bind' ? this.id : this.is;
if (lang && lang.length > 0) {
var fallbackLanguageList = this._enumerateFallbackLanguages(lang);
var tryLang;
while ((tryLang = fallbackLanguageList.shift())) {
if (!bundles[tryLang]) {
// set up an empty bundle for the language if missing
bundles[tryLang] = {};
}
if (bundles[tryLang][id]) {
// bundle found
resolved = bundles[tryLang][id];
break;
}
}
}
else {
// lang is not specified
lang = '';
resolved = bundles[lang][id];
}
// Fallback priorities: last > app default > element default > fallback > {}
// TODO: need more research on fallback priorities
if (!resolved) {
if (bundles[this._fetchStatus.lastLang] && bundles[this._fetchStatus.lastLang][id]) {
// old bundle for now (no changes should be shown)
resolved = bundles[this._fetchStatus.lastLang][id];
}
else if (defaultLang && defaultLang.length > 0 &&
bundles[defaultLang] && bundles[defaultLang][id]) {
// app default language for now
resolved = bundles[defaultLang][id];
}
else if (this.templateDefaultLang && this.templateDefaultLang.length > 0 &&
bundles[this.templateDefaultLang] && bundles[this.templateDefaultLang][id]) {
// element default language for now
resolved = bundles[this.templateDefaultLang][id];
}
/* no more fallback should happen */
/* istanbul ignore else */
else if (bundles[''][id]) {
// fallback language for now (this should be the same as element default)
resolved = bundles[''][id];
}
else {
// give up providing a bundle (this should not happen)
resolved = {};
}
}
return resolved;
},
/**
* Enumerate fallback locales for the target locale.
*
* Subset implementation of BCP47 (https://tools.ietf.org/html/bcp47).
*
* ### Examples:
*
*| Target Locale | Fallback 1 | Fallback 2 | Fallback 3 |
*|:--------------|:-----------|:-----------|:-----------|
*| ru | N/A | N/A | N/A |
*| en-GB | en | N/A | N/A |
*| en-Latn-GB | en-GB | en-Latn | en |
*| fr-CA | fr | N/A | N/A |
*| zh-Hans-CN | zh-Hans | zh | N/A |
*| zh-CN | zh-Hans | zh | N/A |
*| zh-TW | zh-Hant | zh | N/A |
*
* #### Note:
*
* For zh language, the script Hans or Hant is supplied as its default script when a country/region code is supplied.
*
* @param {string} lang Target locale.
* @return {Array} List of fallback locales including the target locale at the index 0.
*/
_enumerateFallbackLanguages: function (lang) {
var result = [];
var parts;
var match;
var isExtLangCode = 0;
var extLangCode;
var isScriptCode = 0;
var scriptCode;
var isCountryCode = 0;
var countryCode;
var n;
if (!lang || lang.length === 0) {
result.push('');
}
else {
parts = lang.split(/[-_]/);
// normalize ISO-639-1 language codes
if (parts.length > 0 &&
parts[0].match(/^[A-Za-z]{2,3}$/)) {
// language codes have to be lowercased
// e.g. JA -> ja, FR -> fr
// TODO: normalize 3-letter codes to 2-letter codes
parts[0] = parts[0].toLowerCase();
}
// normalize ISO-639-3 extension language codes
if (parts.length >= 2 &&
parts[1].match(/^[A-Za-z]{3}$/) &&
!parts[1].match(/^[Cc][Hh][SsTt]$/)) { // exclude CHS,CHT
// extension language codes have to be lowercased
// e.g. YUE -> yue
isExtLangCode = 1;
extLangCode = parts[1] = parts[1].toLowerCase();
}
// normalize ISO-15924 script codes
if (parts.length >= isExtLangCode + 2 &&
(match = parts[isExtLangCode + 1].match(/^([A-Za-z])([A-Za-z]{3})$/))) {
// script codes have to be capitalized only at the first character
// e.g. HANs -> Hans, lAtN -> Latn
isScriptCode = 1;
scriptCode = parts[isExtLangCode + 1] = match[1].toUpperCase() + match[2].toLowerCase();
}
// normalize ISO-3166-1 country/region codes
if (parts.length >= isExtLangCode + isScriptCode + 2 &&
(match = parts[isExtLangCode + isScriptCode + 1].match(/^[A-Za-z0-9]{2,3}$/))) {
// country/region codes have to be capitalized
// e.g. cn -> CN, jP -> JP
isCountryCode = 1;
countryCode = parts[isExtLangCode + isScriptCode + 1] = match[0].toUpperCase();
}
// extensions have to be in lowercases
// e.g. U-cA-Buddhist -> u-ca-buddhist, X-LiNux -> x-linux
if (parts.length >= isExtLangCode + isScriptCode + isCountryCode + 2) {
for (n = isExtLangCode + isScriptCode + isCountryCode + 1; n < parts.length; n++) {
parts[n] = parts[n].toLowerCase();
}
}
// enumerate fallback languages
while (parts.length > 0) {
// normalize delimiters as -
// e.g. ja_JP -> ja-JP
result.push(parts.join('-'));
if (isScriptCode &&
isCountryCode &&
parts.length == isExtLangCode + isScriptCode + 2) {
// script code can be omitted to default
// e.g. en-Latn-GB -> en-GB, zh-Hans-CN -> zh-CN
parts.splice(isExtLangCode + isScriptCode, 1);
result.push(parts.join('-'));
parts.splice(isExtLangCode + isScriptCode, 0, scriptCode);
}
if (isExtLangCode &&
isCountryCode &&
parts.length == isExtLangCode + isScriptCode + 2) {
// ext lang code can be omitted to default
// e.g. zh-yue-Hans-CN -> zh-Hans-CN
parts.splice(isExtLangCode, 1);
result.push(parts.join('-'));
parts.splice(isExtLangCode, 0, extLangCode);
}
if (isExtLangCode &&
isScriptCode &&
parts.length == isExtLangCode + isScriptCode + 1) {
// ext lang code can be omitted to default
// e.g. zh-yue-Hans -> zh-Hans
parts.splice(isExtLangCode, 1);
result.push(parts.join('-'));
parts.splice(isExtLangCode, 0, extLangCode);
}
if (!isScriptCode &&
!isExtLangCode &&
isCountryCode &&
parts.length == 2) {
// default script code can be added in certain cases with country codes
// e.g. zh-CN -> zh-Hans-CN, zh-TW -> zh-Hant-TW
switch (result[result.length - 1]) {
case 'zh-CN':
case 'zh-CHS':
result.push('zh-Hans');
break;
case 'zh-TW':
case 'zh-SG':
case 'zh-HK':
case 'zh-CHT':
result.push('zh-Hant');
break;
default:
break;
}
}
parts.pop();
}
}
return result;
},
/**
* Get the next fallback locale for the target locale.
*
* Subset implementation of BCP47 (https://tools.ietf.org/html/bcp47).
*
* ### Examples:
*
*| Target Locale | Next Fallback |
*|:--------------|:--------------|
*| ru | null |
*| en-GB | en |
*| fr-CA | fr |
*| zh-Hans-CN | zh-Hans |
*
* @param {string} lang Target locale.
* @return {string} Next fallback locale. `null` if there are no fallback languages.
*/
/*
_getNextFallbackLanguage: function (lang) {
var fallbackLanguageList = this._enumerateFallbackLanguages(lang);
fallbackLanguageList.shift();
var nextFallbackLanguage = fallbackLanguageList.shift();
return nextFallbackLanguage ? nextFallbackLanguage : null;
},
*/
/**
* MutationObserver callback of `lang` attribute for Safari 7
*
* @param {Array} mutations Array of MutationRecord (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver).
*/
_handleLangAttributeChange: function (mutations) {
mutations.forEach(function(mutation) {
switch (mutation.type) {
case 'attributes':
if (mutation.attributeName === 'lang') {
//console.log('_handleLangAttributeChange lang = ' + this.lang + ' oldValue = ' + mutation.oldValue +
// ' typeof oldValue = ' + typeof mutation.oldValue);
if (!(typeof mutation.oldValue === 'object' && !mutation.oldValue) &&
mutation.oldValue !== this.lang) {
if (this._lang !== mutation.oldValue) {
//console.log('assigning this._lang = ' + mutation.oldValue + ' from old value');
this._lang = mutation.oldValue;
}
//console.log('assigning this._lang = ' + this.lang);
this._lang = this.lang;
}
}
break;
default:
/* istanbul ignore next: mutation.type is always attributes */
break;
}
}, this);
},
/**
* Observer of `this.lang` changes.
*
* Update `this.text` object if the text message bundle of the new `lang` is locally available.
*
* Trigger fetching of the text message bundle of the new `lang` if the bundle is not locally available.
*
* @param {string} lang New value of `lang`.
* @param {string} oldLang Old value of `lang`.
*/
_langChanged: function (lang, oldLang) {
//console.log(this.id + ':_langChanged lang = ' + lang + ' oldLang = ' + oldLang);
var id = (this.is || this.getAttribute('is')) === 'i18n-dom-bind' ? this.id : this.is;
lang = lang || ''; // undefined and null are treated as default ''
oldLang = oldLang || '';
if (lang !== oldLang &&
bundles[oldLang] && bundles[oldLang][id]) {
this._fetchStatus.lastLang = oldLang;
}
if (bundles[lang] && bundles[lang][id]) {
// bundle available for the new language
if (lang !== this._fetchStatus.ajaxLang) {
// reset error status
this._fetchStatus.error = null;
}
this.notifyPath('text', this._getBundle(this.lang));
this.fire('lang-updated', {
lang: this.lang,
oldLang: oldLang,
lastLang: this._fetchStatus.lastLang
});
}
else {
// fetch the missing bundle
this._fetchLanguage(lang);
}
},
/**
* Called on `lang-updated` events and update `this.effectiveLang` with the value of `this.lang`.
*/
_updateEffectiveLang: function (event) {
if (dom(event).rootTarget === this) {
//console.log('_updateEffectiveLang: lang = ' + this.lang);
this.effectiveLang = this.lang;
}
},
/**
* Trigger fetching of the appropriate text message bundle of the target locale.
*
* ### Two Layers of Fallbacks:
*
* 1. Missing bundles fall back to those of their fallback locales.
* 1. Missing texts in the non-default bundles fall back to those in the default bundle.
*
* ### Fallback Examples:
*
*| Locale | Bundle Status |
*|:------------|:---------------------------------|
*| fr-CA | existent with sparse texts |
*| fr | existent with full texts |
*| ja | existent with some missing texts |
*| zh-Hans-CN | missing |
*| zh-Hans | existent with some missing texts |
*| zh | missing |
*| en | existent with full texts |
*| ''(default) | existent with full texts |
*
*| Target | Fallback bundle | Resolved locale |
*|:------------|:----------------------|:----------------|
*| en | en | en |
*| ja | ja + ''(default) | ja |
*| fr-CA | fr-CA + fr | fr-CA |
*| zh-Hans-CN | zh-Hans + ''(default) | zh-Hans |
*
* @param {string} lang Target locale.
*/
_fetchLanguage: function (lang) {
if (this._fetchStatus) {
this._fetchStatus.fallbackLanguageList = this._enumerateFallbackLanguages(lang);
this._fetchStatus.fallbackLanguageList.push('');
this._fetchStatus.targetLang = this._fetchStatus.fallbackLanguageList.shift();
this._fetchBundle(this._fetchStatus.targetLang);
}
},
/**
* Fetch the text message bundle of the target locale
* cooperatively with other instances.
*
* @param {string} lang Target locale.
*/
_fetchBundle: function (lang) {
//console.log('_fetchBundle lang = ' + lang);
if (!lang || lang.length === 0) {
// handle empty cases
if (defaultLang && defaultLang.length > 0) {
lang = defaultLang; // app default language
}
else if (this.templateDefaultLang && this.templateDefaultLang.length > 0) {
lang = this.templateDefaultLang; // element default language
}
else {
lang = ''; // fallback default language
}
}
// set up an empty bundle if inexistent
bundles[lang] = bundles[lang] || {};
var id = this.is === 'i18n-dom-bind' ? this.id : this.is;
if (bundles[lang][id]) {
// bundle is available; no need to fetch
if (this._fetchStatus.targetLang === lang) {
// reset error status
this._fetchStatus.error = null;
if (this.lang === lang) {
this.notifyPath('text', this._getBundle(this.lang));
this.fire('lang-updated', {
lang: this.lang,
lastLang: this._fetchStatus.lastLang
});
}
else {
this.lang = lang; // trigger lang-updated event
}
}
else {
var nextFallbackLanguage = this._fetchStatus.fallbackLanguageList.shift();
// bundle is available; no need to fetch
this._fetchStatus.fetchingInstance = null;
if (nextFallbackLanguage) {
this._fetchBundle(nextFallbackLanguage);
}
else {
this._constructBundle(this._fetchStatus.targetLang);
// reset error status
this._fetchStatus.error = null;
if (this.lang === this._fetchStatus.targetLang) {
this.notifyPath('text', this._getBundle(this.lang));
this.fire('lang-updated', {
lang: this.lang,
lastLang: this._fetchStatus.lastLang
});
}
else {
this.lang = this._fetchStatus.targetLang; // trigger lang-updated event
}
}
}
}
else if (this._fetchStatus.fetchingInstance) {
if (this._fetchStatus.fetchingInstance !== this) {
// fetching in progress by another instance
// TODO: redundant addEventListener multiple times
this._forwardLangEventBindThis = this._forwardLangEventBindThis ||
this._forwardLangEvent.bind(this);
this._fetchStatus.fetchingInstance
.addEventListener('lang-updated', this._forwardLangEventBindThis);
}
}
else if (bundleFetchingInstances[lang]) {
// fetching bundle.lang.json in progress by an instance of another element
this._fetchStatus.fetchingInstance = this;
this._fetchStatus.ajaxLang = lang;
this._handleBundleFetchedBindThis = this._handleBundleFetchedBindThis ||
this._handleBundleFetched.bind(this);
bundleFetchingInstances[lang]
.addEventListener('bundle-fetched', this._handleBundleFetchedBindThis);
//console.log(this.is + ' addEventListener bundle-fetched');
}
else {
// proceed to fetch
this._fetchStatus.fetchingInstance = this;
if (!this._fetchStatus.ajax) {
// set up ajax client
this._fetchStatus.ajax = Base.create('iron-ajax');
this._fetchStatus.ajax.handleAs = 'json';
this._fetchStatus._handleResponseBindFetchingInstance = this._handleResponse.bind(this);
this._fetchStatus._handleErrorBindFetchingInstance = this._handleError.bind(this);
this._fetchStatus.ajax.addEventListener('response', this._fetchStatus._handleResponseBindFetchingInstance);
this._fetchStatus.ajax.addEventListener('error', this._fetchStatus._handleErrorBindFetchingInstance);
}
else {
if (this._fetchStatus._handleResponseBindFetchingInstance) {
this._fetchStatus.ajax.removeEventListener('response', this._fetchStatus._handleResponseBindFetchingInstance);
}
if (this._fetchStatus._handleErrorBindFetchingInstance) {
this._fetchStatus.ajax.removeEventListener('error', this._fetchStatus._handleErrorBindFetchingInstance);
}
this._fetchStatus._handleResponseBindFetchingInstance = this._handleResponse.bind(this);
this._fetchStatus._handleErrorBindFetchingInstance = this._handleError.bind(this);
this._fetchStatus.ajax.addEventListener('response', this._fetchStatus._handleResponseBindFetchingInstance);
this._fetchStatus.ajax.addEventListener('error', this._fetchStatus._handleErrorBindFetchingInstance);
}
// TODO: app global bundles have to be handled
var url;
var skipFetching = false;
if (lang === '') {
url = this.resolveUrl(id + '.json');
}
else {
if (bundles[lang] && bundles[lang].bundle) {
// missing in the bundle
url = this.resolveUrl(localesPath + '/' + id + '.' + lang + '.json');
skipFetching = !!this.isI18nController;
}
else {
// fetch the bundle
bundleFetchingInstances[lang] = this;
url = this.resolveUrl(startUrl + localesPath + '/bundle.' + lang + '.json');
}
}
this._fetchStatus.ajax.url = url;
this._fetchStatus.ajaxLang = lang;
try {
this._fetchStatus.error = null;
if (skipFetching) {
this._handleError({ detail: { error: 'skip fetching for I18nController' }});
}
else {
this._fetchStatus.ajax.generateRequest();
}
}
catch (e) {
// TODO: extract error message from the exception e
this._handleError({ detail: { error: 'ajax request failed: ' + e }});
}
}
},
/**
* Handle Ajax success response for a bundle.
*
* @param {Object} event `iron-ajax` success event.
*/
_handleResponse: function (event) {
//console.log('_handleResponse ajaxLang = ' + this._fetchStatus.ajaxLang);
if (this._fetchStatus.ajax.url.indexOf('/' + localesPath + '/bundle.') >= 0) {
bundles[this._fetchStatus.ajaxLang] = bundles[this._fetchStatus.ajaxLang] || {};
this._deepMap(bundles[this._fetchStatus.ajaxLang],
event.detail.response,
function (text) { return text; });
bundles[this._fetchStatus.ajaxLang].bundle = true;
bundleFetchingInstances[this._fetchStatus.ajaxLang] = null;
//console.log('bundle-fetched ' + this.is + ' ' + this._fetchStatus.ajaxLang);
this.fire('bundle-fetched', { success: true, lang: this._fetchStatus.ajaxLang });
var id = this.is === 'i18n-dom-bind' ? this.id : this.is;
if (bundles[this._fetchStatus.ajaxLang][id]) {
this._fetchStatus.lastResponse = bundles[this._fetchStatus.ajaxLang][id];
}
else {
// bundle does not contain text for this.is
this._fetchStatus.fetchingInstance = null;
this._fetchBundle(this._fetchStatus.ajaxLang);
return;
}
}
else {
this._fetchStatus.lastResponse = event.detail.response;
}
if (this._fetchStatus.lastResponse) {
var nextFallbackLanguage = this._fetchStatus.fallbackLanguageList.shift();
// store the raw response
this._fetchStatus.rawResponses[this._fetchStatus.ajaxLang] =
this._fetchStatus.lastResponse;
this._fetchStatus.fetchingInstance = null;
if (nextFallbackLanguage) {
this._fetchBundle(nextFallbackLanguage);
}
else {
this._fetchBundle('');
}
}
else {
event.detail.error = 'empty response for ' + this._fetchStatus.ajax.url;
this._handleError(event);
}
},
/**
* Handle Ajax error response for a bundle.
*
* @param {Object} event `iron-ajax` error event.
*/
_handleError: function (event) {
var nextFallbackLanguage;
this._fetchStatus.fetchingInstance = null;
if (this._fetchStatus.ajax.url.indexOf('/' + localesPath + '/bundle.') >= 0) {
bundles[this._fetchStatus.ajaxLang] = bundles[this._fetchStatus.ajaxLang] || {};
bundles[this._fetchStatus.ajaxLang].bundle = true;
bundleFetchingInstances[this._fetchStatus.ajaxLang] = null;
// falls back to its element-specific bundle
this._fetchBundle(this._fetchStatus.ajaxLang);
//console.log('bundle-fetched ' + this.is + ' ' + this._fetchStatus.ajaxLang);
this.fire('bundle-fetched', { success: false, lang: this._fetchStatus.ajaxLang });
return;
}
nextFallbackLanguage = this._fetchStatus.fallbackLanguageList.shift();
if (this._fetchStatus.ajaxLang === this._fetchStatus.targetLang) {
if (nextFallbackLanguage) {
//console.log(this.is + ': ' + this._fetchStatus.ajaxLang +
// ' falls back to ' + nextFallbackLanguage);
this._fetchStatus.targetLang = nextFallbackLanguage;
this._fetchBundle(nextFallbackLanguage);
}
else {
this._fetchStatus.error = event.detail.error;
//console.log(this._fetchStatus.error);
// falls back to default
this.lang = '';
}
}
else {
// fetching dependent fallback languages
if (nextFallbackLanguage) {
//console.log(this.is + ': ' + this._fetchStatus.ajaxLang +
// ' is missing and skipped');
//console.log(this.is + ': step to the next dependent fallback ' +
// nextFallbackLanguage);
this._fetchBundle(nextFallbackLanguage);
}
else {
this._fetchBundle('');
}
}
},
/**
* Forward `lang-updated` event to other instances of the same element.
*
* @param {Object} event `lang-updated` event object.
*/
_forwardLangEvent: function (event) {
//console.log('_forwardLangEvent ' + this.is + ' ' + event.detail.lang);
event.target.removeEventListener(event.type, this._forwardLangEventBindThis);
if (this.lang === event.detail.lang) {
this.notifyPath('text', this._getBundle(this.lang));
this.fire(event.type, event.detail);
}
else {
this.lang = event.detail.lang;
this.notifyPath('text', this._getBundle(this.lang));
}
},
/**
* Handle `bundle-fetched` event.
*
* @param {Object} event `bundle-fetched` event object.
*/
_handleBundleFetched: function (event) {
var detail = event.detail;
//console.log('_handleBundleFetched ' + this.is + ' ' + detail.lang);
event.target.removeEventListener(event.type, this._handleBundleFetchedBindThis);
if (this._fetchStatus.ajaxLang === detail.lang) {
this._fetchStatus.fetchingInstance = null;
this._fetchBundle(this._fetchStatus.ajaxLang);
}
},
/**
* Handle changes of `observeHtmlLang` property.
*
* @param {Boolean} value Value of `observeHtmlLang`
*/
_observeHtmlLangChanged: function (value) {
if (value) {
this._htmlLangObserver = this._htmlLangObserver ||
new MutationObserver(this._handleHtmlLangChange.bind(this));
this._htmlLangObserver.observe(html, { attributes: true });
}
else {
if (this._htmlLangObserver) {
this._htmlLangObserver.disconnect();
}
}
},
/**
* MutationObserver callback of `<html lang>` attribute.
*
* @param {Array} mutations Array of MutationRecord (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver).
*/
_handleHtmlLangChange: function (mutations) {
mutations.forEach(function(mutation) {
switch (mutation.type) {
case 'attributes':
if (mutation.attributeName === 'lang') {
this.lang = html.lang;
}
break;
default:
break;
}
}, this);
},
/**
* Construct the text message bundle of the target locale with fallback of missing texts.
*
* @param {strings} lang Target locale.
*/
_constructBundle: function (lang) {
var fallbackLanguageList = this._enumerateFallbackLanguages(lang);
var bundle = {};
var raw;
var baseLang;
var id = this.is === 'i18n-dom-bind' ? this.id : this.is;
var i;
fallbackLanguageList.push('');
for (i = 0; i < fallbackLanguageList.length; i++) {
if (bundles[fallbackLanguageList[i]] &&
bundles[fallbackLanguageList[i]][id]) {
break;
}
}
fallbackLanguageList.splice(i + 1, fallbackLanguageList.length);
while ((baseLang = fallbackLanguageList.pop()) !== undefined) {
if (bundles[baseLang][id]) {
bundle = deepcopy(bundles[baseLang][id]);
}
else {
raw = this._fetchStatus.rawResponses[baseLang];
if (raw) {
this._deepMap(bundle, raw, function (text) { return text; });
}
}
}
// store the constructed bundle
if (!bundles[lang]) {
bundles[lang] = {};
}
bundles[lang][id] = bundle;
},
/**
* Construct a pseudo-bundle for the target locale. (Not used for now)
*
* @param {string} lang Target locale.
*/
/*
_constructPseudoBundle: function (lang) {
var bundle = {};
var id = this.is === 'i18n-dom-bind' ? this.id : this.is;
this._deepMap(bundle, bundles[''][id], function (value) {
return typeof value === 'string' ? lang + ' ' + value : value;
});
bundles[lang] = bundles[lang] || {};
bundles[lang][id] = bundle;
return bundle;
},
*/
/**
* Recursively map the source object onto the target object with the specified map function.
*
* The method is used to merge a bundle into its fallback bundle.
*
* @param {Object} target Target object.
* @param {Object} source Source object.
* @param {Function} map Mapping function.
*/
_deepMap: function (target, source, map) {
var value;
for (var prop in source) {
value = source[prop];
switch (typeof value) {
case 'string':
case 'number':
case 'boolean':
if (typeof target === 'object') {
target[prop] = map(value, prop);
}
break;
case 'object':
if (typeof target === 'object') {
if (Array.isArray(value)) {
// TODO: cannot handle deep objects properly
target[prop] = target[prop] || [];
this._deepMap(target[prop], value, map);
}
else {
target[prop] = target[prop] || {};
this._deepMap(target[prop], value, map);
}
}
break;
default:
if (typeof target === 'object') {
target[prop] = value;
}
break;
}
}
},
/**
* Construct the default bundle from the element's template.
*
* Extract the default bundle from the template if it is embedded as JSON at build time.
*
* ### Hard-coded UI text example:
* ```
* <dom-module id="custom-element">
* <template>
* <span id="label">UI Text Label:</span>
* <input id="input-el"
* value="{{keyword}}"
* placeholder="Keyword">
* </template>
* </dom-module>
* ```
*
* ### Constructed default bundle for the above example:
* ```
* {
* "model" : {
* "input-el": {
* "placeholder": "Keyword"
* }
* },
* "label": "UI Text Label:"
* }
* ```
*
* ### Processed template with bound annotations for the above example:
* ```
* <dom-module id="custom-element">
* <template localizable-text="embedded">
* <span id="label">{{text.label}}</span>
* <input id="input-el"
* value="{{keyword}}"
* placeholder="{{model.input-el.placeholder}}">
* </template>
* </dom-module>
* ```
*
* ### Embedded JSON bundle format for the above example:
* ```
* <dom-module id="custom-element">
* <template localizable-text="embedded">
* <span id="label">{{text.label}}</span>
* <input id="input-el"
* value="{{keyword}}"
* placeholder="{{model.input-el.placeholder}}">
* <template id="localizable-text">
* <json-data>{
* "model" : {
* "input-el": {
* "placeholder": "Keyword"
* }
* },
* "label": "UI Text Label:"
* }</json-data>
* </template>
* </template>
* </dom-module>
* ```
*/
_constructDefaultBundle: function () {
var template;
var id = this.is;
if (this.is === 'i18n-dom-bind') {
template = this;
id = this.id;
/* istanbul ignore if */
if (template.content.childNodes.length === 0) {
// Find the real template in Internet Explorer 11 when i18n-dom-bind is concealed in a parent template
// This does not happen on Polymer 1.3.1 or later. So ignore this 'if' statement in code coverage.
template = Array.prototype.map.call(document.querySelectorAll('template'), function (parentTemplate) {
return parentTemplate.content.querySelector('template#' + id + '[is="i18n-dom-bind"]');
}).reduce(function (prev, current) {
return prev || current;
});
// Patch this.content with the real one
if (template) {
this.content = template.content;
}
}
}
else {
template = DomModule.import(id, 'template');
}
if (template) {
this.templateDefaultLang = template.hasAttribute('lang') ? template.lang : 'en';
}
else {
this.templateDefaultLang = 'en';
}
var bundle = { model: {} };
var path = [];
var templateDefaultLang = this.templateDefaultLang;
var localizableText, jsonData;
if (template) {
// register localizable attributes of the element itself
attributesRepository.registerLocalizableAttributes(id, template);
if (template.getAttribute('localizable-text') === 'embedded') {
// pick up embedded JSON from the template
localizableText = template.content.querySelector('#localizable-text');
if (localizableText) {
jsonData = localizableText.content.querySelector('json-data');
if (jsonData) {
bundle = JSON.parse(jsonData.textContent);
}
else {
console.error('<json-data> not found in <template id=\"localizable-text\">');
}
}
else {
console.error('<template id=\"localizable-text\"> not found');
}
}
else {
if (extraWhiteSpaceNode) {
template.setAttribute('strip-whitespace', '');
}
// traverse template to generate bundle
this._traverseTemplateTree(template.content, path, bundle, 0);
}
}
bundles[''][id] = bundle;
bundles[templateDefaultLang] = bundles[templateDefaultLang] || {};
bundles[templateDefaultLang][id] = bundle;
//console.log('text = ');
//console.log(JSON.stringify(bundle, null, 2));
return true;
},
/**
* Traverse localizable attributes of the target element node and
* add them to the target bundle under the `model` object.
*
* The `<i18n-attr-repo>` object is used
* to judge if the target attributes are localizable.
*
* @param {Object} node Target element node.
* @param {string} path Path to the target node.
* @param {Object} bundle Default bundle.
*/
_traverseAttributes: function (node, path, bundle) {
var name = node.nodeName.toLowerCase();
var id = node.getAttribute ?
(node.getAttribute('text-id') ||
node.getAttribute('id')) : null;
var text;
var messageId;
var attrId;
var isLocalizable;
var dummy;
// pick up element attributes
Array.prototype.forEach.call(node.attributes, function (attribute) {
text = attribute.value;
switch (attribute.name) {
case 'id':
case 'text-id':
case 'is':
case 'lang':
case 'class':
// verification required before removing these attributes
case 'href':
case 'src':
case 'style':
case 'url':
case 'selected':
break;
default:
if (!(isLocalizable = attributesRepository.isLocalizableAttribute(node, attribute.name))) {
break;
}
if (text.length === 0) {
// skip empty value attribute
}
else if (text.match(/^{{[^{}]*}}$/) || text.match(/^\[\[[^\[\]]*\]\]$/)) {
// skip annotation attribute
}
else if (text.replace(/\n/g, ' ').match(/^{.*}|\[.*\]$/g) &&
!text.match(/^{{[^{}]*}}|\[\[[^\[\]]*\]\]/) &&
!text.match(/{{[^{}]*}}|\[\[[^\[\]]*\]\]$/)) {
// generate message id
messageId = this._generateMessageId(path, id);
try {
//console.log(messageId + ' parsing attribute ' + attribute.name + ' = ' + text);
var value = JSON.parse(text.replace(/\n/g, ' '));
//console.log('parsed JSON object = ');
//console.log(value);
switch (typeof value) {
case 'string':
case 'number':
case 'object':
// put into model
attrId = ['model', messageId, attribute.name].join('.');
debuglog(attrId + ' = ' + text);
this._setBundleValue(bundle, attrId, value);
attribute.value = '{{' + attrId + '}}';
break;
default: // skip other types
break;
}
}
catch (e) {
// invalid JSON
console.warn(e, 'Invalid JSON at <' + name + ' ' + attribute.name + '> with value = ' + text);
}
}
else if (text.match(/{{[^{}]{1,}}}|\[\[[^\[\]]{1,}\]\]/)) {
// compound binding attribute
// Parameterized:
// e.g., attr="Compound binding attribute has [[bound.value]] {{parameters}} in the value string"
// replaced as "{{i18nFormat(attrId.0,bound.value,parameters)}}"
// extracted as [ "Compound binding attribute has {1} {2} in the value string", "[[bound.value]]", "{{parameters}}" ]
// Concatenated: (Parameters with functions cannot be reordered in translation)
// e.g., attr2="Compound binding attribute has [[f1(bound.value)]] {{f2(parameters)}} in the value string"
// replaced as "{{attrId.0}}[[f1(bound.value)]]{{attrId.2}}{{f2(parameters)}}{{attrId.4}}"
// extracted as [ "Compound binding attribute has ", "[[f1(bound.value)]]", " ", "{{f2(parameters)}}", " in the value string" ]
var parsed = text.match(/([^{}\[\]]{1,})|({{[^{}]{1,}}})|(\[\[[^\[\]]{1,}\]\])/g);
var parameterized;
var processed;
var n;
messageId = this._generateMessageId(path, id);
attrId = ['model', messageId, attribute.name.replace(/\$$/, '')].join('.');
if (text.match(/\)}}|\)\]\]/)) { // check for function parameter
// Concatenate
debuglog(attrId + ' = ' + JSON.stringify(parsed));
this._setBundleValue(bundle, attrId, parsed);
processed = '';
for (n = 0; n < parsed.length; n++) {
if (parsed[n].match(/^{{[^{}]{1,}}}|\[\[[^\[\]]{1,}\]\]$/)) {
processed += parsed[n];
}
else {
processed += '{{' + attrId + '.' + n + '}}';
}
}
if (isLocalizable === '$' && !attribute.name.match(/\$$/)) {
dummy = document.createElement('span');
dummy.innerHTML = '<span ' + attribute.name + '$="' + processed + '"></span>';
node.setAttributeNode(dummy.childNodes[0].attributes[0].cloneNode());
}
else {
attribute.value = processed;
}
}
else {
// Parameterize
parameterized = [ '' ];
while (parsed.length) {
if (parsed[0].match(/^{{[^{}]{1,}}}|\[\[[^\[\]]{1,}\]\]$/)) {
parameterized.push(parsed[0]);
parameterized[0] += '{' + (parameterized.length - 1) + '}';
}
else {
parameterized[0] += parsed[0];
}
parsed.shift();
}
debuglog(attrId + ' = ' + JSON.stringify(parameterized));
this._setBundleValue(bundle, attrId, parameterized);
processed = '{{i18nFormat(' + attrId + '.0';
for (n = 1; n < parameterized.length; n++) {
processed += ',' + parameterized[n].replace(/^[{\[][{\[](.*)[}\]][}\]]$/, '$1');
}
processed += ')}}';
if (isLocalizable === '$' && !attribute.name.match(/\$$/)) {
dummy = document.createElement('span');
dummy.innerHTML = '<span ' + attribute.name + '$="' + processed + '"></span>';
node.setAttributeNode(dummy.childNodes[0].attributes[0].cloneNode());
}
else {
attribute.value = processed;
}
}
}
else {
// string attribute
messageId = this._generateMessageId(path, id);
attrId = ['model', messageId, attribute.name].join('.');
debuglog(attrId + ' = ' + text);
this._setBundleValue(bundle, attrId, text);
if (isLocalizable === '$' && !attribute.name.match(/\$$/)) {
dummy = document.createElement('span');
dummy.innerHTML = '<span ' + attribute.name + '$=' + '"{{' + attrId + '}}"' + '></span>';
node.setAttributeNode(dummy.childNodes[0].attributes[0].cloneNode());
}
else {
attribute.value = '{{' + attrId + '}}';
}
}
break;
}
}, this);
},
/**
* Recursively traverse text contents of the target element node
* and add them to the target bundle object.
*
* Traversed text contents are replaced with annotations
* for the corresponding text in the bundle.
*
* - - -
*
* There are some special treatments in the following cases.
*
* ### Sentence with parameterized child parameter-like elements:
*
* As the order of the parameters can change in different languages,
* `<i18n-format>` element is used to make the sentence localizable.
*
* ### Before processing
*
* ```
* <p id="p"><code>i18n-format</code> is
* used for
* <a href="https://www.google.com">parameterized</a>
* sentences.</p>
* ```
*
* ### After processing
*
* ```
* <p id="p">
* <i18n-format lang="{{effectiveLang}}">
* <span>{{text.p.0}}</span>
* <code>{{text.p.1}}</code>
* <a href="https://www.google.com">{{text.p.2}}</a>
* </i18n-format>
* </p>
* ```
*
* ### Constructed bundle data: Texts are stored in an Array of strings.
*
* ```
* {
* "p" : [
* "{1} is\n used for\n {2}\n sentences.",
* "i18n-format",
* "parameterized"
* ]
* }
* ```
*
* - - -
*
* ### `<i18n-format>` element with compound templates:
*
* Texts with compound templates for `<i18n-format>` element are
* processed as below.
*
* `lang="{{effectiveLang}}"` attribute is added to `<i18n-format>` node
* as well as `<i18n-number>` node.
*
* ### Before processing
*
* ```
* <i18n-format id="sentence">
* <json-data>{
* "0": "You ({3}) gave no gifts.",
* "1": {
* "male": "You ({3}) gave him ({4}) {5}.",
* "female": "You ({3}) gave her ({4}) {5}.",
* "other": "You ({3}) gave them ({4}) {5}."
* },
* "one": {
* "male":
* "You ({3}) gave him ({4}) and one other {5}.",
* "female":
* "You ({3}) gave her ({4}) and one other {5}.",
* "other":
* "You ({3}) gave them ({4}) and one other {5}."
* },
* "other":
* "You ({3}) gave them ({4}) and {1} others gifts."
* }</json-data>
* <i18n-number
* offset="1"
* >{{recipients.length}}</i18n-number>
* <span>{{recipients.0.gender}}</span>
* <span>{{sender.name}}</span>
* <span>{{recipients.0.name}}</span>
* <span>a gift</span>
* </i18n-format>
* ```
*
* ### After processing
*
* ```
* <i18n-format id="sentence"
* lang="{{effectiveLang}}">
* <json-data>{{serialize(text.sentence.0)}}</json-data>
* <i18n-number
* offset="1"
* lang="{{effectiveLang}}"
* >{{recipients.length}}</i18n-number>
* <span>{{recipients.0.gender}}</span>
* <span>{{sender.name}}</span>
* <span>{{recipients.0.name}}</span>
* <span>{{text.sentence.5}}</span>
* </i18n-format>
* ```
*
* ### Constructed bundle data:
*
* ```
* {
* "sentence" : [
* {
* "0": "You ({3}) gave no gifts.",
* "1": {
* "male": "You ({3}) gave him ({4}) {5}.",
* "female": "You ({3}) gave her ({4}) {5}.",
* "other": "You ({3}) gave them ({4}) {5}."
* },
* "one": {
* "male":
* "You ({3}) gave him ({4}) and one other {5}.",
* "female":
* "You ({3}) gave her ({4}) and one other {5}.",
* "other":
* "You ({3}) gave them ({4}) and one other {5}."
* },
* "other":
* "You ({3}) gave them ({4}) and {1} others gifts."
* },
* "{{recipients.length - 1}}",
* "{{recipients.0.gender}}",
* "{{sender.name}}",
* "{{recipients.0.name}}",
* "a gift"
* ]
* }
* ```
*
* @param {Object} node Target element node.
* @param {string} path Path to the target node.
* @param {Object} bundle Default bundle.
* @param {Number} index Index in the siblings of the target node excluding whitespace nodes.
*/
_traverseTemplateTree: function (node, path, bundle, index) {
var i;
var whiteSpaceElements = 0;
var isWhiteSpace = false;
var isCompoundAnnotatedNode = false;
var text;
var span;
var name = node.nodeName.toLowerCase();
var id = node.getAttribute ?
(node.getAttribute('text-id') ||
node.getAttribute('id')) : null;
var messageId;
var n;
var templateText;
var templateTextParams;
path.push(id ? '#' + id : name + (index > 0 ? '_' + index : ''));
//console.log(path.join(':'));
switch (node.nodeType) {
case node.ELEMENT_NODE:
switch (name) {
case 'style':
case 'script':
case 'meta':
// skip
break;
case 'i18n-format':
// pick up element attributes
this._traverseAttributes(node, path, bundle);
// generate message id
messageId = this._generateMessageId(path, id);
if (!node.hasAttribute('lang')) {
node.setAttribute('lang', '{{effectiveLang}}');
}
text = Array.prototype.filter.call(node.childNodes, function (child) {
return child.nodeType === child.ELEMENT_NODE;
}).map(function (param, n) {
var value = param.textContent;
var parsedValue = value.match(/^({{)(.*)(}})$/) ||
value.match(/^(\[\[)(.*)(\]\])$/);
if (n === 0) {
// template element
if (param.tagName.toLowerCase() === 'json-data') {
if (parsedValue) {
var parsedValue2 = value.match(/^({{)(serialize\(.*\))(}})$/) ||
value.match(/^(\[\[)(serialize\(.*\))(\]\])$/);
if (!parsedValue2) {
// convert to {{serialize(id)}}
parsedValue.shift();
parsedValue.splice(1, 0, 'serialize(');
parsedValue.splice(3, 0, ')');
param.textContent = parsedValue.join('');
}
}
else {
value = JSON.parse(value);
param.textContent = '{{serialize(text.' + messageId + '.' + n + ')}}';
}
}
else {
if (!parsedValue) {
param.textContent = '{{text.' + messageId + '.' + n + '}}';
}
}
}
else {
// param element
// TODO: handle localization of param nodes and attributes
if (!param.hasAttribute('param')) {
param.setAttribute('param', n);
}
if (param.tagName.toLowerCase() === 'i18n-number') {
if (!param.hasAttribute('lang')) {
param.setAttribute('lang', '{{effectiveLang}}');
}
var offset = param.getAttribute('offset');
if (offset) {
offset = ' - ' + offset;
}
else {
offset = '';
}
if (parsedValue) {
// convert to {{path - offset}}
parsedValue.shift();
parsedValue.splice(2, 0, offset);
value = parsedValue.join('');
}
else {
param.textContent = '{{text.' + messageId + '.' + n + '}}';
}
}
else {
if (!parsedValue) {
param.textContent = '{{text.' + messageId + '.' + n + '}}';
}
}
}
return value;
}, this);
debuglog(messageId + ' = ' + text);
this._setBundleValue(bundle, messageId, text);
break;
case 'template':
// traverse into its content
//console.log(path.join(':') + ':' + node.content.nodeName + ':' + 0);
if (extraWhiteSpaceNode) {
//if (node.hasAttribute('is') && node.getAttribute('is').match(/^(i18n-)?dom-/)) {
node.setAttribute('strip-whitespace', '');
//}
}
this._traverseTemplateTree(node.content, path, bundle, 0);
break;
default:
// element node
if (name === 'i18n-number' ||
name === 'i18n-datetime') {
if (!node.hasAttribute('lang')) {
node.setAttribute('lang', '{{effectiveLang}}');
}
}
// pick up element attributes
this._traverseAttributes(node, path, bundle);
// check annonated node
isCompoundAnnotatedNode = false;
if (node.childElementCount === 0) {
if (node.textContent) {
isCompoundAnnotatedNode = this._isCompoundAnnotatedText(node.textContent);
}
}
if (node.childElementCount === 0 && !isCompoundAnnotatedNode) {
if (node.textContent) { // use textContent for Firefox compatibility
text = node.textContent;
if (text.length === 0 || text.match(/^\s*$/g)) {
// skip empty or whitespace node
}
else if (text.trim().match(/^({{[^{}]*}}|\[\[[^\[\]]*\]\])$/)) {
// skip annotation node
// TODO: compound bindings support
}
else {
// a text message found
// generate message id
messageId = this._generateMessageId(path, id);
// store the text message
text = text.replace(/^[\s]*[\s]/, ' ').replace(/[\s][\s]*$/, ' ');
if (name === 'json-data') {
this._setBundleValue(bundle, messageId, JSON.parse(text));
}
else {
this._setBundleValue(bundle, messageId, text);
}
// replace textContent with annotation
node.textContent = '{{text.' + messageId + '}}';
if (!id) {
//node.id = messageId;
//console.warn('add missing node id as ' + messageId + ' for ' + text);
}
debuglog(messageId + ' = ' + text);
}
}
else {
// skip
}
}
else {
// has children or compound annotation
// check if i18n-format is applicable
var childStatus = Array.prototype.map.call(
node.childNodes, function (child) {
var result;
if (child.nodeType === child.ELEMENT_NODE &&
child.tagName === 'TEMPLATE') {
var templateNonCommentChildNodes =
Array.prototype.filter.call(child.content.childNodes, function (templateChild) {
switch (templateChild.nodeType) {
case templateChild.COMMENT_NODE:
return false;
case templateChild.TEXT_NODE:
return !templateChild.textContent.match(/^\s*$/g);
default:
case templateChild.ELEMENT_NODE:
return true;
}
});
var firstChild = templateNonCommentChildNodes.shift();
// Examples:
// hasText: <template>text</template>
// hasCompoundAnnotatedText: <template>{{item.name}} text</template>
// hasTextChild: <template><b>text</b></template> or <template><br></template>
// hasCompoundAnnotatedChildNode: <template><b>{{item.name}} text</b></template>
// hasGrandChildren: <template><span><b>text</b></span></template> or
// <template><b>A</b><i>B</i></template> or
// hasCompoundAnnotatedText
result = {
hasText: templateNonCommentChildNodes.length === 0 &&
firstChild &&
firstChild.nodeType === firstChild.TEXT_NODE &&
firstChild.textContent.length > 0 &&
!firstChild.textContent.match(/^\s*$/g),
hasCompoundAnnotatedText: firstChild &&
firstChild.nodeType === firstChild.TEXT_NODE &&
this._isCompoundAnnotatedText(firstChild.textContent),
hasTextChild: templateNonCommentChildNodes.length === 0 &&
firstChild &&
firstChild.nodeType === child.ELEMENT_NODE &&
firstChild.childElementCount === 0, // including <br>
hasCompoundAnnotatedChildNode: firstChild &&
firstChild.nodeType === firstChild.ELEMENT_NODE &&
firstChild.childElementCount === 0 &&
this._isCompoundAnnotatedText(firstChild.textContent),
hasGrandChildren: templateNonCommentChildNodes.length > 0 ||
(firstChild &&
firstChild.nodeType === firstChild.ELEMENT_NODE &&
Array.prototype.map.call(
firstChild.childNodes,
function (grandChild) {
return grandChild.nodeType !== grandChild.TEXT_NODE;
}
).reduce(function (prev, current) {
return prev || current;
}, false)) ||
(firstChild &&
firstChild.nodeType === firstChild.TEXT_NODE &&
this._isCompoundAnnotatedText(firstChild.textContent))
};
}
else {
result = {
hasText: child.nodeType === child.TEXT_NODE &&
child.textContent.length > 0 &&
!child.textContent.match(/^\s*$/g),
hasCompoundAnnotatedText: child.nodeType === child.TEXT_NODE &&
this._isCompoundAnnotatedText(child.textContent),
hasTextChild: child.nodeType === child.ELEMENT_NODE &&
child.childElementCount === 0, // including <br>
hasCompoundAnnotatedChildNode: child.nodeType === child.ELEMENT_NODE &&
child.childElementCount === 0 &&
this._isCompoundAnnotatedText(child.textContent),
hasGrandChildren: child.nodeType === child.ELEMENT_NODE &&
Array.prototype.map.call(
child.childNodes,
function (grandChild) {
return grandChild.nodeType !== grandChild.TEXT_NODE;
}
).reduce(function (prev, current) {
return prev || current;
}, false)
};
}
return result;
}.bind(this)).reduce(function (prev, current) {
return {
hasText: prev.hasText || current.hasText,
hasCompoundAnnotatedText: prev.hasCompoundAnnotatedText || current.hasCompoundAnnotatedText,
hasTextChild: prev.hasTextChild || current.hasTextChild,
hasCompoundAnnotatedChildNode: prev.hasCompoundAnnotatedChildNode || current.hasCompoundAnnotatedChildNode,
hasGrandChildren: prev.hasGrandChildren || current.hasGrandChildren
};
}, {
hasText: false,
hasCompoundAnnotatedText: false,
hasTextChild: false,
hasCompoundAnnotatedChildNode: false,
hasGrandChildren: false
});
if ((childStatus.hasText || node.hasAttribute('text-id')) &&
(childStatus.hasTextChild || childStatus.hasCompoundAnnotatedText) &&
!childStatus.hasGrandChildren &&
!childStatus.hasCompoundAnnotatedChildNode) {
// apply i18n-format
/*
<i18n-format>
<span>{{text.simpleChartDesc.0}}</span>
<code param="1">{{text.simpleChartDesc.1}}</code>
<a param="2" href="link">{{text.simpleChartDesc.2}}</a>
<a param="3" href="link2">{{text.simpleChartDesc.3}}</a>
</i18n-format>
*/
n = 0;
messageId = this._generateMessageId(path, id);
templateTextParams = Array.prototype.map.call(
node.childNodes, function (child) {
var firstChild;
if (child.nodeType === child.TEXT_NODE &&
this._hasAnnotatedText(child.textContent)) {
return this._compoundAnnotationToSpan(child)
.map(function (_child) {
return {
node: _child,
templateNode: null,
type: _child.nodeType,
text: _child.nodeType === _child.TEXT_NODE ?
_child.textContent : null,
childTextNode: _child.nodeType === _child.ELEMENT_NODE &&
_child.childNodes.length > 0
};
});
}
else if (child.nodeType === child.ELEMENT_NODE &&
child.tagName === 'TEMPLATE') {
firstChild =
Array.prototype.filter.call(child.content.childNodes, function (templateChild) {
switch (templateChild.nodeType) {
case templateChild.COMMENT_NODE:
return false;
case templateChild.TEXT_NODE:
return !templateChild.textContent.match(/^\s*$/g);
default:
case templateChild.ELEMENT_NODE:
return true;
}
}).shift();
if (!firstChild) {
firstChild =
Array.prototype.filter.call(child.content.childNodes, function (templateChild) {
switch (templateChild.nodeType) {
case templateChild.COMMENT_NODE:
return false;
default:
return true;
}
}).shift();
}
if (firstChild) {
return [{
node: firstChild,
templateNode: child,
type: firstChild.nodeType,
text: null,
childTextNode: true
}];
}
else {
return [];
}
}
else {
return [{
node: child,
templateNode: null,
type: child.nodeType,
text: child.nodeType === child.TEXT_NODE ?
child.textContent : null,
childTextNode: child.nodeType === child.ELEMENT_NODE &&
child.childNodes.length > 0
}];
}
}.bind(this)).reduce(function (prev, currentList) {
var current;
var textContent;
for (var i = 0; i < currentList.length; i++) {
current = currentList[i];
if (current.text) {
prev.text[0] += current.text;
}
if (current.type === current.node.ELEMENT_NODE) {
n++;
prev.text[0] += '{' + n + '}';
path.push(n);
this._traverseAttributes(current.node, path, bundle);
path.pop();
if (current.childTextNode) {
textContent = current.node.textContent;
if (textContent.length === 0) {
// tag without textContent
prev.text.push('<' + current.node.nodeName.toLowerCase() + '>');
current.node.textContent = '';
}
else if (textContent.match(/^\s*$/g)) {
// tag with whitespace textContent
prev.text.push('<' + current.node.nodeName.toLowerCase() + '>');
current.node.textContent = ' ';
}
else if (textContent.match(/^[\s]*({{.*}}|\[\[.*\]\])[\s]*$/)) {
// tag with annotation
prev.text.push(textContent);
// textContent is untouched
}
else {
prev.text.push(current.node.textContent.replace(/^[\s]*[\s]/, ' ').replace(/[\s][\s]*$/, ' '));
current.node.textContent = '{{text.' + messageId + '.' + n + '}}';
}
}
else {
prev.text.push('<' + current.node.nodeName.toLowerCase() + '>');
}
current.node.setAttribute('param', n.toString());
prev.params.push(current.templateNode || current.node);
}
else if (current.type === current.node.TEXT_NODE &&
current.childTextNode) {
// in template node
n++;
prev.text[0] += '{' + n + '}';
textContent = current.node.textContent;
if (textContent.length === 0) {
// template without textContent
prev.text.push('<template>');
current.node.textContent = '';
}
else if (textContent.match(/^\s*$/g)) {
// template with whitespace textContent
prev.text.push('<template>');
current.node.textContent = ' ';
}
else if (textContent.match(/^[\s]*({{.*}}|\[\[.*\]\])[\s]*$/)) {
// tag with annotation
prev.text.push(textContent);
// textContent is untouched
}
else {
prev.text.push(textContent.replace(/^[\s]*[\s]/, ' ').replace(/[\s][\s]*$/, ' '));
current.node.textContent = '{{text.' + messageId + '.' + n + '}}';
}
span = document.createElement('span');
span.setAttribute('param', n.toString());
current.templateNode.content.removeChild(current.node);
span.appendChild(current.node);
current.templateNode.content.appendChild(span);
prev.params.push(current.templateNode);
}
}
return prev;
}.bind(this), { text: [ '' ], params: [ '{{text.' + messageId + '.0}}' ] });
templateText = document.createElement('i18n-format');
templateText.setAttribute('lang', '{{effectiveLang}}');
span = document.createElement('span');
// span.innerText does not set an effective value in Firefox
span.textContent = templateTextParams.params.shift();
templateText.appendChild(span);
Array.prototype.forEach.call(templateTextParams.params,
function (param) {
templateText.appendChild(param);
}
);
// store the text message
templateTextParams.text[0] = templateTextParams.text[0].replace(/^[\s]*[\s]/, ' ').replace(/[\s][\s]*$/, ' ');
this._setBundleValue(bundle, messageId, templateTextParams.text);
// insert i18n-format
node.innerHTML = '';
dom(node).appendChild(templateText);
if (!id) {
//node.id = messageId;
//console.warn('add missing node id as ' + messageId + ' for ' + templateTextParams.text[0]);
}
debuglog(messageId + ' = ' + templateTextParams.text);
}
else {
// traverse childNodes
for (i = 0; i < node.childNodes.length; i++) {
//console.log(path.join(':') + ':' + node.childNodes[i].nodeName + ':' + (i - whiteSpaceElements) + ' i = ' + i + ' whiteSpaceElements = ' + whiteSpaceElements);
if (this._traverseTemplateTree(node.childNodes[i], path, bundle, i - whiteSpaceElements)) {
whiteSpaceElements++;
}
}
}
}
break;
}
break;
case node.TEXT_NODE:
// text node
text = node.textContent;
if (text.length === 0 || text.match(/^\s*$/g)) {
// skip empty or whitespace node
isWhiteSpace = true;
}
else if (text.trim().match(/^({{[^{}]*}}|\[\[[^\[\]]*\]\])$/)) {
// skip annotation node
}
else {
var parent = node.parentNode;
if (this._isCompoundAnnotatedText(text)) {
// apply i18n-format
n = 0;
messageId = this._generateMessageId(path, id);
templateTextParams = Array.prototype.map.call(
[ node ], function (child) {
return this._compoundAnnotationToSpan(child)
.map(function (_child) {
return {
node: _child,
type: _child.nodeType,
text: _child.nodeType === _child.TEXT_NODE ?
_child.textContent : null,
childTextNode: _child.nodeType === _child.ELEMENT_NODE &&
_child.childNodes.length > 0
};
});
}.bind(this)).reduce(function (prev, currentList) {
var current;
for (var i = 0; i < currentList.length; i++) {
current = currentList[i];
if (current.text) {
prev.text[0] += current.text;
}
if (current.type === current.node.ELEMENT_NODE) {
n++;
prev.text[0] += '{' + n + '}';
path.push(n);
this._traverseAttributes(current.node, path, bundle);
path.pop();
/* current.childTextNode is always true since current.node is <span>{{annotation}}</span> */
prev.text.push(current.node.textContent);
current.node.setAttribute('param', n.toString());
prev.params.push(current.node);
}
}
return prev;
}.bind(this), { text: [ '' ], params: [ '{{text.' + messageId + '.0}}' ] });
templateText = document.createElement('i18n-format');
templateText.setAttribute('lang', '{{effectiveLang}}');
span = document.createElement('span');
// span.innerText does not set an effective value in Firefox
span.textContent = templateTextParams.params.shift();
templateText.appendChild(span);
Array.prototype.forEach.call(templateTextParams.params,
function (param) {
templateText.appendChild(param);
}
);
// store the text message
templateTextParams.text[0] = templateTextParams.text[0].replace(/^[\s]*[\s]/, ' ').replace(/[\s][\s]*$/, ' ');
this._setBundleValue(bundle, messageId, templateTextParams.text);
// insert i18n-format
dom(parent).insertBefore(templateText, node);
dom(parent).removeChild(node);
debuglog(messageId + ' = ' + templateTextParams.text);
}
else {
// generate message id
messageId = this._generateMessageId(path, id);
// store the text message
text = text.replace(/^[\s]*[\s]/, ' ').replace(/[\s][\s]*$/, ' ');
this._setBundleValue(bundle, messageId, text);
// replace textContent with annotation
node.textContent = '{{text.' + messageId + '}}';
if (!id) {
//span.id = messageId;
//console.warn('add missing span with id as ' + messageId + ' for ' + text);
}
debuglog(messageId + ' = ' + text);
}
}
break;
case node.DOCUMENT_NODE:
case node.DOCUMENT_FRAGMENT_NODE:
// traverse childNodes
for (i = 0; i < node.childNodes.length; i++) {
//console.log(path.join(':') + ':' + node.childNodes[i].nodeName + ':' + (i - whiteSpaceElements) + ' i = ' + i + ' whiteSpaceElements = ' + whiteSpaceElements);
if (this._traverseTemplateTree(node.childNodes[i], path, bundle, i - whiteSpaceElements)) {
whiteSpaceElements++;
}
}
break;
default:
isWhiteSpace = true;
// comment node, etc.
break;
}
path.pop();
return isWhiteSpace;
},
/**
* Check if the text has compound annotation
*
* @param {string} text target text to check compound annotation
* @return {Boolean} true if the text contains compound annotation
*/
_isCompoundAnnotatedText: function (text) {
return !text.trim().match(/^({{[^{}]*}}|\[\[[^\[\]]*\]\])$/) &&
!!text.match(/({{[^{}]*}}|\[\[[^\[\]]*\]\])/);
},
/**
* Check if the text has annotation
*
* @param {string} text target text to check annotation
* @return {Boolean} true if the text contains annotation
*/
_hasAnnotatedText: function (text) {
return !!text.match(/({{[^{}]*}}|\[\[[^\[\]]*\]\])/);
},
/**
* Convert compound annotations to span elements
*
* @param {Text} node target text node to convert compound annotations
* @return {Object[]} Array of Text or span elements
*/
_compoundAnnotationToSpan: function (node) {
var result;
/* istanbul ignore else: node is prechecked to contain annotation(s) */
if (node.textContent.match(/({{[^{}]*}}|\[\[[^\[\]]*\]\])/)) {
result = node.textContent
.match(/({{[^{}]*}}|\[\[[^\[\]]*\]\]|[^{}\[\]]{1,}|[{}\[\]]{1,})/g)
.reduce(function (prev, current) {
if (current.match(/^({{[^{}]*}}|\[\[[^\[\]]*\]\])$/)) {
prev.push(current);
prev.push('');
}
else {
if (prev.length === 0) {
prev.push(current);
}
else {
prev[prev.length - 1] += current;
}
}
return prev;
}.bind(this), [])
.map(function (item) {
var childNode;
if (item.match(/^({{[^{}]*}}|\[\[[^\[\]]*\]\])$/)) {
childNode = document.createElement('span');
childNode.textContent = item;
}
else if (item) {
childNode = document.createTextNode(item);
}
else {
childNode = null;
}
return childNode;
});
if (result.length > 0) {
if (!result[result.length - 1]) {
result.pop(); // pop null node for ''
}
}
}
else {
// no compound annotation
result = [ node ];
}
return result;
},
/**
* Add the value to the target default bundle with the specified message Id
*
* @param {Object} bundle Default bundle.
* @param {string} messageId ID string of the value.
* @param {Object} value Value of the text message. Normally a string.
*/
_setBundleValue: function (bundle, messageId, value) {
var messageIdPath = messageId.split('.');
bundle.model = bundle.model || {};
if (messageIdPath.length === 1) {
bundle[messageId] = value;
}
else {
var cursor = bundle;
for (var i = 0; i < messageIdPath.length; i++) {
if (i < messageIdPath.length - 1) {
cursor[messageIdPath[i]] = cursor[messageIdPath[i]] || {};
cursor = cursor[messageIdPath[i]];
}
else {
cursor[messageIdPath[i]] = value;
}
}
}
},
/**
* Generate a message ID from the specified path and id.
*
* ### TODO:
*
* - Shorten or optimize ids
*
* @param {Array} path List of ascestor elements of the current node in traversal.
* @param {id} id Value of `id` or `text-id` attribute of the current node.
*/
_generateMessageId: function (path, id) {
var messageId;
if (!id || id.length === 0) {
for (var i = 1; i < path.length; i++) {
if (path[i][0] === '#') {
if (path[i] !== '#document-fragment') {
if (messageId && path[i].substr(0, 5) === '#text') {
messageId += ':' + path[i].substr(1);
}
else {
messageId = path[i].substr(1);
}
}
}
else {
if (messageId) {
messageId += ':' + path[i];
}
else {
messageId = path[i];
}
}
}
}
else {
messageId = id;
}
return messageId;
},
/**
* Merge `this.defaultText` into the target default bundle.
*
* ### TODO:
*
* - Need more research on the effective usage of this feature.
*
* @param {Object} bundle Default bundle.
*/
/*
_mergeDefaultText: function (bundle) {
if (this.defaultText) {
this._deepMap(bundle, this.defaultText, function (text) { return text; });
}
},
*/
/**
* Return the first non-null argument.
*
* Utility method for use in annotations.
*
* ### Example Usage:
* ```
* <input is="iron-input" class="flex"
* type="search" id="query" bind-value="{{query}}"
* autocomplete="off"
* placeholder="{{or(placeholder,text.search)}}">
* ```
*
* @param {*} arguments List of arguments.
*/
or: function () {
var result = arguments[0];
var i = 1;
while (!result && i < arguments.length) {
result = arguments[i++];
}
return result;
},
/**
* Translate a string by a message table.
*
* Utility method for use in annotations.
*
* ### Example Usage:
* ```
* <span>{{tr(status,text.statusMsgs)}}</span>
* <span>{{tr(errorId,text)}}</span>
* <template>
* <json-data text-id="statusMsgs">{
* "signed-in": "Authenticated",
* "signed-out": "Not Authenticated",
* "error": "Error in Authentication",
* "default": "Unknown Status in Authentication"
* }</json-data>
* <span text-id="http-404">File Not Found</span>
* <span text-id="http-301">Moved Permanently</span>
* </template>
* ```
*
* Note: The second `table` parameter should always be specified in order
* to trigger automatic updates on `this.text` mutations, i.e., updates of `this.effectiveLang`.
*
* @param {string} key Key of the message.
* @param {Object} table The message table object or this.text itself if omitted
* @return {string} Translated string, `table.default` if `table[key]` is undefined, or key string if table.default is undefined.
*/
tr: function (key, table) {
if (table) {
if (typeof table === 'object') {
if (typeof table[key] !== 'undefined') {
return table[key];
}
else if (typeof table['default'] !== 'undefined') {
return table['default'];
}
else {
return key;
}
}
else {
return key;
}
}
else {
return (typeof this.text === 'object') &&
(typeof key !== 'undefined') &&
(typeof this.text[key] !== 'undefined') ? this.text[key] : key;
}
},
/**
* Format a parameterized string.
*
* Utility method for use in annotations.
*
* ### Example Usage:
* ```
* <span attr="{{i18nFormat(text.param.0,text.textparam1,text.textparam2)}}"></span>
* <template>
* <json-data text-id="param">[
* "String with {1} and {2} are formetted",
* "[[text.textparam1]]",
* "[[text.textparam2]]"
* ]</json-data>
* <span text-id="textparam1">Parameter 1</span>
* <span text-id="textparam2">Parameter 2</span>
* </template>
* ```
*
* Note: Compound bindings in attributes are automatically converted to {{i18nFormat()}} in preprocessing.
*
* @param {*} arguments List of arguments.
* @return {string} Formatted string
*/
i18nFormat: function () {
if (arguments.length > 0) {
var formatted = arguments[0];
for (var n = 1; n < arguments.length; n++) {
formatted = formatted.replace('{' + n + '}', arguments[n]);
}
}
return formatted;
},
// Lifecycle callbacks
/**
* Lifecycle callback before registration of the custom element.
*
* The default bundle is constructed via traversal of the element's template at this timing per registration.
*
* ### Notes:
*
* - For `i18n-dom-bind` elements, bundle construction is put off until `ready` lifecycle callback.
* - As called twice per custom element registration, the method skips bundle construction at the second call.
*/
beforeRegister: function () {
if (this.is !== 'i18n-dom-bind') {
if (!this._templateLocalizable) {
this._templateLocalizable = this._constructDefaultBundle();
}
}
},
/**
* Lifecycle callback at registration of the custom element.
*
* this._fetchStatus is initialized per registration.
*/
registered: function () {
if (this.is !== 'i18n-dom-bind') {
this._fetchStatus = deepcopy({ // per custom element
fetchingInstance: null,
ajax: null,
ajaxLang: null,
lastLang: null,
fallbackLanguageList: null,
targetLang: null,
lastResponse: {},
rawResponses: {}
});
}
},
/**
* Lifecycle callback on instance creation
*/
created: function () {
// Fix #34. [Polymer 1.4.0] _propertyEffects have to be maintained per instance
if (this.is === 'i18n-dom-bind') {
this._propertyEffects = deepcopy(this._propertyEffects);
}
if (!isStandardPropertyConfigurable) {
// Fix #36. Emulate lang's observer since Safari 7 predefines non-configurable lang property
this.observer = new MutationObserver(this._handleLangAttributeChange.bind(this));
this.observer.observe(this, {
attributes: true,
attributeFilter: [ 'lang' ],
attributeOldValue: true
});
}
},
/**
* Lifecycle callback when the template children are ready.
*/
ready: function () {
if (this.is === 'i18n-dom-bind') {
if (!this._templateLocalizable) {
this._templateLocalizable = this._constructDefaultBundle();
}
if (!this._fetchStatus) {
this._fetchStatus = deepcopy({ // per instance
fetchingInstance: null,
ajax: null,
ajaxLang: null,
lastLang: null,
fallbackLanguageList: null,
targetLang: null,
lastResponse: {},
rawResponses: {}
});
}
this._onDomChangeBindThis = this._onDomChange.bind(this);
this.addEventListener('dom-change', this._onDomChangeBindThis);
// Fix #34. [Polymer 1.4.0] Supply an empty object if this.__data__ is undefined
this.__data__ = this.__data__ || Object.create(null);
}
else {
if (!isStandardPropertyConfigurable) {
// Fix #36. Patch missing properties except for lang
for (var p in this._propertyEffects) {
if (this._propertyEffects[p] &&
!Object.getOwnPropertyDescriptor(this, p)) {
//console.log('ready: creating accessors for ' + p);
Polymer.Bind._createAccessors(this, p, this._propertyEffects[p]);
}
}
}
this._langChanged(this.getAttribute('lang'), undefined);
// model per instance
this.model = deepcopy(this.text.model);
}
},
/**
* attached lifecycle callback.
*/
attached: function () {
if (this.is === 'i18n-dom-bind') {
if (this._properties) {
// Fix #35. [IE10] Restore properties for use in rendering
this.properties = this._properties;
delete this._properties;
}
}
if (this.observeHtmlLang) {
this.lang = html.lang;
// TODO: this call is redundant
this._observeHtmlLangChanged(true);
}
},
/**
* Handle `dom-change` event for `i18n-dom-bind`
*/
_onDomChange: function () {
// Fix #16: [IE11][Polymer 1.3.0] On IE11, i18n-dom-bind does not work with Polymer 1.3.0
// Patch the broken lang property accessors manually if it is missing
// Fix #34: [IE11][Polymer 1.4.0] Create missing property accessors including lang
for (var p in this._propertyEffects) {
if (this._propertyEffects[p] &&
!Object.getOwnPropertyDescriptor(this, p)) {
Polymer.Bind._createAccessors(this, p, this._propertyEffects[p]);
}
}
this.removeEventListener('dom-change', this._onDomChangeBindThis);
if (this.text && this.text.model) {
this.model = deepcopy(this.text.model);
}
// Fix #17: [Polymer 1.3.0] observeHtmlLang is undefined in i18n-dom-bind
// Explicitly initialize observeHtmlLang if the value is undefined.
if (typeof this.observeHtmlLang === 'undefined' &&
!this.hasAttribute('observe-html-lang')) {
this.observeHtmlLang = true;
}
if (this.observeHtmlLang) {
this.lang = html.lang;
this._observeHtmlLangChanged(true);
}
},
/**
* detached lifecycle callback
*/
detached: function () {
if (this.observeHtmlLang) {
this._observeHtmlLangChanged(false);
}
}
};
// Fix #36. Rename lang property as _lang to avoid conflict with the predefined lang property
if (!isStandardPropertyConfigurable) {
var _properties = Object.create(null);
for (var p in BehaviorsStore.I18nBehavior.properties) {
if (p === 'lang') {
_properties._lang = BehaviorsStore.I18nBehavior.properties.lang;
}
else {
_properties[p] = BehaviorsStore.I18nBehavior.properties[p];
}
}
BehaviorsStore.I18nBehavior.properties = _properties;
BehaviorsStore.I18nBehavior.properties._lang.reflectToAttribute = false;
BehaviorsStore.I18nBehavior.properties.text.computed = '_getBundle(_lang)';
BehaviorsStore.I18nBehavior._updateEffectiveLang = function () {
//console.log('lang-updated: _updateEffectiveLang: assigning effectiveLang = ' + this._lang);
this.effectiveLang = this._lang;
};
BehaviorsStore.I18nBehavior.hostAttributes = {
'lang': defaultLang
};
}
/**
* `<template is="i18n-dom-bind">` element extends `dom-bind` template element with `I18nBehavior`
*
* @group I18nBehavior
* @element i18n-dom-bind
*/
var i18nBehaviorDomBind = {};
Base.extend(i18nBehaviorDomBind, BehaviorsStore.I18nBehavior);
var i18nDomBind = {};
var domBind = document.createElement('template', 'dom-bind');
var domBindProto = Object.getPrototypeOf(domBind);
if (typeof domBindProto.render !== 'function') {
domBindProto = domBind.__proto__; // fallback for IE10
}
Base.extend(i18nDomBind, domBindProto);
i18nDomBind.is = 'i18n-dom-bind';
if (!navigator.language && navigator.browserLanguage) { // Detect IE10
// Fix #35. [IE10] Hide properties until attached phase in IE10
// to avoid exceptions in overriding unconfigurable properties in Object.defineProperty
i18nBehaviorDomBind._properties = i18nBehaviorDomBind.properties;
i18nBehaviorDomBind.properties = Object.create(null);
}
/* As of Polymer 1.3.1, dom-bind does not have predefined behaviors */
/* istanbul ignore if */
if (i18nDomBind.behaviors) {
i18nDomBind.behaviors.push(i18nBehaviorDomBind);
}
else {
i18nDomBind.behaviors = [ i18nBehaviorDomBind ];
}
var _Polymer = Polymer$0;
_Polymer(i18nDomBind);
})(document);
</script>
<dom-module id="simple-text-element" assetpath="simple-text-element/">
<template localizable-text="embedded">{{text.text}}<div><div></div></div>
<span id="whitespace"> </span>
<h1>{{text.h1_3}}</h1>{{text.text_4}}<span>{{text.span_5}}</span>
<span>{{text.span_6}}</span>
<span id="label-1">{{text.label-1}}</span>
<span id="label-2">{{text.label-2}}</span>
<div>
<span>{{text.div_9:span}}</span>
<span>{{text.div_9:span_1}}</span>
<div><div>{{text.div_9:div_2:div}}</div></div>
</div>
<div>{{text.div_10:text}}<span>{{text.div_10:span_1}}</span>{{text.div_10:text_2}}<span>{{text.div_10:span_3}}</span>
<div><div>{{text.div_10:div_4:div}}</div></div>{{text.div_10:text_5}}</div>
<div id="toplevel-div">
<span>{{text.toplevel-div:span}}</span>
<span>{{text.toplevel-div:span_1}}</span>
<div id="second-level-div">
<div id="third-level-div">{{text.third-level-div}}</div>
<div>{{text.second-level-div:div_1}}</div>
</div>
</div>
<div>
<ul>
<li>{{text.div_12:ul:li}}</li>
<li>{{text.div_12:ul:li_1}}</li>
<li>{{text.div_12:ul:li_2}}</li>
</ul>
<ul id="line-items">
<li>{{text.line-items:li}}</li>
<li>{{text.line-items:li_1}}</li>
<li>{{text.line-items:li_2}}</li>
</ul>
</div>
<p><i18n-format lang="{{effectiveLang}}"><span>{{text.p_13.0}}</span><b param="1">{{text.p_13.1}}</b><code param="2">{{text.p_13.2}}</code></i18n-format></p>
<p id="paragraph"><i18n-format lang="{{effectiveLang}}"><span>{{text.paragraph.0}}</span><b param="1">{{text.paragraph.1}}</b><code param="2">{{text.paragraph.2}}</code></i18n-format></p>{{text.text_15}}<template id="localizable-text">
<json-data>
{
"meta": {},
"model": {},
"text": " outermost text at the beginning ",
"h1_3": "outermost header 1",
"text_4": " outermost text in the middle ",
"span_5": "simple text without id",
"span_6": "simple text without id 2",
"label-1": "simple text with id",
"label-2": "simple text with id 2",
"div_9:span": "simple text within div",
"div_9:span_1": "simple text within div 2",
"div_9:div_2:div": "great grandchild text within div",
"div_10:text": " simple text as the first element in div ",
"div_10:span_1": "simple text within div",
"div_10:text_2": " simple text in the middle of div ",
"div_10:span_3": "simple text within div 2",
"div_10:div_4:div": "great grandchild text within div",
"div_10:text_5": " simple text at the last element in div ",
"toplevel-div:span": "simple text within div",
"toplevel-div:span_1": "simple text within div 2",
"third-level-div": "great grandchild text within div",
"second-level-div:div_1": "great grandchild text within div without id",
"div_12:ul:li": "line item without id 1",
"div_12:ul:li_1": "line item without id 2",
"div_12:ul:li_2": "line item without id 3",
"line-items:li": "line item with id 1",
"line-items:li_1": "line item with id 2",
"line-items:li_2": "line item with id 3",
"p_13": [
"A paragraph with {1} is converted to {2}.",
"parameters",
"<i18n-format>"
],
"paragraph": [
"A paragraph with {1} is converted to {2}.",
"id",
"<i18n-format>"
],
"text_15": " outermost text at the end "
}
</json-data>
</template>
</template>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
Polymer({
is: 'simple-text-element',
behaviors: [
BehaviorsStore.I18nBehavior
],
properties: {
},
observers: [
],
listeners: {
'lang-updated': '_langUpdated'
},
ready: function () {
//this.observeHtmlLang = false;
},
attached: function () {
},
_langUpdated: function (e) {
if (dom(e).rootTarget === this) {
this.model = deepcopy(this.text.model);
}
}
});
</script>
</dom-module>
<dom-module id="commented-simple-text-element" assetpath="commented-simple-text-element/">
<template localizable-text="embedded">{{text.text}}
<div><div></div></div>
<span id="whitespace"> </span>
<h1>{{text.h1_3}}</h1>{{text.text_4}}
<span>{{text.span_5}}</span>
<span>{{text.span_6}}</span>
<span id="label-1">{{text.label-1}}</span>
<span id="label-2">{{text.label-2}}</span>
<div>
<span>{{text.div_9:span}}</span>
<span>{{text.div_9:span_1}}</span>
<div><div>{{text.div_9:div_2:div}}</div></div>
</div>
<div>{{text.div_10:text}}
<span>{{text.div_10:span_1}}</span>{{text.div_10:text_2}}
<span>{{text.div_10:span_3}}</span>
<div><div>{{text.div_10:div_4:div}}</div></div>{{text.div_10:text_5}}</div>
<div id="toplevel-div">
<span>{{text.toplevel-div:span}}</span>
<span>{{text.toplevel-div:span_1}}</span>
<div id="second-level-div">
<div id="third-level-div">{{text.third-level-div}}</div>
<div>{{text.second-level-div:div_1}}</div>
</div>
</div>
<div>
<ul>
<li>{{text.div_12:ul:li}}</li>
<li>{{text.div_12:ul:li_1}}</li>
<li>{{text.div_12:ul:li_2}}</li>
</ul>
<ul id="line-items">
<li>{{text.line-items:li}}</li>
<li>{{text.line-items:li_1}}</li>
<li>{{text.line-items:li_2}}</li>
</ul>
</div>
<p><i18n-format lang="{{effectiveLang}}"><span>{{text.p_13.0}}</span><b param="1">{{text.p_13.1}}</b><code param="2">{{text.p_13.2}}</code></i18n-format></p>
<p id="paragraph"><i18n-format lang="{{effectiveLang}}"><span>{{text.paragraph.0}}</span><b param="1">{{text.paragraph.1}}</b><code param="2">{{text.paragraph.2}}</code></i18n-format></p>{{text.text_15}}
<template id="localizable-text">
<json-data>
{
"meta": {},
"model": {},
"text": " outermost text at the beginning ",
"h1_3": "outermost header 1",
"text_4": " outermost text in the middle ",
"span_5": "simple text without id",
"span_6": "simple text without id 2",
"label-1": "simple text with id",
"label-2": "simple text with id 2",
"div_9:span": "simple text within div",
"div_9:span_1": "simple text within div 2",
"div_9:div_2:div": "great grandchild text within div",
"div_10:text": " simple text as the first element in div ",
"div_10:span_1": "simple text within div",
"div_10:text_2": " simple text in the middle of div ",
"div_10:span_3": "simple text within div 2",
"div_10:div_4:div": "great grandchild text within div",
"div_10:text_5": " simple text at the last element in div ",
"toplevel-div:span": "simple text within div",
"toplevel-div:span_1": "simple text within div 2",
"third-level-div": "great grandchild text within div",
"second-level-div:div_1": "great grandchild text within div without id",
"div_12:ul:li": "line item without id 1",
"div_12:ul:li_1": "line item without id 2",
"div_12:ul:li_2": "line item without id 3",
"line-items:li": "line item with id 1",
"line-items:li_1": "line item with id 2",
"line-items:li_2": "line item with id 3",
"p_13": [
"A paragraph with {1} is converted to {2}.",
"parameters",
"<i18n-format>"
],
"paragraph": [
"A paragraph with {1} is converted to {2}.",
"id",
"<i18n-format>"
],
"text_15": " outermost text at the end "
}
</json-data>
</template>
</template>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
Polymer({
is: 'commented-simple-text-element',
behaviors: [
BehaviorsStore.I18nBehavior
],
properties: {
},
observers: [
],
listeners: {
'lang-updated': '_langUpdated'
},
ready: function () {
//this.observeHtmlLang = false;
},
attached: function () {
},
_langUpdated: function () {
this.model = deepcopy(this.text.model);
}
});
</script>
</dom-module>
<dom-module id="plural-gender-element" assetpath="plural-gender-element/">
<template localizable-text="embedded">
<p>
<i18n-format id="compound-format-text" lang="{{effectiveLang}}">
<json-data>{{serialize(text.compound-format-text.0)}}</json-data>
<i18n-number offset="1" param="1" lang="{{effectiveLang}}">{{recipients.length}}</i18n-number>
<span param="2">{{recipients.0.gender}}</span>
<span param="3">{{sender.name}}</span>
<span param="4">{{recipients.0.name}}</span>
<span param="5">{{text.compound-format-text.5}}</span>
</i18n-format>
</p>
<template id="localizable-text">
<json-data>
{
"meta": {},
"model": {},
"compound-format-text": [
{
"0": "You ({3}) gave no gifts.",
"1": {
"male": "You ({3}) gave him ({4}) {5}.",
"female": "You ({3}) gave her ({4}) {5}.",
"other": "You ({3}) gave them ({4}) {5}."
},
"one": {
"male": "You ({3}) gave him ({4}) and one other person {5}.",
"female": "You ({3}) gave her ({4}) and one other person {5}.",
"other": "You ({3}) gave them ({4}) and one other person {5}."
},
"other": "You ({3}) gave them ({4}) and {1} other people gifts."
},
"{{recipients.length - 1}}",
"{{recipients.0.gender}}",
"{{sender.name}}",
"{{recipients.0.name}}",
"a gift"
]
}
</json-data>
</template>
</template>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
Polymer({
is: 'plural-gender-element',
behaviors: [
BehaviorsStore.I18nBehavior
],
properties: {
sender: {
type: Object
},
recipients: {
type: Array
}
},
observers: [
],
listeners: {
'lang-updated': '_langUpdated',
'compound-format-text.rendered': '_rendered'
},
attached: function () {
},
_langUpdated: function () {
console.log('plural-gender-element lang-updated lang = ' + this.lang + ' effectiveLang = ' + this.effectiveLang);
this.model = deepcopy(this.text.model);
if (this.renderedEffectiveLang === this.effectiveLang ||
(this.renderedEffectiveLang === '' && this.effectiveLang === 'en')) {
this.fire('local-dom-ready');
}
},
_rendered: function () {
console.log('plural-gender-element rendered lang = ' + this.lang + ' effectiveLang = ' + this.effectiveLang);
if (this.lang === this.effectiveLang) {
this.fire('local-dom-ready');
}
else {
this.renderedEffectiveLang = this.effectiveLang;
}
}
});
</script>
</dom-module>
<script>
/**
Polymer.IronFormElementBehavior enables a custom element to be included
in an `iron-form`.
@demo demo/index.html
@polymerBehavior
*/
Polymer.IronFormElementBehavior = {
properties: {
/**
* Fired when the element is added to an `iron-form`.
*
* @event iron-form-element-register
*/
/**
* Fired when the element is removed from an `iron-form`.
*
* @event iron-form-element-unregister
*/
/**
* The name of this element.
*/
name: {
type: String
},
/**
* The value for this element.
*/
value: {
notify: true,
type: String
},
/**
* Set to true to mark the input as required. If used in a form, a
* custom element that uses this behavior should also use
* Polymer.IronValidatableBehavior and define a custom validation method.
* Otherwise, a `required` element will always be considered valid.
* It's also strongly recommended to provide a visual style for the element
* when its value is invalid.
*/
required: {
type: Boolean,
value: false
},
/**
* The form that the element is registered to.
*/
_parentForm: {
type: Object
}
},
attached: function() {
// Note: the iron-form that this element belongs to will set this
// element's _parentForm property when handling this event.
this.fire('iron-form-element-register');
},
detached: function() {
if (this._parentForm) {
this._parentForm.fire('iron-form-element-unregister', {target: this});
}
}
};
</script>
<dom-module id="iron-a11y-announcer" assetpath="../../../iron-a11y-announcer/">
<template>
<style>
:host {
display: inline-block;
position: fixed;
clip: rect(0px,0px,0px,0px);
}
</style>
<div aria-live$="[[mode]]">[[_text]]</div>
</template>
<script type="module">
import { Polymer as Polymer$0 } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { IronA11yAnnouncer as IronA11yAnnouncer$0 } from '@polymer/iron-a11y-announcer/iron-a11y-announcer.js';
export const IronA11yAnnouncer = Polymer$0({
is: 'iron-a11y-announcer',
properties: {
/**
* The value of mode is used to set the `aria-live` attribute
* for the element that will be announced. Valid values are: `off`,
* `polite` and `assertive`.
*/
mode: {
type: String,
value: 'polite'
},
_text: {
type: String,
value: ''
}
},
created: function() {
if (!IronA11yAnnouncer$0.instance) {
IronA11yAnnouncer$0.instance = this;
}
document.body.addEventListener('iron-announce', this._onIronAnnounce.bind(this));
},
/**
* Cause a text string to be announced by screen readers.
*
* @param {string} text The text that should be announced.
*/
announce: function(text) {
this._text = '';
this.async(function() {
this._text = text;
}, 100);
},
_onIronAnnounce: function(event) {
if (event.detail && event.detail.text) {
this.announce(event.detail.text);
}
}
});
IronA11yAnnouncer$0.instance = null;
IronA11yAnnouncer$0.requestAvailability = function() {
if (!IronA11yAnnouncer$0.instance) {
IronA11yAnnouncer$0.instance = document.createElement('iron-a11y-announcer');
}
document.body.appendChild(IronA11yAnnouncer$0.instance);
};
</script>
</dom-module>
<script type="module">
import { Polymer as Polymer$0 } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { IronMeta as IronMeta$0 } from '@polymer/iron-meta/iron-meta.js';
// monostate data
var metaDatas = {};
var metaArrays = {};
var singleton = null;
export const IronMeta = Polymer$0({
is: 'iron-meta',
properties: {
/**
* The type of meta-data. All meta-data of the same type is stored
* together.
*/
type: {
type: String,
value: 'default',
observer: '_typeChanged'
},
/**
* The key used to store `value` under the `type` namespace.
*/
key: {
type: String,
observer: '_keyChanged'
},
/**
* The meta-data to store or retrieve.
*/
value: {
type: Object,
notify: true,
observer: '_valueChanged'
},
/**
* If true, `value` is set to the iron-meta instance itself.
*/
self: {
type: Boolean,
observer: '_selfChanged'
},
/**
* Array of all meta-data values for the given type.
*/
list: {
type: Array,
notify: true
}
},
hostAttributes: {
hidden: true
},
/**
* Only runs if someone invokes the factory/constructor directly
* e.g. `new Polymer.IronMeta()`
*
* @param {{type: (string|undefined), key: (string|undefined), value}=} config
*/
factoryImpl: function(config) {
if (config) {
for (var n in config) {
switch(n) {
case 'type':
case 'key':
case 'value':
this[n] = config[n];
break;
}
}
}
},
created: function() {
// TODO(sjmiles): good for debugging?
this._metaDatas = metaDatas;
this._metaArrays = metaArrays;
},
_keyChanged: function(key, old) {
this._resetRegistration(old);
},
_valueChanged: function(value) {
this._resetRegistration(this.key);
},
_selfChanged: function(self) {
if (self) {
this.value = this;
}
},
_typeChanged: function(type) {
this._unregisterKey(this.key);
if (!metaDatas[type]) {
metaDatas[type] = {};
}
this._metaData = metaDatas[type];
if (!metaArrays[type]) {
metaArrays[type] = [];
}
this.list = metaArrays[type];
this._registerKeyValue(this.key, this.value);
},
/**
* Retrieves meta data value by key.
*
* @method byKey
* @param {string} key The key of the meta-data to be returned.
* @return {*}
*/
byKey: function(key) {
return this._metaData && this._metaData[key];
},
_resetRegistration: function(oldKey) {
this._unregisterKey(oldKey);
this._registerKeyValue(this.key, this.value);
},
_unregisterKey: function(key) {
this._unregister(key, this._metaData, this.list);
},
_registerKeyValue: function(key, value) {
this._register(key, value, this._metaData, this.list);
},
_register: function(key, value, data, list) {
if (key && data && value !== undefined) {
data[key] = value;
list.push(value);
}
},
_unregister: function(key, data, list) {
if (key && data) {
if (key in data) {
var value = data[key];
delete data[key];
this.arrayDelete(list, value);
}
}
}
});
IronMeta$0.getIronMeta = function getIronMeta() {
if (singleton === null) {
singleton = new IronMeta$0();
}
return singleton;
};
/**
`iron-meta-query` can be used to access infomation stored in `iron-meta`.
Examples:
If I create an instance like this:
<iron-meta key="info" value="foo/bar"></iron-meta>
Note that value="foo/bar" is the metadata I've defined. I could define more
attributes or use child nodes to define additional metadata.
Now I can access that element (and it's metadata) from any `iron-meta-query` instance:
var value = new Polymer.IronMetaQuery({key: 'info'}).value;
@group Polymer Iron Elements
@element iron-meta-query
*/
export const IronMetaQuery = Polymer$0({
is: 'iron-meta-query',
properties: {
/**
* The type of meta-data. All meta-data of the same type is stored
* together.
*/
type: {
type: String,
value: 'default',
observer: '_typeChanged'
},
/**
* Specifies a key to use for retrieving `value` from the `type`
* namespace.
*/
key: {
type: String,
observer: '_keyChanged'
},
/**
* The meta-data to store or retrieve.
*/
value: {
type: Object,
notify: true,
readOnly: true
},
/**
* Array of all meta-data values for the given type.
*/
list: {
type: Array,
notify: true
}
},
/**
* Actually a factory method, not a true constructor. Only runs if
* someone invokes it directly (via `new Polymer.IronMeta()`);
*
* @param {{type: (string|undefined), key: (string|undefined)}=} config
*/
factoryImpl: function(config) {
if (config) {
for (var n in config) {
switch(n) {
case 'type':
case 'key':
this[n] = config[n];
break;
}
}
}
},
created: function() {
// TODO(sjmiles): good for debugging?
this._metaDatas = metaDatas;
this._metaArrays = metaArrays;
},
_keyChanged: function(key) {
this._setValue(this._metaData && this._metaData[key]);
},
_typeChanged: function(type) {
this._metaData = metaDatas[type];
this.list = metaArrays[type];
if (this.key) {
this._keyChanged(this.key);
}
},
/**
* Retrieves meta data value by key.
* @param {string} key The key of the meta-data to be returned.
* @return {*}
*/
byKey: function(key) {
return this._metaData && this._metaData[key];
}
});
</script>
<script type="module">
import { IronMeta } from '@polymer/iron-meta/iron-meta.js';
import { IronValidatableBehaviorMeta as IronValidatableBehaviorMeta$0 } from '@polymer/iron-validatable-behavior/iron-validatable-behavior.js';
/**
* Singleton IronMeta instance.
*/
export let IronValidatableBehaviorMeta = null;
/**
* `Use Polymer.IronValidatableBehavior` to implement an element that validates user input.
* Use the related `Polymer.IronValidatorBehavior` to add custom validation logic to an iron-input.
*
* By default, an `<iron-form>` element validates its fields when the user presses the submit button.
* To validate a form imperatively, call the form's `validate()` method, which in turn will
* call `validate()` on all its children. By using `Polymer.IronValidatableBehavior`, your
* custom element will get a public `validate()`, which
* will return the validity of the element, and a corresponding `invalid` attribute,
* which can be used for styling.
*
* To implement the custom validation logic of your element, you must override
* the protected `_getValidity()` method of this behaviour, rather than `validate()`.
* See [this](https://github.com/PolymerElements/iron-form/blob/master/demo/simple-element.html)
* for an example.
*
* ### Accessibility
*
* Changing the `invalid` property, either manually or by calling `validate()` will update the
* `aria-invalid` attribute.
*
* @demo demo/index.html
* @polymerBehavior
*/
export const IronValidatableBehavior = {
properties: {
/**
* Name of the validator to use.
*/
validator: {
type: String
},
/**
* True if the last call to `validate` is invalid.
*/
invalid: {
notify: true,
reflectToAttribute: true,
type: Boolean,
value: false
},
/**
* This property is deprecated and should not be used. Use the global
* validator meta singleton, `Polymer.IronValidatableBehaviorMeta` instead.
*/
_validatorMeta: {
type: Object
},
/**
* Namespace for this validator. This property is deprecated and should
* not be used. For all intents and purposes, please consider it a
* read-only, config-time property.
*/
validatorType: {
type: String,
value: 'validator'
},
_validator: {
type: Object,
computed: '__computeValidator(validator)'
}
},
observers: [
'_invalidChanged(invalid)'
],
registered: function() {
IronValidatableBehaviorMeta = new IronMeta({type: 'validator'});
},
_invalidChanged: function() {
if (this.invalid) {
this.setAttribute('aria-invalid', 'true');
} else {
this.removeAttribute('aria-invalid');
}
},
/**
* @return {boolean} True if the validator `validator` exists.
*/
hasValidator: function() {
return this._validator != null;
},
/**
* Returns true if the `value` is valid, and updates `invalid`. If you want
* your element to have custom validation logic, do not override this method;
* override `_getValidity(value)` instead.
* @param {Object} value The value to be validated. By default, it is passed
* to the validator's `validate()` function, if a validator is set.
* @return {boolean} True if `value` is valid.
*/
validate: function(value) {
this.invalid = !this._getValidity(value);
return !this.invalid;
},
/**
* Returns true if `value` is valid. By default, it is passed
* to the validator's `validate()` function, if a validator is set. You
* should override this method if you want to implement custom validity
* logic for your element.
*
* @param {Object} value The value to be validated.
* @return {boolean} True if `value` is valid.
*/
_getValidity: function(value) {
if (this.hasValidator()) {
return this._validator.validate(value);
}
return true;
},
__computeValidator: function() {
return IronValidatableBehaviorMeta$0 &&
IronValidatableBehaviorMeta$0.byKey(this.validator);
}
};
</script>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { IronValidatableBehavior } from '@polymer/iron-validatable-behavior/iron-validatable-behavior.js';
import { IronA11yAnnouncer } from '@polymer/iron-a11y-announcer/iron-a11y-announcer.js';
/*
`<iron-input>` adds two-way binding and custom validators using `Polymer.IronValidatorBehavior`
to `<input>`.
### Two-way binding
By default you can only get notified of changes to an `input`'s `value` due to user input:
<input value="{{myValue::input}}">
`iron-input` adds the `bind-value` property that mirrors the `value` property, and can be used
for two-way data binding. `bind-value` will notify if it is changed either by user input or by script.
<input is="iron-input" bind-value="{{myValue}}">
### Custom validators
You can use custom validators that implement `Polymer.IronValidatorBehavior` with `<iron-input>`.
<input is="iron-input" validator="my-custom-validator">
### Stopping invalid input
It may be desirable to only allow users to enter certain characters. You can use the
`prevent-invalid-input` and `allowed-pattern` attributes together to accomplish this. This feature
is separate from validation, and `allowed-pattern` does not affect how the input is validated.
<!-- only allow characters that match [0-9] -->
<input is="iron-input" prevent-invalid-input allowed-pattern="[0-9]">
@hero hero.svg
@demo demo/index.html
*/
Polymer({
is: 'iron-input',
extends: 'input',
behaviors: [
IronValidatableBehavior
],
properties: {
/**
* Use this property instead of `value` for two-way data binding.
*/
bindValue: {
observer: '_bindValueChanged',
type: String
},
/**
* Set to true to prevent the user from entering invalid input. If `allowedPattern` is set,
* any character typed by the user will be matched against that pattern, and rejected if it's not a match.
* Pasted input will have each character checked individually; if any character
* doesn't match `allowedPattern`, the entire pasted string will be rejected.
* If `allowedPattern` is not set, it will use the `type` attribute (only supported for `type=number`).
*/
preventInvalidInput: {
type: Boolean
},
/**
* Regular expression that list the characters allowed as input.
* This pattern represents the allowed characters for the field; as the user inputs text,
* each individual character will be checked against the pattern (rather than checking
* the entire value as a whole). The recommended format should be a list of allowed characters;
* for example, `[a-zA-Z0-9.+-!;:]`
*/
allowedPattern: {
type: String,
observer: "_allowedPatternChanged"
},
_previousValidInput: {
type: String,
value: ''
},
_patternAlreadyChecked: {
type: Boolean,
value: false
}
},
listeners: {
'input': '_onInput',
'keypress': '_onKeypress'
},
/** @suppress {checkTypes} */
registered: function() {
// Feature detect whether we need to patch dispatchEvent (i.e. on FF and IE).
if (!this._canDispatchEventOnDisabled()) {
this._origDispatchEvent = this.dispatchEvent;
this.dispatchEvent = this._dispatchEventFirefoxIE;
}
},
created: function() {
IronA11yAnnouncer.requestAvailability();
},
_canDispatchEventOnDisabled: function() {
var input = document.createElement('input');
var canDispatch = false;
input.disabled = true;
input.addEventListener('feature-check-dispatch-event', function() {
canDispatch = true;
});
try {
input.dispatchEvent(new Event('feature-check-dispatch-event'));
} catch(e) {}
return canDispatch;
},
_dispatchEventFirefoxIE: function() {
// Due to Firefox bug, events fired on disabled form controls can throw
// errors; furthermore, neither IE nor Firefox will actually dispatch
// events from disabled form controls; as such, we toggle disable around
// the dispatch to allow notifying properties to notify
// See issue #47 for details
var disabled = this.disabled;
this.disabled = false;
this._origDispatchEvent.apply(this, arguments);
this.disabled = disabled;
},
get _patternRegExp() {
var pattern;
if (this.allowedPattern) {
pattern = new RegExp(this.allowedPattern);
} else {
switch (this.type) {
case 'number':
pattern = /[0-9.,e-]/;
break;
}
}
return pattern;
},
ready: function() {
this.bindValue = this.value;
},
/**
* @suppress {checkTypes}
*/
_bindValueChanged: function() {
if (this.value !== this.bindValue) {
this.value = !(this.bindValue || this.bindValue === 0 || this.bindValue === false) ? '' : this.bindValue;
}
// manually notify because we don't want to notify until after setting value
this.fire('bind-value-changed', {value: this.bindValue});
},
_allowedPatternChanged: function() {
// Force to prevent invalid input when an `allowed-pattern` is set
this.preventInvalidInput = this.allowedPattern ? true : false;
},
_onInput: function() {
// Need to validate each of the characters pasted if they haven't
// been validated inside `_onKeypress` already.
if (this.preventInvalidInput && !this._patternAlreadyChecked) {
var valid = this._checkPatternValidity();
if (!valid) {
this._announceInvalidCharacter('Invalid string of characters not entered.');
this.value = this._previousValidInput;
}
}
this.bindValue = this.value;
this._previousValidInput = this.value;
this._patternAlreadyChecked = false;
},
_isPrintable: function(event) {
// What a control/printable character is varies wildly based on the browser.
// - most control characters (arrows, backspace) do not send a `keypress` event
// in Chrome, but the *do* on Firefox
// - in Firefox, when they do send a `keypress` event, control chars have
// a charCode = 0, keyCode = xx (for ex. 40 for down arrow)
// - printable characters always send a keypress event.
// - in Firefox, printable chars always have a keyCode = 0. In Chrome, the keyCode
// always matches the charCode.
// None of this makes any sense.
// For these keys, ASCII code == browser keycode.
var anyNonPrintable =
(event.keyCode == 8) || // backspace
(event.keyCode == 9) || // tab
(event.keyCode == 13) || // enter
(event.keyCode == 27); // escape
// For these keys, make sure it's a browser keycode and not an ASCII code.
var mozNonPrintable =
(event.keyCode == 19) || // pause
(event.keyCode == 20) || // caps lock
(event.keyCode == 45) || // insert
(event.keyCode == 46) || // delete
(event.keyCode == 144) || // num lock
(event.keyCode == 145) || // scroll lock
(event.keyCode > 32 && event.keyCode < 41) || // page up/down, end, home, arrows
(event.keyCode > 111 && event.keyCode < 124); // fn keys
return !anyNonPrintable && !(event.charCode == 0 && mozNonPrintable);
},
_onKeypress: function(event) {
if (!this.preventInvalidInput && this.type !== 'number') {
return;
}
var regexp = this._patternRegExp;
if (!regexp) {
return;
}
// Handle special keys and backspace
if (event.metaKey || event.ctrlKey || event.altKey)
return;
// Check the pattern either here or in `_onInput`, but not in both.
this._patternAlreadyChecked = true;
var thisChar = String.fromCharCode(event.charCode);
if (this._isPrintable(event) && !regexp.test(thisChar)) {
event.preventDefault();
this._announceInvalidCharacter('Invalid character ' + thisChar + ' not entered.');
}
},
_checkPatternValidity: function() {
var regexp = this._patternRegExp;
if (!regexp) {
return true;
}
for (var i = 0; i < this.value.length; i++) {
if (!regexp.test(this.value[i])) {
return false;
}
}
return true;
},
/**
* Returns true if `value` is valid. The validator provided in `validator` will be used first,
* then any constraints.
* @return {boolean} True if the value is valid.
*/
validate: function() {
// First, check what the browser thinks. Some inputs (like type=number)
// behave weirdly and will set the value to "" if something invalid is
// entered, but will set the validity correctly.
var valid = this.checkValidity();
// Only do extra checking if the browser thought this was valid.
if (valid) {
// Empty, required input is invalid
if (this.required && this.value === '') {
valid = false;
} else if (this.hasValidator()) {
valid = IronValidatableBehavior.validate.call(this, this.value);
}
}
this.invalid = !valid;
this.fire('iron-input-validate');
return valid;
},
_announceInvalidCharacter: function(message) {
this.fire('iron-announce', { text: message });
}
});
/*
The `iron-input-validate` event is fired whenever `validate()` is called.
@event iron-input-validate
*/
</script>
<script>
(function() {
'use strict';
/**
* Chrome uses an older version of DOM Level 3 Keyboard Events
*
* Most keys are labeled as text, but some are Unicode codepoints.
* Values taken from: http://www.w3.org/TR/2007/WD-DOM-Level-3-Events-20071221/keyset.html#KeySet-Set
*/
var KEY_IDENTIFIER = {
'U+0008': 'backspace',
'U+0009': 'tab',
'U+001B': 'esc',
'U+0020': 'space',
'U+007F': 'del'
};
/**
* Special table for KeyboardEvent.keyCode.
* KeyboardEvent.keyIdentifier is better, and KeyBoardEvent.key is even better
* than that.
*
* Values from: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.keyCode#Value_of_keyCode
*/
var KEY_CODE = {
8: 'backspace',
9: 'tab',
13: 'enter',
27: 'esc',
33: 'pageup',
34: 'pagedown',
35: 'end',
36: 'home',
32: 'space',
37: 'left',
38: 'up',
39: 'right',
40: 'down',
46: 'del',
106: '*'
};
/**
* MODIFIER_KEYS maps the short name for modifier keys used in a key
* combo string to the property name that references those same keys
* in a KeyboardEvent instance.
*/
var MODIFIER_KEYS = {
'shift': 'shiftKey',
'ctrl': 'ctrlKey',
'alt': 'altKey',
'meta': 'metaKey'
};
/**
* KeyboardEvent.key is mostly represented by printable character made by
* the keyboard, with unprintable keys labeled nicely.
*
* However, on OS X, Alt+char can make a Unicode character that follows an
* Apple-specific mapping. In this case, we fall back to .keyCode.
*/
var KEY_CHAR = /[a-z0-9*]/;
/**
* Matches a keyIdentifier string.
*/
var IDENT_CHAR = /U\+/;
/**
* Matches arrow keys in Gecko 27.0+
*/
var ARROW_KEY = /^arrow/;
/**
* Matches space keys everywhere (notably including IE10's exceptional name
* `spacebar`).
*/
var SPACE_KEY = /^space(bar)?/;
/**
* Matches ESC key.
*
* Value from: http://w3c.github.io/uievents-key/#key-Escape
*/
var ESC_KEY = /^escape$/;
/**
* Transforms the key.
* @param {string} key The KeyBoardEvent.key
* @param {Boolean} [noSpecialChars] Limits the transformation to
* alpha-numeric characters.
*/
function transformKey(key, noSpecialChars) {
var validKey = '';
if (key) {
var lKey = key.toLowerCase();
if (lKey === ' ' || SPACE_KEY.test(lKey)) {
validKey = 'space';
} else if (ESC_KEY.test(lKey)) {
validKey = 'esc';
} else if (lKey.length == 1) {
if (!noSpecialChars || KEY_CHAR.test(lKey)) {
validKey = lKey;
}
} else if (ARROW_KEY.test(lKey)) {
validKey = lKey.replace('arrow', '');
} else if (lKey == 'multiply') {
// numpad '*' can map to Multiply on IE/Windows
validKey = '*';
} else {
validKey = lKey;
}
}
return validKey;
}
function transformKeyIdentifier(keyIdent) {
var validKey = '';
if (keyIdent) {
if (keyIdent in KEY_IDENTIFIER) {
validKey = KEY_IDENTIFIER[keyIdent];
} else if (IDENT_CHAR.test(keyIdent)) {
keyIdent = parseInt(keyIdent.replace('U+', '0x'), 16);
validKey = String.fromCharCode(keyIdent).toLowerCase();
} else {
validKey = keyIdent.toLowerCase();
}
}
return validKey;
}
function transformKeyCode(keyCode) {
var validKey = '';
if (Number(keyCode)) {
if (keyCode >= 65 && keyCode <= 90) {
// ascii a-z
// lowercase is 32 offset from uppercase
validKey = String.fromCharCode(32 + keyCode);
} else if (keyCode >= 112 && keyCode <= 123) {
// function keys f1-f12
validKey = 'f' + (keyCode - 112);
} else if (keyCode >= 48 && keyCode <= 57) {
// top 0-9 keys
validKey = String(keyCode - 48);
} else if (keyCode >= 96 && keyCode <= 105) {
// num pad 0-9
validKey = String(keyCode - 96);
} else {
validKey = KEY_CODE[keyCode];
}
}
return validKey;
}
/**
* Calculates the normalized key for a KeyboardEvent.
* @param {KeyboardEvent} keyEvent
* @param {Boolean} [noSpecialChars] Set to true to limit keyEvent.key
* transformation to alpha-numeric chars. This is useful with key
* combinations like shift + 2, which on FF for MacOS produces
* keyEvent.key = @
* To get 2 returned, set noSpecialChars = true
* To get @ returned, set noSpecialChars = false
*/
function normalizedKeyForEvent(keyEvent, noSpecialChars) {
// Fall back from .key, to .keyIdentifier, to .keyCode, and then to
// .detail.key to support artificial keyboard events.
return transformKey(keyEvent.key, noSpecialChars) ||
transformKeyIdentifier(keyEvent.keyIdentifier) ||
transformKeyCode(keyEvent.keyCode) ||
transformKey(keyEvent.detail ? keyEvent.detail.key : keyEvent.detail, noSpecialChars) || '';
}
function keyComboMatchesEvent(keyCombo, event) {
// For combos with modifiers we support only alpha-numeric keys
var keyEvent = normalizedKeyForEvent(event, keyCombo.hasModifiers);
return keyEvent === keyCombo.key &&
(!keyCombo.hasModifiers || (
!!event.shiftKey === !!keyCombo.shiftKey &&
!!event.ctrlKey === !!keyCombo.ctrlKey &&
!!event.altKey === !!keyCombo.altKey &&
!!event.metaKey === !!keyCombo.metaKey)
);
}
function parseKeyComboString(keyComboString) {
if (keyComboString.length === 1) {
return {
combo: keyComboString,
key: keyComboString,
event: 'keydown'
};
}
return keyComboString.split('+').reduce(function(parsedKeyCombo, keyComboPart) {
var eventParts = keyComboPart.split(':');
var keyName = eventParts[0];
var event = eventParts[1];
if (keyName in MODIFIER_KEYS) {
parsedKeyCombo[MODIFIER_KEYS[keyName]] = true;
parsedKeyCombo.hasModifiers = true;
} else {
parsedKeyCombo.key = keyName;
parsedKeyCombo.event = event || 'keydown';
}
return parsedKeyCombo;
}, {
combo: keyComboString.split(':').shift()
});
}
function parseEventString(eventString) {
return eventString.trim().split(' ').map(function(keyComboString) {
return parseKeyComboString(keyComboString);
});
}
/**
* `Polymer.IronA11yKeysBehavior` provides a normalized interface for processing
* keyboard commands that pertain to [WAI-ARIA best practices](http://www.w3.org/TR/wai-aria-practices/#kbd_general_binding).
* The element takes care of browser differences with respect to Keyboard events
* and uses an expressive syntax to filter key presses.
*
* Use the `keyBindings` prototype property to express what combination of keys
* will trigger the callback. A key binding has the format
* `"KEY+MODIFIER:EVENT": "callback"` (`"KEY": "callback"` or
* `"KEY:EVENT": "callback"` are valid as well). Some examples:
*
* keyBindings: {
* 'space': '_onKeydown', // same as 'space:keydown'
* 'shift+tab': '_onKeydown',
* 'enter:keypress': '_onKeypress',
* 'esc:keyup': '_onKeyup'
* }
*
* The callback will receive with an event containing the following information in `event.detail`:
*
* _onKeydown: function(event) {
* console.log(event.detail.combo); // KEY+MODIFIER, e.g. "shift+tab"
* console.log(event.detail.key); // KEY only, e.g. "tab"
* console.log(event.detail.event); // EVENT, e.g. "keydown"
* console.log(event.detail.keyboardEvent); // the original KeyboardEvent
* }
*
* Use the `keyEventTarget` attribute to set up event handlers on a specific
* node.
*
* See the [demo source code](https://github.com/PolymerElements/iron-a11y-keys-behavior/blob/master/demo/x-key-aware.html)
* for an example.
*
* @demo demo/index.html
* @polymerBehavior
*/
Polymer.IronA11yKeysBehavior = {
properties: {
/**
* The EventTarget that will be firing relevant KeyboardEvents. Set it to
* `null` to disable the listeners.
* @type {?EventTarget}
*/
keyEventTarget: {
type: Object,
value: function() {
return this;
}
},
/**
* If true, this property will cause the implementing element to
* automatically stop propagation on any handled KeyboardEvents.
*/
stopKeyboardEventPropagation: {
type: Boolean,
value: false
},
_boundKeyHandlers: {
type: Array,
value: function() {
return [];
}
},
// We use this due to a limitation in IE10 where instances will have
// own properties of everything on the "prototype".
_imperativeKeyBindings: {
type: Object,
value: function() {
return {};
}
}
},
observers: [
'_resetKeyEventListeners(keyEventTarget, _boundKeyHandlers)'
],
/**
* To be used to express what combination of keys will trigger the relative
* callback. e.g. `keyBindings: { 'esc': '_onEscPressed'}`
* @type {Object}
*/
keyBindings: {},
registered: function() {
this._prepKeyBindings();
},
attached: function() {
this._listenKeyEventListeners();
},
detached: function() {
this._unlistenKeyEventListeners();
},
/**
* Can be used to imperatively add a key binding to the implementing
* element. This is the imperative equivalent of declaring a keybinding
* in the `keyBindings` prototype property.
*/
addOwnKeyBinding: function(eventString, handlerName) {
this._imperativeKeyBindings[eventString] = handlerName;
this._prepKeyBindings();
this._resetKeyEventListeners();
},
/**
* When called, will remove all imperatively-added key bindings.
*/
removeOwnKeyBindings: function() {
this._imperativeKeyBindings = {};
this._prepKeyBindings();
this._resetKeyEventListeners();
},
/**
* Returns true if a keyboard event matches `eventString`.
*
* @param {KeyboardEvent} event
* @param {string} eventString
* @return {boolean}
*/
keyboardEventMatchesKeys: function(event, eventString) {
var keyCombos = parseEventString(eventString);
for (var i = 0; i < keyCombos.length; ++i) {
if (keyComboMatchesEvent(keyCombos[i], event)) {
return true;
}
}
return false;
},
_collectKeyBindings: function() {
var keyBindings = this.behaviors.map(function(behavior) {
return behavior.keyBindings;
});
if (keyBindings.indexOf(this.keyBindings) === -1) {
keyBindings.push(this.keyBindings);
}
return keyBindings;
},
_prepKeyBindings: function() {
this._keyBindings = {};
this._collectKeyBindings().forEach(function(keyBindings) {
for (var eventString in keyBindings) {
this._addKeyBinding(eventString, keyBindings[eventString]);
}
}, this);
for (var eventString in this._imperativeKeyBindings) {
this._addKeyBinding(eventString, this._imperativeKeyBindings[eventString]);
}
// Give precedence to combos with modifiers to be checked first.
for (var eventName in this._keyBindings) {
this._keyBindings[eventName].sort(function (kb1, kb2) {
var b1 = kb1[0].hasModifiers;
var b2 = kb2[0].hasModifiers;
return (b1 === b2) ? 0 : b1 ? -1 : 1;
})
}
},
_addKeyBinding: function(eventString, handlerName) {
parseEventString(eventString).forEach(function(keyCombo) {
this._keyBindings[keyCombo.event] =
this._keyBindings[keyCombo.event] || [];
this._keyBindings[keyCombo.event].push([
keyCombo,
handlerName
]);
}, this);
},
_resetKeyEventListeners: function() {
this._unlistenKeyEventListeners();
if (this.isAttached) {
this._listenKeyEventListeners();
}
},
_listenKeyEventListeners: function() {
if (!this.keyEventTarget) {
return;
}
Object.keys(this._keyBindings).forEach(function(eventName) {
var keyBindings = this._keyBindings[eventName];
var boundKeyHandler = this._onKeyBindingEvent.bind(this, keyBindings);
this._boundKeyHandlers.push([this.keyEventTarget, eventName, boundKeyHandler]);
this.keyEventTarget.addEventListener(eventName, boundKeyHandler);
}, this);
},
_unlistenKeyEventListeners: function() {
var keyHandlerTuple;
var keyEventTarget;
var eventName;
var boundKeyHandler;
while (this._boundKeyHandlers.length) {
// My kingdom for block-scope binding and destructuring assignment..
keyHandlerTuple = this._boundKeyHandlers.pop();
keyEventTarget = keyHandlerTuple[0];
eventName = keyHandlerTuple[1];
boundKeyHandler = keyHandlerTuple[2];
keyEventTarget.removeEventListener(eventName, boundKeyHandler);
}
},
_onKeyBindingEvent: function(keyBindings, event) {
if (this.stopKeyboardEventPropagation) {
event.stopPropagation();
}
// if event has been already prevented, don't do anything
if (event.defaultPrevented) {
return;
}
for (var i = 0; i < keyBindings.length; i++) {
var keyCombo = keyBindings[i][0];
var handlerName = keyBindings[i][1];
if (keyComboMatchesEvent(keyCombo, event)) {
this._triggerKeyHandler(keyCombo, handlerName, event);
// exit the loop if eventDefault was prevented
if (event.defaultPrevented) {
return;
}
}
}
},
_triggerKeyHandler: function(keyCombo, handlerName, keyboardEvent) {
var detail = Object.create(keyCombo);
detail.keyboardEvent = keyboardEvent;
var event = new CustomEvent(keyCombo.event, {
detail: detail,
cancelable: true
});
this[handlerName].call(this, event);
if (event.defaultPrevented) {
keyboardEvent.preventDefault();
}
}
};
})();
</script>
<script type="module">
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
/**
* @demo demo/index.html
* @polymerBehavior
*/
export const IronControlState = {
properties: {
/**
* If true, the element currently has focus.
*/
focused: {
type: Boolean,
value: false,
notify: true,
readOnly: true,
reflectToAttribute: true
},
/**
* If true, the user cannot interact with this element.
*/
disabled: {
type: Boolean,
value: false,
notify: true,
observer: '_disabledChanged',
reflectToAttribute: true
},
_oldTabIndex: {
type: Number
},
_boundFocusBlurHandler: {
type: Function,
value: function() {
return this._focusBlurHandler.bind(this);
}
}
},
observers: [
'_changedControlState(focused, disabled)'
],
ready: function() {
this.addEventListener('focus', this._boundFocusBlurHandler, true);
this.addEventListener('blur', this._boundFocusBlurHandler, true);
},
_focusBlurHandler: function(event) {
// NOTE(cdata): if we are in ShadowDOM land, `event.target` will
// eventually become `this` due to retargeting; if we are not in
// ShadowDOM land, `event.target` will eventually become `this` due
// to the second conditional which fires a synthetic event (that is also
// handled). In either case, we can disregard `event.path`.
if (event.target === this) {
this._setFocused(event.type === 'focus');
} else if (!this.shadowRoot) {
var target = /** @type {Node} */(dom(event).localTarget);
if (!this.isLightDescendant(target)) {
this.fire(event.type, {sourceEvent: event}, {
node: this,
bubbles: event.bubbles,
cancelable: event.cancelable
});
}
}
},
_disabledChanged: function(disabled, old) {
this.setAttribute('aria-disabled', disabled ? 'true' : 'false');
this.style.pointerEvents = disabled ? 'none' : '';
if (disabled) {
this._oldTabIndex = this.tabIndex;
this._setFocused(false);
this.tabIndex = -1;
this.blur();
} else if (this._oldTabIndex !== undefined) {
this.tabIndex = this._oldTabIndex;
}
},
_changedControlState: function() {
// _controlStateChanged is abstract, follow-on behaviors may implement it
if (this._controlStateChanged) {
this._controlStateChanged();
}
}
};
</script>
<script type="module">
import { PaperInputHelper as PaperInputHelper$0, PaperInputBehaviorImpl as PaperInputBehaviorImpl$0 } from '@polymer/paper-input/paper-input-behavior.js';
import { IronControlState } from '@polymer/iron-behaviors/iron-control-state.js';
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
import { IronA11yKeysBehavior } from '@polymer/iron-a11y-keys-behavior/iron-a11y-keys-behavior.js';
// Generate unique, monotonically increasing IDs for labels (needed by
// aria-labelledby) and add-ons.
export const PaperInputHelper = {};
PaperInputHelper$0.NextLabelID = 1;
PaperInputHelper$0.NextAddonID = 1;
/**
* Use `Polymer.PaperInputBehavior` to implement inputs with `<paper-input-container>`. This
* behavior is implemented by `<paper-input>`. It exposes a number of properties from
* `<paper-input-container>` and `<input is="iron-input">` and they should be bound in your
* template.
*
* The input element can be accessed by the `inputElement` property if you need to access
* properties or methods that are not exposed.
* @polymerBehavior Polymer.PaperInputBehavior
*/
export const PaperInputBehaviorImpl = {
properties: {
/**
* Fired when the input changes due to user interaction.
*
* @event change
*/
/**
* The label for this input. If you're using PaperInputBehavior to
* implement your own paper-input-like element, bind this to
* `<label>`'s content and `hidden` property, e.g.
* `<label hidden$="[[!label]]">[[label]]</label>` in your `template`
*/
label: {
type: String
},
/**
* The value for this input. If you're using PaperInputBehavior to
* implement your own paper-input-like element, bind this to
* the `<input is="iron-input">`'s `bindValue`
* property, or the value property of your input that is `notify:true`.
*/
value: {
notify: true,
type: String
},
/**
* Set to true to disable this input. If you're using PaperInputBehavior to
* implement your own paper-input-like element, bind this to
* both the `<paper-input-container>`'s and the input's `disabled` property.
*/
disabled: {
type: Boolean,
value: false
},
/**
* Returns true if the value is invalid. If you're using PaperInputBehavior to
* implement your own paper-input-like element, bind this to both the
* `<paper-input-container>`'s and the input's `invalid` property.
*
* If `autoValidate` is true, the `invalid` attribute is managed automatically,
* which can clobber attempts to manage it manually.
*/
invalid: {
type: Boolean,
value: false,
notify: true
},
/**
* Set to true to prevent the user from entering invalid input. If you're
* using PaperInputBehavior to implement your own paper-input-like element,
* bind this to `<input is="iron-input">`'s `preventInvalidInput` property.
*/
preventInvalidInput: {
type: Boolean
},
/**
* Set this to specify the pattern allowed by `preventInvalidInput`. If
* you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `allowedPattern`
* property.
*/
allowedPattern: {
type: String
},
/**
* The type of the input. The supported types are `text`, `number` and `password`.
* If you're using PaperInputBehavior to implement your own paper-input-like element,
* bind this to the `<input is="iron-input">`'s `type` property.
*/
type: {
type: String
},
/**
* The datalist of the input (if any). This should match the id of an existing `<datalist>`.
* If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `list` property.
*/
list: {
type: String
},
/**
* A pattern to validate the `input` with. If you're using PaperInputBehavior to
* implement your own paper-input-like element, bind this to
* the `<input is="iron-input">`'s `pattern` property.
*/
pattern: {
type: String
},
/**
* Set to true to mark the input as required. If you're using PaperInputBehavior to
* implement your own paper-input-like element, bind this to
* the `<input is="iron-input">`'s `required` property.
*/
required: {
type: Boolean,
value: false
},
/**
* The error message to display when the input is invalid. If you're using
* PaperInputBehavior to implement your own paper-input-like element,
* bind this to the `<paper-input-error>`'s content, if using.
*/
errorMessage: {
type: String
},
/**
* Set to true to show a character counter.
*/
charCounter: {
type: Boolean,
value: false
},
/**
* Set to true to disable the floating label. If you're using PaperInputBehavior to
* implement your own paper-input-like element, bind this to
* the `<paper-input-container>`'s `noLabelFloat` property.
*/
noLabelFloat: {
type: Boolean,
value: false
},
/**
* Set to true to always float the label. If you're using PaperInputBehavior to
* implement your own paper-input-like element, bind this to
* the `<paper-input-container>`'s `alwaysFloatLabel` property.
*/
alwaysFloatLabel: {
type: Boolean,
value: false
},
/**
* Set to true to auto-validate the input value. If you're using PaperInputBehavior to
* implement your own paper-input-like element, bind this to
* the `<paper-input-container>`'s `autoValidate` property.
*/
autoValidate: {
type: Boolean,
value: false
},
/**
* Name of the validator to use. If you're using PaperInputBehavior to
* implement your own paper-input-like element, bind this to
* the `<input is="iron-input">`'s `validator` property.
*/
validator: {
type: String
},
// HTMLInputElement attributes for binding if needed
/**
* If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `autocomplete` property.
*/
autocomplete: {
type: String,
value: 'off'
},
/**
* If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `autofocus` property.
*/
autofocus: {
type: Boolean,
observer: '_autofocusChanged'
},
/**
* If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `inputmode` property.
*/
inputmode: {
type: String
},
/**
* The minimum length of the input value.
* If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `minlength` property.
*/
minlength: {
type: Number
},
/**
* The maximum length of the input value.
* If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `maxlength` property.
*/
maxlength: {
type: Number
},
/**
* The minimum (numeric or date-time) input value.
* If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `min` property.
*/
min: {
type: String
},
/**
* The maximum (numeric or date-time) input value.
* Can be a String (e.g. `"2000-1-1"`) or a Number (e.g. `2`).
* If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `max` property.
*/
max: {
type: String
},
/**
* Limits the numeric or date-time increments.
* If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `step` property.
*/
step: {
type: String
},
/**
* If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `name` property.
*/
name: {
type: String
},
/**
* A placeholder string in addition to the label. If this is set, the label will always float.
*/
placeholder: {
type: String,
// need to set a default so _computeAlwaysFloatLabel is run
value: ''
},
/**
* If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `readonly` property.
*/
readonly: {
type: Boolean,
value: false
},
/**
* If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `size` property.
*/
size: {
type: Number
},
// Nonstandard attributes for binding if needed
/**
* If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `autocapitalize` property.
*/
autocapitalize: {
type: String,
value: 'none'
},
/**
* If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `autocorrect` property.
*/
autocorrect: {
type: String,
value: 'off'
},
/**
* If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `autosave` property,
* used with type=search.
*/
autosave: {
type: String
},
/**
* If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `results` property,
* used with type=search.
*/
results: {
type: Number
},
/**
* If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the `<input is="iron-input">`'s `accept` property,
* used with type=file.
*/
accept: {
type: String
},
/**
* If you're using PaperInputBehavior to implement your own paper-input-like
* element, bind this to the`<input is="iron-input">`'s `multiple` property,
* used with type=file.
*/
multiple: {
type: Boolean
},
_ariaDescribedBy: {
type: String,
value: ''
},
_ariaLabelledBy: {
type: String,
value: ''
}
},
listeners: {
'addon-attached': '_onAddonAttached',
},
keyBindings: {
'shift+tab:keydown': '_onShiftTabDown'
},
hostAttributes: {
tabindex: 0
},
/**
* Returns a reference to the input element.
*/
get inputElement() {
return this.$.input;
},
/**
* Returns a reference to the focusable element.
*/
get _focusableElement() {
return this.inputElement;
},
registered: function() {
// These types have some default placeholder text; overlapping
// the label on top of it looks terrible. Auto-float the label in this case.
this._typesThatHaveText = ["date", "datetime", "datetime-local", "month",
"time", "week", "file"];
},
attached: function() {
this._updateAriaLabelledBy();
if (this.inputElement &&
this._typesThatHaveText.indexOf(this.inputElement.type) !== -1) {
this.alwaysFloatLabel = true;
}
},
_appendStringWithSpace: function(str, more) {
if (str) {
str = str + ' ' + more;
} else {
str = more;
}
return str;
},
_onAddonAttached: function(event) {
var target = event.path ? event.path[0] : event.target;
if (target.id) {
this._ariaDescribedBy = this._appendStringWithSpace(this._ariaDescribedBy, target.id);
} else {
var id = 'paper-input-add-on-' + PaperInputHelper$0.NextAddonID++;
target.id = id;
this._ariaDescribedBy = this._appendStringWithSpace(this._ariaDescribedBy, id);
}
},
/**
* Validates the input element and sets an error style if needed.
*
* @return {boolean}
*/
validate: function() {
return this.inputElement.validate();
},
/**
* Forward focus to inputElement. Overriden from IronControlState.
*/
_focusBlurHandler: function(event) {
IronControlState._focusBlurHandler.call(this, event);
// Forward the focus to the nested input.
if (this.focused && !this._shiftTabPressed)
this._focusableElement.focus();
},
/**
* Handler that is called when a shift+tab keypress is detected by the menu.
*
* @param {CustomEvent} event A key combination event.
*/
_onShiftTabDown: function(event) {
var oldTabIndex = this.getAttribute('tabindex');
this._shiftTabPressed = true;
this.setAttribute('tabindex', '-1');
this.async(function() {
this.setAttribute('tabindex', oldTabIndex);
this._shiftTabPressed = false;
}, 1);
},
/**
* If `autoValidate` is true, then validates the element.
*/
_handleAutoValidate: function() {
if (this.autoValidate)
this.validate();
},
/**
* Restores the cursor to its original position after updating the value.
* @param {string} newValue The value that should be saved.
*/
updateValueAndPreserveCaret: function(newValue) {
// Not all elements might have selection, and even if they have the
// right properties, accessing them might throw an exception (like for
// <input type=number>)
try {
var start = this.inputElement.selectionStart;
this.value = newValue;
// The cursor automatically jumps to the end after re-setting the value,
// so restore it to its original position.
this.inputElement.selectionStart = start;
this.inputElement.selectionEnd = start;
} catch (e) {
// Just set the value and give up on the caret.
this.value = newValue;
}
},
_computeAlwaysFloatLabel: function(alwaysFloatLabel, placeholder) {
return placeholder || alwaysFloatLabel;
},
_updateAriaLabelledBy: function() {
var label = dom(this.root).querySelector('label');
if (!label) {
this._ariaLabelledBy = '';
return;
}
var labelledBy;
if (label.id) {
labelledBy = label.id;
} else {
labelledBy = 'paper-input-label-' + PaperInputHelper$0.NextLabelID++;
label.id = labelledBy;
}
this._ariaLabelledBy = labelledBy;
},
_onChange:function(event) {
// In the Shadow DOM, the `change` event is not leaked into the
// ancestor tree, so we must do this manually.
// See https://w3c.github.io/webcomponents/spec/shadow/#events-that-are-not-leaked-into-ancestor-trees.
if (this.shadowRoot) {
this.fire(event.type, {sourceEvent: event}, {
node: this,
bubbles: event.bubbles,
cancelable: event.cancelable
});
}
},
_autofocusChanged: function() {
// Firefox doesn't respect the autofocus attribute if it's applied after
// the page is loaded (Chrome/WebKit do respect it), preventing an
// autofocus attribute specified in markup from taking effect when the
// element is upgraded. As a workaround, if the autofocus property is set,
// and the focus hasn't already been moved elsewhere, we take focus.
if (this.autofocus && this._focusableElement) {
// In IE 11, the default document.activeElement can be the page's
// outermost html element, but there are also cases (under the
// polyfill?) in which the activeElement is not a real HTMLElement, but
// just a plain object. We identify the latter case as having no valid
// activeElement.
var activeElement = document.activeElement;
var isActiveElementValid = activeElement instanceof HTMLElement;
// Has some other element has already taken the focus?
var isSomeElementActive = isActiveElementValid &&
activeElement !== document.body &&
activeElement !== document.documentElement; /* IE 11 */
if (!isSomeElementActive) {
// No specific element has taken the focus yet, so we can take it.
this._focusableElement.focus();
}
}
}
};
/** @polymerBehavior */
export const PaperInputBehavior = [
IronControlState,
IronA11yKeysBehavior,
PaperInputBehaviorImpl$0
];
</script>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:400,300,300italic,400italic,500,500italic,700,700italic">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto+Mono:400,700">
<style is="custom-style">
:root {
/* Shared Styles */
--paper-font-common-base: {
font-family: 'Roboto', 'Noto', sans-serif;
-webkit-font-smoothing: antialiased;
};
--paper-font-common-code: {
font-family: 'Roboto Mono', 'Consolas', 'Menlo', monospace;
-webkit-font-smoothing: antialiased;
};
--paper-font-common-expensive-kerning: {
text-rendering: optimizeLegibility;
};
--paper-font-common-nowrap: {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
};
/* Material Font Styles */
--paper-font-display4: {
@apply(--paper-font-common-base);
@apply(--paper-font-common-nowrap);
font-size: 112px;
font-weight: 300;
letter-spacing: -.044em;
line-height: 120px;
};
--paper-font-display3: {
@apply(--paper-font-common-base);
@apply(--paper-font-common-nowrap);
font-size: 56px;
font-weight: 400;
letter-spacing: -.026em;
line-height: 60px;
};
--paper-font-display2: {
@apply(--paper-font-common-base);
font-size: 45px;
font-weight: 400;
letter-spacing: -.018em;
line-height: 48px;
};
--paper-font-display1: {
@apply(--paper-font-common-base);
font-size: 34px;
font-weight: 400;
letter-spacing: -.01em;
line-height: 40px;
};
--paper-font-headline: {
@apply(--paper-font-common-base);
font-size: 24px;
font-weight: 400;
letter-spacing: -.012em;
line-height: 32px;
};
--paper-font-title: {
@apply(--paper-font-common-base);
@apply(--paper-font-common-nowrap);
font-size: 20px;
font-weight: 500;
line-height: 28px;
};
--paper-font-subhead: {
@apply(--paper-font-common-base);
font-size: 16px;
font-weight: 400;
line-height: 24px;
};
--paper-font-body2: {
@apply(--paper-font-common-base);
font-size: 14px;
font-weight: 500;
line-height: 24px;
};
--paper-font-body1: {
@apply(--paper-font-common-base);
font-size: 14px;
font-weight: 400;
line-height: 20px;
};
--paper-font-caption: {
@apply(--paper-font-common-base);
@apply(--paper-font-common-nowrap);
font-size: 12px;
font-weight: 400;
letter-spacing: 0.011em;
line-height: 20px;
};
--paper-font-menu: {
@apply(--paper-font-common-base);
@apply(--paper-font-common-nowrap);
font-size: 13px;
font-weight: 500;
line-height: 24px;
};
--paper-font-button: {
@apply(--paper-font-common-base);
@apply(--paper-font-common-nowrap);
font-size: 14px;
font-weight: 500;
letter-spacing: 0.018em;
line-height: 24px;
text-transform: uppercase;
};
--paper-font-code2: {
@apply(--paper-font-common-code);
font-size: 14px;
font-weight: 700;
line-height: 20px;
};
--paper-font-code1: {
@apply(--paper-font-common-code);
font-size: 14px;
font-weight: 500;
line-height: 20px;
};
}
</style>
<script>
/**
* Use `Polymer.PaperInputAddonBehavior` to implement an add-on for `<paper-input-container>`. A
* add-on appears below the input, and may display information based on the input value and
* validity such as a character counter or an error message.
* @polymerBehavior
*/
Polymer.PaperInputAddonBehavior = {
hostAttributes: {
'add-on': ''
},
attached: function() {
this.fire('addon-attached');
},
/**
* The function called by `<paper-input-container>` when the input value or validity changes.
* @param {{
* inputElement: (Element|undefined),
* value: (string|undefined),
* invalid: boolean
* }} state -
* inputElement: The input element.
* value: The input value.
* invalid: True if the input value is invalid.
*/
update: function(state) {
}
};
</script>
<dom-module id="paper-input-char-counter" assetpath="../../../paper-input/">
<template>
<style>
:host {
display: inline-block;
float: right;
@apply(--paper-font-caption);
@apply(--paper-input-char-counter);
}
:host([hidden]) {
display: none !important;
}
:host-context([dir="rtl"]) {
float: left;
}
</style>
<span>[[_charCounterStr]]</span>
</template>
</dom-module>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { PaperInputAddonBehavior } from '@polymer/paper-input/paper-input-addon-behavior.js';
Polymer({
is: 'paper-input-char-counter',
behaviors: [
PaperInputAddonBehavior
],
properties: {
_charCounterStr: {
type: String,
value: '0'
}
},
/**
* This overrides the update function in PaperInputAddonBehavior.
* @param {{
* inputElement: (Element|undefined),
* value: (string|undefined),
* invalid: boolean
* }} state -
* inputElement: The input element.
* value: The input value.
* invalid: True if the input value is invalid.
*/
update: function(state) {
if (!state.inputElement) {
return;
}
state.value = state.value || '';
var counter = state.value.toString().length.toString();
if (state.inputElement.hasAttribute('maxlength')) {
counter += '/' + state.inputElement.getAttribute('maxlength');
}
this._charCounterStr = counter;
}
});
</script>
<style>
/* IE 10 support for HTML5 hidden attr */
[hidden] {
display: none !important;
}
</style>
<style is="custom-style">
:root {
--layout: {
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
};
--layout-inline: {
display: -ms-inline-flexbox;
display: -webkit-inline-flex;
display: inline-flex;
};
--layout-horizontal: {
@apply(--layout);
-ms-flex-direction: row;
-webkit-flex-direction: row;
flex-direction: row;
};
--layout-horizontal-reverse: {
@apply(--layout);
-ms-flex-direction: row-reverse;
-webkit-flex-direction: row-reverse;
flex-direction: row-reverse;
};
--layout-vertical: {
@apply(--layout);
-ms-flex-direction: column;
-webkit-flex-direction: column;
flex-direction: column;
};
--layout-vertical-reverse: {
@apply(--layout);
-ms-flex-direction: column-reverse;
-webkit-flex-direction: column-reverse;
flex-direction: column-reverse;
};
--layout-wrap: {
-ms-flex-wrap: wrap;
-webkit-flex-wrap: wrap;
flex-wrap: wrap;
};
--layout-wrap-reverse: {
-ms-flex-wrap: wrap-reverse;
-webkit-flex-wrap: wrap-reverse;
flex-wrap: wrap-reverse;
};
--layout-flex-auto: {
-ms-flex: 1 1 auto;
-webkit-flex: 1 1 auto;
flex: 1 1 auto;
};
--layout-flex-none: {
-ms-flex: none;
-webkit-flex: none;
flex: none;
};
--layout-flex: {
-ms-flex: 1 1 0.000000001px;
-webkit-flex: 1;
flex: 1;
-webkit-flex-basis: 0.000000001px;
flex-basis: 0.000000001px;
};
--layout-flex-2: {
-ms-flex: 2;
-webkit-flex: 2;
flex: 2;
};
--layout-flex-3: {
-ms-flex: 3;
-webkit-flex: 3;
flex: 3;
};
--layout-flex-4: {
-ms-flex: 4;
-webkit-flex: 4;
flex: 4;
};
--layout-flex-5: {
-ms-flex: 5;
-webkit-flex: 5;
flex: 5;
};
--layout-flex-6: {
-ms-flex: 6;
-webkit-flex: 6;
flex: 6;
};
--layout-flex-7: {
-ms-flex: 7;
-webkit-flex: 7;
flex: 7;
};
--layout-flex-8: {
-ms-flex: 8;
-webkit-flex: 8;
flex: 8;
};
--layout-flex-9: {
-ms-flex: 9;
-webkit-flex: 9;
flex: 9;
};
--layout-flex-10: {
-ms-flex: 10;
-webkit-flex: 10;
flex: 10;
};
--layout-flex-11: {
-ms-flex: 11;
-webkit-flex: 11;
flex: 11;
};
--layout-flex-12: {
-ms-flex: 12;
-webkit-flex: 12;
flex: 12;
};
/* alignment in cross axis */
--layout-start: {
-ms-flex-align: start;
-webkit-align-items: flex-start;
align-items: flex-start;
};
--layout-center: {
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
};
--layout-end: {
-ms-flex-align: end;
-webkit-align-items: flex-end;
align-items: flex-end;
};
--layout-baseline: {
-ms-flex-align: baseline;
-webkit-align-items: baseline;
align-items: baseline;
};
/* alignment in main axis */
--layout-start-justified: {
-ms-flex-pack: start;
-webkit-justify-content: flex-start;
justify-content: flex-start;
};
--layout-center-justified: {
-ms-flex-pack: center;
-webkit-justify-content: center;
justify-content: center;
};
--layout-end-justified: {
-ms-flex-pack: end;
-webkit-justify-content: flex-end;
justify-content: flex-end;
};
--layout-around-justified: {
-ms-flex-pack: distribute;
-webkit-justify-content: space-around;
justify-content: space-around;
};
--layout-justified: {
-ms-flex-pack: justify;
-webkit-justify-content: space-between;
justify-content: space-between;
};
--layout-center-center: {
@apply(--layout-center);
@apply(--layout-center-justified);
};
/* self alignment */
--layout-self-start: {
-ms-align-self: flex-start;
-webkit-align-self: flex-start;
align-self: flex-start;
};
--layout-self-center: {
-ms-align-self: center;
-webkit-align-self: center;
align-self: center;
};
--layout-self-end: {
-ms-align-self: flex-end;
-webkit-align-self: flex-end;
align-self: flex-end;
};
--layout-self-stretch: {
-ms-align-self: stretch;
-webkit-align-self: stretch;
align-self: stretch;
};
--layout-self-baseline: {
-ms-align-self: baseline;
-webkit-align-self: baseline;
align-self: baseline;
};
/* multi-line alignment in main axis */
--layout-start-aligned: {
-ms-flex-line-pack: start; /* IE10 */
-ms-align-content: flex-start;
-webkit-align-content: flex-start;
align-content: flex-start;
};
--layout-end-aligned: {
-ms-flex-line-pack: end; /* IE10 */
-ms-align-content: flex-end;
-webkit-align-content: flex-end;
align-content: flex-end;
};
--layout-center-aligned: {
-ms-flex-line-pack: center; /* IE10 */
-ms-align-content: center;
-webkit-align-content: center;
align-content: center;
};
--layout-between-aligned: {
-ms-flex-line-pack: justify; /* IE10 */
-ms-align-content: space-between;
-webkit-align-content: space-between;
align-content: space-between;
};
--layout-around-aligned: {
-ms-flex-line-pack: distribute; /* IE10 */
-ms-align-content: space-around;
-webkit-align-content: space-around;
align-content: space-around;
};
/*******************************
Other Layout
*******************************/
--layout-block: {
display: block;
};
--layout-invisible: {
visibility: hidden !important;
};
--layout-relative: {
position: relative;
};
--layout-fit: {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
};
--layout-scroll: {
-webkit-overflow-scrolling: touch;
overflow: auto;
};
--layout-fullbleed: {
margin: 0;
height: 100vh;
};
/* fixed position */
--layout-fixed-top: {
position: fixed;
top: 0;
left: 0;
right: 0;
};
--layout-fixed-right: {
position: fixed;
top: 0;
right: 0;
bottom: 0;
};
--layout-fixed-bottom: {
position: fixed;
right: 0;
bottom: 0;
left: 0;
};
--layout-fixed-left: {
position: fixed;
top: 0;
bottom: 0;
left: 0;
};
}
</style>
<style is="custom-style">
:root {
/* Material Design color palette for Google products */
--google-red-100: #f4c7c3;
--google-red-300: #e67c73;
--google-red-500: #db4437;
--google-red-700: #c53929;
--google-blue-100: #c6dafc;
--google-blue-300: #7baaf7;
--google-blue-500: #4285f4;
--google-blue-700: #3367d6;
--google-green-100: #b7e1cd;
--google-green-300: #57bb8a;
--google-green-500: #0f9d58;
--google-green-700: #0b8043;
--google-yellow-100: #fce8b2;
--google-yellow-300: #f7cb4d;
--google-yellow-500: #f4b400;
--google-yellow-700: #f09300;
--google-grey-100: #f5f5f5;
--google-grey-300: #e0e0e0;
--google-grey-500: #9e9e9e;
--google-grey-700: #616161;
/* Material Design color palette from online spec document */
--paper-red-50: #ffebee;
--paper-red-100: #ffcdd2;
--paper-red-200: #ef9a9a;
--paper-red-300: #e57373;
--paper-red-400: #ef5350;
--paper-red-500: #f44336;
--paper-red-600: #e53935;
--paper-red-700: #d32f2f;
--paper-red-800: #c62828;
--paper-red-900: #b71c1c;
--paper-red-a100: #ff8a80;
--paper-red-a200: #ff5252;
--paper-red-a400: #ff1744;
--paper-red-a700: #d50000;
--paper-pink-50: #fce4ec;
--paper-pink-100: #f8bbd0;
--paper-pink-200: #f48fb1;
--paper-pink-300: #f06292;
--paper-pink-400: #ec407a;
--paper-pink-500: #e91e63;
--paper-pink-600: #d81b60;
--paper-pink-700: #c2185b;
--paper-pink-800: #ad1457;
--paper-pink-900: #880e4f;
--paper-pink-a100: #ff80ab;
--paper-pink-a200: #ff4081;
--paper-pink-a400: #f50057;
--paper-pink-a700: #c51162;
--paper-purple-50: #f3e5f5;
--paper-purple-100: #e1bee7;
--paper-purple-200: #ce93d8;
--paper-purple-300: #ba68c8;
--paper-purple-400: #ab47bc;
--paper-purple-500: #9c27b0;
--paper-purple-600: #8e24aa;
--paper-purple-700: #7b1fa2;
--paper-purple-800: #6a1b9a;
--paper-purple-900: #4a148c;
--paper-purple-a100: #ea80fc;
--paper-purple-a200: #e040fb;
--paper-purple-a400: #d500f9;
--paper-purple-a700: #aa00ff;
--paper-deep-purple-50: #ede7f6;
--paper-deep-purple-100: #d1c4e9;
--paper-deep-purple-200: #b39ddb;
--paper-deep-purple-300: #9575cd;
--paper-deep-purple-400: #7e57c2;
--paper-deep-purple-500: #673ab7;
--paper-deep-purple-600: #5e35b1;
--paper-deep-purple-700: #512da8;
--paper-deep-purple-800: #4527a0;
--paper-deep-purple-900: #311b92;
--paper-deep-purple-a100: #b388ff;
--paper-deep-purple-a200: #7c4dff;
--paper-deep-purple-a400: #651fff;
--paper-deep-purple-a700: #6200ea;
--paper-indigo-50: #e8eaf6;
--paper-indigo-100: #c5cae9;
--paper-indigo-200: #9fa8da;
--paper-indigo-300: #7986cb;
--paper-indigo-400: #5c6bc0;
--paper-indigo-500: #3f51b5;
--paper-indigo-600: #3949ab;
--paper-indigo-700: #303f9f;
--paper-indigo-800: #283593;
--paper-indigo-900: #1a237e;
--paper-indigo-a100: #8c9eff;
--paper-indigo-a200: #536dfe;
--paper-indigo-a400: #3d5afe;
--paper-indigo-a700: #304ffe;
--paper-blue-50: #e3f2fd;
--paper-blue-100: #bbdefb;
--paper-blue-200: #90caf9;
--paper-blue-300: #64b5f6;
--paper-blue-400: #42a5f5;
--paper-blue-500: #2196f3;
--paper-blue-600: #1e88e5;
--paper-blue-700: #1976d2;
--paper-blue-800: #1565c0;
--paper-blue-900: #0d47a1;
--paper-blue-a100: #82b1ff;
--paper-blue-a200: #448aff;
--paper-blue-a400: #2979ff;
--paper-blue-a700: #2962ff;
--paper-light-blue-50: #e1f5fe;
--paper-light-blue-100: #b3e5fc;
--paper-light-blue-200: #81d4fa;
--paper-light-blue-300: #4fc3f7;
--paper-light-blue-400: #29b6f6;
--paper-light-blue-500: #03a9f4;
--paper-light-blue-600: #039be5;
--paper-light-blue-700: #0288d1;
--paper-light-blue-800: #0277bd;
--paper-light-blue-900: #01579b;
--paper-light-blue-a100: #80d8ff;
--paper-light-blue-a200: #40c4ff;
--paper-light-blue-a400: #00b0ff;
--paper-light-blue-a700: #0091ea;
--paper-cyan-50: #e0f7fa;
--paper-cyan-100: #b2ebf2;
--paper-cyan-200: #80deea;
--paper-cyan-300: #4dd0e1;
--paper-cyan-400: #26c6da;
--paper-cyan-500: #00bcd4;
--paper-cyan-600: #00acc1;
--paper-cyan-700: #0097a7;
--paper-cyan-800: #00838f;
--paper-cyan-900: #006064;
--paper-cyan-a100: #84ffff;
--paper-cyan-a200: #18ffff;
--paper-cyan-a400: #00e5ff;
--paper-cyan-a700: #00b8d4;
--paper-teal-50: #e0f2f1;
--paper-teal-100: #b2dfdb;
--paper-teal-200: #80cbc4;
--paper-teal-300: #4db6ac;
--paper-teal-400: #26a69a;
--paper-teal-500: #009688;
--paper-teal-600: #00897b;
--paper-teal-700: #00796b;
--paper-teal-800: #00695c;
--paper-teal-900: #004d40;
--paper-teal-a100: #a7ffeb;
--paper-teal-a200: #64ffda;
--paper-teal-a400: #1de9b6;
--paper-teal-a700: #00bfa5;
--paper-green-50: #e8f5e9;
--paper-green-100: #c8e6c9;
--paper-green-200: #a5d6a7;
--paper-green-300: #81c784;
--paper-green-400: #66bb6a;
--paper-green-500: #4caf50;
--paper-green-600: #43a047;
--paper-green-700: #388e3c;
--paper-green-800: #2e7d32;
--paper-green-900: #1b5e20;
--paper-green-a100: #b9f6ca;
--paper-green-a200: #69f0ae;
--paper-green-a400: #00e676;
--paper-green-a700: #00c853;
--paper-light-green-50: #f1f8e9;
--paper-light-green-100: #dcedc8;
--paper-light-green-200: #c5e1a5;
--paper-light-green-300: #aed581;
--paper-light-green-400: #9ccc65;
--paper-light-green-500: #8bc34a;
--paper-light-green-600: #7cb342;
--paper-light-green-700: #689f38;
--paper-light-green-800: #558b2f;
--paper-light-green-900: #33691e;
--paper-light-green-a100: #ccff90;
--paper-light-green-a200: #b2ff59;
--paper-light-green-a400: #76ff03;
--paper-light-green-a700: #64dd17;
--paper-lime-50: #f9fbe7;
--paper-lime-100: #f0f4c3;
--paper-lime-200: #e6ee9c;
--paper-lime-300: #dce775;
--paper-lime-400: #d4e157;
--paper-lime-500: #cddc39;
--paper-lime-600: #c0ca33;
--paper-lime-700: #afb42b;
--paper-lime-800: #9e9d24;
--paper-lime-900: #827717;
--paper-lime-a100: #f4ff81;
--paper-lime-a200: #eeff41;
--paper-lime-a400: #c6ff00;
--paper-lime-a700: #aeea00;
--paper-yellow-50: #fffde7;
--paper-yellow-100: #fff9c4;
--paper-yellow-200: #fff59d;
--paper-yellow-300: #fff176;
--paper-yellow-400: #ffee58;
--paper-yellow-500: #ffeb3b;
--paper-yellow-600: #fdd835;
--paper-yellow-700: #fbc02d;
--paper-yellow-800: #f9a825;
--paper-yellow-900: #f57f17;
--paper-yellow-a100: #ffff8d;
--paper-yellow-a200: #ffff00;
--paper-yellow-a400: #ffea00;
--paper-yellow-a700: #ffd600;
--paper-amber-50: #fff8e1;
--paper-amber-100: #ffecb3;
--paper-amber-200: #ffe082;
--paper-amber-300: #ffd54f;
--paper-amber-400: #ffca28;
--paper-amber-500: #ffc107;
--paper-amber-600: #ffb300;
--paper-amber-700: #ffa000;
--paper-amber-800: #ff8f00;
--paper-amber-900: #ff6f00;
--paper-amber-a100: #ffe57f;
--paper-amber-a200: #ffd740;
--paper-amber-a400: #ffc400;
--paper-amber-a700: #ffab00;
--paper-orange-50: #fff3e0;
--paper-orange-100: #ffe0b2;
--paper-orange-200: #ffcc80;
--paper-orange-300: #ffb74d;
--paper-orange-400: #ffa726;
--paper-orange-500: #ff9800;
--paper-orange-600: #fb8c00;
--paper-orange-700: #f57c00;
--paper-orange-800: #ef6c00;
--paper-orange-900: #e65100;
--paper-orange-a100: #ffd180;
--paper-orange-a200: #ffab40;
--paper-orange-a400: #ff9100;
--paper-orange-a700: #ff6500;
--paper-deep-orange-50: #fbe9e7;
--paper-deep-orange-100: #ffccbc;
--paper-deep-orange-200: #ffab91;
--paper-deep-orange-300: #ff8a65;
--paper-deep-orange-400: #ff7043;
--paper-deep-orange-500: #ff5722;
--paper-deep-orange-600: #f4511e;
--paper-deep-orange-700: #e64a19;
--paper-deep-orange-800: #d84315;
--paper-deep-orange-900: #bf360c;
--paper-deep-orange-a100: #ff9e80;
--paper-deep-orange-a200: #ff6e40;
--paper-deep-orange-a400: #ff3d00;
--paper-deep-orange-a700: #dd2c00;
--paper-brown-50: #efebe9;
--paper-brown-100: #d7ccc8;
--paper-brown-200: #bcaaa4;
--paper-brown-300: #a1887f;
--paper-brown-400: #8d6e63;
--paper-brown-500: #795548;
--paper-brown-600: #6d4c41;
--paper-brown-700: #5d4037;
--paper-brown-800: #4e342e;
--paper-brown-900: #3e2723;
--paper-grey-50: #fafafa;
--paper-grey-100: #f5f5f5;
--paper-grey-200: #eeeeee;
--paper-grey-300: #e0e0e0;
--paper-grey-400: #bdbdbd;
--paper-grey-500: #9e9e9e;
--paper-grey-600: #757575;
--paper-grey-700: #616161;
--paper-grey-800: #424242;
--paper-grey-900: #212121;
--paper-blue-grey-50: #eceff1;
--paper-blue-grey-100: #cfd8dc;
--paper-blue-grey-200: #b0bec5;
--paper-blue-grey-300: #90a4ae;
--paper-blue-grey-400: #78909c;
--paper-blue-grey-500: #607d8b;
--paper-blue-grey-600: #546e7a;
--paper-blue-grey-700: #455a64;
--paper-blue-grey-800: #37474f;
--paper-blue-grey-900: #263238;
/* opacity for dark text on a light background */
--dark-divider-opacity: 0.12;
--dark-disabled-opacity: 0.38; /* or hint text or icon */
--dark-secondary-opacity: 0.54;
--dark-primary-opacity: 0.87;
/* opacity for light text on a dark background */
--light-divider-opacity: 0.12;
--light-disabled-opacity: 0.3; /* or hint text or icon */
--light-secondary-opacity: 0.7;
--light-primary-opacity: 1.0;
}
</style>
<style is="custom-style">
:root {
/*
* You can use these generic variables in your elements for easy theming.
* For example, if all your elements use `--primary-text-color` as its main
* color, then switching from a light to a dark theme is just a matter of
* changing the value of `--primary-text-color` in your application.
*/
--primary-text-color: var(--light-theme-text-color);
--primary-background-color: var(--light-theme-background-color);
--secondary-text-color: var(--light-theme-secondary-color);
--disabled-text-color: var(--light-theme-disabled-color);
--divider-color: var(--light-theme-divider-color);
--error-color: var(--paper-deep-orange-a700);
/*
* Primary and accent colors. Also see color.html for more colors.
*/
--primary-color: var(--paper-indigo-500);
--light-primary-color: var(--paper-indigo-100);
--dark-primary-color: var(--paper-indigo-700);
--accent-color: var(--paper-pink-a200);
--light-accent-color: var(--paper-pink-a100);
--dark-accent-color: var(--paper-pink-a400);
/*
* Material Design Light background theme
*/
--light-theme-background-color: #ffffff;
--light-theme-base-color: #000000;
--light-theme-text-color: var(--paper-grey-900);
--light-theme-secondary-color: #737373; /* for secondary text and icons */
--light-theme-disabled-color: #9b9b9b; /* disabled/hint text */
--light-theme-divider-color: #dbdbdb;
/*
* Material Design Dark background theme
*/
--dark-theme-background-color: var(--paper-grey-900);
--dark-theme-base-color: #ffffff;
--dark-theme-text-color: #ffffff;
--dark-theme-secondary-color: #bcbcbc; /* for secondary text and icons */
--dark-theme-disabled-color: #646464; /* disabled/hint text */
--dark-theme-divider-color: #3c3c3c;
/*
* Deprecated values because of their confusing names.
*/
--text-primary-color: var(--dark-theme-text-color);
--default-primary-color: var(--primary-color);
}
</style>
<dom-module id="paper-input-container" assetpath="../../../paper-input/">
<template>
<style>
:host {
display: block;
padding: 8px 0;
@apply(--paper-input-container);
}
:host([inline]) {
display: inline-block;
}
:host([disabled]) {
pointer-events: none;
opacity: 0.33;
@apply(--paper-input-container-disabled);
}
:host([hidden]) {
display: none !important;
}
.floated-label-placeholder {
@apply(--paper-font-caption);
}
.underline {
position: relative;
}
.focused-line {
@apply(--layout-fit);
background: var(--paper-input-container-focus-color, --primary-color);
height: 2px;
-webkit-transform-origin: center center;
transform-origin: center center;
-webkit-transform: scale3d(0,1,1);
transform: scale3d(0,1,1);
@apply(--paper-input-container-underline-focus);
}
.underline.is-highlighted .focused-line {
-webkit-transform: none;
transform: none;
-webkit-transition: -webkit-transform 0.25s;
transition: transform 0.25s;
@apply(--paper-transition-easing);
}
.underline.is-invalid .focused-line {
background: var(--paper-input-container-invalid-color, --error-color);
-webkit-transform: none;
transform: none;
-webkit-transition: -webkit-transform 0.25s;
transition: transform 0.25s;
@apply(--paper-transition-easing);
}
.unfocused-line {
@apply(--layout-fit);
background: var(--paper-input-container-color, --secondary-text-color);
height: 1px;
@apply(--paper-input-container-underline);
}
:host([disabled]) .unfocused-line {
border-bottom: 1px dashed;
border-color: var(--paper-input-container-color, --secondary-text-color);
background: transparent;
@apply(--paper-input-container-underline-disabled);
}
.label-and-input-container {
@apply(--layout-flex-auto);
@apply(--layout-relative);
width: 100%;
max-width: 100%;
}
.input-content {
@apply(--layout-horizontal);
@apply(--layout-center);
position: relative;
}
.input-content ::content label,
.input-content ::content .paper-input-label {
position: absolute;
top: 0;
right: 0;
left: 0;
width: 100%;
font: inherit;
color: var(--paper-input-container-color, --secondary-text-color);
-webkit-transition: -webkit-transform 0.25s, width 0.25s;
transition: transform 0.25s, width 0.25s;
-webkit-transform-origin: left top;
transform-origin: left top;
@apply(--paper-font-common-nowrap);
@apply(--paper-font-subhead);
@apply(--paper-input-container-label);
@apply(--paper-transition-easing);
}
.input-content.label-is-floating ::content label,
.input-content.label-is-floating ::content .paper-input-label {
-webkit-transform: translateY(-75%) scale(0.75);
transform: translateY(-75%) scale(0.75);
/* Since we scale to 75/100 of the size, we actually have 100/75 of the
original space now available */
width: 133%;
@apply(--paper-input-container-label-floating);
}
:host-context([dir="rtl"]) .input-content.label-is-floating ::content label,
:host-context([dir="rtl"]) .input-content.label-is-floating ::content .paper-input-label {
/* TODO(noms): Figure out why leaving the width at 133% before the animation
* actually makes
* it wider on the right side, not left side, as you would expect in RTL */
width: 100%;
-webkit-transform-origin: right top;
transform-origin: right top;
}
.input-content.label-is-highlighted ::content label,
.input-content.label-is-highlighted ::content .paper-input-label {
color: var(--paper-input-container-focus-color, --primary-color);
@apply(--paper-input-container-label-focus);
}
.input-content.is-invalid ::content label,
.input-content.is-invalid ::content .paper-input-label {
color: var(--paper-input-container-invalid-color, --error-color);
}
.input-content.label-is-hidden ::content label,
.input-content.label-is-hidden ::content .paper-input-label {
visibility: hidden;
}
.input-content ::content input,
.input-content ::content textarea,
.input-content ::content iron-autogrow-textarea,
.input-content ::content .paper-input-input {
position: relative; /* to make a stacking context */
outline: none;
box-shadow: none;
padding: 0;
width: 100%;
max-width: 100%;
background: transparent;
border: none;
color: var(--paper-input-container-input-color, --primary-text-color);
-webkit-appearance: none;
text-align: inherit;
@apply(--paper-font-subhead);
@apply(--paper-input-container-input);
}
::content [prefix] {
@apply(--paper-font-subhead);
@apply(--paper-input-prefix);
@apply(--layout-flex-none);
}
::content [suffix] {
@apply(--paper-font-subhead);
@apply(--paper-input-suffix);
@apply(--layout-flex-none);
}
/* Firefox sets a min-width on the input, which can cause layout issues */
.input-content ::content input {
min-width: 0;
}
.input-content ::content textarea {
resize: none;
}
.add-on-content {
position: relative;
}
.add-on-content.is-invalid ::content * {
color: var(--paper-input-container-invalid-color, --error-color);
}
.add-on-content.is-highlighted ::content * {
color: var(--paper-input-container-focus-color, --primary-color);
}
</style>
<template is="dom-if" if="[[!noLabelFloat]]">
<div class="floated-label-placeholder" aria-hidden="true"> </div>
</template>
<div class$="[[_computeInputContentClass(noLabelFloat,alwaysFloatLabel,focused,invalid,_inputHasContent)]]">
<content select="[prefix]" id="prefix"></content>
<div class="label-and-input-container" id="labelAndInputContainer">
<content select=":not([add-on]):not([prefix]):not([suffix])"></content>
</div>
<content select="[suffix]"></content>
</div>
<div class$="[[_computeUnderlineClass(focused,invalid)]]">
<div class="unfocused-line"></div>
<div class="focused-line"></div>
</div>
<div class$="[[_computeAddOnContentClass(focused,invalid)]]">
<content id="addOnContent" select="[add-on]"></content>
</div>
</template>
</dom-module>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { dashToCamelCase } from '@polymer/polymer/lib/utils/case-map.js';
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
Polymer({
is: 'paper-input-container',
properties: {
/**
* Set to true to disable the floating label. The label disappears when the input value is
* not null.
*/
noLabelFloat: {
type: Boolean,
value: false
},
/**
* Set to true to always float the floating label.
*/
alwaysFloatLabel: {
type: Boolean,
value: false
},
/**
* The attribute to listen for value changes on.
*/
attrForValue: {
type: String,
value: 'bind-value'
},
/**
* Set to true to auto-validate the input value when it changes.
*/
autoValidate: {
type: Boolean,
value: false
},
/**
* True if the input is invalid. This property is set automatically when the input value
* changes if auto-validating, or when the `iron-input-validate` event is heard from a child.
*/
invalid: {
observer: '_invalidChanged',
type: Boolean,
value: false
},
/**
* True if the input has focus.
*/
focused: {
readOnly: true,
type: Boolean,
value: false,
notify: true
},
_addons: {
type: Array
// do not set a default value here intentionally - it will be initialized lazily when a
// distributed child is attached, which may occur before configuration for this element
// in polyfill.
},
_inputHasContent: {
type: Boolean,
value: false
},
_inputSelector: {
type: String,
value: 'input,textarea,.paper-input-input'
},
_boundOnFocus: {
type: Function,
value: function() {
return this._onFocus.bind(this);
}
},
_boundOnBlur: {
type: Function,
value: function() {
return this._onBlur.bind(this);
}
},
_boundOnInput: {
type: Function,
value: function() {
return this._onInput.bind(this);
}
},
_boundValueChanged: {
type: Function,
value: function() {
return this._onValueChanged.bind(this);
}
}
},
listeners: {
'addon-attached': '_onAddonAttached',
'iron-input-validate': '_onIronInputValidate'
},
get _valueChangedEvent() {
return this.attrForValue + '-changed';
},
get _propertyForValue() {
return dashToCamelCase(this.attrForValue);
},
get _inputElement() {
return dom(this).querySelector(this._inputSelector);
},
get _inputElementValue() {
return this._inputElement[this._propertyForValue] || this._inputElement.value;
},
ready: function() {
if (!this._addons) {
this._addons = [];
}
this.addEventListener('focus', this._boundOnFocus, true);
this.addEventListener('blur', this._boundOnBlur, true);
},
attached: function() {
if (this.attrForValue) {
this._inputElement.addEventListener(this._valueChangedEvent, this._boundValueChanged);
} else {
this.addEventListener('input', this._onInput);
}
// Only validate when attached if the input already has a value.
if (this._inputElementValue != '') {
this._handleValueAndAutoValidate(this._inputElement);
} else {
this._handleValue(this._inputElement);
}
},
_onAddonAttached: function(event) {
if (!this._addons) {
this._addons = [];
}
var target = event.target;
if (this._addons.indexOf(target) === -1) {
this._addons.push(target);
if (this.isAttached) {
this._handleValue(this._inputElement);
}
}
},
_onFocus: function() {
this._setFocused(true);
},
_onBlur: function() {
this._setFocused(false);
this._handleValueAndAutoValidate(this._inputElement);
},
_onInput: function(event) {
this._handleValueAndAutoValidate(event.target);
},
_onValueChanged: function(event) {
this._handleValueAndAutoValidate(event.target);
},
_handleValue: function(inputElement) {
var value = this._inputElementValue;
// type="number" hack needed because this.value is empty until it's valid
if (value || value === 0 || (inputElement.type === 'number' && !inputElement.checkValidity())) {
this._inputHasContent = true;
} else {
this._inputHasContent = false;
}
this.updateAddons({
inputElement: inputElement,
value: value,
invalid: this.invalid
});
},
_handleValueAndAutoValidate: function(inputElement) {
if (this.autoValidate) {
var valid;
if (inputElement.validate) {
valid = inputElement.validate(this._inputElementValue);
} else {
valid = inputElement.checkValidity();
}
this.invalid = !valid;
}
// Call this last to notify the add-ons.
this._handleValue(inputElement);
},
_onIronInputValidate: function(event) {
this.invalid = this._inputElement.invalid;
},
_invalidChanged: function() {
if (this._addons) {
this.updateAddons({invalid: this.invalid});
}
},
/**
* Call this to update the state of add-ons.
* @param {Object} state Add-on state.
*/
updateAddons: function(state) {
for (var addon, index = 0; addon = this._addons[index]; index++) {
addon.update(state);
}
},
_computeInputContentClass: function(noLabelFloat, alwaysFloatLabel, focused, invalid, _inputHasContent) {
var cls = 'input-content';
if (!noLabelFloat) {
var label = this.querySelector('label');
if (alwaysFloatLabel || _inputHasContent) {
cls += ' label-is-floating';
// If the label is floating, ignore any offsets that may have been
// applied from a prefix element.
this.$.labelAndInputContainer.style.position = 'static';
if (invalid) {
cls += ' is-invalid';
} else if (focused) {
cls += " label-is-highlighted";
}
} else {
// When the label is not floating, it should overlap the input element.
if (label) {
this.$.labelAndInputContainer.style.position = 'relative';
}
}
} else {
if (_inputHasContent) {
cls += ' label-is-hidden';
}
}
return cls;
},
_computeUnderlineClass: function(focused, invalid) {
var cls = 'underline';
if (invalid) {
cls += ' is-invalid';
} else if (focused) {
cls += ' is-highlighted'
}
return cls;
},
_computeAddOnContentClass: function(focused, invalid) {
var cls = 'add-on-content';
if (invalid) {
cls += ' is-invalid';
} else if (focused) {
cls += ' is-highlighted'
}
return cls;
}
});
</script>
<dom-module id="paper-input-error" assetpath="../../../paper-input/">
<template>
<style>
:host {
display: inline-block;
visibility: hidden;
color: var(--paper-input-container-invalid-color, --error-color);
@apply(--paper-font-caption);
@apply(--paper-input-error);
position: absolute;
left:0;
right:0;
}
:host([invalid]) {
visibility: visible;
};
</style>
<content></content>
</template>
</dom-module>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { PaperInputAddonBehavior } from '@polymer/paper-input/paper-input-addon-behavior.js';
Polymer({
is: 'paper-input-error',
behaviors: [
PaperInputAddonBehavior
],
properties: {
/**
* True if the error is showing.
*/
invalid: {
readOnly: true,
reflectToAttribute: true,
type: Boolean
}
},
/**
* This overrides the update function in PaperInputAddonBehavior.
* @param {{
* inputElement: (Element|undefined),
* value: (string|undefined),
* invalid: boolean
* }} state -
* inputElement: The input element.
* value: The input value.
* invalid: True if the input value is invalid.
*/
update: function(state) {
this._setInvalid(state.invalid);
}
});
</script>
<dom-module id="paper-input" assetpath="../../../paper-input/">
<template>
<style>
:host {
display: block;
}
:host([focused]) {
outline: none;
}
:host([hidden]) {
display: none !important;
}
input::-webkit-input-placeholder {
color: var(--paper-input-container-color, --secondary-text-color);
}
input:-moz-placeholder {
color: var(--paper-input-container-color, --secondary-text-color);
}
input::-moz-placeholder {
color: var(--paper-input-container-color, --secondary-text-color);
}
input:-ms-input-placeholder {
color: var(--paper-input-container-color, --secondary-text-color);
}
label {
pointer-events: none;
}
</style>
<paper-input-container no-label-float="[[noLabelFloat]]" always-float-label="[[_computeAlwaysFloatLabel(alwaysFloatLabel,placeholder)]]" auto-validate$="[[autoValidate]]" disabled$="[[disabled]]" invalid="[[invalid]]">
<content select="[prefix]"></content>
<label hidden$="[[!label]]" aria-hidden="true" for="input">[[label]]</label>
<input is="iron-input" id="input" aria-labelledby$="[[_ariaLabelledBy]]" aria-describedby$="[[_ariaDescribedBy]]" disabled$="[[disabled]]" title$="[[title]]" bind-value="{{value}}" invalid="{{invalid}}" prevent-invalid-input="[[preventInvalidInput]]" allowed-pattern="[[allowedPattern]]" validator="[[validator]]" type$="[[type]]" pattern$="[[pattern]]" required$="[[required]]" autocomplete$="[[autocomplete]]" autofocus$="[[autofocus]]" inputmode$="[[inputmode]]" minlength$="[[minlength]]" maxlength$="[[maxlength]]" min$="[[min]]" max$="[[max]]" step$="[[step]]" name$="[[name]]" placeholder$="[[placeholder]]" readonly$="[[readonly]]" list$="[[list]]" size$="[[size]]" autocapitalize$="[[autocapitalize]]" autocorrect$="[[autocorrect]]" on-change="_onChange" tabindex$="[[tabindex]]" autosave$="[[autosave]]" results$="[[results]]" accept$="[[accept]]" multiple$="[[multiple]]">
<content select="[suffix]"></content>
<template is="dom-if" if="[[errorMessage]]">
<paper-input-error aria-live="assertive">[[errorMessage]]</paper-input-error>
</template>
<template is="dom-if" if="[[charCounter]]">
<paper-input-char-counter></paper-input-char-counter>
</template>
</paper-input-container>
</template>
</dom-module>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { IronFormElementBehavior } from '@polymer/iron-form-element-behavior/iron-form-element-behavior.js';
import { PaperInputBehavior } from '@polymer/paper-input/paper-input-behavior.js';
Polymer({
is: 'paper-input',
behaviors: [
IronFormElementBehavior,
PaperInputBehavior
]
});
</script>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
/** @type string Most charts use this package. */
var DEFACTO_CHART_PACKAGE = 'corechart';
/**
* A collection of chart type details.
*
* @type !Object<string, {ctor: string, pkg: (string|undefined)}>
*/
var CHART_CONSTRUCTORS = {
'area': {
ctor: 'AreaChart',
},
'bar': {
ctor: 'BarChart',
},
'md-bar': {
ctor: 'Bar',
pkg: 'bar',
},
'bubble': {
ctor: 'BubbleChart',
},
'candlestick': {
ctor: 'CandlestickChart',
},
'column': {
ctor: 'ColumnChart',
},
'combo': {
ctor: 'ComboChart',
},
'geo': {
ctor: 'GeoChart',
},
'histogram': {
ctor: 'Histogram',
},
'line': {
ctor: 'LineChart',
},
'pie': {
ctor: 'PieChart',
},
'scatter': {
ctor: 'ScatterChart',
},
'stepped-area': {
ctor: 'SteppedAreaChart',
},
'table': {
ctor: 'Table',
pkg: 'table',
},
'timeline': {
ctor: 'Timeline',
pkg: 'timeline',
},
'gauge': {
ctor: 'Gauge',
pkg: 'gauge',
},
'treemap': {
ctor: 'TreeMap',
pkg: 'treemap',
},
};
/**
* Returns the namespace for the given chart type.
* @param {string} type the type of the chart
* @return {!Object} the namespace that contains the chart's constructor
*/
function namespaceForType(type) {
return google[type.startsWith('md-') ? 'charts' : 'visualization'];
}
/** @type !Object<string, boolean> set-like object of gviz packages to load */
var packagesToLoad = {};
/** @type !Object<string, !Promise> promises for the various packages */
var promises = {};
/** @type !Object<string, function(!Object)> resolves for the package promises */
var resolves = {};
Polymer({
is: 'google-chart-loader',
properties: {
/**
* Adds packages to the list of packages to load.
*
* This is an array consisting of any Google Visualization package names.
*
* @attribute packages
* @type !Array<string>
*/
packages: {
type: Array,
value: function() { return []; },
observer: '_loadPackages',
},
/**
* Loads the package for the chart type specified.
*
* This may be any of the supported `google-chart` types.
* This is mainly used by the `google-chart` element internally.
*
* @attribute type
* @type string
*/
type: {
type: String,
observer: '_loadPackageForType',
},
},
/**
* Gets a promise for the `corechart` package being loaded.
* @return {!Promise<!Object>} google.visualization package promise
* @private
*/
get _corePackage() {
if (promises[DEFACTO_CHART_PACKAGE]) {
return promises[DEFACTO_CHART_PACKAGE];
}
return this._loadPackages([DEFACTO_CHART_PACKAGE]).then(function(pkgs) {
return pkgs[0];
});
},
/**
* Debounces the actual call to load the packages requested.
* We debounce so that load is only called once.
* @private
*/
_loadPackagesDebounce: function() {
this.debounce('loadPackages', function() {
var packages = Object.keys(packagesToLoad);
if (!packages.length) {
return;
}
packagesToLoad = {};
google.charts.load('current', {'packages': packages});
google.charts.setOnLoadCallback(function() {
packages.forEach(function(pkg) {
this.fire('loaded', pkg);
resolves[pkg](google.visualization);
}.bind(this));
}.bind(this));
}, 100);
},
/**
* Adds a list of packages to load.
*
* @param {!Array<string>} pkgs list of packages to load
* @return {!Promise} Promise resolved when all packages are loaded
* @private
*/
_loadPackages: function(pkgs) {
var returns = [];
pkgs.forEach(function(pkg) {
if (!promises[pkg]) {
packagesToLoad[pkg] = true;
promises[pkg] = new Promise(function(resolve) {
resolves[pkg] = resolve;
});
this._loadPackagesDebounce();
}
returns.push(promises[pkg]);
}.bind(this));
return Promise.all(returns);
},
/**
* Adds a package to load for the given type.
*
* @param {string} type the chart type for which we should load the package
* @return {!Promise<!Function>} Promise for the chart type constructor
* @private
*/
_loadPackageForType: function(type) {
var chartData = CHART_CONSTRUCTORS[type];
return this._loadPackages([chartData.pkg || DEFACTO_CHART_PACKAGE])
.then(function() {
return namespaceForType(type)[chartData.ctor];
});
},
/**
* Creates a chart object by type in the specified element.
* Use *only* if you need total control of a chart object.
* Most should just use the `google-chart` element.
*
* @param {string} type the type of chart to create
* @param {!Element} el the element in which to create the chart
* @return {!Promise<!Object>} promise for the created chart object
*/
create: function(type, el) {
return this._loadPackageForType(type).then(function(ctor) {
return new ctor(el);
});
},
/**
* Begins firing Polymer events for the requested chart event.
* Use *only* if you have control of a chart object.
* Most should just use the `google-chart` element.
*
* Events fired all have the same detail object:
* {{
* chart: !Object, // The chart target object
* data: (Object|undefined), // The chart event details
* }}
*
* @param {!Object} chart the chart object to which we should listen
* @param {string} eventName the name of the chart event
* @param {boolean=} opt_once whether to listen only one time
* @return {!Promise<void>} promise resolved when listener is attached
*/
fireOnChartEvent: function(chart, eventName, opt_once) {
return this._corePackage.then(function(viz) {
var adder = opt_once ?
viz.events.addOneTimeListener : viz.events.addListener;
adder(chart, eventName, function(event) {
this.fire('google-chart-' + eventName, {
chart: chart,
data: event,
});
}.bind(this));
}.bind(this));
},
/**
* Creates a DataTable object for use with a chart.
*
* Multiple different argument types are supported. This is because the
* result of loading the JSON data URL is fed into this function for
* DataTable construction and its format is unknown.
*
* The data argument can be one of a few options:
*
* - null/undefined: An empty DataTable is created. Columns must be added
* - !DataTable: The object is simply returned
* - {{cols: !Array, rows: !Array}}: A DataTable in object format
* - {{cols: !Array}}: A DataTable in object format without rows
* - !Array<!Array>: A DataTable in 2D array format
*
* Un-supported types:
*
* - Empty !Array<!Array>: (e.g. `[]`) While technically a valid data
* format, this is rejected as charts will not render empty DataTables.
* DataTables must at least have columns specified. An empty array is most
* likely due to a bug or bad data. If one wants an empty DataTable, pass
* no arguments.
* - Anything else
*
* @param {Array|{cols: !Array, rows: (!Array<!Array>|undefined)}|undefined} data
* the data with which we should use to construct the new DataTable object
* @return {!Promise<!google.visualization.DataTable>} promise for the created DataTable
*/
dataTable: function(data) {
return this._corePackage.then(function(viz) {
if (data == null) {
return new viz.DataTable();
} else if (data.getNumberOfRows) {
// Data is already a DataTable
return data;
} else if (data.cols) { // data.rows may also be specified
// Data is in the form of object DataTable structure
return new viz.DataTable(data);
} else if (data.length > 0) {
// Data is in the form of a two dimensional array.
return viz.arrayToDataTable(data);
} else if (data.length === 0) {
// Chart data was empty.
// We return null instead of creating an empty DataTable because most
// (if not all) charts will render a sticky error in this situation.
return Promise.reject('Data was empty.');
}
return Promise.reject('Data format was not recognized.');
});
},
/**
* Creates a DataView object from a DataTable for use with a chart.
*
* @param {!google.visualization.DataTable} data the DataTable to use
* @return {!Promise<!google.visualization.DataView>} promise for the created DataView
*/
dataView: function(data) {
return this._corePackage.then(function(viz) {
return new viz.DataView(data);
});
},
});
</script>
<dom-module id="google-chart" assetpath="../../../google-chart/">
<template><style>
:host {
display: -webkit-flex;
display: -ms-flex;
display: flex;
margin: 0;
padding: 0;
width: 400px;
height: 300px;
}
:host([type="gauge"]) {
width: 300px;
height: 300px;
}
#chartdiv {
width: 100%;
}
</style>
<google-chart-loader id="loader" type="[[type]]"></google-chart-loader>
<div id="chartdiv"></div>
</template>
</dom-module>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
Polymer({
is: 'google-chart',
/**
* Fired after a chart type is rendered and ready for interaction.
*
* @event google-chart-ready
* @param {{chart: !Object}} The raw chart object.
*/
/**
* Fired when the user makes a selection in the chart.
*
* @event google-chart-select
* @param {{chart: !Object}} The raw chart object.
*/
/** Polymer element properties. */
properties: {
/**
* Sets the type of the chart.
*
* Should be one of:
* - `area`, `bar`, `bubble`, `candlestick`, `column`, `combo`, `geo`,
* `histogram`, `line`, `pie`, `scatter`, `stepped-area`, `treemap`
*
* See <a href="https://google-developers.appspot.com/chart/interactive/docs/gallery">Google Visualization API reference (Chart Gallery)</a>
* for details.
*
* @attribute type
* @type string
*/
type: {
type: String,
value: 'column',
observer: '_typeChanged'
},
/**
* Sets the options for the chart.
*
* Example:
* <pre>{
* title: "Chart title goes here",
* hAxis: {title: "Categories"},
* vAxis: {title: "Values", minValue: 0, maxValue: 2},
* legend: "none"
* };</pre>
* See <a href="https://google-developers.appspot.com/chart/interactive/docs/gallery">Google Visualization API reference (Chart Gallery)</a>
* for the options available to each chart type.
*
* @attribute options
* @type {!Object|undefined}
*/
options: {
type: Object,
observer: 'redraw'
},
/**
* Sets the data columns for this object.
*
* When specifying data with `cols` you must also specify `rows`, and
* not specify `data`.
*
* Example:
* <pre>[{label: "Categories", type: "string"},
* {label: "Value", type: "number"}]</pre>
* See <a href="https://google-developers.appspot.com/chart/interactive/docs/reference#DataTable_addColumn">Google Visualization API reference (addColumn)</a>
* for column definition format.
*
* @attribute cols
* @type {!Array|undefined}
*/
cols: {
type: Array,
observer: '_rowsOrColumnsChanged',
},
/**
* Sets the data rows for this object.
*
* When specifying data with `rows` you must also specify `cols`, and
* not specify `data`.
*
* Example:
* <pre>[["Category 1", 1.0],
* ["Category 2", 1.1]]</pre>
* See <a href="https://google-developers.appspot.com/chart/interactive/docs/reference#addrow">Google Visualization API reference (addRow)</a>
* for row format.
*
* @attribute rows
* @type {!Array<!Array>|undefined}
*/
rows: {
type: Array,
observer: '_rowsOrColumnsChanged',
},
/**
* Sets the entire dataset for this object.
* Can be used to provide the data directly, or to provide a URL from
* which to request the data.
*
* The data format can be a two-dimensional array or the DataTable format
* expected by Google Charts.
* See <a href="https://google-developers.appspot.com/chart/interactive/docs/reference#DataTable">Google Visualization API reference (DataTable constructor)</a>
* for data table format details.
*
* When specifying data with `data` you must not specify `cols` or `rows`.
*
* Example:
* <pre>[["Categories", "Value"],
* ["Category 1", 1.0],
* ["Category 2", 1.1]]</pre>
*
* @attribute data
* @type {!google.visualization.DataTable|
* !Array<!Array>|
* !{cols: !Array, rows: (!Array<!Array>|undefined)}|
* string|
* undefined}
*/
data: {
type: Object,
observer: '_dataChanged'
},
/**
* Sets the entire dataset for this object to a Google DataView.
*
* See <a href="https://google-developers.appspot.com/chart/interactive/docs/reference#dataview-class">Google Visualization API reference (DataView)</a>
* for details.
*
* When specifying data with `view` you must not specify `data`, `cols` or `rows`.
*
* @attribute view
* @type {!google.visualization.DataView|undefined}
*/
view: {
type: Object,
observer: '_viewChanged'
},
/**
* Selected datapoint(s) in the chart.
*
* An array of objects, each with a numeric row and/or column property.
* `row` and `column` are the zero-based row or column number of an item
* in the data table to select.
*
* To select a whole column, set row to null;
* to select a whole row, set column to null.
*
* Example:
* <pre>
* [{row:0,column:1}, {row:1, column:null}]
* </pre>
*
* @attribute selection
* @type {!Array|undefined}
*/
selection: {
type: Array,
notify: true,
observer: '_setSelection'
},
/**
* Whether the chart is currently rendered.
*
* @type boolean
*/
drawn: {
type: Boolean,
readOnly: true,
value: false
},
},
observers: ['_draw(_chart, _dataView)'],
listeners: {
'google-chart-select': '_updateSelection',
'google-chart-ready': '_onChartReady'
},
/** @type Object Internal Google Visualization chart object */
_chart: null,
/** @type google.visualization.DataView Internal data state */
_dataView: null,
/** @type Array Internal selection state */
_selection: null,
// The chart type was changed.
// We need to create a new chart and redraw.
_typeChanged: function() {
this.$.loader.create(this.type, this.$.chartdiv)
.then(function(chart) {
this.$.loader.fireOnChartEvent(chart, 'select');
this.$.loader.fireOnChartEvent(chart, 'ready');
this._setDrawn(false);
this._chart = chart;
}.bind(this));
},
_setSelection: function() {
// Note: Some charts (e.g. TreeMap) must have a selection.
if (!this.drawn || !this.selection || this.selection === this._selection) {
return;
}
if (this._chart.setSelection) {
this._chart.setSelection(this.selection);
}
this._selection = this.selection;
},
_updateSelection: function() {
this.selection = this._selection = this._chart.getSelection();
},
_onChartReady: function() {
this._setDrawn(true);
this._selection = null;
this._setSelection();
},
/**
* Redraws the chart.
*
* Called automatically when data/type/selection attributes change.
* Call manually to handle view updates, page resizes, etc.
*
* @method redraw
*/
redraw: function() {
if (!this._chart || !this._dataView) { return; }
this._draw(this._chart, this._dataView);
},
_draw: function(chart, data) {
try {
this._setDrawn(false);
chart.draw(data, this.options || {});
} catch(error) {
this.$.chartdiv.innerHTML = error;
}
},
/**
* Returns the chart serialized as an image URI.
*
* Call this after the chart is drawn (google-chart-render event).
*
* @return {?string} Returns image URI.
*/
get imageURI() {
if (!this._chart) { return null; }
return this._chart.getImageURI();
},
/**
* Handles changes to the `view` attribute.
*
* @param {!google.visualization.DataView|undefined} view The new view value
*/
_viewChanged: function(view) {
if (!view) { return; }
this._dataView = view;
},
// Handles changes to the rows & columns attributes.
_rowsOrColumnsChanged: function() {
var rows = this.rows, cols = this.cols;
if (!rows || !cols) { return; }
this.$.loader.dataTable()
.then(function(dataTable) {
cols.forEach(function(col) {
dataTable.addColumn(col);
});
dataTable.addRows(rows);
return dataTable;
}.bind(this))
.then(this.$.loader.dataView.bind(this.$.loader))
.then(function(dataView) {
this._dataView = dataView;
}.bind(this))
.catch(function(reason) {
this.$.chartdiv.innerHTML = reason;
}.bind(this));
},
/**
* Handles changes to the `data` attribute.
*
* @param {
* !google.visualization.DataTable|
* !Array<!Array>|
* !{cols: !Array, rows: (!Array<!Array>|undefined)}|
* string|
* undefined} data The new data value
*/
_dataChanged: function(data) {
var dataPromise;
if (!data) { return; }
if (typeof data == 'string' || data instanceof String) {
// Load data asynchronously, from external URL.
var request = /** @type {!IronRequestElement} */ (document.createElement('iron-request'));
dataPromise = request.send({
url: /** @type string */(data), handleAs: 'json'
}).then(function(xhr) { return xhr.response; });
} else {
// Data is all ready to be processed.
dataPromise = Promise.resolve(data);
}
dataPromise
.then(this.$.loader.dataTable.bind(this.$.loader))
.then(this.$.loader.dataView.bind(this.$.loader))
.then(function(dataView) {
this._dataView = dataView;
}.bind(this));
}
});
</script>
<i18n-attr-repo>
<template id="custom">
<text-attribute-element custom-text-attr2=""></text-attribute-element>
<text-attribute-element custom-text-attr4="$"></text-attribute-element>
<text-attribute-element custom-text-attr5="$"></text-attribute-element>
<text-attribute-element i18n-target=""></text-attribute-element>
<text-attribute-element i18n-target="boolean-attr,!boolean-attr2,string-attr=abc|def,empty-attr=,type1"></text-attribute-element>
<text-attribute-element i18n-target="boolean-attr,boolean-attr2,string-attr=aaa,type2"></text-attribute-element>
<text-attribute-element i18n-target="string-attr=aaa,string-attr2=bbb,type3"></text-attribute-element>
<text-attribute-element i18n-target="boolean-attr=,type4"></text-attribute-element>
<text-attribute-element i18n-target2="boolean-attr,!boolean-attr2,string-attr=abc|def,empty-attr=,type1"></text-attribute-element>
<text-attribute-element i18n-target2="boolean-attr,boolean-attr2,,string-attr=aaa,,type2"></text-attribute-element>
<text-attribute-element i18n-target2="string-attr=aaa,string-attr2=bbb,type3"></text-attribute-element>
<text-attribute-element i18n-target2="boolean-attr=,type4"></text-attribute-element>
<text-attribute-element i18n-target2="type5"></text-attribute-element>
<text-attribute-element i18n-target3="string-attr=aaa,type1"></text-attribute-element>
<text-attribute-element i18n-target3=""></text-attribute-element>
<text-attribute-element i18n-target4=""></text-attribute-element>
<text-attribute-element i18n-target4="string-attr=aaa,type1"></text-attribute-element>
<text-attribute-element i18n-target5=""></text-attribute-element>
<text-attribute-element i18n-target5="type1"></text-attribute-element>
<text-attribute-element i18n-target="boolean-attr=,type4"></text-attribute-element>
<text-attribute-element i18n-target="string-attr=aaa,string-attr2=bbb,type3"></text-attribute-element>
<text-attribute-element i18n-target="boolean-attr,,boolean-attr2,,string-attr=aaa"></text-attribute-element>
<text-attribute-element i18n-target="boolean-attr,!boolean-attr2,string-attr=abc|def,empty-attr=,type1"></text-attribute-element>
<text-attribute-element i18n-target=""></text-attribute-element>
<text-attribute-element i18n-target2="type5"></text-attribute-element>
<text-attribute-element i18n-target2="boolean-attr="></text-attribute-element>
<text-attribute-element i18n-target2="string-attr=aaa,string-attr2=bbb,type3"></text-attribute-element>
<text-attribute-element i18n-target2="boolean-attr,!boolean-attr2,,string-attr=abc|def,,empty-attr=,type1"></text-attribute-element>
<text-attribute-element i18n-target2="boolean-attr,,boolean-attr2,,string-attr=aaa,type2"></text-attribute-element>
<text-attribute-element i18n-target3="string-attr=aaa,type1"></text-attribute-element>
<text-attribute-element i18n-target3=""></text-attribute-element>
<text-attribute-element i18n-target4=""></text-attribute-element>
<text-attribute-element i18n-target4="string-attr=aaa,type1"></text-attribute-element>
<text-attribute-element i18n-target5=""></text-attribute-element>
<text-attribute-element i18n-target5="type1"></text-attribute-element>
<text-attribute-element i18n-target6="type5"></text-attribute-element>
<text-attribute-element i18n-target6="boolean-attr="></text-attribute-element>
<text-attribute-element i18n-target6="boolean-attr,boolean-attr2,type1"></text-attribute-element>
<text-attribute-element i18n-target6="boolean-attr,boolean-attr2,string-attr=aaa,type2"></text-attribute-element>
<text-attribute-element i18n-target7="string-attr=aaa,type1"></text-attribute-element>
<text-attribute-element i18n-target7="invalid!attr=aaa,typeX"></text-attribute-element>
</template>
</i18n-attr-repo>
<dom-module id="text-attribute-element" assetpath="simple-attribute-element/">
<template text-attr="custom-text-attr1 custom-text-attr3" localizable-text="embedded">
<span id="attr1">{{customTextAttr1}}</span>
<span id="attr2">{{customTextAttr2}}</span>
<span id="attr3">{{customTextAttr3}}</span>
<span id="attr4">{{outOfScopeAttr}}</span>
<span>{{text.span_4}}</span>
<template id="localizable-text">
<json-data>
{
"meta": {},
"model": {},
"span_4": "text"
}
</json-data>
</template>
</template>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
Polymer({
is: 'text-attribute-element',
behaviors: [
BehaviorsStore.I18nBehavior
],
properties: {
customTextAttr1: {
type: String,
reflectToAttribute: true
},
customTextAttr2: {
type: String,
reflectToAttribute: true
},
customTextAttr3: {
type: String,
reflectToAttribute: true
},
outOfScopeAttr: {
type: String,
reflectToAttribute: true
},
i18nTarget: {
type: String
},
i18nTarget2: {
type: String
}
},
observers: [
],
listeners: {
'lang-updated': '_langUpdated'
},
ready: function () {
//this.observeHtmlLang = false;
},
attached: function () {
},
_langUpdated: function () {
this.model = deepcopy(this.text.model);
}
});
</script>
</dom-module>
<dom-module id="simple-attribute-element" assetpath="simple-attribute-element/">
<template localizable-text="embedded">
<style attr="This is not extracted">
google-chart {
width: 300px;
}
</style>
<div id="outer-div">
<div id="ordinary-div" attr="This is not targeted for extraction">{{text.ordinary-div}}</div>
<input id="standard-input" placeholder="{{model.standard-input.placeholder}}">
<input placeholder="{{model.outer-div:input_2.placeholder}}">
<paper-input id="paper-input-element" label="{{model.paper-input-element.label}}" error-message="{{model.paper-input-element.error-message}}" placeholder="{{model.paper-input-element.placeholder}}" value="this is not a target">
</paper-input>
<paper-input label="{{model.outer-div:paper-input_4.label}}" error-message="{{model.outer-div:paper-input_4.error-message}}" placeholder="{{model.outer-div:paper-input_4.placeholder}}" value="this is not a target">
</paper-input>
<google-chart type="pie" id="pie-chart" options="{{model.pie-chart.options}}" cols="{{model.pie-chart.cols}}" rows="{{model.pie-chart.rows}}">
</google-chart>
<google-chart id="column-chart" type="column" options="{{model.column-chart.options}}" data="{{model.column-chart.data}}">
</google-chart>
<text-attribute-element id="custom-attr" custom-text-attr1="{{model.custom-attr.custom-text-attr1}}" custom-text-attr2="{{model.custom-attr.custom-text-attr2}}" custom-text-attr3="{{model.custom-attr.custom-text-attr3}}" out-of-scope-attr="out of scope attr">
</text-attribute-element>
<text-attribute-element id="selective-attr" boolean-attr="" empty-attr="" string-attr="abc" custom-text-attr4$="{{i18nFormat(model.selective-attr.custom-text-attr4.0,text.ordinary-div,text.ordinary-div,text.ordinary-div,text.ordinary-div)}}" custom-text-attr5$="[[text.ordinary-div]]{{model.selective-attr.custom-text-attr5.1}}{{or('',text.ordinary-div)}}{{model.selective-attr.custom-text-attr5.3}}[[text.ordinary-div]]" i18n-target="{{i18nFormat(model.selective-attr.i18n-target.0,text.ordinary-div,text.ordinary-div)}}" i18n-target2="{{model.selective-attr.i18n-target2.0}}{{or('',text.ordinary-div)}}{{model.selective-attr.i18n-target2.2}}[[text.ordinary-div]]">
</text-attribute-element>
<text-attribute-element id="selective-attr2" boolean-attr="" boolean-attr2="" string-attr="aaa" i18n-target="{{model.selective-attr2.i18n-target}}">
</text-attribute-element>
<text-attribute-element id="selective-attr3" i18n-target6="{{model.selective-attr3.i18n-target6}}">
</text-attribute-element>
<text-attribute-element id="selective-attr4" boolean-attr="" i18n-target6="{{model.selective-attr4.i18n-target6}}" i18n-target7="unmatching i18n-target4 attribute">
</text-attribute-element>
<text-attribute-element id="selective-attr5" string-attr="xxx" i18n-target7="unmatching i18n-target7 attribute">
</text-attribute-element>
<span id="test-json-data-1">{{model.json-data-id.attr1}}</span>
<span id="test-json-data-2">{{model.json-data-id.i18n-target-attr}}</span>
<span id="test-json-data-3">{{model.template_2:json-data_1.attr1}}</span>
<span id="test-json-data-4">{{model.template_2:json-data_1.i18n-target-attr}}</span>
</div>
<template>
<json-data id="json-data-id" attr1="{{model.json-data-id.attr1}}" i18n-target-attr="{{model.json-data-id.i18n-target-attr}}"></json-data>
<json-data attr1="{{model.template_2:json-data_1.attr1}}" i18n-target-attr="{{model.template_2:json-data_1.i18n-target-attr}}"></json-data>
</template>
<template id="localizable-text">
<json-data>
{
"meta": {},
"model": {
"standard-input": {
"placeholder": "standard HTML5 attribute"
},
"outer-div:input_2": {
"placeholder": "standard HTML5 attribute without id"
},
"paper-input-element": {
"label": "paper-input label",
"error-message": "paper-input error message",
"placeholder": "paper-input placeholder"
},
"outer-div:paper-input_4": {
"label": "paper-input label without id",
"error-message": "paper-input error message without id",
"placeholder": "paper-input placeholder without id"
},
"pie-chart": {
"options": {
"title": "Distribution of days in 2001H1"
},
"cols": [
{
"label": "Month",
"type": "string"
},
{
"label": "Days",
"type": "number"
}
],
"rows": [
[
"Jan",
31
],
[
"Feb",
28
],
[
"Mar",
31
],
[
"Apr",
30
],
[
"May",
31
],
[
"Jun",
30
]
]
},
"column-chart": {
"options": {
"title": "Inventory"
},
"data": [
[
"Year",
"Things",
"Stuff"
],
[
"2004",
1000,
400
],
[
"2005",
1170,
460
],
[
"2006",
660,
1120
],
[
"2007",
1030,
540
]
]
},
"custom-attr": {
"custom-text-attr1": "custom text attribute 1",
"custom-text-attr2": "custom text attribute 2",
"custom-text-attr3": "custom text attribute 3"
},
"selective-attr": {
"custom-text-attr4": [
"{1} custom-text-attr4 attribute with param {2} and param {3} {4}",
"{{text.ordinary-div}}",
"{{text.ordinary-div}}",
"[[text.ordinary-div]]",
"{{text.ordinary-div}}"
],
"custom-text-attr5": [
"[[text.ordinary-div]]",
" custom-text-attr5 attribute with param ",
"{{or('',text.ordinary-div)}}",
" and param ",
"[[text.ordinary-div]]"
],
"i18n-target": [
"i18n-target attribute with param {1} and param {2}",
"{{text.ordinary-div}}",
"[[text.ordinary-div]]"
],
"i18n-target2": [
"i18n-target2 attribute with param ",
"{{or('',text.ordinary-div)}}",
" and param ",
"[[text.ordinary-div]]"
]
},
"selective-attr2": {
"i18n-target": "i18n-target attribute 2"
},
"selective-attr3": {
"i18n-target6": "i18n-target6 attribute 2"
},
"selective-attr4": {
"i18n-target6": "i18n-target6 attribute 3"
},
"json-data-id": {
"attr1": "this attr1 is extracted",
"i18n-target-attr": "this attribute is also extracted"
},
"template_2:json-data_1": {
"attr1": "this attr1 without id is extracted",
"i18n-target-attr": "this attribute without id is also extracted"
}
},
"ordinary-div": "text 1"
}
</json-data>
</template>
</template>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
Polymer({
is: 'simple-attribute-element',
behaviors: [
BehaviorsStore.I18nBehavior
],
properties: {
},
observers: [
],
listeners: {
'lang-updated': '_langUpdated',
'pie-chart.google-chart-render': '_pieChartRendered',
'column-chart.google-chart-render': '_columnChartRendered'
},
ready: function () {
//this.observeHtmlLang = false;
},
attached: function () {
this._intervalId = window.setInterval(this._checkChartStatus.bind(this), 1000);
},
_checkChartStatus: function () {
var pieChartInnerHtml = this.$['pie-chart'].$.chartdiv.innerHTML;
var columnChartInnerHtml = this.$['column-chart'].$.chartdiv.innerHTML;
var notLoaded = false;
if (pieChartInnerHtml === 'Undefined chart type') {
this.isPieChartRendered = true; // google api to blame; this is not responsible
}
if (columnChartInnerHtml === 'Undefined chart type') {
this.isColumnChartRendered = true; // google api to blame; this is not responsible
}
if (this.isPieChartRendered && this.isColumnChartRendered) {
window.clearInterval(this._intervalId);
this.fire('local-dom-ready');
}
},
_langUpdated: function (e) {
if (dom(e).rootTarget === this) {
this.model = deepcopy(this.text.model);
}
},
_pieChartRendered: function () {
this.isPieChartRendered = true;
if (this.isPieChartRendered && this.isColumnChartRendered) {
this.fire('local-dom-ready');
}
},
_columnChartRendered: function () {
this.isColumnChartRendered = true;
if (this.isPieChartRendered && this.isColumnChartRendered) {
this.fire('local-dom-ready');
}
}
});
</script>
</dom-module>
<dom-module id="fallback-text-element" assetpath="fallback-text-element/">
<template localizable-text="embedded">{{text.text}}<div><div></div></div>
<span id="whitespace"> </span>
<h1>{{text.h1_3}}</h1>{{text.text_4}}<span>{{text.span_5}}</span>
<span>{{text.span_6}}</span>
<span id="label-1">{{text.label-1}}</span>
<span id="label-2">{{text.label-2}}</span>
<div>
<span>{{text.div_9:span}}</span>
<span>{{text.div_9:span_1}}</span>
<div><div>{{text.div_9:div_2:div}}</div></div>
</div>
<div>{{text.div_10:text}}<span>{{text.div_10:span_1}}</span>{{text.div_10:text_2}}<span>{{text.div_10:span_3}}</span>
<div><div>{{text.div_10:div_4:div}}</div></div>{{text.div_10:text_5}}</div>
<div id="toplevel-div">
<span>{{text.toplevel-div:span}}</span>
<span>{{text.toplevel-div:span_1}}</span>
<div id="second-level-div">
<div id="third-level-div">{{text.third-level-div}}</div>
<div>{{text.second-level-div:div_1}}</div>
</div>
</div>
<div>
<ul>
<li>{{text.div_12:ul:li}}</li>
<li>{{text.div_12:ul:li_1}}</li>
<li>{{text.div_12:ul:li_2}}</li>
</ul>
<ul id="line-items">
<li>{{text.line-items:li}}</li>
<li>{{text.line-items:li_1}}</li>
<li>{{text.line-items:li_2}}</li>
</ul>
</div>
<p><i18n-format lang="{{effectiveLang}}"><span>{{text.p_13.0}}</span><b param="1">{{text.p_13.1}}</b><code param="2">{{text.p_13.2}}</code></i18n-format></p>
<p id="paragraph"><i18n-format lang="{{effectiveLang}}"><span>{{text.paragraph.0}}</span><b param="1">{{text.paragraph.1}}</b><code param="2">{{text.paragraph.2}}</code></i18n-format></p>{{text.text_15}}<template id="localizable-text">
<json-data>
{
"meta": {},
"model": {},
"text": " outermost text at the beginning ",
"h1_3": "outermost header 1",
"text_4": " outermost text in the middle ",
"span_5": "simple text without id",
"span_6": "simple text without id 2",
"label-1": "simple text with id",
"label-2": "simple text with id 2",
"div_9:span": "simple text within div",
"div_9:span_1": "simple text within div 2",
"div_9:div_2:div": "great grandchild text within div",
"div_10:text": " simple text as the first element in div ",
"div_10:span_1": "simple text within div",
"div_10:text_2": " simple text in the middle of div ",
"div_10:span_3": "simple text within div 2",
"div_10:div_4:div": "great grandchild text within div",
"div_10:text_5": " simple text at the last element in div ",
"toplevel-div:span": "simple text within div",
"toplevel-div:span_1": "simple text within div 2",
"third-level-div": "great grandchild text within div",
"second-level-div:div_1": "great grandchild text within div without id",
"div_12:ul:li": "line item without id 1",
"div_12:ul:li_1": "line item without id 2",
"div_12:ul:li_2": "line item without id 3",
"line-items:li": "line item with id 1",
"line-items:li_1": "line item with id 2",
"line-items:li_2": "line item with id 3",
"p_13": [
"A paragraph with {1} is converted to {2}.",
"parameters",
"<i18n-format>"
],
"paragraph": [
"A paragraph with {1} is converted to {2}.",
"id",
"<i18n-format>"
],
"text_15": " outermost text at the end "
}
</json-data>
</template>
</template>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
Polymer({
is: 'fallback-text-element',
behaviors: [
BehaviorsStore.I18nBehavior
],
properties: {
},
observers: [
],
listeners: {
'lang-updated': '_langUpdated'
},
ready: function () {
//this.observeHtmlLang = false;
},
attached: function () {
},
_langUpdated: function (e) {
if (dom(e).rootTarget === this) {
this.model = deepcopy(this.text.model);
}
}
});
</script>
</dom-module>
<dom-module id="compound-binding-element" assetpath="compound-binding-element/">
<template localizable-text="embedded"><i18n-format lang="{{effectiveLang}}"><span>{{text.text.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format><div><div></div></div>
<span id="whitespace"> </span>
<h1><i18n-format lang="{{effectiveLang}}"><span>{{text.h1_3.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></h1><i18n-format lang="{{effectiveLang}}"><span>{{text.text_4.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format><span><i18n-format lang="{{effectiveLang}}"><span>{{text.span_5.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></span>
<span><i18n-format lang="{{effectiveLang}}"><span>{{text.span_6.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></span>
<span id="label-1"><i18n-format lang="{{effectiveLang}}"><span>{{text.label-1.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></span>
<span id="label-2"><i18n-format lang="{{effectiveLang}}"><span>{{text.label-2.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></span>
<div>
<span><i18n-format lang="{{effectiveLang}}"><span>{{text.div_9:span.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></span>
<span><i18n-format lang="{{effectiveLang}}"><span>{{text.div_9:span_1.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></span>
<div><div><i18n-format lang="{{effectiveLang}}"><span>{{text.div_9:div_2:div.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></div></div>
</div>
<div><i18n-format lang="{{effectiveLang}}"><span>{{text.div_10:text.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format><span><i18n-format lang="{{effectiveLang}}"><span>{{text.div_10:span_1.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></span><i18n-format lang="{{effectiveLang}}"><span>{{text.div_10:text_2.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format><span><i18n-format lang="{{effectiveLang}}"><span>{{text.div_10:span_3.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></span>
<div><div><i18n-format lang="{{effectiveLang}}"><span>{{text.div_10:div_4:div.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></div></div><i18n-format lang="{{effectiveLang}}"><span>{{text.div_10:text_5.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></div>
<div id="toplevel-div">
<span><i18n-format lang="{{effectiveLang}}"><span>{{text.toplevel-div:span.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></span>
<span><i18n-format lang="{{effectiveLang}}"><span>{{text.toplevel-div:span_1.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></span>
<div id="second-level-div">
<div id="third-level-div"><i18n-format lang="{{effectiveLang}}"><span>{{text.third-level-div.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></div>
<div><i18n-format lang="{{effectiveLang}}"><span>{{text.second-level-div:div_1.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></div>
</div>
</div>
<div>
<ul>
<li><i18n-format lang="{{effectiveLang}}"><span>{{text.div_12:ul:li.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></li>
<li><i18n-format lang="{{effectiveLang}}"><span>{{text.div_12:ul:li_1.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></li>
<li><i18n-format lang="{{effectiveLang}}"><span>{{text.div_12:ul:li_2.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></li>
</ul>
<ul id="line-items">
<li><i18n-format lang="{{effectiveLang}}"><span>{{text.line-items:li.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></li>
<li><i18n-format lang="{{effectiveLang}}"><span>{{text.line-items:li_1.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></li>
<li><i18n-format lang="{{effectiveLang}}"><span>{{text.line-items:li_2.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></li>
</ul>
</div>
<p><i18n-format lang="{{effectiveLang}}"><span>{{text.p_13.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></p>
<p id="paragraph"><i18n-format lang="{{effectiveLang}}"><span>{{text.paragraph.0}}</span><b param="1">{{text.paragraph.1}}</b><span param="2">{{param1}}</span><span param="3">{{param2}}</span><code param="4">{{text.paragraph.4}}</code></i18n-format></p><i18n-format lang="{{effectiveLang}}"><span>{{text.text_15.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format><template id="localizable-text">
<json-data>
{
"meta": {},
"model": {},
"text": [
" outermost text at the beginning with compound {1} and {2} variables ",
"{{param1}}",
"{{param2}}"
],
"h1_3": [
"outermost header 1 with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"text_4": [
" outermost text in the middle with {1} and {2} variables ",
"{{param1}}",
"{{param2}}"
],
"span_5": [
"simple text without id with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"span_6": [
"simple text without id 2 with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"label-1": [
"simple text with id and {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"label-2": [
"simple text with id and {1} and {2} variables 2",
"{{param1}}",
"{{param2}}"
],
"div_9:span": [
"simple text within div with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"div_9:span_1": [
"simple text within div with {1} and {2} variables 2",
"{{param1}}",
"{{param2}}"
],
"div_9:div_2:div": [
"great grandchild text within div with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"div_10:text": [
" simple text as the first element in div with {1} and {2} variables ",
"{{param1}}",
"{{param2}}"
],
"div_10:span_1": [
"simple text within div with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"div_10:text_2": [
" simple text in the middle of div with {1} and {2} variables ",
"{{param1}}",
"{{param2}}"
],
"div_10:span_3": [
"simple text within div with {1} and {2} variables 2",
"{{param1}}",
"{{param2}}"
],
"div_10:div_4:div": [
"great grandchild text within div with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"div_10:text_5": [
" simple text at the last element in div with {1} and {2} variables ",
"{{param1}}",
"{{param2}}"
],
"toplevel-div:span": [
"simple text within div with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"toplevel-div:span_1": [
"simple text within div 2 with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"third-level-div": [
"great grandchild text within div with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"second-level-div:div_1": [
"great grandchild text within div without id with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"div_12:ul:li": [
"line item without id 1 with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"div_12:ul:li_1": [
"line item without id 2 with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"div_12:ul:li_2": [
"line item without id 3 with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"line-items:li": [
"line item with id 1 with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"line-items:li_1": [
"line item with id 2 with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"line-items:li_2": [
"line item with id 3 with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"p_13": [
"A paragraph with {1} is converted to {2}.",
"{{param1}}",
"{{param2}}"
],
"paragraph": [
"A paragraph with {1}, {2}, and {3} is converted to {4}.",
"id",
"{{param1}}",
"{{param2}}",
"<i18n-format>"
],
"text_15": [
" outermost text at the end with {1} and {2} variables ",
"{{param1}}",
"{{param2}}"
]
}
</json-data>
</template>
</template>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
Polymer({
is: 'compound-binding-element',
behaviors: [
BehaviorsStore.I18nBehavior
],
properties: {
param1: {
type: String,
value: 'parameter 1'
},
param2: {
type: String,
value: 'parameter 2'
}
},
observers: [
],
listeners: {
'lang-updated': '_langUpdated'
},
ready: function () {
//this.observeHtmlLang = false;
},
attached: function () {
},
_langUpdated: function (e) {
if (dom(e).rootTarget === this) {
this.model = deepcopy(this.text.model);
}
}
});
</script>
</dom-module>
<dom-module id="simple-text-id-element" assetpath="simple-text-id-element/">
<template localizable-text="embedded">{{text.text}}<div><div></div></div>
<span text-id="whitespace"> </span>
<h1>{{text.h1_3}}</h1>{{text.text_4}}<span>{{text.span_5}}</span>
<span>{{text.span_6}}</span>
<span text-id="label-1">{{text.label-1}}</span>
<span text-id="label-2">{{text.label-2}}</span>
<div>
<span>{{text.div_9:span}}</span>
<span>{{text.div_9:span_1}}</span>
<div><div>{{text.div_9:div_2:div}}</div></div>
</div>
<div>{{text.div_10:text}}<span>{{text.div_10:span_1}}</span>{{text.div_10:text_2}}<span>{{text.div_10:span_3}}</span>
<div><div>{{text.div_10:div_4:div}}</div></div>{{text.div_10:text_5}}</div>
<div text-id="toplevel-div">
<span>{{text.toplevel-div:span}}</span>
<span>{{text.toplevel-div:span_1}}</span>
<div text-id="second-level-div"><i18n-format lang="{{effectiveLang}}"><span>{{text.second-level-div.0}}</span><div text-id="third-level-div" param="1">{{text.second-level-div.1}}</div><div param="2">{{text.second-level-div.2}}</div></i18n-format></div>
</div>
<div>
<ul>
<li>{{text.div_12:ul:li}}</li>
<li>{{text.div_12:ul:li_1}}</li>
<li>{{text.div_12:ul:li_2}}</li>
</ul>
<ul text-id="line-items"><i18n-format lang="{{effectiveLang}}"><span>{{text.line-items.0}}</span><li param="1">{{text.line-items.1}}</li><li param="2">{{text.line-items.2}}</li><li param="3">{{text.line-items.3}}</li></i18n-format></ul>
</div>
<p><i18n-format lang="{{effectiveLang}}"><span>{{text.p_13.0}}</span><b param="1">{{text.p_13.1}}</b><code param="2">{{text.p_13.2}}</code></i18n-format></p>
<p text-id="paragraph"><i18n-format lang="{{effectiveLang}}"><span>{{text.paragraph.0}}</span><b param="1">{{text.paragraph.1}}</b><code param="2">{{text.paragraph.2}}</code></i18n-format></p>{{text.text_15}}<template id="localizable-text">
<json-data>
{
"meta": {},
"model": {},
"text": " outermost text at the beginning ",
"h1_3": "outermost header 1",
"text_4": " outermost text in the middle ",
"span_5": "simple text without id",
"span_6": "simple text without id 2",
"label-1": "simple text with id",
"label-2": "simple text with id 2",
"div_9:span": "simple text within div",
"div_9:span_1": "simple text within div 2",
"div_9:div_2:div": "great grandchild text within div",
"div_10:text": " simple text as the first element in div ",
"div_10:span_1": "simple text within div",
"div_10:text_2": " simple text in the middle of div ",
"div_10:span_3": "simple text within div 2",
"div_10:div_4:div": "great grandchild text within div",
"div_10:text_5": " simple text at the last element in div ",
"toplevel-div:span": "simple text within div",
"toplevel-div:span_1": "simple text within div 2",
"second-level-div": [
" {1}\n {2} ",
"great grandchild text within div",
"great grandchild text within div without id"
],
"div_12:ul:li": "line item without id 1",
"div_12:ul:li_1": "line item without id 2",
"div_12:ul:li_2": "line item without id 3",
"line-items": [
" {1}\n {2}\n {3} ",
"line item with id 1",
"line item with id 2",
"line item with id 3"
],
"p_13": [
"A paragraph with {1} is converted to {2}.",
"parameters",
"<i18n-format>"
],
"paragraph": [
"A paragraph with {1} is converted to {2}.",
"id",
"<i18n-format>"
],
"text_15": " outermost text at the end "
}
</json-data>
</template>
</template>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
Polymer({
is: 'simple-text-id-element',
behaviors: [
BehaviorsStore.I18nBehavior
],
properties: {
},
observers: [
],
listeners: {
'lang-updated': '_langUpdated'
},
ready: function () {
//this.observeHtmlLang = false;
},
attached: function () {
},
_langUpdated: function (e) {
if (dom(e).rootTarget === this) {
this.model = deepcopy(this.text.model);
}
}
});
</script>
</dom-module>
</div>
<h2 id="test-name"></h2>
<test-fixture class="test-container" id="simple-text-element-default-fixture">
<template>
<simple-text-element></simple-text-element>
</template>
</test-fixture>
<test-fixture class="test-container" id="commented-simple-text-element-default-fixture">
<template>
<commented-simple-text-element></commented-simple-text-element>
</template>
</test-fixture>
<test-fixture class="test-container" id="simple-text-element-fixture">
<template is="dom-template" id="bound-simple-text-element">
<simple-text-element lang="{{lang}}" observe-html-lang="{{observeHtmlLang}}">
</simple-text-element>
</template>
</test-fixture>
<test-fixture class="test-container" id="commented-simple-text-element-fixture">
<template is="dom-template" id="bound-commented-simple-text-element">
<commented-simple-text-element lang="{{lang}}" observe-html-lang="{{observeHtmlLang}}">
</commented-simple-text-element>
</template>
</test-fixture>
<test-fixture class="test-container" id="simple-text-id-element-fixture">
<template is="dom-template" id="bound-simple-text-id-element">
<simple-text-id-element lang="{{lang}}" observe-html-lang="{{observeHtmlLang}}">
</simple-text-id-element>
</template>
</test-fixture>
<test-fixture class="test-container" id="plural-gender-element-fixture">
<template is="dom-template">
<plural-gender-element lang="{{lang}}" observe-html-lang="{{observeHtmlLang}}" sender="{{sender}}" recipients="{{recipients}}">
</plural-gender-element>
</template>
</test-fixture>
<test-fixture class="test-container" id="simple-attribute-element-fixture">
<template is="dom-template">
<simple-attribute-element lang="{{lang}}" observe-html-lang="{{observeHtmlLang}}">
</simple-attribute-element>
</template>
</test-fixture>
<test-fixture class="test-container" id="fallback-text-element-fixture">
<template is="dom-template">
<fallback-text-element lang="{{lang}}" observe-html-lang="{{observeHtmlLang}}">
</fallback-text-element>
</template>
</test-fixture>
<test-fixture class="test-container" id="compound-binding-element-fixture">
<template is="dom-template">
<compound-binding-element lang="{{lang}}" observe-html-lang="{{observeHtmlLang}}" param1="{{param1}}" param2="{{param2}}">
</compound-binding-element>
</template>
</test-fixture>
<div class="test-container">
<template id="simple-text-dom-bind" is="i18n-dom-bind" assetpath="/" localizable-text="embedded">{{text.text}}<div><div></div></div>
<span id="whitespace"> </span>
<h1>{{text.h1_3}}</h1>{{text.text_4}}<span>{{text.span_5}}</span>
<span>{{text.span_6}}</span>
<span id="label-1">{{text.label-1}}</span>
<span id="label-2">{{text.label-2}}</span>
<div>
<span>{{text.div_9:span}}</span>
<span>{{text.div_9:span_1}}</span>
<div><div>{{text.div_9:div_2:div}}</div></div>
</div>
<div>{{text.div_10:text}}<span>{{text.div_10:span_1}}</span>{{text.div_10:text_2}}<span>{{text.div_10:span_3}}</span>
<div><div>{{text.div_10:div_4:div}}</div></div>{{text.div_10:text_5}}</div>
<div id="toplevel-div">
<span>{{text.toplevel-div:span}}</span>
<span>{{text.toplevel-div:span_1}}</span>
<div id="second-level-div">
<div id="third-level-div">{{text.third-level-div}}</div>
<div>{{text.second-level-div:div_1}}</div>
</div>
</div>
<div>
<ul>
<li>{{text.div_12:ul:li}}</li>
<li>{{text.div_12:ul:li_1}}</li>
<li>{{text.div_12:ul:li_2}}</li>
</ul>
<ul id="line-items">
<li>{{text.line-items:li}}</li>
<li>{{text.line-items:li_1}}</li>
<li>{{text.line-items:li_2}}</li>
</ul>
</div>
<p><i18n-format lang="{{effectiveLang}}"><span>{{text.p_13.0}}</span><b param="1">{{text.p_13.1}}</b><code param="2">{{text.p_13.2}}</code></i18n-format></p>
<p id="paragraph"><i18n-format lang="{{effectiveLang}}"><span>{{text.paragraph.0}}</span><b param="1">{{text.paragraph.1}}</b><code param="2">{{text.paragraph.2}}</code></i18n-format></p>{{text.text_15}}<template id="localizable-text">
<json-data>
{
"meta": {},
"model": {},
"text": " outermost text at the beginning ",
"h1_3": "outermost header 1",
"text_4": " outermost text in the middle ",
"span_5": "simple text without id",
"span_6": "simple text without id 2",
"label-1": "simple text with id",
"label-2": "simple text with id 2",
"div_9:span": "simple text within div",
"div_9:span_1": "simple text within div 2",
"div_9:div_2:div": "great grandchild text within div",
"div_10:text": " simple text as the first element in div ",
"div_10:span_1": "simple text within div",
"div_10:text_2": " simple text in the middle of div ",
"div_10:span_3": "simple text within div 2",
"div_10:div_4:div": "great grandchild text within div",
"div_10:text_5": " simple text at the last element in div ",
"toplevel-div:span": "simple text within div",
"toplevel-div:span_1": "simple text within div 2",
"third-level-div": "great grandchild text within div",
"second-level-div:div_1": "great grandchild text within div without id",
"div_12:ul:li": "line item without id 1",
"div_12:ul:li_1": "line item without id 2",
"div_12:ul:li_2": "line item without id 3",
"line-items:li": "line item with id 1",
"line-items:li_1": "line item with id 2",
"line-items:li_2": "line item with id 3",
"p_13": [
"A paragraph with {1} is converted to {2}.",
"parameters",
"<i18n-format>"
],
"paragraph": [
"A paragraph with {1} is converted to {2}.",
"id",
"<i18n-format>"
],
"text_15": " outermost text at the end "
}
</json-data>
</template>
</template>
</div>
<div class="test-container">
<template id="simple-attribute-dom-bind" is="i18n-dom-bind" assetpath="/" localizable-text="embedded">
<style attr="This is not extracted">
google-chart {
width: 300px;
}
</style>
<div id="outer-div">
<div id="ordinary-div" attr="This is not targeted for extraction">{{text.ordinary-div}}</div>
<input id="standard-input" placeholder="{{model.standard-input.placeholder}}">
<input placeholder="{{model.outer-div:input_2.placeholder}}">
<paper-input id="paper-input-element" label="{{model.paper-input-element.label}}" error-message="{{model.paper-input-element.error-message}}" placeholder="{{model.paper-input-element.placeholder}}" value="this is not a target">
</paper-input>
<paper-input label="{{model.outer-div:paper-input_4.label}}" error-message="{{model.outer-div:paper-input_4.error-message}}" placeholder="{{model.outer-div:paper-input_4.placeholder}}" value="this is not a target">
</paper-input>
<google-chart type="pie" id="pie-chart" options="{{model.pie-chart.options}}" cols="{{model.pie-chart.cols}}" rows="{{model.pie-chart.rows}}">
</google-chart>
<google-chart id="column-chart" type="column" options="{{model.column-chart.options}}" data="{{model.column-chart.data}}">
</google-chart>
<text-attribute-element id="custom-attr" custom-text-attr1="{{model.custom-attr.custom-text-attr1}}" custom-text-attr2="{{model.custom-attr.custom-text-attr2}}" custom-text-attr3="{{model.custom-attr.custom-text-attr3}}" out-of-scope-attr="out of scope attr">
</text-attribute-element>
<text-attribute-element id="selective-attr" boolean-attr="" empty-attr="" string-attr="abc" custom-text-attr4$="{{i18nFormat(model.selective-attr.custom-text-attr4.0,text.ordinary-div,text.ordinary-div,text.ordinary-div,text.ordinary-div)}}" custom-text-attr5$="[[text.ordinary-div]]{{model.selective-attr.custom-text-attr5.1}}{{or('',text.ordinary-div)}}{{model.selective-attr.custom-text-attr5.3}}[[text.ordinary-div]]" i18n-target="{{i18nFormat(model.selective-attr.i18n-target.0,text.ordinary-div,text.ordinary-div)}}" i18n-target2="{{model.selective-attr.i18n-target2.0}}{{or('',text.ordinary-div)}}{{model.selective-attr.i18n-target2.2}}[[text.ordinary-div]]">
</text-attribute-element>
<text-attribute-element id="selective-attr2" boolean-attr="" boolean-attr2="" string-attr="aaa" i18n-target="{{model.selective-attr2.i18n-target}}">
</text-attribute-element>
<text-attribute-element id="selective-attr3" i18n-target6="{{model.selective-attr3.i18n-target6}}">
</text-attribute-element>
<text-attribute-element id="selective-attr4" boolean-attr="" i18n-target6="{{model.selective-attr4.i18n-target6}}" i18n-target7="unmatching i18n-target4 attribute">
</text-attribute-element>
<text-attribute-element id="selective-attr5" string-attr="xxx" i18n-target7="unmatching i18n-target7 attribute">
</text-attribute-element>
<span id="test-json-data-1">{{model.json-data-id.attr1}}</span>
<span id="test-json-data-2">{{model.json-data-id.i18n-target-attr}}</span>
<span id="test-json-data-3">{{model.template_2:json-data_1.attr1}}</span>
<span id="test-json-data-4">{{model.template_2:json-data_1.i18n-target-attr}}</span>
</div>
<template>
<json-data id="json-data-id" attr1="{{model.json-data-id.attr1}}" i18n-target-attr="{{model.json-data-id.i18n-target-attr}}"></json-data>
<json-data attr1="{{model.template_2:json-data_1.attr1}}" i18n-target-attr="{{model.template_2:json-data_1.i18n-target-attr}}"></json-data>
</template>
<template id="localizable-text">
<json-data>
{
"meta": {},
"model": {
"standard-input": {
"placeholder": "standard HTML5 attribute"
},
"outer-div:input_2": {
"placeholder": "standard HTML5 attribute without id"
},
"paper-input-element": {
"label": "paper-input label",
"error-message": "paper-input error message",
"placeholder": "paper-input placeholder"
},
"outer-div:paper-input_4": {
"label": "paper-input label without id",
"error-message": "paper-input error message without id",
"placeholder": "paper-input placeholder without id"
},
"pie-chart": {
"options": {
"title": "Distribution of days in 2001H1"
},
"cols": [
{
"label": "Month",
"type": "string"
},
{
"label": "Days",
"type": "number"
}
],
"rows": [
[
"Jan",
31
],
[
"Feb",
28
],
[
"Mar",
31
],
[
"Apr",
30
],
[
"May",
31
],
[
"Jun",
30
]
]
},
"column-chart": {
"options": {
"title": "Inventory"
},
"data": [
[
"Year",
"Things",
"Stuff"
],
[
"2004",
1000,
400
],
[
"2005",
1170,
460
],
[
"2006",
660,
1120
],
[
"2007",
1030,
540
]
]
},
"custom-attr": {
"custom-text-attr1": "custom text attribute 1",
"custom-text-attr2": "custom text attribute 2",
"custom-text-attr3": "custom text attribute 3"
},
"selective-attr": {
"custom-text-attr4": [
"{1} custom-text-attr4 attribute with param {2} and param {3} {4}",
"{{text.ordinary-div}}",
"{{text.ordinary-div}}",
"[[text.ordinary-div]]",
"{{text.ordinary-div}}"
],
"custom-text-attr5": [
"[[text.ordinary-div]]",
" custom-text-attr5 attribute with param ",
"{{or('',text.ordinary-div)}}",
" and param ",
"[[text.ordinary-div]]"
],
"i18n-target": [
"i18n-target attribute with param {1} and param {2}",
"{{text.ordinary-div}}",
"[[text.ordinary-div]]"
],
"i18n-target2": [
"i18n-target2 attribute with param ",
"{{or('',text.ordinary-div)}}",
" and param ",
"[[text.ordinary-div]]"
]
},
"selective-attr2": {
"i18n-target": "i18n-target attribute 2"
},
"selective-attr3": {
"i18n-target6": "i18n-target6 attribute 2"
},
"selective-attr4": {
"i18n-target6": "i18n-target6 attribute 3"
},
"json-data-id": {
"attr1": "this attr1 is extracted",
"i18n-target-attr": "this attribute is also extracted"
},
"template_2:json-data_1": {
"attr1": "this attr1 without id is extracted",
"i18n-target-attr": "this attribute without id is also extracted"
}
},
"ordinary-div": "text 1"
}
</json-data>
</template>
</template>
</div>
<script type="module">
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
var bind = document.querySelector('template#simple-attribute-dom-bind');
window.addEventListener('dom-change', function onDomChangeForBind (event) {
if (event.target === bind) {
bind._langUpdated = function (e) {
if (dom(e).rootTarget === this) {
console.log('bind._langUpdated: ' + this.is + ' ' + this.id + ' ' + e.type + ' ' + this.lang);
console.log('bind._langUpdated: deepcopying model for lang ' + this.lang);
this.model = deepcopy(this.text.model);
this.notifyPath('model', this.model);
this.render();
}
};
bind._onDomChangeAfterLangUpdated = function (e) {
console.log('bind._onDomChangeAfterLangUpdated ' + this.is + ' ' + this.id + ' ' + e.type + ' ' + this.lang);
if (this.params && this.params.lang === this.lang) {
console.log('bind._onDomChangeAfterLangUpdated ' + this.is + ' ' + this.id + ' ' + e.type + ' firing local-dom-ready');
this.fire('local-dom-ready');
}
};
bind.listen(bind, 'lang-updated', '_langUpdated');
bind.listen(bind, 'dom-change', '_onDomChangeAfterLangUpdated');
window.removeEventListener('dom-change', onDomChangeForBind);
}
});
</script>
<div class="test-container">
<template id="compound-binding-dom-bind" is="i18n-dom-bind" assetpath="/" localizable-text="embedded"><i18n-format lang="{{effectiveLang}}"><span>{{text.text.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format><div><div></div></div>
<span id="whitespace"> </span>
<h1><i18n-format lang="{{effectiveLang}}"><span>{{text.h1_3.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></h1><i18n-format lang="{{effectiveLang}}"><span>{{text.text_4.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format><span><i18n-format lang="{{effectiveLang}}"><span>{{text.span_5.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></span>
<span><i18n-format lang="{{effectiveLang}}"><span>{{text.span_6.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></span>
<span id="label-1"><i18n-format lang="{{effectiveLang}}"><span>{{text.label-1.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></span>
<span id="label-2"><i18n-format lang="{{effectiveLang}}"><span>{{text.label-2.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></span>
<div>
<span><i18n-format lang="{{effectiveLang}}"><span>{{text.div_9:span.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></span>
<span><i18n-format lang="{{effectiveLang}}"><span>{{text.div_9:span_1.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></span>
<div><div><i18n-format lang="{{effectiveLang}}"><span>{{text.div_9:div_2:div.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></div></div>
</div>
<div><i18n-format lang="{{effectiveLang}}"><span>{{text.div_10:text.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format><span><i18n-format lang="{{effectiveLang}}"><span>{{text.div_10:span_1.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></span><i18n-format lang="{{effectiveLang}}"><span>{{text.div_10:text_2.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format><span><i18n-format lang="{{effectiveLang}}"><span>{{text.div_10:span_3.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></span>
<div><div><i18n-format lang="{{effectiveLang}}"><span>{{text.div_10:div_4:div.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></div></div><i18n-format lang="{{effectiveLang}}"><span>{{text.div_10:text_5.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></div>
<div id="toplevel-div">
<span><i18n-format lang="{{effectiveLang}}"><span>{{text.toplevel-div:span.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></span>
<span><i18n-format lang="{{effectiveLang}}"><span>{{text.toplevel-div:span_1.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></span>
<div id="second-level-div">
<div id="third-level-div"><i18n-format lang="{{effectiveLang}}"><span>{{text.third-level-div.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></div>
<div><i18n-format lang="{{effectiveLang}}"><span>{{text.second-level-div:div_1.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></div>
</div>
</div>
<div>
<ul>
<li><i18n-format lang="{{effectiveLang}}"><span>{{text.div_12:ul:li.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></li>
<li><i18n-format lang="{{effectiveLang}}"><span>{{text.div_12:ul:li_1.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></li>
<li><i18n-format lang="{{effectiveLang}}"><span>{{text.div_12:ul:li_2.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></li>
</ul>
<ul id="line-items">
<li><i18n-format lang="{{effectiveLang}}"><span>{{text.line-items:li.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></li>
<li><i18n-format lang="{{effectiveLang}}"><span>{{text.line-items:li_1.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></li>
<li><i18n-format lang="{{effectiveLang}}"><span>{{text.line-items:li_2.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></li>
</ul>
</div>
<p><i18n-format lang="{{effectiveLang}}"><span>{{text.p_13.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format></p>
<p id="paragraph"><i18n-format lang="{{effectiveLang}}"><span>{{text.paragraph.0}}</span><b param="1">{{text.paragraph.1}}</b><span param="2">{{param1}}</span><span param="3">{{param2}}</span><code param="4">{{text.paragraph.4}}</code></i18n-format></p><i18n-format lang="{{effectiveLang}}"><span>{{text.text_15.0}}</span><span param="1">{{param1}}</span><span param="2">{{param2}}</span></i18n-format><template id="localizable-text">
<json-data>
{
"meta": {},
"model": {},
"text": [
" outermost text at the beginning with compound {1} and {2} variables ",
"{{param1}}",
"{{param2}}"
],
"h1_3": [
"outermost header 1 with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"text_4": [
" outermost text in the middle with {1} and {2} variables ",
"{{param1}}",
"{{param2}}"
],
"span_5": [
"simple text without id with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"span_6": [
"simple text without id 2 with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"label-1": [
"simple text with id and {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"label-2": [
"simple text with id and {1} and {2} variables 2",
"{{param1}}",
"{{param2}}"
],
"div_9:span": [
"simple text within div with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"div_9:span_1": [
"simple text within div with {1} and {2} variables 2",
"{{param1}}",
"{{param2}}"
],
"div_9:div_2:div": [
"great grandchild text within div with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"div_10:text": [
" simple text as the first element in div with {1} and {2} variables ",
"{{param1}}",
"{{param2}}"
],
"div_10:span_1": [
"simple text within div with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"div_10:text_2": [
" simple text in the middle of div with {1} and {2} variables ",
"{{param1}}",
"{{param2}}"
],
"div_10:span_3": [
"simple text within div with {1} and {2} variables 2",
"{{param1}}",
"{{param2}}"
],
"div_10:div_4:div": [
"great grandchild text within div with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"div_10:text_5": [
" simple text at the last element in div with {1} and {2} variables ",
"{{param1}}",
"{{param2}}"
],
"toplevel-div:span": [
"simple text within div with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"toplevel-div:span_1": [
"simple text within div 2 with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"third-level-div": [
"great grandchild text within div with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"second-level-div:div_1": [
"great grandchild text within div without id with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"div_12:ul:li": [
"line item without id 1 with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"div_12:ul:li_1": [
"line item without id 2 with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"div_12:ul:li_2": [
"line item without id 3 with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"line-items:li": [
"line item with id 1 with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"line-items:li_1": [
"line item with id 2 with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"line-items:li_2": [
"line item with id 3 with {1} and {2} variables",
"{{param1}}",
"{{param2}}"
],
"p_13": [
"A paragraph with {1} is converted to {2}.",
"{{param1}}",
"{{param2}}"
],
"paragraph": [
"A paragraph with {1}, {2}, and {3} is converted to {4}.",
"id",
"{{param1}}",
"{{param2}}",
"<i18n-format>"
],
"text_15": [
" outermost text at the end with {1} and {2} variables ",
"{{param1}}",
"{{param2}}"
]
}
</json-data>
</template>
</template>
</div>
<script>
suite('I18nBehavior with ' +
(window.location.href.indexOf('?dom=Shadow') >= 0 ? 'Shadow DOM' : 'Shady DOM'),
function () {
var lang0 = '';
var lang1 = 'en';
var lang2 = 'fr';
var lang3 = 'ja';
var lang4 = 'fr-CA';
var lang5 = 'zh-Hans-CN';
var lang6 = 'ru';
var text_simple = {
'model': {},
'text': ' outermost text at the beginning ',
'h1_3': 'outermost header 1',
'text_4': ' outermost text in the middle ',
'span_5': 'simple text without id',
'span_6': 'simple text without id 2',
'label-1': 'simple text with id',
'label-2': 'simple text with id 2',
'div_9:span': 'simple text within div',
'div_9:span_1': 'simple text within div 2',
'div_9:div_2:div': 'great grandchild text within div',
'div_10:text': ' simple text as the first element in div ',
'div_10:span_1': 'simple text within div',
'div_10:text_2': ' simple text in the middle of div ',
'div_10:span_3': 'simple text within div 2',
'div_10:div_4:div': 'great grandchild text within div',
'div_10:text_5': ' simple text at the last element in div ',
'toplevel-div:span': 'simple text within div',
'toplevel-div:span_1': 'simple text within div 2',
'third-level-div': 'great grandchild text within div',
'second-level-div:div_1': 'great grandchild text within div without id',
'div_12:ul:li': 'line item without id 1',
'div_12:ul:li_1': 'line item without id 2',
'div_12:ul:li_2': 'line item without id 3',
'line-items:li': 'line item with id 1',
'line-items:li_1': 'line item with id 2',
'line-items:li_2': 'line item with id 3',
'p_13': [
'A paragraph with {1} is converted to {2}.',
'parameters',
'<i18n-format>'
],
'paragraph': [
'A paragraph with {1} is converted to {2}.',
'id',
'<i18n-format>'
],
'text_15': ' outermost text at the end '
};
var localDOM_simple = [
{ select: 'div:not([id])', 'previousTextSibling.data': ' outermost text at the beginning ' },
{ select: 'h1', textContent: 'outermost header 1' },
{ select: 'h1', 'nextTextSibling.data': ' outermost text in the middle ' },
{ select: 'span:not([id])', textContent: [ 'simple text without id', 'simple text without id 2' ] },
{ select: 'span[id="label-1"]', textContent: 'simple text with id' },
{ select: 'span[id="label-2"]', textContent: 'simple text with id 2' },
{ select: 'span[id="label-2"] + div span:not([id])', textContent: [ 'simple text within div', 'simple text within div 2' ] },
{ select: 'span[id="label-2"] + div div:not([id]) div:not([id])', textContent: [ 'great grandchild text within div' ] },
{ select: 'span[id="label-2"] + div + div', 'childNodes.0.data': ' simple text as the first element in div ' },
{ select: 'span[id="label-2"] + div + div span:not([id])', textContent: [ 'simple text within div', 'simple text within div 2' ] },
{ select: 'span[id="label-2"] + div + div span:not([id])', 'nextTextSibling.data': ' simple text in the middle of div ' },
{ select: 'span[id="label-2"] + div + div div:not([id]) div:not([id])', textContent: 'great grandchild text within div' },
{ select: 'span[id="label-2"] + div + div div:not([id])', 'nextTextSibling.data': ' simple text at the last element in div ' },
{ select: '[id="toplevel-div"] span:not([id])', textContent: [ 'simple text within div', 'simple text within div 2' ] },
{ select: '[id="third-level-div"]', textContent: 'great grandchild text within div' },
{ select: '[id="second-level-div"] div:not([id])', textContent: 'great grandchild text within div without id' },
{ select: 'div ul:not([id]) li:not([id])', textContent: [ 'line item without id 1', 'line item without id 2', 'line item without id 3' ] },
{ select: '[id="line-items"] li:not([id])', textContent: [ 'line item with id 1', 'line item with id 2', 'line item with id 3' ] },
{ select: 'p:not([id]) i18n-format',
'PolymerDom.children.0.textContent': 'A paragraph with {1} is converted to {2}.' },
{ select: 'p:not([id]) i18n-format',
'PolymerDom.children.1.tagName': 'B',
'PolymerDom.children.1.textContent': 'parameters',
'PolymerDom.children.1.attributes.param.value': '1' },
{ select: 'p:not([id]) i18n-format',
'PolymerDom.children.2.tagName': 'CODE',
'PolymerDom.children.2.textContent': '<i18n-format>',
'PolymerDom.children.2.attributes.param.value': '2' },
{ select: '[id="paragraph"] i18n-format',
'PolymerDom.children.0.textContent': 'A paragraph with {1} is converted to {2}.' },
{ select: '[id="paragraph"] i18n-format',
'PolymerDom.children.1.tagName': 'B',
'PolymerDom.children.1.textContent': 'id',
'PolymerDom.children.1.attributes.param.value': '1' },
{ select: '[id="paragraph"] i18n-format',
'PolymerDom.children.2.tagName': 'CODE',
'PolymerDom.children.2.textContent': '<i18n-format>',
'PolymerDom.children.2.attributes.param.value': '2' },
{ select: '[id="paragraph"]', 'nextTextSibling.data': ' outermost text at the end ' }
];
var text_simple_text_id = {
'model': {},
'text': ' outermost text at the beginning ',
'h1_3': 'outermost header 1',
'text_4': ' outermost text in the middle ',
'span_5': 'simple text without id',
'span_6': 'simple text without id 2',
'label-1': 'simple text with id',
'label-2': 'simple text with id 2',
'div_9:span': 'simple text within div',
'div_9:span_1': 'simple text within div 2',
'div_9:div_2:div': 'great grandchild text within div',
'div_10:text': ' simple text as the first element in div ',
'div_10:span_1': 'simple text within div',
'div_10:text_2': ' simple text in the middle of div ',
'div_10:span_3': 'simple text within div 2',
'div_10:div_4:div': 'great grandchild text within div',
'div_10:text_5': ' simple text at the last element in div ',
'toplevel-div:span': 'simple text within div',
'toplevel-div:span_1': 'simple text within div 2',
'second-level-div': [
' {1}\n {2} ',
'great grandchild text within div',
'great grandchild text within div without id'
],
'div_12:ul:li': 'line item without id 1',
'div_12:ul:li_1': 'line item without id 2',
'div_12:ul:li_2': 'line item without id 3',
'line-items': [
' {1}\n {2}\n {3} ',
'line item with id 1',
'line item with id 2',
'line item with id 3'
],
'p_13': [
'A paragraph with {1} is converted to {2}.',
'parameters',
'<i18n-format>'
],
'paragraph': [
'A paragraph with {1} is converted to {2}.',
'id',
'<i18n-format>'
],
'text_15': ' outermost text at the end '
};
var localDOM_simple_text_id = [
{ select: 'div:not([text-id])', 'previousTextSibling.data': ' outermost text at the beginning ' },
{ select: 'h1', textContent: 'outermost header 1' },
{ select: 'h1', 'nextTextSibling.data': ' outermost text in the middle ' },
{ select: 'span:not([text-id])', textContent: [ 'simple text without id', 'simple text without id 2' ] },
{ select: 'span[text-id="label-1"]', textContent: 'simple text with id' },
{ select: 'span[text-id="label-2"]', textContent: 'simple text with id 2' },
{ select: 'span[text-id="label-2"] + div span:not([text-id])', textContent: [ 'simple text within div', 'simple text within div 2' ] },
{ select: 'span[text-id="label-2"] + div div:not([text-id]) div:not([text-id])', textContent: [ 'great grandchild text within div' ] },
{ select: 'span[text-id="label-2"] + div + div', 'childNodes.0.data': ' simple text as the first element in div ' },
{ select: 'span[text-id="label-2"] + div + div span:not([text-id])', textContent: [ 'simple text within div', 'simple text within div 2' ] },
{ select: 'span[text-id="label-2"] + div + div span:not([text-id])', 'nextTextSibling.data': ' simple text in the middle of div ' },
{ select: 'span[text-id="label-2"] + div + div div:not([text-id]) div:not([text-id])', textContent: 'great grandchild text within div' },
{ select: 'span[text-id="label-2"] + div + div div:not([text-id])', 'nextTextSibling.data': ' simple text at the last element in div ' },
{ select: '[text-id="toplevel-div"] span:not([text-id])', textContent: [ 'simple text within div', 'simple text within div 2' ] },
{ select: '[text-id="second-level-div"] i18n-format',
'PolymerDom.children.0.textContent': ' {1}\n {2} ' },
{ select: '[text-id="second-level-div"] i18n-format',
'PolymerDom.children.1.tagName': 'DIV',
'PolymerDom.children.1.textContent': 'great grandchild text within div',
'PolymerDom.children.1.attributes.param.value': '1' },
{ select: '[text-id="second-level-div"] i18n-format',
'PolymerDom.children.2.tagName': 'DIV',
'PolymerDom.children.2.textContent': 'great grandchild text within div without id',
'PolymerDom.children.2.attributes.param.value': '2' },
{ select: 'div ul:not([text-id]) li:not([text-id])', textContent: [ 'line item without id 1', 'line item without id 2', 'line item without id 3' ] },
{ select: '[text-id="line-items"] i18n-format',
'PolymerDom.children.0.textContent': ' {1}\n {2}\n {3} ' },
{ select: '[text-id="line-items"] i18n-format',
'PolymerDom.children.1.tagName': 'LI',
'PolymerDom.children.1.textContent': 'line item with id 1',
'PolymerDom.children.1.attributes.param.value': '1' },
{ select: '[text-id="line-items"] i18n-format',
'PolymerDom.children.2.tagName': 'LI',
'PolymerDom.children.2.textContent': 'line item with id 2',
'PolymerDom.children.2.attributes.param.value': '2' },
{ select: '[text-id="line-items"] i18n-format',
'PolymerDom.children.3.tagName': 'LI',
'PolymerDom.children.3.textContent': 'line item with id 3',
'PolymerDom.children.3.attributes.param.value': '3' },
{ select: 'p:not([text-id]) i18n-format',
'PolymerDom.children.0.textContent': 'A paragraph with {1} is converted to {2}.' },
{ select: 'p:not([text-id]) i18n-format',
'PolymerDom.children.1.tagName': 'B',
'PolymerDom.children.1.textContent': 'parameters',
'PolymerDom.children.1.attributes.param.value': '1' },
{ select: 'p:not([text-id]) i18n-format',
'PolymerDom.children.2.tagName': 'CODE',
'PolymerDom.children.2.textContent': '<i18n-format>',
'PolymerDom.children.2.attributes.param.value': '2' },
{ select: '[text-id="paragraph"] i18n-format',
'PolymerDom.children.0.textContent': 'A paragraph with {1} is converted to {2}.' },
{ select: '[text-id="paragraph"] i18n-format',
'PolymerDom.children.1.tagName': 'B',
'PolymerDom.children.1.textContent': 'id',
'PolymerDom.children.1.attributes.param.value': '1' },
{ select: '[text-id="paragraph"] i18n-format',
'PolymerDom.children.2.tagName': 'CODE',
'PolymerDom.children.2.textContent': '<i18n-format>',
'PolymerDom.children.2.attributes.param.value': '2' },
{ select: '[text-id="paragraph"]', 'nextTextSibling.data': ' outermost text at the end ' }
];
var sender1 = {
'name': 'Joe',
'gender': 'male'
};
var recipients1 = [
{ 'name': 'Alice', 'gender': 'female' },
{ 'name': 'Bob', 'gender': 'male' },
{ 'name': 'Yoda', 'gender': 'other' }
];
var recipients2 = [
{ 'name': 'Alice', 'gender': 'female' },
{ 'name': 'Bob', 'gender': 'male' }
];
var recipients3 = [
{ 'name': 'Bob', 'gender': 'male' }
];
var recipients4 = [];
var text_plural_gender = {
'model': {},
'compound-format-text': [
{
'0': 'You ({3}) gave no gifts.',
'1': {
'male': 'You ({3}) gave him ({4}) {5}.',
'female': 'You ({3}) gave her ({4}) {5}.',
'other': 'You ({3}) gave them ({4}) {5}.'
},
'one': {
'male': 'You ({3}) gave him ({4}) and one other person {5}.',
'female': 'You ({3}) gave her ({4}) and one other person {5}.',
'other': 'You ({3}) gave them ({4}) and one other person {5}.'
},
'other': 'You ({3}) gave them ({4}) and {1} other people gifts.'
},
'{{recipients.length - 1}}',
'{{recipients.0.gender}}',
'{{sender.name}}',
'{{recipients.0.name}}',
'a gift'
]
};
var localDOM_plural_gender_1 = [
{ select: '#compound-format-text', 'root.PolymerDom.textContent': 'You () gave them () and other people gifts.' },
{ select: '#compound-format-text', 'PolymerDom.children.1.PolymerDom.childNodes.0.data.raw': '3' },
{ select: '#compound-format-text', 'PolymerDom.children.2.PolymerDom.childNodes.0.data.raw': 'female' },
{ select: '#compound-format-text', 'PolymerDom.children.3.PolymerDom.childNodes.0.data.raw': 'Joe' },
{ select: '#compound-format-text', 'PolymerDom.children.4.PolymerDom.childNodes.0.data.raw': 'Alice' },
{ select: '#compound-format-text', 'PolymerDom.children.5.PolymerDom.childNodes.0.data': 'a gift' }
];
var localDOM_plural_gender_2 = [
{ select: '#compound-format-text', 'root.PolymerDom.textContent': 'You () gave her () and one other person .' },
{ select: '#compound-format-text', 'PolymerDom.children.1.PolymerDom.childNodes.0.data.raw': '2' },
{ select: '#compound-format-text', 'PolymerDom.children.2.PolymerDom.childNodes.0.data.raw': 'female' },
{ select: '#compound-format-text', 'PolymerDom.children.3.PolymerDom.childNodes.0.data.raw': 'Joe' },
{ select: '#compound-format-text', 'PolymerDom.children.4.PolymerDom.childNodes.0.data.raw': 'Alice' },
{ select: '#compound-format-text', 'PolymerDom.children.5.PolymerDom.childNodes.0.data': 'a gift' }
];
var localDOM_plural_gender_3 = [
{ select: '#compound-format-text', 'root.PolymerDom.textContent': 'You () gave him () .' },
{ select: '#compound-format-text', 'PolymerDom.children.1.PolymerDom.childNodes.0.data.raw': '1' },
{ select: '#compound-format-text', 'PolymerDom.children.2.PolymerDom.childNodes.0.data.raw': 'male' },
{ select: '#compound-format-text', 'PolymerDom.children.3.PolymerDom.childNodes.0.data.raw': 'Joe' },
{ select: '#compound-format-text', 'PolymerDom.children.4.PolymerDom.childNodes.0.data.raw': 'Bob' },
{ select: '#compound-format-text', 'PolymerDom.children.5.PolymerDom.childNodes.0.data': 'a gift' }
];
var localDOM_plural_gender_4 = [
{ select: '#compound-format-text', 'root.PolymerDom.textContent': 'You () gave no gifts.' },
{ select: '#compound-format-text', 'PolymerDom.children.1.PolymerDom.childNodes.0.data.raw': '0' },
{ select: '#compound-format-text', 'PolymerDom.children.2.PolymerDom.childNodes.0.data.raw': '' },
{ select: '#compound-format-text', 'PolymerDom.children.3.PolymerDom.childNodes.0.data.raw': 'Joe' },
{ select: '#compound-format-text', 'PolymerDom.children.4.PolymerDom.childNodes.0.data.raw': '' },
{ select: '#compound-format-text', 'PolymerDom.children.5.PolymerDom.childNodes.0.data': 'a gift' }
];
var text_simple_attribute = {
'model': {
'standard-input': {
'placeholder': 'standard HTML5 attribute'
},
'outer-div:input_2': {
'placeholder': 'standard HTML5 attribute without id'
},
'paper-input-element': {
'label': 'paper-input label',
'error-message': 'paper-input error message',
'placeholder': 'paper-input placeholder'
},
'outer-div:paper-input_4': {
'label': 'paper-input label without id',
'error-message': 'paper-input error message without id',
'placeholder': 'paper-input placeholder without id'
},
'pie-chart': {
'options': {
'title': 'Distribution of days in 2001H1'
},
'cols': [
{
'label': 'Month',
'type': 'string'
},
{
'label': 'Days',
'type': 'number'
}
],
'rows': [
[
'Jan',
31
],
[
'Feb',
28
],
[
'Mar',
31
],
[
'Apr',
30
],
[
'May',
31
],
[
'Jun',
30
]
]
},
'column-chart': {
'options': {
'title': 'Inventory'
},
'data': [
[
'Year',
'Things',
'Stuff'
],
[
'2004',
1000,
400
],
[
'2005',
1170,
460
],
[
'2006',
660,
1120
],
[
'2007',
1030,
540
]
]
},
'custom-attr': {
'custom-text-attr1': 'custom text attribute 1',
'custom-text-attr2': 'custom text attribute 2',
'custom-text-attr3': 'custom text attribute 3'
},
'selective-attr': {
'custom-text-attr4': [
'{1} custom-text-attr4 attribute with param {2} and param {3} {4}',
'{{text.ordinary-div}}',
'{{text.ordinary-div}}',
'[[text.ordinary-div]]',
'{{text.ordinary-div}}'
],
'custom-text-attr5': [
'[[text.ordinary-div]]',
' custom-text-attr5 attribute with param ',
"{{or('',text.ordinary-div)}}",
' and param ',
'[[text.ordinary-div]]'
],
'i18n-target': [
'i18n-target attribute with param {1} and param {2}',
'{{text.ordinary-div}}',
'[[text.ordinary-div]]'
],
'i18n-target2': [
'i18n-target2 attribute with param ',
"{{or('',text.ordinary-div)}}",
' and param ',
'[[text.ordinary-div]]'
]
},
'selective-attr2': {
'i18n-target': 'i18n-target attribute 2'
},
'selective-attr3': {
'i18n-target6': 'i18n-target6 attribute 2'
},
'selective-attr4': {
'i18n-target6': 'i18n-target6 attribute 3'
},
'json-data-id': {
'attr1': 'this attr1 is extracted',
'i18n-target-attr': 'this attribute is also extracted'
},
'template_2:json-data_1': {
'attr1': 'this attr1 without id is extracted',
'i18n-target-attr': 'this attribute without id is also extracted'
}
},
'ordinary-div': 'text 1'
};
var model_simple_attribute = {
'standard-input': {
'placeholder': 'standard HTML5 attribute'
},
'outer-div:input_2': {
'placeholder': 'standard HTML5 attribute without id'
},
'paper-input-element': {
'label': 'paper-input label',
'error-message': 'paper-input error message',
'placeholder': 'paper-input placeholder'
},
'outer-div:paper-input_4': {
'label': 'paper-input label without id',
'error-message': 'paper-input error message without id',
'placeholder': 'paper-input placeholder without id'
},
'pie-chart': {
'options': {
'title': 'Distribution of days in 2001H1'
},
'cols': [
{
'label': 'Month',
'type': 'string'
},
{
'label': 'Days',
'type': 'number'
}
],
'rows': [
[
'Jan',
31
],
[
'Feb',
28
],
[
'Mar',
31
],
[
'Apr',
30
],
[
'May',
31
],
[
'Jun',
30
]
]
},
'column-chart': {
'options': {
'title': 'Inventory'
},
'data': [
[
'Year',
'Things',
'Stuff'
],
[
'2004',
1000,
400
],
[
'2005',
1170,
460
],
[
'2006',
660,
1120
],
[
'2007',
1030,
540
]
]
},
'custom-attr': {
'custom-text-attr1': 'custom text attribute 1',
'custom-text-attr2': 'custom text attribute 2',
'custom-text-attr3': 'custom text attribute 3'
},
'selective-attr': {
'custom-text-attr4': [
'{1} custom-text-attr4 attribute with param {2} and param {3} {4}',
'{{text.ordinary-div}}',
'{{text.ordinary-div}}',
'[[text.ordinary-div]]',
'{{text.ordinary-div}}'
],
'custom-text-attr5': [
'[[text.ordinary-div]]',
' custom-text-attr5 attribute with param ',
"{{or('',text.ordinary-div)}}",
' and param ',
'[[text.ordinary-div]]'
],
'i18n-target': [
'i18n-target attribute with param {1} and param {2}',
'{{text.ordinary-div}}',
'[[text.ordinary-div]]'
],
'i18n-target2': [
'i18n-target2 attribute with param ',
"{{or('',text.ordinary-div)}}",
' and param ',
'[[text.ordinary-div]]'
]
},
'selective-attr2': {
'i18n-target': 'i18n-target attribute 2'
},
'selective-attr3': {
'i18n-target6': 'i18n-target6 attribute 2'
},
'selective-attr4': {
'i18n-target6': 'i18n-target6 attribute 3'
},
'json-data-id': {
'attr1': 'this attr1 is extracted',
'i18n-target-attr': 'this attribute is also extracted'
},
'template_2:json-data_1': {
'attr1': 'this attr1 without id is extracted',
'i18n-target-attr': 'this attribute without id is also extracted'
}
};
var localDOM_simple_attribute = [
{ select: 'input[id="standard-input"]', 'placeholder.text': 'standard HTML5 attribute' },
{ select: 'input[id="standard-input"] + input', 'placeholder.text': 'standard HTML5 attribute without id' },
{ select: 'paper-input[id="paper-input-element"]', 'label.text': 'paper-input label', 'errorMessage.text': 'paper-input error message', 'placeholder.text': 'paper-input placeholder' },
{ select: 'paper-input[id="paper-input-element"] + paper-input', 'label.text': 'paper-input label without id', 'errorMessage.text': 'paper-input error message without id', 'placeholder.text': 'paper-input placeholder without id' },
{ select: 'google-chart[id="pie-chart"]', 'options.title.text': 'Distribution of days in 2001H1', 'cols.0.label.text': 'Month', 'cols.1.label.text': 'Days', 'rows.0.0.text': 'Jan', 'rows.1.0.text': 'Feb', 'rows.2.0.text': 'Mar', 'rows.3.0.text': 'Apr', 'rows.4.0.text': 'May', 'rows.5.0.text': 'Jun' },
{ select: 'google-chart[id="column-chart"]', 'options.title.text': 'Inventory', 'data.0.0.text': 'Year', 'data.0.1.text': 'Things', 'data.0.2.text': 'Stuff' },
{ select: 'text-attribute-element[id="custom-attr"]', 'customTextAttr1.text': 'custom text attribute 1', 'customTextAttr2.text': 'custom text attribute 2', 'customTextAttr3.text': 'custom text attribute 3' },
{ select: 'text-attribute-element[id="selective-attr"]', 'i18nTarget.raw': 'i18n-target attribute with param text 1 and param text 1', 'i18nTarget2.raw': 'i18n-target2 attribute with param text 1 and param text 1' },
{ select: 'span[id="test-json-data-1"]', 'textContent': 'this attr1 is extracted' },
{ select: 'span[id="test-json-data-2"]', 'textContent': 'this attribute is also extracted' },
{ select: 'span[id="test-json-data-3"]', 'textContent': 'this attr1 without id is extracted' },
{ select: 'span[id="test-json-data-4"]', 'textContent': 'this attribute without id is also extracted' },
];
var localDOM_simple_attribute_fr = [
{ select: 'input[id="standard-input"]', 'placeholder.text': 'standard HTML5 attribute' },
{ select: 'input[id="standard-input"] + input', 'placeholder.text': 'standard HTML5 attribute without id' },
{ select: 'paper-input[id="paper-input-element"]', 'label.text': 'paper-input label', 'errorMessage.text': 'paper-input error message', 'placeholder.text': 'paper-input placeholder' },
{ select: 'paper-input[id="paper-input-element"] + paper-input', 'label.text': 'paper-input label without id', 'errorMessage.text': 'paper-input error message without id', 'placeholder.text': 'paper-input placeholder without id' },
{ select: 'google-chart[id="pie-chart"]', 'options.title.text': 'Distribution of days in 2001H1', 'cols.0.label.text': 'Month', 'cols.1.label.text': 'Days', 'rows.0.0.text': 'Jan', 'rows.1.0.text': 'Feb', 'rows.2.0.text': 'Mar', 'rows.3.0.text': 'Apr', 'rows.4.0.text': 'May', 'rows.5.0.text': 'Jun' },
{ select: 'google-chart[id="column-chart"]', 'options.title.text': 'Inventory', 'data.0.0.text': 'Year', 'data.0.1.text': 'Things', 'data.0.2.text': 'Stuff' },
{ select: 'text-attribute-element[id="custom-attr"]', 'customTextAttr1.text': 'custom text attribute 1', 'customTextAttr2.text': 'custom text attribute 2', 'customTextAttr3.text': 'custom text attribute 3' },
{ select: 'text-attribute-element[id="selective-attr"]', 'i18nTarget.raw': 'fr i18n-target attribute with param fr text 1 and param fr text 1', 'i18nTarget2.raw': 'fr i18n-target2 attribute with param fr text 1fr and param fr text 1' },
{ select: 'span[id="test-json-data-1"]', 'textContent': 'this attr1 is extracted' },
{ select: 'span[id="test-json-data-2"]', 'textContent': 'this attribute is also extracted' },
{ select: 'span[id="test-json-data-3"]', 'textContent': 'this attr1 without id is extracted' },
{ select: 'span[id="test-json-data-4"]', 'textContent': 'this attribute without id is also extracted' },
];
var text_fallback = {
'model': {},
'text': 'fr-CA outermost text at the beginning ',
'h1_3': 'fr-CA outermost header 1',
'text_4': 'fr-CA outermost text in the middle ',
'span_5': 'fr-CA simple text without id',
'span_6': 'fr-CA simple text without id 2',
'label-1': 'fr-CA simple text with id',
'label-2': 'fr-CA simple text with id 2',
'div_9:span': 'simple text within div',
'div_9:span_1': 'simple text within div 2',
'div_9:div_2:div': 'great grandchild text within div',
'div_10:text': ' simple text as the first element in div ',
'div_10:span_1': 'fr-CA simple text within div',
'div_10:text_2': ' simple text in the middle of div ',
'div_10:span_3': 'simple text within div 2',
'div_10:div_4:div': 'great grandchild text within div',
'div_10:text_5': ' simple text at the last element in div ',
'toplevel-div:span': 'fr-CA simple text within div',
'toplevel-div:span_1': 'fr-CA simple text within div 2',
'third-level-div': 'fr-CA great grandchild text within div',
'second-level-div:div_1': 'fr-CA great grandchild text within div without id',
'div_12:ul:li': 'fr line item without id 1',
'div_12:ul:li_1': 'fr line item without id 2',
'div_12:ul:li_2': 'fr line item without id 3',
'line-items:li': 'fr line item with id 1',
'line-items:li_1': 'fr line item with id 2',
'line-items:li_2': 'fr line item with id 3',
'p_13': [
'fr-CA A paragraph with {1} is converted to {2}.',
'fr-CA parameters',
'fr-CA <i18n-format>'
],
'paragraph': [
'fr-CA A paragraph with {1} is converted to {2}.',
'fr-CA id',
'fr-CA <i18n-format>'
],
'text_15': 'fr-CA outermost text at the end '
};
var localDOM_fallback = [
{ select: 'div:not([id])', 'previousTextSibling.data': 'fr-CA outermost text at the beginning ' },
{ select: 'h1', textContent: 'fr-CA outermost header 1' },
{ select: 'h1', 'nextTextSibling.data': 'fr-CA outermost text in the middle ' },
{ select: 'span:not([id])', textContent: [ 'fr-CA simple text without id', 'fr-CA simple text without id 2' ] },
{ select: 'span[id="label-1"]', textContent: 'fr-CA simple text with id' },
{ select: 'span[id="label-2"]', textContent: 'fr-CA simple text with id 2' },
{ select: 'span[id="label-2"] + div span:not([id])', textContent: [ 'simple text within div', 'simple text within div 2' ] },
{ select: 'span[id="label-2"] + div div:not([id]) div:not([id])', textContent: [ 'great grandchild text within div' ] },
{ select: 'span[id="label-2"] + div + div', 'childNodes.0.data': ' simple text as the first element in div ' },
{ select: 'span[id="label-2"] + div + div span:not([id])', textContent: [ 'fr-CA simple text within div', 'simple text within div 2' ] },
{ select: 'span[id="label-2"] + div + div span:not([id])', 'nextTextSibling.data': ' simple text in the middle of div ' },
{ select: 'span[id="label-2"] + div + div div:not([id]) div:not([id])', textContent: 'great grandchild text within div' },
{ select: 'span[id="label-2"] + div + div div:not([id])', 'nextTextSibling.data': ' simple text at the last element in div ' },
{ select: '[id="toplevel-div"] span:not([id])', textContent: [ 'fr-CA simple text within div', 'fr-CA simple text within div 2' ] },
{ select: '[id="third-level-div"]', textContent: 'fr-CA great grandchild text within div' },
{ select: '[id="second-level-div"] div:not([id])', textContent: 'fr-CA great grandchild text within div without id' },
{ select: 'div ul:not([id]) li:not([id])', textContent: [ 'fr line item without id 1', 'fr line item without id 2', 'fr line item without id 3' ] },
{ select: '[id="line-items"] li:not([id])', textContent: [ 'fr line item with id 1', 'fr line item with id 2', 'fr line item with id 3' ] },
{ select: 'p:not([id]) i18n-format',
'PolymerDom.children.0.textContent': 'fr-CA A paragraph with {1} is converted to {2}.' },
{ select: 'p:not([id]) i18n-format',
'PolymerDom.children.1.tagName': 'B',
'PolymerDom.children.1.textContent': 'fr-CA parameters',
'PolymerDom.children.1.attributes.param.value': '1' },
{ select: 'p:not([id]) i18n-format',
'PolymerDom.children.2.tagName': 'CODE',
'PolymerDom.children.2.textContent': 'fr-CA <i18n-format>',
'PolymerDom.children.2.attributes.param.value': '2' },
{ select: '[id="paragraph"] i18n-format',
'PolymerDom.children.0.textContent': 'fr-CA A paragraph with {1} is converted to {2}.' },
{ select: '[id="paragraph"] i18n-format',
'PolymerDom.children.1.tagName': 'B',
'PolymerDom.children.1.textContent': 'fr-CA id',
'PolymerDom.children.1.attributes.param.value': '1' },
{ select: '[id="paragraph"] i18n-format',
'PolymerDom.children.2.tagName': 'CODE',
'PolymerDom.children.2.textContent': 'fr-CA <i18n-format>',
'PolymerDom.children.2.attributes.param.value': '2' },
{ select: '[id="paragraph"]', 'nextTextSibling.data': 'fr-CA outermost text at the end ' }
];
var param1 = '1st compound parameter';
var param2 = '2nd compound parameter';
var text_compound = {
'model': {},
'text': [
' outermost text at the beginning with compound {1} and {2} variables ',
'{{param1}}',
'{{param2}}'
],
'h1_3': [
'outermost header 1 with {1} and {2} variables',
'{{param1}}',
'{{param2}}'
],
'text_4': [
' outermost text in the middle with {1} and {2} variables ',
'{{param1}}',
'{{param2}}'
],
'span_5': [
'simple text without id with {1} and {2} variables',
'{{param1}}',
'{{param2}}'
],
'span_6': [
'simple text without id 2 with {1} and {2} variables',
'{{param1}}',
'{{param2}}'
],
'label-1': [
'simple text with id and {1} and {2} variables',
'{{param1}}',
'{{param2}}'
],
'label-2': [
'simple text with id and {1} and {2} variables 2',
'{{param1}}',
'{{param2}}'
],
'div_9:span': [
'simple text within div with {1} and {2} variables',
'{{param1}}',
'{{param2}}'
],
'div_9:span_1': [
'simple text within div with {1} and {2} variables 2',
'{{param1}}',
'{{param2}}'
],
'div_9:div_2:div': [
'great grandchild text within div with {1} and {2} variables',
'{{param1}}',
'{{param2}}'
],
'div_10:text': [
' simple text as the first element in div with {1} and {2} variables ',
'{{param1}}',
'{{param2}}'
],
'div_10:span_1': [
'simple text within div with {1} and {2} variables',
'{{param1}}',
'{{param2}}'
],
'div_10:text_2': [
' simple text in the middle of div with {1} and {2} variables ',
'{{param1}}',
'{{param2}}'
],
'div_10:span_3': [
'simple text within div with {1} and {2} variables 2',
'{{param1}}',
'{{param2}}'
],
'div_10:div_4:div': [
'great grandchild text within div with {1} and {2} variables',
'{{param1}}',
'{{param2}}'
],
'div_10:text_5': [
' simple text at the last element in div with {1} and {2} variables ',
'{{param1}}',
'{{param2}}'
],
'toplevel-div:span': [
'simple text within div with {1} and {2} variables',
'{{param1}}',
'{{param2}}'
],
'toplevel-div:span_1': [
'simple text within div 2 with {1} and {2} variables',
'{{param1}}',
'{{param2}}'
],
'third-level-div': [
'great grandchild text within div with {1} and {2} variables',
'{{param1}}',
'{{param2}}'
],
'second-level-div:div_1': [
'great grandchild text within div without id with {1} and {2} variables',
'{{param1}}',
'{{param2}}'
],
'div_12:ul:li': [
'line item without id 1 with {1} and {2} variables',
'{{param1}}',
'{{param2}}'
],
'div_12:ul:li_1': [
'line item without id 2 with {1} and {2} variables',
'{{param1}}',
'{{param2}}'
],
'div_12:ul:li_2': [
'line item without id 3 with {1} and {2} variables',
'{{param1}}',
'{{param2}}'
],
'line-items:li': [
'line item with id 1 with {1} and {2} variables',
'{{param1}}',
'{{param2}}'
],
'line-items:li_1': [
'line item with id 2 with {1} and {2} variables',
'{{param1}}',
'{{param2}}'
],
'line-items:li_2': [
'line item with id 3 with {1} and {2} variables',
'{{param1}}',
'{{param2}}'
],
'p_13': [
'A paragraph with {1} is converted to {2}.',
'{{param1}}',
'{{param2}}'
],
'paragraph': [
'A paragraph with {1}, {2}, and {3} is converted to {4}.',
'id',
'{{param1}}',
'{{param2}}',
'<i18n-format>'
],
'text_15': [
' outermost text at the end with {1} and {2} variables ',
'{{param1}}',
'{{param2}}'
]
};
var localDOM_compound = [
{ select: 'i18n-format',
'PolymerDom.children.0.textContent': [
' outermost text at the beginning with compound {1} and {2} variables ',
'outermost header 1 with {1} and {2} variables',
' outermost text in the middle with {1} and {2} variables ',
'simple text without id with {1} and {2} variables',
'simple text without id 2 with {1} and {2} variables',
'simple text with id and {1} and {2} variables',
'simple text with id and {1} and {2} variables 2',
'simple text within div with {1} and {2} variables',
'simple text within div with {1} and {2} variables 2',
'great grandchild text within div with {1} and {2} variables',
' simple text as the first element in div with {1} and {2} variables ',
'simple text within div with {1} and {2} variables',
' simple text in the middle of div with {1} and {2} variables ',
'simple text within div with {1} and {2} variables 2',
'great grandchild text within div with {1} and {2} variables',
' simple text at the last element in div with {1} and {2} variables ',
'simple text within div with {1} and {2} variables',
'simple text within div 2 with {1} and {2} variables',
'great grandchild text within div with {1} and {2} variables',
'great grandchild text within div without id with {1} and {2} variables',
'line item without id 1 with {1} and {2} variables',
'line item without id 2 with {1} and {2} variables',
'line item without id 3 with {1} and {2} variables',
'line item with id 1 with {1} and {2} variables',
'line item with id 2 with {1} and {2} variables',
'line item with id 3 with {1} and {2} variables',
'A paragraph with {1} is converted to {2}.',
'A paragraph with {1}, {2}, and {3} is converted to {4}.',
' outermost text at the end with {1} and {2} variables '
],
'PolymerDom.children.1.textContent.raw': [
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter',
'1st compound parameter'
],
'PolymerDom.children.2.textContent.raw': [
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'2nd compound parameter',
'1st compound parameter',
'2nd compound parameter'
]
},
{ select: '[id="paragraph"] i18n-format',
'PolymerDom.children.1.tagName': 'B',
'PolymerDom.children.1.textContent': 'id',
'PolymerDom.children.1.attributes.param.value.raw': '1',
'PolymerDom.children.3.tagName': 'SPAN',
'PolymerDom.children.3.textContent.raw': '2nd compound parameter',
'PolymerDom.children.3.attributes.param.value.raw': '3'
},
{ select: '[id="paragraph"] +i18n-format',
'PolymerDom.children.1.textContent.raw': '1st compound parameter'
}
];
var suites = [
s('simple text default', null, {
fixture: 'simple-text-element-default-fixture',
fixtureModel: undefined,
assign: undefined,
lang: lang1,
effectiveLang: lang1,
templateDefaultLang: lang1,
observeHtmlLang: true,
text: text_simple,
model: {},
localDOM: localDOM_simple,
lightDOM: undefined
}),
s('commented simple text default', 'simple text default', {
fixture: 'commented-simple-text-element-default-fixture'
}),
s('simple text default null lang', 'simple text default', {
assign: { lang: lang0 },
lang: lang0,
effectiveLang: lang0
}),
s('commented simple text default null lang', 'commented simple text default', {
assign: { lang: lang0 },
lang: lang0,
effectiveLang: lang0
}),
s(lang2 + ' simple text default', 'simple text default', {
assign: { lang: lang2 },
lang: lang2,
effectiveLang: lang2
}),
s(lang2 + ' commented simple text default', 'commented simple text default', {
assign: { lang: lang2 },
lang: lang2,
effectiveLang: lang2
}),
s('simple text null lang', 'simple text default', {
fixture: 'simple-text-element-fixture',
fixtureModel: { observeHtmlLang: false, lang: lang0 },
lang: lang0,
effectiveLang: lang0,
observeHtmlLang: false
}),
s('simple text', 'simple text null lang', {
assign: { lang: lang1 },
lang: lang1,
effectiveLang: lang1
}),
s(lang2 + ' simple text', 'simple text', {
assign: { lang: lang2 },
lang: lang2,
effectiveLang: lang2
}),
s(lang6 + ' simple text', 'simple text', {
assign: { lang: lang6 },
lang: lang6,
effectiveLang: lang6
}),
s('commented simple text', 'simple text', {
fixture: 'commented-simple-text-element-fixture'
}),
s('commented simple text null lang', 'commented simple text', {
assign: undefined,
lang: lang0,
effectiveLang: lang0
}),
s(lang2 + ' commented simple text', 'commented simple text', {
fixtureModel: { observeHtmlLang: false, lang: lang0 },
assign: { lang: lang2 },
lang: lang2,
effectiveLang: lang2
}),
s(lang2 + ' static commented simple text', 'commented simple text', {
fixtureModel: { observeHtmlLang: false, lang: lang2 },
assign: undefined,
lang: lang2,
effectiveLang: lang2
}),
s('simple text id', 'simple text', {
fixture: 'simple-text-id-element-fixture',
text: text_simple_text_id,
localDOM: localDOM_simple_text_id
}),
s(lang2 + ' simple text id', 'simple text id', {
assign: { lang: lang2 },
lang: lang2,
effectiveLang: lang2
}),
s('plural gender', 'simple text default', {
fixture: 'plural-gender-element-fixture',
fixtureModel: {
observeHtmlLang: false,
lang: lang0
},
assign: {
lang: lang1,
sender: sender1,
recipients: recipients1
},
observeHtmlLang: false,
event: 'local-dom-ready',
text: text_plural_gender,
localDOM: localDOM_plural_gender_1
}),
s('plural gender 2', 'plural gender', {
assign: {
lang: lang1,
sender: sender1,
recipients: recipients2
},
localDOM: localDOM_plural_gender_2
}),
s('plural gender 3', 'plural gender', {
assign: {
lang: lang1,
sender: sender1,
recipients: recipients3
},
localDOM: localDOM_plural_gender_3
}),
s('plural gender 4', 'plural gender', {
assign: {
lang: lang1,
sender: sender1,
recipients: recipients4
},
localDOM: localDOM_plural_gender_4
}),
s(lang2 + ' plural gender', 'plural gender', {
assign: {
lang: lang2,
sender: sender1,
recipients: recipients1
},
lang: lang2,
effectiveLang: lang2
}),
s(lang2 + ' plural gender 2', 'plural gender 2', {
assign: {
lang: lang2,
sender: sender1,
recipients: recipients2
},
lang: lang2,
effectiveLang: lang2,
localDOM: localDOM_plural_gender_2
}),
s(lang2 + ' plural gender 3', 'plural gender 3', {
assign: {
lang: lang2,
sender: sender1,
recipients: recipients3
},
lang: lang2,
effectiveLang: lang2,
localDOM: localDOM_plural_gender_3
}),
s(lang2 + ' plural gender 4', 'plural gender 4', {
assign: {
lang: lang2,
sender: sender1,
recipients: recipients4
},
lang: lang2,
effectiveLang: lang2,
localDOM: localDOM_plural_gender_4
}),
s('simple attribute', 'simple text default', {
fixture: 'simple-attribute-element-fixture',
fixtureModel: {
observeHtmlLang: false,
lang: lang0
},
assign: { lang: lang1 },
observeHtmlLang: false,
text: text_simple_attribute,
model: model_simple_attribute,
localDOM: localDOM_simple_attribute
}),
s(lang2 + ' simple attribute', 'simple attribute', {
assign: { lang: lang2 },
lang: lang2,
effectiveLang: lang2,
localDOM: localDOM_simple_attribute_fr
}),
s(lang4 + ' simple text default with fallback to ' + lang2, 'simple text default', {
timeout: 60000,
assign: { lang: lang4 },
lang: lang2,
effectiveLang: lang2
}),
s(lang4 + ' simple text with fallback to ' + lang2, 'simple text', {
timeout: 60000,
assign: { lang: lang4 },
lang: lang2,
effectiveLang: lang2
}),
s(lang5 + ' simple text with fallback to default', 'simple text', {
timeout: 60000,
assign: { lang: lang5 },
lang: lang0,
effectiveLang: lang0
}),
s(lang3 + ' simple text with fallback to default', 'simple text', {
timeout: 60000,
assign: { lang: lang3 },
lang: lang0,
effectiveLang: lang0
}),
s(lang4 + ' fallback text', 'simple text', {
timeout: 60000,
fixture: 'fallback-text-element-fixture',
assign: { lang: lang4 },
lang: lang4,
effectiveLang: lang4,
rawText: true,
text: text_fallback,
localDOM: localDOM_fallback
}),
s('compound binding', 'simple text', {
fixture: 'compound-binding-element-fixture',
fixtureModel: {
observeHtmlLang: false,
lang: lang0,
param1: param1,
param2: param2
},
text: text_compound,
localDOM: localDOM_compound
}),
s(lang2 + ' compound binding', 'compound binding', {
fixtureModel: {
observeHtmlLang: false,
lang: lang0,
param1: param1,
param2: param2
},
assign: { lang: lang2 },
lang: lang2,
effectiveLang: lang2
}),
s('simple attribute dom bind', 'simple attribute', {
fixture: 'simple-attribute-dom-bind',
fixtureModel: {
observeHtmlLang: false,
lang: lang0
},
assign: { lang: lang1 },
event: 'local-dom-ready',
text: text_simple_attribute,
model: model_simple_attribute,
localDOM: localDOM_simple_attribute
}),
s(lang2 + ' simple attribute dom bind', 'simple attribute dom bind', {
fixtureModel: {
observeHtmlLang: false,
lang: lang0
},
assign: { lang: lang2 },
lang: lang2,
effectiveLang: lang2,
localDOM: localDOM_simple_attribute_fr
}),
s('compound binding dom bind', 'compound binding', {
fixture: 'compound-binding-dom-bind'
}),
s(lang2 + ' compound binding dom bind', 'compound binding dom bind', {
assign: { lang: lang2 },
lang: lang2,
effectiveLang: lang2
}),
s(lang2 + ' default observeHtmlLang simple text dom bind', 'simple text', {
fixture: 'simple-text-dom-bind',
fixtureModel: {
'html.lang': lang5
},
assign: { 'html.lang': lang2 },
lang: lang2,
effectiveLang: lang2,
text: text_simple,
model: undefined,
localDOM: localDOM_simple,
observeHtmlLang: true
}),
s('simple text dom bind', 'simple text', {
fixture: 'simple-text-dom-bind',
fixtureModel: {
observeHtmlLang: false,
lang: lang0
},
text: text_simple,
localDOM: localDOM_simple
}),
s(lang2 + ' simple text dom bind', 'simple text dom bind', {
assign: { lang: lang2 },
lang: lang2,
effectiveLang: lang2
}),
s('html.lang simple text dom bind', 'simple text dom bind', {
fixtureModel: {
observeHtmlLang: true,
lang: lang1,
'html.lang': lang1
},
assign: { 'html.lang': lang1 },
observeHtmlLang: true
}),
s(lang2 + ' html.lang simple text dom bind', 'html.lang simple text dom bind', {
assign: { 'html.lang': lang2 },
lang: lang2,
effectiveLang: lang2
}),
s('observeHtmlLang default simple text', 'simple text null lang', {
fixtureModel: {
observeHtmlLang: true
},
assign: { 'html.lang': lang1 },
lang: lang1,
effectiveLang: lang1,
observeHtmlLang: true
})
];
suitesRunner(suites);
});
</script>
</body></html>