Struktura programu z widokami i repozytorium

This commit is contained in:
Jan Modrzejewski 2023-01-27 21:24:56 +01:00
commit d42be59ec6
66 changed files with 21420 additions and 0 deletions

34
.gitignore vendored Normal file
View File

@ -0,0 +1,34 @@
node_modules
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/

BIN
.mvn/wrapper/maven-wrapper.jar vendored Normal file

Binary file not shown.

2
.mvn/wrapper/maven-wrapper.properties vendored Normal file
View File

@ -0,0 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar

View File

@ -0,0 +1,32 @@
/******************************************************************************
* This file is auto-generated by Vaadin.
* If you want to customize the entry point, you can copy this file or create
* your own `index.ts` in your frontend directory.
* By default, the `index.ts` file should be in `./frontend/` folder.
*
* NOTE:
* - You need to restart the dev-server after adding the new `index.ts` file.
* After that, all modifications to `index.ts` are recompiled automatically.
* - `index.js` is also supported if you don't want to use TypeScript.
******************************************************************************/
// import Vaadin client-router to handle client-side and server-side navigation
import { Router } from '@vaadin/router';
// import Flow module to enable navigation to Vaadin server-side views
import { Flow } from 'Frontend/generated/jar-resources/Flow.js';
const { serverSideRoutes } = new Flow({
imports: () => import('../../target/frontend/generated-flow-imports.js')
});
const routes = [
// for client-side, place routes below (more info https://vaadin.com/docs/v15/flow/typescript/creating-routes.html)
// for server-side, the next magic line sends all unmatched routes:
...serverSideRoutes // IMPORTANT: this must be the last entry in the array
];
// Vaadin router needs an outlet in the index.html page to display views
const router = new Router(document.querySelector('#outlet'));
router.setRoutes(routes);

View File

@ -0,0 +1,74 @@
export interface FlowConfig {
imports?: () => void;
}
interface AppConfig {
productionMode: boolean;
appId: string;
uidl: any;
clientRouting: boolean;
}
interface AppInitResponse {
appConfig: AppConfig;
pushScript?: string;
}
interface Router {
render: (ctx: NavigationParameters, shouldUpdateHistory: boolean) => Promise<void>;
}
interface HTMLRouterContainer extends HTMLElement {
onBeforeEnter?: (ctx: NavigationParameters, cmd: PreventAndRedirectCommands, router: Router) => void | Promise<any>;
onBeforeLeave?: (ctx: NavigationParameters, cmd: PreventCommands, router: Router) => void | Promise<any>;
serverConnected?: (cancel: boolean, url?: NavigationParameters) => void;
}
interface FlowRoute {
action: (params: NavigationParameters) => Promise<HTMLRouterContainer>;
path: string;
}
export interface NavigationParameters {
pathname: string;
search: string;
}
export interface PreventCommands {
prevent: () => any;
}
export interface PreventAndRedirectCommands extends PreventCommands {
redirect: (route: string) => any;
}
/**
* Client API for flow UI operations.
*/
export declare class Flow {
config: FlowConfig;
response?: AppInitResponse;
pathname: string;
container: HTMLRouterContainer;
private isActive;
private baseRegex;
private appShellTitle;
constructor(config?: FlowConfig);
/**
* Return a `route` object for vaadin-router in an one-element array.
*
* The `FlowRoute` object `path` property handles any route,
* and the `action` returns the flow container without updating the content,
* delaying the actual Flow server call to the `onBeforeEnter` phase.
*
* This is a specific API for its use with `vaadin-router`.
*/
get serverSideRoutes(): [FlowRoute];
loadingStarted(): void;
loadingFinished(): void;
private get action();
private flowLeave;
private flowNavigate;
private getFlowRoutePath;
private getFlowRouteQuery;
private flowInit;
private loadScript;
private injectAppIdScript;
private flowInitClient;
private flowInitUi;
private addConnectionIndicator;
private offlineStubAction;
private isFlowClientLoaded;
}
export {};

View File

@ -0,0 +1,324 @@
import { ConnectionIndicator, ConnectionState } from '@vaadin/common-frontend';
class FlowUiInitializationError extends Error {
}
// flow uses body for keeping references
const flowRoot = window.document.body;
const $wnd = window;
/**
* Client API for flow UI operations.
*/
export class Flow {
constructor(config) {
this.response = undefined;
this.pathname = '';
// flag used to inform Testbench whether a server route is in progress
this.isActive = false;
this.baseRegex = /^\//;
flowRoot.$ = flowRoot.$ || [];
this.config = config || {};
// TB checks for the existence of window.Vaadin.Flow in order
// to consider that TB needs to wait for `initFlow()`.
$wnd.Vaadin = $wnd.Vaadin || {};
$wnd.Vaadin.Flow = $wnd.Vaadin.Flow || {};
$wnd.Vaadin.Flow.clients = {
TypeScript: {
isActive: () => this.isActive
}
};
// Regular expression used to remove the app-context
const elm = document.head.querySelector('base');
this.baseRegex = new RegExp(`^${
// IE11 does not support document.baseURI
(document.baseURI || (elm && elm.href) || '/').replace(/^https?:\/\/[^/]+/i, '')}`);
this.appShellTitle = document.title;
// Put a vaadin-connection-indicator in the dom
this.addConnectionIndicator();
}
/**
* Return a `route` object for vaadin-router in an one-element array.
*
* The `FlowRoute` object `path` property handles any route,
* and the `action` returns the flow container without updating the content,
* delaying the actual Flow server call to the `onBeforeEnter` phase.
*
* This is a specific API for its use with `vaadin-router`.
*/
get serverSideRoutes() {
return [
{
path: '(.*)',
action: this.action
}
];
}
loadingStarted() {
// Make Testbench know that server request is in progress
this.isActive = true;
$wnd.Vaadin.connectionState.loadingStarted();
}
loadingFinished() {
// Make Testbench know that server request has finished
this.isActive = false;
$wnd.Vaadin.connectionState.loadingFinished();
}
get action() {
// Return a function which is bound to the flow instance, thus we can use
// the syntax `...serverSideRoutes` in vaadin-router.
return async (params) => {
// Store last action pathname so as we can check it in events
this.pathname = params.pathname;
if ($wnd.Vaadin.connectionState.online) {
try {
await this.flowInit();
}
catch (error) {
if (error instanceof FlowUiInitializationError) {
// error initializing Flow: assume connection lost
$wnd.Vaadin.connectionState.state = ConnectionState.CONNECTION_LOST;
return this.offlineStubAction();
}
else {
throw error;
}
}
}
else {
// insert an offline stub
return this.offlineStubAction();
}
// When an action happens, navigation will be resolved `onBeforeEnter`
this.container.onBeforeEnter = (ctx, cmd) => this.flowNavigate(ctx, cmd);
// For covering the 'server -> client' use case
this.container.onBeforeLeave = (ctx, cmd) => this.flowLeave(ctx, cmd);
return this.container;
};
}
// Send a remote call to `JavaScriptBootstrapUI` to check
// whether navigation has to be cancelled.
async flowLeave(ctx, cmd) {
// server -> server, viewing offline stub, or browser is offline
const { connectionState } = $wnd.Vaadin;
if (this.pathname === ctx.pathname || !this.isFlowClientLoaded() || connectionState.offline) {
return Promise.resolve({});
}
// 'server -> client'
return new Promise((resolve) => {
this.loadingStarted();
// The callback to run from server side to cancel navigation
this.container.serverConnected = (cancel) => {
resolve(cmd && cancel ? cmd.prevent() : {});
this.loadingFinished();
};
// Call server side to check whether we can leave the view
flowRoot.$server.leaveNavigation(this.getFlowRoutePath(ctx), this.getFlowRouteQuery(ctx));
});
}
// Send the remote call to `JavaScriptBootstrapUI` to render the flow
// route specified by the context
async flowNavigate(ctx, cmd) {
if (this.response) {
return new Promise((resolve) => {
this.loadingStarted();
// The callback to run from server side once the view is ready
this.container.serverConnected = (cancel, redirectContext) => {
if (cmd && cancel) {
resolve(cmd.prevent());
}
else if (cmd && cmd.redirect && redirectContext) {
resolve(cmd.redirect(redirectContext.pathname));
}
else {
this.container.style.display = '';
resolve(this.container);
}
this.loadingFinished();
};
// Call server side to navigate to the given route
flowRoot.$server.connectClient(this.container.localName, this.container.id, this.getFlowRoutePath(ctx), this.getFlowRouteQuery(ctx), this.appShellTitle, history.state);
});
}
else {
// No server response => offline or erroneous connection
return Promise.resolve(this.container);
}
}
getFlowRoutePath(context) {
return decodeURIComponent(context.pathname).replace(this.baseRegex, '');
}
getFlowRouteQuery(context) {
return (context.search && context.search.substring(1)) || '';
}
// import flow client modules and initialize UI in server side.
async flowInit(serverSideRouting = false) {
// Do not start flow twice
if (!this.isFlowClientLoaded()) {
// show flow progress indicator
this.loadingStarted();
// Initialize server side UI
this.response = await this.flowInitUi(serverSideRouting);
// Enable or disable server side routing
this.response.appConfig.clientRouting = !serverSideRouting;
const { pushScript, appConfig } = this.response;
if (typeof pushScript === 'string') {
await this.loadScript(pushScript);
}
const { appId } = appConfig;
// Load bootstrap script with server side parameters
const bootstrapMod = await import('./FlowBootstrap');
await bootstrapMod.init(this.response);
// Load custom modules defined by user
if (typeof this.config.imports === 'function') {
this.injectAppIdScript(appId);
await this.config.imports();
}
// Load flow-client module
const clientMod = await import('./FlowClient');
await this.flowInitClient(clientMod);
if (!serverSideRouting) {
// we use a custom tag for the flow app container
const tag = `flow-container-${appId.toLowerCase()}`;
this.container = document.createElement(tag);
flowRoot.$[appId] = this.container;
this.container.id = appId;
}
// hide flow progress indicator
this.loadingFinished();
}
// It might be that components created from server expect that their content has been rendered.
// Appending eagerly the container we avoid these kind of errors.
// Note that the client router will move this container to the outlet if the navigation succeed
if (this.container && !this.container.isConnected) {
this.container.style.display = 'none';
document.body.appendChild(this.container);
}
return this.response;
}
async loadScript(url) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.onload = () => resolve();
script.onerror = reject;
script.src = url;
document.body.appendChild(script);
});
}
injectAppIdScript(appId) {
const appIdWithoutHashCode = appId.substring(0, appId.lastIndexOf('-'));
const scriptAppId = document.createElement('script');
scriptAppId.type = 'module';
scriptAppId.setAttribute('data-app-id', appIdWithoutHashCode);
document.body.append(scriptAppId);
}
// After the flow-client javascript module has been loaded, this initializes flow UI
// in the browser.
async flowInitClient(clientMod) {
clientMod.init();
// client init is async, we need to loop until initialized
return new Promise((resolve) => {
const intervalId = setInterval(() => {
// client `isActive() == true` while initializing or processing
const initializing = Object.keys($wnd.Vaadin.Flow.clients)
.filter((key) => key !== 'TypeScript')
.reduce((prev, id) => prev || $wnd.Vaadin.Flow.clients[id].isActive(), false);
if (!initializing) {
clearInterval(intervalId);
resolve();
}
}, 5);
});
}
// Returns the `appConfig` object
async flowInitUi(serverSideRouting) {
// appConfig was sent in the index.html request
const initial = $wnd.Vaadin && $wnd.Vaadin.TypeScript && $wnd.Vaadin.TypeScript.initial;
if (initial) {
$wnd.Vaadin.TypeScript.initial = undefined;
return Promise.resolve(initial);
}
// send a request to the `JavaScriptBootstrapHandler`
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
const httpRequest = xhr;
const serverRoutingParam = serverSideRouting ? '&serverSideRouting' : '';
const requestPath = `?v-r=init&location=${encodeURIComponent(this.getFlowRoutePath(location))}&query=${encodeURIComponent(this.getFlowRouteQuery(location))}${serverRoutingParam}`;
httpRequest.open('GET', requestPath);
httpRequest.onerror = () => reject(new FlowUiInitializationError(`Invalid server response when initializing Flow UI.
${httpRequest.status}
${httpRequest.responseText}`));
httpRequest.onload = () => {
const contentType = httpRequest.getResponseHeader('content-type');
if (contentType && contentType.indexOf('application/json') !== -1) {
resolve(JSON.parse(httpRequest.responseText));
}
else {
httpRequest.onerror();
}
};
httpRequest.send();
});
}
// Create shared connection state store and connection indicator
addConnectionIndicator() {
// add connection indicator to DOM
ConnectionIndicator.create();
// Listen to browser online/offline events and update the loading indicator accordingly.
// Note: if flow-client is loaded, it instead handles the state transitions.
$wnd.addEventListener('online', () => {
if (!this.isFlowClientLoaded()) {
// Send an HTTP HEAD request for sw.js to verify server reachability.
// We do not expect sw.js to be cached, so the request goes to the
// server rather than being served from local cache.
// Require network-level failure to revert the state to CONNECTION_LOST
// (HTTP error code is ok since it still verifies server's presence).
$wnd.Vaadin.connectionState.state = ConnectionState.RECONNECTING;
const http = new XMLHttpRequest();
http.open('HEAD', 'sw.js');
http.onload = () => {
$wnd.Vaadin.connectionState.state = ConnectionState.CONNECTED;
};
http.onerror = () => {
$wnd.Vaadin.connectionState.state = ConnectionState.CONNECTION_LOST;
};
// Postpone request to reduce potential net::ERR_INTERNET_DISCONNECTED
// errors that sometimes occurs even if browser says it is online
setTimeout(() => http.send(), 50);
}
});
$wnd.addEventListener('offline', () => {
if (!this.isFlowClientLoaded()) {
$wnd.Vaadin.connectionState.state = ConnectionState.CONNECTION_LOST;
}
});
}
async offlineStubAction() {
const offlineStub = document.createElement('iframe');
const offlineStubPath = './offline-stub.html';
offlineStub.setAttribute('src', offlineStubPath);
offlineStub.setAttribute('style', 'width: 100%; height: 100%; border: 0');
this.response = undefined;
let onlineListener;
const removeOfflineStubAndOnlineListener = () => {
if (onlineListener !== undefined) {
$wnd.Vaadin.connectionState.removeStateChangeListener(onlineListener);
onlineListener = undefined;
}
};
offlineStub.onBeforeEnter = (ctx, _cmds, router) => {
onlineListener = () => {
if ($wnd.Vaadin.connectionState.online) {
removeOfflineStubAndOnlineListener();
router.render(ctx, false);
}
};
$wnd.Vaadin.connectionState.addStateChangeListener(onlineListener);
};
offlineStub.onBeforeLeave = (_ctx, _cmds, _router) => {
removeOfflineStubAndOnlineListener();
};
return offlineStub;
}
isFlowClientLoaded() {
return this.response !== undefined;
}
}
//# sourceMappingURL=Flow.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
export const init: (appInitResponse: any) => void;

View File

