js: use ES6 classes for polymer 2.x

This commit is contained in:
Marcin Lulek 2018-10-30 15:24:48 +01:00
parent 69b8d6a77f
commit d75cc12c5c
9 changed files with 226 additions and 138 deletions

View file

@ -6,5 +6,5 @@
}
}]
],
"plugins": ["transform-object-rest-spread"]
"plugins": ["transform-object-rest-spread"]
}

View file

@ -16,7 +16,7 @@
"main": {
"expand": true,
"cwd": "bower_components",
"src": "webcomponentsjs/webcomponents*.*",
"src": "webcomponentsjs/*.*",
"dest": "<%= dirs.js.dest %>/vendors"
}
},

View file

@ -17,9 +17,14 @@
var ccLog = Logger.get('RhodeCodeApp');
ccLog.setLevel(Logger.OFF);
var rhodeCodeApp = Polymer({
is: 'rhodecode-app',
attached: function () {
class RhodecodeApp extends Polymer.Element {
static get is() {
return 'rhodecode-app';
}
connectedCallback() {
super.connectedCallback();
ccLog.debug('rhodeCodeApp created');
$.Topic('/notifications').subscribe(this.handleNotifications.bind(this));
$.Topic('/favicon/update').subscribe(this.faviconUpdate.bind(this));
@ -37,46 +42,47 @@
$(document).ready(function () {
this.kickoffChannelstreamPlugin();
}.bind(this));
},
}
initPlugins: function(){
initPlugins() {
for (var i = 0; i < window.APPLICATION_PLUGINS.length; i++) {
var pluginDef = window.APPLICATION_PLUGINS[i];
if (pluginDef.component){
if (pluginDef.component) {
var pluginElem = document.createElement(pluginDef.component);
this.shadowRoot.appendChild(pluginElem);
if (typeof pluginElem.init !== 'undefined'){
if (typeof pluginElem.init !== 'undefined') {
pluginElem.init();
}
}
}
},
/** proxy to channelstream connection */
getChannelStreamConnection: function () {
return this.$['channelstream-connection'];
},
}
handleNotifications: function (data) {
/** proxy to channelstream connection */
getChannelStreamConnection() {
return this.$['channelstream-connection'];
}
handleNotifications(data) {
var elem = document.getElementById('notifications');
if(elem){
if (elem) {
elem.handleNotification(data);
}
},
}
faviconUpdate: function (data) {
faviconUpdate(data) {
this.shadowRoot.querySelector('rhodecode-favicon').counter = data.count;
},
}
/** opens connection to ws server */
kickoffChannelstreamPlugin: function (data) {
kickoffChannelstreamPlugin(data) {
ccLog.debug('kickoffChannelstreamPlugin');
var channels = ['broadcast'];
var addChannels = this.checkViewChannels();
for (var i = 0; i < addChannels.length; i++) {
channels.push(addChannels[i]);
}
if (window.CHANNELSTREAM_SETTINGS && CHANNELSTREAM_SETTINGS.enabled){
if (window.CHANNELSTREAM_SETTINGS && CHANNELSTREAM_SETTINGS.enabled) {
var channelstreamConnection = this.getChannelStreamConnection();
channelstreamConnection.connectUrl = CHANNELSTREAM_URLS.connect;
channelstreamConnection.subscribeUrl = CHANNELSTREAM_URLS.subscribe;
@ -90,9 +96,9 @@
$.Topic('/connection_controller/subscribe').processPrepared();
channelstreamConnection.connect();
}
},
}
checkViewChannels: function () {
checkViewChannels() {
// subscribe to different channels data is sent.
var channels = [];
@ -110,10 +116,10 @@
}
return channels;
},
}
/** subscribes users from channels in channelstream */
subscribeToChannelTopic: function (channels) {
subscribeToChannelTopic(channels) {
var channelstreamConnection = this.getChannelStreamConnection();
var toSubscribe = channelstreamConnection.calculateSubscribe(channels);
ccLog.debug('subscribeToChannelTopic', toSubscribe);
@ -129,34 +135,35 @@
}
}
}
},
}
/** publish received messages into correct topic */
receivedMessage: function (event) {
receivedMessage(event) {
for (var i = 0; i < event.detail.length; i++) {
var message = event.detail[i];
if (message.message.topic) {
ccLog.debug('publishing', message.message.topic);
$.Topic(message.message.topic).publish(message);
}
else if (message.type === 'presence'){
else if (message.type === 'presence') {
$.Topic('/connection_controller/presence').publish(message);
}
else {
ccLog.warn('unhandled message', message);
}
}
},
}
handleConnected: function (event) {
handleConnected(event) {
var channelstreamConnection = this.getChannelStreamConnection();
channelstreamConnection.set('channelsState',
event.detail.channels_info);
channelstreamConnection.set('userState', event.detail.state);
channelstreamConnection.set('channels', event.detail.channels);
this.propagageChannelsState();
},
handleSubscribed: function (event) {
}
handleSubscribed(event) {
var channelstreamConnection = this.getChannelStreamConnection();
var channelInfo = event.detail.channels_info;
var channelKeys = Object.keys(event.detail.channels_info);
@ -166,9 +173,10 @@
}
channelstreamConnection.set('channels', event.detail.channels);
this.propagageChannelsState();
},
}
/** propagates channel states on topics */
propagageChannelsState: function (event) {
propagageChannelsState(event) {
var channelstreamConnection = this.getChannelStreamConnection();
var channel_data = channelstreamConnection.channelsState;
var channels = channelstreamConnection.channels;
@ -179,7 +187,9 @@
);
}
}
});
}
customElements.define(RhodecodeApp.is, RhodecodeApp);
</script>
</dom-module>

