mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
b8b5190bc6
Currently, some of the things on the playground must be changed directly on the master branch while other things require checking out the gh-pages branch and making the modifications there. Even when changes need to be made on the master branch, all changes that are not direcly in owl itself need to be copied by hand to the gh-pages branch. This commit moves all files that exist on the gh-pages branch to the master branch in the docs folder, this change will require configuring the github page to use the docs folder instead of a separate branch, but will make maintenance of the github page and playground easier going forward.
193 lines
5.1 KiB
JavaScript
193 lines
5.1 KiB
JavaScript
// This example is slightly more complex than usual. We demonstrate
|
|
// here a way to manage sub windows in Owl, declaratively. This is still just a
|
|
// demonstration. Managing windows can be as complex as we want. For example,
|
|
// we could implement the following features:
|
|
// - resizing windows
|
|
// - minimizing windows
|
|
// - configuration options for windows to make a window non resizeable
|
|
// - minimal width/height
|
|
// - better heuristic for initial window position
|
|
// - ...
|
|
import { Component, useState, mount, useRef, reactive, useEnv, onMounted } from "@odoo/owl";
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Window manager code
|
|
// -----------------------------------------------------------------------------
|
|
|
|
class WindowManager {
|
|
// contains all components with metadata
|
|
static Windows = {};
|
|
windows = {}; // mapping id => info
|
|
nextId = 1;
|
|
|
|
add(type) {
|
|
const Comp = WindowManager.Windows[type];
|
|
const left = 50 + Math.round(Math.random()*(window.innerWidth - 50 - Comp.defaultWidth));
|
|
const top = 50 + Math.round(Math.random()*(window.innerHeight - 100 - Comp.defaultHeight));
|
|
const id = this.nextId++;
|
|
this.windows[id] = {
|
|
id,
|
|
title: Comp.defaultTitle,
|
|
width: Comp.defaultWidth,
|
|
height: Comp.defaultHeight,
|
|
left,
|
|
top,
|
|
Component: Comp,
|
|
};
|
|
}
|
|
|
|
close(id) {
|
|
delete this.windows[id];
|
|
}
|
|
|
|
updatePosition(id, left, top) {
|
|
const w = this.windows[id];
|
|
w.left = left;
|
|
w.top = top;
|
|
}
|
|
|
|
getWindows() {
|
|
return Object.values(this.windows);
|
|
}
|
|
}
|
|
|
|
function createWindowService() {
|
|
return reactive(new WindowManager());
|
|
}
|
|
|
|
function useWindowService() {
|
|
const env = useEnv();
|
|
return useState(env.windowService);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Generic Window Component
|
|
// -----------------------------------------------------------------------------
|
|
|
|
class Window extends Component {
|
|
static template = "Window";
|
|
static nextZIndex = 1;
|
|
zIndex = 0;
|
|
|
|
setup() {
|
|
this.windowService = useWindowService();
|
|
this.root = useRef('root');
|
|
onMounted(this.updateZIndex);
|
|
}
|
|
|
|
get style() {
|
|
let { width, height, top, left } = this.props.info;
|
|
return `width: ${width}px;height: ${height}px;top:${top}px;left:${left}px;z-index:${this.zIndex}`;
|
|
}
|
|
|
|
close() {
|
|
this.windowService.close(this.props.info.id);
|
|
}
|
|
|
|
startDragAndDrop(ev) {
|
|
this.updateZIndex();
|
|
const self = this;
|
|
const root = this.root;
|
|
|
|
const el = root.el;
|
|
el.classList.add('dragging');
|
|
|
|
const current = this.props.info;
|
|
const offsetX = current.left - ev.pageX;
|
|
const offsetY = current.top - ev.pageY;
|
|
let left, top;
|
|
|
|
window.addEventListener("mousemove", moveWindow);
|
|
window.addEventListener("mouseup", stopDnD, { once: true });
|
|
|
|
function moveWindow(ev) {
|
|
left = Math.max(offsetX + ev.pageX, 0);
|
|
top = Math.max(offsetY + ev.pageY, 0);
|
|
el.style.left = `${left}px`;
|
|
el.style.top = `${top}px`;
|
|
}
|
|
function stopDnD() {
|
|
window.removeEventListener("mousemove", moveWindow);
|
|
el.classList.remove('dragging');
|
|
|
|
if (top !== undefined && left !== undefined) {
|
|
self.windowService.updatePosition(current.id, left, top);
|
|
}
|
|
}
|
|
}
|
|
|
|
updateZIndex() {
|
|
this.zIndex = Window.nextZIndex++;
|
|
this.root.el.style['z-index'] = this.zIndex;
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Two concrete Window type implementations
|
|
// -----------------------------------------------------------------------------
|
|
|
|
class HelloWorld extends Component {
|
|
static template = "HelloWorld";
|
|
static defaultTitle = "Hello Owl!";
|
|
static defaultWidth = 200;
|
|
static defaultHeight = 100;
|
|
}
|
|
|
|
|
|
class Counter extends Component {
|
|
static template = "Counter";
|
|
static defaultTitle = "Click Counter";
|
|
static defaultWidth = 300;
|
|
static defaultHeight = 120;
|
|
|
|
state = useState({ value: 0 });
|
|
|
|
inc() {
|
|
this.state.value++;
|
|
}
|
|
}
|
|
|
|
// register window components
|
|
WindowManager.Windows.Hello = HelloWorld;
|
|
WindowManager.Windows.Counter = Counter;
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Window Container
|
|
// -----------------------------------------------------------------------------
|
|
|
|
class WindowContainer extends Component {
|
|
static template = "WindowContainer";
|
|
static components = { Window };
|
|
|
|
setup() {
|
|
this.windowService = useWindowService();
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Root Component
|
|
// -----------------------------------------------------------------------------
|
|
|
|
class Root extends Component {
|
|
static template = "Root";
|
|
static components = { WindowContainer };
|
|
|
|
setup() {
|
|
this.windowService = useWindowService();
|
|
}
|
|
|
|
addWindow(type) {
|
|
this.windowService.add(type);
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Setup
|
|
// -----------------------------------------------------------------------------
|
|
|
|
const env = {
|
|
windowService: createWindowService(),
|
|
};
|
|
|
|
mount(Root, document.body, { templates: TEMPLATES, env, dev: true });
|