@ -0,0 +1,262 @@
/* This is a copy of the regular `BootstrapHandler.js` in the flow-server
module, but with the following modifications:
- The main function is exported as an ES module for lazy initialization.
- Application configuration is passed as a parameter instead of using
replacement placeholders as in the regular bootstrapping.
- It reuses `Vaadin.Flow.clients` if exists.
- Fixed lint errors.
*/
const init = function (appInitResponse) {
window.Vaadin = window.Vaadin || {};
window.Vaadin.Flow = window.Vaadin.Flow || {};
var apps = {};
var widgetsets = {};
var log;
if (typeof window.console === undefined || !window.location.search.match(/[&?]debug(&|$)/)) {
/* If no console.log present, just use a no-op */
log = function () {};
} else if (typeof window.console.log === 'function') {
/* If it's a function, use it with apply */
log = function () {
window.console.log.apply(window.console, arguments);
};
} else {
/* In IE, its a native function for which apply is not defined, but it works
without a proper 'this' reference */
log = window.console.log;
}
var isInitializedInDom = function (appId) {
var appDiv = document.getElementById(appId);
if (!appDiv) {
return false;
}
for (var i = 0; i < appDiv.childElementCount; i++) {
var className = appDiv.childNodes[i].className;
/* If the app div contains a child with the class
'v-app-loading' we have only received the HTML
but not yet started the widget set
(UIConnector removes the v-app-loading div). */
if (className && className.indexOf('v-app-loading') != -1) {
return false;
}
}
return true;
};
/*
* Needed for Testbench compatibility, but prevents any Vaadin 7 app from
* bootstrapping unless the legacy vaadinBootstrap.js file is loaded before
* this script.
*/
window.Vaadin = window.Vaadin || {};
window.Vaadin.Flow = window.Vaadin.Flow || {};
/*
* Needed for wrapping custom javascript functionality in the components (i.e. connectors)
*/
window.Vaadin.Flow.tryCatchWrapper = function (originalFunction, component) {
return function () {
try {
// eslint-disable-next-line
const result = originalFunction.apply(this, arguments);
return result;
} catch (error) {
console.error(
`There seems to be an error in ${component}:
${error.message}
Please submit an issue to https://github.com/vaadin/flow-components/issues/new/choose`
);
}
};
};
if (!window.Vaadin.Flow.initApplication) {
window.Vaadin.Flow.clients = window.Vaadin.Flow.clients || {};
window.Vaadin.Flow.initApplication = function (appId, config) {
var testbenchId = appId.replace(/-\d+$/, '');
if (apps[appId]) {
if (
window.Vaadin &&
window.Vaadin.Flow &&
window.Vaadin.Flow.clients &&
window.Vaadin.Flow.clients[testbenchId] &&
window.Vaadin.Flow.clients[testbenchId].initializing
) {
throw new Error('Application ' + appId + ' is already being initialized');
}
if (isInitializedInDom(appId)) {
throw new Error('Application ' + appId + ' already initialized');
}
}
log('init application', appId, config);
window.Vaadin.Flow.clients[testbenchId] = {
isActive: function () {
return true;
},
initializing: true,
productionMode: mode
};
var getConfig = function (name) {
var value = config[name];
return value;
};
/* Export public data */
var app = {
getConfig: getConfig
};
apps[appId] = app;
if (!window.name) {
window.name = appId + '-' + Math.random();
}
var widgetset = 'client';
widgetsets[widgetset] = {
pendingApps: []
};
if (widgetsets[widgetset].callback) {
log('Starting from bootstrap', appId);
widgetsets[widgetset].callback(appId);
} else {
log('Setting pending startup', appId);
widgetsets[widgetset].pendingApps.push(appId);
}
return app;
};
window.Vaadin.Flow.getAppIds = function () {
var ids = [];
for (var id in apps) {
if (Object.prototype.hasOwnProperty.call(apps, id)) {
ids.push(id);
}
}
return ids;
};
window.Vaadin.Flow.getApp = function (appId) {
return apps[appId];
};
window.Vaadin.Flow.registerWidgetset = function (widgetset, callback) {
log('Widgetset registered', widgetset);
var ws = widgetsets[widgetset];
if (ws && ws.pendingApps) {
ws.callback = callback;
for (var i = 0; i < ws.pendingApps.length; i++) {
var appId = ws.pendingApps[i];
log('Starting from register widgetset', appId);
callback(appId);
}
ws.pendingApps = null;
}
};
window.Vaadin.Flow.getBrowserDetailsParameters = function () {
var params = {};
/* Screen height and width */
params['v-sh'] = window.screen.height;
params['v-sw'] = window.screen.width;
/* Browser window dimensions */
params['v-wh'] = window.innerHeight;
params['v-ww'] = window.innerWidth;
/* Body element dimensions */
params['v-bh'] = document.body.clientHeight;
params['v-bw'] = document.body.clientWidth;
/* Current time */
var date = new Date();
params['v-curdate'] = date.getTime();
/* Current timezone offset (including DST shift) */
var tzo1 = date.getTimezoneOffset();
/* Compare the current tz offset with the first offset from the end
of the year that differs --- if less that, we are in DST, otherwise
we are in normal time */
var dstDiff = 0;
var rawTzo = tzo1;
for (var m = 12; m > 0; m--) {
date.setUTCMonth(m);
var tzo2 = date.getTimezoneOffset();
if (tzo1 != tzo2) {
dstDiff = tzo1 > tzo2 ? tzo1 - tzo2 : tzo2 - tzo1;
rawTzo = tzo1 > tzo2 ? tzo1 : tzo2;
break;
}
}
/* Time zone offset */
params['v-tzo'] = tzo1;
/* DST difference */
params['v-dstd'] = dstDiff;
/* Time zone offset without DST */
params['v-rtzo'] = rawTzo;
/* DST in effect? */
params['v-dston'] = tzo1 != rawTzo;
/* Time zone id (if available) */
try {
params['v-tzid'] = Intl.DateTimeFormat().resolvedOptions().timeZone;
} catch (err) {
params['v-tzid'] = '';
}
/* Window name */
if (window.name) {
params['v-wn'] = window.name;
}
/* Detect touch device support */
var supportsTouch = false;
try {
document.createEvent('TouchEvent');
supportsTouch = true;
} catch (e) {
/* Chrome and IE10 touch detection */
supportsTouch = 'ontouchstart' in window || typeof navigator.msMaxTouchPoints !== 'undefined';
}
params['v-td'] = supportsTouch;
/* Device Pixel Ratio */
params['v-pr'] = window.devicePixelRatio;
if (navigator.platform) {
params['v-np'] = navigator.platform;
}
/* Stringify each value (they are parsed on the server side) */
Object.keys(params).forEach(function (key) {
var value = params[key];
if (typeof value !== 'undefined') {
params[key] = value.toString();
}
});
return params;
};
}
log('Flow bootstrap loaded');
if (appInitResponse.appConfig.productionMode && typeof window.__gwtStatsEvent != 'function') {
window.Vaadin.Flow.gwtStatsEvents = [];
window.__gwtStatsEvent = function (event) {
window.Vaadin.Flow.gwtStatsEvents.push(event);
return true;
};
}
var config = appInitResponse.appConfig;
var mode = appInitResponse.appConfig.productionMode;
window.Vaadin.Flow.initApplication(config.appId, config);
};
export { init };

View File

@ -0,0 +1 @@
export const init: () => void;

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,14 @@
export interface Product {
name: string;
version: string;
}
export interface ProductAndMessage {
message: string;
messageHtml?: string;
product: Product;
}
export declare const findAll: (element: Element | ShadowRoot | Document, tags: string[]) => Element[];
export declare const licenseCheckOk: (data: Product) => void;
export declare const licenseCheckFailed: (data: ProductAndMessage) => void;
export declare const licenseCheckNoKey: (data: ProductAndMessage) => void;
export declare const licenseInit: () => void;

View File

@ -0,0 +1,110 @@
const noLicenseFallbackTimeout = 1000;
export const findAll = (element, tags) => {
const lightDom = Array.from(element.querySelectorAll(tags.join(', ')));
const shadowDom = Array.from(element.querySelectorAll('*'))
.filter((e) => e.shadowRoot)
.flatMap((e) => findAll(e.shadowRoot, tags));
return [...lightDom, ...shadowDom];
};
let licenseCheckListener = false;
const showNoLicenseFallback = (element, productAndMessage) => {
if (!licenseCheckListener) {
// When a license check has succeeded, refresh so that all elements are properly shown again
window.addEventListener('message', (e) => {
if (e.data === 'validate-license') {
window.location.reload();
}
}, false);
licenseCheckListener = true;
}
const overlay = element._overlayElement;
if (overlay) {
if (overlay.shadowRoot) {
const defaultSlot = overlay.shadowRoot.querySelector('slot:not([name])');
if (defaultSlot && defaultSlot.assignedElements().length > 0) {
showNoLicenseFallback(defaultSlot.assignedElements()[0], productAndMessage);
return;
}
}
showNoLicenseFallback(overlay, productAndMessage);
return;
}
const htmlMessage = productAndMessage.messageHtml
? productAndMessage.messageHtml
: `${productAndMessage.message} <p>Component: ${productAndMessage.product.name} ${productAndMessage.product.version}</p>`.replace(/https:([^ ]*)/g, "<a href='https:$1'>https:$1</a>");
if (element.isConnected) {
element.outerHTML = `<no-license style="display:flex;align-items:center;text-align:center;justify-content:center;"><div>${htmlMessage}</div></no-license>`;
}
};
const productTagNames = {};
const productChecking = {};
const productMissingLicense = {};
const productCheckOk = {};
const key = (product) => {
return `${product.name}_${product.version}`;
};
const checkLicenseIfNeeded = (cvdlElement) => {
var _a;
const { cvdlName, version } = cvdlElement.constructor;
const product = { name: cvdlName, version };
const tagName = cvdlElement.tagName.toLowerCase();
productTagNames[cvdlName] = (_a = productTagNames[cvdlName]) !== null && _a !== void 0 ? _a : [];
productTagNames[cvdlName].push(tagName);
const failedLicenseCheck = productMissingLicense[key(product)];
if (failedLicenseCheck) {
// Has been checked and the check failed
setTimeout(() => showNoLicenseFallback(cvdlElement, failedLicenseCheck), noLicenseFallbackTimeout);
}
if (productMissingLicense[key(product)] || productCheckOk[key(product)]) {
// Already checked
}
else if (!productChecking[key(product)]) {
// Has not been checked
productChecking[key(product)] = true;
window.Vaadin.devTools.checkLicense(product);
}
};
export const licenseCheckOk = (data) => {
productCheckOk[key(data)] = true;
// eslint-disable-next-line no-console
console.debug('License check ok for', data);
};
export const licenseCheckFailed = (data) => {
const productName = data.product.name;
productMissingLicense[key(data.product)] = data;
// eslint-disable-next-line no-console
console.error('License check failed for', productName);
const tags = productTagNames[productName];
if ((tags === null || tags === void 0 ? void 0 : tags.length) > 0) {
findAll(document, tags).forEach((element) => {
setTimeout(() => showNoLicenseFallback(element, productMissingLicense[key(data.product)]), noLicenseFallbackTimeout);
});
}
};
export const licenseCheckNoKey = (data) => {
const keyUrl = data.message;
const productName = data.product.name;
data.messageHtml = `No license found. <a target=_blank onclick="javascript:window.open(this.href);return false;" href="${keyUrl}">Go here to start a trial or retrieve your license.</a>`;
productMissingLicense[key(data.product)] = data;
// eslint-disable-next-line no-console
console.error('No license found when checking', productName);
const tags = productTagNames[productName];
if ((tags === null || tags === void 0 ? void 0 : tags.length) > 0) {
findAll(document, tags).forEach((element) => {
setTimeout(() => showNoLicenseFallback(element, productMissingLicense[key(data.product)]), noLicenseFallbackTimeout);
});
}
};
export const licenseInit = () => {
// Process already registered elements
window.Vaadin.devTools.createdCvdlElements.forEach((element) => {
checkLicenseIfNeeded(element);
});
// Handle new elements directly
window.Vaadin.devTools.createdCvdlElements = {
push: (element) => {
checkLicenseIfNeeded(element);
}
};
};
//# sourceMappingURL=License.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,284 @@
import { Debouncer } from '@polymer/polymer/lib/utils/debounce.js';
import { timeOut } from '@polymer/polymer/lib/utils/async.js';
import { ComboBoxPlaceholder } from '@vaadin/combo-box/src/vaadin-combo-box-placeholder.js';
(function () {
const tryCatchWrapper = function (callback) {
return window.Vaadin.Flow.tryCatchWrapper(callback, 'Vaadin Combo Box');
};
window.Vaadin.Flow.comboBoxConnector = {
initLazy: (comboBox) =>
tryCatchWrapper(function (comboBox) {
// Check whether the connector was already initialized for the ComboBox
if (comboBox.$connector) {
return;
}
comboBox.$connector = {};
// holds pageIndex -> callback pairs of subsequent indexes (current active range)
const pageCallbacks = {};
let cache = {};
let lastFilter = '';
const placeHolder = new window.Vaadin.ComboBoxPlaceholder();
const serverFacade = (() => {
// Private variables
let lastFilterSentToServer = '';
let dataCommunicatorResetNeeded = false;
// Public methods
const needsDataCommunicatorReset = () => (dataCommunicatorResetNeeded = true);
const getLastFilterSentToServer = () => lastFilterSentToServer;
const requestData = (startIndex, endIndex, params) => {
const count = endIndex - startIndex;
const filter = params.filter;
comboBox.$server.setRequestedRange(startIndex, count, filter);
lastFilterSentToServer = filter;
if (dataCommunicatorResetNeeded) {
comboBox.$server.resetDataCommunicator();
dataCommunicatorResetNeeded = false;
}
};
return {
needsDataCommunicatorReset,
getLastFilterSentToServer,
requestData
};
})();
const clearPageCallbacks = (pages = Object.keys(pageCallbacks)) => {
// Flush and empty the existing requests
pages.forEach((page) => {
pageCallbacks[page]([], comboBox.size);
delete pageCallbacks[page];
// Empty the comboBox's internal cache without invoking observers by filling
// the filteredItems array with placeholders (comboBox will request for data when it
// encounters a placeholder)
const pageStart = parseInt(page) * comboBox.pageSize;
const pageEnd = pageStart + comboBox.pageSize;
const end = Math.min(pageEnd, comboBox.filteredItems.length);
for (let i = pageStart; i < end; i++) {
comboBox.filteredItems[i] = placeHolder;
}
});
};
comboBox.dataProvider = function (params, callback) {
if (params.pageSize != comboBox.pageSize) {
throw 'Invalid pageSize';
}
if (comboBox._clientSideFilter) {
// For clientside filter we first make sure we have all data which we also
// filter based on comboBox.filter. While later we only filter clientside data.
if (cache[0]) {
performClientSideFilter(cache[0], params.filter, callback);
return;
} else {
// If client side filter is enabled then we need to first ask all data
// and filter it on client side, otherwise next time when user will
// input another filter, eg. continue to type, the local cache will be only
// what was received for the first filter, which may not be the whole
// data from server (keep in mind that client side filter is enabled only
// when the items count does not exceed one page).
params.filter = '';
}
}
const filterChanged = params.filter !== lastFilter;
if (filterChanged) {
cache = {};
lastFilter = params.filter;
this._filterDebouncer = Debouncer.debounce(this._filterDebouncer, timeOut.after(500), () => {
if (serverFacade.getLastFilterSentToServer() === params.filter) {
// Fixes the case when the filter changes
// to something else and back to the original value
// within debounce timeout, and the
// DataCommunicator thinks it doesn't need to send data
serverFacade.needsDataCommunicatorReset();
}
if (params.filter !== lastFilter) {
throw new Error("Expected params.filter to be '" + lastFilter + "' but was '" + params.filter + "'");
}
// Remove the debouncer before clearing page callbacks.
// This makes sure that they are executed.
this._filterDebouncer = undefined;
// Call the method again after debounce.
clearPageCallbacks();
comboBox.dataProvider(params, callback);
});
return;
}
// Postpone the execution of new callbacks if there is an active debouncer.
// They will be executed when the page callbacks are cleared within the debouncer.
if (this._filterDebouncer) {
pageCallbacks[params.page] = callback;
return;
}
if (cache[params.page]) {
// This may happen after skipping pages by scrolling fast
commitPage(params.page, callback);
} else {
pageCallbacks[params.page] = callback;
const maxRangeCount = Math.max(params.pageSize * 2, 500); // Max item count in active range
const activePages = Object.keys(pageCallbacks).map((page) => parseInt(page));
const rangeMin = Math.min(...activePages);
const rangeMax = Math.max(...activePages);
if (activePages.length * params.pageSize > maxRangeCount) {
if (params.page === rangeMin) {
clearPageCallbacks([String(rangeMax)]);
} else {
clearPageCallbacks([String(rangeMin)]);
}
comboBox.dataProvider(params, callback);
} else if (rangeMax - rangeMin + 1 !== activePages.length) {
// Wasn't a sequential page index, clear the cache so combo-box will request for new pages
clearPageCallbacks();
} else {
// The requested page was sequential, extend the requested range
const startIndex = params.pageSize * rangeMin;
const endIndex = params.pageSize * (rangeMax + 1);
serverFacade.requestData(startIndex, endIndex, params);
}
}
};
comboBox.$connector.clear = tryCatchWrapper((start, length) => {
const firstPageToClear = Math.floor(start / comboBox.pageSize);
const numberOfPagesToClear = Math.ceil(length / comboBox.pageSize);
for (let i = firstPageToClear; i < firstPageToClear + numberOfPagesToClear; i++) {
delete cache[i];
}
});
comboBox.$connector.filter = tryCatchWrapper(function (item, filter) {
filter = filter ? filter.toString().toLowerCase() : '';
return comboBox._getItemLabel(item, comboBox.itemLabelPath).toString().toLowerCase().indexOf(filter) > -1;
});
comboBox.$connector.set = tryCatchWrapper(function (index, items, filter) {
if (filter != serverFacade.getLastFilterSentToServer()) {
return;
}
if (index % comboBox.pageSize != 0) {
throw 'Got new data to index ' + index + ' which is not aligned with the page size of ' + comboBox.pageSize;
}
if (index === 0 && items.length === 0 && pageCallbacks[0]) {
// Makes sure that the dataProvider callback is called even when server
// returns empty data set (no items match the filter).
cache[0] = [];
return;
}
const firstPageToSet = index / comboBox.pageSize;
const updatedPageCount = Math.ceil(items.length / comboBox.pageSize);
for (let i = 0; i < updatedPageCount; i++) {
let page = firstPageToSet + i;
let slice = items.slice(i * comboBox.pageSize, (i + 1) * comboBox.pageSize);
cache[page] = slice;
}
});
comboBox.$connector.updateData = tryCatchWrapper(function (items) {
const itemsMap = new Map(items.map((item) => [item.key, item]));
comboBox.filteredItems = comboBox.filteredItems.map((item) => {
return itemsMap.get(item.key) || item;
});
});
comboBox.$connector.updateSize = tryCatchWrapper(function (newSize) {
if (!comboBox._clientSideFilter) {
// FIXME: It may be that this size set is unnecessary, since when
// providing data to combobox via callback we may use data's size.
// However, if this size reflect the whole data size, including
// data not fetched yet into client side, and combobox expect it
// to be set as such, the at least, we don't need it in case the
// filter is clientSide only, since it'll increase the height of
// the popup at only at first user filter to this size, while the
// filtered items count are less.
comboBox.size = newSize;
}
});
comboBox.$connector.reset = tryCatchWrapper(function () {
clearPageCallbacks();
cache = {};
comboBox.clearCache();
});
comboBox.$connector.confirm = tryCatchWrapper(function (id, filter) {
if (filter != serverFacade.getLastFilterSentToServer()) {
return;
}
// We're done applying changes from this batch, resolve pending
// callbacks
let activePages = Object.getOwnPropertyNames(pageCallbacks);
for (let i = 0; i < activePages.length; i++) {
let page = activePages[i];
if (cache[page]) {
commitPage(page, pageCallbacks[page]);
}
}
// Let server know we're done
comboBox.$server.confirmUpdate(id);
});
const commitPage = tryCatchWrapper(function (page, callback) {
let data = cache[page];
if (comboBox._clientSideFilter) {
performClientSideFilter(data, comboBox.filter, callback);
} else {
// Remove the data if server-side filtering, but keep it for client-side
// filtering
delete cache[page];
// FIXME: It may be that we ought to provide data.length instead of
// comboBox.size and remove updateSize function.
callback(data, comboBox.size);
}
});
// Perform filter on client side (here) using the items from specified page
// and submitting the filtered items to specified callback.
// The filter used is the one from combobox, not the lastFilter stored since
// that may not reflect user's input.
const performClientSideFilter = tryCatchWrapper(function (page, filter, callback) {
let filteredItems = page;
if (filter) {
filteredItems = page.filter((item) => comboBox.$connector.filter(item, filter));
}
callback(filteredItems, filteredItems.length);
});
// Prevent setting the custom value as the 'value'-prop automatically
comboBox.addEventListener(
'custom-value-set',
tryCatchWrapper((e) => e.preventDefault())
);
})(comboBox)
};
})();
window.Vaadin.ComboBoxPlaceholder = ComboBoxPlaceholder;