View file

@ -4,26 +4,35 @@
<template>
</template>
<script>
Polymer({
is: 'rhodecode-favicon',
properties: {
favicon: Object,
counter: {
type: Number,
observer: '_handleCounter'
}
},
class RhodecodeFavicon extends Polymer.Element {
ready: function () {
static get is() { return 'rhodecode-favicon'; }
static get properties() {
return {
favicon: Object,
counter: {
type: Number,
observer: '_handleCounter'
}
}
}
connectedCallback() {
super.connectedCallback();
this.favicon = new Favico({
type: 'rectangle',
animation: 'none'
});
},
_handleCounter: function (newVal, oldVal) {
}
_handleCounter(newVal, oldVal) {
this.favicon.badge(this.counter);
}
});
}
customElements.define(RhodecodeFavicon.is, RhodecodeFavicon);
</script>
</dom-module>

View file

@ -1,5 +1,6 @@
<link rel="import" href="../../../../../../bower_components/paper-button/paper-button.html">
<link rel="import" href="../../../../../../bower_components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
<link rel="import"
href="../../../../../../bower_components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
<link rel="import" href="../rhodecode-unsafe-html/rhodecode-unsafe-html.html">
<dom-module id="rhodecode-toast">
<template>
@ -19,57 +20,69 @@
bottom: 0;
right: 0;
}
.top-left-rounded-corner {
-webkit-border-top-left-radius: 2px;
-khtml-border-radius-topleft: 2px;
border-top-left-radius: 2px;
}
.top-right-rounded-corner {
-webkit-border-top-right-radius: 2px;
-khtml-border-radius-topright: 2px;
border-top-right-radius: 2px;
}
.bottom-left-rounded-corner {
-webkit-border-bottom-left-radius: 2px;
-khtml-border-radius-bottomleft: 2px;
border-bottom-left-radius: 2px;
}
.bottom-right-rounded-corner {
-webkit-border-bottom-right-radius: 2px;
-khtml-border-radius-bottomright: 2px;
border-bottom-right-radius: 2px;
}
.top-left-rounded-corner-mid {
-webkit-border-top-left-radius: 2px;
-khtml-border-radius-topleft: 2px;
border-top-left-radius: 2px;
}
.top-right-rounded-corner-mid {
-webkit-border-top-right-radius: 2px;
-khtml-border-radius-topright: 2px;
border-top-right-radius: 2px;
}
.bottom-left-rounded-corner-mid {
-webkit-border-bottom-left-radius: 2px;
-khtml-border-radius-bottomleft: 2px;
border-bottom-left-radius: 2px;
}
.bottom-right-rounded-corner-mid {
-webkit-border-bottom-right-radius: 2px;
-khtml-border-radius-bottomright: 2px;
border-bottom-right-radius: 2px;
}
.alert {
margin: 10px 0;
}
.toast-close {
margin: 0;
float: right;
cursor: pointer;
}
.toast-message-holder {
background: rgba(255, 255, 255, 0.25);
}
.toast-message-holder.fixed {
position: fixed;
padding: 10px 0;
@ -86,7 +99,7 @@
<div class$="container toast-message-holder [[conditionalClass(isFixed)]]">
<template is="dom-repeat" items="[[toasts]]">
<div class$="alert alert-[[item.level]]">
<div on-tap="dismissNotification" class="toast-close" index-pos="[[index]]">
<div on-click="dismissNotification" class="toast-close" index-pos="[[index]]">
<span>[[_gettext('Close')]]</span>
</div>
<rhodecode-unsafe-html text="[[item.message]]"></rhodecode-unsafe-html>
@ -97,104 +110,124 @@
</template>
<script>
Polymer({
is: 'rhodecode-toast',
properties: {
toasts: {
type: Array,
value: function(){
return []
}
},
isFixed: {
type: Boolean,
value: false
},
hasToasts: {
type: Boolean,
computed: '_computeHasToasts(toasts.*)'
},
keyEventTarget: {
type: Object,
value: function() {
return document.body;
class RhodecodeToast extends Polymer.mixinBehaviors([Polymer.IronA11yKeysBehavior], Polymer.Element) {
static get is() {
return 'rhodecode-toast';
}
static get properties() {
return {
toasts: {
type: Array,
value() {
return []
}
},
isFixed: {
type: Boolean,
value: false
},
hasToasts: {
type: Boolean,
computed: '_computeHasToasts(toasts.*)'
},
keyEventTarget: {
type: Object,
value() {
return document.body;
}
}
}
},
behaviors: [
Polymer.IronA11yKeysBehavior
],
observers: [
'_changedToasts(toasts.splices)'
],
}
keyBindings: {
'esc:keyup': '_hideOnEsc'
},
get keyBindings() {
return {
'esc:keyup': '_hideOnEsc'
}
}
_hideOnEsc: function (event) {
static get observers() {
return [
'_changedToasts(toasts.splices)'
]
}
_hideOnEsc(event) {
return this.dismissNotifications();
},
}
_computeHasToasts: function(){
_computeHasToasts() {
return this.toasts.length > 0;
},
}
_debouncedCalc: function(){
_debouncedCalc() {
// calculate once in a while
this.debounce('debouncedCalc', this.toastInWindow, 25);
},
}
conditionalClass: function(){
return this.isFixed ? 'fixed': '';
},
conditionalClass() {
return this.isFixed ? 'fixed' : '';
}
toastInWindow: function() {
if (!this._headerNode){
toastInWindow() {
if (!this._headerNode) {
return true
}
var headerHeight = this._headerNode.offsetHeight;
var scrollPosition = window.scrollY;
if (this.isFixed){
if (this.isFixed) {
this.isFixed = 1 <= scrollPosition;
}
else{
else {
this.isFixed = headerHeight <= scrollPosition;
}
},
}
attached: function(){
connectedCallback() {
super.connectedCallback();
this._headerNode = document.querySelector('.header', document);
this.listen(window,'scroll', '_debouncedCalc');
this.listen(window,'resize', '_debouncedCalc');
this.listen(window, 'scroll', '_debouncedCalc');
this.listen(window, 'resize', '_debouncedCalc');
this._debouncedCalc();
},
_changedToasts: function(newValue, oldValue){
}
_changedToasts(newValue, oldValue) {
$.Topic('/favicon/update').publish({count: this.toasts.length});
},
dismissNotification: function(e) {
$.Topic('/favicon/update').publish({count: this.toasts.length-1});
}
dismissNotification(e) {
$.Topic('/favicon/update').publish({count: this.toasts.length - 1});
var idx = e.target.parentNode.indexPos
this.splice('toasts', idx, 1);
},
dismissNotifications: function(){
}
dismissNotifications() {
$.Topic('/favicon/update').publish({count: 0});
this.splice('toasts', 0);
},
handleNotification: function(data){
}
handleNotification(data) {
if (!templateContext.rhodecode_user.notification_status && !data.message.force) {
// do not act if notifications are disabled
return
}
this.push('toasts',{
this.push('toasts', {
level: data.message.level,
message: data.message.message
});
},
_gettext: _gettext
});
}
_gettext(x){
return _gettext(x)
}
}
customElements.define(RhodecodeToast.is, RhodecodeToast);
</script>
</dom-module>

View file

@ -1,4 +1,5 @@
<link rel="import" href="../../../../../../bower_components/paper-toggle-button/paper-toggle-button.html">
<link rel="import"
href="../../../../../../bower_components/paper-toggle-button/paper-toggle-button.html">
<link rel="import" href="../../../../../../bower_components/paper-spinner/paper-spinner.html">
<link rel="import" href="../../../../../../bower_components/paper-tooltip/paper-tooltip.html">
@ -9,6 +10,7 @@
float: left;
position: relative;
}
.rc-toggle paper-spinner {
position: absolute;
top: 0;
@ -29,20 +31,31 @@
</template>
<script>
Polymer({
is: 'rhodecode-toggle',
properties: {
noSpinner: { type: Boolean, value: false, reflectToAttribute:true},
tooltipText: { type: String, value: "Click to toggle", reflectToAttribute:true},
checked: { type: Boolean, value: false, reflectToAttribute:true},
active: { type: Boolean, value: false, reflectToAttribute:true, notify:true}
},
shouldShow: function(){
return !this.noSpinner
},
labelStatus: function(isActive){
return this.checked? 'Enabled' : "Disabled"
class RhodecodeToggle extends Polymer.Element {
static get is() {
return 'rhodecode-toggle';
}
});
static get properties() {
return {
noSpinner: {type: Boolean, value: false, reflectToAttribute: true},
tooltipText: {type: String, value: "Click to toggle", reflectToAttribute: true},
checked: {type: Boolean, value: false, reflectToAttribute: true},
active: {type: Boolean, value: false, reflectToAttribute: true, notify: true}
}
}
shouldShow() {
return !this.noSpinner
}
labelStatus(isActive) {
return this.checked ? 'Enabled' : "Disabled"
}
}
customElements.define(RhodecodeToggle.is, RhodecodeToggle);
</script>
</dom-module>

View file

@ -1,4 +1,4 @@
<link rel="import" href="../../../../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../../../../../bower_components/polymer/polymer-element.html">
<dom-module id="rhodecode-unsafe-html">
<template>
@ -6,18 +6,26 @@
<slot></slot>
</template>
<script>
Polymer({
is: 'rhodecode-unsafe-html',
properties: {
text: {
type: String,
observer: '_handleText'
class RhodecodeUnsafeHtml extends Polymer.Element {
static get is() {
return 'rhodecode-unsafe-html';
}
static get properties() {
return {
text: {
type: String,
observer: '_handleText'
}
}
},
_handleText: function(newVal, oldVal){
}
_handleText(newVal, oldVal) {
this.innerHTML = this.text;
}
})
}
customElements.define(RhodecodeUnsafeHtml.is, RhodecodeUnsafeHtml);
</script>
</dom-module>

View file

@ -27,6 +27,8 @@ c.template_context['default_user'] = {
%>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="${h.asset('js/vendors/webcomponentsjs/custom-elements-es5-adapter.js', ver=c.rhodecode_version_hash)}"></script>
<script src="${h.asset('js/vendors/webcomponentsjs/webcomponents-lite.js', ver=c.rhodecode_version_hash)}"></script>
<title>${self.title()}</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />

View file

@ -10,6 +10,18 @@ if (process.env.RC_STATIC_DIR) {
destinationDirectory = process.env.RC_STATIC_DIR;
}
// doing it this way because it seems that plugin via grunt does not pick up .babelrc
let babelRCOptions = {
"presets": [
["env", {
"targets": {
"browsers": ["last 2 versions"]
}
}]
],
"plugins": ["transform-object-rest-spread"]
}
module.exports = {
// Tell Webpack which file kicks off our app.
entry: {
@ -42,7 +54,8 @@ module.exports = {
// polymer-webpack-loader, and hand the output to
// babel-loader. This let's us transpile JS in our `<script>` elements.
use: [
{loader: 'babel-loader'},
{loader: 'babel-loader',
options: babelRCOptions},
{loader: 'polymer-webpack-loader',
options: {
processStyleLinks: true,
@ -53,7 +66,7 @@ module.exports = {
{
// If you see a file that ends in .js, just send it to the babel-loader.
test: /\.js$/,
use: 'babel-loader'
use: {loader: 'babel-loader', options: babelRCOptions}
// Optionally exclude node_modules from transpilation except for polymer-webpack-loader:
// exclude: /node_modules\/(?!polymer-webpack-loader\/).*/
},