First working sitemap version.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
PYTHON_PATH=/opt/ros/indigo/lib/python2.7/dist-packages
|
||||
PYTHON_PATH=/home/matzman/tmp/ros_catkin_ws/install_isolated/lib/python2.7/dist-packages
|
||||
|
||||
# delete old files
|
||||
rm -rf devel devel_isolated build build_isolated install install_isolated
|
||||
|
||||
-1
@@ -62,7 +62,6 @@ void DeviceImpl::handleCommandMsg(const Variant& msg, const timestamp_t& stamp)
|
||||
|
||||
|
||||
void DeviceImpl::sendCommand(const Variant& cmd) {
|
||||
std::lock_guard<std::recursive_mutex> lock(objMutex);
|
||||
parent->sendDeviceCommand(this, cmd);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
{
|
||||
"type": "sitemap/sitemap_template",
|
||||
"title": "TestApp",
|
||||
"rootpage": {
|
||||
"rootpage": "page01",
|
||||
"pages": {
|
||||
"page01": {
|
||||
"type": "sitemap/sitemap_template#/definitions/page",
|
||||
"title": "Root Page",
|
||||
"elements": [
|
||||
{
|
||||
"type": "sitemap/sitemap_template#/definitions/text_element",
|
||||
"label": "Switch0 Text",
|
||||
"type": "sitemap/sitemap_template#/definitions/frame_element",
|
||||
"label": "Group 0",
|
||||
"icon" : "some_icon01",
|
||||
"format" : "Format: %1%",
|
||||
"elements" : [
|
||||
{
|
||||
"type": "sitemap/sitemap_template#/definitions/text_element",
|
||||
"label": "Switch0",
|
||||
"icon" : "some_icon01",
|
||||
"format" : "Value: %1%",
|
||||
"linkedPage" : "page02",
|
||||
"device": {
|
||||
"id": "dummySwitch0",
|
||||
"pointer": "/switch/value"
|
||||
@@ -18,10 +26,25 @@
|
||||
"type": "sitemap/sitemap_template#/definitions/switch_element",
|
||||
"label": "Switch0",
|
||||
"icon" : "some_icon02",
|
||||
"format" : "bla: %1%",
|
||||
"linkedPage" : "page02",
|
||||
"device": {
|
||||
"id": "dummySwitch0",
|
||||
"pointer": "/switch/value"
|
||||
},
|
||||
"commandTemplate": {
|
||||
"switch": {
|
||||
"set": null
|
||||
}
|
||||
},
|
||||
"commandValuePointer": "/switch/set"
|
||||
}, {
|
||||
"type": "sitemap/sitemap_template#/definitions/text_element",
|
||||
"label": "Slider0",
|
||||
"icon" : "some_icon01",
|
||||
"format" : "Value: %1%",
|
||||
"device": {
|
||||
"id": "dummyDimmer0",
|
||||
"pointer": "/dimmer/value"
|
||||
}
|
||||
}, {
|
||||
"type": "sitemap/sitemap_template#/definitions/slider_element",
|
||||
@@ -33,8 +56,236 @@
|
||||
},
|
||||
"min": 0,
|
||||
"max": 1,
|
||||
"step": 0.1
|
||||
"step": 0.1,
|
||||
"commandTemplate": {
|
||||
"dimmer": {
|
||||
"set": null
|
||||
}
|
||||
},
|
||||
"commandValuePointer": "/dimmer/set"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "sitemap/sitemap_template#/definitions/frame_element",
|
||||
"label": "Group 1",
|
||||
"icon" : "some_icon01",
|
||||
"elements" : [
|
||||
{
|
||||
"type": "sitemap/sitemap_template#/definitions/text_element",
|
||||
"label": "Switch1",
|
||||
"icon" : "some_icon01",
|
||||
"format" : "Value: %1%",
|
||||
"device": {
|
||||
"id": "dummySwitch1",
|
||||
"pointer": "/switch/value"
|
||||
}
|
||||
}, {
|
||||
"type": "sitemap/sitemap_template#/definitions/switch_element",
|
||||
"label": "Switch1",
|
||||
"icon" : "some_icon02",
|
||||
"device": {
|
||||
"id": "dummySwitch1",
|
||||
"pointer": "/switch/value"
|
||||
},
|
||||
"commandTemplate": {
|
||||
"switch": {
|
||||
"set": null
|
||||
}
|
||||
},
|
||||
"commandValuePointer": "/switch/set"
|
||||
}, {
|
||||
"type": "sitemap/sitemap_template#/definitions/text_element",
|
||||
"label": "Slider1",
|
||||
"icon" : "some_icon01",
|
||||
"format" : "Value: %1%",
|
||||
"device": {
|
||||
"id": "dummyDimmer1",
|
||||
"pointer": "/dimmer/value"
|
||||
}
|
||||
}, {
|
||||
"type": "sitemap/sitemap_template#/definitions/slider_element",
|
||||
"label": "Slider1",
|
||||
"icon" : "some_icon03",
|
||||
"device": {
|
||||
"id": "dummyDimmer1",
|
||||
"pointer": "/dimmer/value"
|
||||
},
|
||||
"min": 0,
|
||||
"max": 1,
|
||||
"step": 0.1,
|
||||
"commandTemplate": {
|
||||
"dimmer": {
|
||||
"set": null
|
||||
}
|
||||
},
|
||||
"commandValuePointer": "/dimmer/set"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "sitemap/sitemap_template#/definitions/frame_element",
|
||||
"label": "Group 2",
|
||||
"icon" : "some_icon01",
|
||||
"elements" : [
|
||||
{
|
||||
"type": "sitemap/sitemap_template#/definitions/text_element",
|
||||
"label": "Switch2",
|
||||
"icon" : "some_icon01",
|
||||
"format" : "Value: %1%",
|
||||
"device": {
|
||||
"id": "dummySwitch2",
|
||||
"pointer": "/switch/value"
|
||||
}
|
||||
}, {
|
||||
"type": "sitemap/sitemap_template#/definitions/switch_element",
|
||||
"label": "Switch2",
|
||||
"icon" : "some_icon02",
|
||||
"device": {
|
||||
"id": "dummySwitch2",
|
||||
"pointer": "/switch/value"
|
||||
},
|
||||
"commandTemplate": {
|
||||
"switch": {
|
||||
"set": null
|
||||
}
|
||||
},
|
||||
"commandValuePointer": "/switch/set"
|
||||
}, {
|
||||
"type": "sitemap/sitemap_template#/definitions/text_element",
|
||||
"label": "Slider2",
|
||||
"icon" : "some_icon01",
|
||||
"format" : "Value: %1%",
|
||||
"device": {
|
||||
"id": "dummyDimmer2",
|
||||
"pointer": "/dimmer/value"
|
||||
}
|
||||
}, {
|
||||
"type": "sitemap/sitemap_template#/definitions/slider_element",
|
||||
"label": "Slider2",
|
||||
"icon" : "some_icon03",
|
||||
"device": {
|
||||
"id": "dummyDimmer2",
|
||||
"pointer": "/dimmer/value"
|
||||
},
|
||||
"min": 0,
|
||||
"max": 1,
|
||||
"step": 0.1,
|
||||
"commandTemplate": {
|
||||
"dimmer": {
|
||||
"set": null
|
||||
}
|
||||
},
|
||||
"commandValuePointer": "/dimmer/set"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "sitemap/sitemap_template#/definitions/frame_element",
|
||||
"label": "Group 3",
|
||||
"icon" : "some_icon01",
|
||||
"elements" : [
|
||||
{
|
||||
"type": "sitemap/sitemap_template#/definitions/text_element",
|
||||
"label": "Switch3",
|
||||
"icon" : "some_icon01",
|
||||
"format" : "Value: %1%",
|
||||
"device": {
|
||||
"id": "dummySwitch3",
|
||||
"pointer": "/switch/value"
|
||||
}
|
||||
}, {
|
||||
"type": "sitemap/sitemap_template#/definitions/switch_element",
|
||||
"label": "Switch3",
|
||||
"icon" : "some_icon02",
|
||||
"device": {
|
||||
"id": "dummySwitch3",
|
||||
"pointer": "/switch/value"
|
||||
},
|
||||
"commandTemplate": {
|
||||
"switch": {
|
||||
"set": null
|
||||
}
|
||||
},
|
||||
"commandValuePointer": "/switch/set"
|
||||
}, {
|
||||
"type": "sitemap/sitemap_template#/definitions/text_element",
|
||||
"label": "Slider3",
|
||||
"icon" : "some_icon01",
|
||||
"format" : "Value: %1%",
|
||||
"device": {
|
||||
"id": "dummyDimmer3",
|
||||
"pointer": "/dimmer/value"
|
||||
}
|
||||
}, {
|
||||
"type": "sitemap/sitemap_template#/definitions/slider_element",
|
||||
"label": "Slider3",
|
||||
"icon" : "some_icon03",
|
||||
"device": {
|
||||
"id": "dummyDimmer3",
|
||||
"pointer": "/dimmer/value"
|
||||
},
|
||||
"min": 0,
|
||||
"max": 1,
|
||||
"step": 0.1,
|
||||
"commandTemplate": {
|
||||
"dimmer": {
|
||||
"set": null
|
||||
}
|
||||
},
|
||||
"commandValuePointer": "/dimmer/set"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"page02": {
|
||||
"type": "sitemap/sitemap_template#/definitions/page",
|
||||
"title": "Page 2",
|
||||
"elements": [
|
||||
{
|
||||
"type": "sitemap/sitemap_template#/definitions/frame_element",
|
||||
"label": "Some Text",
|
||||
"icon" : "some_icon01",
|
||||
"elements" : [
|
||||
{
|
||||
"type": "sitemap/sitemap_template#/definitions/text_element",
|
||||
"label": "Switch0 Text",
|
||||
"icon" : "some_icon01",
|
||||
"format" : "blabla: %1%",
|
||||
"device": {
|
||||
"id": "dummyDimmer1",
|
||||
"pointer": "/dimmer/value"
|
||||
},
|
||||
"linkedPage" : "page03"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"page03": {
|
||||
"type": "sitemap/sitemap_template#/definitions/page",
|
||||
"title": "Page 3",
|
||||
"elements": [
|
||||
{
|
||||
"type": "sitemap/sitemap_template#/definitions/frame_element",
|
||||
"label": "Some Text 2",
|
||||
"icon" : "some_icon01",
|
||||
"elements" : [
|
||||
{
|
||||
"type": "sitemap/sitemap_template#/definitions/text_element",
|
||||
"label": "Switch2 Text",
|
||||
"icon" : "some_icon01",
|
||||
"format" : "blabla: %1%",
|
||||
"device": {
|
||||
"id": "dummyDimmer3",
|
||||
"pointer": "/dimmer/value"
|
||||
},
|
||||
"linkedPage" : "page01"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
{
|
||||
"type": "sitemap/sitemap_template",
|
||||
"title": "Hue Lights App",
|
||||
"rootpage": "page01",
|
||||
"pages": {
|
||||
"page01": {
|
||||
"type": "sitemap/sitemap_template#/definitions/page",
|
||||
"title": "My Room",
|
||||
"elements": [
|
||||
{
|
||||
"type": "sitemap/sitemap_template#/definitions/frame_element",
|
||||
"label": "Lightstrips 1",
|
||||
"icon" : "some_icon01",
|
||||
"elements" : [
|
||||
{
|
||||
"type": "sitemap/sitemap_template#/definitions/switch_element",
|
||||
"label": "Lightstrips 1 Switch",
|
||||
"icon" : "some_icon02",
|
||||
"device": {
|
||||
"id": "huelight1",
|
||||
"pointer": "/switch/value"
|
||||
},
|
||||
"commandTemplate": {
|
||||
"switch": {
|
||||
"set": null
|
||||
}
|
||||
},
|
||||
"commandValuePointer": "/switch/set"
|
||||
}, {
|
||||
"type": "sitemap/sitemap_template#/definitions/slider_element",
|
||||
"label": "Lightstrips 1 Slider",
|
||||
"icon" : "some_icon03",
|
||||
"device": {
|
||||
"id": "huelight1",
|
||||
"pointer": "/brightness/value"
|
||||
},
|
||||
"min": 0,
|
||||
"max": 1,
|
||||
"step": 0.1,
|
||||
"commandTemplate": {
|
||||
"brightness": {
|
||||
"set": null
|
||||
}
|
||||
},
|
||||
"commandValuePointer": "/brightness/set"
|
||||
}
|
||||
]
|
||||
}, {
|
||||
"type": "sitemap/sitemap_template#/definitions/frame_element",
|
||||
"label": "Lightstrips 2",
|
||||
"icon" : "some_icon01",
|
||||
"elements" : [
|
||||
{
|
||||
"type": "sitemap/sitemap_template#/definitions/switch_element",
|
||||
"label": "Lightstrips 2 Switch",
|
||||
"icon" : "some_icon02",
|
||||
"device": {
|
||||
"id": "huelight2",
|
||||
"pointer": "/switch/value"
|
||||
},
|
||||
"commandTemplate": {
|
||||
"switch": {
|
||||
"set": null
|
||||
}
|
||||
},
|
||||
"commandValuePointer": "/switch/set"
|
||||
}, {
|
||||
"type": "sitemap/sitemap_template#/definitions/slider_element",
|
||||
"label": "Lightstrips 2 Slider",
|
||||
"icon" : "some_icon03",
|
||||
"device": {
|
||||
"id": "huelight2",
|
||||
"pointer": "/brightness/value"
|
||||
},
|
||||
"min": 0,
|
||||
"max": 1,
|
||||
"step": 0.1,
|
||||
"commandTemplate": {
|
||||
"brightness": {
|
||||
"set": null
|
||||
}
|
||||
},
|
||||
"commandValuePointer": "/brightness/set"
|
||||
}
|
||||
]
|
||||
}, {
|
||||
"type": "sitemap/sitemap_template#/definitions/frame_element",
|
||||
"label": "ZimmerLampe",
|
||||
"icon" : "some_icon01",
|
||||
"elements" : [
|
||||
{
|
||||
"type": "sitemap/sitemap_template#/definitions/switch_element",
|
||||
"label": "ZimmerLampe Switch",
|
||||
"icon" : "some_icon02",
|
||||
"device": {
|
||||
"id": "huelight3",
|
||||
"pointer": "/switch/value"
|
||||
},
|
||||
"commandTemplate": {
|
||||
"switch": {
|
||||
"set": null
|
||||
}
|
||||
},
|
||||
"commandValuePointer": "/switch/set"
|
||||
}, {
|
||||
"type": "sitemap/sitemap_template#/definitions/slider_element",
|
||||
"label": "ZimmerLampe Slider",
|
||||
"icon" : "some_icon03",
|
||||
"device": {
|
||||
"id": "huelight3",
|
||||
"pointer": "/brightness/value"
|
||||
},
|
||||
"min": 0,
|
||||
"max": 1,
|
||||
"step": 0.1,
|
||||
"commandTemplate": {
|
||||
"brightness": {
|
||||
"set": null
|
||||
}
|
||||
},
|
||||
"commandValuePointer": "/brightness/set"
|
||||
}
|
||||
]
|
||||
}, {
|
||||
"type": "sitemap/sitemap_template#/definitions/frame_element",
|
||||
"label": "TischLampe",
|
||||
"icon" : "some_icon01",
|
||||
"elements" : [
|
||||
{
|
||||
"type": "sitemap/sitemap_template#/definitions/switch_element",
|
||||
"label": "TischLampe Switch",
|
||||
"icon" : "some_icon02",
|
||||
"device": {
|
||||
"id": "huelight4",
|
||||
"pointer": "/switch/value"
|
||||
},
|
||||
"commandTemplate": {
|
||||
"switch": {
|
||||
"set": null
|
||||
}
|
||||
},
|
||||
"commandValuePointer": "/switch/set"
|
||||
}, {
|
||||
"type": "sitemap/sitemap_template#/definitions/slider_element",
|
||||
"label": "TischLampe Slider",
|
||||
"icon" : "some_icon03",
|
||||
"device": {
|
||||
"id": "huelight4",
|
||||
"pointer": "/brightness/value"
|
||||
},
|
||||
"min": 0,
|
||||
"max": 1,
|
||||
"step": 0.1,
|
||||
"commandTemplate": {
|
||||
"brightness": {
|
||||
"set": null
|
||||
}
|
||||
},
|
||||
"commandValuePointer": "/brightness/set"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
@@ -59,6 +59,8 @@ public:
|
||||
virtual std::map<std::string, std::weak_ptr<sitemaptemplate::SitemapTemplate>> getSitemaps() noexcept = 0;
|
||||
virtual std::vector<std::string> getSitemapNames() noexcept = 0;
|
||||
|
||||
virtual std::weak_ptr<sitemaptemplate::SitemapTemplate> getDefaultSitemap() noexcept = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
+65
-4
@@ -20,20 +20,78 @@ class SitemapService;
|
||||
|
||||
namespace sitemaptemplate {
|
||||
|
||||
|
||||
class SitemapTemplate;
|
||||
class Page;
|
||||
class Element;
|
||||
class AtomicElement;
|
||||
class CompositeElement;
|
||||
class Device;
|
||||
|
||||
/*
|
||||
* Sitemap event type.
|
||||
*
|
||||
**/
|
||||
enum class SitemapEventType : int {
|
||||
ALL_EVENTS = 1,
|
||||
SITEMAP_ELEMENT_CHANGED = 2,
|
||||
SITEMAP_INVALIDATED = 3
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for sitemap events.
|
||||
*/
|
||||
class SitemapEvent {
|
||||
public:
|
||||
typedef std::chrono::system_clock::time_point timestamp_t;
|
||||
|
||||
SitemapEventType eventType;
|
||||
|
||||
SitemapTemplate* const sitemap;
|
||||
|
||||
const timestamp_t timestamp;
|
||||
|
||||
SitemapEvent(SitemapTemplate* sitemap, const SitemapEventType& type, const timestamp_t& timestamp)
|
||||
: eventType(type), sitemap(sitemap), timestamp(timestamp) {}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* sitemap element changed event.
|
||||
*/
|
||||
class SitemapElementChangedEvent
|
||||
: public SitemapEvent {
|
||||
public:
|
||||
std::vector<std::weak_ptr<Element>> elements;
|
||||
|
||||
SitemapElementChangedEvent(SitemapTemplate* sitemap, const timestamp_t& timestamp)
|
||||
: SitemapEvent(sitemap,SitemapEventType::SITEMAP_ELEMENT_CHANGED, timestamp) {}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* sitemap invalidated event.
|
||||
*/
|
||||
class SitemapInvalidatedEvent
|
||||
: public SitemapEvent {
|
||||
public:
|
||||
SitemapInvalidatedEvent(SitemapTemplate* sitemap, const timestamp_t& timestamp)
|
||||
: SitemapEvent(sitemap,SitemapEventType::SITEMAP_INVALIDATED, timestamp) {}
|
||||
};
|
||||
|
||||
|
||||
class SitemapTemplate
|
||||
: public virtual interface::Object {
|
||||
: public virtual interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>,
|
||||
public virtual interface::ObservableObject<SitemapEventType, SitemapEvent> {
|
||||
public:
|
||||
virtual SitemapService* getParent() noexcept = 0;
|
||||
virtual size_t pageCount() noexcept = 0;
|
||||
virtual std::weak_ptr<Page> getPage(const std::string& name) noexcept = 0;
|
||||
virtual std::vector<std::weak_ptr<Page>> getPages(const std::string& name) noexcept = 0;
|
||||
virtual std::weak_ptr<Page> getRootPage() noexcept = 0;
|
||||
virtual const std::string& getRootPageName() noexcept = 0;
|
||||
virtual std::weak_ptr<Element> getPageElement(size_t& uid) noexcept = 0;
|
||||
|
||||
virtual const std::string& getName() noexcept = 0;
|
||||
|
||||
virtual libvariant::Variant renderSitemap() = 0;
|
||||
};
|
||||
@@ -44,7 +102,7 @@ class Page
|
||||
: public virtual interface::Object {
|
||||
public:
|
||||
virtual SitemapTemplate* getSiteMap() noexcept = 0;
|
||||
virtual Page* getParent() noexcept = 0;
|
||||
virtual const std::string& getName() noexcept = 0;
|
||||
|
||||
virtual size_t elementCount() noexcept = 0;
|
||||
virtual std::weak_ptr<Element> getElement(size_t index) noexcept = 0;
|
||||
@@ -99,7 +157,8 @@ public:
|
||||
virtual const std::string& getFormat() noexcept = 0;
|
||||
virtual std::weak_ptr<Device> getDevice() noexcept = 0;
|
||||
virtual const libvariant::Variant& getAdditionalParams() noexcept = 0;
|
||||
virtual std::weak_ptr<Page> getLinkedToPage() noexcept = 0;
|
||||
virtual std::weak_ptr<Page> getLinkedPage() noexcept = 0;
|
||||
virtual const std::string& getLinkedPageName() noexcept = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -107,10 +166,12 @@ public:
|
||||
class Device
|
||||
: public virtual interface::Object {
|
||||
public:
|
||||
virtual std::weak_ptr<Element> getParent() noexcept = 0;
|
||||
virtual const std::string& getDeviceID() noexcept = 0;
|
||||
virtual std::weak_ptr<devicerepository::Device> getDevice() noexcept = 0;
|
||||
virtual const std::string& getPointer() noexcept = 0;
|
||||
virtual bool deviceExists() noexcept = 0;
|
||||
virtual void sendCommand(const libvariant::Variant& cmd) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<launch>
|
||||
<group ns="/hos/sitemap/sitemap_templates">
|
||||
<param name="test01" textfile="$(find hos_cosgi_sitemap)/examples/test01.json"/>
|
||||
<param name="test02" textfile="$(find hos_cosgi_sitemap)/examples/test02.json"/>
|
||||
</group>
|
||||
|
||||
<group ns="/hos/types/repository/sitemap">
|
||||
|
||||
@@ -13,12 +13,24 @@
|
||||
"type": "string",
|
||||
"description": ""
|
||||
},
|
||||
"rootpage": {
|
||||
"default": {
|
||||
"type": "boolean",
|
||||
"description": ""
|
||||
},
|
||||
"pages": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"[A-Za-z0-9_-]+": {
|
||||
"$ref": "#/definitions/page"
|
||||
}
|
||||
}
|
||||
},
|
||||
"rootpage": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["title", "rootpage"],
|
||||
"required": ["title", "pages", "rootpage"],
|
||||
|
||||
"definitions": {
|
||||
|
||||
@@ -109,7 +121,7 @@
|
||||
"icon": {
|
||||
"type": "string"
|
||||
},
|
||||
"page": {
|
||||
"linkedPage": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,13 +103,38 @@ void SitemapServiceImpl::addSitemap(const std::string& name, XmlRpc::XmlRpcValue
|
||||
throw std::runtime_error("title is not a string.");
|
||||
}
|
||||
std::string title = titleRaw.AsString();
|
||||
auto rootpage = value["rootpage"];
|
||||
if (!rootpage.IsMap()) {
|
||||
throw std::runtime_error("rootpage is not a map.");
|
||||
auto rootpageRaw = value["rootpage"];
|
||||
if (!rootpageRaw.IsString()) {
|
||||
throw std::runtime_error("rootpage is not a string.");
|
||||
}
|
||||
std::string rootpage = rootpageRaw.AsString();
|
||||
bool isDefault = false;
|
||||
if (value.Contains("default")) {
|
||||
auto isDefaultRaw = value["default"];
|
||||
if (!isDefaultRaw.IsBool()) {
|
||||
throw std::runtime_error("default is not a boolean.");
|
||||
}
|
||||
isDefault = isDefaultRaw.IsTrue();
|
||||
}
|
||||
auto pages = value["pages"];
|
||||
if (!pages.IsMap()) {
|
||||
throw std::runtime_error("pages is not a map.");
|
||||
}
|
||||
std::shared_ptr<sitemaptemplate::SitemapTemplateImpl> st = std::make_shared<sitemaptemplate::SitemapTemplateImpl>(*this, name, title);
|
||||
for (auto page : pages.AsMap()) {
|
||||
st->addPage(page.first, page.second);
|
||||
}
|
||||
if (!st->setRootPageName(rootpage)) {
|
||||
ROS_WARN_STREAM("Sitemap " << st->getName() << " has unknown root page " << rootpage << ".");
|
||||
}
|
||||
std::shared_ptr<sitemaptemplate::SitemapTemplateImpl> st = std::make_shared<sitemaptemplate::SitemapTemplateImpl>(*this, title);
|
||||
st->createPage(rootpage);
|
||||
sitemapTemplates.insert({name, st});
|
||||
if (!sitemapDefault || isDefault) {
|
||||
sitemapDefault = st;
|
||||
}
|
||||
repoService->addObserver(devicerepository::DeviceEventType::ALL_EVENTS, st.get());
|
||||
if (name.compare("default") == 0) {
|
||||
ROS_WARN("There exists a sitemap with name \"default\".");
|
||||
}
|
||||
} else {
|
||||
std::stringstream ss;
|
||||
ss << "Could not validate sitemap config value: " << sr.PrettyPrintMessage();
|
||||
@@ -146,6 +171,10 @@ std::vector<std::string> SitemapServiceImpl::getSitemapNames() noexcept {
|
||||
}
|
||||
|
||||
|
||||
std::weak_ptr<sitemaptemplate::SitemapTemplate> SitemapServiceImpl::getDefaultSitemap() noexcept {
|
||||
return std::static_pointer_cast<sitemaptemplate::SitemapTemplate>(sitemapDefault);
|
||||
}
|
||||
|
||||
} /* namespace sitemap */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
|
||||
@@ -38,6 +38,8 @@ private:
|
||||
bool initialized = false;
|
||||
|
||||
std::map<std::string, std::shared_ptr<sitemaptemplate::SitemapTemplateImpl>> sitemapTemplates;
|
||||
std::shared_ptr<sitemaptemplate::SitemapTemplateImpl> sitemapDefault;
|
||||
|
||||
|
||||
void init() noexcept;
|
||||
void addSitemap(const std::string& name, XmlRpc::XmlRpcValue& rawValue);
|
||||
@@ -72,6 +74,8 @@ public:
|
||||
|
||||
virtual std::vector<std::string> getSitemapNames() noexcept override;
|
||||
|
||||
virtual std::weak_ptr<sitemaptemplate::SitemapTemplate> getDefaultSitemap() noexcept override;
|
||||
|
||||
|
||||
/* Internal */
|
||||
|
||||
|
||||
+219
-82
@@ -1,5 +1,6 @@
|
||||
|
||||
#include "SitemapTemplateImpl.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
@@ -9,54 +10,6 @@ namespace sitemaptemplate {
|
||||
|
||||
|
||||
|
||||
std::atomic<uint64_t> ElementImpl::nextID;
|
||||
|
||||
std::shared_ptr<PageImpl> SitemapTemplateImpl::createPage(const libvariant::Variant& param, PageImpl* parent) {
|
||||
std::shared_ptr<PageImpl> newPage;
|
||||
if (!parent && rootPage) {
|
||||
throw std::runtime_error("There is already a root page.");
|
||||
}
|
||||
auto titleRaw = param["title"];
|
||||
if (!titleRaw.IsString()) {
|
||||
throw std::runtime_error("title is not a string.");
|
||||
}
|
||||
std::string title = titleRaw.AsString();
|
||||
auto elements = param["elements"];
|
||||
if (!elements.IsList()) {
|
||||
throw std::runtime_error("elements is not a list.");
|
||||
}
|
||||
newPage = std::make_shared<PageImpl>(*this, title, parent);
|
||||
for ( auto e : elements.AsList()) {
|
||||
newPage->createElement(e);
|
||||
}
|
||||
if (!parent) {
|
||||
rootPage = newPage;
|
||||
}
|
||||
return newPage;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<DeviceImpl> SitemapTemplateImpl::createDevice(const libvariant::Variant& param) {
|
||||
auto idRaw = param["id"];
|
||||
if (!idRaw.IsString()) {
|
||||
throw std::runtime_error("id is not a string.");
|
||||
}
|
||||
std::string id = idRaw.AsString();
|
||||
std::string pointer;
|
||||
auto pointerRaw = param["pointer"];
|
||||
if (!pointerRaw.IsString()) {
|
||||
throw std::runtime_error("pointer is not a string.");
|
||||
} else if (pointerRaw.IsString()) {
|
||||
pointer = pointerRaw.AsString();
|
||||
}
|
||||
auto devRepo = parent.getDeviceRepository();
|
||||
auto device = devRepo->getDevice(id);
|
||||
std::shared_ptr<DeviceImpl> newDevice = std::make_shared<DeviceImpl>(id, device, pointer);
|
||||
return newDevice;
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
struct _elementTypeInfo {
|
||||
@@ -75,26 +28,85 @@ _elementTypeInfo elementTypeInfo[] = {
|
||||
|
||||
}
|
||||
|
||||
std::atomic<uint64_t> ElementImpl::nextID;
|
||||
|
||||
std::shared_ptr<PageImpl> SitemapTemplateImpl::addPage(const std::string& name, const libvariant::Variant& pageRaw) {
|
||||
auto titleRaw = pageRaw["title"];
|
||||
if (!titleRaw.IsString()) {
|
||||
throw std::runtime_error("title is not a string.");
|
||||
}
|
||||
std::string title = titleRaw.AsString();
|
||||
auto elements = pageRaw["elements"];
|
||||
if (!elements.IsList()) {
|
||||
throw std::runtime_error("elements is not a list.");
|
||||
}
|
||||
auto newPage = std::make_shared<PageImpl>(*this, name, title);
|
||||
for (auto element : elements.AsList()) {
|
||||
newPage->addElement(element);
|
||||
}
|
||||
pages.insert({name, newPage});
|
||||
return newPage;
|
||||
}
|
||||
|
||||
std::vector<std::weak_ptr<Element>> PageImpl::getElements() noexcept {
|
||||
std::vector<std::weak_ptr<Element>> retval;
|
||||
for (auto i : elements) {
|
||||
retval.push_back(std::static_pointer_cast<Element>(i));
|
||||
std::weak_ptr<Page> SitemapTemplateImpl::getPage(const std::string& name) noexcept {
|
||||
auto page = pages.find(name);
|
||||
if (page == pages.end()) {
|
||||
return std::weak_ptr<Page>();
|
||||
} else {
|
||||
return page->second;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::weak_ptr<Page>> SitemapTemplateImpl::getPages(const std::string& name) noexcept {
|
||||
std::vector<std::weak_ptr<Page>> retval;
|
||||
for (auto page : pages) {
|
||||
retval.push_back(page.second);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::vector<std::weak_ptr<Element>> CompositeElementImpl::getElements() noexcept {
|
||||
std::vector<std::weak_ptr<Element>> retval;
|
||||
for (auto i : elements) {
|
||||
retval.push_back(std::static_pointer_cast<Element>(i));
|
||||
std::weak_ptr<Page> SitemapTemplateImpl::getRootPage() noexcept {
|
||||
return getPage(rootPageName);
|
||||
}
|
||||
return retval;
|
||||
|
||||
bool SitemapTemplateImpl::setRootPageName(const std::string& name) noexcept {
|
||||
rootPageName = name;
|
||||
if (pages.find(name) != pages.end()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::weak_ptr<Element> SitemapTemplateImpl::getPageElement(size_t& uid) noexcept {
|
||||
auto r = pageElements.find(uid);
|
||||
if (r != pageElements.end()) {
|
||||
return r->second;
|
||||
}
|
||||
return std::weak_ptr<Element>();
|
||||
}
|
||||
|
||||
std::shared_ptr<DeviceImpl> SitemapTemplateImpl::createDevice(const libvariant::Variant& param, const libvariant::Variant& commandTemplate, const std::string& commandValuePointer) {
|
||||
auto idRaw = param["id"];
|
||||
if (!idRaw.IsString()) {
|
||||
throw std::runtime_error("id is not a string.");
|
||||
}
|
||||
std::string id = idRaw.AsString();
|
||||
std::string pointer;
|
||||
auto pointerRaw = param["pointer"];
|
||||
if (!pointerRaw.IsString()) {
|
||||
throw std::runtime_error("pointer is not a string.");
|
||||
} else if (pointerRaw.IsString()) {
|
||||
pointer = pointerRaw.AsString();
|
||||
}
|
||||
auto devRepo = parent.getDeviceRepository();
|
||||
auto device = devRepo->getDevice(id);
|
||||
std::shared_ptr<DeviceImpl> newDevice = std::make_shared<DeviceImpl>(id, device, pointer, commandTemplate, commandValuePointer);
|
||||
devices.insert({id, newDevice});
|
||||
return newDevice;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<ElementImpl> PageImpl::createElement(const libvariant::Variant& param, CompositeElementImpl* parent) {
|
||||
std::shared_ptr<ElementImpl> SitemapTemplateImpl::createElement(PageImpl& page, const libvariant::Variant& param, CompositeElementImpl* parent) {
|
||||
std::shared_ptr<ElementImpl> newElement;
|
||||
libvariant::Variant addParams = param.Copy();
|
||||
auto typeRaw = param["type"];
|
||||
@@ -134,13 +146,23 @@ std::shared_ptr<ElementImpl> PageImpl::createElement(const libvariant::Variant&
|
||||
}
|
||||
}
|
||||
if (info->isComposite) {
|
||||
auto elements = param["elements"];
|
||||
if (elements.IsNull()) {
|
||||
throw std::runtime_error("elements is missing.");
|
||||
} else if (!elements.IsList()) {
|
||||
throw std::runtime_error("elements is not an array.");
|
||||
}
|
||||
addParams.Erase("elements");
|
||||
switch (info->type) {
|
||||
case ElementType::Frame:
|
||||
newElement = std::make_shared<FrameElementImpl>(*this, info->typeString, label, icon, parent);
|
||||
newElement = std::make_shared<FrameElementImpl>(page, info->typeString, label, icon, parent);
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error((boost::format("Registered element type %1% is unknown.") % info->typeName).str());
|
||||
}
|
||||
for (auto element : elements.AsList()) {
|
||||
std::static_pointer_cast<CompositeElementImpl>(newElement)->addElement(element);
|
||||
}
|
||||
} else {
|
||||
std::string format;
|
||||
if (param.Contains("format")) {
|
||||
@@ -158,38 +180,120 @@ std::shared_ptr<ElementImpl> PageImpl::createElement(const libvariant::Variant&
|
||||
if (!deviceRaw.IsMap()) {
|
||||
throw std::runtime_error("device is not a map.");
|
||||
} else {
|
||||
device = sitemap.createDevice(deviceRaw);
|
||||
libvariant::Variant commandTemplate;
|
||||
std::string commandValuePointer;
|
||||
if (param.Contains("commandTemplate")) {
|
||||
commandTemplate = param["commandTemplate"];
|
||||
addParams.Erase("commandTemplate");
|
||||
}
|
||||
if (param.Contains("commandValuePointer") && param["commandValuePointer"].IsString()) {
|
||||
commandValuePointer = param["commandValuePointer"].AsString();
|
||||
addParams.Erase("commandValuePointer");
|
||||
}
|
||||
device = createDevice(deviceRaw, commandTemplate, commandValuePointer);
|
||||
addParams.Erase("device");
|
||||
}
|
||||
}
|
||||
libvariant::Variant pageRaw;
|
||||
if (param.Contains("page")) {
|
||||
pageRaw = param["page"];
|
||||
if (!pageRaw.IsMap()) {
|
||||
throw std::runtime_error("page is not a map.");
|
||||
libvariant::Variant linkedPageRaw;
|
||||
if (param.Contains("linkedPage")) {
|
||||
linkedPageRaw = param["linkedPage"];
|
||||
if (!linkedPageRaw.IsString()) {
|
||||
throw std::runtime_error("linkedPage is not a string.");
|
||||
} else {
|
||||
addParams.Erase("page");
|
||||
addParams.Erase("linkedPage");
|
||||
}
|
||||
}
|
||||
std::shared_ptr<AtomicElementImpl> newAElement;
|
||||
switch (info->type) {
|
||||
case ElementType::Text:
|
||||
newAElement = std::make_shared<TextElementImpl>(*this, info->typeString, label, icon, format, device, addParams, parent);
|
||||
newAElement = std::make_shared<TextElementImpl>(page, info->typeString, label, icon, format, device, addParams, parent);
|
||||
break;
|
||||
case ElementType::Slider:
|
||||
newAElement = std::make_shared<SliderElementImpl>(*this, info->typeString, label, icon, format, device, addParams, parent);
|
||||
newAElement = std::make_shared<SliderElementImpl>(page, info->typeString, label, icon, format, device, addParams, parent);
|
||||
break;
|
||||
case ElementType::Switch:
|
||||
newAElement = std::make_shared<SwitchElementImpl>(*this, info->typeString, label, icon, format, device, addParams, parent);
|
||||
newAElement = std::make_shared<SwitchElementImpl>(page, info->typeString, label, icon, format, device, addParams, parent);
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error((boost::format("Registered element type %1% is unknown.") % info->typeName).str());
|
||||
}
|
||||
if (pageRaw.IsMap()) {
|
||||
newAElement->createLinkedToPage(pageRaw);
|
||||
if (device) {
|
||||
device->setParent(newAElement);
|
||||
}
|
||||
if (linkedPageRaw.IsString()) {
|
||||
newAElement->setLinkedPage(linkedPageRaw.AsString());
|
||||
}
|
||||
newElement = newAElement;
|
||||
}
|
||||
pageElements.insert({newElement->getID(), newElement});
|
||||
return newElement;
|
||||
}
|
||||
|
||||
void SitemapTemplateImpl::notificationReceived(observable_type* o, const devicerepository::DeviceEventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||
SitemapElementChangedEvent event(this, std::chrono::system_clock::now());
|
||||
switch (e->eventType) {
|
||||
case devicerepository::DeviceEventType::DEVICE_ADDED:
|
||||
{
|
||||
auto range = devices.equal_range(e->device->getDeviceID());
|
||||
for (auto i = range.first; i != range.second && i != devices.end(); i++) {
|
||||
auto dev = i->second.lock();
|
||||
if (!dev->deviceExists()) {
|
||||
dev->resolveDevice();
|
||||
event.elements.push_back(dev->getParent());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case devicerepository::DeviceEventType::DEVICE_REMOVED:
|
||||
{
|
||||
auto range = devices.equal_range(e->device->getDeviceID());
|
||||
for (auto i = range.first; i != range.second && i != devices.end(); i++) {
|
||||
auto dev = i->second.lock();
|
||||
dev->resolveDevice();
|
||||
event.elements.push_back(dev->getParent());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case devicerepository::DeviceEventType::STATE_CHANGED:
|
||||
{
|
||||
auto range = devices.equal_range(e->device->getDeviceID());
|
||||
for (auto i = range.first; i != range.second && i != devices.end(); i++) {
|
||||
auto dev = i->second.lock();
|
||||
event.elements.push_back(dev->getParent());
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (event.elements.size() > 0) {
|
||||
notifyObservers(SitemapEventType::ALL_EVENTS, SitemapEventType::SITEMAP_ELEMENT_CHANGED, &event);
|
||||
notifyObservers(SitemapEventType::SITEMAP_ELEMENT_CHANGED, &event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
std::vector<std::weak_ptr<Element>> PageImpl::getElements() noexcept {
|
||||
std::vector<std::weak_ptr<Element>> retval;
|
||||
for (auto i : elements) {
|
||||
retval.push_back(std::static_pointer_cast<Element>(i));
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::vector<std::weak_ptr<Element>> CompositeElementImpl::getElements() noexcept {
|
||||
std::vector<std::weak_ptr<Element>> retval;
|
||||
for (auto i : elements) {
|
||||
retval.push_back(std::static_pointer_cast<Element>(i));
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<ElementImpl> PageImpl::addElement(const libvariant::Variant& param, CompositeElementImpl* parent) {
|
||||
std::shared_ptr<ElementImpl> newElement = sitemap.createElement(*this, param, parent);
|
||||
if (!parent) {
|
||||
elements.push_back(newElement);
|
||||
}
|
||||
@@ -198,33 +302,40 @@ std::shared_ptr<ElementImpl> PageImpl::createElement(const libvariant::Variant&
|
||||
|
||||
|
||||
|
||||
std::shared_ptr<ElementImpl> CompositeElementImpl::createElement(const libvariant::Variant& param) {
|
||||
std::shared_ptr<ElementImpl> newElement = page.createElement(param, this);
|
||||
std::shared_ptr<ElementImpl> CompositeElementImpl::addElement(const libvariant::Variant& param) {
|
||||
std::shared_ptr<ElementImpl> newElement = page.addElement(param, this);
|
||||
elements.push_back(newElement);
|
||||
return newElement;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<PageImpl> AtomicElementImpl::createLinkedToPage(const libvariant::Variant& param) {
|
||||
if (linkedToPage) {
|
||||
throw std::runtime_error("There is already a linked page.");
|
||||
bool AtomicElementImpl::setLinkedPage(const std::string& pagename) noexcept {
|
||||
linkedPageName = pagename;
|
||||
if (!this->page.getSiteMap()->getPage(linkedPageName).expired()) {
|
||||
return true;
|
||||
}
|
||||
linkedToPage = page.sitemap.createPage(param, &page);
|
||||
return linkedToPage;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
libvariant::Variant SitemapTemplateImpl::renderSitemap() {
|
||||
libvariant::Variant retval = libvariant::Variant::Map();
|
||||
retval["title"] = title;
|
||||
retval["rootpage"] = rootPage->renderSitemap();
|
||||
retval["name"] = name;
|
||||
retval["type"] = "sitemap/sitemap";
|
||||
retval["rootpage"] = rootPageName;
|
||||
auto tmp = libvariant::Variant::Map();
|
||||
for (auto page : pages) {
|
||||
tmp[page.first] = page.second->renderSitemap();
|
||||
}
|
||||
retval["pages"] = tmp;
|
||||
return retval;
|
||||
}
|
||||
|
||||
libvariant::Variant PageImpl::renderSitemap() {
|
||||
libvariant::Variant retval = libvariant::Variant::Map();
|
||||
retval["title"] = title;
|
||||
retval["name"] = name;
|
||||
libvariant::Variant elements = libvariant::Variant::List();
|
||||
for (auto i : this->elements) {
|
||||
elements.Append(i->renderSitemap());
|
||||
@@ -246,20 +357,27 @@ libvariant::Variant CompositeElementImpl::renderSitemap() {
|
||||
}
|
||||
retval["elements"] = elements;
|
||||
retval["type"] = typeString;
|
||||
retval["uid"] = id;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
std::weak_ptr<Page> AtomicElementImpl::getLinkedPage() noexcept {
|
||||
return this->page.getSiteMap()->getPage(linkedPageName);
|
||||
}
|
||||
|
||||
libvariant::Variant AtomicElementImpl::renderSitemap() {
|
||||
libvariant::Variant retval = libvariant::Variant::Map();
|
||||
retval["label"] = label;
|
||||
if (!icon.empty()) {
|
||||
retval["icon"] = icon;
|
||||
}
|
||||
if (linkedToPage) {
|
||||
retval["page"] = linkedToPage->renderSitemap();
|
||||
if (!linkedPageName.empty()) {
|
||||
retval["linkedPage"] = linkedPageName;
|
||||
}
|
||||
retval["value"] = _getDeviceValue();
|
||||
retval["type"] = typeString;
|
||||
retval["uid"] = id;
|
||||
retval.Merge(additionalParams);
|
||||
return retval;
|
||||
}
|
||||
@@ -267,7 +385,7 @@ libvariant::Variant AtomicElementImpl::renderSitemap() {
|
||||
|
||||
libvariant::Variant AtomicElementImpl::_getDeviceValue() {
|
||||
libvariant::Variant devState;
|
||||
if (device->deviceExists()) {
|
||||
if (device && device->deviceExists()) {
|
||||
try {
|
||||
devState = device->getDevice().lock()->getCurrentState();
|
||||
if (!device->getPointer().empty()) {
|
||||
@@ -280,7 +398,11 @@ libvariant::Variant AtomicElementImpl::_getDeviceValue() {
|
||||
devState = "NaN";
|
||||
}
|
||||
if (!format.empty()) {
|
||||
try {
|
||||
devState = (boost::format(format) % devState.AsString()).str();
|
||||
} catch (boost::io::format_error& e) {
|
||||
devState = format;
|
||||
}
|
||||
}
|
||||
return devState;
|
||||
}
|
||||
@@ -321,6 +443,21 @@ libvariant::Variant SwitchElementImpl::_getDeviceValue() {
|
||||
return devState;
|
||||
}
|
||||
|
||||
void DeviceImpl::resolveDevice() noexcept {
|
||||
if (!parent.expired()) {
|
||||
auto devRepo = parent.lock()->getPage()->getSiteMap()->getParent()->getDeviceRepository();
|
||||
device = devRepo->getDevice(deviceID);
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceImpl::sendCommand(const libvariant::Variant& cmd) {
|
||||
if (!device.expired() && commandTemplate.IsMap() && !commandValuePointer.empty()) {
|
||||
std::cout << "DeviceImpl::sendCommand: " << libvariant::SerializeJSON(cmd) << std::endl;
|
||||
auto msg = commandTemplate.Copy();
|
||||
msg.SetPath(commandValuePointer, cmd);
|
||||
device.lock()->sendCommand(msg);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sitemaptemplate
|
||||
} // namespace sitemap
|
||||
|
||||
+62
-17
@@ -3,6 +3,8 @@
|
||||
|
||||
// hos includes
|
||||
#include <hos/cosgi/service/sitemap/sitemap_template/SitemapTemplate.h>
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include <hos/cosgi/service/Interface.h>
|
||||
#include "../SitemapServiceImpl.h"
|
||||
#include <hos/utils/SchemaLoader.h>
|
||||
// libvariant
|
||||
@@ -15,6 +17,22 @@
|
||||
#include <atomic>
|
||||
|
||||
|
||||
namespace std {
|
||||
/**
|
||||
* Specialization of std::hash for DeviceEventType.
|
||||
*
|
||||
* Required by std::map.
|
||||
*/
|
||||
template <>
|
||||
class hash <hos::cosgi::service::sitemap::sitemaptemplate::SitemapEventType>{
|
||||
public :
|
||||
size_t operator()(const hos::cosgi::service::sitemap::sitemaptemplate::SitemapEventType& x) const {
|
||||
return static_cast<size_t>(x);
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
@@ -35,20 +53,37 @@ class DeviceImpl;
|
||||
|
||||
class SitemapTemplateImpl
|
||||
: public virtual SitemapTemplate,
|
||||
public implementation::Object {
|
||||
public implementation::ObservableObject<SitemapEventType, SitemapEvent> {
|
||||
private:
|
||||
SitemapServiceImpl& parent;
|
||||
std::string name;
|
||||
std::string title;
|
||||
std::shared_ptr<PageImpl> rootPage;
|
||||
std::map<std::string, std::shared_ptr<PageImpl>> pages;
|
||||
std::map<size_t, std::shared_ptr<ElementImpl>> pageElements;
|
||||
std::string rootPageName;
|
||||
std::multimap<std::string, std::weak_ptr<DeviceImpl>> devices;
|
||||
|
||||
public:
|
||||
SitemapTemplateImpl(SitemapServiceImpl& parent, const std::string& title) : parent(parent), title(title) {}
|
||||
SitemapTemplateImpl(SitemapServiceImpl& parent, const std::string& name, const std::string& title)
|
||||
: parent(parent), name(name), title(title) {}
|
||||
|
||||
std::shared_ptr<PageImpl> createPage(const libvariant::Variant& param, PageImpl* parent = nullptr);
|
||||
std::shared_ptr<DeviceImpl> createDevice(const libvariant::Variant& param);
|
||||
virtual void notificationReceived(observable_type* o, const devicerepository::DeviceEventType& key, const devicerepository::DeviceEvent* e) noexcept override;
|
||||
|
||||
std::shared_ptr<PageImpl> addPage(const std::string& name, const libvariant::Variant& page);
|
||||
bool setRootPageName(const std::string& name) noexcept;
|
||||
std::shared_ptr<DeviceImpl> createDevice(const libvariant::Variant& param, const libvariant::Variant& commandTemplate, const std::string& commandValuePointer);
|
||||
std::shared_ptr<ElementImpl> createElement(PageImpl& page, const libvariant::Variant& param, CompositeElementImpl* parent);
|
||||
|
||||
virtual SitemapService* getParent() noexcept override { return dynamic_cast<SitemapService*>(&parent); }
|
||||
virtual std::weak_ptr<Page> getRootPage() noexcept override { return std::static_pointer_cast<Page>(rootPage); };
|
||||
virtual size_t pageCount() noexcept override { return pages.size(); }
|
||||
virtual std::weak_ptr<Page> getPage(const std::string& name) noexcept override;
|
||||
virtual std::vector<std::weak_ptr<Page>> getPages(const std::string& name) noexcept override;
|
||||
virtual std::weak_ptr<Page> getRootPage() noexcept override;
|
||||
virtual const std::string& getRootPageName() noexcept override { return rootPageName; }
|
||||
virtual std::weak_ptr<Element> getPageElement(size_t& uid) noexcept override;
|
||||
|
||||
|
||||
virtual const std::string& getName() noexcept { return name; };
|
||||
|
||||
virtual libvariant::Variant renderSitemap() override;
|
||||
};
|
||||
@@ -61,18 +96,18 @@ class PageImpl
|
||||
friend class AtomicElementImpl;
|
||||
private:
|
||||
SitemapTemplateImpl& sitemap;
|
||||
PageImpl* parent;
|
||||
std::string name;
|
||||
std::string title;
|
||||
std::vector<std::shared_ptr<ElementImpl>> elements;
|
||||
|
||||
public:
|
||||
PageImpl(SitemapTemplateImpl& sitemap, const std::string& title, PageImpl* parent = nullptr)
|
||||
: sitemap(sitemap), parent(parent), title(title) {}
|
||||
PageImpl(SitemapTemplateImpl& sitemap, const std::string& name, const std::string& title)
|
||||
: sitemap(sitemap), name(name), title(title) {}
|
||||
|
||||
virtual SitemapTemplate* getSiteMap() noexcept override { return static_cast<SitemapTemplate*>(&sitemap); }
|
||||
virtual Page* getParent() noexcept override { return static_cast<Page*>(parent); }
|
||||
virtual const std::string& getName() noexcept { return name; }
|
||||
|
||||
std::shared_ptr<ElementImpl> createElement(const libvariant::Variant& param, CompositeElementImpl* parent = nullptr);
|
||||
std::shared_ptr<ElementImpl> addElement(const libvariant::Variant& param, CompositeElementImpl* parent = nullptr);
|
||||
|
||||
virtual size_t elementCount() noexcept override { return elements.size(); }
|
||||
virtual std::weak_ptr<Element> getElement(size_t index) noexcept override
|
||||
@@ -135,7 +170,7 @@ public:
|
||||
CompositeElementImpl* parent = nullptr)
|
||||
: ElementImpl(page, true, etype, typeStr, parent, label, icon) {}
|
||||
|
||||
std::shared_ptr<ElementImpl> createElement(const libvariant::Variant& param);
|
||||
std::shared_ptr<ElementImpl> addElement(const libvariant::Variant& param);
|
||||
|
||||
virtual size_t elementCount() noexcept override { return elements.size(); }
|
||||
virtual std::weak_ptr<Element> getElement(size_t index) noexcept override { return std::static_pointer_cast<Element>(elements.at(index)); }
|
||||
@@ -153,7 +188,7 @@ protected:
|
||||
std::string format;
|
||||
std::shared_ptr<DeviceImpl> device;
|
||||
libvariant::Variant additionalParams;
|
||||
std::shared_ptr<PageImpl> linkedToPage;
|
||||
std::string linkedPageName;
|
||||
|
||||
virtual libvariant::Variant _getDeviceValue();
|
||||
|
||||
@@ -163,12 +198,13 @@ public:
|
||||
CompositeElementImpl* parent = nullptr)
|
||||
: ElementImpl(page, false, etype, typeStr, parent, label, icon), format(format), device(device), additionalParams(additionalParams) {}
|
||||
|
||||
std::shared_ptr<PageImpl> createLinkedToPage(const libvariant::Variant& param);
|
||||
bool setLinkedPage(const std::string& pagename) noexcept;
|
||||
|
||||
virtual const std::string& getFormat() noexcept override { return format; }
|
||||
virtual std::weak_ptr<Device> getDevice() noexcept override;
|
||||
virtual const libvariant::Variant& getAdditionalParams() noexcept override { return additionalParams; }
|
||||
virtual std::weak_ptr<Page> getLinkedToPage() noexcept override { return linkedToPage; }
|
||||
virtual std::weak_ptr<Page> getLinkedPage() noexcept override;
|
||||
virtual const std::string& getLinkedPageName() noexcept override { return linkedPageName; }
|
||||
|
||||
virtual libvariant::Variant renderSitemap() override;
|
||||
};
|
||||
@@ -218,15 +254,24 @@ private:
|
||||
std::string deviceID;
|
||||
std::weak_ptr<devicerepository::Device> device;
|
||||
std::string pointer;
|
||||
std::weak_ptr<ElementImpl> parent;
|
||||
libvariant::Variant commandTemplate;
|
||||
std::string commandValuePointer;
|
||||
|
||||
public:
|
||||
DeviceImpl(const std::string& deviceID, std::weak_ptr<devicerepository::Device> device, const std::string& pointer)
|
||||
: deviceID(deviceID), device(device), pointer(pointer) {}
|
||||
DeviceImpl(const std::string& deviceID, std::weak_ptr<devicerepository::Device> device, const std::string& pointer, const libvariant::Variant& commandTemplate, const std::string& commandValuePointer)
|
||||
: deviceID(deviceID), device(device), pointer(pointer), commandTemplate(commandTemplate), commandValuePointer(commandValuePointer) {}
|
||||
|
||||
virtual std::weak_ptr<Element> getParent() noexcept override { return parent; }
|
||||
void setParent(std::weak_ptr<ElementImpl> parent) noexcept { this->parent = parent; }
|
||||
void resolveDevice() noexcept;
|
||||
void setDevice(std::weak_ptr<devicerepository::Device> device) noexcept { this->device = device; }
|
||||
|
||||
virtual const std::string& getDeviceID() noexcept override { return deviceID; }
|
||||
virtual std::weak_ptr<devicerepository::Device> getDevice() noexcept override { return device; }
|
||||
virtual const std::string& getPointer() noexcept override { return pointer; }
|
||||
virtual bool deviceExists() noexcept override { return !device.expired(); }
|
||||
virtual void sendCommand(const libvariant::Variant& cmd) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+196
-5
@@ -85,14 +85,23 @@ void SitemapHandler::__handleInfo(Poco::Net::HTTPServerRequest &req, Poco::Net::
|
||||
for (auto s : sitemaps) {
|
||||
result.Append(s);
|
||||
}
|
||||
Variant message = Variant::Map();
|
||||
message["sitemaps"] = result;
|
||||
auto dsm = service->getDefaultSitemap();
|
||||
if (!dsm.expired()) {
|
||||
message["default"] = dsm.lock()->getName();
|
||||
}
|
||||
|
||||
handleResponse(req, resp, form, result);
|
||||
handleResponse(req, resp, form, message);
|
||||
|
||||
// Single sitemap mode
|
||||
} else {
|
||||
// Get sitemap
|
||||
std::string sitemapName = pathPieces[matchPieces.size()];
|
||||
auto sitemap = service->getSitemap(sitemapName);
|
||||
if (sitemap.expired() && sitemapName.compare("default") == 0) {
|
||||
sitemap = service->getDefaultSitemap();
|
||||
}
|
||||
if (!sitemap.expired()) {
|
||||
// Get path from url and append pointer parameter
|
||||
std::stringstream path;
|
||||
@@ -108,6 +117,15 @@ void SitemapHandler::__handleInfo(Poco::Net::HTTPServerRequest &req, Poco::Net::
|
||||
}
|
||||
// Render sitemap
|
||||
Variant result = sitemap.lock()->renderSitemap();
|
||||
std::string pathStr = path.str();
|
||||
if (!pathStr.empty()) {
|
||||
if (result.HasPath(pathStr)) {
|
||||
result = result.GetPath(pathStr);
|
||||
} else {
|
||||
throw webserver::webresource::WebResourceHandlerException((boost::format("Unknown path \"%1%\" for sitemap \"%2%\".") % path % sitemapName).str(),
|
||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
// Return device info
|
||||
handleResponse(req, resp, form, result);
|
||||
} else {
|
||||
@@ -119,14 +137,131 @@ void SitemapHandler::__handleInfo(Poco::Net::HTTPServerRequest &req, Poco::Net::
|
||||
|
||||
|
||||
void SitemapHandler::__handleCommand(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, SitemapAPIMethod method, Net::HTMLForm& form) {
|
||||
throw webserver::webresource::WebResourceHandlerException("ToDo. Implement that shit.",
|
||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_IMPLEMENTED);
|
||||
std::vector<std::string> pathPieces, matchPieces;
|
||||
matchUri.getPathSegments(matchPieces);
|
||||
Poco::URI uri(req.getURI());
|
||||
uri.getPathSegments(pathPieces);
|
||||
|
||||
// No sitemap given, error
|
||||
if (pathPieces.size() <= matchPieces.size()) {
|
||||
throw webserver::webresource::WebResourceHandlerException("Missing sitemap.",
|
||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Get sitemap and do stuff
|
||||
std::string sitemapName = pathPieces[matchPieces.size()];
|
||||
std::weak_ptr<sitemaptemplate::SitemapTemplate> sitemap = service->getSitemap(sitemapName);
|
||||
if (!sitemap.expired()) {
|
||||
|
||||
Variant result;
|
||||
std::string msg;
|
||||
if (form.has("value")) {
|
||||
msg = form.get("value");
|
||||
}
|
||||
if (!msg.empty()) {
|
||||
result = libvariant::DeserializeYAML(msg);
|
||||
if (result.Contains("eventtype")) {
|
||||
auto eventtype = result["eventtype"].AsString();
|
||||
if (eventtype == "sitemap_element_command") {
|
||||
auto uid = result["uid"].AsUnsigned();
|
||||
auto value = result["value"];
|
||||
auto pe = sitemap.lock()->getPageElement(uid);
|
||||
if (!pe.expired()) {
|
||||
auto spe = pe.lock();
|
||||
if (!spe->isComposite()) {
|
||||
auto ae = std::dynamic_pointer_cast<sitemaptemplate::AtomicElement>(spe);
|
||||
auto dev = ae->getDevice();
|
||||
if (!dev.expired()) {
|
||||
dev.lock()->sendCommand(value);
|
||||
handleResponse(req, resp, form, std::string("OK: Command executed"));
|
||||
} else {
|
||||
throw webserver::webresource::WebResourceHandlerException("No device associated with element.",
|
||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
} else {
|
||||
throw webserver::webresource::WebResourceHandlerException("Cannot send a command to a composite element.",
|
||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
||||
}
|
||||
} else {
|
||||
throw webserver::webresource::WebResourceHandlerException((boost::format("Couldn't find element uid \"%1%\"") % uid).str(),
|
||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
||||
}
|
||||
} else {
|
||||
throw webserver::webresource::WebResourceHandlerException((boost::format("Unknown eventtype \"%1%\"") % eventtype).str(),
|
||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
||||
}
|
||||
} else {
|
||||
throw webserver::webresource::WebResourceHandlerException("Missing eventtype.",
|
||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
||||
}
|
||||
} else {
|
||||
throw webserver::webresource::WebResourceHandlerException("Missing msg.",
|
||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
||||
}
|
||||
} else {
|
||||
throw webserver::webresource::WebResourceHandlerException((boost::format("Could not find sitemap \"%1%\"") % sitemapName).str(),
|
||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SitemapHandler::__handleEvent(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Net::HTMLForm& form, bool websocket) {
|
||||
throw webserver::webresource::WebResourceHandlerException("ToDo. Implement that shit.",
|
||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_IMPLEMENTED);
|
||||
std::vector<std::string> pathPieces, matchPieces;
|
||||
matchUri.getPathSegments(matchPieces);
|
||||
Poco::URI uri(req.getURI());
|
||||
uri.getPathSegments(pathPieces);
|
||||
|
||||
// No sitemap given, error
|
||||
if (pathPieces.size() <= matchPieces.size()) {
|
||||
throw webserver::webresource::WebResourceHandlerException("Missing sitemap.",
|
||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Get sitemap and do stuff
|
||||
std::string sitemapName = pathPieces[matchPieces.size()];
|
||||
std::weak_ptr<sitemaptemplate::SitemapTemplate> sitemap = service->getSitemap(sitemapName);
|
||||
if (!sitemap.expired()) {
|
||||
// Get client ID
|
||||
std::string clientID;
|
||||
if (form.has("clientid")) {
|
||||
clientID = form.get("clientid");
|
||||
} else if (req.has("Client-Id")) {
|
||||
clientID = req.get("Client-Id");
|
||||
} else if (req.has("X-Client-Id")) {
|
||||
clientID = req.get("X-Client-Id");
|
||||
}
|
||||
// Get path from url and append pointer parameter
|
||||
std::stringstream path;
|
||||
for (int i = matchPieces.size() + 2; i < pathPieces.size(); i++) {
|
||||
path << "/" << pathPieces[i];
|
||||
}
|
||||
std::string pointer;
|
||||
if (getPointerParameter(pointer, form)) {
|
||||
if (pointer.size() > 0 && pointer[0] != '/') {
|
||||
path << "/";
|
||||
}
|
||||
path << pointer;
|
||||
}
|
||||
// Get event queue
|
||||
auto eventQueue = parent->getEventQueue(clientID, service);
|
||||
if (!eventQueue->setHandler(this, &req, &resp)) {
|
||||
throw webserver::webresource::WebResourceHandlerException((boost::format("Client id \"%1%\" already in use.") % clientID).str(),
|
||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
||||
}
|
||||
std::cout << "Got EventQueue \"" << eventQueue->clientID << "\"" << std::endl;
|
||||
eventQueue->checkRegistration(sitemaptemplate::SitemapEventType::ALL_EVENTS, sitemap.lock().get());
|
||||
if (websocket) {
|
||||
__handleEventWebSocket(req, resp, form, eventQueue.get(), parent);
|
||||
} else {
|
||||
__handleEventLongPolling(req, resp, form, eventQueue.get(), parent);
|
||||
}
|
||||
eventQueue->unsetHandler();
|
||||
} else {
|
||||
throw webserver::webresource::WebResourceHandlerException((boost::format("Could not find sitemap \"%1%\"") % sitemapName).str(),
|
||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
||||
}
|
||||
/*throw webserver::webresource::WebResourceHandlerException("ToDo. Implement that shit.",
|
||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_IMPLEMENTED);*/
|
||||
}
|
||||
|
||||
|
||||
@@ -160,6 +295,62 @@ SitemapAPIMethod SitemapHandler::getSitemapAPIMethod(Net::HTTPServerRequest &req
|
||||
|
||||
|
||||
|
||||
void SitemapEventQueue::checkRegistration(sitemaptemplate::SitemapEventType eventType, sitemaptemplate::SitemapTemplate* sitemap) {
|
||||
if (!registeredToEvent || eventType != this->eventType || sitemap != this->sitemap) {
|
||||
unregisterEvents();
|
||||
registerEvents(eventType, sitemap);
|
||||
}
|
||||
}
|
||||
|
||||
void SitemapEventQueue::registerEvents(sitemaptemplate::SitemapEventType eventType, sitemaptemplate::SitemapTemplate* sitemap) {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
if (!registeredToEvent) {
|
||||
std::cout << "SitemapEventQueue::registerEvents" << std::endl;
|
||||
sitemap->addObserver(eventType, this);
|
||||
this->sitemap = sitemap;
|
||||
this->eventType = eventType;
|
||||
registeredToEvent = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SitemapEventQueue::unregisterEvents() {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
if (registeredToEvent) {
|
||||
std::cout << "SitemapEventQueue::unregisterEvents" << std::endl;
|
||||
if (sitemap) {
|
||||
sitemap->deleteObserver(this);
|
||||
}
|
||||
registeredToEvent = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SitemapEventQueue::notificationReceived( interface::Observer<sitemaptemplate::SitemapEventType, sitemaptemplate::SitemapEvent>::observable_type* o,
|
||||
const sitemaptemplate::SitemapEventType& key,
|
||||
const sitemaptemplate::SitemapEvent* e) noexcept {
|
||||
Variant event;
|
||||
switch (key) {
|
||||
case sitemaptemplate::SitemapEventType::SITEMAP_INVALIDATED:
|
||||
event["eventtype"] = "sitemap_invalidated";
|
||||
break;
|
||||
case sitemaptemplate::SitemapEventType::SITEMAP_ELEMENT_CHANGED:
|
||||
{
|
||||
const sitemaptemplate::SitemapElementChangedEvent* event2 = static_cast<const sitemaptemplate::SitemapElementChangedEvent*>(e);
|
||||
event["eventtype"] = "sitemap_element_changed";
|
||||
auto elements = Variant::List();
|
||||
for (auto el : event2->elements) {
|
||||
elements.push_back(el.lock()->renderSitemap());
|
||||
}
|
||||
event["elements"] = elements;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!event.IsNull()) {
|
||||
pushEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webresource
|
||||
} // namespace sitemap
|
||||
} // namespace service
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <hos/cosgi/service/webserver/WebServerService.h>
|
||||
#include <hos/cosgi/service/webserver/webresource/WebResourceHandlerImpl.h>
|
||||
#include <hos/cosgi/service/sitemap/SitemapService.h>
|
||||
#include <hos/cosgi/service/sitemap/sitemap_template/SitemapTemplate.h>
|
||||
#include <hos/utils/FunctionTable.h>
|
||||
#include <Poco/Net/HTTPRequestHandler.h>
|
||||
#include <Variant/Variant.h>
|
||||
@@ -40,8 +41,42 @@ enum class SitemapAPIMethod {
|
||||
};
|
||||
|
||||
|
||||
typedef webserver::webresource::WebResourceEventQueue<
|
||||
interface::Observer<sitemaptemplate::SitemapEventType, sitemaptemplate::SitemapEvent>,
|
||||
SitemapHandlerFactory,
|
||||
SitemapHandler
|
||||
> SitemapEventQueueBase;
|
||||
|
||||
class SitemapEventQueue
|
||||
: public SitemapEventQueueBase {
|
||||
public:
|
||||
sitemaptemplate::SitemapEventType eventType = sitemaptemplate::SitemapEventType::ALL_EVENTS;
|
||||
SitemapService* const sitemapService;
|
||||
sitemaptemplate::SitemapTemplate* sitemap = nullptr;
|
||||
|
||||
SitemapEventQueue( const std::string& clientID,
|
||||
SitemapHandlerFactory* handlerFactory,
|
||||
SitemapService* sitemapService )
|
||||
: WebResourceEventQueue(clientID, handlerFactory), sitemapService(sitemapService) {}
|
||||
virtual ~SitemapEventQueue() {
|
||||
unregisterEvents();
|
||||
}
|
||||
|
||||
void checkRegistration(sitemaptemplate::SitemapEventType eventType, sitemaptemplate::SitemapTemplate* sitemap);
|
||||
void registerEvents(sitemaptemplate::SitemapEventType eventType, sitemaptemplate::SitemapTemplate* sitemap = nullptr);
|
||||
void unregisterEvents();
|
||||
|
||||
virtual void notificationReceived( interface::Observer<sitemaptemplate::SitemapEventType, sitemaptemplate::SitemapEvent>::observable_type* o,
|
||||
const sitemaptemplate::SitemapEventType& key,
|
||||
const sitemaptemplate::SitemapEvent* e) noexcept override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class SitemapHandlerFactory
|
||||
: public webserver::webresource::WebResourceHandlerFactoryImpl<SitemapHandlerFactory, false> {
|
||||
: public webserver::webresource::WebResourceHandlerFactoryImpl<SitemapHandlerFactory, false, SitemapEventQueue> {
|
||||
private:
|
||||
SitemapService* service;
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
define([
|
||||
"dojo/_base/config",
|
||||
'dojo/_base/declare',
|
||||
"dojo/Deferred",
|
||||
"dojo/dom",
|
||||
"dojo/dom-construct",
|
||||
"dijit/layout/ContentPane",
|
||||
"hos/sitemap/PageElementFactory"
|
||||
], function(config, declare, Deferred, dom, domConstruct, ContentPane, PageElementFactory) {
|
||||
|
||||
/*
|
||||
* Class representing a page.
|
||||
*/
|
||||
var PageClass = declare(null, {
|
||||
|
||||
/*
|
||||
* constructor.
|
||||
*
|
||||
* sitemap: parent sitemap.
|
||||
*
|
||||
* name: page name.
|
||||
*
|
||||
* data: page json object received from server
|
||||
*/
|
||||
constructor: function(/*hos/sitemap/Sitemap*/ sitemap, /*string*/ name, /*json object*/ data) {
|
||||
this.sitemap = sitemap;
|
||||
this.name = name;
|
||||
this.title = data["title"];
|
||||
this.elements = [];
|
||||
var _this = this;
|
||||
data["elements"].forEach(function(data) {
|
||||
var element = PageElementFactory.createPageElement(_this, data);
|
||||
_this.elements.push(element);
|
||||
_this.sitemap.pageElements[element.uid] = element;
|
||||
});
|
||||
},
|
||||
|
||||
/* returns string representation for debugging. */
|
||||
toString: function() {
|
||||
var str = "Page <b>\"" + this.name + "\"<b> {<br> \n";
|
||||
this.elements.forEach(function(e) {
|
||||
str += e.toString() + "<br> \n";
|
||||
});
|
||||
str += "} ";
|
||||
return str;
|
||||
},
|
||||
|
||||
/*
|
||||
* Build the DOM.
|
||||
*/
|
||||
buildDom: function() {
|
||||
var nodes = []
|
||||
this.elements.forEach(function(e) {
|
||||
nodes.push(e.domNode);
|
||||
});
|
||||
this.widget = new ContentPane({
|
||||
title: this.title,
|
||||
id: this.name,
|
||||
content: nodes,
|
||||
style: "height: 100%; width: 100%;"
|
||||
});
|
||||
this.domNode = this.widget.domNode;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return PageClass;
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
define([
|
||||
"dojo/_base/config",
|
||||
'dojo/_base/declare',
|
||||
"dojo/Deferred",
|
||||
"dojo/dom",
|
||||
"dojo/dom-construct",
|
||||
"hos/sitemap/pageelements/FrameElement",
|
||||
"hos/sitemap/pageelements/TextElement",
|
||||
"hos/sitemap/pageelements/SwitchElement",
|
||||
"hos/sitemap/pageelements/SliderElement",
|
||||
"hos/sitemap/pageelements/ErrorElement",
|
||||
], function(
|
||||
config,
|
||||
declare,
|
||||
Deferred,
|
||||
dom,
|
||||
domConstruct,
|
||||
FrameElement,
|
||||
TextElement,
|
||||
SwitchElement,
|
||||
SliderElement,
|
||||
ErrorElement
|
||||
) {
|
||||
|
||||
/*
|
||||
* Class representing a page element factory.
|
||||
*/
|
||||
var ElementFactoryClass = declare(null, {
|
||||
|
||||
/*
|
||||
* Creates and returns a page element.
|
||||
*/
|
||||
createPageElement: function(/*hos/sitemap/Page*/ page, /*json object*/ data, /*hos/sitemap/pageelements/CompositeElement*/ parent) {
|
||||
if (typeof(parent)==='undefined') parent = null;
|
||||
var element = null;
|
||||
if (data["type"] == "sitemap/sitemap#/definitions/frame_element") {
|
||||
element = new FrameElement(page, data, this, parent);
|
||||
} else if (data["type"] == "sitemap/sitemap#/definitions/text_element") {
|
||||
element = new TextElement(page, data, this, parent);
|
||||
} else if (data["type"] == "sitemap/sitemap#/definitions/switch_element") {
|
||||
element = new SwitchElement(page, data, this, parent);
|
||||
} else if (data["type"] == "sitemap/sitemap#/definitions/slider_element") {
|
||||
element = new SliderElement(page, data, this, parent);
|
||||
} else {
|
||||
element = new ErrorElement(page, data, this, parent);
|
||||
}
|
||||
element.buildDom();
|
||||
return element;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/* Create and return factory instance. */
|
||||
var factory = new ElementFactoryClass();
|
||||
return factory;
|
||||
});
|
||||
@@ -0,0 +1,213 @@
|
||||
define([
|
||||
"dojo/_base/config",
|
||||
'dojo/_base/declare',
|
||||
'dojo/_base/lang',
|
||||
"dojo/dom",
|
||||
"dojo/dom-construct",
|
||||
"dojo/Deferred",
|
||||
"dojox/uuid/generateRandomUuid",
|
||||
"hos/sitemap/Page",
|
||||
"hos/sitemap/widgets/SitemapWidget",
|
||||
"dojox/socket",
|
||||
"dojox/socket/Reconnect",
|
||||
"dojo/request/xhr"
|
||||
], function(
|
||||
config,
|
||||
declare,
|
||||
lang,
|
||||
dom,
|
||||
domConstruct,
|
||||
Deferred,
|
||||
generateRandomUuid,
|
||||
Page,
|
||||
SitemapWidget,
|
||||
Socket,
|
||||
Reconnect,
|
||||
xhr
|
||||
) {
|
||||
|
||||
/*
|
||||
* Class representing a sitemap.
|
||||
*/
|
||||
var SitemapClass = declare(null, {
|
||||
|
||||
/*
|
||||
* Constructor.
|
||||
*
|
||||
* api: parent API.
|
||||
*
|
||||
* name: sitemap name.
|
||||
*
|
||||
* data: sitemap json object received from server
|
||||
*/
|
||||
constructor: function(/*hos.sitemap.SitemapAPI*/ api, /*string*/ name, /*json object*/ data) {
|
||||
this.api = api;
|
||||
this.name = name;
|
||||
// parse json data
|
||||
this.rootPageName = data["rootpage"];
|
||||
this.title = data["title"];
|
||||
// Create pages
|
||||
this.pages = {}
|
||||
var _pages = data["pages"];
|
||||
for (var _pageName in _pages) {
|
||||
if (_pages.hasOwnProperty(_pageName)) {
|
||||
var _page = new Page(this, _pageName, _pages[_pageName]);
|
||||
this.pages[_pageName] = _page
|
||||
}
|
||||
}
|
||||
this.buildDom();
|
||||
},
|
||||
|
||||
/*
|
||||
* Dictionary containing all page elements.
|
||||
*/
|
||||
pageElements: {},
|
||||
|
||||
/*
|
||||
* Stack containing name of visited pages.
|
||||
* Needed for bread crumbs and back button.
|
||||
*/
|
||||
pageNameStack: [],
|
||||
|
||||
/* returns string representation for debugging. */
|
||||
toString: function() {
|
||||
var str = "Sitemap <b>\"" + this.name + "\"<b> {<br> \n";
|
||||
for (var pageName in this.pages) {
|
||||
str += this.pages[pageName].toString() + "<br> \n";
|
||||
}
|
||||
str += "} ";
|
||||
return str;
|
||||
},
|
||||
|
||||
/*
|
||||
* Build the DOM.
|
||||
*/
|
||||
buildDom: function() {
|
||||
this.widget = new SitemapWidget({sitemap: this});
|
||||
for (var pageName in this.pages) {
|
||||
var page = this.pages[pageName];
|
||||
page.buildDom();
|
||||
this.widget.stackContainer.addChild(page.widget);
|
||||
}
|
||||
this.domNode = this.widget.domNode;
|
||||
},
|
||||
|
||||
/*
|
||||
* Startup function.
|
||||
*/
|
||||
startup: function() {
|
||||
this.widget.startup();
|
||||
this.goToRootPage();
|
||||
this.enableUpdates();
|
||||
},
|
||||
|
||||
/*
|
||||
* Update the bread crumbs in the ui.
|
||||
*/
|
||||
updateBreadCrumbs: function() {
|
||||
var str = "> " + this.rootPageName;
|
||||
this.pageNameStack.forEach(function(e) {
|
||||
str += " > " + e;
|
||||
});
|
||||
this.widget.setBreadCrumbs(str);
|
||||
},
|
||||
|
||||
/*
|
||||
* Go to page with given name.
|
||||
*/
|
||||
goToPage: function(/*string*/ name) {
|
||||
this.pageNameStack.push(name);
|
||||
this.widget.stackContainer.selectChild(name, true);
|
||||
this.updateBreadCrumbs();
|
||||
},
|
||||
|
||||
/*
|
||||
* Go to root page.
|
||||
*/
|
||||
goToRootPage: function() {
|
||||
this.pageNameStack = [];
|
||||
this.widget.stackContainer.selectChild(this.rootPageName);
|
||||
this.updateBreadCrumbs();
|
||||
},
|
||||
|
||||
/*
|
||||
* Go one page back.
|
||||
*/
|
||||
goBack: function() {
|
||||
if (this.pageNameStack.length > 0) {
|
||||
this.pageNameStack.pop();
|
||||
if (this.pageNameStack.length > 0) {
|
||||
this.goToPage(this.pageNameStack.pop());
|
||||
} else {
|
||||
this.goToRootPage();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Connect to server and listen for updates.
|
||||
*/
|
||||
enableUpdates: function() {
|
||||
this._updateSocketOpened = false;
|
||||
this._updateSocketClientId = generateRandomUuid();
|
||||
this._updateSocket = Reconnect(new Socket({
|
||||
url: config.hos.sitemapUrl + "/" + this.name + '?onevent=all&clientid=' + this._updateSocketClientId,
|
||||
headers: {
|
||||
"On-Event": "changes",
|
||||
/*"Connection-Timeout": 60000,*/
|
||||
"Client-Id": 1234
|
||||
},
|
||||
transport: xhr.post
|
||||
}),{});
|
||||
this._updateSocket.on("open", lang.hitch(this, function(event){
|
||||
this._socketOpened = true;
|
||||
console.log("Socket Opened ", event.message);
|
||||
}));
|
||||
this._updateSocket.on("close", lang.hitch(this, function(event){
|
||||
this._socketOpened = false;
|
||||
console.log("Socket Closed ", event.message);
|
||||
}));
|
||||
this._updateSocket.on("error", lang.hitch(this, function(event){
|
||||
this._socketOpened = false;
|
||||
console.log("Socket Error ", event.message);
|
||||
}));
|
||||
this._updateSocket.on("message", lang.hitch(this, function(event) {
|
||||
var data = JSON.parse(event.data);
|
||||
console.log("Message: " + event);
|
||||
//console.log("Message: " + event.data);
|
||||
if (data && data["eventtype"] == "sitemap_element_changed") {
|
||||
var elements = data["elements"];
|
||||
elements.forEach(lang.hitch(this, function(e) {
|
||||
var uid = e["uid"];
|
||||
if (uid in this.pageElements) {
|
||||
var el = this.pageElements[uid];
|
||||
el.updateData(e);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
/*
|
||||
* Send command.
|
||||
*/
|
||||
sendPageElementCommand: function(uid, value) {
|
||||
if (this._updateSocket) {
|
||||
var msg = {eventtype: "sitemap_element_command", uid: uid, value: value};
|
||||
xhr.post(config.hos.sitemapUrl + "/" + this.name, {
|
||||
data: {method: 'command', value: JSON.stringify(msg)}
|
||||
}).then(function(data){
|
||||
console.log("sendPageElementCommand ok: " + data)
|
||||
}, function(err){
|
||||
console.log("sendPageElementCommand error: " + err)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return SitemapClass;
|
||||
});
|
||||
@@ -0,0 +1,98 @@
|
||||
define([
|
||||
"dojo/_base/config",
|
||||
'dojo/_base/declare',
|
||||
"dojo/request/xhr",
|
||||
"dojo/Deferred",
|
||||
"hos/sitemap/Sitemap"
|
||||
], function(config, declare, xhr, Deferred, Sitemap) {
|
||||
|
||||
/*
|
||||
* Class representing the sitemap API.
|
||||
*/
|
||||
var ApiClass = declare(null, {
|
||||
|
||||
/*
|
||||
* Constructor.
|
||||
*/
|
||||
constructor: function(/*string*/ baseUrl) {
|
||||
this.baseUrl = baseUrl;
|
||||
},
|
||||
|
||||
/*
|
||||
* Returns name of default sitemap.
|
||||
*
|
||||
* returns: Promise(string)
|
||||
*/
|
||||
getDefaultSitemapName: function() {
|
||||
var deferred = new Deferred();
|
||||
xhr.get(this.baseUrl, {
|
||||
handleAs: "json"
|
||||
}).then(function(data){
|
||||
deferred.resolve(data["default"]);
|
||||
}, function(err){
|
||||
deferred.reject(err);
|
||||
});
|
||||
return deferred;
|
||||
},
|
||||
|
||||
/*
|
||||
* Returns an array containing the names of all available sitemaps.
|
||||
*
|
||||
* returns: Promise(array(string))
|
||||
*/
|
||||
getSitemapNames: function() {
|
||||
var deferred = new Deferred();
|
||||
xhr.get(this.baseUrl, {
|
||||
handleAs: "json"
|
||||
}).then(function(data){
|
||||
deferred.resolve(data["sitemaps"]);
|
||||
}, function(err){
|
||||
deferred.reject(err);
|
||||
});
|
||||
return deferred;
|
||||
},
|
||||
|
||||
/*
|
||||
* Returns the sitemap with given name.
|
||||
*
|
||||
* returns: Promise(hos.sitemap.Sitemap)
|
||||
*/
|
||||
getSitemap: function(/*string*/ name) {
|
||||
var deferred = new Deferred();
|
||||
var _this = this
|
||||
xhr.get(this.baseUrl + "/" + name, {
|
||||
handleAs: "json"
|
||||
}).then(function(data){
|
||||
var sitemap = new Sitemap(_this, name, data)
|
||||
deferred.resolve(sitemap);
|
||||
}, function(err){
|
||||
deferred.reject(err);
|
||||
});
|
||||
return deferred;
|
||||
},
|
||||
|
||||
/*
|
||||
* Returns the default sitemap.
|
||||
*
|
||||
* returns: Promise(hos.sitemap.Sitemap)
|
||||
*/
|
||||
getDefaultSitemap: function() {
|
||||
var deferred = new Deferred();
|
||||
var _this = this
|
||||
this.getDefaultSitemapName().then(function(name){
|
||||
_this.getSitemap(name).then(function(sitemap){
|
||||
deferred.resolve(sitemap);
|
||||
}, function(err){
|
||||
deferred.reject(err);
|
||||
});
|
||||
}, function(err){
|
||||
deferred.reject(err);
|
||||
});
|
||||
return deferred;
|
||||
}
|
||||
});
|
||||
|
||||
/* Create and returns API instance. */
|
||||
var api = new ApiClass(config.hos.sitemapUrl);
|
||||
return api;
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
define([
|
||||
"dojo/_base/config",
|
||||
'dojo/_base/declare',
|
||||
"dojo/Deferred",
|
||||
"dojo/dom",
|
||||
"dojo/dom-construct",
|
||||
"hos/sitemap/pageelements/ElementBase"
|
||||
], function(config, declare, Deferred, dom, domConstruct, ElementBase) {
|
||||
|
||||
return declare([ElementBase], {
|
||||
|
||||
/*
|
||||
* constructor.
|
||||
*
|
||||
* page: parent page.
|
||||
*
|
||||
* data: page element json object received from server
|
||||
*
|
||||
* factory: reference to page element factory
|
||||
*
|
||||
* parent: parent page element
|
||||
*/
|
||||
constructor: function(/*hos.sitemap.Page*/ page, /*json object*/ data, /*hos.sitemap.PageElementFactory*/ factory, /*hos/sitemap/pageelements/CompositeElement*/ parent) {
|
||||
this.linkedPageName = data["linkedPage"];
|
||||
this.value = data["value"];
|
||||
},
|
||||
|
||||
/*
|
||||
* Go to linked page.
|
||||
*/
|
||||
goToLinkedPage: function() {
|
||||
if (this.linkedPageName) {
|
||||
this.page.sitemap.goToPage(this.linkedPageName);
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Update data.
|
||||
*/
|
||||
updateData: function(data) {
|
||||
this.inherited(arguments);
|
||||
this.value = data["value"];
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
define([
|
||||
"dojo/_base/config",
|
||||
'dojo/_base/declare',
|
||||
"dojo/Deferred",
|
||||
"dojo/dom",
|
||||
"dojo/dom-construct",
|
||||
"hos/sitemap/pageelements/ElementBase"
|
||||
], function(config, declare, Deferred, dom, domConstruct, ElementBase) {
|
||||
|
||||
return declare([ElementBase], {
|
||||
|
||||
/*
|
||||
* constructor.
|
||||
*
|
||||
* page: parent page.
|
||||
*
|
||||
* data: page element json object received from server
|
||||
*
|
||||
* factory: reference to page element factory
|
||||
*
|
||||
* parent: parent page element
|
||||
*/
|
||||
constructor: function(/*hos.sitemap.Page*/ page, /*json object*/ data, /*hos.sitemap.PageElementFactory*/ factory, /*hos/sitemap/pageelements/CompositeElement*/ parent) {
|
||||
this.elements = []
|
||||
var _this = this;
|
||||
data["elements"].forEach(function(data) {
|
||||
var element = factory.createPageElement(page, data, _this)
|
||||
_this.page.sitemap.pageElements[element.uid] = element;
|
||||
_this.elements.push(element)
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,58 @@
|
||||
define([
|
||||
"dojo/_base/config",
|
||||
'dojo/_base/declare',
|
||||
"dojo/Deferred",
|
||||
"dojo/dom",
|
||||
"dojo/dom-construct"
|
||||
], function(config, declare, Deferred, dom, domConstruct) {
|
||||
|
||||
return declare(null, {
|
||||
|
||||
/*
|
||||
* constructor.
|
||||
*
|
||||
* page: parent page.
|
||||
*
|
||||
* data: page element json object received from server
|
||||
*
|
||||
* factory: reference to page element factory
|
||||
*
|
||||
* parent: parent page element
|
||||
*/
|
||||
constructor: function(/*hos.sitemap.Page*/ page, /*json object*/ data, /*hos.sitemap.PageElementFactory*/ factory, /*hos/sitemap/pageelements/CompositeElement*/ parent) {
|
||||
this.page = page;
|
||||
this.parent = parent;
|
||||
this.factory = factory;
|
||||
this.uid = data["uid"];
|
||||
this.type = data["type"];
|
||||
this.icon = data["icon"];
|
||||
this.label = data["label"];
|
||||
},
|
||||
|
||||
/* returns string representation for debugging. */
|
||||
toString: function() {
|
||||
return " <b>**Unknown(" + this.uid + ")**</b> ";
|
||||
},
|
||||
|
||||
/*
|
||||
* Build the DOM.
|
||||
*/
|
||||
buildDom: function() {
|
||||
this.domNode = domConstruct.toDom(this.toString());
|
||||
},
|
||||
|
||||
/*
|
||||
* Update data.
|
||||
*/
|
||||
updateData: function(data) {
|
||||
this.label = data["label"];
|
||||
},
|
||||
|
||||
/*
|
||||
* Update DOM.
|
||||
*/
|
||||
updateDom: function() {
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
define([
|
||||
"dojo/_base/config",
|
||||
'dojo/_base/declare',
|
||||
"dojo/Deferred",
|
||||
"dojo/dom",
|
||||
"dojo/dom-construct",
|
||||
"hos/sitemap/pageelements/AtomicElement"
|
||||
], function(config, declare, Deferred, dom, domConstruct, AtomicElement) {
|
||||
|
||||
return declare([AtomicElement], {
|
||||
|
||||
/* returns string representation for debugging. */
|
||||
toString: function() {
|
||||
var str = " <b>ErrorElement (" + this.uid + ")</b> ";
|
||||
return str;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
define([
|
||||
"dojo/_base/config",
|
||||
'dojo/_base/declare',
|
||||
"dojo/Deferred",
|
||||
"dojo/dom",
|
||||
"dojo/dom-construct",
|
||||
"hos/sitemap/pageelements/CompositeElement",
|
||||
"dijit/TitlePane"
|
||||
], function(config, declare, Deferred, dom, domConstruct, CompositeElement, TitlePane) {
|
||||
|
||||
return declare([CompositeElement], {
|
||||
|
||||
/* returns string representation for debugging. */
|
||||
toString: function() {
|
||||
var str = " <b>FrameElement (" + this.uid + ")</b>{<br> \n";
|
||||
this.elements.forEach(function(e) {
|
||||
str += e.toString() + "<br> \n";
|
||||
});
|
||||
str += "} ";
|
||||
return str;
|
||||
},
|
||||
|
||||
/*
|
||||
* Build the DOM.
|
||||
*/
|
||||
buildDom: function() {
|
||||
var nodes = []
|
||||
this.elements.forEach(function(e) {
|
||||
nodes.push(e.domNode);
|
||||
});
|
||||
this.widget = new TitlePane({
|
||||
title:this.label,
|
||||
content:nodes
|
||||
});
|
||||
this.domNode = this.widget.domNode
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,100 @@
|
||||
define([
|
||||
"dojo/_base/config",
|
||||
'dojo/_base/declare',
|
||||
'dojo/_base/lang',
|
||||
"dojo/Deferred",
|
||||
"dojo/dom",
|
||||
"dojo/dom-construct",
|
||||
"hos/sitemap/pageelements/AtomicElement",
|
||||
"hos/sitemap/pageelements/widgets/ElementWidget",
|
||||
"dojox/mobile/Slider"
|
||||
], function(config, declare, lang, Deferred, dom, domConstruct, AtomicElement, ElementWidget, Slider) {
|
||||
|
||||
return declare([AtomicElement], {
|
||||
|
||||
/*
|
||||
* constructor.
|
||||
*
|
||||
* page: parent page.
|
||||
*
|
||||
* data: page element json object received from server
|
||||
*
|
||||
* factory: reference to page element factory
|
||||
*
|
||||
* parent: parent page element
|
||||
*/
|
||||
constructor: function(/*hos.sitemap.Page*/ page, /*json object*/ data, /*hos.sitemap.PageElementFactory*/ factory, /*hos/sitemap/pageelements/CompositeElement*/ parent) {
|
||||
this.min = data["min"];
|
||||
this.max = data["max"];
|
||||
},
|
||||
|
||||
/* returns string representation for debugging. */
|
||||
toString: function() {
|
||||
var str = " <b>SliderElement (" + this.uid + ")</b> ";
|
||||
return str;
|
||||
},
|
||||
|
||||
/*
|
||||
* Set Slider value.
|
||||
*/
|
||||
setSliderValue: function(value) {
|
||||
this.value = value/100;
|
||||
this.page.sitemap.sendPageElementCommand(this.uid, this.value);
|
||||
},
|
||||
|
||||
/*
|
||||
* Build the DOM.
|
||||
*/
|
||||
buildDom: function() {
|
||||
this.widget = new ElementWidget({baseClass: "SliderElementWidget"});
|
||||
/*this.sliderWidget = HorizontalSlider({
|
||||
minimum: this.min,
|
||||
maximum: this.max,
|
||||
value: this.value,
|
||||
onChange: lang.hitch(this, this.setSliderValue)
|
||||
});*/
|
||||
this.sliderWidget = Slider({
|
||||
minimum: this.min*100,
|
||||
maximum: this.max*100,
|
||||
value: this.value*100,
|
||||
style: "width: 95%;",
|
||||
onChange: lang.hitch(this, this.setSliderValue)
|
||||
});
|
||||
this.widget.setValue(this.sliderWidget.domNode);
|
||||
this.updateDom();
|
||||
this.domNode = this.widget.domNode;
|
||||
},
|
||||
|
||||
/*
|
||||
* Update data.
|
||||
*/
|
||||
updateData: function(data) {
|
||||
this.inherited(arguments);
|
||||
this.updateDom();
|
||||
},
|
||||
|
||||
/*
|
||||
* Update DOM.
|
||||
*/
|
||||
updateDom: function() {
|
||||
if (typeof(this.linkedPageName) != "undefined") {
|
||||
var tmp = domConstruct.create("a",{
|
||||
href: "javascript:void(0)",
|
||||
innerHTML: "<b>" + this.label + "</b>",
|
||||
onclick: lang.hitch(this, this.goToLinkedPage)
|
||||
});
|
||||
this.widget.setLabel(tmp);
|
||||
var tmp2 = domConstruct.create("div",{
|
||||
innerHTML: " >> ",
|
||||
onclick: lang.hitch(this, this.goToLinkedPage)
|
||||
});
|
||||
this.widget.setLink(tmp2);
|
||||
} else {
|
||||
this.widget.setLabel(domConstruct.toDom("<b>" + this.label + "</b>"));
|
||||
}
|
||||
this.sliderWidget.set("value", this.value*100);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,84 @@
|
||||
define([
|
||||
"dojo/_base/config",
|
||||
"dojo/_base/lang",
|
||||
"dojo/_base/declare",
|
||||
"dojo/Deferred",
|
||||
"dojo/dom",
|
||||
"dojo/dom-construct",
|
||||
"hos/sitemap/pageelements/AtomicElement",
|
||||
"hos/sitemap/pageelements/widgets/ElementWidget",
|
||||
"dojox/mobile/Switch"
|
||||
], function(config, lang, declare, Deferred, dom, domConstruct, AtomicElement, ElementWidget, Switch) {
|
||||
|
||||
return declare([AtomicElement], {
|
||||
|
||||
/* returns string representation for debugging. */
|
||||
toString: function() {
|
||||
var str = " <b>SwitchElement (" + this.uid + ")</b> ";
|
||||
return str;
|
||||
},
|
||||
|
||||
/*
|
||||
* Build the DOM.
|
||||
*/
|
||||
buildDom: function() {
|
||||
this.widget = new ElementWidget({baseClass: "SwitchElementWidget"});
|
||||
this.buttonWidget = Switch({
|
||||
});
|
||||
this.buttonWidget.on("stateChanged", lang.hitch(this, this.setSwitch));
|
||||
this.widget.setValue(this.buttonWidget.domNode);
|
||||
this.updateDom();
|
||||
this.domNode = this.widget.domNode;
|
||||
},
|
||||
|
||||
/*
|
||||
* Toggle switch.
|
||||
*/
|
||||
toggleSwitch: function() {
|
||||
this.value = !this.value;
|
||||
this.updateDom();
|
||||
this.page.sitemap.sendPageElementCommand(this.uid, this.value);
|
||||
},
|
||||
|
||||
/*
|
||||
* Set switch.
|
||||
*/
|
||||
setSwitch: function(value) {
|
||||
this.value = (value == "on");
|
||||
this.updateDom();
|
||||
this.page.sitemap.sendPageElementCommand(this.uid, this.value);
|
||||
},
|
||||
|
||||
/*
|
||||
* Update data.
|
||||
*/
|
||||
updateData: function(data) {
|
||||
this.inherited(arguments);
|
||||
this.updateDom();
|
||||
},
|
||||
|
||||
/*
|
||||
* Update DOM.
|
||||
*/
|
||||
updateDom: function() {
|
||||
if (typeof(this.linkedPageName) != "undefined") {
|
||||
var tmp = domConstruct.create("a",{
|
||||
href: "javascript:void(0)",
|
||||
innerHTML: "<b>" + this.label + "</b>",
|
||||
onclick: lang.hitch(this, this.goToLinkedPage)
|
||||
});
|
||||
this.widget.setLabel(tmp);
|
||||
var tmp2 = domConstruct.create("div",{
|
||||
innerHTML: " >> ",
|
||||
onclick: lang.hitch(this, this.goToLinkedPage)
|
||||
});
|
||||
this.widget.setLink(tmp2);
|
||||
} else {
|
||||
this.widget.setLabel(domConstruct.toDom("<b>" + this.label + "</b>"));
|
||||
}
|
||||
this.buttonWidget.set("value", this.value ? "on" : "off");
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
define([
|
||||
"dojo/_base/config",
|
||||
'dojo/_base/declare',
|
||||
"dojo/_base/lang",
|
||||
"dojo/Deferred",
|
||||
"dojo/dom",
|
||||
"dojo/dom-construct",
|
||||
"hos/sitemap/pageelements/AtomicElement",
|
||||
"hos/sitemap/pageelements/widgets/ElementWidget"
|
||||
], function(config, declare, lang, Deferred, dom, domConstruct, AtomicElement, ElementWidget) {
|
||||
|
||||
return declare([AtomicElement], {
|
||||
|
||||
/* returns string representation for debugging. */
|
||||
toString: function() {
|
||||
var str = " <b>TextElement (" + this.uid + ")</b> ";
|
||||
return str;
|
||||
},
|
||||
|
||||
/*
|
||||
* Build the DOM.
|
||||
*/
|
||||
buildDom: function() {
|
||||
this.widget= new ElementWidget({baseClass: "TextElementWidget"});
|
||||
this.updateDom();
|
||||
this.domNode = this.widget.domNode;
|
||||
},
|
||||
|
||||
/*
|
||||
* Update data.
|
||||
*/
|
||||
updateData: function(data) {
|
||||
this.inherited(arguments);
|
||||
this.updateDom();
|
||||
},
|
||||
|
||||
/*
|
||||
* Update DOM.
|
||||
*/
|
||||
updateDom: function() {
|
||||
if (typeof(this.linkedPageName) != "undefined") {
|
||||
var tmp = domConstruct.create("a",{
|
||||
href: "javascript:void(0)",
|
||||
innerHTML: "<b>" + this.label + "</b>",
|
||||
onclick: lang.hitch(this, this.goToLinkedPage)
|
||||
});
|
||||
this.widget.setLabel(tmp);
|
||||
var tmp2 = domConstruct.create("div",{
|
||||
innerHTML: " >> ",
|
||||
onclick: lang.hitch(this, this.goToLinkedPage)
|
||||
});
|
||||
this.widget.setLink(tmp2);
|
||||
} else {
|
||||
this.widget.setLabel(domConstruct.toDom("<b>" + this.label + "</b>"));
|
||||
}
|
||||
this.widget.setValue(domConstruct.toDom("<b>" + this.value + "</b>"));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
define([
|
||||
"dojo/_base/declare",
|
||||
"dojo/dom",
|
||||
"dojo/dom-construct",
|
||||
"dijit/_WidgetBase",
|
||||
"dijit/_TemplatedMixin",
|
||||
"dojo/text!./templates/ElementWidget.html"
|
||||
], function(declare, dom, domConstruct, _WidgetBase, _TemplatedMixin, template) {
|
||||
|
||||
return declare([_WidgetBase, _TemplatedMixin], {
|
||||
|
||||
templateString: template,
|
||||
|
||||
setLabel: function(label) {
|
||||
domConstruct.empty(this.domLabelNode);
|
||||
domConstruct.place(label, this.domLabelNode);
|
||||
},
|
||||
|
||||
setValue: function(value) {
|
||||
domConstruct.empty(this.domValueNode);
|
||||
domConstruct.place(value, this.domValueNode);
|
||||
},
|
||||
|
||||
setLink: function(link) {
|
||||
domConstruct.empty(this.domLinkNode);
|
||||
domConstruct.place(link, this.domLinkNode);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<div class="${baseClass}" data-dojo-attach-point="domNode" style="background-color: #fcfcfc;">
|
||||
<table class="${baseClass}Table" data-dojo-attach-point="domTableNode" style="width:100%;">
|
||||
<tr>
|
||||
<td class="${baseClass}Icon" data-dojo-attach-point="domIconNode"></td>
|
||||
<td class="${baseClass}Label" data-dojo-attach-point="domLabelNode" style="width: 50%;"></td>
|
||||
<td class="${baseClass}Value" data-dojo-attach-point="domValueNode" style="text-align: right; width: 50%;"></td>
|
||||
<td class="${baseClass}Link" data-dojo-attach-point="domLinkNode"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
@@ -0,0 +1,86 @@
|
||||
define([
|
||||
"dojo/_base/declare",
|
||||
"dojo/_base/lang",
|
||||
"dojo/dom",
|
||||
"dojo/dom-construct",
|
||||
"dijit/_WidgetBase",
|
||||
"dijit/layout/BorderContainer",
|
||||
"dijit/layout/StackContainer",
|
||||
"dijit/layout/ContentPane",
|
||||
"dijit/form/Button"
|
||||
], function(declare, lang, dom, domConstruct, _WidgetBase, BorderContainer, StackContainer, ContentPane, Button) {
|
||||
|
||||
return declare([_WidgetBase], {
|
||||
|
||||
/*
|
||||
* buildRendering function.
|
||||
*/
|
||||
buildRendering: function() {
|
||||
if(!this._rendered){
|
||||
|
||||
// create a BorderContainer as the top widget in the hierarchy
|
||||
this.bc = new BorderContainer({
|
||||
style: "width: 100%; height: 100%;"
|
||||
|
||||
});
|
||||
|
||||
// create a ContentPane as the left pane in the BorderContainer
|
||||
/*this.cp1 = new ContentPane({
|
||||
region: "left",
|
||||
splitter: true,
|
||||
style: "width: 150px;",
|
||||
content: "<h4>Sitemap/Navigation</h4><ul><li>ToDo</li></ul>"
|
||||
});
|
||||
this.bc.addChild(this.cp1);*/
|
||||
|
||||
this.stackContainer = StackContainer();
|
||||
this.backButton = new Button({
|
||||
label: "Back",
|
||||
onClick: lang.hitch(this, function(){
|
||||
this.sitemap.goBack();
|
||||
})
|
||||
});
|
||||
this.homeButton = new Button({
|
||||
label: "Home",
|
||||
onClick: lang.hitch(this, function(){
|
||||
this.sitemap.goToRootPage();
|
||||
})
|
||||
});
|
||||
// create a ContentPane as the center pane in the BorderContainer
|
||||
this.cp2 = new ContentPane({
|
||||
region: "center",
|
||||
content: [this.stackContainer.domNode, this.backButton.domNode, this.homeButton.domNode]
|
||||
});
|
||||
this.bc.addChild(this.cp2);
|
||||
|
||||
var contentNode = domConstruct.toDom("<b>Home Operating System:</b> <div id=\"breadCrumbNode\">bread crumbs here</div>");
|
||||
this.breadCrumbNode = dom.byId("breadCrumbNode", contentNode)
|
||||
// create a ContentPane as the top pane in the BorderContainer
|
||||
this.cp3 = new ContentPane({
|
||||
region: "top",
|
||||
content: contentNode
|
||||
});
|
||||
this.bc.addChild(this.cp3);
|
||||
|
||||
this.domNode = this.bc.domNode;
|
||||
}
|
||||
this.inherited(arguments);
|
||||
this._rendered = true;
|
||||
},
|
||||
|
||||
/*
|
||||
* startup function.
|
||||
*/
|
||||
startup: function() {
|
||||
this.bc.startup();
|
||||
},
|
||||
|
||||
/*
|
||||
* Set bread crumbs.
|
||||
*/
|
||||
setBreadCrumbs: function(/*string*/ text) {
|
||||
this.breadCrumbNode.innerHTML=text
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
echo 'Hello World! Running on "'.php_uname().'" and time is '.date('Y-m-d H:i:s')."\n";
|
||||
echo "debug1\n";
|
||||
require_once('../index.php');
|
||||
echo "debug2\n";
|
||||
?>
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#appLayout {
|
||||
height: 100%;
|
||||
}
|
||||
#leftCol {
|
||||
width: 14em;
|
||||
}
|
||||
|
||||
.claro .demoLayout .edgePanel {
|
||||
background-color: #d0e9fc;
|
||||
}
|
||||
|
||||
#viewsChart {
|
||||
width: 550px;
|
||||
height: 550px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.claro .dijitToggleButtonChecked .dijitButtonNode {
|
||||
background-color: #0090ff;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2) inset;
|
||||
transition-duration: 0.1s;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Sitemap Test 01</title>
|
||||
|
||||
<link rel="stylesheet" href="libs/dijit/themes/claro/claro.css" media="screen">
|
||||
<link rel="stylesheet" href="libs/dojox/mobile/themes/ios7/ios7.css" media="screen">
|
||||
<link rel="stylesheet" href="sitemap01.css" media="screen">
|
||||
|
||||
<!-- configure Dojo -->
|
||||
<script>
|
||||
var dojoConfig = {
|
||||
async: true,
|
||||
parseOnLoad: true,
|
||||
isDebug: true,
|
||||
deps: [
|
||||
"dojo/parser",
|
||||
"dijit/layout/BorderContainer",
|
||||
"dijit/layout/TabContainer",
|
||||
"dijit/layout/ContentPane",
|
||||
"dijit/Calendar",
|
||||
"dijit/Fieldset",
|
||||
"dijit/TitlePane",
|
||||
"dijit/form/HorizontalSlider",
|
||||
"dijit/form/HorizontalRule",
|
||||
"dijit/form/HorizontalRuleLabels"
|
||||
],
|
||||
hos: {
|
||||
deviceRepoUrl: "/hos/api/devices",
|
||||
sitemapUrl: "/hos/api/sitemap"
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- load Dojo -->
|
||||
<script src="libs/dojo/dojo.js"
|
||||
data-dojo-config="async: true"></script>
|
||||
</head>
|
||||
|
||||
|
||||
<body class="claro">
|
||||
|
||||
<script>
|
||||
require([
|
||||
"hos/sitemap/SitemapAPI",
|
||||
"dojo/dom-construct",
|
||||
"dojo/dom",
|
||||
"dojo/domReady!"
|
||||
], function(sitemapAPI, domConstruct, dom) {
|
||||
sitemapAPI.getDefaultSitemap().then(function(sitemap) {
|
||||
domConstruct.place(sitemap.domNode, "contentPane");
|
||||
sitemap.startup();
|
||||
}, function(error) {
|
||||
var node = domConstruct.toDom("<b>Error: " + error + "</b>");
|
||||
domConstruct.place(node, "contentPane");
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="contentPane" style="width: 100%; height: 100%;"></div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,65 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Sitemap Test 01</title>
|
||||
|
||||
<link rel="stylesheet" href="libs/dijit/themes/claro/claro.css" media="screen">
|
||||
<link rel="stylesheet" href="libs/dojox/mobile/themes/ios7/ios7.css" media="screen">
|
||||
<link rel="stylesheet" href="sitemap01.css" media="screen">
|
||||
|
||||
<!-- configure Dojo -->
|
||||
<script>
|
||||
var dojoConfig = {
|
||||
async: true,
|
||||
parseOnLoad: true,
|
||||
isDebug: true,
|
||||
deps: [
|
||||
"dojo/parser",
|
||||
"dijit/layout/BorderContainer",
|
||||
"dijit/layout/TabContainer",
|
||||
"dijit/layout/ContentPane",
|
||||
"dijit/Calendar",
|
||||
"dijit/Fieldset",
|
||||
"dijit/TitlePane",
|
||||
"dijit/form/HorizontalSlider",
|
||||
"dijit/form/HorizontalRule",
|
||||
"dijit/form/HorizontalRuleLabels"
|
||||
],
|
||||
hos: {
|
||||
deviceRepoUrl: "/hos/api/devices",
|
||||
sitemapUrl: "/hos/api/sitemap"
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- load Dojo -->
|
||||
<script src="libs/dojo/dojo.js"
|
||||
data-dojo-config="async: true"></script>
|
||||
</head>
|
||||
|
||||
|
||||
<body class="claro">
|
||||
|
||||
<script>
|
||||
require([
|
||||
"hos/sitemap/SitemapAPI",
|
||||
"dojo/dom-construct",
|
||||
"dojo/dom",
|
||||
"dojo/domReady!"
|
||||
], function(sitemapAPI, domConstruct, dom) {
|
||||
sitemapAPI.getSitemap("test02").then(function(sitemap) {
|
||||
domConstruct.place(sitemap.domNode, "contentPane");
|
||||
sitemap.startup();
|
||||
}, function(error) {
|
||||
var node = domConstruct.toDom("<b>Error: " + error + "</b>");
|
||||
domConstruct.place(node, "contentPane");
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="contentPane" style="width: 100%; height: 100%;"></div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -33,7 +33,7 @@
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [ "type", "set" ]
|
||||
"required": [ "set" ]
|
||||
},
|
||||
"effect": {
|
||||
"description": "",
|
||||
@@ -49,7 +49,7 @@
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [ "type", "set" ]
|
||||
"required": [ "set" ]
|
||||
},
|
||||
"advproperties": {
|
||||
"description": "",
|
||||
@@ -64,15 +64,15 @@
|
||||
}
|
||||
},
|
||||
"additionalProperties": true,
|
||||
"required": [ "type" ]
|
||||
"required": []
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"anyOf": [
|
||||
{ "required": [ "type", "switch" ] },
|
||||
{ "required": [ "type", "brightness" ] },
|
||||
{ "required": [ "type", "color" ] },
|
||||
{ "required": [ "type", "alert" ] },
|
||||
{ "required": [ "type", "effect" ] }
|
||||
{ "required": [ "switch" ] },
|
||||
{ "required": [ "brightness" ] },
|
||||
{ "required": [ "color" ] },
|
||||
{ "required": [ "alert" ] },
|
||||
{ "required": [ "effect" ] }
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user