View File

@ -0,0 +1,40 @@
(function () {
function copyClassName(dialog) {
const overlay = dialog._overlayElement;
if (overlay) {
overlay.className = dialog.className;
}
}
const observer = new MutationObserver((records) => {
records.forEach((mutation) => {
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
copyClassName(mutation.target);
}
});
});
window.Vaadin.Flow.confirmDialogConnector = {
initLazy: function (dialog) {
if (dialog.$connector) {
return;
}
dialog.$connector = {};
dialog.addEventListener('opened-changed', (e) => {
if (e.detail.value) {
copyClassName(dialog);
}
});
observer.observe(dialog, {
attributes: true,
attributeFilter: ['class']
});
// Copy initial class
copyClassName(dialog);
}
};
})();

View File

@ -0,0 +1,117 @@
(function () {
function tryCatchWrapper(callback) {
return window.Vaadin.Flow.tryCatchWrapper(callback, 'Vaadin Context Menu');
}
function getContainer(appId, nodeId) {
try {
return window.Vaadin.Flow.clients[appId].getByNodeId(nodeId);
} catch (error) {
console.error('Could not get node %s from app %s', nodeId, appId);
console.error(error);
}
}
/**
* Initializes the connector for a context menu element.
*
* @param {HTMLElement} contextMenu
* @param {string} appId
*/
function initLazy(contextMenu, appId) {
if (contextMenu.$connector) {
return;
}
contextMenu.$connector = {
/**
* Generates and assigns the items to the context menu.
*
* @param {number} nodeId
*/
generateItems: tryCatchWrapper((nodeId) => {
const items = generateItemsTree(appId, nodeId);
contextMenu.items = items;
})
};
}
/**
* Generates an items tree compatible with the context-menu web component
* by traversing the given Flow DOM tree of context menu item nodes
* whose root node is identified by the `nodeId` argument.
*
* The app id is required to access the store of Flow DOM nodes.
*
* @param {string} appId
* @param {number} nodeId
*/
function generateItemsTree(appId, nodeId) {
const container = getContainer(appId, nodeId);
if (!container) {
return;
}
return Array.from(container.children).map((child) => {
const item = {
component: child,
checked: child._checked,
theme: child.__theme
};
if (child.localName == 'vaadin-context-menu-item' && child._containerNodeId) {
item.children = generateItemsTree(appId, child._containerNodeId);
}
child._item = item;
return item;
});
}
/**
* Sets the checked state for a context menu item.
*
* This method is supposed to be called when the context menu item is closed,
* so there is no need for triggering a re-render eagarly.
*
* @param {HTMLElement} component
* @param {boolean} checked
*/
function setChecked(component, checked) {
if (component._item) {
component._item.checked = checked;
}
}
/**
* Sets the theme for a context menu item.
*
* This method is supposed to be called when the context menu item is closed,
* so there is no need for triggering a re-render eagarly.
*
* @param {HTMLElement} component
* @param {string | undefined | null} theme
*/
function setTheme(component, theme) {
if (component._item) {
component._item.theme = theme;
}
}
window.Vaadin.Flow.contextMenuConnector = {
initLazy(...args) {
return tryCatchWrapper(initLazy)(...args);
},
generateItemsTree(...args) {
return tryCatchWrapper(generateItemsTree)(...args);
},
setChecked(...args) {
return tryCatchWrapper(setChecked)(...args);
},
setTheme(...args) {
return tryCatchWrapper(setTheme)(...args);
}
};
})();

View File

@ -0,0 +1,70 @@
import * as Gestures from '@vaadin/component-base/src/gestures.js';
(function () {
function tryCatchWrapper(callback) {
return window.Vaadin.Flow.tryCatchWrapper(callback, 'Vaadin Context Menu Target');
}
function init(target) {
if (target.$contextMenuTargetConnector) {
return;
}
target.$contextMenuTargetConnector = {
openOnHandler: tryCatchWrapper(function (e) {
e.preventDefault();
e.stopPropagation();
this.$contextMenuTargetConnector.openEvent = e;
let detail = {};
if (target.getContextMenuBeforeOpenDetail) {
detail = target.getContextMenuBeforeOpenDetail(e);
}
target.dispatchEvent(
new CustomEvent('vaadin-context-menu-before-open', {
detail: detail
})
);
}),
updateOpenOn: tryCatchWrapper(function (eventType) {
this.removeListener();
this.openOnEventType = eventType;
customElements.whenDefined('vaadin-context-menu').then(
tryCatchWrapper(() => {
if (Gestures.gestures[eventType]) {
Gestures.addListener(target, eventType, this.openOnHandler);
} else {
target.addEventListener(eventType, this.openOnHandler);
}
})
);
}),
removeListener: tryCatchWrapper(function () {
if (this.openOnEventType) {
if (Gestures.gestures[this.openOnEventType]) {
Gestures.removeListener(target, this.openOnEventType, this.openOnHandler);
} else {
target.removeEventListener(this.openOnEventType, this.openOnHandler);
}
}
}),
openMenu: tryCatchWrapper(function (contextMenu) {
contextMenu.open(this.openEvent);
}),
removeConnector: tryCatchWrapper(function () {
this.removeListener();
target.$contextMenuTargetConnector = undefined;
})
};
}
window.Vaadin.Flow.contextMenuTargetConnector = {
init(...args) {
return tryCatchWrapper(init)(...args);
}
};
})();

View File

@ -0,0 +1,150 @@
"use strict";
var deselectCurrent = function () {
var selection = document.getSelection();
if (!selection.rangeCount) {
return function () {};
}
var active = document.activeElement;
var ranges = [];
for (var i = 0; i < selection.rangeCount; i++) {
ranges.push(selection.getRangeAt(i));
}
switch (active.tagName.toUpperCase()) { // .toUpperCase handles XHTML
case 'INPUT':
case 'TEXTAREA':
active.blur();
break;
default:
active = null;
break;
}
selection.removeAllRanges();
return function () {
selection.type === 'Caret' &&
selection.removeAllRanges();
if (!selection.rangeCount) {
ranges.forEach(function(range) {
selection.addRange(range);
});
}
active &&
active.focus();
};
};
var clipboardToIE11Formatting = {
"text/plain": "Text",
"text/html": "Url",
"default": "Text"
}
var defaultMessage = "Copy to clipboard: #{key}, Enter";
function format(message) {
var copyKey = (/mac os x/i.test(navigator.userAgent) ? "⌘" : "Ctrl") + "+C";
return message.replace(/#{\s*key\s*}/g, copyKey);
}
export function copy(text, options) {
var debug,
message,
reselectPrevious,
range,
selection,
mark,
success = false;
if (!options) {
options = {};
}
debug = options.debug || false;
try {
reselectPrevious = deselectCurrent();
range = document.createRange();
selection = document.getSelection();
mark = document.createElement("span");
mark.textContent = text;
// reset user styles for span element
mark.style.all = "unset";
// prevents scrolling to the end of the page
mark.style.position = "fixed";
mark.style.top = 0;
mark.style.clip = "rect(0, 0, 0, 0)";
// used to preserve spaces and line breaks
mark.style.whiteSpace = "pre";
// do not inherit user-select (it may be `none`)
mark.style.webkitUserSelect = "text";
mark.style.MozUserSelect = "text";
mark.style.msUserSelect = "text";
mark.style.userSelect = "text";
mark.addEventListener("copy", function(e) {
e.stopPropagation();
if (options.format) {
e.preventDefault();
if (typeof e.clipboardData === "undefined") { // IE 11
debug && console.warn("unable to use e.clipboardData");
debug && console.warn("trying IE specific stuff");
window.clipboardData.clearData();
var format = clipboardToIE11Formatting[options.format] || clipboardToIE11Formatting["default"]
window.clipboardData.setData(format, text);
} else { // all other browsers
e.clipboardData.clearData();
e.clipboardData.setData(options.format, text);
}
}
if (options.onCopy) {
e.preventDefault();
options.onCopy(e.clipboardData);
}
});
document.body.appendChild(mark);
range.selectNodeContents(mark);
selection.addRange(range);
var successful = document.execCommand("copy");
if (!successful) {
throw new Error("copy command was unsuccessful");
}
success = true;
} catch (err) {
debug && console.error("unable to copy using execCommand: ", err);
debug && console.warn("trying IE specific stuff");
try {
window.clipboardData.setData(options.format || "text", text);
options.onCopy && options.onCopy(window.clipboardData);
success = true;
} catch (err) {
debug && console.error("unable to copy using clipboardData: ", err);
debug && console.error("falling back to prompt");
message = format("message" in options ? options.message : defaultMessage);
window.prompt(message, text);
}
} finally {
if (selection) {
if (typeof selection.removeRange == "function") {
selection.removeRange(range);
} else {
selection.removeAllRanges();
}
}
if (mark) {
document.body.removeChild(mark);
}
reselectPrevious();
}
return success;
}

View File

@ -0,0 +1,159 @@
import dateFnsFormat from 'date-fns/format';
import dateFnsParse from 'date-fns/parse';
import dateFnsIsValid from 'date-fns/isValid';
import { extractDateParts, parseDate as _parseDate } from '@vaadin/date-picker/src/vaadin-date-picker-helper.js';
(function () {
const tryCatchWrapper = function (callback) {
return window.Vaadin.Flow.tryCatchWrapper(callback, 'Vaadin Date Picker');
};
window.Vaadin.Flow.datepickerConnector = {
initLazy: (datepicker) =>
tryCatchWrapper(function (datepicker) {
// Check whether the connector was already initialized for the datepicker
if (datepicker.$connector) {
return;
}
datepicker.$connector = {};
const createLocaleBasedDateFormat = function (locale) {
try {
// Check whether the locale is supported or not
new Date().toLocaleDateString(locale);
} catch (e) {
console.warn('The locale is not supported, using default locale setting(en-US).');
return 'M/d/yyyy';
}
// format test date and convert to date-fns pattern
const testDate = new Date(Date.UTC(1234, 4, 6));
let pattern = testDate.toLocaleDateString(locale, { timeZone: 'UTC' });
pattern = pattern
// escape date-fns pattern letters by enclosing them in single quotes
.replace(/([a-zA-Z]+)/g, "'$1'")
// insert date placeholder
.replace('06', 'dd')
.replace('6', 'd')
// insert month placeholder
.replace('05', 'MM')
.replace('5', 'M')
// insert year placeholder
.replace('1234', 'yyyy');
const isValidPattern = pattern.includes('d') && pattern.includes('M') && pattern.includes('y');
if (!isValidPattern) {
console.warn('The locale is not supported, using default locale setting(en-US).');
return 'M/d/yyyy';
}
return pattern;
};
const createFormatterAndParser = tryCatchWrapper(function (formats) {
if (!formats || formats.length === 0) {
throw new Error('Array of custom date formats is null or empty');
}
function getShortYearFormat(format) {
if (format.includes('yyyy') && !format.includes('yyyyy')) {
return format.replace('yyyy', 'yy');
}
if (format.includes('YYYY') && !format.includes('YYYYY')) {
return format.replace('YYYY', 'YY');
}
return undefined;
}
function isShortYearFormat(format) {
if (format.includes('y')) {
return !format.includes('yyy');
}
if (format.includes('Y')) {
return !format.includes('YYY');
}
return false;
}
function formatDate(dateParts) {
const format = formats[0];
const date = _parseDate(`${dateParts.year}-${dateParts.month + 1}-${dateParts.day}`);
return dateFnsFormat(date, format);
}
function parseDate(dateString) {
const referenceDate = _getReferenceDate();
for (let format of formats) {
// We first try to match the date with the shorter version.
const shortYearFormat = getShortYearFormat(format);
if (shortYearFormat) {
const shortYearFormatDate = dateFnsParse(dateString, shortYearFormat, referenceDate);
if (dateFnsIsValid(shortYearFormatDate)) {
let yearValue = shortYearFormatDate.getFullYear();
// The last parsed year check handles the case where a four-digit year is parsed, then formatted
// as a two-digit year, and then parsed again. In this case we want to keep the century of the
// originally parsed year, instead of using the century of the reference date.
if (
datepicker.$connector._lastParsedYear &&
yearValue === datepicker.$connector._lastParsedYear % 100
) {
yearValue = datepicker.$connector._lastParsedYear;
}
return {
day: shortYearFormatDate.getDate(),
month: shortYearFormatDate.getMonth(),
year: yearValue
};
}
}
const date = dateFnsParse(dateString, format, referenceDate);
if (dateFnsIsValid(date)) {
let yearValue = date.getFullYear();
if (
datepicker.$connector._lastParsedYear &&
yearValue % 100 === datepicker.$connector._lastParsedYear % 100 &&
isShortYearFormat(format)
) {
yearValue = datepicker.$connector._lastParsedYear;
} else {
datepicker.$connector._lastParsedYear = yearValue;
}
return {
day: date.getDate(),
month: date.getMonth(),
year: yearValue
};
}
}
datepicker.$connector._lastParsedYear = undefined;
return false;
}
return {
formatDate: formatDate,
parseDate: parseDate
};
});
function _getReferenceDate() {
const { referenceDate } = datepicker.i18n;
return referenceDate ? new Date(referenceDate.year, referenceDate.month - 1, referenceDate.day) : new Date();
}
datepicker.$connector.updateI18n = tryCatchWrapper(function (locale, i18n) {
// Either use custom formats specified in I18N, or create format from locale
const hasCustomFormats = i18n && i18n.dateFormats && i18n.dateFormats.length > 0;
if (i18n && i18n.referenceDate) {
i18n.referenceDate = extractDateParts(new Date(i18n.referenceDate));
}
const usedFormats = hasCustomFormats ? i18n.dateFormats : [createLocaleBasedDateFormat(locale)];
const formatterAndParser = createFormatterAndParser(usedFormats);
// Merge current web component I18N settings with new I18N settings and the formatting and parsing functions
datepicker.i18n = Object.assign({}, datepicker.i18n, i18n, formatterAndParser);
});
})(datepicker)
};
})();

View File

@ -0,0 +1,38 @@
(function () {
function copyClassName(dialog) {
const overlay = dialog.$.overlay;
if (overlay) {
overlay.className = dialog.className;
}
}
const observer = new MutationObserver((records) => {
records.forEach((mutation) => {
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
copyClassName(mutation.target);
}
});
});
window.Vaadin.Flow.dialogConnector = {
initLazy: function (dialog) {
if (dialog.$connector) {
return;
}
dialog.$connector = {};
dialog.addEventListener('opened-changed', (e) => {
if (e.detail.value) {
copyClassName(dialog);
}
});
observer.observe(dialog, {
attributes: true,
attributeFilter: ['class']
});
copyClassName(dialog);
}
};
})();

View File

@ -0,0 +1 @@
import './dndConnector.js';

View File

@ -0,0 +1,110 @@
window.Vaadin = window.Vaadin || {};
window.Vaadin.Flow = window.Vaadin.Flow || {};
window.Vaadin.Flow.dndConnector = {
__ondragenterListener: function (event) {
// TODO filter by data type
// TODO prevent dropping on itself (by default)
const effect = event.currentTarget['__dropEffect'];
if (!event.currentTarget.hasAttribute('disabled')) {
if (effect) {
event.dataTransfer.dropEffect = effect;
}
if (effect && effect !== 'none') {
/* #7108: if drag moves on top of drop target's children, first another ondragenter event
* is fired and then a ondragleave event. This happens again once the drag
* moves on top of another children, or back on top of the drop target element.
* Thus need to "cancel" the following ondragleave, to not remove class name.
* Drop event will happen even when dropped to a child element. */
if (event.currentTarget.classList.contains('v-drag-over-target')) {
event.currentTarget['__skip-leave'] = true;
} else {
event.currentTarget.classList.add('v-drag-over-target');
}
// enables browser specific pseudo classes (at least FF)
event.preventDefault();
event.stopPropagation(); // don't let parents know
}
}
},
__ondragoverListener: function (event) {
// TODO filter by data type
// TODO filter by effectAllowed != dropEffect due to Safari & IE11 ?
if (!event.currentTarget.hasAttribute('disabled')) {
const effect = event.currentTarget['__dropEffect'];
if (effect) {
event.dataTransfer.dropEffect = effect;
}
// allows the drop && don't let parents know
event.preventDefault();
event.stopPropagation();
}
},
__ondragleaveListener: function (event) {
if (event.currentTarget['__skip-leave']) {
event.currentTarget['__skip-leave'] = false;
} else {
event.currentTarget.classList.remove('v-drag-over-target');
}
// #7109 need to stop or any parent drop target might not get highlighted,
// as ondragenter for it is fired before the child gets dragleave.
event.stopPropagation();
},
__ondropListener: function (event) {
const effect = event.currentTarget['__dropEffect'];
if (effect) {
event.dataTransfer.dropEffect = effect;
}
event.currentTarget.classList.remove('v-drag-over-target');
// prevent browser handling && don't let parents know
event.preventDefault();
event.stopPropagation();
},
updateDropTarget: function (element) {
if (element['__active']) {
element.addEventListener('dragenter', this.__ondragenterListener, false);
element.addEventListener('dragover', this.__ondragoverListener, false);
element.addEventListener('dragleave', this.__ondragleaveListener, false);
element.addEventListener('drop', this.__ondropListener, false);
} else {
element.removeEventListener('dragenter', this.__ondragenterListener, false);
element.removeEventListener('dragover', this.__ondragoverListener, false);
element.removeEventListener('dragleave', this.__ondragleaveListener, false);
element.removeEventListener('drop', this.__ondropListener, false);
element.classList.remove('v-drag-over-target');
}
},
/** DRAG SOURCE METHODS: */
__dragstartListener: function (event) {
event.stopPropagation();
event.dataTransfer.setData('text/plain', '');
if (event.currentTarget.hasAttribute('disabled')) {
event.preventDefault();
} else {
if (event.currentTarget['__effectAllowed']) {
event.dataTransfer.effectAllowed = event.currentTarget['__effectAllowed'];
}
event.currentTarget.classList.add('v-dragged');
}
},
__dragendListener: function (event) {
event.currentTarget.classList.remove('v-dragged');
},
updateDragSource: function (element) {
if (element['draggable']) {
element.addEventListener('dragstart', this.__dragstartListener, false);
element.addEventListener('dragend', this.__dragendListener, false);
} else {
element.removeEventListener('dragstart', this.__dragstartListener, false);
element.removeEventListener('dragend', this.__dragendListener, false);
}
}
};

