Merge branch 'feature-onboarding'

This commit is contained in:
Stefan Zermatten
2017-09-28 13:18:52 +02:00
45 changed files with 2170 additions and 66 deletions

View File

@@ -191,6 +191,7 @@ Schemas.Character = new SimpleSchema({
"settings.exportFeatures": {type: Boolean, defaultValue: true},
"settings.exportAttacks": {type: Boolean, defaultValue: true},
"settings.exportDescription": {type: Boolean, defaultValue: true},
"settings.newUserExperience": {type: Boolean, optional: true},
});
Characters.attachSchema(Schemas.Character);
@@ -298,6 +299,7 @@ Characters.calculate = {
var fieldSelector = {};
fieldSelector[fieldName] = 1;
var char = Characters.findOne(charId, {fields: fieldSelector});
if (!char) return;
var field = char[fieldName];
if (field === undefined){
throw new Meteor.Error(
@@ -331,6 +333,7 @@ Characters.calculate = {
},
attributeValue: memoize(function(charId, attributeName){
var attribute = Characters.calculate.getField(charId, attributeName);
if (!attribute) return;
//base value
var value = Characters.calculate.attributeBase(charId, attributeName);
//plus adjustment
@@ -342,6 +345,7 @@ Characters.calculate = {
}),
skillMod: memoize(preventLoop(function(charId, skillName){
var skill = Characters.calculate.getField(charId, skillName);
if (!skill) return;
//get the final value of the ability score
var ability = Characters.calculate.attributeValue(charId, skill.ability);
@@ -393,7 +397,6 @@ Characters.calculate = {
return prof && prof.value || 0;
}),
passiveSkill: memoize(function(charId, skillName){
var skill = Characters.calculate.getField(charId, skillName);
var mod = +Characters.calculate.skillMod(charId, skillName);
var value = 10 + mod;
Effects.find(
@@ -554,6 +557,10 @@ if (Meteor.isServer){
});
Characters.before.insert(function(userId, doc) {
doc.urlName = getSlug(doc.name, {maintainCase: true}) || "-";
// The first character a user creates should have the new user experience
if (!Characters.find({owner: userId}).count()){
doc.settings.newUserExperience = true;
}
});
}

View File

@@ -3,7 +3,8 @@ Template.registerHelper("canEditCharacter", function(charId) {
});
canEditCharacter = function(charId) {
var char = Characters.findOne(charId)
var char = Characters.findOne(charId);
if (!char) return false;
var userId = Meteor.userId();
return char.owner === userId ||
_.contains(char.writers, userId);

View File

@@ -0,0 +1,17 @@
@keyframes bounce {
from {
transform: translate(0px,0px);
}
to {
transform: translate(0px,-16px);
}
}
.bounce{
animation-name: bounce;
animation-duration: 0.3s;
animation-direction: alternate;
animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
animation-delay: 0s;
animation-iteration-count: infinite;
}

View File

@@ -10,7 +10,7 @@ Template.deleteCharacterConfirmation.helpers({
if (Template.instance().canDelete.get()) {
return "background: #d23f31; color: white;";
}
}
},
});
Template.deleteCharacterConfirmation.events({
@@ -20,9 +20,7 @@ Template.deleteCharacterConfirmation.events({
},
"click #deleteButton": function(event, instance) {
if (instance.find("#nameInput").value === this.name) {
popDialogStack();
Router.go("/characterList");
Characters.remove(this._id);
popDialogStack(true);
}
},
"click .cancelButton": function(event, instance){

View File

@@ -1,7 +1,7 @@
<template name="characterSheet">
<div class="fit layout vertical character-sheet">
<app-header fixed effects="waterfall">
<app-toolbar class="medium-tall {{colorClass}}">
<app-toolbar class="medium-tall {{colorClass}}" style="z-index: 2;">
<div top-item class="layout horizontal center">
<paper-icon-button icon="menu" drawer-toggle></paper-icon-button>
<div class="flex character-name">
@@ -44,17 +44,18 @@
</div>
<div bottom-item>
<paper-tabs id="characterSheetTabs" selected={{selectedTab}} class="{{colorClass}}">
<paper-tab name="stats">Stats</paper-tab>
<paper-tab name="features">Features</paper-tab>
<paper-tab name="stats" class="{{#if shouldBounce 0}}bounce{{/if}}">Stats</paper-tab>
<paper-tab name="features" class="{{#if shouldBounce 1}}bounce{{/if}}">Features</paper-tab>
<paper-tab name="inventory">Inventory</paper-tab>
{{#unless hideSpellcasting}}
<paper-tab name="spells">Spells</paper-tab>
{{/unless}}
<paper-tab name="persona">Persona</paper-tab>
<paper-tab name="journal">Journal</paper-tab>
<paper-tab name="journal" class="{{#if shouldBounce 5}}bounce{{/if}}">Journal</paper-tab>
</paper-tabs>
</div>
</app-toolbar>
{{#if newUserExperience}}{{> newUserStepper}}{{/if}}
</app-header>
<div class="flex" style="position: relative;">
<iron-pages id="tabPages" class="fit" selected={{selectedTab}}>

View File

@@ -29,7 +29,7 @@ Template.characterSheet.onRendered(function() {
tabFabMenus = _.times(6, (n) =>
tabPages[n].find(".mini-holder")
);
})
});
//watch this character and make sure their encumbrance is updated
//trackEncumbranceConditions(this.data._id, this);
@@ -172,6 +172,18 @@ Template.characterSheet.helpers({
var char = Characters.findOne(this._id);
return char && char.settings.hideSpellcasting;
},
newUserExperience: function(){
var char = Characters.findOne(this._id);
return char && char.settings.newUserExperience;
},
shouldBounce: function(tab){
const selected = Session.get(this._id + ".selectedTab")
const step = Session.get("newUserExperienceStep");
if (selected == tab) return false;
return (tab === 1 && step === 0) ||
(tab === 5 && step === 1) ||
(tab === 0 && step === 2);
},
});
Template.characterSheet.events({
@@ -187,6 +199,12 @@ Template.characterSheet.events({
data: this,
template: "deleteCharacterConfirmation",
element: event.currentTarget.parentElement.parentElement,
callback: (result) => {
if (result === true){
Router.go("/characterList");
Tracker.afterFlush(() => Characters.remove(this._id));
}
},
});
},
"click #shareCharacter": function(event, instance){

View File

@@ -42,9 +42,20 @@
</template>
<template name="featureEdit">
{{#if showNewUserExperience}}
{{# infoBox}}
<p>
Features represent all the permanent things your character can do.
</p><p>
A feature can change a character's stats with effects,
or give the character proficiencies, attacks, and buffs.
</p><p>
Give the feature a name, and close it to continue.
</p>
{{/infoBox}}
{{/if}}
<!--name-->
<paper-input id="featureNameInput" class="fullwidth" label="Name" value={{name}}></paper-input>
<div class="layout horizontal center wrap justified">
<paper-dropdown-menu class=flex label="Enable Feature" style="flex-basis: 150px; max-width: 200px;">
<dicecloud-selector selected={{enabledSelection}} class="dropdown-content enabled-dropdown">

View File

@@ -47,6 +47,10 @@ Template.featureDetails.events({
});
Template.featureEdit.helpers({
showNewUserExperience: function(){
return Session.get("newUserExperienceStep") === 0 ||
Session.get("newUserExperienceStep") === 1;
},
usesSet: function(){
return _.isString(this.uses);
},

View File

@@ -74,7 +74,7 @@
checked={{enabled}}
disabled={{#unless canEditCharacter charId}}true{{/unless}}>
</paper-checkbox>
<paper-tooltip position="left">Feature enabled</paper-tooltip>
{{#simpleTooltip}}Feature enabled{{/simpleTooltip}}
</div>
{{/if}}
</div>
@@ -101,11 +101,13 @@
{{/each}}
</div>
{{#if canEditCharacter _id}}
<paper-fab id="addFeature"
class="floatyButton"
icon="add">
<paper-tooltip position="left">Add Feature</paper-tooltip>
</paper-fab>
<div class="floatyButton">
<paper-fab id="addFeature"
class="{{#if shouldFloatyButtonBounce}}bounce{{/if}}"
icon="add">
</paper-fab>
{{#simpleTooltip}}Add Feature{{/simpleTooltip}}
</div>
{{/if}}
</div>
</template>

View File

@@ -59,6 +59,10 @@ Template.features.helpers({
hasCharacters: function(string){
return string && string.match(/\S/);
},
shouldFloatyButtonBounce: function(){
const step = Session.get("newUserExperienceStep");
return step === 0 && Features.find({charId: this._id}).count() <= 1;
},
});
Template.features.events({

View File

@@ -110,12 +110,12 @@
<div class="paper-font-caption" style="margin-right: 8px">
{{round totalWeight}} lbs
</div>
<div>
<div style="position: relative;">
<paper-checkbox class="carriedCheckbox"
disabled={{#unless canEditCharacter charId}}true{{/unless}}
checked={{isCarried}}>
</paper-checkbox>
<paper-tooltip position="left"> Container carried</paper-tooltip>
{{#simpleTooltip}} Container carried{{/simpleTooltip}}
</div>
</div>
<div class="bottom list">
@@ -136,21 +136,21 @@
class="addContainer"
mini>
</paper-fab>
<paper-tooltip position="left"> New container </paper-tooltip>
{{#simpleTooltip class="always"}} Container {{/simpleTooltip}}
</div>
<div>
<paper-fab icon="av:library-books"
class="libraryItem"
mini>
</paper-fab>
<paper-tooltip position="left"> Library item </paper-tooltip>
{{#simpleTooltip class="always"}} Item from library {{/simpleTooltip}}
</div>
<div>
<paper-fab icon="note-add"
class="addItem"
mini>
</paper-fab>
<paper-tooltip position="left"> New item </paper-tooltip>
{{#simpleTooltip class="always"}} Item {{/simpleTooltip}}
</div>
{{/fabMenu}}
{{/if}}

View File

@@ -53,7 +53,7 @@
</div>
<div class="bottom list">
<div class="item-slot">
<div class="item race layout horizontal center">
<div class="item race layout horizontal center {{#if shouldRaceBounce}}bounce{{/if}}">
{{race}}
</div>
</div>
@@ -83,9 +83,12 @@
</div>
<div class="fab-buffer"></div>
{{#if canEditCharacter _id}}
<paper-fab id="addNote"
class="floatyButton"
icon="add"
title="Add"></paper-fab>
<div class="floatyButton">
<paper-fab id="addNote"
icon="add"
title="Add">
</paper-fab>
{{#simpleTooltip}}Add Note{{/simpleTooltip}}
</div>
{{/if}}
</template>

View File

@@ -50,6 +50,9 @@ Template.journal.helpers({
var char = Characters.findOne(this._id, {fields: {race: 1}});
return char && char.race;
},
shouldRaceBounce: function(){
return Session.get("newUserExperienceStep") === 1;
},
});
Template.journal.events({

View File

@@ -1,11 +1,34 @@
<template name="raceDialog">
{{#baseDialog title="Race" class=color hideColor="true" hideDelete="true" startEditing=startEditing}}
{{#if showNewUserExperience}}
{{#infoBox}}
{{#if stepComplete}}
<p>You can add all the effects you need to represent how your race affects your character's attributes.</p>
{{else}}
<p>Click the edit button to edit your race and add a racial effect</p>
{{/if}}
{{/infoBox}}
{{/if}}
<div class="horizontal layout center-justified paper-font-display2">
{{race}}
</div>
{{> effectsViewList charId=charId parentId=charId parentGroup="racial"}}
{{> proficiencyViewList charId=charId parentId=charId parentGroup="racial"}}
{{else}}
{{#if showNewUserExperience}}
{{#infoBox}}
{{#if stepComplete}}
<p>You can add all the effects you need to represent how your race affects your character's attributes.</p>
{{else}}
<p>
Add an effect with the following options: <br>
Attribute: <b>stats > speed</b> <br>
Operation: <b>Base Value</b> <br>
Value: <b>30</b> (might be different for some races)
</p>
{{/if}}
{{/infoBox}}
{{/if}}
<paper-input id="raceInput" label="Race" value={{race}}></paper-input>
{{> effectsEditList parentId=charId parentCollection="Characters" charId=charId parentGroup="racial"}}
{{> proficiencyEditList parentId=charId parentCollection="Characters" charId=charId parentGroup="racial"}}

View File

@@ -19,4 +19,10 @@ Template.raceDialog.helpers({
var char = Characters.findOne(this.charId, {fields: {color: 1}});
if (char) return getColorClass(char.color);
},
stepComplete: function(){
return Session.get("newUserExperienceStep") > 1;
},
showNewUserExperience: function(){
return Session.get("newUserExperienceStep") >= 1;
},
});

View File

@@ -0,0 +1,12 @@
.newUserStepper {
height: 180px !important;
}
.newUserStepper paper-step .invalid-step-message {
color: #d13b2e;
visibility: hidden;
}
.newUserStepper paper-step[invalid] .invalid-step-message {
visibility: visible;
}

View File

@@ -0,0 +1,29 @@
<template name="newUserStepper">
<paper-stepper linear selected="0" class="newUserStepper">
<paper-step id="step0" label="Add a feature">
<p>
To get started, add a feature
</p>
</paper-step>
<paper-step id="step1" label="Add an effect">
<p>
Add a racial effect to set your speed
</p>
</paper-step>
<paper-step id="step2" label="See the effect in action">
<p>
View your speed stat
</p>
</paper-step>
<paper-step id="step3" label="Finish">
Done! If you get stuck, be sure to check out the <a href="/guide">guide</a>, or ask for help using the feedback form
<div class="layout vertical end">
<paper-button class="done-button" style="color: #d13b2e">Finish</paper-button>
</div>
</paper-step>
</paper-stepper>
</template>
<template name="newUserStepperPlaceholder">
<div style="height: 300px"></div>
</template>

View File

@@ -0,0 +1,58 @@
Template.newUserStepper.onRendered(function(){
Session.set("newUserExperienceStep", 0);
let stepper = this.find("paper-stepper");
_.defer(() => {
this.autorun((c) => {
var step = Session.get("newUserExperienceStep");
var hasFeatures = Features.find({charId: this.data._id}).count() > 1;
if (step === 0 && hasFeatures){
stepper.continue();
}
});
this.autorun((c) => {
var step = Session.get("newUserExperienceStep");
var hasEffect = !!Effects.find({
charId: this.data._id,
stat: "speed",
"parent.group": "racial",
operation: "base",
value: {$gt: 0},
}).count();
if (step === 1 && hasEffect){
stepper.continue();
}
});
this.autorun((c) => {
var step = Session.get("newUserExperienceStep");
if (step === 2 && Session.get("viewedSpeed")){
Session.set("viewedSpeed", undefined);
stepper.continue();
}
});
});
});
Template.newUserStepper.events({
"paper-stepper-progressed paper-stepper": function(event, template){
const step = template.find("paper-stepper").selected;
Session.set("newUserExperienceStep", step);
},
"paper-stepper-completed paper-stepper": function(event, template){
Session.set("newUserExperienceStep", undefined);
Session.set("showNewUserExperience", undefined);
Characters.update(this._id, {$unset: {"settings.newUserExperience": 1}});
},
"click .done-button": function(event, instance){
const stepper = instance.find("paper-stepper");
stepper.continue();
},
});
Template.stats.events({
"click .stat-card": function(event, instance){
var step = Session.get("newUserExperienceStep");
if (this.stat === "speed" && step === 2){
Session.set("viewedSpeed", true);
}
}
});

View File

@@ -53,22 +53,22 @@
{{numPrepared}} / {{evaluate charId maxPrepared}}
</div>
{{/if}}
<div>
<paper-tooltip position="left">
Done
</paper-tooltip>
<div style="position: relative;">
<paper-icon-button class="finishPrep" icon="done">
</paper-icon-button>
{{#simpleTooltip}}
Done
{{/simpleTooltip}}
</div>
{{else}}
<div>
<paper-tooltip position="left">
Change prepared spells
</paper-tooltip>
<div style="position: relative;">
<paper-icon-button class="prepSpells"
disabled={{#unless canEditCharacter charId}}true{{/unless}}
icon="book">
</paper-icon-button>
{{#simpleTooltip}}
Change prepared spells
{{/simpleTooltip}}
</div>
{{/if}}
</div>
@@ -124,32 +124,31 @@
{{#if canEditCharacter _id}}
{{#fabMenu}}
<div>
<paper-tooltip position="left">
New spell list
</paper-tooltip>
<paper-fab icon="work"
class="addSpellList"
mini>
</paper-fab>
{{#simpleTooltip class="always"}}
Spell list
{{/simpleTooltip}}
</div>
<div>
<paper-tooltip position="left">
Spell library
</paper-tooltip>
<paper-fab icon="av:library-books"
class="librarySpell"
mini>
</paper-fab>
{{#simpleTooltip class="always"}}
Spell from library
{{/simpleTooltip}}
</div>
<div>
<paper-tooltip position="left">
New spell
</paper-tooltip>
<paper-fab icon="note-add"
class="addSpell"
mini>
</paper-fab>
{{#simpleTooltip class="always"}}
Spell
{{/simpleTooltip}}
</div>
{{/fabMenu}}
{{/if}}

View File

@@ -6,6 +6,16 @@
</template>
<template name="attributeDialogView">
{{#if showNewUserExperience}}
{{#infoBox}}
<p>
This dialog shows how your speed is set by the effect you added to your character's race.
</p>
<p>
In DiceCloud you don't change stats directly, rather you add effects which impact your stats in different ways. This way, you can always tell where your stats came from, and how they got to their current value.
</p>
{{/infoBox}}
{{/if}}
<div class="layout horizontal center-justified end">
<div class="paper-font-display2">
{{attributeValue}}

View File

@@ -157,4 +157,9 @@ Template.attributeDialogView.helpers({
statValue: function(){
return evaluateEffect(this.charId, this);
},
showNewUserExperience: function(){
if (this.statName === "speed"){
return Session.get("newUserExperienceStep") >= 2;
}
},
});

View File

@@ -1,6 +1,6 @@
<template name="statCard">
<div>
<paper-material class="stat-card layout horizontal">
<paper-material class="stat-card layout horizontal {{#if bounce}}bounce{{/if}}">
<div class="numbers paper-font-display1">
{{#if isSkill}}
{{prefix}}{{skillMod}}

View File

@@ -15,7 +15,7 @@
<!--Armor-->
{{> statCard stat="armor" name="Armor Class" color="teal"}}
<!--Speed-->
{{> statCard stat="speed" name="Speed" color="teal"}}
{{> statCard stat="speed" name="Speed" color="teal" bounce=shouldSpeedBounce}}
<!--Initiative-->
{{> statCard stat="initiative" name="Initiative" color="indigo" isSkill="true"}}
<!--Proficiency Bonus-->

View File

@@ -8,6 +8,10 @@ Template.stats.helpers({
};
return Buffs.find(selector);
},
// New user experience
shouldSpeedBounce: function(){
return Session.get("newUserExperienceStep") === 2;
},
})
Template.stats.events({
@@ -84,8 +88,7 @@ Template.stats.events({
callback: (result) => {
if (!result) {
return;
}
else Meteor.call("giveCondition", this._id, result)
} else Meteor.call("giveCondition", this._id, result)
},
//returnElement: () => $(`[data-id='${itemId}']`).get(0),
})

View File

@@ -49,14 +49,14 @@
class="addParty"
mini>
</paper-fab>
<paper-tooltip position="left"> New Party </paper-tooltip>
{{#simpleTooltip class="always"}} New Party {{/simpleTooltip}}
</div>
<div>
<paper-fab icon="face"
class="addCharacter"
mini>
</paper-fab>
<paper-tooltip position="left"> New Character </paper-tooltip>
{{#simpleTooltip class="always"}} New Character {{/simpleTooltip}}
</div>
{{/fabMenu}}
</div>

View File

@@ -0,0 +1,15 @@
.infoBox iron-icon {
color: #747474;
color: rgba(0,0,0,0.54);
height: 32px;
width: 32px;
margin-right: 12px;
}
.infoBox > div > p {
margin: 0;
}
.infoBox > div > p + p {
margin-top: 10px;
}

View File

@@ -0,0 +1,10 @@
<template name="infoBox">
<div class="layout horizontal center infoBox">
<div>
<iron-icon icon="info-outline"></iron-icon>
</div>
<div class="flex">
{{> Template.contentBlock}}
</div>
</div>
</template>

View File

@@ -25,7 +25,6 @@
{{/ simpleTooltip}}
</div>
<div class="brackets" style="position: relative">
<!--<paper-tooltip position="left" animation-delay="0">This field accepts formulae in {curly brackets}</paper-tooltip>-->
<iron-icon icon="dicecloud:code-braces"></iron-icon>
{{# simpleTooltip}}
This field accepts formulae in {curly brackets}

View File

@@ -1,4 +1,18 @@
.simple-tooltip:hover .tooltip {
.simple-tooltip {
pointer-events: none;
}
.simple-tooltip:active {
pointer-events: none;
}
/* Show the tooltip if a older sibling is hovered */
*:hover ~ .simple-tooltip > .tooltip {
opacity: 0.9;
}
/* Show the tooltip if parent is hovered */
*:hover > .simple-tooltip > .tooltip {
opacity: 0.9;
}
@@ -16,3 +30,7 @@
pointer-events: none;
white-space: nowrap;
}
.tooltip.always {
opacity: 0.9;
}

View File

@@ -1,6 +1,6 @@
<template name="simpleTooltip">
<div class="simple-tooltip fit">
<div class="tooltip">
<div class="simple-tooltip fit layout vertical center-justified">
<div class="tooltip {{class}}">
{{> Template.contentBlock}}
</div>
</div>

View File

@@ -27,7 +27,7 @@
{{#if verified}}
<span>
<iron-icon icon="check"></iron-icon>
<paper-tooltip>Verified</paper-tooltip>
{{#simpleTooltip}}Verified{{/simpleTooltip}}
</span>
{{/if}}
</div>

View File

@@ -49,6 +49,7 @@
"/custom_components/dicecloud-wrapper/dicecloud-wrapper.html",
"/custom_components/paper-checkbox/paper-checkbox.html",
"/custom_components/paper-diff-slider/paper-diff-slider.html",
"/custom_components/paper-stepper/paper-stepper.html",
"/custom_components/app-theme.html"
]
}

View File

@@ -2,7 +2,7 @@ AccountsTemplates.configure({
//behaviour
confirmPassword: true,
enablePasswordChange: true,
enforceEmailVerification: true,
enforceEmailVerification: false,
overrideLoginErrors: false,
sendVerificationEmail: true,
lowercaseUsername: true,
@@ -21,35 +21,35 @@ AccountsTemplates.configure({
AccountsTemplates.configureRoute("changePwd", {
template: "titledAtForm",
layoutTemplate: 'layout',
layoutTemplate: "layout",
});
AccountsTemplates.configureRoute("enrollAccount", {
template: "titledAtForm",
layoutTemplate: 'layout',
layoutTemplate: "layout",
});
AccountsTemplates.configureRoute("forgotPwd", {
template: "titledAtForm",
layoutTemplate: 'layout',
layoutTemplate: "layout",
});
AccountsTemplates.configureRoute("resetPwd", {
template: "titledAtForm",
layoutTemplate: 'layout',
layoutTemplate: "layout",
});
AccountsTemplates.configureRoute("signIn", {
template: "titledAtForm",
layoutTemplate: 'layout',
layoutTemplate: "layout",
});
AccountsTemplates.configureRoute("signUp", {
template: "titledAtForm",
layoutTemplate: 'layout',
layoutTemplate: "layout",
});
AccountsTemplates.configureRoute("verifyEmail", {
template: "titledAtForm",
layoutTemplate: 'layout',
layoutTemplate: "layout",
});
AccountsTemplates.configureRoute("resendVerificationEmail", {
template: "titledAtForm",
layoutTemplate: 'layout',
layoutTemplate: "layout",
});
if (Meteor.isServer){

View File

@@ -0,0 +1,45 @@
<!--
@license
Copyright (c) 2015 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
-->
<link rel="import" href="../../../components/polymer/polymer.html">
<link rel="import" href="../../../components/neon-animation/neon-animation-behavior.html">
<link rel="import" href="../../../components/neon-animation/web-animations.html">
<script>
Polymer({
is: 'fade-in-slide-from-left-animation',
behaviors: [
Polymer.NeonAnimationBehavior
],
configure: function(config) {
var node = config.node;
this._effect = new KeyframeEffect(node, [
{'transform': 'translateX(-100%)', 'opacity': '0'},
{'transform': 'translateX(-50%)', 'opacity': '0'},
{'transform': 'none', 'opacity': '1'}
], this.timingFromConfig(config));
if (config.transformOrigin) {
this.setPrefixedProperty(node, 'transformOrigin', config.transformOrigin);
} else {
this.setPrefixedProperty(node, 'transformOrigin', '0 50%');
}
return this._effect;
}
});
</script>

View File

@@ -0,0 +1,45 @@
<!--
@license
Copyright (c) 2015 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
-->
<link rel="import" href="../../../components/polymer/polymer.html">
<link rel="import" href="../../../components/neon-animation/neon-animation-behavior.html">
<link rel="import" href="../../../components/neon-animation/web-animations.html">
<script>
Polymer({
is: 'fade-in-slide-from-right-animation',
behaviors: [
Polymer.NeonAnimationBehavior
],
configure: function(config) {
var node = config.node;
this._effect = new KeyframeEffect(node, [
{'transform': 'translateX(100%)', 'opacity': '0'},
{'transform': 'translateX(50%)', 'opacity': '0'},
{'transform': 'none', 'opacity': '1'}
], this.timingFromConfig(config));
if (config.transformOrigin) {
this.setPrefixedProperty(node, 'transformOrigin', config.transformOrigin);
} else {
this.setPrefixedProperty(node, 'transformOrigin', '0 50%');
}
return this._effect;
}
});
</script>

View File

@@ -0,0 +1,45 @@
<!--
@license
Copyright (c) 2015 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
-->
<link rel="import" href="../../../components/polymer/polymer.html">
<link rel="import" href="../../../components/neon-animation/neon-animation-behavior.html">
<link rel="import" href="../../../components/neon-animation/web-animations.html">
<script>
Polymer({
is: 'fade-out-slide-left-animation',
behaviors: [
Polymer.NeonAnimationBehavior
],
configure: function(config) {
var node = config.node;
this._effect = new KeyframeEffect(node, [
{'transform': 'none', 'opacity': '1'},
{'transform': 'translateX(-50%)', 'opacity': '0'},
{'transform': 'translateX(-100%)', 'opacity': '0'},
], this.timingFromConfig(config));
if (config.transformOrigin) {
this.setPrefixedProperty(node, 'transformOrigin', config.transformOrigin);
} else {
this.setPrefixedProperty(node, 'transformOrigin', '0 50%');
}
return this._effect;
}
});
</script>

View File

@@ -0,0 +1,45 @@
<!--
@license
Copyright (c) 2015 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
-->
<link rel="import" href="../../../components/polymer/polymer.html">
<link rel="import" href="../../../components/neon-animation/neon-animation-behavior.html">
<link rel="import" href="../../../components/neon-animation/web-animations.html">
<script>
Polymer({
is: 'fade-out-slide-right-animation',
behaviors: [
Polymer.NeonAnimationBehavior
],
configure: function(config) {
var node = config.node;
this._effect = new KeyframeEffect(node, [
{'transform': 'none', 'opacity': '1'},
{'transform': 'translateX(50%)', 'opacity': '1'},
{'transform': 'translateX(100%)', 'opacity': '0'}
], this.timingFromConfig(config));
if (config.transformOrigin) {
this.setPrefixedProperty(node, 'transformOrigin', config.transformOrigin);
} else {
this.setPrefixedProperty(node, 'transformOrigin', '0 50%');
}
return this._effect;
}
});
</script>

View File

@@ -0,0 +1,48 @@
{
"name": "paper-stepper",
"version": "2.0-beta.5",
"authors": [
"Zecat <jullienfelix@gmail.com>"
],
"description": "Material paper-stepper element.",
"keywords": [
"web-component",
"polymer",
"seed"
],
"main": "paper-stepper.html",
"license": "http://polymer.github.io/LICENSE.txt",
"homepage": "https://github.com/zecat/paper-stepper/",
"ignore": [
"/.*",
"/test/"
],
"dependencies": {
"polymer": "Polymer/polymer#^1.2.0",
"paper-button": "PolymerElements/paper-button#^1.0.11",
"iron-icons": "PolymerElements/iron-icons#^1.1.3",
"paper-styles": "PolymerElements/paper-styles#^1.1.4",
"paper-ripple": "PolymerElements/paper-ripple#^1.0.5",
"iron-selector": "PolymerElements/iron-selector#^1.3.0",
"iron-icon": "PolymerElements/iron-icon#^1.0.8",
"iron-flex-layout": "PolymerElements/iron-flex-layout#^1.3.1",
"neon-animation": "PolymerElements/neon-animation#^1.1.1",
"iron-validatable-behavior": "PolymerElements/iron-validatable-behavior#^1.0.5",
"iron-collapse": "PolymerElements/iron-collapse#^1.2.0"
},
"devDependencies": {
"paper-input": "PolymerElements/paper-input#^1.1.10",
"paper-material": "PolymerElements/paper-material#^1.0.6",
"iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
"web-component-tester": "*",
"iron-form": "PolymerElements/iron-form#^1.0.16",
"iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.2.2",
"paper-toggle-button": "PolymerElements/paper-toggle-button#^1.2.0",
"app-layout": "PolymerElements/app-layout#^0.10.2",
"paper-menu": "PolymerElements/paper-menu#^1.2.2",
"iron-scroll-spy": "Zecat/iron-scroll-spy#^2.1.0",
"paper-item": "PolymerElements/paper-item#^1.2.1",
"paper-toast": "PolymerElements/paper-toast#^1.3.0",
"paper-checkbox": "PolymerElements/paper-checkbox#^1.4.0"
}
}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 225 126" enable-background="new 0 0 225 126" xml:space="preserve">
<g id="background" display="none">
<rect display="inline" fill="#B0BEC5" width="225" height="126"/>
</g>
<g id="label">
</g>
<g id="art">
<g id="ic_x5F_add_x0D_">
</g>
<circle cx="78" cy="98" r="4"/>
<circle cx="171" cy="90" r="4"/>
<circle cx="132" cy="61" r="4"/>
<circle cx="53" cy="61" r="4"/>
<circle cx="126" cy="28" r="4"/>
<circle cx="91" cy="67" r="4"/>
<circle cx="132" cy="90" r="4"/>
<circle cx="65" cy="32" r="4"/>
<path d="M77.7,99.4L51.9,61.1L64.3,31l64.1-4.2L92.6,66.7l16.1,9l23.3-16L174,91h-42.3l-23-12.9L77.7,99.4z M54.1,60.9l24.1,35.7
L106.8,77l-17.4-9.8l34.2-38.1L65.7,33L54.1,60.9z M132.3,89H168l-36-26.8l-21.4,14.6L132.3,89z"/>
</g>
<g id="Guides">
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,424 @@
<link rel="import" href="../../components/iron-validatable-behavior/iron-validatable-behavior.html">
<link rel="import" href="../../components/paper-item/paper-item-behavior.html">
<link rel="import" href="../../components/paper-behaviors/paper-ripple-behavior.html">
<link rel="import" href="../../components/neon-animation/neon-animatable-behavior.html">
<link rel="import" href="../../components/paper-styles/default-theme.html">
<link rel="import" href="step-horizontal-label.html">
<link rel="import" href="step-vertical.html">
<link rel="import" href="../../components/polymer/polymer.html">
<!--
Missing Doc
@element paper-step
@demo demo/index.html
@hero hero.svg
-->
<dom-module id="paper-step">
<template>
<style>
:host {
display: block;
box-sizing: border-box;
outline: 0;
}
:host(:not([vertical])) {
overflow: hidden;
@apply(--layout);
@apply(--layout-flex);
}
:host(:not([vertical])[opened]){
overflow: visible;
}
:host(:not([opened]):not(.neon-animating)) #slideshowViewport{
display: none;
}
#slideshowViewport {
position: absolute;
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
}
#contentWrapper {
padding: 16px 0 16px 16px;
@apply(--layout-scroll);
@apply(--layout-fit);
pointer-events: auto;
}
:host(:focus:not([opened]):not([saved])) step-horizontal-label ::content #badge {
background: var(--paper-step-selectable-hovered-badge-background, --paper-grey-500);
}
</style>
<!-- horizontal step layout -->
<template is="dom-if" if="[[!vertical]]">
<step-horizontal-label id="horizontalStepLabel" editable="[[editable]]" label="[[label]]"
alternative-label="[[_alternativeLabel]]" optional="[[optional]]"
opened="[[opened]]" selectable="[[selectable]]" index="[[index]]"
saved="[[saved]]" stepper-data="[[_stepperData]]">
</step-horizontal-label>
<div id="slideshowViewport">
<div id="contentWrapper">
</div>
</div>
</template>
<!-- vertical step layout -->
<template is="dom-if" if="[[vertical]]">
<step-vertical id="verticalStepLabel" editable="[[editable]]" label="[[label]]"
optional="[[optional]]" opened="[[opened]]"
selectable="[[selectable]]" stepper-data="[[_stepperData]]" index="[[index]]"
saved="[[saved]]" _attr-for-primary-button-text="[[_attrForPrimaryButtonText]]"
can-skip="[[_canSkip]]" has-back-step="[[_hasBackStep]]">
</step-vertical>
</template>
</template>
<script>
Polymer({
is: 'paper-step',
behaviors: [
Polymer.IronValidatableBehavior,
Polymer.NeonAnimatableBehavior,
Polymer.PaperItemBehavior,
Polymer.PaperRippleBehavior
],
/**
* Fired when the step has been saved.
*
* @event paper-step-saved
*/
/**
* Fired when the step has been updated
*
* @event paper-step-updated
*/
properties: {
/**
* MISSING Doc
*/
saved: {
type: Boolean,
value: false,
notify: true,
readOnly: true
},
/**
* Missing Doc
*/
editable: {
type: Boolean,
value: false
},
/**
* Missing Doc
*/
index: {
type: Number,
notify: true,
readOnly: true
},
/**
* Missing Doc
*/
_previousSaved: {
type: Boolean,
readOnly: true
},
/**
* Missing Doc
*/
optional: {
type: Boolean,
value: false
},
/**
* Missing Doc
*/
selectable: {
type: Boolean,
computed: '_computeSelectable(_stepperData.linear, saved, editable, _previousSaved)',
reflectToAttribute: true,
notify: true
},
/**
* Missing Doc
*/
disabled: {
computed: '_computeDisabled(selectable)'
},
/**
* Missing Doc
*/
label: {
type: String,
value: ''
},
/**
* Missing Doc
*/
opened: {
type: Boolean,
value: false
},
/**
* Missing Doc
*/
animationConfig: {
readOnly: true
},
/**
* Missing Doc
*/
entryAnimation: {
readOnly: true
},
/**
* Missing Doc
*/
exitAnimation: {
readOnly: true
},
/**
* Missing Doc
*/
vertical: {
type: Boolean,
readOnly: true,
reflectToAttribute: true
},
/**
* Missing Doc
*/
horizontalHigherEntryAnimation: {
type: String
},
/**
* Missing Doc
*/
horizontalHigherExitAnimation: {
type: String
},
/**
* Missing Doc
*/
horizontalLowerEntryAnimation: {
type: String
},
/**
* Missing Doc
*/
horizontalLowerExitAnimation: {
type: String
},
/**
* Missing Doc
*/
_alternativeLabel: {
type: Boolean,
readOnly: true
},
/**
* Missing Doc
*/
_optionalText: {
type: Boolean,
readOnly: true
},
/**
* Missing Doc
*/
_attrForPrimaryButtonText: {
type: String,
readOnly: true
},
/**
* A reference to the parent stepper
*/
_stepper: {
type: Object,
readOnly: true
},
_stepperData: {
type: Object,
readOnly: true
},
_canSkip: {
type: Boolean,
readOnly: true
},
_hasBackStep: {
type: Boolean,
readOnly: true
}
},
listeners: {
'paper-step-vertical-skip-tapped': 'skip',
'paper-step-vertical-back-tapped': 'back',
'paper-step-vertical-continue-tapped': 'continue',
'tap': '_tapHandler'
},
observers: [
'_toggleClassPosition(index, _stepperData.stepNumber, vertical)',
'_updateSlideshowViewportTop(optional, _alternativeLabel, vertical)',
'_verticalChange(vertical)',
'_focusedChanged(receivedFocusFromKeyboard)',
'_labelElementChanged(_labelElement)'
],
_focusedChanged: function(receivedFocusFromKeyboard) {
if (receivedFocusFromKeyboard) {
this.ensureRipple();
// generate a ripple effect from the center of the badge
var badge = Polymer.dom(this._rippleContainer).querySelector('#badge');
var badgePos = badge.getBoundingClientRect();
var rippleX = badgePos.left + 12;
var rippleY = badgePos.top + 12;
this._ripple.downAction({detail: {x: rippleX, y: rippleY}});
}
if (this.hasRipple()) {
this._ripple.holdDown = receivedFocusFromKeyboard;
}
},
_tapHandler: function(e) {
var rootTarget = Polymer.dom(e).rootTarget;
if (rootTarget !== this && rootTarget !== this._rippleContainer) {
e.stopImmediatePropagation();
}
},
/**
* Missing Doc
*/
skip: function() {
// would it be better to send an event?
this._stepper.progress();
},
/**
* Missing Doc
*/
back: function() {
// would it be better to send an event?
this._stepper.back();
},
/**
* Mark the step as saved and fire `paper-step-saved` if it is valid.
* @return {Boolean} True if the step has been saved.
*/
save: function() {
if ((!this.saved || this.editable) && this.validate()) {
if (this.saved) {
this.fire('paper-step-updated');
} else {
this._setSaved(true);
this.fire('paper-step-saved');
}
return true;
}
return false;
},
/**
* Atempte to save the step and select and to progress into the stepper.
* @return {Boolean} True if the step is valid for saving.
*/
continue: function() {
if (this.save()) {
// would it be better to send an event?
this._stepper.progress();
return true;
}
return false;
},
_removeAnimatingClass: function() {
if (this._animationCanceled) {
this._set_animationCanceled(false);
} else {
this.toggleClass('neon-animating', false);
}
},
_cancelAnimation: function() {
this._set_animationCanceled(true);
this.toggleClass('neon-animating', false);
},
_updateSlideshowViewportTop: function(optional, _alternativeLabel, vertical) {
if (!vertical) {
this.async(function() {
this.$$('#slideshowViewport').style.top = this.clientHeight+'px';
this.fire('step-horizontal-label-resize');
})
}
},
_toggleClassPosition: function(index, stepNumber, vertical) {
this.async(function() {
var stepLabel = this.$$(vertical ? '#verticalStepLabel' : '#horizontalStepLabel');
this.toggleClass('first-step', (index == 1), stepLabel);
this.toggleClass('last-step', (index == stepNumber), stepLabel);
});
},
_updateAnimationConfig: function() {
/* TODO: call this method when horizontalHigher/LowerEntry/ExitAnimation change */
var animatedNode = this.$$('#contentWrapper');
this._setAnimationConfig({
'higher-step-entry': {
node: animatedNode,
name: this.horizontalHigherEntryAnimation
},
'higher-step-exit': {
node: animatedNode,
name: this.horizontalHigherExitAnimation
},
'lower-step-entry': {
node: animatedNode,
name: this.horizontalLowerEntryAnimation
},
'lower-step-exit': {
node: animatedNode,
name: this.horizontalLowerExitAnimation
}
});
},
_verticalChange: function(vertical) {
this.async(function() {
// move or create the content tag
Polymer.dom(this.$$(vertical ? '#verticalStepLabel' : '#contentWrapper')).appendChild(this.$$('content') || this.create('content'));
// reset the ripple
this._ripple = false;
this._rippleContainer = vertical ? this.$$('#verticalStepLabel').$.label : this.$$('#horizontalStepLabel').$.label;
if (!vertical) {
this._updateAnimationConfig();
}
}.bind(this));
},
_computeSelectable: function(linear, saved, editable, previousSaved) {
// TODO: factorize the expression
return (!linear || previousSaved) && (!saved || editable) || (editable && saved);
},
_computeDisabled: function(selectable) {
// disabled is used by IronMenuBehavior in paper-stepper
// TODO: remove selectable attribute and use disabled instead
return !selectable;
}
});
</script>
</dom-module>

View File

@@ -0,0 +1,735 @@
<link rel="import" href="../../components/iron-flex-layout/iron-flex-layout.html">
<link rel="import" href="../../components/iron-selector/iron-selectable.html">
<link rel="import" href="../../components/iron-menu-behavior/iron-menu-behavior.html">
<link rel="import" href="../../components/neon-animation/neon-animation-runner-behavior.html">
<link rel="import" href="../../components/paper-button/paper-button.html">
<link rel="import" href="../../components/paper-styles/default-theme.html">
<link rel="import" href="../../components/paper-styles/shadow.html">
<link rel="import" href="../../components/iron-collapse/iron-collapse.html">
<link rel="import" href="../../components/iron-resizable-behavior/iron-resizable-behavior.html">
<link rel="import" href="../../components/polymer/polymer.html">
<link rel="import" href="animations/fade-in-slide-from-right-animation.html">
<link rel="import" href="animations/fade-out-slide-right-animation.html">
<link rel="import" href="animations/fade-in-slide-from-left-animation.html">
<link rel="import" href="animations/fade-out-slide-left-animation.html">
<link rel="import" href="paper-step.html">
<!--
Missing Doc
## Styling
The default color values respect the material specifications. For basic configuration, just defines the `--primary-color` for your app.
The stepper has a complexe interface so many custom properties are available, use them this way :
```html
<style is="custom-style">
paper-stepper {
--paper-stepper-custom-property: value;
}
paper-step {
--paper-step-custom-property: value;
}
</style>
<paper-stepper>
<paper-step></paper-step>
<paper-step></paper-step>
</paper-stepper>
```
Note, for sizing the stepper and steps depending on the layout, use the following instead of setting 'height' and 'max-height' :
- `--paper-stepper-horizontal-opened-height`
- `--paper-stepper-vertical-max-height`
- `--paper-vertical-step-max-height`
### Stepper
Custom property | Description | Default
------|-------------|----------
`--paper-stepper-horizontal-opened-height` | The horizontal opened stepper height | 450px
`--paper-stepper-horizontal-opening-transition-duration`| The horizontal stepper opening transition duration (ms) | 500
`--paper-stepper-vertical-max-height`| The vertical stepper max height so it has a scrollable area | undefined
### Step
Custom property | Description | Default
------|-------------|----------
`--paper-step-connector-line-background` | The connector lines background color. | `--divider-color`
`--paper-step-label-hover-background` | The steps label background when hovered. | rgba(0,0,0,0.04)
`--paper-step-ink-color` | The steps ripple effect ink color. | `--divider-color`
### Step text label
Custom property | Description | Default
------|-------------|----------
`--paper-step-disabled-label-text-color` | The no-selectable steps label text color. | `--paper-grey-400`
`--paper-step-selectable-label-text-color` | The selectable steps label text color. | `--paper-grey-600`
`--paper-step-opened-label-text-color` | The opened steps label text color. | `--light-theme-text-color`
`--paper-step-label-text-font-size` | The steps label text font size. | 14px
`--paper-step-label-optional-text-font-size` | The steps label optional text font size. | 12px
### Step badge
Custom property | Description | Default
------|-------------|----------
`--paper-step-badge-background` | The badge background. | `--paper-grey-300`
`--paper-step-badge-color` | The badge color. | `--dark-theme-text-color`
`--paper-step-badge-icon-width` | The badge icon width. | 16px
`--paper-step-badge-icon-height` | The badge icon height. | 16px
`--paper-step-opened-badge-background` | The opened steps badge background. | `--primary-color`
`--paper-step-saved-badge-background` | The saved steps badge background. | `--primary-color`
`--paper-step-selectable-hovered-badge-background` | The no-opened no-saved selectable steps badge background. | `--paper-grey-500`
### Vertical step
Custom property | Description | Default
------|-------------|----------
`--paper-vertical-step-continue-button-background` | The continue button background. | `--primary-color`
`--paper-vertical-step-continue-button-color` | The continue button background. | `--dark-theme-text-color`
`--paper-vertical-step-max-height` | The unrolled step content max-height. | 400px
`--paper-vertical-step-transition-duration` | The step opening transition duration | 500ms
@element paper-stepper
@demo demo/index.html
@hero hero.svg
-->
<dom-module id="paper-stepper">
<template>
<style>
:host {
display: block;
box-sizing: border-box;
@apply(--layout-vertical);
@apply(--shadow-elevation-2dp);
background: white;
border-radius: 1px;
}
#verticalResponsiveWidth {
width: var(--paper-stepper-vertical-responsive-width, 0px);
visibility: hidden;
}
/* Horizontal layout styles */
:host([vertical]) {
padding: 4px 0;
@apply(--layout-scroll);
max-height: var(--paper-stepper-vertical-max-height);
}
:host(:not([vertical])) {
position: relative;
/* Note: this variable is updated by the stepper itself, don't use it on user side */
height: var(--label-wrapper-height);
max-height: var(--label-wrapper-height);
transition: max-height var(--paper-stepper-horizontal-opening-transition-duration, 300ms), box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);
}
:host(:not([vertical]):not([opened]):not(.collapsing)) {
@apply(--shadow-none);
}
:host(:not([vertical])[opened]) {
max-height: var(--paper-stepper-horizontal-opened-height, 450px);
}
:host(:not([vertical])[opened]), :host(:not([vertical]).collapsing) {
height: var(--paper-stepper-horizontal-opened-height, 450px);
}
:host(:not([vertical])) #content-wrapper {
@apply(--shadow-elevation-2dp);
@apply(--layout-horizontal);
@apply(--layout-flex-none);
@apply(--layout-justified);
background: var(--paper-stepper-horizontal-label-wrapper-background, --primary-background-color);
border-radius: 1px;
overflow: hidden;
}
.flex {
@apply(--layout-flex);
}
#buttonsWrapper {
@apply(--layout-horizontal);
overflow: hidden;
}
#continueButton:not([disabled]) {
color: var(--primary-color);
}
paper-button[disabled] {
background-color: transparent;
}
[hidden] {
display: none;
}
:host(:not[vertical]) #content-wrapper ::content paper-step[opened] {
overflow: visible;
}
</style>
<!-- Hidden block with width equals to the responsive threshold -->
<div id="verticalResponsiveWidth"></div>
<!-- This wrapper contains the horizontal stepper header or the full vertical stepper -->
<div id="content-wrapper">
<content select="[[selectable]]"></content>
</div>
<!-- Slideshow and buttons area for horizontal layout -->
<template is="dom-if" if="[[!vertical]]">
<div class="flex"></div>
<!--
<div id="buttonsWrapper">
<paper-button hidden$="[[!hasBackButton]]" disabled=[[!_hasBackStep]] on-tap="back">[[backText]]</paper-button>
<span class="flex"></span>
<paper-button hidden$="[[!hasSkipButton]]" disabled="[[!_canSkip]]" on-tap="progress">[[skipText]]</paper-button>
<paper-button id="continueButton" on-tap="continue">{{_choosePrimaryButtonText(_attrForSelectedStepPrimaryButtonText, finishText, continueText, updateText)}}</paper-button>
</div>
-->
</template>
</template>
<script>
'use strict';
Polymer({
is: 'paper-stepper',
behaviors: [
Polymer.IronMenuBehavior,
Polymer.NeonAnimationRunnerBehavior,
Polymer.IronResizableBehavior
],
/**
* Fired when the stepper progress.
*
* @event paper-stepper-progressed
*/
/**
* Fired when all the steps are saved.
*
* @event paper-stepper-completed
*/
properties: {
opened: {
type: Boolean,
computed: '_computeOpened(_selectedIndex)',
observer: '_openedChanged',
notify: true,
reflectToAttribute: true
},
alternativeLabel: {
type: Boolean,
value: false
},
vertical: {
type: Boolean,
value: false,
reflectToAttribute: true
},
backText: {
type: String,
value: 'BACK'
},
finishText: {
type: String,
value: 'FINISH'
},
continueText: {
type: String,
value: 'CONTINUE'
},
skipText: {
type: String,
value: 'SKIP'
},
optionalText: {
type: String,
value: 'Optional'
},
updateText: {
type: String,
value: 'UPDATE'
},
linear: {
type: Boolean,
value: false
},
completed: {
type: Boolean,
value: false,
notify: true,
computed: '_computeCompleted(stepNumber, savedStepNumber)'
},
hasSkipButton: {
type: Boolean,
value: false
},
hasBackButton: {
type: Boolean,
value: false
},
stepNumber: {
type: Number,
notify: true,
computed: '_computeStepNumber(items.length)'
},
savedStepNumber: {
type: Number,
notify: true,
readOnly: true
},
selectedAttribute: {
value: 'opened',
readOnly: true
},
/**
* Note: if you decide to change this attribute, take care to only include `<paper-step>` elements in your `<paper-stepper>`
*/
selectable: {
value: 'paper-step'
},
/**
* Multi mode is not allowed for now in paper-stepper.
*/
mutli: {
value: false,
readOnly: true
},
responsiveCheckFrequence: {
type: Number,
value: 200
},
animateInitialSelection: {
type: Boolean,
value: false
},
horizontalHigherEntryAnimation: {
type: String,
value: 'fade-in-slide-from-right-animation'
},
horizontalHigherExitAnimation: {
type: String,
value: 'fade-out-slide-right-animation'
},
horizontalLowerEntryAnimation: {
type: String,
value: 'fade-in-slide-from-left-animation'
},
horizontalLowerExitAnimation: {
type: String,
value: 'fade-out-slide-left-animation'
},
_skipStepIndex: {
type: Number,
computed: '_compute_skipStepIndex(_selectedIndex)'
},
_canSkip: {
type: Boolean,
notify: true,
computed: '_isntNull(_skipStepIndex)'
},
_backStepIndex: {
type: Number,
computed: '_compute_backStepIndex(_selectedIndex)'
},
_hasBackStep: {
type: Boolean,
computed: '_isntNull(_backStepIndex)'
},
_selectedIndex: {
type: Number,
observer: '_selectedIndexChanged',
readOnly: true,
value: -1
},
_attrForSelectedStepPrimaryButtonText: {
type: String,
computed: '_compute__attrForSelectedStepPrimaryButtonText(_selectedIndex, stepNumber)'
},
_previousAnimatedStep: {
type: Object,
value: null,
readOnly: true
},
_previousSelected: {
type: Object,
readOnly: true
}
},
keyBindings: {
'left': '_onLeftKey',
'right': '_onRightKey'
},
listeners: {
'iron-items-changed': '_initializeSteps',
'paper-step-saved': '_stepSaved',
'transitionend': '_transitionEnd',
'step-horizontal-label-resize': '_updateStepperClosedMaxHeight',
'iron-resize': '_resizeHandler',
'neon-animation-finish': '_onNeonAnimationFinish'
},
observers: [
'_forwardCanSkip(_canSkip, selectedItem)',
'_forwardHasBackStep(_hasBackStep, selectedItem)',
'_forwardVertical(vertical)',
'_forwardAlternativeLabel(alternativeLabel)',
'_forwardStepperData(linear, backText, optionalText, finishText, continueText, skipText, updateText, hasSkipButton, hasBackButton)'
],
attached: function() {
this._responsiveCheck();
},
/**
* Missing Doc
*/
back: function() {
this.selectIndex(this._backStepIndex);
},
/**
* @return {Boolean} Try to continue the current step (if no step opened, use the first one).
*/
continue: function() {
if (this.selectedItem) {
if (this.selectedItem.save()) {
this.progress();
}
}
},
/**
* Loops around the steps from the current (if no step opened, from the first one)
* in order to open the next selectable unsaved step. Returns true if a step has been opened.
*/
progress: function() {
if (!this.stepNumber) {
return false;
}
if (this.completed) {
this.selected = null;
return true;
}
for (var i = (this._selectedIndex+1)%this.stepNumber; i != this._selectedIndex; i = (i+1)%this.stepNumber) {
if (this.items[i].selectable && !this.items[i].saved) {
this.selectIndex(i);
this.fire('paper-stepper-progressed');
return true;
}
}
return false;
},
/* Deselect and set the steps as unsaved*/
reset: function() {
this._setSavedStepNumber(0);
this.selected = null;
if (!this.items.length) {
return;
}
this.items.map(function(step) {
step._setSaved(false);
step._set_previousSaved(false);
});
this.items[0]._set_previousSaved(true);
},
get _isRTL() {
return window.getComputedStyle(this)['direction'] === 'rtl';
},
_onLeftKey: function(event) {
if (this._isRTL) {
this._focusNext();
} else {
this._focusPrevious();
}
event.detail.keyboardEvent.preventDefault();
},
_onRightKey: function(event) {
if (this._isRTL) {
this._focusPrevious();
} else {
this._focusNext();
}
event.detail.keyboardEvent.preventDefault();
},
/**
* Work around: Override the method from IronSelectableBehavior to only allow the selection of selectable step. https://github.com/PolymerElements/iron-selector/issues/99
*/
_selectSelected: function(selected) {
var item = this._valueToItem(this.selected);
if (item) {
var selectable = item.selectable;
if (selectable == undefined) {
// if selectable isn't define it means the step is not yet ready for selection
// and this method will be recalled by the initialization method.
return;
} else if (!selectable) {
//reset previous selected if non null and selectable or deselect
if (this._previousSelected && this._previousSelected.selectable) {
this.selected = this._valueForItem(this.previousSelected);
} else {
this.selected = null;
}
this._set_previousSelected(null);
return;
}
}
this._selection.select(item);
this._set_previousSelected(item);
this._set_selectedIndex(this.indexOf(item));
// Check for items, since this array is populated only when attached
// Since Number(0) is falsy, explicitly check for undefined
if (this.fallbackSelection && this.items.length && (this._selection.get() === undefined)) {
this.selected = this.fallbackSelection;
}
},
_updateStepperClosedMaxHeight: function() {
this.debounce('updateStepperClosedMaxHeight', function() {
this.customStyle['--label-wrapper-height'] = this.$$('#content-wrapper').clientHeight + 'px';
this.updateStyles('--label-wrapper-height');
});
},
_openedChanged: function(newValue, oldValue) {
if (!this.vertical && oldValue != undefined) {
this.toggleClass('collapsing', true);
}
},
_transitionEnd: function(e) {
// check to ignore event fired by paper-ripple
if (e.propertyName == 'max-height') {
this.toggleClass('collapsing', false);
}
},
_computeOpened: function(_selectedIndex) {
return _selectedIndex >= 0;
},
_stepSaved: function(e) {
var previousStep = this.items[this.indexOf(e.target)+1];
if (previousStep) {
previousStep._set_previousSaved(true);
}
this._setSavedStepNumber(this.savedStepNumber+1);
},
_forwardVertical: function(vertical) {
if (this.stepNumber) {
this.items.map(function(step) {
step._setVertical(vertical);
});
}
this.setAttribute('role', vertical ? 'menu': 'menubar');
},
_forwardStepperData: function(linear, backText, optionalText, finishText, continueText, skipText, updateText, hasSkipButton, hasBackButton) {
if (this.stepNumber) {
this.items.map(function(step) {
step._set_stepperData({
linear: linear,
backText: backText,
optionalText: optionalText,
finishText: finishText,
continueText: continueText,
skipText: skipText,
updateText: updateText,
hasSkipButton: hasSkipButton,
hasBackButton: hasBackButton,
stepNumber: this.stepNumber
});
}.bind(this));
}
},
_forwardAlternativeLabel: function(alternativeLabel) {
if (this.stepNumber) {
this.items.map(function(step) {
step._set_alternativeLabel(alternativeLabel);
});
}
},
_computeStepNumber: function(length) {
return length;
},
_selectedIndexChanged: function(newValue, oldValue) {
if (!this.vertical && newValue >=0 && oldValue >= 0) {
var oldStep = this.items[oldValue], newStep = this.items[newValue];
if (newStep.classList.contains('neon-animating')) {
this.cancelAnimation();
}
if (this._previousAnimatedStep && this._previousAnimatedStep.classList.contains('neon-animating')) {
this.cancelAnimation();
this.toggleClass('neon-animating', false, this._previousAnimatedStep);
}
var forward = newValue - oldValue > 0;
this.animationConfig = {
'new-step-entry': {
animatable: newStep,
type: forward ?
newStep.horizontalHigherEntryAnimation && 'higher-step-entry' :
newStep.horizontalLowerEntryAnimation && 'lower-step-entry'
},
'old-step-exit': {
animatable: oldStep,
type: forward ?
oldStep.horizontalLowerExitAnimation && 'lower-step-exit' :
oldStep.horizontalHigherExitAnimation && 'higher-step-exit'
}
};
if (this.animationConfig['new-step-entry'].type) {
this.playAnimation('new-step-entry', {step: newStep});
this.toggleClass('neon-animating', true, newStep);
}
if (this.animationConfig['old-step-exit'].type) {
this.playAnimation('old-step-exit', {step: oldStep});
this.toggleClass('neon-animating', true, oldStep);
}
this._set_previousAnimatedStep(oldStep);
}
},
_onNeonAnimationFinish: function(event) {
var step = event.detail.step;
if (step) {
this.toggleClass('neon-animating', false, step);
}
},
_forwardCanSkip: function(_canSkip, selectedItem) {
selectedItem._set_canSkip(_canSkip);
},
_forwardHasBackStep: function(_hasBackStep, selectedItem) {
selectedItem._set_hasBackStep(_hasBackStep);
},
_compute__attrForSelectedStepPrimaryButtonText: function(selectedIndex) {
/* TODO: compute from selectedItem when https://github.com/PolymerElements/iron-selector/issues/118 is fixed*/
if (selectedIndex < 0) {
return null;
}
var _attrForPrimaryButtonText = this.selectedItem.saved ? 'updateText' :
( (this.stepNumber - this.savedStepNumber) == 1 ? 'finishText' : 'continueText' );
this.selectedItem._set_attrForPrimaryButtonText(_attrForPrimaryButtonText);
return _attrForPrimaryButtonText;
},
_initializeSteps: function() {
var savedStepNumber = 0;
var data = {
linear: this.linear,
backText: this.backText,
optionalText: this.optionalText,
finishText: this.finishText,
continueText: this.continueText,
skipText: this.skipText,
updateText: this.updateText,
hasSkipButton: this.hasSkipButton,
hasBackButton: this.hasBackButton,
stepNumber: this.stepNumber
};
this.items.map(function(step, i) {
if (this.horizontalHigherEntryAnimation && !step.horizontalHigherEntryAnimation) {
step.horizontalHigherEntryAnimation = this.horizontalHigherEntryAnimation;
}
if (this.horizontalHigherExitAnimation && !step.horizontalHigherExitAnimation) {
step.horizontalHigherExitAnimation = this.horizontalHigherExitAnimation;
}
if (this.horizontalLowerEntryAnimation && !step.horizontalLowerEntryAnimation) {
step.horizontalLowerEntryAnimation = this.horizontalLowerEntryAnimation;
}
if (this.horizontalLowerExitAnimation && !step.horizontalLowerExitAnimation) {
step.horizontalLowerExitAnimation = this.horizontalLowerExitAnimation;
}
step._setIndex(i + 1);
step._set_stepper(this);
step._setVertical(this.vertical);
step._set_alternativeLabel(this.alternativeLabel);
step._set_stepperData(data);
// true for index 0
step._set_previousSaved(!i);
if (step.saved) {
savedStepNumber++;
}
}.bind(this));
this._setSavedStepNumber(savedStepNumber);
// method from IronSelectableBehavior
this._updateSelected();
},
_compute_skipStepIndex: function(_selectedIndex) {
if (_selectedIndex >= 0 && !this.completed) {
for (var i=(_selectedIndex+1)%this.stepNumber; i!=_selectedIndex; i=(i+1)%this.stepNumber) {
if (this.items[i].selectable && !this.items[i].saved) {
return i;
}
}
}
return null;
},
_compute_backStepIndex: function(_selectedIndex) {
if (_selectedIndex >= 0) {
for (var i=_selectedIndex - 1; i >= 0; i--) {
if (this.items[i].selectable) {
return i;
}
}
}
return null
},
_isntNull: function(n) {
return n != null;
},
_computeCompleted: function(savedStepNumber, stepNumber) {
var completed = stepNumber == savedStepNumber;
if (completed) {
this.fire('paper-stepper-completed');
return true;
}
return false;
},
_choosePrimaryButtonText: function(_attrForSelectedStepPrimaryButtonText) {
return this[_attrForSelectedStepPrimaryButtonText];
},
_resizeHandler: function() {
this.debounce('paper-stepper-responsive-check', function() {
this._responsiveCheck();
}, this.responsiveCheckFrequence);
},
_responsiveCheck: function() {
var verticalResponsiveWidth = this.$.verticalResponsiveWidth.clientWidth;
if (verticalResponsiveWidth) {
this.vertical = !(this.clientWidth > verticalResponsiveWidth);
}
}
});
</script>
</dom-module>

View File

@@ -0,0 +1,124 @@
<link rel="import" href="../../components/iron-flex-layout/iron-flex-layout.html">
<link rel="import" href="../../components/iron-icons/iron-icons.html">
<link rel="import" href="../../components/iron-icons/editor-icons.html">
<link rel="import" href="../../components/paper-styles/color.html">
<link rel="import" href="../../components/paper-styles/typography.html">
<link rel="import" href="../../components/paper-styles/default-theme.html">
<link rel="import" href="../../components/polymer/polymer.html">
<link rel="import" href="step-label-behavior.html">
<link rel="import" href="step-label-shared-styles.html">
<dom-module id="step-horizontal-label">
<template>
<style include="step-label-shared-styles">
:host{
overflow: hidden;
}
:host([alternative-label]) {
@apply(--layout);
}
#textWrapper {
@apply(--layout-vertical);
padding-right: 8px;
overflow: hidden;
}
#textLabel, #optional {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
#badge {
margin: 0 8px;
}
#badgeWrapper, #textWrapper {
pointer-events: none;
/* to be above paper-ripple*/
z-index: 1;
}
:host(:not([alternative-label])) #label {
@apply(--layout-horizontal);
@apply(--layout-center);
height: 72px;
}
:host(.firstStep:not([alternative-label])) #badge {
margin-left: 24px;
}
:host(.lastStep:not([alternative-label])) #textWrapper {
padding-right: 24px;
}
:host(:not([alternative-label]):not(.first-step)) #label::before,
:host(:not([alternative-label]):not(.last-step)) #label::after,
:host([alternative-label]) #badgeWrapper::before,
:host([alternative-label]) #badgeWrapper::after {
height: 1px;
min-width: 16px;
background: var(--paper-step-connector-line-color, --divider-color);
@apply(--layout-flex);
content: '';
}
:host([alternative-label].first-step) #badgeWrapper::before,
:host([alternative-label].last-step) #badgeWrapper::after {
visibility: hidden;
}
:host([alternative-label]) #textWrapper{
padding: 0 16px;
@apply(--layout-vertical);
@apply(--layout-center);
}
:host([alternative-label]) #textLabel, :host([alternative-label]) #optional{
text-align: center;
@apply(--layout-self-stretch);
}
:host([alternative-label]) #label{
@apply(--layout-vertical);
@apply(--layout-self-stretch);
padding: 24px 0;
width: 100%;
}
:host([alternative-label]) #badgeWrapper {
@apply(--layout-horizontal);
@apply(--layout-center);
padding-bottom: 16px;
}
:host(.first-step:not([alternative-label])) #label {
padding-left: 16px;
}
:host(.last-step:not([alternative-label])) #label {
padding-right: 16px;
}
</style>
<!-- use a "label" wrapper to use the same shared css rules with step-vertical -->
<div id="label">
<div id="badgeWrapper">
<div id="badge">
<iron-icon hidden$="{{!_computeIsIconBadge(icon)}}" icon="{{icon}}"></iron-icon>
<span hidden$="{{_computeIsIconBadge(icon)}}">{{index}}</span>
</div>
</div>
<div id="textWrapper">
<span id="textLabel">[[label]]</span>
<template is="dom-if" if="[[optional]]">
<span id="optional">[[stepperData.optionalText]]</span>
</template>
</div>
</div>
</template>
<script>
Polymer({
is: 'step-horizontal-label',
behaviors: [
Stepper.StepLabelBehavior
],
properties: {
alternativeLabel: {
type: Boolean,
value: false,
reflectToAttribute: true
}
},
});
</script>
</dom-module>

View File

@@ -0,0 +1,58 @@
<link rel="import" href="../../components/polymer/polymer.html">
<script>
window.Stepper = window.Stepper || {};
/*
* @polymerBehavior Stepper.StepLabelBehavior
*/
Stepper.StepLabelBehavior = {
properties: {
icon: {
type: String,
computed: '_computeIcon(saved, editable)'
},
opened: {
type: Boolean,
reflectToAttribute: true
},
selectable: {
type: Boolean,
reflectToAttribute: true
},
editable: {
type: Boolean,
reflectToAttribute: true,
},
label: {
type: String,
notify: true
},
optional: {
type: Boolean,
notify: true
},
saved: {
type: Boolean,
reflectToAttribute: true
},
index: {
type: Number
},
stepperData: {
type: Object
}
},
_computeIcon: function(saved, editable) {
return saved ? ( editable ? 'editor:mode-edit' : 'done' ) : '';
},
_computeIsIconBadge: function(icon) {
return icon.length > 0;
}
};
</script>

View File

@@ -0,0 +1,74 @@
<link rel="import" href="../../components/iron-flex-layout/iron-flex-layout.html">
<link rel="import" href="../../components/paper-styles/default-theme.html">
<link rel="import" href="../../components/paper-styles/color.html">
<link rel="import" href="../../components/paper-styles/typography.html">
<link rel="import" href="../../components/polymer/polymer.html">
<dom-module id="step-label-shared-styles">
<template>
<style>
:host {
display: block;
box-sizing: border-box;
@apply(--paper-font-common-base);
@apply(--layout-flex);
}
#textWrapper {
color: var(--paper-step-disabled-label-text-color, --paper-grey-400);
}
#textLabel {
font-size: var(--paper-step-label-text-font-size, 14px);
}
#optional{
font-size: var(--paper-step-label-optional-text-font-size, 12px);
}
:host([selectable]) #textWrapper {
color: var(--paper-step-selectable-label-text-color, --paper-grey-600);
}
:host([opened]) #textLabel {
color: var(--paper-step-opened-label-text-color, --light-theme-text-color);
font-weight: 500;
}
#label {
cursor: default;
pointer-events: none;
/* For paper-ripple */
position: relative;
}
:host([selectable]) #label {
cursor: pointer;
pointer-events: auto;
}
#label:hover {
/* using alpha chanel for .connectorLine to grow dark */
background: var(--paper-step-label-hover-background, rgba(0,0,0,0.04));
}
#badge {
width: 24px;
height: 24px;
background: var(--paper-step-badge-background, --paper-grey-300);
border-radius: 50%;
color: var(--paper-step-badge-color, --dark-theme-text-color);
font-size: 12px;
@apply(--layout);
@apply(--layout-center-center);
}
#badge iron-icon {
--iron-icon-height: var(--paper-step-badge-icon-width, 16px);
--iron-icon-width: var(--paper-step-badge-icon-height, 16px);
}
:host([opened]) #badge {
background: var(--paper-step-opened-badge-background, --primary-color);
}
:host([saved]) #badge {
background: var(--paper-step-saved-badge-background, --primary-color);
}
:host([selectable]:not([opened]):not([saved])) #label:hover #badge {
background: var(--paper-step-selectable-hovered-badge-background, --paper-grey-500);
}
paper-ripple {
color: var(--paper-step-ink-color, --paper-grey-400);
}
</style>
</template>
</dom-module>

View File

@@ -0,0 +1,177 @@
<link rel="import" href="../../components/iron-flex-layout/iron-flex-layout.html">
<link rel="import" href="../../components/paper-button/paper-button.html">
<link rel="import" href="../../components/paper-styles/color.html">
<link rel="import" href="../../components/paper-styles/default-theme.html">
<link rel="import" href="../../components/paper-styles/typography.html">
<link rel="import" href="../../components/polymer/polymer.html">
<link rel="import" href="../../components/iron-icons/iron-icons.html">
<link rel="import" href="../../components/iron-icon/iron-icon.html">
<link rel="import" href="../../components/iron-icons/editor-icons.html">
<link rel="import" href="../../components/iron-collapse/iron-collapse.html">
<link rel="import" href="step-label-behavior.html">
<link rel="import" href="step-label-shared-styles.html">
<dom-module id="step-vertical">
<template>
<style include="step-label-shared-styles">
:host {
@apply(--layout-vertical);
}
#connectedBadge, #textWrapper {
pointer-events: none;
/* to be above paper-ripple*/
z-index: 1;
}
#collapse {
--iron-collapse-transition-duration: var(--paper-vertical-step-transition-duration, 500ms);
@apply(--layout-horizontal);
}
/**
* Content
*/
#connectedStep {
@apply(--layout-horizontal);
}
#contentConnectorLine {
width: 1px;
background: var(--divider-color, --paper-grey-300);
margin-left: 36px;
margin-right: 24px;
}
#stepWrapper {
@apply(--layout-flex);
/*should be 48px on large screen?*/
padding-right: 24px;
}
#paperStepWrapper {
max-height: calc(var(--paper-vertical-step-max-height, 400px) - 92px);
@apply(--layout-scroll);
}
/**
* Buttons
*/
#buttonsWrapper {
height: 48px;
@apply(--layout-horizontal);
@apply(--layout-center);
@apply(--layout-flex-none);
}
#buttonsWrapper > paper-button {
margin-right: 8px;
margin-left: 0;
}
#continueButton {
--paper-button: {
background: var(--paper-vertical-step-continue-button-background, --primary-color);
color: var(--paper-vertical-step-continue-button-color, --dark-theme-text-color);
};
}
/**
* Label
*/
#textWrapper {
@apply(--layout-vertical);
padding: 8px 0 8px 8px;
}
#label {
@apply(--layout-horizontal);
}
#connectedBadge {
@apply(--layout-vertical);
@apply(--layout-center);
margin-left: 24px;
}
#beforeConnectorLine, #afterConnectorLine {
width: 1px;
background: var(--paper-step-connector-line-color, --divider-color);
}
#beforeConnectorLine {
height: 10px;
}
#afterConnectorLine {
@apply(--layout-flex);
}
#badge {
margin: 8px 0;
}
:host(.first-step) #beforeConnectorLine, :host(.lastStep) #contentConnectorLine{
visibility: hidden;
}
:host(.last-step:not([opened])) #afterConnectorLine {
display: none;
}
</style>
<div id="label">
<div id="connectedBadge">
<div id="beforeConnectorLine"></div>
<div id="badge">
<iron-icon hidden$="{{!_computeIsIconBadge(icon)}}" icon="{{icon}}"></iron-icon>
<span hidden$="{{_computeIsIconBadge(icon)}}">{{index}}</span>
</div>
<div id="afterConnectorLine" class="connectorLine"></div>
</div>
<div id="textWrapper">
<span id="textLabel">[[label]]</span>
<template is="dom-if" if="[[optional]]">
<span id="optional">[[stepperData.optionalText]]</span>
</template>
</div>
</div>
<iron-collapse id="collapse" opened="[[opened]]">
<div id="contentConnectorLine"></div>
<div id="stepWrapper">
<div id="paperStepWrapper">
<content></content>
</div>
<div id="buttonsWrapper">
<paper-button id="continueButton" on-tap="continue">{{choosePrimaryButtonText(_attrForPrimaryButtonText, stepperData.continueText, stepperData.finishText, stepperData.updateText)}}</paper-button>
<paper-button id="backButton" disabled="[[!hasBackStep]]" on-tap="back" hidden$="[[!stepperData.hasBackButton]]">
[[stepperData.backText]]
</paper-button>
<paper-button id="skipButton" disabled="[[!canSkip]]" on-tap="skip" hidden$="[[!stepperData.hasSkipButton]]">
[[stepperData.skipText]]
</paper-button>
</div>
</div>
</iron-collapse>
</template>
<script>
Polymer({
is: 'step-vertical',
properties: {
canSkip: {
type: Boolean
},
_attrForPrimaryButtonText: {
type: String,
value: false
},
hasBackStep: Boolean
},
behaviors: [
Stepper.StepLabelBehavior
],
skip: function() {
this.fire('paper-step-vertical-skip-tapped');
},
back: function() {
this.fire('paper-step-vertical-back-tapped');
},
continue: function() {
this.fire('paper-step-vertical-continue-tapped');
},
choosePrimaryButtonText: function(_attrForPrimaryButtonText) {
return this.stepperData[_attrForPrimaryButtonText];
}
});
</script>
</dom-module>