@print-one/grapesjs
Version:
Free and Open Source Web Builder Framework
222 lines (202 loc) • 6.59 kB
text/typescript
/**
* You can customize the initial state of the module from the editor initialization, by passing the following [Configuration Object](https://github.com/GrapesJS/grapesjs/blob/master/src/device_manager/config/config.ts)
* ```js
* const editor = grapesjs.init({
* deviceManager: {
* // options
* }
* })
* ```
*
* Once the editor is instantiated you can use its API. Before using these methods you should get the module from the instance
*
* ```js
* const deviceManager = editor.Devices;
* ```
* ## Available Events
* * `device:add` - Added new device. The [Device] is passed as an argument to the callback
* * `device:remove` - Device removed. The [Device] is passed as an argument to the callback
* * `device:select` - New device selected. The newly selected [Device] and the previous one, are passed as arguments to the callback
* * `device:update` - Device updated. The updated [Device] and the object containing changes are passed as arguments to the callback
* * `device` - Catch-all event for all the events mentioned above. An object containing all the available data about the triggered event is passed as an argument to the callback
*
* ## Methods
* * [add](#add)
* * [get](#get)
* * [getDevices](#getdevices)
* * [remove](#remove)
* * [select](#select)
* * [getSelected](#getselected)
*
* [Device]: device.html
*
* @module Devices
*/
import { isString } from 'underscore';
import { ItemManagerModule } from '../abstract/Module';
import EditorModel from '../editor/model/Editor';
import defaults, { DeviceManagerConfig } from './config/config';
import Device, { DeviceProperties } from './model/Device';
import Devices from './model/Devices';
import DevicesView from './view/DevicesView';
export const evAll = 'device';
export const evPfx = `${evAll}:`;
export const evSelect = `${evPfx}select`;
export const evSelectBefore = `${evSelect}:before`;
export const evUpdate = `${evPfx}update`;
export const evAdd = `${evPfx}add`;
export const evAddBefore = `${evAdd}:before`;
export const evRemove = `${evPfx}remove`;
export const evRemoveBefore = `${evRemove}:before`;
const chnSel = 'change:device';
const deviceEvents = {
all: evAll,
select: evSelect,
update: evUpdate,
add: evAdd,
remove: evRemove,
removeBefore: evRemoveBefore,
};
export default class DeviceManager extends ItemManagerModule<
DeviceManagerConfig & { appendTo?: HTMLElement | string },
Devices
> {
devices: Devices;
events!: typeof deviceEvents;
view?: DevicesView;
Device = Device;
Devices = Devices;
storageKey = '';
constructor(em: EditorModel) {
super(em, 'DeviceManager', new Devices(), deviceEvents, defaults);
this.devices = this.all;
this.config.devices?.forEach(device => this.add(device, { silent: true }));
this.select(this.config.default || this.devices.at(0));
em.on(chnSel, this._onSelect, this);
return this;
}
_onSelect(m: EditorModel, deviceId: string, opts: Record<string, any>) {
const { em, events } = this;
const prevId = m.previous('device');
const newDevice = this.get(deviceId);
const ev = events.select;
em.trigger(ev, newDevice, this.get(prevId));
this.__catchAllEvent(ev, newDevice, opts);
}
/**
* Add new device
* @param {Object} props Device properties
* @returns {[Device]} Added device
* @example
* const device1 = deviceManager.add({
* // Without an explicit ID, the `name` will be taken. In case of missing `name`, a random ID will be created.
* id: 'tablet',
* name: 'Tablet',
* width: '900px', // This width will be applied on the canvas frame and for the CSS media
* });
* const device2 = deviceManager.add({
* id: 'tablet2',
* name: 'Tablet 2',
* width: '800px', // This width will be applied on the canvas frame
* widthMedia: '810px', // This width that will be used for the CSS media
* height: '600px', // Height will be applied on the canvas frame
* });
*/
add(props: DeviceProperties, options: Record<string, any> = {}) {
let result;
let opts = options;
// Support old API
if (isString(props)) {
const width = options;
opts = arguments[2] || {};
result = {
...opts,
id: props,
name: opts.name || props,
width,
};
} else {
result = props;
}
if (!result.id) {
result.id = result.name || this._createId();
}
return this.devices.add(result, opts);
}
/**
* Return device by ID
* @param {String} id ID of the device
* @returns {[Device]|null}
* @example
* const device = deviceManager.get('Tablet');
* console.log(JSON.stringify(device));
* // {name: 'Tablet', width: '900px'}
*/
get(id: string): Device | undefined {
// Support old API
const byName = this.getAll().filter(d => d.get('name') === id)[0];
return byName || this.devices.get(id) || null;
}
/**
* Remove device
* @param {String|[Device]} device Device or device id
* @returns {[Device]} Removed device
* @example
* const removed = deviceManager.remove('device-id');
* // or by passing the Device
* const device = deviceManager.get('device-id');
* deviceManager.remove(device);
*/
remove(device: string | Device, opts = {}) {
return this.__remove(device, opts);
}
/**
* Return all devices
* @returns {Array<[Device]>}
* @example
* const devices = deviceManager.getDevices();
* console.log(JSON.stringify(devices));
* // [{name: 'Desktop', width: ''}, ...]
*/
getDevices() {
return this.devices.models;
}
/**
* Change the selected device. This will update the frame in the canvas
* @param {String|[Device]} device Device or device id
* @example
* deviceManager.select('some-id');
* // or by passing the page
* const device = deviceManager.get('some-id');
* deviceManager.select(device);
*/
select(device: string | Device, opts = {}) {
const md = isString(device) ? this.get(device) : device;
md && this.em.set('device', md.get('id'), opts);
return this;
}
/**
* Get the selected device
* @returns {[Device]}
* @example
* const selected = deviceManager.getSelected();
*/
getSelected() {
return this.get(this.em.get('device'));
}
getAll() {
return this.devices;
}
render() {
const { em } = this;
this.view?.remove();
this.view = new DevicesView({
collection: this.devices,
config: { em, ...this.config },
});
return this.view.render().el;
}
destroy() {
this.__destroy();
}
}