View File

@ -0,0 +1,155 @@
import '@polymer/polymer/lib/elements/dom-if.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { Debouncer } from '@polymer/polymer/lib/utils/debounce.js';
import { idlePeriod } from '@polymer/polymer/lib/utils/async.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
class FlowComponentRenderer extends PolymerElement {
static get template() {
return html`
<style>
:host {
animation: 1ms flow-component-renderer-appear;
}
@keyframes flow-component-renderer-appear {
to {
opacity: 1;
}
}
</style>
<slot></slot>
`;
}
static get is() {
return 'flow-component-renderer';
}
static get properties() {
return {
nodeid: Number,
appid: String,
};
}
static get observers() {
return ['_attachRenderedComponentIfAble(appid, nodeid)'];
}
ready() {
super.ready();
this.addEventListener('click', function (event) {
if (
this.firstChild &&
typeof this.firstChild.click === 'function' &&
event.target === this
) {
event.stopPropagation();
this.firstChild.click();
}
});
this.addEventListener('animationend', this._onAnimationEnd);
}
_asyncAttachRenderedComponentIfAble() {
this._debouncer = Debouncer.debounce(this._debouncer, idlePeriod, () =>
this._attachRenderedComponentIfAble()
);
}
_attachRenderedComponentIfAble() {
if (!this.nodeid || !this.appid) {
return;
}
const renderedComponent = this._getRenderedComponent();
if (this.firstChild) {
if (!renderedComponent) {
this._asyncAttachRenderedComponentIfAble();
} else if (this.firstChild !== renderedComponent) {
this.replaceChild(renderedComponent, this.firstChild);
this._defineFocusTarget();
this.onComponentRendered();
} else {
this._defineFocusTarget();
this.onComponentRendered();
}
} else {
if (renderedComponent) {
this.appendChild(renderedComponent);
this._defineFocusTarget();
this.onComponentRendered();
} else {
this._asyncAttachRenderedComponentIfAble();
}
}
}
_getRenderedComponent() {
try {
return window.Vaadin.Flow.clients[this.appid].getByNodeId(this.nodeid);
} catch (error) {
console.error(
'Could not get node %s from app %s',
this.nodeid,
this.appid
);
console.error(error);
}
return null;
}
onComponentRendered() {
// subclasses can override this method to execute custom logic on resize
}
/* Setting the `focus-target` attribute to the first focusable descendant
starting from the firstChild necessary for the focus to be delegated
within the flow-component-renderer when used inside a vaadin-grid cell */
_defineFocusTarget() {
var focusable = this._getFirstFocusableDescendant(this.firstChild);
if (focusable !== null) {
focusable.setAttribute('focus-target', 'true');
}
}
_getFirstFocusableDescendant(node) {
if (this._isFocusable(node)) {
return node;
}
if (node.hasAttribute && (node.hasAttribute('disabled') || node.hasAttribute('hidden'))) {
return null;
}
if (!node.children) {
return null;
}
for (var i = 0; i < node.children.length; i++) {
var focusable = this._getFirstFocusableDescendant(node.children[i]);
if (focusable !== null) {
return focusable;
}
}
return null;
}
_isFocusable(node) {
if (
node.hasAttribute &&
typeof node.hasAttribute === 'function' &&
(node.hasAttribute('disabled') || node.hasAttribute('hidden'))
) {
return false;
}
return node.tabIndex === 0;
}
_onAnimationEnd(e) {
// ShadyCSS applies scoping suffixes to animation names
// To ensure that child is attached once element is unhidden
// for when it was filtered out from, eg, ComboBox
// https://github.com/vaadin/vaadin-flow-components/issues/437
if (e.animationName.indexOf('flow-component-renderer-appear') === 0) {
this._attachRenderedComponentIfAble();
}
}
}
window.customElements.define(FlowComponentRenderer.is, FlowComponentRenderer);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
export * from './Flow';

View File

@ -0,0 +1,2 @@
export * from './Flow';
//# sourceMappingURL=index.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/main/frontend/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC","sourcesContent":["export * from './Flow';\n"]}

View File

@ -0,0 +1,166 @@
import { Debouncer } from '@polymer/polymer/lib/utils/debounce.js';
import { timeOut } from '@polymer/polymer/lib/utils/async.js';
window.Vaadin.Flow.ironListConnector = {
initLazy: function (list) {
// Check whether the connector was already initialized for the Iron list
if (list.$connector) {
return;
}
const extraItemsBuffer = 20;
let lastRequestedRange = [0, 0];
list.$connector = {};
list.$connector.placeholderItem = { __placeholder: true };
const updateRequestedItem = function () {
/*
* TODO Iron list seems to do a small index adjustment after scrolling
* has stopped. This causes a redundant request to be sent to make a
* corresponding minimal change to the buffer. We should avoid these
* requests by making the logic skip doing a request if the available
* buffer is within some tolerance compared to the requested buffer.
*/
let firstNeededItem = list._virtualStart;
let lastNeededItem = list._virtualEnd;
let first = Math.max(0, firstNeededItem - extraItemsBuffer);
let last = Math.min(lastNeededItem + extraItemsBuffer, list.items.length);
if (lastRequestedRange[0] != first || lastRequestedRange[1] != last) {
lastRequestedRange = [first, last];
const count = 1 + last - first;
list.$server.setRequestedRange(first, count);
}
};
let requestDebounce;
const scheduleUpdateRequest = function () {
requestDebounce = Debouncer.debounce(requestDebounce, timeOut.after(10), updateRequestedItem);
};
/*
* Ensure all items that iron list will be looking at are actually defined.
* If this is not done, the component will keep looking ahead through the
* array until finding enough present items to render. In our case, that's
* a really slow way of achieving nothing since the rest of the array is
* empty.
*/
const originalAssign = list._assignModels;
list._assignModels = function () {
const tempItems = [];
const start = list._virtualStart;
const count = Math.min(list.items.length, list._physicalCount);
for (let i = 0; i < count; i++) {
if (list.items[start + i] === undefined) {
tempItems.push(i);
list.items[start + i] = list.$connector.placeholderItem;
}
}
originalAssign.apply(list, arguments);
/*
* TODO: Keep track of placeholder items in the "active" range and
* avoid deleting them so that the next pass will be faster. Instead,
* the end of each pass should only delete placeholders that are no
* longer needed.
*/
for (let i = 0; i < tempItems.length; i++) {
delete list.items[start + tempItems[i]];
}
/*
* Check if we need to do anything once things have settled down.
* This method is called multiple times in sequence for the same user
* action, but we only want to do the check once.
*/
scheduleUpdateRequest();
};
list.items = [];
list.$connector.set = function (index, items) {
for (let i = 0; i < items.length; i++) {
const itemsIndex = index + i;
list.items[itemsIndex] = items[i];
}
// Do a full render since dirty detection for splices is broken
list._render();
};
list.$connector.updateData = function (items) {
// Find the items by key inside the list update them
const oldItems = list.items;
const mapByKey = {};
let leftToUpdate = items.length;
for (let i = 0; i < items.length; i++) {
const item = items[i];
mapByKey[item.key] = item;
}
for (let i = 0; i < oldItems.length; i++) {
const oldItem = oldItems[i];
const newItem = mapByKey[oldItem.key];
if (newItem) {
list.items[i] = newItem;
list.notifyPath('items.' + i);
leftToUpdate--;
if (leftToUpdate == 0) {
break;
}
}
}
};
list.$connector.clear = function (index, length) {
for (let i = 0; i < length; i++) {
const itemsIndex = index + i;
delete list.items[itemsIndex];
// Most likely a no-op since the affected index isn't in view
list.notifyPath('items.' + itemsIndex);
}
};
list.$connector.updateSize = function (newSize) {
const delta = newSize - list.items.length;
if (delta > 0) {
list.items.length = newSize;
list.notifySplices('items', [
{
index: newSize - delta,
removed: [],
addedCount: delta,
object: list.items,
type: 'splice'
}
]);
} else if (delta < 0) {
const removed = list.items.slice(newSize, list.items.length);
list.items.splice(newSize);
list.notifySplices('items', [
{
index: newSize,
removed: removed,
addedCount: 0,
object: list.items,
type: 'splice'
}
]);
}
};
list.$connector.setPlaceholderItem = function (placeholderItem) {
if (!placeholderItem) {
placeholderItem = {};
}
placeholderItem.__placeholder = true;
list.$connector.placeholderItem = placeholderItem;
};
}
};

View File

@ -0,0 +1,12 @@
import '@polymer/polymer/lib/elements/custom-style.js';
const $_documentContainer = document.createElement('template');
$_documentContainer.innerHTML = `<style>
/* Fixes zero width in flex layouts */
iron-list {
flex: auto;
align-self: stretch;
}
</style>`;
document.head.appendChild($_documentContainer.content);

View File

@ -0,0 +1,108 @@
/* eslint-disable no-restricted-syntax */
/* eslint-disable max-params */
import { html, render } from 'lit';
type RenderRoot = HTMLElement & { __litRenderer?: Renderer; _$litPart$?: any };
type ItemModel = { item: any; index: number };
type Renderer = ((root: RenderRoot, rendererOwner: HTMLElement, model: ItemModel) => void) & { __rendererId?: string };
type Component = HTMLElement & { [key: string]: Renderer | undefined };
const _window = window as any;
_window.Vaadin = _window.Vaadin || {};
/**
* Assigns the component a renderer function which uses Lit to render
* the given template expression inside the render root element.
*
* @param component The host component to which the renderer runction is to be set
* @param rendererName The name of the renderer function
* @param templateExpression The content of the template literal passed to Lit for rendering.
* @param returnChannel A channel to the server.
* Calling it will end up invoking a handler in the server-side LitRenderer.
* @param clientCallables A list of function names that can be called from within the template literal.
* @param propertyNamespace LitRenderer-specific namespace for properties.
* Needed to avoid property name collisions between renderers.
*/
_window.Vaadin.setLitRenderer = (
component: Component,
rendererName: string,
templateExpression: string,
returnChannel: (name: string, itemKey: string, args: any[]) => void,
clientCallables: string[],
propertyNamespace: string,
) => {
// Dynamically created function that renders the templateExpression
// inside the given root element using Lit
const renderFunction = Function(`
"use strict";
const [render, html, returnChannel] = arguments;
return (root, {item, index}, itemKey) => {
${clientCallables
.map((clientCallable) => {
// Map all the client-callables as inline functions so they can be accessed from the template literal
return `
const ${clientCallable} = (...args) => {
if (itemKey !== undefined) {
returnChannel('${clientCallable}', itemKey, args[0] instanceof Event ? [] : [...args]);
}
}`;
})
.join('')}
render(html\`${templateExpression}\`, root)
}
`)(render, html, returnChannel);
const renderer: Renderer = (root, _, { index, item }) => {
// Clean up the root element of any existing content
// (and Lit's _$litPart$ property) from other renderers
// TODO: Remove once https://github.com/vaadin/web-components/issues/2235 is done
if (root.__litRenderer !== renderer) {
root.innerHTML = '';
delete root._$litPart$;
root.__litRenderer = renderer;
}
// Map a new item that only includes the properties defined by
// this specific LitRenderer instance. The renderer instance specific
// "propertyNamespace" prefix is stripped from the property name at this point:
//
// item: { key: "2", lr_3_lastName: "Tyler"}
// ->
// mappedItem: { lastName: "Tyler" }
const mappedItem: { [key: string]: any } = {};
for (const key in item) {
if (key.startsWith(propertyNamespace)) {
mappedItem[key.replace(propertyNamespace, '')] = item[key];
}
}
renderFunction(root, { index, item: mappedItem }, item.key);
};
renderer.__rendererId = propertyNamespace;
component[rendererName] = renderer;
};
/**
* Removes the renderer function with the given name from the component
* if the propertyNamespace matches the renderer's id.
*
* @param component The host component whose renderer function is to be removed
* @param rendererName The name of the renderer function
* @param rendererId The rendererId of the function to be removed
*/
_window.Vaadin.unsetLitRenderer = (component: Component, rendererName: string, rendererId: string) => {
// The check for __rendererId property is necessary since the renderer function
// may get overridden by another renderer, for example, by one coming from
// vaadin-template-renderer. We don't want LitRenderer registration cleanup to
// unintentionally remove the new renderer.
if (component[rendererName]?.__rendererId === rendererId) {
component[rendererName] = undefined;
}
};

View File

@ -0,0 +1,40 @@
(function () {
function copyClassName(loginOverlay) {
const overlayWrapper = loginOverlay.$.vaadinLoginOverlayWrapper;
if (overlayWrapper) {
overlayWrapper.className = loginOverlay.className;
}
}
const observer = new MutationObserver((records) => {
records.forEach((mutation) => {
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
copyClassName(mutation.target);
}
});
});
window.Vaadin.Flow.loginOverlayConnector = {
initLazy: function (loginOverlay) {
if (loginOverlay.$connector) {
return;
}
loginOverlay.$connector = {};
loginOverlay.addEventListener('opened-changed', (e) => {
if (e.detail.value) {
copyClassName(loginOverlay);
}
});
observer.observe(loginOverlay, {
attributes: true,
attributeFilter: ['class']
});
// Copy initial class
copyClassName(loginOverlay);
}
};
})();

View File

@ -0,0 +1,9 @@
import { color } from '@vaadin/vaadin-lumo-styles/color.js';
import { typography } from '@vaadin/vaadin-lumo-styles/typography.js';
const tpl = document.createElement('template');
tpl.innerHTML = `<style>
${color.cssText}
${typography.cssText}
</style>`;
document.head.appendChild(tpl.content);

View File

@ -0,0 +1,9 @@
import { colorLight } from '@vaadin/vaadin-material-styles';
import { typography } from '@vaadin/vaadin-material-styles';
const tpl = document.createElement('template');
tpl.innerHTML = `<style>
${colorLight.cssText}
${typography.cssText}
</style>`;
document.head.appendChild(tpl.content);

View File

@ -0,0 +1,111 @@
/*
* Copyright 2000-2022 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
import './contextMenuConnector.js';
(function () {
const tryCatchWrapper = function (callback) {
return window.Vaadin.Flow.tryCatchWrapper(callback, 'Vaadin Menu Bar');
};
/**
* Initializes the connector for a menu bar element.
*
* @param {HTMLElement} menubar
* @param {string} appId
*/
function initLazy(menubar, appId) {
if (menubar.$connector) {
return;
}
const observer = new MutationObserver((records) => {
const hasChangedAttributes = records.some((entry) => {
const oldValue = entry.oldValue;
const newValue = entry.target.getAttribute(entry.attributeName);
return oldValue !== newValue;
});
if (hasChangedAttributes) {
menubar.$connector.generateItems();
}
});
menubar.$connector = {
/**
* Generates and assigns the items to the menu bar.
*
* When the method is called without providing a node id,
* the previously generated items tree will be used.
* That can be useful if you only want to sync the disabled and hidden properties of root items.
*
* @param {number | undefined} nodeId
*/
generateItems: tryCatchWrapper((nodeId) => {
if (!menubar.shadowRoot) {
// workaround for https://github.com/vaadin/flow/issues/5722
setTimeout(() => menubar.$connector.generateItems(nodeId));
return;
}
if (nodeId) {
menubar.__generatedItems = window.Vaadin.Flow.contextMenuConnector.generateItemsTree(appId, nodeId);
}
let items = menubar.__generatedItems || [];
// Propagate disabled state from items to parent buttons
items.forEach((item) => (item.disabled = item.component.disabled));
// Remove hidden items entirely from the array. Just hiding them
// could cause the overflow button to be rendered without items.
//
// The items-prop needs to be set even when all items are visible
// to update the disabled state and re-render buttons.
items = items.filter((item) => !item.component.hidden);
// Observe for hidden and disabled attributes in case they are changed by Flow.
// When a change occurs, the observer will re-generate items on top of the existing tree
// to sync the new attribute values with the corresponding properties in the items array.
items.forEach((item) => {
observer.observe(item.component, {
attributeFilter: ['hidden', 'disabled'],
attributeOldValue: true
});
});
menubar.items = items;
// Propagate click events from the menu buttons to the item components
menubar._buttons.forEach((button) => {
if (button.item && button.item.component) {
button.addEventListener('click', (e) => {
if (e.composedPath().indexOf(button.item.component) === -1) {
button.item.component.click();
e.stopPropagation();
}
});
}
});
})
};
}
window.Vaadin.Flow.menubarConnector = {
initLazy(...args) {
return tryCatchWrapper(initLazy)(...args);
}
};
})();

View File

@ -0,0 +1,41 @@
/*
* Copyright 2000-2022 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
(function () {
const tryCatchWrapper = function (callback) {
return window.Vaadin.Flow.tryCatchWrapper(callback, 'Vaadin Message List');
};
window.Vaadin.Flow.messageListConnector = {
setItems: (list, items, locale) =>
tryCatchWrapper(function (list, items, locale) {
const formatter = new Intl.DateTimeFormat(locale, {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: 'numeric',
minute: 'numeric'
});
list.items = items.map((item) =>
item.time
? Object.assign(item, {
time: formatter.format(new Date(item.time))
})
: item
);
})(list, items, locale)
};
})();

View File

@ -0,0 +1,38 @@
(function () {
function copyClassName(notification) {
const card = notification._card;
if (card) {
card.className = notification.className;
}
}
const observer = new MutationObserver((records) => {
records.forEach((mutation) => {
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
copyClassName(mutation.target);
}
});
});
window.Vaadin.Flow.notificationConnector = {
initLazy: function (notification) {
if (notification.$connector) {
return;
}
notification.$connector = {};
notification.addEventListener('opened-changed', (e) => {
if (e.detail.value) {
copyClassName(notification);
}
});
observer.observe(notification, {
attributes: true,
attributeFilter: ['class']
});
copyClassName(notification);
}
};
})();

View File

@ -0,0 +1,36 @@
(function () {
const tryCatchWrapper = function (callback) {
return window.Vaadin.Flow.tryCatchWrapper(callback, 'Vaadin Select');
};
window.Vaadin.Flow.selectConnector = {
initLazy: (select) =>
tryCatchWrapper(function (select) {
const _findListBoxElement = tryCatchWrapper(function () {
for (let i = 0; i < select.childElementCount; i++) {
const child = select.children[i];
if ('VAADIN-SELECT-LIST-BOX' === child.tagName.toUpperCase()) {
return child;
}
}
});
// do not init this connector twice for the given select
if (select.$connector) {
return;
}
select.$connector = {};
select.renderer = tryCatchWrapper(function (root) {
const listBox = _findListBoxElement();
if (listBox) {
if (root.firstChild) {
root.removeChild(root.firstChild);
}
root.appendChild(listBox);
}
});
})(select)
};
})();

View File

@ -0,0 +1,11 @@
import { Tooltip } from '@vaadin/tooltip';
const _window = window as any;
_window.Vaadin = _window.Vaadin || {};
_window.Vaadin.Flow = _window.Vaadin.Flow || {};
_window.Vaadin.Flow.tooltip = {
setDefaultHideDelay: (hideDelay: number) => Tooltip.setDefaultHideDelay(hideDelay),
setDefaultFocusDelay: (focusDelay: number) => Tooltip.setDefaultFocusDelay(focusDelay),
setDefaultHoverDelay: (hoverDelay: number) => Tooltip.setDefaultHoverDelay(hoverDelay),
}

View File

@ -0,0 +1,77 @@
/*
* Copyright 2000-2022 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
(function() {
let memoizedTemplate;
customElements.whenDefined('vaadin-text-field').then(() => {
class BigDecimalFieldElement extends customElements.get('vaadin-text-field') {
static get template() {
if (!memoizedTemplate) {
memoizedTemplate = super.template.cloneNode(true);
memoizedTemplate.innerHTML +=
`<style>
:host {
width: 8em;
}
:host([dir="rtl"]) [part="input-field"] {
direction: ltr;
}
:host([dir="rtl"]) [part="input-field"] ::slotted(input) {
--_lumo-text-field-overflow-mask-image: linear-gradient(to left, transparent, #000 1.25em) !important;
}
</style>`;
}
return memoizedTemplate;
}
static get is() {
return 'vaadin-big-decimal-field';
}
static get properties() {
return {
_decimalSeparator: {
type: String,
value: '.',
observer: '__decimalSeparatorChanged'
}
}
}
ready() {
super.ready();
this.inputElement.setAttribute('inputmode', 'decimal');
}
__decimalSeparatorChanged(separator, oldSeparator) {
this.allowedCharPattern = '[\\d-+' + separator + ']';
if (this.value && oldSeparator) {
this.value = this.value.split(oldSeparator).join(separator);
}
}
}
customElements.define(BigDecimalFieldElement.is, BigDecimalFieldElement);
});
})();

View File

@ -0,0 +1,119 @@
import { LitElement } from 'lit';
import { Product } from './License';
interface Feature {
id: string;
title: string;
moreInfoLink: string;
requiresServerRestart: boolean;
enabled: boolean;
}
declare enum ConnectionStatus {
ACTIVE = "active",
INACTIVE = "inactive",
UNAVAILABLE = "unavailable",
ERROR = "error"
}
export declare class Connection extends Object {
static HEARTBEAT_INTERVAL: number;
status: ConnectionStatus;
webSocket?: WebSocket;
constructor(url?: string);
onHandshake(): void;
onReload(): void;
onConnectionError(_: string): void;
onStatusChange(_: ConnectionStatus): void;
onMessage(message: any): void;
handleMessage(msg: any): void;
handleError(msg: any): void;
setActive(yes: boolean): void;
setStatus(status: ConnectionStatus): void;
private send;
setFeature(featureId: string, enabled: boolean): void;
sendTelemetry(browserData: any): void;
sendLicenseCheck(product: Product): void;
}
declare enum MessageType {
LOG = "log",
INFORMATION = "information",
WARNING = "warning",
ERROR = "error"
}
interface Message {
id: number;
type: MessageType;
message: string;
details?: string;
link?: string;
persistentId?: string;
dontShowAgain: boolean;
deleted: boolean;
}
export declare class VaadinDevTools extends LitElement {
static BLUE_HSL: import("lit").CSSResult;
static GREEN_HSL: import("lit").CSSResult;
static GREY_HSL: import("lit").CSSResult;
static YELLOW_HSL: import("lit").CSSResult;
static RED_HSL: import("lit").CSSResult;
static MAX_LOG_ROWS: number;
static get styles(): import("lit").CSSResult;
static DISMISSED_NOTIFICATIONS_IN_LOCAL_STORAGE: string;
static ACTIVE_KEY_IN_SESSION_STORAGE: string;
static TRIGGERED_KEY_IN_SESSION_STORAGE: string;
static TRIGGERED_COUNT_KEY_IN_SESSION_STORAGE: string;
static AUTO_DEMOTE_NOTIFICATION_DELAY: number;
static HOTSWAP_AGENT: string;
static JREBEL: string;
static SPRING_BOOT_DEVTOOLS: string;
static BACKEND_DISPLAY_NAME: Record<string, string>;
static get isActive(): boolean;
static notificationDismissed(persistentId: string): boolean;
url?: string;
liveReloadDisabled?: boolean;
backend?: string;
springBootLiveReloadPort?: number;
expanded: boolean;
messages: Message[];
splashMessage?: string;
notifications: Message[];
frontendStatus: ConnectionStatus;
javaStatus: ConnectionStatus;
private tabs;
private activeTab;
private serverInfo;
private features;
private unreadErrors;
private root;
private javaConnection?;
private frontendConnection?;
private nextMessageId;
private disableEventListener?;
private transitionDuration;
elementTelemetry(): void;
openWebSocketConnection(): void;
getDedicatedWebSocketUrl(): string | undefined;
getSpringBootWebSocketUrl(location: any): string;
connectedCallback(): void;
format(o: any): string;
catchErrors(): void;
disconnectedCallback(): void;
toggleExpanded(): void;
showSplashMessage(msg: string | undefined): void;
demoteSplashMessage(): void;
checkLicense(productInfo: Product): void;
log(type: MessageType, message: string, details?: string, link?: string): void;
showNotification(type: MessageType, message: string, details?: string, link?: string, persistentId?: string): void;
dismissNotification(id: number): void;
findNotificationIndex(id: number): number;
toggleDontShowAgain(id: number): void;
setActive(yes: boolean): void;
getStatusColor(status: ConnectionStatus | undefined): import("lit").CSSResult;
renderMessage(messageObject: Message): import("lit-html").TemplateResult<1>;
render(): import("lit-html").TemplateResult<1>;
renderLog(): import("lit-html").TemplateResult<1>;
activateLog(): void;
renderInfo(): import("lit-html").TemplateResult<1>;
private renderFeatures;
copyInfoToClipboard(): void;
toggleFeatureFlag(e: Event, feature: Feature): void;
}
export {};

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,156 @@
import '@vaadin/grid/vaadin-grid-column.js';
import { GridColumn } from '@vaadin/grid/src/vaadin-grid-column.js';
{
class GridFlowSelectionColumnElement extends GridColumn {
static get is() {
return 'vaadin-grid-flow-selection-column';
}
static get properties() {
return {
/**
* Automatically sets the width of the column based on the column contents when this is set to `true`.
*/
autoWidth: {
type: Boolean,
value: true
},
/**
* Width of the cells for this column.
*/
width: {
type: String,
value: '56px'
},
/**
* Flex grow ratio for the cell widths. When set to 0, cell width is fixed.
*/
flexGrow: {
type: Number,
value: 0
},
/**
* When true, all the items are selected.
*/
selectAll: {
type: Boolean,
value: false,
notify: true
},
/**
* Whether to display the select all checkbox in indeterminate state,
* which means some, but not all, items are selected
*/
indeterminate: {
type: Boolean,
value: false,
notify: true
},
selectAllHidden: Boolean
};
}
constructor() {
super();
this._boundOnSelectEvent = this._onSelectEvent.bind(this);
this._boundOnDeselectEvent = this._onDeselectEvent.bind(this);
}
static get observers() {
return [
'_onHeaderRendererOrBindingChanged(_headerRenderer, _headerCell, path, header, selectAll, indeterminate, selectAllHidden)'
];
}
/** @private */
connectedCallback() {
super.connectedCallback();
if (this._grid) {
this._grid.addEventListener('select', this._boundOnSelectEvent);
this._grid.addEventListener('deselect', this._boundOnDeselectEvent);
}
}
/** @private */
disconnectedCallback() {
super.disconnectedCallback();
if (this._grid) {
this._grid.removeEventListener('select', this._boundOnSelectEvent);
this._grid.removeEventListener('deselect', this._boundOnDeselectEvent);
}
}
/**
* Renders the Select All checkbox to the header cell.
*
* @override
*/
_defaultHeaderRenderer(root, _column) {
let checkbox = root.firstElementChild;
if (!checkbox) {
checkbox = document.createElement('vaadin-checkbox');
checkbox.id = 'selectAllCheckbox';
checkbox.setAttribute('aria-label', 'Select All');
checkbox.classList.add('vaadin-grid-select-all-checkbox');
checkbox.addEventListener('click', this._onSelectAllClick.bind(this));
root.appendChild(checkbox);
}
const checked = this.selectAll;
checkbox.hidden = this.selectAllHidden;
checkbox.checked = checked;
checkbox.indeterminate = this.indeterminate;
}
/**
* Renders the Select Row checkbox to the body cell.
*
* @override
*/
_defaultRenderer(root, _column, { item, selected }) {
let checkbox = root.firstElementChild;
if (!checkbox) {
checkbox = document.createElement('vaadin-checkbox');
checkbox.setAttribute('aria-label', 'Select Row');
checkbox.addEventListener('click', this._onSelectClick.bind(this));
root.appendChild(checkbox);
}
checkbox.__item = item;
checkbox.checked = selected;
}
_onSelectClick(e) {
e.currentTarget.checked ? this._grid.$connector.doDeselection([e.currentTarget.__item], true) : this._grid.$connector.doSelection([e.currentTarget.__item], true);
}
_onSelectAllClick(e) {
e.preventDefault();
if (this._grid.hasAttribute('disabled')) {
e.currentTarget.checked = !e.currentTarget.checked;
return;
}
this.selectAll ? this.$server.deselectAll() : this.$server.selectAll();
}
_onSelectEvent(e) {
}
_onDeselectEvent(e) {
if (e.detail.userOriginated) {
this.selectAll = false;
}
}
}
customElements.define(GridFlowSelectionColumnElement.is, GridFlowSelectionColumnElement);
Vaadin.GridFlowSelectionColumnElement = GridFlowSelectionColumnElement;
}

View File

@ -0,0 +1,183 @@
// map from unicode eastern arabic number characters to arabic numbers
const EASTERN_ARABIC_DIGIT_MAP = {
'\\u0660': '0',
'\\u0661': '1',
'\\u0662': '2',
'\\u0663': '3',
'\\u0664': '4',
'\\u0665': '5',
'\\u0666': '6',
'\\u0667': '7',
'\\u0668': '8',
'\\u0669': '9'
};
/**
* Escapes the given string so it can be safely used in a regexp.
*
* @param {string} string
* @return {string}
*/
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
/**
* Parses eastern arabic number characters to arabic numbers (0-9)
*
* @param {string} digits
* @return {string}
*/
function parseEasternArabicDigits(digits) {
return digits.replace(/[\u0660-\u0669]/g, function (char) {
const unicode = '\\u0' + char.charCodeAt(0).toString(16);
return EASTERN_ARABIC_DIGIT_MAP[unicode];
});
}
/**
* @param {string} locale
* @param {Date} testTime
* @return {string | null}
*/
function getAmOrPmString(locale, testTime) {
const testTimeString = testTime.toLocaleTimeString(locale);
// AM/PM string is anything from one letter in eastern arabic to standard two letters,
// to having space in between, dots ...
// cannot disqualify whitespace since some locales use a. m. / p. m.
// TODO when more scripts support is added (than Arabic), need to exclude those numbers too
const amOrPmRegExp = /[^\d\u0660-\u0669]/;
const matches =
// In most locales, the time ends with AM/PM:
testTimeString.match(new RegExp(`${amOrPmRegExp.source}+$`, 'g')) ||
// In some locales, the time starts with AM/PM e.g in Chinese:
testTimeString.match(new RegExp(`^${amOrPmRegExp.source}+`, 'g'));
return matches && matches[0].trim();
}
/**
* @param {string} locale
* @return {string | null}
*/
export function getSeparator(locale) {
let timeString = TEST_PM_TIME.toLocaleTimeString(locale);
// Since the next regex picks first non-number-whitespace,
// need to discard possible PM from beginning (eg. chinese locale)
const pmString = getPmString(locale);
if (pmString && timeString.startsWith(pmString)) {
timeString = timeString.replace(pmString, '');
}
const matches = timeString.match(/[^\u0660-\u0669\s\d]/);
return matches && matches[0];
}
/**
* Searches for either an AM or PM token in the given time string
* depending on what is provided in `amOrPmString`.
*
* The search is case and space insensitive.
*
* @example
* `searchAmOrPmToken('1 P M', 'PM')` => `'P M'`
*
* @example
* `searchAmOrPmToken('1 a.m.', 'A. M.')` => `a.m.`
*
* @param {string} timeString
* @param {string} amOrPmString
* @return {string | null}
*/
export function searchAmOrPmToken(timeString, amOrPmString) {
if (!amOrPmString) return null;
// Create a regexp string for searching for AM/PM without space-sensitivity.
const tokenRegExpString = amOrPmString.split(/\s*/).map(escapeRegExp).join('\\s*');
// Create a regexp without case-sensitivity.
const tokenRegExp = new RegExp(tokenRegExpString, 'i');
// Match the regexp against the time string.
const tokenMatches = timeString.match(tokenRegExp);
if (tokenMatches) {
return tokenMatches[0];
}
}
export const TEST_PM_TIME = new Date('August 19, 1975 23:15:30');
export const TEST_AM_TIME = new Date('August 19, 1975 05:15:30');
/**
* @param {string} locale
* @return {string}
*/
export function getPmString(locale) {
return getAmOrPmString(locale, TEST_PM_TIME);
}
/**
* @param {string} locale
* @return {string}
*/
export function getAmString(locale) {
return getAmOrPmString(locale, TEST_AM_TIME);
}
/**
* @param {string} digits
* @return {number}
*/
export function parseDigitsIntoInteger(digits) {
return parseInt(parseEasternArabicDigits(digits));
}
/**
* @param {string} milliseconds
* @return {number}
*/
export function parseMillisecondsIntoInteger(milliseconds) {
milliseconds = parseEasternArabicDigits(milliseconds);
// digits are either .1 .01 or .001 so need to "shift"
if (milliseconds.length === 1) {
milliseconds += '00';
} else if (milliseconds.length === 2) {
milliseconds += '0';
}
return parseInt(milliseconds);
}
/**
* @param {string} timeString
* @param {number} milliseconds
* @param {string} amString
* @param {string} pmString
* @return {string}
*/
export function formatMilliseconds(timeString, milliseconds, amString, pmString) {
// might need to inject milliseconds between seconds and AM/PM
let cleanedTimeString = timeString;
if (timeString.endsWith(amString)) {
cleanedTimeString = timeString.replace(' ' + amString, '');
} else if (timeString.endsWith(pmString)) {
cleanedTimeString = timeString.replace(' ' + pmString, '');
}
if (milliseconds) {
let millisecondsString = milliseconds < 10 ? '0' : '';
millisecondsString += milliseconds < 100 ? '0' : '';
millisecondsString += milliseconds;
cleanedTimeString += '.' + millisecondsString;
} else {
cleanedTimeString += '.000';
}
if (timeString.endsWith(amString)) {
cleanedTimeString = cleanedTimeString + ' ' + amString;
} else if (timeString.endsWith(pmString)) {
cleanedTimeString = cleanedTimeString + ' ' + pmString;
}
return cleanedTimeString;
}

View File

@ -0,0 +1,178 @@
import {
TEST_PM_TIME,
formatMilliseconds,
parseMillisecondsIntoInteger,
parseDigitsIntoInteger,
getAmString,
getPmString,
getSeparator,
searchAmOrPmToken
} from './helpers.js';
(function () {
const tryCatchWrapper = function (callback) {
return window.Vaadin.Flow.tryCatchWrapper(callback, 'Vaadin Time Picker');
};
// Execute callback when predicate returns true.
// Try again later if predicate returns false.
function when(predicate, callback, timeout = 0) {
if (predicate()) {
callback();
} else {
setTimeout(() => when(predicate, callback, 200), timeout);
}
}
window.Vaadin.Flow.timepickerConnector = {
initLazy: (timepicker) =>
tryCatchWrapper(function (timepicker) {
// Check whether the connector was already initialized for the timepicker
if (timepicker.$connector) {
return;
}
timepicker.$connector = {};
timepicker.$connector.setLocale = tryCatchWrapper(function (locale) {
// capture previous value if any
let previousValueObject;
if (timepicker.value && timepicker.value !== '') {
previousValueObject = timepicker.i18n.parseTime(timepicker.value);
}
try {
// Check whether the locale is supported by the browser or not
TEST_PM_TIME.toLocaleTimeString(locale);
} catch (e) {
locale = 'en-US';
// FIXME should do a callback for server to throw an exception ?
throw new Error(
'vaadin-time-picker: The locale ' +
locale +
' is not supported, falling back to default locale setting(en-US).'
);
}
// 1. 24 or 12 hour clock, if latter then what are the am/pm strings ?
const pmString = getPmString(locale);
const amString = getAmString(locale);
// 2. What is the separator ?
const separator = getSeparator(locale);
const includeSeconds = function () {
return timepicker.step && timepicker.step < 60;
};
const includeMilliSeconds = function () {
return timepicker.step && timepicker.step < 1;
};
let cachedTimeString;
let cachedTimeObject;
timepicker.i18n = {
formatTime: tryCatchWrapper(function (timeObject) {
if (!timeObject) return;
const timeToBeFormatted = new Date();
timeToBeFormatted.setHours(timeObject.hours);
timeToBeFormatted.setMinutes(timeObject.minutes);
timeToBeFormatted.setSeconds(timeObject.seconds !== undefined ? timeObject.seconds : 0);
// the web component expects the correct granularity used for the time string,
// thus need to format the time object in correct granularity by passing the format options
let localeTimeString = timeToBeFormatted.toLocaleTimeString(locale, {
hour: 'numeric',
minute: 'numeric',
second: includeSeconds() ? 'numeric' : undefined
});
// milliseconds not part of the time format API
if (includeMilliSeconds()) {
localeTimeString = formatMilliseconds(localeTimeString, timeObject.milliseconds, amString, pmString);
}
return localeTimeString;
}),
parseTime: tryCatchWrapper(function (timeString) {
if (timeString && timeString === cachedTimeString && cachedTimeObject) {
return cachedTimeObject;
}
if (!timeString) {
// when nothing is returned, the component shows the invalid state for the input
return;
}
const amToken = searchAmOrPmToken(timeString, amString);
const pmToken = searchAmOrPmToken(timeString, pmString);
const numbersOnlyTimeString = timeString
.replace(amToken || '', '')
.replace(pmToken || '', '')
.trim();
// A regexp that allows to find the numbers with optional separator and continuing searching after it.
const numbersRegExp = new RegExp('([\\d\\u0660-\\u0669]){1,2}(?:' + separator + ')?', 'g');
let hours = numbersRegExp.exec(numbersOnlyTimeString);
if (hours) {
hours = parseDigitsIntoInteger(hours[0].replace(separator, ''));
// handle 12 am -> 0
// do not do anything if am & pm are not used or if those are the same,
// as with locale bg-BG there is always ч. at the end of the time
if (amToken !== pmToken) {
if (hours === 12 && amToken) {
hours = 0;
}
if (hours !== 12 && pmToken) {
hours += 12;
}
}
const minutes = numbersRegExp.exec(numbersOnlyTimeString);
const seconds = minutes && numbersRegExp.exec(numbersOnlyTimeString);
// detecting milliseconds from input, expects am/pm removed from end, eg. .0 or .00 or .000
const millisecondRegExp = /[[\.][\d\u0660-\u0669]{1,3}$/;
// reset to end or things can explode
let milliseconds = seconds && includeMilliSeconds() && millisecondRegExp.exec(numbersOnlyTimeString);
// handle case where last numbers are seconds and . is the separator (invalid regexp match)
if (milliseconds && milliseconds['index'] <= seconds['index']) {
milliseconds = undefined;
}
// hours is a number at this point, others are either arrays or null
// the string in [0] from the arrays includes the separator too
cachedTimeObject = hours !== undefined && {
hours: hours,
minutes: minutes ? parseDigitsIntoInteger(minutes[0].replace(separator, '')) : 0,
seconds: seconds ? parseDigitsIntoInteger(seconds[0].replace(separator, '')) : 0,
milliseconds:
minutes && seconds && milliseconds
? parseMillisecondsIntoInteger(milliseconds[0].replace('.', ''))
: 0
};
cachedTimeString = timeString;
return cachedTimeObject;
}
})
};
if (previousValueObject) {
when(
() => timepicker.$,
() => {
const newValue = timepicker.i18n.formatTime(previousValueObject);
// FIXME works but uses private API, needs fixes in web component
if (timepicker.inputElement.value !== newValue) {
timepicker.inputElement.value = newValue;
timepicker.$.comboBox.value = newValue;
}
}
);
}
});
})(timepicker)
};
})();

View File

@ -0,0 +1,130 @@
import { Debouncer } from '@polymer/polymer/lib/utils/debounce.js';
import { timeOut } from '@polymer/polymer/lib/utils/async.js';
window.Vaadin.Flow.virtualListConnector = {
initLazy: function (list) {
// Check whether the connector was already initialized for the virtual list
if (list.$connector) {
return;
}
const extraItemsBuffer = 20;
let lastRequestedRange = [0, 0];
list.$connector = {};
list.$connector.placeholderItem = { __placeholder: true };
const updateRequestedItem = function () {
/*
* TODO virtual list seems to do a small index adjustment after scrolling
* has stopped. This causes a redundant request to be sent to make a
* corresponding minimal change to the buffer. We should avoid these
* requests by making the logic skip doing a request if the available
* buffer is within some tolerance compared to the requested buffer.
*/
const visibleIndexes = [...list.children]
.filter((el) => '__virtualListIndex' in el)
.map((el) => el.__virtualListIndex);
const firstNeededItem = Math.min(...visibleIndexes);
const lastNeededItem = Math.max(...visibleIndexes);
let first = Math.max(0, firstNeededItem - extraItemsBuffer);
let last = Math.min(lastNeededItem + extraItemsBuffer, list.items.length);
if (lastRequestedRange[0] != first || lastRequestedRange[1] != last) {
lastRequestedRange = [first, last];
const count = 1 + last - first;
list.$server.setRequestedRange(first, count);
}
};
const scheduleUpdateRequest = function () {
list.__requestDebounce = Debouncer.debounce(list.__requestDebounce, timeOut.after(50), updateRequestedItem);
};
requestAnimationFrame(() => updateRequestedItem);
// Add an observer function that will invoke on virtualList.renderer property
// change and then patches it with a wrapper renderer
list.patchVirtualListRenderer = function () {
if (!list.renderer || list.renderer.__virtualListConnectorPatched) {
// The list either doesn't have a renderer yet or it's already been patched
return;
}
const originalRenderer = list.renderer;
const renderer = (root, list, model) => {
root.__virtualListIndex = model.index;
if (model.item === undefined) {
originalRenderer.call(list, root, list, {
...model,
item: list.$connector.placeholderItem
});
} else {
originalRenderer.call(list, root, list, model);
}
/*
* Check if we need to do anything once things have settled down.
* This method is called multiple times in sequence for the same user
* action, but we only want to do the check once.
*/
scheduleUpdateRequest();
};
renderer.__virtualListConnectorPatched = true;
renderer.__rendererId = originalRenderer.__rendererId;
list.renderer = renderer;
};
list._createPropertyObserver('renderer', 'patchVirtualListRenderer', true);
list.patchVirtualListRenderer();
list.items = [];
list.$connector.set = function (index, items) {
list.items.splice(index, items.length, ...items);
list.items = [...list.items];
};
list.$connector.clear = function (index, length) {
// How many items, starting from "index", should be set as undefined
const clearCount = Math.min(length, list.items.length - index);
list.$connector.set(index, [...Array(clearCount)]);
};
list.$connector.updateData = function (items) {
const updatedItemsMap = items.reduce((map, item) => {
map[item.key] = item;
return map;
}, {});
list.items = list.items.map((item) => {
// Items can be undefined if they are outside the viewport
if (!item) {
return item;
}
// Replace existing item with updated item,
// return existing item as fallback if it was not updated
return updatedItemsMap[item.key] || item;
});
};
list.$connector.updateSize = function (newSize) {
const delta = newSize - list.items.length;
if (delta > 0) {
list.items = [...list.items, ...Array(delta)];
} else if (delta < 0) {
list.items = list.items.slice(0, newSize);
}
};
list.$connector.setPlaceholderItem = function (placeholderItem = {}) {
placeholderItem.__placeholder = true;
list.$connector.placeholderItem = placeholderItem;
};
}
};

View File

@ -0,0 +1,11 @@
// @ts-nocheck
window.Vaadin = window.Vaadin || {};
window.Vaadin.featureFlags = window.Vaadin.featureFlags || {};
window.Vaadin.featureFlags.exampleFeatureFlag = false;
window.Vaadin.featureFlags.hillaPush = false;
window.Vaadin.featureFlags.hillaEngine = false;
window.Vaadin.featureFlags.oldLicenseChecker = false;
window.Vaadin.featureFlags.collaborationEngineBackend = false;
window.Vaadin.featureFlags.webpackForFrontendBuild = false;
window.Vaadin.featureFlags.enforceFieldValidation = false;
export {};

View File

@ -0,0 +1,5 @@
import './vaadin-featureflags.ts';
import './index';
import 'Frontend/generated/jar-resources/vaadin-dev-tools.js';

View File

@ -0,0 +1,31 @@
// @ts-ignore
if (import.meta.hot) {
// @ts-ignore
const hot = import.meta.hot;
const isLiveReloadDisabled = () => {
// Checks if live reload is disabled in the debug window
return sessionStorage.getItem('vaadin.live-reload.active') === 'false';
};
const preventViteReload = (payload: any) => {
// Changing the path prevents Vite from reloading
payload.path = '/_fake/path.html';
};
let pendingNavigationTo: string | undefined = undefined;
window.addEventListener('vaadin-router-go', (routerEvent: any) => {
pendingNavigationTo = routerEvent.detail.pathname + routerEvent.detail.search;
});
hot.on('vite:beforeFullReload', (payload: any) => {
if (isLiveReloadDisabled()) {
preventViteReload(payload);
}
if (pendingNavigationTo) {
// Force reload with the new URL
location.href = pendingNavigationTo;
preventViteReload(payload);
}
});
}

23
frontend/index.html Normal file
View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<!--
This file is auto-generated by Vaadin.
-->
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
body, #outlet {
height: 100vh;
width: 100%;
margin: 0;
}
</style>
<!-- index.ts is included here automatically (either by the dev server or during the build) -->
</head>
<body>
<!-- This outlet div is where the views are rendered -->
<div id="outlet"></div>
</body>
</html>

316
mvnw vendored Normal file
View File

@ -0,0 +1,316 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /usr/local/etc/mavenrc ] ; then
. /usr/local/etc/mavenrc
fi
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`\\unset -f command; \\command -v java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaClass")
fi
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
$MAVEN_DEBUG_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" \
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

188
mvnw.cmd vendored Normal file
View File

@ -0,0 +1,188 @@
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM https://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% ^
%JVM_CONFIG_MAVEN_PROPS% ^
%MAVEN_OPTS% ^
%MAVEN_DEBUG_OPTS% ^
-classpath %WRAPPER_JAR% ^
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
%WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%"=="on" pause
if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
cmd /C exit /B %ERROR_CODE%

12371
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

360
package.json Normal file
View File

@ -0,0 +1,360 @@
{
"name": "no-name",
"license": "UNLICENSED",
"dependencies": {
"@polymer/iron-icon": "3.0.1",
"@polymer/iron-iconset-svg": "3.0.1",
"@polymer/iron-list": "3.1.0",
"@polymer/iron-meta": "3.0.1",
"@polymer/iron-resizable-behavior": "3.0.1",
"@polymer/polymer": "3.5.1",
"@vaadin/accordion": "23.3.5",
"@vaadin/app-layout": "23.3.5",
"@vaadin/avatar": "23.3.5",
"@vaadin/avatar-group": "23.3.5",
"@vaadin/bundles": "23.3.5",
"@vaadin/button": "23.3.5",
"@vaadin/checkbox": "23.3.5",
"@vaadin/checkbox-group": "23.3.5",
"@vaadin/combo-box": "23.3.5",
"@vaadin/common-frontend": "0.0.17",
"@vaadin/component-base": "23.3.5",
"@vaadin/confirm-dialog": "23.3.5",
"@vaadin/context-menu": "23.3.5",
"@vaadin/custom-field": "23.3.5",
"@vaadin/date-picker": "23.3.5",
"@vaadin/date-time-picker": "23.3.5",
"@vaadin/details": "23.3.5",
"@vaadin/dialog": "23.3.5",
"@vaadin/email-field": "23.3.5",
"@vaadin/field-base": "23.3.5",
"@vaadin/field-highlighter": "23.3.5",
"@vaadin/form-layout": "23.3.5",
"@vaadin/grid": "23.3.5",
"@vaadin/horizontal-layout": "23.3.5",
"@vaadin/icon": "23.3.5",
"@vaadin/icons": "23.3.5",
"@vaadin/input-container": "23.3.5",
"@vaadin/integer-field": "23.3.5",
"@vaadin/item": "23.3.5",
"@vaadin/list-box": "23.3.5",
"@vaadin/lit-renderer": "23.3.5",
"@vaadin/login": "23.3.5",
"@vaadin/menu-bar": "23.3.5",
"@vaadin/message-input": "23.3.5",
"@vaadin/message-list": "23.3.5",
"@vaadin/multi-select-combo-box": "23.3.5",
"@vaadin/notification": "23.3.5",
"@vaadin/number-field": "23.3.5",
"@vaadin/password-field": "23.3.5",
"@vaadin/polymer-legacy-adapter": "23.3.5",
"@vaadin/progress-bar": "23.3.5",
"@vaadin/radio-group": "23.3.5",
"@vaadin/router": "1.7.4",
"@vaadin/scroller": "23.3.5",
"@vaadin/select": "23.3.5",
"@vaadin/split-layout": "23.3.5",
"@vaadin/tabs": "23.3.5",
"@vaadin/tabsheet": "23.3.5",
"@vaadin/text-area": "23.3.5",
"@vaadin/text-field": "23.3.5",
"@vaadin/time-picker": "23.3.5",
"@vaadin/tooltip": "23.3.5",
"@vaadin/upload": "23.3.5",
"@vaadin/vaadin-accordion": "23.3.5",
"@vaadin/vaadin-app-layout": "23.3.5",
"@vaadin/vaadin-avatar": "23.3.5",
"@vaadin/vaadin-button": "23.3.5",
"@vaadin/vaadin-checkbox": "23.3.5",
"@vaadin/vaadin-combo-box": "23.3.5",
"@vaadin/vaadin-confirm-dialog": "23.3.5",
"@vaadin/vaadin-context-menu": "23.3.5",
"@vaadin/vaadin-custom-field": "23.3.5",
"@vaadin/vaadin-date-picker": "23.3.5",
"@vaadin/vaadin-date-time-picker": "23.3.5",
"@vaadin/vaadin-details": "23.3.5",
"@vaadin/vaadin-development-mode-detector": "2.0.5",
"@vaadin/vaadin-dialog": "23.3.5",
"@vaadin/vaadin-form-layout": "23.3.5",
"@vaadin/vaadin-grid": "23.3.5",
"@vaadin/vaadin-icon": "23.3.5",
"@vaadin/vaadin-icons": "23.3.5",
"@vaadin/vaadin-item": "23.3.5",
"@vaadin/vaadin-list-box": "23.3.5",
"@vaadin/vaadin-list-mixin": "23.3.5",
"@vaadin/vaadin-login": "23.3.5",
"@vaadin/vaadin-lumo-styles": "23.3.5",
"@vaadin/vaadin-material-styles": "23.3.5",
"@vaadin/vaadin-menu-bar": "23.3.5",
"@vaadin/vaadin-messages": "23.3.5",
"@vaadin/vaadin-notification": "23.3.5",
"@vaadin/vaadin-ordered-layout": "23.3.5",
"@vaadin/vaadin-overlay": "23.3.5",
"@vaadin/vaadin-progress-bar": "23.3.5",
"@vaadin/vaadin-radio-button": "23.3.5",
"@vaadin/vaadin-select": "23.3.5",
"@vaadin/vaadin-split-layout": "23.3.5",
"@vaadin/vaadin-tabs": "23.3.5",
"@vaadin/vaadin-template-renderer": "23.3.5",
"@vaadin/vaadin-text-field": "23.3.5",
"@vaadin/vaadin-themable-mixin": "23.3.5",
"@vaadin/vaadin-time-picker": "23.3.5",
"@vaadin/vaadin-upload": "23.3.5",
"@vaadin/vaadin-usage-statistics": "2.1.2",
"@vaadin/vaadin-virtual-list": "23.3.5",
"@vaadin/vertical-layout": "23.3.5",
"@vaadin/virtual-list": "23.3.5",
"construct-style-sheets-polyfill": "3.1.0",
"date-fns": "2.29.3",
"lit": "2.6.1"
},
"devDependencies": {
"@rollup/plugin-replace": "3.1.0",
"@rollup/pluginutils": "4.1.0",
"async": "3.2.2",
"glob": "7.2.3",
"mkdirp": "1.0.4",
"rollup-plugin-brotli": "3.1.0",
"strip-css-comments": "5.0.0",
"transform-ast": "2.4.4",
"typescript": "4.9.3",
"vite": "3.2.5",
"vite-plugin-checker": "0.5.1",
"workbox-build": "6.5.4",
"workbox-core": "6.5.4",
"workbox-precaching": "6.5.4"
},
"vaadin": {
"dependencies": {
"@polymer/iron-icon": "3.0.1",
"@polymer/iron-iconset-svg": "3.0.1",
"@polymer/iron-list": "3.1.0",
"@polymer/iron-meta": "3.0.1",
"@polymer/iron-resizable-behavior": "3.0.1",
"@polymer/polymer": "3.5.1",
"@vaadin/accordion": "23.3.5",
"@vaadin/app-layout": "23.3.5",
"@vaadin/avatar": "23.3.5",
"@vaadin/avatar-group": "23.3.5",
"@vaadin/bundles": "23.3.5",
"@vaadin/button": "23.3.5",
"@vaadin/checkbox": "23.3.5",
"@vaadin/checkbox-group": "23.3.5",
"@vaadin/combo-box": "23.3.5",
"@vaadin/common-frontend": "0.0.17",
"@vaadin/component-base": "23.3.5",
"@vaadin/confirm-dialog": "23.3.5",
"@vaadin/context-menu": "23.3.5",
"@vaadin/custom-field": "23.3.5",
"@vaadin/date-picker": "23.3.5",
"@vaadin/date-time-picker": "23.3.5",
"@vaadin/details": "23.3.5",
"@vaadin/dialog": "23.3.5",
"@vaadin/email-field": "23.3.5",
"@vaadin/field-base": "23.3.5",
"@vaadin/field-highlighter": "23.3.5",
"@vaadin/form-layout": "23.3.5",
"@vaadin/grid": "23.3.5",
"@vaadin/horizontal-layout": "23.3.5",
"@vaadin/icon": "23.3.5",
"@vaadin/icons": "23.3.5",
"@vaadin/input-container": "23.3.5",
"@vaadin/integer-field": "23.3.5",
"@vaadin/item": "23.3.5",
"@vaadin/list-box": "23.3.5",
"@vaadin/lit-renderer": "23.3.5",
"@vaadin/login": "23.3.5",
"@vaadin/menu-bar": "23.3.5",
"@vaadin/message-input": "23.3.5",
"@vaadin/message-list": "23.3.5",
"@vaadin/multi-select-combo-box": "23.3.5",
"@vaadin/notification": "23.3.5",
"@vaadin/number-field": "23.3.5",
"@vaadin/password-field": "23.3.5",
"@vaadin/polymer-legacy-adapter": "23.3.5",
"@vaadin/progress-bar": "23.3.5",
"@vaadin/radio-group": "23.3.5",
"@vaadin/router": "1.7.4",
"@vaadin/scroller": "23.3.5",
"@vaadin/select": "23.3.5",
"@vaadin/split-layout": "23.3.5",
"@vaadin/tabs": "23.3.5",
"@vaadin/tabsheet": "23.3.5",
"@vaadin/text-area": "23.3.5",
"@vaadin/text-field": "23.3.5",
"@vaadin/time-picker": "23.3.5",
"@vaadin/tooltip": "23.3.5",
"@vaadin/upload": "23.3.5",
"@vaadin/vaadin-accordion": "23.3.5",
"@vaadin/vaadin-app-layout": "23.3.5",
"@vaadin/vaadin-avatar": "23.3.5",
"@vaadin/vaadin-button": "23.3.5",
"@vaadin/vaadin-checkbox": "23.3.5",
"@vaadin/vaadin-combo-box": "23.3.5",
"@vaadin/vaadin-confirm-dialog": "23.3.5",
"@vaadin/vaadin-context-menu": "23.3.5",
"@vaadin/vaadin-custom-field": "23.3.5",
"@vaadin/vaadin-date-picker": "23.3.5",
"@vaadin/vaadin-date-time-picker": "23.3.5",
"@vaadin/vaadin-details": "23.3.5",
"@vaadin/vaadin-development-mode-detector": "2.0.5",
"@vaadin/vaadin-dialog": "23.3.5",
"@vaadin/vaadin-form-layout": "23.3.5",
"@vaadin/vaadin-grid": "23.3.5",
"@vaadin/vaadin-icon": "23.3.5",
"@vaadin/vaadin-icons": "23.3.5",
"@vaadin/vaadin-item": "23.3.5",
"@vaadin/vaadin-list-box": "23.3.5",
"@vaadin/vaadin-list-mixin": "23.3.5",
"@vaadin/vaadin-login": "23.3.5",
"@vaadin/vaadin-lumo-styles": "23.3.5",
"@vaadin/vaadin-material-styles": "23.3.5",
"@vaadin/vaadin-menu-bar": "23.3.5",
"@vaadin/vaadin-messages": "23.3.5",
"@vaadin/vaadin-notification": "23.3.5",
"@vaadin/vaadin-ordered-layout": "23.3.5",
"@vaadin/vaadin-overlay": "23.3.5",
"@vaadin/vaadin-progress-bar": "23.3.5",
"@vaadin/vaadin-radio-button": "23.3.5",
"@vaadin/vaadin-select": "23.3.5",
"@vaadin/vaadin-split-layout": "23.3.5",
"@vaadin/vaadin-tabs": "23.3.5",
"@vaadin/vaadin-template-renderer": "23.3.5",
"@vaadin/vaadin-text-field": "23.3.5",
"@vaadin/vaadin-themable-mixin": "23.3.5",
"@vaadin/vaadin-time-picker": "23.3.5",
"@vaadin/vaadin-upload": "23.3.5",
"@vaadin/vaadin-usage-statistics": "2.1.2",
"@vaadin/vaadin-virtual-list": "23.3.5",
"@vaadin/vertical-layout": "23.3.5",
"@vaadin/virtual-list": "23.3.5",
"construct-style-sheets-polyfill": "3.1.0",
"date-fns": "2.29.3",
"lit": "2.6.1"
},
"devDependencies": {
"@rollup/plugin-replace": "3.1.0",
"@rollup/pluginutils": "4.1.0",
"async": "3.2.2",
"glob": "7.2.3",
"mkdirp": "1.0.4",
"rollup-plugin-brotli": "3.1.0",
"strip-css-comments": "5.0.0",
"transform-ast": "2.4.4",
"typescript": "4.9.3",
"vite": "3.2.5",
"vite-plugin-checker": "0.5.1",
"workbox-build": "6.5.4",
"workbox-core": "6.5.4",
"workbox-precaching": "6.5.4"
},
"hash": "4fbd84d097de8f423b32ad784ed7600eba86a880677dae141a768b1c60913627"
},
"overrides": {
"@vaadin/bundles": "$@vaadin/bundles",
"@vaadin/accordion": "$@vaadin/accordion",
"@vaadin/app-layout": "$@vaadin/app-layout",
"@vaadin/avatar": "$@vaadin/avatar",
"@vaadin/avatar-group": "$@vaadin/avatar-group",
"@vaadin/button": "$@vaadin/button",
"@vaadin/checkbox": "$@vaadin/checkbox",
"@vaadin/checkbox-group": "$@vaadin/checkbox-group",
"@vaadin/combo-box": "$@vaadin/combo-box",
"@vaadin/component-base": "$@vaadin/component-base",
"@vaadin/confirm-dialog": "$@vaadin/confirm-dialog",
"@vaadin/context-menu": "$@vaadin/context-menu",
"@vaadin/custom-field": "$@vaadin/custom-field",
"@vaadin/date-picker": "$@vaadin/date-picker",
"@vaadin/date-time-picker": "$@vaadin/date-time-picker",
"@vaadin/details": "$@vaadin/details",
"@vaadin/dialog": "$@vaadin/dialog",
"@vaadin/email-field": "$@vaadin/email-field",
"@vaadin/field-base": "$@vaadin/field-base",
"@vaadin/field-highlighter": "$@vaadin/field-highlighter",
"@vaadin/form-layout": "$@vaadin/form-layout",
"@vaadin/grid": "$@vaadin/grid",
"@vaadin/horizontal-layout": "$@vaadin/horizontal-layout",
"@vaadin/icon": "$@vaadin/icon",
"@vaadin/icons": "$@vaadin/icons",
"@vaadin/input-container": "$@vaadin/input-container",
"@vaadin/integer-field": "$@vaadin/integer-field",
"@polymer/iron-icon": "$@polymer/iron-icon",
"@polymer/iron-iconset-svg": "$@polymer/iron-iconset-svg",
"@polymer/iron-list": "$@polymer/iron-list",
"@polymer/iron-meta": "$@polymer/iron-meta",
"@polymer/iron-resizable-behavior": "$@polymer/iron-resizable-behavior",
"@vaadin/item": "$@vaadin/item",
"@vaadin/list-box": "$@vaadin/list-box",
"@vaadin/lit-renderer": "$@vaadin/lit-renderer",
"@vaadin/login": "$@vaadin/login",
"@vaadin/menu-bar": "$@vaadin/menu-bar",
"@vaadin/message-input": "$@vaadin/message-input",
"@vaadin/message-list": "$@vaadin/message-list",
"@vaadin/multi-select-combo-box": "$@vaadin/multi-select-combo-box",
"@vaadin/notification": "$@vaadin/notification",
"@vaadin/number-field": "$@vaadin/number-field",
"@vaadin/password-field": "$@vaadin/password-field",
"@vaadin/polymer-legacy-adapter": "$@vaadin/polymer-legacy-adapter",
"@vaadin/progress-bar": "$@vaadin/progress-bar",
"@vaadin/radio-group": "$@vaadin/radio-group",
"@vaadin/scroller": "$@vaadin/scroller",
"@vaadin/select": "$@vaadin/select",
"@vaadin/split-layout": "$@vaadin/split-layout",
"@vaadin/tabs": "$@vaadin/tabs",
"@vaadin/tabsheet": "$@vaadin/tabsheet",
"@vaadin/text-area": "$@vaadin/text-area",
"@vaadin/text-field": "$@vaadin/text-field",
"@vaadin/time-picker": "$@vaadin/time-picker",
"@vaadin/tooltip": "$@vaadin/tooltip",
"@vaadin/upload": "$@vaadin/upload",
"@vaadin/vaadin-accordion": "$@vaadin/vaadin-accordion",
"@vaadin/vaadin-app-layout": "$@vaadin/vaadin-app-layout",
"@vaadin/vaadin-avatar": "$@vaadin/vaadin-avatar",
"@vaadin/vaadin-button": "$@vaadin/vaadin-button",
"@vaadin/vaadin-checkbox": "$@vaadin/vaadin-checkbox",
"@vaadin/vaadin-combo-box": "$@vaadin/vaadin-combo-box",
"@vaadin/vaadin-confirm-dialog": "$@vaadin/vaadin-confirm-dialog",
"@vaadin/vaadin-context-menu": "$@vaadin/vaadin-context-menu",
"@vaadin/vaadin-custom-field": "$@vaadin/vaadin-custom-field",
"@vaadin/vaadin-date-picker": "$@vaadin/vaadin-date-picker",
"@vaadin/vaadin-date-time-picker": "$@vaadin/vaadin-date-time-picker",
"@vaadin/vaadin-details": "$@vaadin/vaadin-details",
"@vaadin/vaadin-development-mode-detector": "$@vaadin/vaadin-development-mode-detector",
"@vaadin/vaadin-dialog": "$@vaadin/vaadin-dialog",
"@vaadin/vaadin-form-layout": "$@vaadin/vaadin-form-layout",
"@vaadin/vaadin-grid": "$@vaadin/vaadin-grid",
"@vaadin/vaadin-icon": "$@vaadin/vaadin-icon",
"@vaadin/vaadin-icons": "$@vaadin/vaadin-icons",
"@vaadin/vaadin-item": "$@vaadin/vaadin-item",
"@vaadin/vaadin-list-box": "$@vaadin/vaadin-list-box",
"@vaadin/vaadin-list-mixin": "$@vaadin/vaadin-list-mixin",
"@vaadin/vaadin-login": "$@vaadin/vaadin-login",
"@vaadin/vaadin-lumo-styles": "$@vaadin/vaadin-lumo-styles",
"@vaadin/vaadin-material-styles": "$@vaadin/vaadin-material-styles",
"@vaadin/vaadin-menu-bar": "$@vaadin/vaadin-menu-bar",
"@vaadin/vaadin-messages": "$@vaadin/vaadin-messages",
"@vaadin/vaadin-notification": "$@vaadin/vaadin-notification",
"@vaadin/vaadin-ordered-layout": "$@vaadin/vaadin-ordered-layout",
"@vaadin/vaadin-overlay": "$@vaadin/vaadin-overlay",
"@vaadin/vaadin-progress-bar": "$@vaadin/vaadin-progress-bar",
"@vaadin/vaadin-radio-button": "$@vaadin/vaadin-radio-button",
"@vaadin/router": "$@vaadin/router",
"@vaadin/vaadin-select": "$@vaadin/vaadin-select",
"@vaadin/vaadin-split-layout": "$@vaadin/vaadin-split-layout",
"@vaadin/vaadin-tabs": "$@vaadin/vaadin-tabs",
"@vaadin/vaadin-template-renderer": "$@vaadin/vaadin-template-renderer",
"@vaadin/vaadin-text-field": "$@vaadin/vaadin-text-field",
"@vaadin/vaadin-themable-mixin": "$@vaadin/vaadin-themable-mixin",
"@vaadin/vaadin-time-picker": "$@vaadin/vaadin-time-picker",
"@vaadin/vaadin-upload": "$@vaadin/vaadin-upload",
"@vaadin/vaadin-usage-statistics": "$@vaadin/vaadin-usage-statistics",
"@vaadin/vaadin-virtual-list": "$@vaadin/vaadin-virtual-list",
"@vaadin/vertical-layout": "$@vaadin/vertical-layout",
"@vaadin/virtual-list": "$@vaadin/virtual-list",
"@vaadin/common-frontend": "$@vaadin/common-frontend",
"construct-style-sheets-polyfill": "$construct-style-sheets-polyfill",
"lit": "$lit",
"@polymer/polymer": "$@polymer/polymer",
"date-fns": "$date-fns"
}
}

96
pom.xml Normal file
View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.8</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>edu.janmod</groupId>
<artifactId>SvarTalk</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SvarTalk</name>
<description>Projekt komunikatora</description>
<properties>
<java.version>17</java.version>
<vaadin.version>23.3.5</vaadin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-bom</artifactId>
<version>${vaadin.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>production</id>
<build>
<plugins>
<plugin>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-maven-plugin</artifactId>
<version>${vaadin.version}</version>
<executions>
<execution>
<id>frontend</id>
<phase>compile</phase>
<goals>
<goal>prepare-frontend</goal>
<goal>build-frontend</goal>
</goals>
<configuration>
<productionMode>true</productionMode>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,78 @@
package edu.janmod.SvarTalk;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.Key;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.html.Paragraph;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.textfield.EmailField;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.data.binder.Binder;
import com.vaadin.flow.data.binder.ValidationException;
import com.vaadin.flow.router.Route;
@Route("")
public class MainView extends VerticalLayout {
private PersonRepository repository;
private TextField firstName = new TextField("Imię");
private TextField lastName = new TextField("Nazwisko");
private EmailField email = new EmailField("Email");
private Grid<Person> grid = new Grid<>(Person.class);
private Binder<Person> binder = new Binder<>(Person.class);
public MainView(PersonRepository repository) {
this.repository = repository;
grid.setColumns("firstName", "lastName", "email");
add(getForm(), grid);
refreshGrid();
/*var button = new Button("Przycisk");
var textField = new TextField();
add(new HorizontalLayout(textField, button));
button.addClickListener(e -> {
add(new Paragraph("Hello, " + textField.getValue()));
textField.clear();
});*/
/* add(new H1("Hello!")); */
}
private Component getForm() {
var layout = new HorizontalLayout();
layout.setAlignItems(Alignment.BASELINE);
var addButton = new Button("Add");
addButton.addClickShortcut(Key.ENTER);
addButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
layout.add(firstName, lastName, email, addButton);
binder.bindInstanceFields(this);
addButton.addClickListener(click -> {
try{
var person = new Person();
binder.writeBean(person);
repository.save(person);
binder.readBean(new Person());
refreshGrid();
}catch(ValidationException e) {
}
});
return layout;
}
private void refreshGrid() {
grid.setItems(repository.findAll());
}
}

View File

@ -0,0 +1,41 @@
package edu.janmod.SvarTalk;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Person {
@Id
@GeneratedValue
private Long id;
private String firstName;
private String lastName;
private String email;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}

View File

@ -0,0 +1,7 @@
package edu.janmod.SvarTalk;
import org.springframework.data.jpa.repository.JpaRepository;
public interface PersonRepository extends JpaRepository<Person, Long> {
}

View File

@ -0,0 +1,13 @@
package edu.janmod.SvarTalk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SvarTalkApplication {
public static void main(String[] args) {
SpringApplication.run(SvarTalkApplication.class, args);
}
}

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,13 @@
package edu.janmod.SvarTalk;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SvarTalkApplicationTests {
@Test
void contextLoads() {
}
}

37
tsconfig.json Normal file
View File

@ -0,0 +1,37 @@
// This TypeScript configuration file is generated by vaadin-maven-plugin.
// This is needed for TypeScript compiler to compile your TypeScript code in the project.
// It is recommended to commit this file to the VCS.
// You might want to change the configurations to fit your preferences
// For more information about the configurations, please refer to http://www.typescriptlang.org/docs/handbook/tsconfig-json.html
{
"flow_version": "23.3.0.1",
"compilerOptions": {
"sourceMap": true,
"jsx": "react-jsx",
"inlineSources": true,
"module": "esNext",
"target": "es2020",
"moduleResolution": "node",
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noImplicitAny": true,
"noImplicitThis": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"experimentalDecorators": true,
"useDefineForClassFields": false,
"baseUrl": "frontend",
"paths": {
"@vaadin/flow-frontend": ["generated/jar-resources"],
"@vaadin/flow-frontend/*": ["generated/jar-resources/*"],
"Frontend/*": ["*"]
}
},
"include": [
"frontend/**/*",
"types.d.ts"
],
"exclude": []
}

10
types.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
// This TypeScript modules definition file is generated by vaadin-maven-plugin.
// You can not directly import your different static files into TypeScript,
// This is needed for TypeScript compiler to declare and export as a TypeScript module.
// It is recommended to commit this file to the VCS.
// You might want to change the configurations to fit your preferences
declare module '*.css' {
import { CSSResultGroup } from 'lit';
const content: CSSResultGroup;
export default content;
}

9
vite.config.ts Normal file
View File

@ -0,0 +1,9 @@
import { UserConfigFn } from 'vite';
import { overrideVaadinConfig } from './vite.generated';
const customConfig: UserConfigFn = (env) => ({
// Here you can add custom Vite parameters
// https://vitejs.dev/config/
});
export default overrideVaadinConfig(customConfig);

639
vite.generated.ts Normal file
View File

@ -0,0 +1,639 @@
/**
* NOTICE: this is an auto-generated file
*
* This file has been generated by the `flow:prepare-frontend` maven goal.
* This file will be overwritten on every run. Any custom changes should be made to vite.config.ts
*/
import path from 'path';
import { readFileSync, existsSync, writeFileSync, mkdirSync } from 'fs';
import * as net from 'net';
import { processThemeResources } from './target/plugins/application-theme-plugin/theme-handle.js';
import { rewriteCssUrls } from './target/plugins/theme-loader/theme-loader-utils.js';
import settings from './target/vaadin-dev-server-settings.json';
import { defineConfig, mergeConfig, PluginOption, ResolvedConfig, UserConfigFn, OutputOptions, AssetInfo, ChunkInfo } from 'vite';
import { getManifest } from 'workbox-build';
import * as rollup from 'rollup';
import brotli from 'rollup-plugin-brotli';
import replace from '@rollup/plugin-replace';
import checker from 'vite-plugin-checker';
import postcssLit from './target/plugins/rollup-plugin-postcss-lit-custom/rollup-plugin-postcss-lit.js';
const appShellUrl = '.';
const frontendFolder = path.resolve(__dirname, settings.frontendFolder);
const themeFolder = path.resolve(frontendFolder, settings.themeFolder);
const statsFolder = path.resolve(__dirname, settings.statsOutput);
const frontendBundleFolder = path.resolve(__dirname, settings.frontendBundleOutput);
const jarResourcesFolder = path.resolve(__dirname, settings.jarResourcesFolder);
const generatedFlowImportsFolder = path.resolve(__dirname, settings.generatedFlowImportsFolder);
const themeResourceFolder = path.resolve(__dirname, settings.themeResourceFolder);
const statsFile = path.resolve(statsFolder, 'stats.json');
const projectStaticAssetsFolders = [
path.resolve(__dirname, 'src', 'main', 'resources', 'META-INF', 'resources'),
path.resolve(__dirname, 'src', 'main', 'resources', 'static'),
frontendFolder
];
// Folders in the project which can contain application themes
const themeProjectFolders = projectStaticAssetsFolders.map((folder) => path.resolve(folder, settings.themeFolder));
const themeOptions = {
devMode: false,
// The following matches folder 'frontend/generated/themes/'
// (not 'frontend/themes') for theme in JAR that is copied there
themeResourceFolder: path.resolve(themeResourceFolder, settings.themeFolder),
themeProjectFolders: themeProjectFolders,
projectStaticAssetsOutputFolder: path.resolve(__dirname, settings.staticOutput),
frontendGeneratedFolder: path.resolve(frontendFolder, settings.generatedFolder)
};
const hasExportedWebComponents = existsSync(path.resolve(frontendFolder, 'web-component.html'));
// Block debug and trace logs.
console.trace = () => {};
console.debug = () => {};
function injectManifestToSWPlugin(): rollup.Plugin {
const rewriteManifestIndexHtmlUrl = (manifest) => {
const indexEntry = manifest.find((entry) => entry.url === 'index.html');
if (indexEntry) {
indexEntry.url = appShellUrl;
}
return { manifest, warnings: [] };
};
return {
name: 'vaadin:inject-manifest-to-sw',
async transform(code, id) {
if (/sw\.(ts|js)$/.test(id)) {
const { manifestEntries } = await getManifest({
globDirectory: frontendBundleFolder,
globPatterns: ['**/*'],
globIgnores: ['**/*.br'],
manifestTransforms: [rewriteManifestIndexHtmlUrl],
maximumFileSizeToCacheInBytes: 100 * 1024 * 1024, // 100mb,
});
return code.replace('self.__WB_MANIFEST', JSON.stringify(manifestEntries));
}
}
}
}
function buildSWPlugin(opts): PluginOption {
let config: ResolvedConfig;
const devMode = opts.devMode;
const swObj = {}
async function build(action: 'generate' | 'write', additionalPlugins: rollup.Plugin[] = []) {
const includedPluginNames = [
'alias',
'vite:resolve',
'vite:esbuild',
'rollup-plugin-dynamic-import-variables',
'vite:esbuild-transpile',
'vite:terser',
]
const plugins: rollup.Plugin[] = config.plugins.filter((p) => {
return includedPluginNames.includes(p.name)
});
plugins.push(
replace({
values: {
'process.env.NODE_ENV': JSON.stringify(config.mode),
...config.define,
},
preventAssignment: true
})
);
if (additionalPlugins) {
plugins.push(...additionalPlugins);
}
const bundle = await rollup.rollup({
input: path.resolve(settings.clientServiceWorkerSource),
plugins
});
try {
return await bundle[action]({
file: path.resolve(frontendBundleFolder, 'sw.js'),
format: 'es',
exports: 'none',
sourcemap: config.command === 'serve' || config.build.sourcemap,
inlineDynamicImports: true,
});
} finally {
await bundle.close();
}
}
return {
name: 'vaadin:build-sw',
enforce: 'post',
async configResolved(resolvedConfig) {
config = resolvedConfig;
},
async buildStart() {
if (devMode) {
const { output } = await build('generate');
swObj.code = output[0].code;
swObj.map = output[0].map;
}
},
async load(id) {
if (id.endsWith('sw.js')) {
return '';
}
},
async transform(_code, id) {
if (id.endsWith('sw.js')) {
return swObj;
}
},
async closeBundle() {
await build('write', [
injectManifestToSWPlugin(),
brotli(),
]);
}
}
}
function statsExtracterPlugin(): PluginOption {
return {
name: 'vaadin:stats',
enforce: 'post',
async writeBundle(options: OutputOptions, bundle: { [fileName: string]: AssetInfo | ChunkInfo }) {
const modules = Object.values(bundle).flatMap((b) => (b.modules ? Object.keys(b.modules) : []));
const nodeModulesFolders = modules.filter((id) => id.includes('node_modules'));
const npmModules = nodeModulesFolders
.map((id) => id.replace(/.*node_modules./, ''))
.map((id) => {
const parts = id.split('/');
if (id.startsWith('@')) {
return parts[0] + '/' + parts[1];
} else {
return parts[0];
}
})
.sort()
.filter((value, index, self) => self.indexOf(value) === index);
mkdirSync(path.dirname(statsFile), { recursive: true });
writeFileSync(statsFile, JSON.stringify({ npmModules }, null, 1));
}
};
}
function vaadinBundlesPlugin(): PluginOption {
type ExportInfo =
| string
| {
namespace?: string;
source: string;
};
type ExposeInfo = {
exports: ExportInfo[];
};
type PackageInfo = {
version: string;
exposes: Record<string, ExposeInfo>;
};
type BundleJson = {
packages: Record<string, PackageInfo>;
};
const disabledMessage = 'Vaadin component dependency bundles are disabled.';
const modulesDirectory = path.resolve(__dirname, 'node_modules').replace(/\\/g, '/');
let vaadinBundleJson: BundleJson;
function parseModuleId(id: string): { packageName: string; modulePath: string } {
const [scope, scopedPackageName] = id.split('/', 3);
const packageName = scope.startsWith('@') ? `${scope}/${scopedPackageName}` : scope;
const modulePath = `.${id.substring(packageName.length)}`;
return {
packageName,
modulePath
};
}
function getExports(id: string): string[] | undefined {
const { packageName, modulePath } = parseModuleId(id);
const packageInfo = vaadinBundleJson.packages[packageName];
if (!packageInfo) return;
const exposeInfo: ExposeInfo = packageInfo.exposes[modulePath];
if (!exposeInfo) return;
const exportsSet = new Set<string>();
for (const e of exposeInfo.exports) {
if (typeof e === 'string') {
exportsSet.add(e);
} else {
const { namespace, source } = e;
if (namespace) {
exportsSet.add(namespace);
} else {
const sourceExports = getExports(source);
if (sourceExports) {
sourceExports.forEach((e) => exportsSet.add(e));
}
}
}
}
return Array.from(exportsSet);
}
function getExportBinding(binding: string) {
return binding === 'default' ? '_default as default' : binding;
}
function getImportAssigment(binding: string) {
return binding === 'default' ? 'default: _default' : binding;
}
return {
name: 'vaadin:bundles',
enforce: 'pre',
apply(config, { command }) {
if (command !== 'serve') return false;
try {
const vaadinBundleJsonPath = require.resolve('@vaadin/bundles/vaadin-bundle.json');
vaadinBundleJson = JSON.parse(readFileSync(vaadinBundleJsonPath, { encoding: 'utf8' }));
} catch (e: unknown) {
if (typeof e === 'object' && (e as { code: string }).code === 'MODULE_NOT_FOUND') {
vaadinBundleJson = { packages: {} };
console.info(`@vaadin/bundles npm package is not found, ${disabledMessage}`);
return false;
} else {
throw e;
}
}
const versionMismatches: Array<{ name: string; bundledVersion: string; installedVersion: string }> = [];
for (const [name, packageInfo] of Object.entries(vaadinBundleJson.packages)) {
let installedVersion: string | undefined = undefined;
try {
const { version: bundledVersion } = packageInfo;
const installedPackageJsonFile = path.resolve(modulesDirectory, name, 'package.json');
const packageJson = JSON.parse(readFileSync(installedPackageJsonFile, { encoding: 'utf8' }));
installedVersion = packageJson.version;
if (installedVersion && installedVersion !== bundledVersion) {
versionMismatches.push({
name,
bundledVersion,
installedVersion
});
}
} catch (_) {
// ignore package not found
}
}
if (versionMismatches.length) {
console.info(`@vaadin/bundles has version mismatches with installed packages, ${disabledMessage}`);
console.info(`Packages with version mismatches: ${JSON.stringify(versionMismatches, undefined, 2)}`);
vaadinBundleJson = { packages: {} };
return false;
}
return true;
},
async config(config) {
return mergeConfig(
{
optimizeDeps: {
exclude: [
// Vaadin bundle
'@vaadin/bundles',
...Object.keys(vaadinBundleJson.packages)
]
}
},
config
);
},
load(rawId) {
const [path, params] = rawId.split('?');
if (!path.startsWith(modulesDirectory)) return;
const id = path.substring(modulesDirectory.length + 1);
const bindings = getExports(id);
if (bindings === undefined) return;
const cacheSuffix = params ? `?${params}` : '';
const bundlePath = `@vaadin/bundles/vaadin.js${cacheSuffix}`;
return `import { init as VaadinBundleInit, get as VaadinBundleGet } from '${bundlePath}';
await VaadinBundleInit('default');
const { ${bindings.map(getImportAssigment).join(', ')} } = (await VaadinBundleGet('./node_modules/${id}'))();
export { ${bindings.map(getExportBinding).join(', ')} };`;
}
};
}
function themePlugin(opts): PluginOption {
const fullThemeOptions = {...themeOptions, devMode: opts.devMode };
return {
name: 'vaadin:theme',
config() {
processThemeResources(fullThemeOptions, console);
},
configureServer(server) {
function handleThemeFileCreateDelete(themeFile, stats) {
if (themeFile.startsWith(themeFolder)) {
const changed = path.relative(themeFolder, themeFile)
console.debug('Theme file ' + (!!stats ? 'created' : 'deleted'), changed);
processThemeResources(fullThemeOptions, console);
}
}
server.watcher.on('add', handleThemeFileCreateDelete);
server.watcher.on('unlink', handleThemeFileCreateDelete);
},
handleHotUpdate(context) {
const contextPath = path.resolve(context.file);
const themePath = path.resolve(themeFolder);
if (contextPath.startsWith(themePath)) {
const changed = path.relative(themePath, contextPath);
console.debug('Theme file changed', changed);
if (changed.startsWith(settings.themeName)) {
processThemeResources(fullThemeOptions, console);
}
}
},
async resolveId(id, importer) {
// force theme generation if generated theme sources does not yet exist
// this may happen for example during Java hot reload when updating
// @Theme annotation value
if (path.resolve(themeOptions.frontendGeneratedFolder, "theme.js") === importer &&
!existsSync(path.resolve(themeOptions.frontendGeneratedFolder, id))) {
console.debug('Generate theme file ' + id + ' not existing. Processing theme resource');
processThemeResources(fullThemeOptions, console);
return;
}
if (!id.startsWith(settings.themeFolder)) {
return;
}
for (const location of [themeResourceFolder, frontendFolder]) {
const result = await this.resolve(path.resolve(location, id));
if (result) {
return result;
}
}
},
async transform(raw, id, options) {
// rewrite urls for the application theme css files
const [bareId, query] = id.split('?');
if (!bareId?.startsWith(themeFolder) || !bareId?.endsWith('.css')) {
return;
}
const [themeName] = bareId.substring(themeFolder.length + 1).split('/');
return rewriteCssUrls(raw, path.dirname(bareId), path.resolve(themeFolder, themeName), console, opts);
}
};
}
function lenientLitImportPlugin(): PluginOption {
return {
name: 'vaadin:lenient-lit-import',
async transform(code, id) {
const decoratorImports = [
/import (.*?) from (['"])(lit\/decorators)(['"])/,
/import (.*?) from (['"])(lit-element\/decorators)(['"])/
];
const directiveImports = [
/import (.*?) from (['"])(lit\/directives\/)([^\\.]*?)(['"])/,
/import (.*?) from (['"])(lit-html\/directives\/)([^\\.]*?)(['"])/
];
decoratorImports.forEach((decoratorImport) => {
let decoratorMatch;
while ((decoratorMatch = code.match(decoratorImport))) {
console.warn(
`Warning: the file ${id} imports from '${decoratorMatch[3]}' when it should import from '${decoratorMatch[3]}.js'`
);
code = code.replace(decoratorImport, 'import $1 from $2$3.js$4');
}
});
directiveImports.forEach((directiveImport) => {
let directiveMatch;
while ((directiveMatch = code.match(directiveImport))) {
console.warn(
`Warning: the file ${id} imports from '${directiveMatch[3]}${directiveMatch[4]}' when it should import from '${directiveMatch[3]}${directiveMatch[4]}.js'`
);
code = code.replace(directiveImport, 'import $1 from $2$3$4.js$5');
}
});
return code;
}
};
}
function runWatchDog(watchDogPort, watchDogHost) {
const client = net.Socket();
client.setEncoding('utf8');
client.on('error', function (err) {
console.log('Watchdog connection error. Terminating vite process...', err);
client.destroy();
process.exit(0);
});
client.on('close', function () {
client.destroy();
runWatchDog(watchDogPort, watchDogHost);
});
client.connect(watchDogPort, watchDogHost || 'localhost');
}
let spaMiddlewareForceRemoved = false;
const allowedFrontendFolders = [
frontendFolder,
path.resolve(generatedFlowImportsFolder), // Contains only generated-flow-imports
path.resolve(__dirname, 'node_modules')
];
function setHmrPortToServerPort(): PluginOption {
return {
name: 'set-hmr-port-to-server-port',
configResolved(config) {
if (config.server.strictPort && config.server.hmr !== false) {
if (config.server.hmr === true) config.server.hmr = {};
config.server.hmr = config.server.hmr || {};
config.server.hmr.clientPort = config.server.port;
}
}
};
}
function showRecompileReason(): PluginOption {
return {
name: 'vaadin:why-you-compile',
handleHotUpdate(context) {
console.log('Recompiling because', context.file, 'changed');
}
};
}
export const vaadinConfig: UserConfigFn = (env) => {
const devMode = env.mode === 'development';
if (devMode && process.env.watchDogPort) {
// Open a connection with the Java dev-mode handler in order to finish
// vite when it exits or crashes.
runWatchDog(process.env.watchDogPort, process.env.watchDogHost);
}
return {
root: frontendFolder,
base: '',
resolve: {
alias: {
'@vaadin/flow-frontend': jarResourcesFolder,
Frontend: frontendFolder
},
preserveSymlinks: true
},
define: {
OFFLINE_PATH: settings.offlinePath,
VITE_ENABLED: 'true'
},
server: {
host: '127.0.0.1',
strictPort: true,
fs: {
allow: allowedFrontendFolders
}
},
build: {
outDir: frontendBundleFolder,
assetsDir: 'VAADIN/build',
rollupOptions: {
input: {
indexhtml: path.resolve(frontendFolder, 'index.html'),
...hasExportedWebComponents
? { webcomponenthtml: path.resolve(frontendFolder, 'web-component.html') }
: {}
}
}
},
optimizeDeps: {
entries: [
// Pre-scan entrypoints in Vite to avoid reloading on first open
'generated/vaadin.ts'
],
exclude: [
'@vaadin/router',
'@vaadin/vaadin-license-checker',
'@vaadin/vaadin-usage-statistics',
'workbox-core',
'workbox-precaching',
'workbox-routing',
'workbox-strategies'
]
},
plugins: [
!devMode && brotli(),
devMode && vaadinBundlesPlugin(),
devMode && setHmrPortToServerPort(),
devMode && showRecompileReason(),
settings.offlineEnabled && buildSWPlugin({ devMode }),
!devMode && statsExtracterPlugin(),
themePlugin({devMode}),
lenientLitImportPlugin(),
postcssLit({
include: ['**/*.css', '**/*.css\?*'],
exclude: [
`${themeFolder}/**/*.css`,
`${themeFolder}/**/*.css\?*`,
`${themeResourceFolder}/**/*.css`,
`${themeResourceFolder}/**/*.css\?*`,
'**/*\?html-proxy*'
]
}),
{
name: 'vaadin:force-remove-html-middleware',
transformIndexHtml: {
enforce: 'pre',
transform(_html, { server }) {
if (server && !spaMiddlewareForceRemoved) {
server.middlewares.stack = server.middlewares.stack.filter((mw) => {
const handleName = '' + mw.handle;
return !handleName.includes('viteHtmlFallbackMiddleware');
});
spaMiddlewareForceRemoved = true;
}
}
}
},
hasExportedWebComponents && {
name: 'vaadin:inject-entrypoints-to-web-component-html',
transformIndexHtml: {
enforce: 'pre',
transform(_html, { path, server }) {
if (path !== '/web-component.html') {
return;
}
return [
{
tag: 'script',
attrs: { type: 'module', src: `/generated/vaadin-web-component.ts` },
injectTo: 'head'
}
]
}
}
},
{
name: 'vaadin:inject-entrypoints-to-index-html',
transformIndexHtml: {
enforce: 'pre',
transform(_html, { path, server }) {
if (path !== '/index.html') {
return;
}
const scripts = [];
if (devMode) {
scripts.push({
tag: 'script',
attrs: { type: 'module', src: `/generated/vite-devmode.ts` },
injectTo: 'head'
});
}
scripts.push({
tag: 'script',
attrs: { type: 'module', src: '/generated/vaadin.ts' },
injectTo: 'head'
});
return scripts;
}
}
},
checker({
typescript: true
})
]
};
};
export const overrideVaadinConfig = (customConfig: UserConfigFn) => {
return defineConfig((env) => mergeConfig(vaadinConfig(env), customConfig(env)));
};