diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/pom.xml b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/pom.xml
new file mode 100644
index 0000000000..069494173f
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/pom.xml
@@ -0,0 +1,171 @@
+
+
+
+
+
+ org.wso2.carbon.devicemgt-plugins
+ device-mgt-iot-feature
+ 1.9.2-SNAPSHOT
+ ../pom.xml
+
+
+ 4.0.0
+ org.wso2.carbon.device.mgt.iot.feature
+ pom
+ 1.9.2-SNAPSHOT
+ WSO2 Carbon - IoT Server - Features
+ http://wso2.org
+ This feature contains the core bundles required for IoT Server
+
+
+
+ org.wso2.carbon.devicemgt-plugins
+ org.wso2.carbon.device.mgt.iot
+
+
+
+ org.wso2.carbon.devicemgt-plugins
+ org.wso2.carbon.device.mgt.iot.api
+ war
+
+
+
+ org.json.wso2
+ json
+
+
+
+
+ org.igniterealtime.smack.wso2
+ smack
+
+
+ org.igniterealtime.smack.wso2
+ smackx
+
+
+
+ net.sf.ehcache.wso2
+ ehcache
+ 1.5.0.wso2v3
+
+
+
+
+
+
+
+ maven-resources-plugin
+
+
+ copy-resources
+ generate-resources
+
+ copy-resources
+
+
+ src/main/resources
+
+
+ resources
+
+ build.properties
+ p2.inf
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ copy
+ package
+
+ copy
+
+
+
+
+ org.wso2.carbon.devicemgt-plugins
+ org.wso2.carbon.device.mgt.iot.api
+ war
+ true
+ ${basedir}/src/main/resources/webapps/
+ common.war
+
+
+
+
+
+
+
+ org.wso2.maven
+ carbon-p2-plugin
+
+
+ p2-feature-generation
+ package
+
+ p2-feature-gen
+
+
+ org.wso2.carbon.device.mgt.iot
+ ../../../features/etc/feature.properties
+
+
+ org.wso2.carbon.p2.category.type:server
+ org.eclipse.equinox.p2.type.group:false
+
+
+
+
+ org.wso2.carbon.devicemgt-plugins:org.wso2.carbon.device.mgt.iot:${carbon.iot.device.mgt.version}
+
+
+ org.json.wso2:json:${commons-json.version}
+
+
+ org.igniterealtime.smack.wso2:smack:${smack.wso2.version}
+
+
+ org.igniterealtime.smack.wso2:smackx:${smackx.wso2.version}
+
+
+ net.sf.ehcache.wso2:ehcache
+
+
+
+ org.wso2.carbon.core.server:${carbon.kernel.version}
+
+ org.wso2.carbon.device.mgt.server:${carbon.device.mgt.version}
+
+
+
+
+
+
+
+
+
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/build.properties b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/build.properties
new file mode 100644
index 0000000000..9c86577d76
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/build.properties
@@ -0,0 +1 @@
+custom = true
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/devicecloud-config.xml b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/devicecloud-config.xml
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/devicecloud-config.xml
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/devicecloud-config.xml
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/devicecloud-config.xsd b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/devicecloud-config.xsd
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/devicecloud-config.xsd
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/devicecloud-config.xsd
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/iot-config.xml b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/iot-config.xml
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/iot-config.xml
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/iot-config.xml
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/iot-config.xsd b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/iot-config.xsd
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/iot-config.xsd
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/conf/iot-config.xsd
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/device-api.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/device-api.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/device-api.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/device-api.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/event-api.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/event-api.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/event-api.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/event-api.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/group-api.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/group-api.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/group-api.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/group-api.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/operation-api.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/operation-api.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/operation-api.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/operation-api.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/policy-api.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/policy-api.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/policy-api.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/policy-api.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/stats-api.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/stats-api.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/stats-api.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/stats-api.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/user-api.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/user-api.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/user-api.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/api/user-api.jag
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/config/config.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/config/config.json
new file mode 100644
index 0000000000..b4516196eb
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/config/config.json
@@ -0,0 +1,16 @@
+{
+ "appContext" : "/iotserver/",
+ "apiContext" : "api",
+ "httpsURL": "%https.ip%",
+ "httpURL": "%http.ip%",
+ "ssoConfiguration": {
+ "enabled": false,
+ "issuer": "iot",
+ "appName": "iot",
+ "identityProviderURL": "%https.ip%/sso/samlsso.jag",
+ "responseSigningEnabled": "true",
+ "keyStorePassword": "wso2carbon",
+ "identityAlias": "wso2carbon",
+ "keyStoreName": "/repository/resources/security/wso2carbon.jks"
+ }
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/config/dc-props.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/config/dc-props.js
new file mode 100644
index 0000000000..7911f514d0
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/config/dc-props.js
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var config = function () {
+ var conf = application.get("PINCH_CONFIG");
+ if (!conf) {//if not in cache
+ var pinch = require('/modules/pinch.min.js').pinch;
+ var server = require('carbon').server;
+ var config = require('/config/config.json');
+ pinch(config, /^/, function (path, key, value) {
+ if ((typeof value === 'string') && value.indexOf('%https.ip%') > -1) {
+ return value.replace('%https.ip%', server.address("https"));
+ } else if ((typeof value === 'string') && value.indexOf('%http.ip%') > -1) {
+ return value.replace('%http.ip%', server.address("http"));
+ }
+ return value;
+ });
+ application.put("PINCH_CONFIG", config);//caching
+ conf = config;
+ }
+ return conf;
+};
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/config/init.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/config/init.js
new file mode 100644
index 0000000000..5fd208f2da
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/config/init.js
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var carbonModule = require("carbon");
+var dcProps = require('/config/dc-props.js').config();
+var carbonServer = new carbonModule.server.Server({
+ tenanted: true,
+ url: dcProps.httpsURL + '/admin'
+});
+application.put("carbonServer", carbonServer);
+var userModule = require("/modules/user.js").userModule;
+var utility = require("/modules/utility.js").utility;
+utility.insertAppPermissions(userModule, "init");
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/jaggery.conf b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/jaggery.conf
new file mode 100644
index 0000000000..5a7e83c162
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/jaggery.conf
@@ -0,0 +1,67 @@
+{
+ "displayName": "Fuse Sample",
+ "logLevel": "info",
+ "initScripts": ["/config/init.js"],
+ "urlMappings": [
+ {
+ "url" : "/testb/*",
+ "path" : "test.jag"
+ },
+ {
+ "url" : "/test/*",
+ "path" : "test/testExecutor.jag"
+ },
+ {
+ "url": "/api/device/*",
+ "path": "/api/device-api.jag"
+ },
+ {
+ "url": "/api/devices/*",
+ "path": "/api/device-api.jag"
+ },
+ {
+ "url": "/api/group/*",
+ "path": "/api/group-api.jag"
+ },
+ {
+ "url": "/api/event/*",
+ "path": "/api/event-api.jag"
+ },
+ {
+ "url": "/api/operation/*",
+ "path": "/api/operation-api.jag"
+ },
+ {
+ "url": "/api/user/*",
+ "path": "/api/user-api.jag"
+ },
+ {
+ "url": "/api/users/*",
+ "path": "/api/user-api.jag"
+ },
+ {
+ "url": "/api/stats/*",
+ "path": "/api/stats-api.jag"
+ },
+ {
+ "url": "/api/policies/*",
+ "path": "/api/policy-api.jag"
+ },
+ {
+ "url": "/sso/login",
+ "path": "/lib/login.jag"
+ },
+ {
+ "url": "/sso/logout",
+ "path": "/lib/logout.jag"
+ },
+ {
+ "url": "/sso/acs",
+ "path": "/lib/acs.jag"
+ },
+ {
+ "url": "/*",
+ "path": "/lib/fuse.jag"
+ }
+ ]
+}
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/layouts/enrollment.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/layouts/enrollment.hbs
new file mode 100644
index 0000000000..553c912377
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/layouts/enrollment.hbs
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+ {{ defineZone "title"}}
+
+ {{ defineZone "topLibCss"}}
+ {{ defineZone "topCss"}}
+
+
+
+
+
+
+ {{ defineZone "body"}}
+ {{ defineZone "footer"}}
+
+ {{ defineZone "bottomjquery" }}
+ {{ defineZone "bottomLibJs" }}
+ {{ defineZone "bottomJs" }}
+
+
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/layouts/fluid-backup.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/layouts/fluid-backup.hbs
new file mode 100644
index 0000000000..6c9436ce6c
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/layouts/fluid-backup.hbs
@@ -0,0 +1,44 @@
+
+
+
+
+ {{ defineZone "title"}}
+ {{ defineZone "topCss"}}
+
+
+
+
+
+
+
+
+ Login
+ {{ defineZone "upperRight"}}
+
+
+
+
+
+
+
+
+ {{ defineZone "content"}}
+
+
+
+
+
+
+
+
+
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/layouts/fluid.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/layouts/fluid.hbs
new file mode 100644
index 0000000000..6cedfaad5a
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/layouts/fluid.hbs
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+ {{defineZone "favicon"}}
+
+ {{ defineZone "title"}}
+
+ {{ defineZone "topLibCss"}}
+ {{ defineZone "topCss"}}
+
+
+
+ {{ defineZone "notification"}}
+
+
+ {{ defineZone "header"}}
+
+ {{ defineZone "body"}}
+ {{ defineZone "footer"}}
+
+ {{ defineZone "bottomjquery" }}
+ {{ defineZone "bottomLibJs" }}
+ {{ defineZone "bottomJs" }}
+
+
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/layouts/nav-fluid.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/layouts/nav-fluid.hbs
new file mode 100644
index 0000000000..0027877267
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/layouts/nav-fluid.hbs
@@ -0,0 +1,50 @@
+
+
+
+
+ {{ defineZone "title"}}
+ {{ defineZone "topCss"}}
+
+
+
+
+
+
+
+ Login
+ {{ defineZone "upperRight"}}
+
+
+
+
+
+
+
+
+
+
+ {{ defineZone "left"}}
+
+
+
+ {{ defineZone "content"}}
+
+
+
+
+
+
+
+
+
+
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/acs.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/acs.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/acs.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/acs.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/fuse-router.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/fuse-router.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/fuse-router.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/fuse-router.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/fuse.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/fuse.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/fuse.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/fuse.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/fuse.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/fuse.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/fuse.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/fuse.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/handlebars-helpers.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/handlebars-helpers.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/handlebars-helpers.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/handlebars-helpers.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/handlebars-v2.0.0.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/handlebars-v2.0.0.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/handlebars-v2.0.0.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/handlebars-v2.0.0.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/less-rhino-1.7.5.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/less-rhino-1.7.5.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/less-rhino-1.7.5.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/less-rhino-1.7.5.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/login.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/login.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/login.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/login.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/logout.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/logout.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/logout.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/lib/logout.jag
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/api-wrapper-util.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/api-wrapper-util.js
new file mode 100644
index 0000000000..2de3c4fac4
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/api-wrapper-util.js
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var apiWrapperUtil = function () {
+ var module = {};
+ var tokenUtil = require("/modules/util.js").util;
+ module.refreshToken = function () {
+ var tokenPair = session.get("accessTokenPair");
+ tokenPair = tokenUtil.refreshToken(tokenPair);
+ session.put("accessTokenPair", tokenPair);
+ response.addCookie({'name': 'accessToken', 'value': tokenPair.accessToken});
+ };
+ module.setupAccessTokenPair = function (type, properties) {
+ var tokenPair;
+ var clientId = "pY0FbBUC_GI7mfHVS1FvhWAifEwa";
+ var clientSecret = "Tu5Za1R3fHtGc5yH4KK8TNiLVSca";
+ if (type == "password") {
+ //tokenPair = tokenUtil.getTokenWithPasswordGrantType(properties.username, properties.password, clientId, clientSecret);
+ } else if (type == "saml") {
+
+ }
+ //session.put("accessTokenPair", tokenPair);
+ //response.addCookie({'name': 'accessToken', 'value': tokenPair.accessToken});
+ };
+ return module;
+}();
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/constants.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/constants.js
new file mode 100644
index 0000000000..c0cb451682
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/constants.js
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var WEB_APP_TITLE = "WSO2 IoT - IoT Server";
+var WEB_APP_CONTEXT = "/iotserver";
+var USER_SESSION_KEY = "USER";
+var UNSPECIFIED = "Unspecified";
+var DEVICES_UNIT_PATH="/units/";
+var POLICY_REGISTRY_PATH="/_system/governance/policy_declarations/";
+
+var DEVICE_IDENTIFIER = "deviceIdentifier";
+var DEVICE_NAME = "name";
+var DEVICE_OWNERSHIP = "ownership";
+var DEVICE_OWNER = "owner";
+var DEVICE_TYPE = "type";
+var DEVICE_VENDOR = "vendor";
+var DEVICE_MODEL = "model";
+var DEVICE_PRODUCT = "PRODUCT";
+var DEVICE_OS_VERSION = "osVersion";
+var DEVICE_PROPERTIES = "properties";
+
+var FEATURE_NAME = "featureName";
+var FEATURE_DESCRIPTION = "featureDescription";
+
+var PLATFORM_ANDROID = "android";
+var PLATFORM_IOS = "ios";
+var DEVICE_ENROLLMENT = "dateOfEnrolment";
+
+var VENDOR_APPLE = "Apple";
+var ERRORS = {
+ "USER_NOT_FOUND": "USER_NOT_FOUND"
+};
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/device.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/device.js
new file mode 100644
index 0000000000..195bba887c
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/device.js
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+var deviceModule;
+deviceModule = function () {
+ var log = new Log("modules/device.js");
+
+ var constants = require("/modules/constants.js");
+ var utility = require("/modules/utility.js").utility;
+
+ var carbon = require('carbon');
+ var carbonHttpServletTransport = carbon.server.address('http');
+ var carbonHttpsServletTransport = carbon.server.address('https');
+
+ var ArrayList = Packages.java.util.ArrayList;
+ var Properties = Packages.java.util.Properties;
+ var DeviceIdentifier = Packages.org.wso2.carbon.device.mgt.common.DeviceIdentifier;
+ var DeviceManagerUtil = Packages.org.wso2.carbon.device.mgt.core.util.DeviceManagerUtil;
+ var SimpleOperation = Packages.org.wso2.carbon.device.mgt.core.operation.mgt.SimpleOperation;
+ var ConfigOperation = Packages.org.wso2.carbon.device.mgt.core.operation.mgt.ConfigOperation;
+ var CommandOperation = Packages.org.wso2.carbon.device.mgt.core.operation.mgt.CommandOperation;
+ var deviceManagementDAOFactory = Packages.org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory;
+
+ var deviceManagementService = utility.getDeviceManagementService();
+
+ var publicMethods = {};
+ var privateMethods = {};
+
+ privateMethods.validateAndReturn = function (value) {
+ return (value == undefined || value == null) ? constants.UNSPECIFIED : value;
+ };
+
+ privateMethods.getStoreDefinition = function (deviceTypeStr) {
+ var storeJSON = new File(constants.DEVICES_UNIT_PATH + deviceTypeStr + "/public/store.json");
+ if (storeJSON.isExists()) {
+ storeJSON.open('r');
+ log.debug('reading file "' + storeJSON.getPath() + '"');
+ var content = storeJSON.readAll().trim();
+ storeJSON.close();
+ return parse(content);
+ }
+ return null;
+ };
+
+ publicMethods.listDevices = function () {
+ var devices = deviceManagementService.getAllDevices();
+ var deviceList = [];
+ var i, device, propertiesList, deviceObject;
+ for (i = 0; i < devices.size(); i++) {
+ device = devices.get(i);
+ propertiesList = DeviceManagerUtil.convertDevicePropertiesToMap(device.getProperties());
+
+ deviceObject = {};
+ deviceObject[constants.DEVICE_IDENTIFIER] =
+ privateMethods.validateAndReturn(device.getDeviceIdentifier());
+ deviceObject[constants.DEVICE_NAME] =
+ privateMethods.validateAndReturn(device.getName());
+ deviceObject[constants.DEVICE_OWNERSHIP] =
+ privateMethods.validateAndReturn(device.getOwnership());
+ deviceObject[constants.DEVICE_OWNER] =
+ privateMethods.validateAndReturn(device.getOwner());
+ deviceObject[constants.DEVICE_TYPE] =
+ privateMethods.validateAndReturn(device.getType());
+ deviceObject[constants.DEVICE_PROPERTIES] = {};
+ if (device.getType() == constants.PLATFORM_IOS) {
+ deviceObject[constants.DEVICE_PROPERTIES][constants.DEVICE_MODEL] =
+ privateMethods.validateAndReturn(propertiesList.get(constants.DEVICE_PRODUCT));
+ deviceObject[constants.DEVICE_PROPERTIES][constants.DEVICE_VENDOR] = constants.VENDOR_APPLE;
+ } else {
+ deviceObject[constants.DEVICE_PROPERTIES][constants.DEVICE_MODEL] =
+ privateMethods.validateAndReturn(propertiesList.get(constants.DEVICE_MODEL));
+ deviceObject[constants.DEVICE_PROPERTIES][constants.DEVICE_VENDOR] =
+ privateMethods.validateAndReturn(propertiesList.get(constants.DEVICE_VENDOR));
+ }
+ deviceObject[constants.DEVICE_PROPERTIES][constants.DEVICE_OS_VERSION] =
+ privateMethods.validateAndReturn(propertiesList.get(constants.DEVICE_OS_VERSION));
+
+ deviceList.push(deviceObject);
+ }
+ return deviceList;
+ };
+
+ publicMethods.listDevicesForUser = function (username) {
+ var devices = deviceManagementService.getDeviceListOfUser(username);
+ var deviceList = [];
+ var i, device, propertiesList, deviceObject;
+ for (i = 0; i < devices.size(); i++) {
+ device = devices.get(i);
+ propertiesList = DeviceManagerUtil.convertDevicePropertiesToMap(device.getProperties());
+
+ deviceObject = {};
+ deviceObject[constants.DEVICE_IDENTIFIER] =
+ privateMethods.validateAndReturn(device.getDeviceIdentifier());
+ deviceObject[constants.DEVICE_NAME] =
+ privateMethods.validateAndReturn(device.getName());
+ deviceObject[constants.DEVICE_OWNERSHIP] =
+ privateMethods.validateAndReturn(device.getOwnership());
+ deviceObject[constants.DEVICE_OWNER] =
+ privateMethods.validateAndReturn(device.getOwner());
+ deviceObject[constants.DEVICE_TYPE] =
+ privateMethods.validateAndReturn(device.getType());
+ deviceObject[constants.DEVICE_PROPERTIES] = {};
+ if (device.getType() == constants.PLATFORM_IOS) {
+ deviceObject[constants.DEVICE_PROPERTIES][constants.DEVICE_MODEL] =
+ privateMethods.validateAndReturn(propertiesList.get(constants.DEVICE_PRODUCT));
+ deviceObject[constants.DEVICE_PROPERTIES][constants.DEVICE_VENDOR] = constants.VENDOR_APPLE;
+ } else {
+ deviceObject[constants.DEVICE_PROPERTIES][constants.DEVICE_MODEL] =
+ privateMethods.validateAndReturn(propertiesList.get(constants.DEVICE_MODEL));
+ deviceObject[constants.DEVICE_PROPERTIES][constants.DEVICE_VENDOR] =
+ privateMethods.validateAndReturn(propertiesList.get(constants.DEVICE_VENDOR));
+ }
+ deviceObject[constants.DEVICE_PROPERTIES][constants.DEVICE_OS_VERSION] =
+ privateMethods.validateAndReturn(propertiesList.get(constants.DEVICE_OS_VERSION));
+
+ deviceList.push(deviceObject);
+ }
+ return deviceList;
+ };
+
+ /**
+ * Return list of device types.
+ * Device types should be registered in CDMF and specific unit with name of '{devicetype}' should be presented.
+ * @returns {Array}
+ */
+ publicMethods.listDeviceTypes = function () {
+ deviceManagementDAOFactory.openConnection();
+ var deviceTypes = deviceManagementDAOFactory.getDeviceTypeDAO().getDeviceTypes();
+ deviceManagementDAOFactory.closeConnection();
+ var deviceTypesList = [];
+ var i, deviceType, deviceTypeObject;
+ for (i = 0; i < deviceTypes.size(); i++) {
+ deviceType = deviceTypes.get(i);
+ var deviceUnit = new File(constants.DEVICES_UNIT_PATH + deviceType.getName());
+ if (deviceUnit.isExists()) {
+ deviceTypeObject = {};
+ deviceTypeObject["name"] = deviceType.getName();
+ deviceTypeObject["id"] = deviceType.getId();
+ var storeProperties = privateMethods.getStoreDefinition(deviceType.getName());
+ if (storeProperties) {
+ deviceTypeObject["storeTitle"] = storeProperties.title;
+ deviceTypeObject["storeDescription"] = storeProperties.description;
+ }
+ deviceTypesList.push(deviceTypeObject);
+ } else {
+ log.warn("Device type `" + deviceType.getName() + "` is missing unit implementation at: " + constants.DEVICES_UNIT_PATH);
+ }
+ }
+ return deviceTypesList;
+ };
+
+ publicMethods.removeDevice = function (deviceType, deviceId) {
+ //URL: https://localhost:9443/{deviceType}/manager/device/remove/{deviceId}
+ var deviceCloudService = carbonHttpsServletTransport + "/" + deviceType + "/manager",
+ removeDeviceEndpoint = deviceCloudService + "/device/remove/" + deviceId;
+
+ var data = {};
+ //XMLHTTPRequest's GET
+ //log.info(removeDeviceEndpoint);
+ return del(removeDeviceEndpoint, data, "text");
+ };
+
+ publicMethods.updateDevice = function (deviceType, deviceId, device) {
+ //URL: https://localhost:9443/{deviceType}/manager/device/update/{deviceId}
+ var deviceCloudService = carbonHttpsServletTransport + "/" + deviceType + "/manager",
+ updateDeviceEndpoint = deviceCloudService + "/device/update/" + deviceId;
+
+ var data = {};
+ //XMLHTTPRequest's POST
+ //log.info(updateDeviceEndpoint+ "?name="+device.name);
+ return post(updateDeviceEndpoint + "?name=" + encodeURIComponent(device.name), data, "text");
+ };
+
+ /*
+ Get the supported features by the device type
+ */
+ publicMethods.getFeatures = function (deviceType) {
+ var features = deviceManagementService.getFeatureManager(deviceType).getFeatures();
+ var featuresConverted = {};
+
+ if (features) {
+ var i, feature, featureObject;
+ for (i = 0; i < features.size(); i++) {
+ feature = features.get(i);
+ featureObject = {};
+ featureObject[constants.FEATURE_NAME] = feature.getName();
+ featureObject[constants.FEATURE_DESCRIPTION] = feature.getDescription();
+ featuresConverted[feature.getName()] = featureObject;
+ }
+ }
+ return featuresConverted;
+ };
+
+ publicMethods.performOperation = function (devices, operation) {
+ var operationInstance;
+ if (operation.type == "COMMAND") {
+ operationInstance = new CommandOperation();
+ } else if (operation.type == "CONFIG") {
+ operationInstance = new ConfigOperation();
+ } else {
+ operationInstance = new SimpleOperation();
+ }
+ operationInstance.setCode(operation.featureName);
+ var props = new Properties();
+ var i, object;
+ for (i = 0; i < operation.properties.length; i++) {
+ object = properties[i];
+ props.setProperty(object.key, object.value);
+ }
+ operationInstance.setProperties(props);
+ var deviceList = new ArrayList();
+ var j, device, deviceIdentifier;
+ for (j = 0; j < devices.length; i++) {
+ device = devices[j];
+ deviceIdentifier = new DeviceIdentifier();
+ deviceIdentifier.setId(device.id);
+ deviceIdentifier.setType(device.type);
+ deviceList.add(deviceIdentifier);
+ }
+ deviceManagementService.addOperation(operationInstance, deviceList);
+ };
+
+ publicMethods.getDevice = function (type, deviceId) {
+ var deviceIdentifier = new DeviceIdentifier();
+ deviceIdentifier.setType(type);
+ deviceIdentifier.setId(deviceId);
+ return deviceManagementService.getDevice(deviceIdentifier);
+ };
+
+ publicMethods.viewDevice = function (type, deviceId) {
+ var device = publicMethods.getDevice(type, deviceId);
+ if (device) {
+ var propertiesList = DeviceManagerUtil.convertDevicePropertiesToMap(device.getProperties());
+ var entries = propertiesList.entrySet();
+ var iterator = entries.iterator();
+ var properties = {};
+ var entry, key, value;
+
+ while (iterator.hasNext()) {
+ entry = iterator.next();
+ key = entry.getKey();
+ value = entry.getValue();
+ properties[key] = privateMethods.validateAndReturn(value);
+ }
+
+ var deviceObject = {};
+ deviceObject[constants.DEVICE_IDENTIFIER] = device.getDeviceIdentifier();
+ deviceObject[constants.DEVICE_NAME] = privateMethods.validateAndReturn(device.getName());
+ deviceObject[constants.DEVICE_OWNERSHIP] = privateMethods.validateAndReturn(device.getEnrolmentInfo().getOwnership());
+ deviceObject[constants.DEVICE_OWNER] = device.getEnrolmentInfo().getOwner();
+ deviceObject[constants.DEVICE_TYPE] = device.getType();
+ if (device.getType() == constants.PLATFORM_IOS) {
+ properties[constants.DEVICE_MODEL] = properties[constants.DEVICE_PRODUCT];
+ delete properties[constants.DEVICE_PRODUCT];
+ properties[constants.DEVICE_VENDOR] = constants.VENDOR_APPLE;
+ }
+ deviceObject[constants.DEVICE_PROPERTIES] = properties;
+ deviceObject[constants.DEVICE_ENROLLMENT] = device.getEnrolmentInfo().getDateOfEnrolment();
+ return deviceObject;
+ }
+ };
+
+ return publicMethods;
+
+}();
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/download.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/download.js
new file mode 100644
index 0000000000..5394c8bf22
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/download.js
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var downloadModule;
+var Handlebars = require('../lib/handlebars-v2.0.0.js').Handlebars;
+downloadModule = function () {
+ var log = new Log("modules/download.js");
+
+ var constants = require("/modules/constants.js");
+
+ var publicMethods = {};
+ var privateMethods = {};
+
+ /**
+ * Downloading a specified sketch file.
+ *
+ * @param file File name or file object of the downloading file
+ * @param replaceParams
+ */
+ publicMethods.downloadSketch = function (file, response, replaceParams) {
+ var file = new File("../sketch/" + file);
+
+ file.open('r');
+ log.debug("Reading file '" + file.getPath() + "'");
+ var content = file.readAll().trim();
+ file.close();
+
+ var downloadFile = privateMethods.allReplace(content,replaceParams);
+
+ response.contentType = "application/octet-stream";
+ response.addHeader("Content-Disposition", "attachment; filename='sketch.hbs'");
+ response.addHeader("Content-Length", String(downloadFile.length));
+ response.content = downloadFile;
+ };
+
+ /**
+ * Find and replace all occurrences.
+ * @param inStr input string
+ * @param replaceParams key value array
+ * @returns retStr replaced string
+ */
+ privateMethods.allReplace = function (inStr, replaceParams) {
+ var retStr = inStr;
+ for (var x in replaceParams) {
+ retStr = retStr.replace(new RegExp(x, 'g'), replaceParams[x])
+ }
+ return retStr;
+ };
+
+ return publicMethods;
+}();
+
+
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/event.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/event.js
new file mode 100644
index 0000000000..bf4a01de09
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/event.js
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var eventModule;
+eventModule = function () {
+ var log = new Log("modules/event.js");
+
+ var constants = require("/modules/constants.js");
+ var utility = require("/modules/utility.js").utility;
+
+ var publicMethods = {};
+ var privateMethods = {};
+
+ var statsClient = new Packages.org.wso2.carbon.device.mgt.iot.common.analytics.statistics.IoTEventsStatisticsClient;
+
+ publicMethods.getEventsData = function (username, recordLimit) {
+ var fetchedData = null;
+
+ try {
+ fetchedData = statsClient.getRecentDeviceStats(username, recordLimit);
+ } catch (error) {
+ log.error(error);
+ }
+
+ var eventsData = [];
+
+ for (var i = 0; i < fetchedData.size(); i++) {
+ eventsData.push({
+ time: fetchedData.get(i).getTime(),
+ deviceId: fetchedData.get(i).getDeviceId(),
+ activity: fetchedData.get(i).getDeviceActivity()
+ });
+ };
+
+ return eventsData;
+ };
+
+
+ return publicMethods;
+}();
+
+
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/pinch.min.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/pinch.min.js
new file mode 100644
index 0000000000..feccd2da86
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/pinch.min.js
@@ -0,0 +1,27 @@
+/*
+* Copyright (c) 2011 František Hába
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of
+* this software and associated documentation files (the 'Software'), to deal in
+* the Software without restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+* Software, and to permit persons to whom the Software is furnished to do so,
+* subject to the following conditions:
+* The above copyright notice and this permission notice shall be included in all
+* copies or substantial portions of the Software.
+
+* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*
+* Reference:- https://github.com/Baggz/Pinch
+* Pinch is a small JavaScript utility which is able to replace any data in a JavaScript object (or JSON).
+* */
+(function(){var k=function(a,c){return a.length!==c.length?!1:a.every(function(a,b){return c[b]===a})},j=function(a,c,d){var b,e;if("[object Array]"===Object.prototype.toString.call(a)){b=0;for(e=a.length;bYou are now being redirected to SSO Provider. If the redirection fails, please click on the "+
+ "button below.
" +
+ "");
+ };
+
+ sso.logout = function (user) {
+ var sso_sessions = getSSOSessions();
+ sso.sessionId = session.getId();
+ sso.sessionIndex = sso_sessions[sso.sessionId];
+
+ var referer = request.getHeader("referer");
+ sso.relayState = (referer ? referer : sso.relayState);
+ sso.relayState = sso.relayState + request.getQueryString(); // append query string
+ sso.encodedSAMLLogoutRequest = ssoMod.client.getEncodedSAMLLogoutRequest(user, sso.sessionIndex, sso.issuer);
+ var postUrl = sso.address + sso.ssoService;
+
+ if (log.isDebugEnabled()) {
+ sso.log.debug("Logout request recieved from session id ::: " + sso.sessionId);
+ }
+ print("You are now redirected to Stratos Identity. If theredirection fails, please click the post " +
+ "button.
");
+ };
+
+ sso.acs = function (loginCallback, logoutCallback) {
+ var sso_sessions = getSSOSessions();
+ sso.sessionId = session.getId();
+ var samlResponse = request.getParameter('SAMLResponse');
+ var samlRequest = request.getParameter('SAMLRequest');
+ var relayState = request.getParameter('RelayState');
+ var samlRespObj;
+
+ if (samlResponse != null) {
+ samlRespObj = ssoMod.client.getSamlObject(samlResponse);
+ if (ssoMod.client.isLogoutResponse(samlRespObj)) {
+ logoutCallback();
+ if (log.isDebugEnabled()) {
+ sso.log.debug('Session Id Invalidated :::' + sso.sessionId);
+ }
+ // Invalidating the session after the callback
+ session.invalidate();
+ } else {
+ if (log.isDebugEnabled()) {
+ sso.log.debug("Login request");
+ }
+ // validating the signature
+ if (sso.responseSign) {
+ if (ssoMod.client.validateSignature(samlRespObj, sso.keyStoreProps)) {
+ var sessionObj = ssoMod.client.decodeSAMLLoginResponse(samlRespObj, samlResponse,
+ sso.sessionId);
+ if (log.isDebugEnabled()) {
+ sso.log.debug("Saml object session ID :::" + sessionObj.sessionId);
+ }
+ if (sessionObj.sessionIndex != null || sessionObj.sessionIndex != 'undefined') {
+ sso_sessions[sso_sessions[sessionObj.sessionIndex] = sessionObj.sessionId] =
+ sessionObj.sessionIndex;
+ if (log.isDebugEnabled()) {
+ sso.log.debug("Login successful");
+ sso.log.debug('User is set :::' + sessionObj.loggedInUser);
+ }
+ loginCallback(sessionObj.loggedInUser);
+ } else {
+ sso.log.error("Session index invalid");
+ }
+ } else {
+ sso.log.error("Response Signing failed");
+ }
+ } else {
+ if (log.isDebugEnabled()) {
+ sso.log.debug("Response Signing is disabled");
+ }
+ }
+ }
+ }
+ /*
+ Executed for single logout requests
+ */
+ if (samlRequest != null) {
+ var index = ssoMod.client.decodeSAMLLogoutRequest(ssoMod.client.getSamlObject(samlRequest));
+ var jSessionId = getSSOSessions()[index];
+ delete getSSOSessions()[index];
+ if (log.isDebugEnabled()) {
+ sso.log.debug('Backend logout received from store. The index is :::' + index);
+ sso.log.debug('Session Id Invalidated :::' + jSessionId);
+ }
+ session.invalidate();
+ }
+ }
+})();
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/user.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/user.js
new file mode 100644
index 0000000000..7689494353
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/user.js
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var userModule;
+userModule = function () {
+ var log = new Log("modules/user.js");
+
+ var constants = require("/modules/constants.js");
+ var utility = require("/modules/utility.js").utility;
+
+ var publicMethods = {};
+ var privateMethods = {};
+
+ /**
+ * Authenticate a user when he or she attempts to login to DC.
+ *
+ * @param username Username of the user
+ * @param password Password of the user
+ * @param successCallback Function to be called at the event of successful authentication
+ * @param failureCallback Function to be called at the event of failed authentication
+ */
+ publicMethods.login = function (username, password, successCallback, failureCallback) {
+ var carbonModule = require("carbon");
+ var carbonServer = application.get("carbonServer");
+ try {
+ // get tenant specific full user name.
+ username = username + "@" + carbonModule.server.tenantDomain();
+ // check if the user is an authenticated user.
+ var isAuthenticated = carbonServer.authenticate(username, password);
+ if (isAuthenticated) {
+ var tenantUser = carbonModule.server.tenantUser(username);
+ session.put(constants.USER_SESSION_KEY, tenantUser);
+ successCallback(tenantUser);
+ } else {
+ failureCallback();
+ }
+ } catch (e) {
+ throw e;
+ }
+ };
+
+ /**
+ * Register user to dc-user-store.
+ *
+ * @param username Username of the user
+ * @param firstname First name of the user
+ * @param lastname Last name of the user
+ * @param emailAddress Email address of the user
+ * @param password Password of the user
+ * @param userRoles Roles assigned to the user
+ *
+ * @returns {number} HTTP Status code 201 if succeeded, 409 if user already exists
+ */
+ publicMethods.registerUser = function (username, firstname, lastname, emailAddress, password, userRoles) {
+ var carbon = require('carbon');
+ var tenantId = carbon.server.tenantId();
+ var url = carbon.server.address('https') + "/admin/services";
+ var server = new carbon.server.Server(url);
+ var userManager = new carbon.user.UserManager(server, tenantId);
+
+ try {
+ if (userManager.userExists(username)) {
+ if (log.isDebugEnabled()) {
+ log.debug("A user with name '" + username + "' already exists.");
+ }
+ // http status code 409 refers to - conflict.
+ return 409;
+ } else {
+ var defaultUserClaims = privateMethods.buildDefaultUserClaims(firstname, lastname, emailAddress);
+
+ userManager.addUser(username, password, userRoles, defaultUserClaims, "default");
+ if (log.isDebugEnabled()) {
+ log.debug("A new user with name '" + username + "' was created.");
+ }
+ // http status code 201 refers to - created.
+ return 201;
+ }
+ } catch (e) {
+ throw e;
+ }
+ };
+
+ /**
+ * Add user to dc-user-store.
+ *
+ * @param username Username of the user
+ * @param firstname First name of the user
+ * @param lastname Last name of the user
+ * @param emailAddress Email address of the user
+ * @param userRoles Roles assigned to the user
+ *
+ * @returns {number} HTTP Status code 201 if succeeded, 409 if user already exists
+ */
+ publicMethods.addUser = function (username, firstname, lastname, emailAddress, userRoles) {
+ var carbon = require('carbon');
+ var tenantId = carbon.server.tenantId();
+ var url = carbon.server.address('https') + "/admin/services";
+ var server = new carbon.server.Server(url);
+ var userManager = new carbon.user.UserManager(server, tenantId);
+
+ try {
+ if (userManager.userExists(username)) {
+ if (log.isDebugEnabled()) {
+ log.debug("A user with name '" + username + "' already exists.");
+ }
+ // http status code 409 refers to - conflict.
+ return 409;
+ } else {
+ var initialUserPassword = privateMethods.generateInitialUserPassword();
+ var defaultUserClaims = privateMethods.buildDefaultUserClaims(firstname, lastname, emailAddress);
+
+ userManager.addUser(username, initialUserPassword, userRoles, defaultUserClaims, "default");
+ privateMethods.inviteUserToEnroll(username, initialUserPassword);
+ if (log.isDebugEnabled()) {
+ log.debug("A new user with name '" + username + "' was created.");
+ }
+ // http status code 201 refers to - created.
+ return 201;
+ }
+ } catch (e) {
+ throw e;
+ }
+ };
+
+ /**
+ * Remove an existing user from mdm-user-store.
+ *
+ * @param username Username of the user
+ * @returns {number} HTTP Status code 200 if succeeded, 409 if the user does not exist
+ */
+ publicMethods.removeUser = function (username) {
+ var carbon = require('carbon');
+ var tenantId = carbon.server.tenantId();
+ var url = carbon.server.address('https') + "/admin/services";
+ var server = new carbon.server.Server(url);
+ var userManager = new carbon.user.UserManager(server, tenantId);
+
+ try {
+ if (userManager.userExists(username)) {
+ userManager.removeUser(username);
+ if (log.isDebugEnabled()) {
+ log.debug("An existing user with name '" + username + "' was removed.");
+ }
+ // http status code 200 refers to - success.
+ return 200;
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("A user with name '" + username + "' does not exist to remove.");
+ }
+ // http status code 409 refers to - conflict.
+ return 409;
+ }
+ } catch (e) {
+ throw e;
+ }
+ };
+
+ /**
+ * Private method to be used by addUser() to
+ * generate an initial user password for a user.
+ * This will be the password used by a user for his initial login to the system.
+ *
+ * @returns {string} Initial User Password
+ */
+ privateMethods.generateInitialUserPassword = function () {
+ var passwordLength = 6;
+ //defining the pool of characters to be used for initial password generation
+ var lowerCaseCharset = "abcdefghijklmnopqrstuvwxyz";
+ var upperCaseCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ var numericCharset = "0123456789";
+
+ var totalCharset = lowerCaseCharset + upperCaseCharset + numericCharset;
+ var totalCharsetLength = totalCharset.length;
+
+ var initialUserPassword = "";
+ for (var i = 0; i < passwordLength; ++i) {
+ initialUserPassword += totalCharset.charAt(Math.floor(Math.random() * totalCharsetLength));
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("Initial password created for new user : " + initialUserPassword);
+ }
+ return String(initialUserPassword);
+ };
+
+ /**
+ * Build default user claims.
+ *
+ * @param firstname First name of the user
+ * @param lastname Last name of the user
+ * @param emailAddress Email address of the user
+ *
+ * @returns {Object} Default user claims to be provided
+ */
+ privateMethods.buildDefaultUserClaims = function (firstname, lastname, emailAddress) {
+ var defaultUserClaims = {
+ "http://wso2.org/claims/givenname": firstname,
+ "http://wso2.org/claims/lastname": lastname,
+ "http://wso2.org/claims/emailaddress": emailAddress
+ };
+ if (log.isDebugEnabled()) {
+ log.debug("ClaimMap created for new user : " + stringify(defaultUserClaims));
+ }
+ return defaultUserClaims;
+ };
+
+ publicMethods.addPermissions = function (permissionList, path, init) {
+ var carbonModule = require("carbon");
+ var carbonServer = application.get("carbonServer");
+ var options = {system: true};
+ if (init == "login") {
+ var carbonUser = session.get(constants.USER_SESSION_KEY);
+ if (carbonUser) {
+ options.tenantId = carbonUser.tenantId;
+ }
+ }
+ var registry = new carbonModule.registry.Registry(carbonServer, options);
+ var i, permission, resource;
+ for (i = 0; i < permissionList.length; i++) {
+ permission = permissionList[i];
+ resource = {
+ collection : true,
+ name : permission.name,
+ properties : {
+ name : permission.name
+ }
+ };
+ registry.put("/_system/governance/permission/" + path + "/" + permission.key, resource);
+ }
+ };
+
+ publicMethods.getUsers = function () {
+ var users = [];
+ var carbonUser = session.get(constants.USER_SESSION_KEY);
+ if (!carbonUser) {
+ log.error("User object was not found in the session");
+ throw constants.ERRORS.USER_NOT_FOUND;
+ }
+ var carbon = require('carbon');
+ var tenantId = carbon.server.tenantId();
+ var url = carbon.server.address('https') + "/admin/services";
+ var server = new carbon.server.Server(url);
+ var userManager = new carbon.user.UserManager(server, tenantId);
+ var userList = userManager.listUsers();
+ var i, username, userObject, email, firstname, lastname;
+ for (i = 0; i < userList.length; i++) {
+ username = userList[i];
+ userObject = userManager.getUser(username);
+ email = userManager.getClaim(username,"http://wso2.org/claims/emailaddress", null);
+ firstname = userManager.getClaim(username,"http://wso2.org/claims/givenname", null);
+ lastname = userManager.getClaim(username,"http://wso2.org/claims/lastname", null);
+ //log.info(userManager.getClaimsForSet(username, "http://wso2.org/claims/emailaddress,http://wso2.org/claims/givenname,http://wso2.org/claims/lastname".split(","), null));
+ userObj = {
+ "username" : userObject.username,
+ "email" : email,
+ "name" : firstname + " " + lastname
+ };
+ if(userObj.username == "admin"){
+ userObj.name = "admin";
+ }
+ users.push(userObj);
+ }
+ return users;
+ };
+
+ publicMethods.isAuthorized = function (permission) {
+ var carbonModule = require("carbon");
+ var carbonServer = application.get("carbonServer");
+ var carbonUser = session.get(constants.USER_SESSION_KEY);
+ if (!carbonUser) {
+ log.error("User object was not found in the session");
+ throw constants.ERRORS.USER_NOT_FOUND;
+ }
+ var userManager = new carbonModule.user.UserManager(carbonServer, carbonUser.tenantId);
+ var user = new carbonModule.user.User(userManager, carbonUser.username);
+ return user.isAuthorized(permission, "ui.execute");
+ };
+
+ publicMethods.getUIPermissions = function(){
+ var permissions = {};
+ if (publicMethods.isAuthorized("/permission/device-mgt/admin/devices/list") ||
+ publicMethods.isAuthorized("/permission/device-mgt/user/devices/list")) {
+ permissions.LIST_DEVICES = true;
+ }
+ if (publicMethods.isAuthorized("/permission/device-mgt/admin/users/list")) {
+ permissions.LIST_USERS = true;
+ }
+ if (publicMethods.isAuthorized("/permission/device-mgt/admin/users/add")) {
+ permissions.ADD_USER = true;
+ }
+ if (publicMethods.isAuthorized("/permission/device-mgt/admin/policies/add")) {
+ permissions.ADD_POLICY = true;
+ }
+ if (publicMethods.isAuthorized("/permission/device-mgt/admin/policies/list")) {
+ permissions.LIST_POLICIES = true;
+ }
+ if (publicMethods.isAuthorized("/permission/device-mgt/admin/dashboard/view")) {
+ permissions.DASHBOARD_VIEW = true;
+ }
+ //TO-DO Apply followings in to carbon permissions
+ permissions.ADD_DEVICE = true;
+ return permissions;
+ };
+
+ /**
+ * Get User Roles from user store.
+ * If "Internal/Everyone" role is required - true param needs to be passed.
+ * @param enableInternalEveryone boolean value true/false to enable Internal/Everyone role
+ */
+ publicMethods.getRoles = function (enableInternalEveryone) {
+ var carbonModule = require("carbon");
+ var carbonServer = application.get("carbonServer");
+ var carbonUser = session.get(constants.USER_SESSION_KEY);
+ if (!carbonUser) {
+ log.error("User object was not found in the session");
+ throw constants.ERRORS.USER_NOT_FOUND;
+ }
+ var userManager = new carbonModule.user.UserManager(carbonServer, carbonUser.tenantId);
+ var allRoles = userManager.allRoles();
+ var filteredRoles = [];
+ var i;
+ for (i = 0; i < allRoles.length; i++) {
+ if (enableInternalEveryone && allRoles[i] == "Internal/everyone") {
+ filteredRoles.push(allRoles[i]);
+ }
+ if (allRoles[i].indexOf("Internal/") != 0) {
+ filteredRoles.push(allRoles[i]);
+ }
+ }
+ return filteredRoles;
+ };
+
+ publicMethods.logout = function (successCallback) {
+ session.invalidate();
+ successCallback();
+ };
+
+
+
+ return publicMethods;
+}();
+
+
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/util.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/util.js
new file mode 100644
index 0000000000..f6d413b2f3
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/util.js
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var util = function () {
+ var module = {};
+ var Base64 = Packages.org.apache.commons.codec.binary.Base64;
+ var String = Packages.java.lang.String;
+ var log = new Log();
+
+ /**
+ * Encode the payload in Base64
+ * @param payload
+ * @returns {Packages.java.lang.String}
+ */
+ function encode(payload){
+ return new String(Base64.encodeBase64(new String(payload).getBytes()));
+ }
+
+ /**
+ * Get an AccessToken pair based on username and password
+ * @param username
+ * @param password
+ * @param clientId
+ * @param clientSecret
+ * @param scope
+ * @returns {{accessToken: "", refreshToken: ""}}
+ */
+ module.getTokenWithPasswordGrantType = function (username, password, clientId, clientSecret, scope) {
+ var xhr = new XMLHttpRequest();
+ var tokenEndpoint = "https://localhost:9443/oauth2/token";
+ var encodedClientKeys = encode(clientId + ":" + clientSecret);
+ xhr.open("POST", tokenEndpoint, false);
+ xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+ xhr.setRequestHeader("Authorization", "Basic " + encodedClientKeys);
+ xhr.send("grant_type=password&username=" + username + "&password=" + password + "&scope=" + scope);
+ delete password, delete clientSecret, delete encodedClientKeys;
+ var tokenPair = {};
+ if (xhr.status == 200) {
+ var data = parse(xhr.responseText);
+ tokenPair.refreshToken = data.refresh_token;
+ tokenPair.accessToken = data.access_token;
+ } else if (xhr.status == 403) {
+ throw "Error in obtaining token with Password Grant Type";
+ } else {
+ throw "Error in obtaining token with Password Grant Type";
+ }
+ return tokenPair;
+ };
+ module.getTokenWithSAMLGrantType = function () {
+
+ };
+ module.refreshToken = function(tokenPair){
+ var xhr = new XMLHttpRequest();
+ var tokenEndpoint = "https://localhost:9443/oauth2/token";
+ var encodedClientKeys = encode(clientId + ":" + clientSecret);
+ xhr.open("POST", tokenEndpoint, false);
+ xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+ xhr.setRequestHeader("Authorization", "Basic " + encodedClientKeys);
+ xhr.send("grant_type=refresh_token&refresh_token=" + tokenPair.refreshToken + "&scope=" + scope);
+ delete password, delete clientSecret, delete encodedClientKeys;
+ var tokenPair = {};
+ if (xhr.status == 200) {
+ var data = parse(xhr.responseText);
+ tokenPair.refreshToken = data.refresh_token;
+ tokenPair.accessToken = data.access_token;
+ } else if (xhr.status == 403) {
+ throw "Error in obtaining token with Password Grant Type";
+ } else {
+ throw "Error in obtaining token with Password Grant Type";
+ }
+ return tokenPair;
+ };
+ return module;
+}();
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/utility.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/utility.js
new file mode 100644
index 0000000000..76c0f3c610
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/modules/utility.js
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var utility;
+utility = function () {
+ var JavaClass = Packages.java.lang.Class;
+ var PrivilegedCarbonContext = Packages.org.wso2.carbon.context.PrivilegedCarbonContext;
+
+ var getOsgiService = function (className) {
+ return PrivilegedCarbonContext.getThreadLocalCarbonContext().getOSGiService(JavaClass.forName(className));
+ };
+
+ var publicMethods = {};
+
+ publicMethods.getDeviceManagementService = function () {
+ return getOsgiService('org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService');
+ };
+
+ publicMethods.getPolicyManagementService = function () {
+ return getOsgiService('org.wso2.carbon.policy.mgt.core.PolicyManagerService');
+ };
+
+ publicMethods.insertAppPermissions = function (userModule, type) {
+ userModule.addPermissions([{key: "device-mgt", name: "Device Management"}], "", type);
+ userModule.addPermissions([{
+ key: "admin",
+ name: "Device Management Admin"
+ }], "device-mgt", type);
+ userModule.addPermissions([{
+ key: "user",
+ name: "Device Management User"
+ }], "device-mgt", type);
+
+ userModule.addPermissions([{key: "devices", name: "Devices"}], "device-mgt/admin", type);
+ userModule.addPermissions([{
+ key: "devices/list",
+ name: "List Devices"
+ }], "device-mgt/admin", type);
+ userModule.addPermissions([{
+ key: "devices/operation",
+ name: "Perform Operation"
+ }], "device-mgt/admin", type);
+
+ userModule.addPermissions([{key: "groups", name: "Groups"}], "device-mgt/admin", type);
+ userModule.addPermissions([{
+ key: "groups/add_devices",
+ name: "Add Devices to Group"
+ }], "device-mgt/admin", type);
+ userModule.addPermissions([{
+ key: "groups/remove_devices",
+ name: "Remove Devices from Group"
+ }], "device-mgt/admin", type);
+ userModule.addPermissions([{
+ key: "groups/modify",
+ name: "Modify Group"
+ }], "device-mgt/admin", type);
+ userModule.addPermissions([{
+ key: "groups/share",
+ name: "Change Group Sharing"
+ }], "device-mgt/admin", type);
+ userModule.addPermissions([{
+ key: "groups/delete",
+ name: "Delete Group"
+ }], "device-mgt/admin", type);
+
+ userModule.addPermissions([{key: "users", name: "Users"}], "device-mgt/admin", type);
+ userModule.addPermissions([{
+ key: "users/add",
+ name: "Add New Users"
+ }], "device-mgt/admin", type);
+ userModule.addPermissions([{
+ key: "users/invite",
+ name: "Invite Users"
+ }], "device-mgt/admin", type);
+ userModule.addPermissions([{
+ key: "users/list",
+ name: "List Users"
+ }], "device-mgt/admin", type);
+ userModule.addPermissions([{
+ key: "users/remove",
+ name: "Remove Users"
+ }], "device-mgt/admin", type);
+
+ userModule.addPermissions([{key: "devices", name: "Devices"}], "device-mgt/user", type);
+ userModule.addPermissions([{
+ key: "devices/list",
+ name: "List Devices"
+ }], "device-mgt/user", type);
+ userModule.addPermissions([{
+ key: "devices/operation",
+ name: "Perform Operation"
+ }], "device-mgt/user", "init");
+
+ userModule.addPermissions([{key: "groups", name: "Groups"}], "device-mgt/user", type);
+ userModule.addPermissions([{
+ key: "groups/device_monitor",
+ name: "Monitor Statistics Devices in Group"
+ }], "device-mgt/user", type);
+ userModule.addPermissions([{
+ key: "groups/device_operation",
+ name: "Perform Device Operation"
+ }], "device-mgt/user", type);
+ userModule.addPermissions([{
+ key: "groups/device_policies/add",
+ name: "Apply Device Policies"
+ }], "device-mgt/user", type);
+ userModule.addPermissions([{
+ key: "groups/device_policies/view",
+ name: "View Device Policies"
+ }], "device-mgt/user", type);
+ userModule.addPermissions([{
+ key: "groups/device_events",
+ name: "Monitor Device Events"
+ }], "device-mgt/user", type);
+ userModule.addPermissions([{
+ key: "groups/device_list",
+ name: "List Groups of User"
+ }], "device-mgt/user", type);
+ };
+
+ return publicMethods;
+}();
+
+
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/alldevices.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/alldevices.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/alldevices.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/alldevices.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/analytics.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/analytics.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/analytics.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/analytics.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/dashboard.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/dashboard.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/dashboard.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/dashboard.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/device.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/device.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/device.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/device.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/devices/add-device.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/devices/add-device.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/devices/add-device.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/devices/add-device.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/devices/index.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/devices/index.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/devices/index.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/devices/index.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/events/index.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/events/index.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/events/index.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/events/index.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/group.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/group.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/group.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/group.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/groups/add-group.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/groups/add-group.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/groups/add-group.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/groups/add-group.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/groups/index.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/groups/index.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/groups/index.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/groups/index.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/index.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/index.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/index.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/index.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/login.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/login.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/login.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/login.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/policies/add-policy.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/policies/add-policy.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/policies/add-policy.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/policies/add-policy.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/policies/index.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/policies/index.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/policies/index.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/policies/index.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/register.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/register.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/register.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/register.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/users/add-user.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/users/add-user.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/users/add-user.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/users/add-user.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/users/index.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/users/index.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/users/index.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/pages/users/index.hbs
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/test.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/test.jag
new file mode 100644
index 0000000000..c0097b638f
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/test.jag
@@ -0,0 +1,12 @@
+<%
+var userModule = require("/modules/user.js").userModule;
+userModule.addPermissions([{key: "device-mgt/", name: "Device Management"}], "");
+userModule.addPermissions([{key: "device-mgt/admin", name: "Device Management Admin"}], "");
+userModule.addPermissions([{key: "device-mgt/user", name: "Device Management User"}], "");
+
+userModule.addPermissions([{key: "devices", name: "Device"}], "device-mgt/admin");
+userModule.addPermissions([{key: "devices", name: "Device"}], "device-mgt/user");
+userModule.addPermissions([{key: "devices/list", name: "List all Devices"}], "device-mgt/admin");
+userModule.addPermissions([{key: "devices/list", name: "List own Devices"}], "device-mgt/user");
+new Log().info(userModule.isAuthorized("/permission/device-mgt/admin/devices/list"));
+%>
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/test/device-spec.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/test/device-spec.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/test/device-spec.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/test/device-spec.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/test/testExecutor.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/test/testExecutor.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/test/testExecutor.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/test/testExecutor.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/test/user-spec.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/test/user-spec.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/test/user-spec.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/test/user-spec.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/tmp/cached_theme_less_base.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/tmp/cached_theme_less_base.css
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/tmp/cached_theme_less_base.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/tmp/cached_theme_less_base.css
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/token.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/token.jag
new file mode 100644
index 0000000000..777783078a
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/token.jag
@@ -0,0 +1,4 @@
+<%
+var apiWrapperUtil = require("/modules/api-wrapper-util.js").apiWrapperUtil;
+apiWrapperUtil.refreshToken();
+%>
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/alldevices/alldevices.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/alldevices/alldevices.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/alldevices/alldevices.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/alldevices/alldevices.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/alldevices/alldevices.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/alldevices/alldevices.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/alldevices/alldevices.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/alldevices/alldevices.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/alldevices/alldevices.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/alldevices/alldevices.json
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/alldevices/alldevices.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/alldevices/alldevices.json
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/alldevices/public/js/alldevices_util.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/alldevices/public/js/alldevices_util.js
similarity index 97%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/alldevices/public/js/alldevices_util.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/alldevices/public/js/alldevices_util.js
index 74da90713e..0b9c881c64 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/alldevices/public/js/alldevices_util.js
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/alldevices/public/js/alldevices_util.js
@@ -1,49 +1,49 @@
-function getAllDevices() {
- var getDevicesRequest = $.ajax({
- url: "api/devices/all/",
- method: "GET",
- contentType: "application/json"
- });
-
- getDevicesRequest.done(function (data) {
- updateDevicesTable(JSON.parse(data));
- });
-
- getDevicesRequest.fail(function (jqXHR, textStatus) {
- var err = jqXHR;
- alert("Request failed: " + textStatus);
- });
-}
-
-function updateDevicesTable(data) {
- devices = data.data.device;
- if (devices.length > 0) {
- clearTable('devicesTable');
- for (var i = 0; i < devices.length; i++) {
- var deviceIdentifier = devices[i].deviceIdentifier;
- var deviceName = devices[i].name;
- var deviceType = devices[i].type;
- $('#devicesTable tbody').append(
- "" + deviceIdentifier + " " +
- "" + deviceName + " " +
- "" + deviceType + " " +
- "" +
- " " +
- "" +
- " View " +
- "" +
- " Edit " +
- "" +
- " Remove " +
- " ");
- }
- }
-}
-
-function clearTable(tableId) {
- $('#' + tableId + ' tbody > tr').remove();
-}
-
-$(document).ready(function () {
- getAllDevices();
+function getAllDevices() {
+ var getDevicesRequest = $.ajax({
+ url: "api/devices/all/",
+ method: "GET",
+ contentType: "application/json"
+ });
+
+ getDevicesRequest.done(function (data) {
+ updateDevicesTable(JSON.parse(data));
+ });
+
+ getDevicesRequest.fail(function (jqXHR, textStatus) {
+ var err = jqXHR;
+ alert("Request failed: " + textStatus);
+ });
+}
+
+function updateDevicesTable(data) {
+ devices = data.data.device;
+ if (devices.length > 0) {
+ clearTable('devicesTable');
+ for (var i = 0; i < devices.length; i++) {
+ var deviceIdentifier = devices[i].deviceIdentifier;
+ var deviceName = devices[i].name;
+ var deviceType = devices[i].type;
+ $('#devicesTable tbody').append(
+ "" + deviceIdentifier + " " +
+ "" + deviceName + " " +
+ "" + deviceType + " " +
+ "" +
+ " " +
+ "" +
+ " View " +
+ "" +
+ " Edit " +
+ "" +
+ " Remove " +
+ " ");
+ }
+ }
+}
+
+function clearTable(tableId) {
+ $('#' + tableId + ' tbody > tr').remove();
+}
+
+$(document).ready(function () {
+ getAllDevices();
});
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analiytics-graphs/analiytics-graphs.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analiytics-graphs/analiytics-graphs.hbs
new file mode 100644
index 0000000000..c802e1e98f
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analiytics-graphs/analiytics-graphs.hbs
@@ -0,0 +1,7 @@
+{{#zone "topCss"}}
+
+
+
+
+
+{{/zone}}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analiytics-graphs/analiytics-graphs.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analiytics-graphs/analiytics-graphs.json
new file mode 100644
index 0000000000..56db749f0a
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analiytics-graphs/analiytics-graphs.json
@@ -0,0 +1,3 @@
+{
+ "predicate": "urlMatch('/analytics')"
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/daterangepicker.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analiytics-graphs/public/css/daterangepicker.css
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/daterangepicker.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analiytics-graphs/public/css/daterangepicker.css
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analiytics-graphs/public/css/detail.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analiytics-graphs/public/css/detail.css
new file mode 100644
index 0000000000..501719f429
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analiytics-graphs/public/css/detail.css
@@ -0,0 +1,105 @@
+.rickshaw_graph .detail {
+ pointer-events: none;
+ position: absolute;
+ top: 0;
+ z-index: 2;
+ background: rgba(0, 0, 0, 0.1);
+ bottom: 0;
+ width: 1px;
+ transition: opacity 0.25s linear;
+ -moz-transition: opacity 0.25s linear;
+ -o-transition: opacity 0.25s linear;
+ -webkit-transition: opacity 0.25s linear;
+}
+.rickshaw_graph .detail.inactive {
+ opacity: 0;
+}
+.rickshaw_graph .detail .item.active {
+ opacity: 1;
+}
+.rickshaw_graph .detail .x_label {
+ font-family: Arial, sans-serif;
+ border-radius: 3px;
+ padding: 6px;
+ opacity: 0.5;
+ border: 1px solid #e0e0e0;
+ font-size: 12px;
+ position: absolute;
+ background: white;
+ white-space: nowrap;
+}
+.rickshaw_graph .detail .x_label.left {
+ left: 0;
+}
+.rickshaw_graph .detail .x_label.right {
+ right: 0;
+}
+.rickshaw_graph .detail .item {
+ position: absolute;
+ z-index: 2;
+ border-radius: 3px;
+ padding: 0.25em;
+ font-size: 12px;
+ font-family: Arial, sans-serif;
+ opacity: 0;
+ background: rgba(0, 0, 0, 0.4);
+ color: white;
+ border: 1px solid rgba(0, 0, 0, 0.4);
+ margin-left: 1em;
+ margin-right: 1em;
+ margin-top: -1em;
+ white-space: nowrap;
+}
+.rickshaw_graph .detail .item.left {
+ left: 0;
+}
+.rickshaw_graph .detail .item.right {
+ right: 0;
+}
+.rickshaw_graph .detail .item.active {
+ opacity: 1;
+ background: rgba(0, 0, 0, 0.8);
+}
+.rickshaw_graph .detail .item:after {
+ position: absolute;
+ display: block;
+ width: 0;
+ height: 0;
+
+ content: "";
+
+ border: 5px solid transparent;
+}
+.rickshaw_graph .detail .item.left:after {
+ top: 1em;
+ left: -5px;
+ margin-top: -5px;
+ border-right-color: rgba(0, 0, 0, 0.8);
+ border-left-width: 0;
+}
+.rickshaw_graph .detail .item.right:after {
+ top: 1em;
+ right: -5px;
+ margin-top: -5px;
+ border-left-color: rgba(0, 0, 0, 0.8);
+ border-right-width: 0;
+}
+.rickshaw_graph .detail .dot {
+ width: 4px;
+ height: 4px;
+ margin-left: -3px;
+ margin-top: -3.5px;
+ border-radius: 5px;
+ position: absolute;
+ box-shadow: 0 0 2px rgba(0, 0, 0, 0.6);
+ box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ background: white;
+ border-width: 2px;
+ border-style: solid;
+ display: none;
+ background-clip: padding-box;
+}
+.rickshaw_graph .detail .dot.active {
+ display: block;
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analiytics-graphs/public/css/graph.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analiytics-graphs/public/css/graph.css
new file mode 100644
index 0000000000..48defd85b2
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analiytics-graphs/public/css/graph.css
@@ -0,0 +1,197 @@
+/* graph */
+
+.rickshaw_graph {
+ position: relative;
+}
+.rickshaw_graph svg {
+ display: block;
+ overflow: hidden;
+}
+
+/* ticks */
+
+.rickshaw_graph .x_tick {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ width: 0px;
+ border-left: 1px dotted rgba(0, 0, 0, 0.2);
+ pointer-events: none;
+}
+.rickshaw_graph .x_tick .title {
+ position: absolute;
+ font-size: 12px;
+ font-family: Arial, sans-serif;
+ opacity: 0.5;
+ white-space: nowrap;
+ margin-left: 3px;
+ bottom: -20px;
+}
+
+/* annotations */
+
+.rickshaw_annotation_timeline {
+ height: 1px;
+ border-top: 1px solid #e0e0e0;
+ margin-top: 10px;
+ position: relative;
+}
+.rickshaw_annotation_timeline .annotation {
+ position: absolute;
+ height: 6px;
+ width: 6px;
+ margin-left: -2px;
+ top: -3px;
+ border-radius: 5px;
+ background-color: rgba(0, 0, 0, 0.25);
+}
+.rickshaw_graph .annotation_line {
+ position: absolute;
+ top: 0;
+ bottom: -6px;
+ width: 0px;
+ border-left: 2px solid rgba(0, 0, 0, 0.3);
+ display: none;
+}
+.rickshaw_graph .annotation_line.active {
+ display: block;
+}
+
+.rickshaw_graph .annotation_range {
+ background: rgba(0, 0, 0, 0.1);
+ display: none;
+ position: absolute;
+ top: 0;
+ bottom: -6px;
+}
+.rickshaw_graph .annotation_range.active {
+ display: block;
+}
+.rickshaw_graph .annotation_range.active.offscreen {
+ display: none;
+}
+
+.rickshaw_annotation_timeline .annotation .content {
+ background: white;
+ color: black;
+ opacity: 0.9;
+ padding: 5px 5px;
+ box-shadow: 0 0 2px rgba(0, 0, 0, 0.8);
+ border-radius: 3px;
+ position: relative;
+ z-index: 20;
+ font-size: 12px;
+ padding: 6px 8px 8px;
+ top: 18px;
+ left: -11px;
+ width: 160px;
+ display: none;
+ cursor: pointer;
+}
+.rickshaw_annotation_timeline .annotation .content:before {
+ content: "\25b2";
+ position: absolute;
+ top: -11px;
+ color: white;
+ text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.8);
+}
+.rickshaw_annotation_timeline .annotation.active,
+.rickshaw_annotation_timeline .annotation:hover {
+ background-color: rgba(0, 0, 0, 0.8);
+ cursor: none;
+}
+.rickshaw_annotation_timeline .annotation .content:hover {
+ z-index: 50;
+}
+.rickshaw_annotation_timeline .annotation.active .content {
+ display: block;
+}
+.rickshaw_annotation_timeline .annotation:hover .content {
+ display: block;
+ z-index: 50;
+}
+.rickshaw_graph .y_axis,
+.rickshaw_graph .x_axis_d3 {
+ fill: none;
+}
+.rickshaw_graph .y_ticks .tick line,
+.rickshaw_graph .x_ticks_d3 .tick {
+ stroke: rgba(0, 0, 0, 0.16);
+ stroke-width: 2px;
+ shape-rendering: crisp-edges;
+ pointer-events: none;
+}
+.rickshaw_graph .y_grid .tick,
+.rickshaw_graph .x_grid_d3 .tick {
+ z-index: -1;
+ stroke: rgba(0, 0, 0, 0.20);
+ stroke-width: 1px;
+ stroke-dasharray: 1 1;
+}
+.rickshaw_graph .y_grid .tick[data-y-value="0"] {
+ stroke-dasharray: 1 0;
+}
+.rickshaw_graph .y_grid path,
+.rickshaw_graph .x_grid_d3 path {
+ fill: none;
+ stroke: none;
+}
+.rickshaw_graph .y_ticks path,
+.rickshaw_graph .x_ticks_d3 path {
+ fill: none;
+ stroke: #808080;
+}
+.rickshaw_graph .y_ticks text,
+.rickshaw_graph .x_ticks_d3 text {
+ opacity: 0.5;
+ font-size: 12px;
+ pointer-events: none;
+}
+.rickshaw_graph .x_tick.glow .title,
+.rickshaw_graph .y_ticks.glow text {
+ fill: black;
+ color: black;
+ text-shadow:
+ -1px 1px 0 rgba(255, 255, 255, 0.1),
+ 1px -1px 0 rgba(255, 255, 255, 0.1),
+ 1px 1px 0 rgba(255, 255, 255, 0.1),
+ 0px 1px 0 rgba(255, 255, 255, 0.1),
+ 0px -1px 0 rgba(255, 255, 255, 0.1),
+ 1px 0px 0 rgba(255, 255, 255, 0.1),
+ -1px 0px 0 rgba(255, 255, 255, 0.1),
+ -1px -1px 0 rgba(255, 255, 255, 0.1);
+}
+.rickshaw_graph .x_tick.inverse .title,
+.rickshaw_graph .y_ticks.inverse text {
+ fill: white;
+ color: white;
+ text-shadow:
+ -1px 1px 0 rgba(0, 0, 0, 0.8),
+ 1px -1px 0 rgba(0, 0, 0, 0.8),
+ 1px 1px 0 rgba(0, 0, 0, 0.8),
+ 0px 1px 0 rgba(0, 0, 0, 0.8),
+ 0px -1px 0 rgba(0, 0, 0, 0.8),
+ 1px 0px 0 rgba(0, 0, 0, 0.8),
+ -1px 0px 0 rgba(0, 0, 0, 0.8),
+ -1px -1px 0 rgba(0, 0, 0, 0.8);
+}
+
+.custom_rickshaw_graph {
+ position: relative;
+ left: 40px;
+}
+
+.custom_y_axis {
+ position: absolute;
+ width: 40px;
+}
+
+.custom_slider {
+ left: 40px;
+}
+
+.custom_x_axis {
+ position: relative;
+ left: 40px;
+ height: 30px;
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analiytics-graphs/public/css/legend.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analiytics-graphs/public/css/legend.css
new file mode 100644
index 0000000000..283e26f297
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analiytics-graphs/public/css/legend.css
@@ -0,0 +1,87 @@
+.rickshaw_legend {
+ font-family: Arial;
+ font-size: 12px;
+ color: white;
+ background: #404040;
+ display: inline-block;
+ padding: 12px 5px;
+ border-radius: 2px;
+ position: relative;
+ float: right;
+}
+.rickshaw_legend:hover {
+ z-index: 10;
+}
+.rickshaw_legend .swatch {
+ width: 10px;
+ height: 10px;
+ border: 1px solid rgba(0, 0, 0, 0.2);
+}
+.rickshaw_legend .line {
+ clear: both;
+ line-height: 140%;
+ padding-right: 15px;
+}
+.rickshaw_legend .line .swatch {
+ display: inline-block;
+ margin-right: 3px;
+ border-radius: 2px;
+}
+.rickshaw_legend .label {
+ margin: 0;
+ white-space: nowrap;
+ display: inline;
+ font-size: inherit;
+ background-color: transparent;
+ color: inherit;
+ font-weight: normal;
+ line-height: normal;
+ padding: 0px;
+ text-shadow: none;
+}
+.rickshaw_legend .action:hover {
+ opacity: 0.6;
+}
+.rickshaw_legend .action {
+ margin-right: 0.2em;
+ font-size: 10px;
+ opacity: 0.2;
+ cursor: pointer;
+ font-size: 14px;
+}
+.rickshaw_legend .line.disabled {
+ opacity: 0.4;
+}
+.rickshaw_legend ul {
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+ margin: 2px;
+ cursor: pointer;
+}
+.rickshaw_legend li {
+ padding: 0 0 0 2px;
+ min-width: 80px;
+ white-space: nowrap;
+}
+.rickshaw_legend li:hover {
+ background: rgba(255, 255, 255, 0.08);
+ border-radius: 3px;
+}
+.rickshaw_legend li:active {
+ background: rgba(255, 255, 255, 0.2);
+ border-radius: 3px;
+}
+.legend {
+ display: inline-block;
+ position: relative;
+ left: 8px;
+}
+.legend_container {
+ float: right;
+ padding-right: 10px;
+ width: 0;
+ z-index: 1;
+ position: relative;
+ opacity: 0.7;
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analiytics-graphs/public/css/lines.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analiytics-graphs/public/css/lines.css
new file mode 100644
index 0000000000..b96fceb846
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analiytics-graphs/public/css/lines.css
@@ -0,0 +1,21 @@
+div, span, p, td {
+ font-family: Arial, sans-serif;
+}
+#chart {
+ display: inline-block;
+}
+#legend {
+ display: inline-block;
+ position: relative;
+ left: 8px;
+}
+#legend_container {
+ position: absolute;
+ right: 0;
+ bottom: 26px;
+ width: 0;
+}
+#chart_container {
+ float: left;
+ position: relative;
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/analytics.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/analytics.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/analytics.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/analytics.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/analytics.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/analytics.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/analytics.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/analytics.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/analytics.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/analytics.json
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/analytics.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/analytics.json
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/images/bulb-off.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/images/bulb-off.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/images/bulb-off.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/images/bulb-off.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/images/bulb-on.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/images/bulb-on.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/images/bulb-on.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/images/bulb-on.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/images/fan.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/images/fan.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/images/fan.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/images/fan.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/images/temp.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/images/temp.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/images/temp.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/images/temp.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/d3.min.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/d3.min.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/d3.min.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/d3.min.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/graph_util.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/graph_util.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/graph_util.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/graph_util.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/jquery-ui-timepicker-addon.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/jquery-ui-timepicker-addon.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/jquery-ui-timepicker-addon.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/jquery-ui-timepicker-addon.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/jquery.daterangepicker.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/jquery.daterangepicker.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/jquery.daterangepicker.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/jquery.daterangepicker.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/moment.min.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/moment.min.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/moment.min.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/moment.min.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/rickshaw.min.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/rickshaw.min.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/rickshaw.min.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/analytics/public/js/rickshaw.min.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/appbar/appbar.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/appbar/appbar.hbs
similarity index 97%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/appbar/appbar.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/appbar/appbar.hbs
index 96557c6892..77f6001a5a 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/appbar/appbar.hbs
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/appbar/appbar.hbs
@@ -1,56 +1,56 @@
-{{#zone "main"}}
-
-
-
-
-
-
-
-
-
-
-
-
-
+{{#zone "main"}}
+
+
+
+
+
+
+
+
+
+
+
+
+
{{/zone}}
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/appbar/appbar.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/appbar/appbar.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/appbar/appbar.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/appbar/appbar.js
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/appbar/appbar.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/appbar/appbar.json
new file mode 100644
index 0000000000..6240cff527
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/appbar/appbar.json
@@ -0,0 +1,3 @@
+{
+ "predicate": "false"
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/dashboard/dashboard.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/dashboard/dashboard.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/dashboard/dashboard.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/dashboard/dashboard.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/dashboard/dashboard.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/dashboard/dashboard.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/dashboard/dashboard.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/dashboard/dashboard.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/dashboard/dashboard.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/dashboard/dashboard.json
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/dashboard/dashboard.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/dashboard/dashboard.json
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/dashboard/public/js/dashboard.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/dashboard/public/js/dashboard.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/dashboard/public/js/dashboard.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/dashboard/public/js/dashboard.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/device-detail.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/device-detail.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/device-detail.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/device-detail.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/device-detail.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/device-detail.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/device-detail.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/device-detail.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/device-detail.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/device-detail.json
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/device-detail.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/device-detail.json
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/android.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/android.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/android.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/android.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/arduino.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/arduino.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/arduino.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/arduino.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/digital_display.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/digital_display.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/digital_display.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/digital_display.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/firealarm.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/firealarm.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/firealarm.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/firealarm.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/ios.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/ios.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/ios.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/ios.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/raspberrypi.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/raspberrypi.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/raspberrypi.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/raspberrypi.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/sensebot.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/sensebot.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/sensebot.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/device_icons/sensebot.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/graph.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/graph.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/graph.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/img/graph.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/js/device-detail.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/js/device-detail.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/js/device-detail.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-detail/public/js/device-detail.js
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/device-listing.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/device-listing.hbs
new file mode 100644
index 0000000000..7ff2282dde
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/device-listing.hbs
@@ -0,0 +1,413 @@
+{{#zone "main"}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
You don't have any associated devices here.
+
+
+
+
+
+
+
+
+
+
Do you really want to remove this device from your Devices List?
+
+
+
+
+
+
+
+
+
+
+
+
Device was successfully removed.
+
+
+
+
+
+
+
+
+
+
Please enter new name for the device?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Device was successfully updated.
+
+
+
+
+
+
+
+
+
+
Please select group
+
+
+
Loading...
+
+
+
+
+
+
+
+
+
+
+
Device was successfully associated with group.
+
+
+
+
+
+
+
+
+
+
Device was successfully removed from group.
+
+
+
+
+
+
+
+
+
+
Exception at backend. Try Later.
+
+
+
+
+
+
+
+
+
+
+
+
Operation not permitted.
+
+
+
+
+
+
+
+
+
+
+
+
Device does not exist.
+
+
+
+
+
+
+
+
+
+
+
+
Select user to manage group sharing
+
Loading...
+
+
+
+
+
+
+
+
+
+
+
Select sharing roles
+
+
Loading...
+
+
+
+
+
+
+
+
+
+
+
Group sharing updated successfully.
+
+
+
+
+
+
+
+
+
+
Do you really want to remove this group from your Group List?
+
+
+
+
+
+
+
+
+
+
+
+
Group was successfully removed.
+
+
+
+
+
+
+
+
+
+
Please enter new name and description for the group
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Group was successfully updated.
+
+
+
+
+
+
+
+
+
+
Exception at backend. Try Later.
+
+
+
+
+
+
+
+
+
+
+
+
Action not permitted.
+
+
+
+
+
+
+
+
+
+
+
+
Group does not exist.
+
+
+
+
+
+
+
+
+
+
+
+
Unexpected error occurred!
+
+
+
+
+
+
+
+{{/zone}}
+{{#zone "bottomJs"}}
+
+
+
+{{/zone}}
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/device-listing.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/device-listing.js
new file mode 100644
index 0000000000..d4cdaca973
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/device-listing.js
@@ -0,0 +1,25 @@
+var log = new Log("modules/device-listing.js");
+
+function onRequest(context){
+ var constants = require("/modules/constants.js");
+ var userModule = require("/modules/user.js").userModule;
+ var permissions = [];
+ if(userModule.isAuthorized("/permission/device-mgt/admin/devices/list")){
+ permissions.push("LIST_DEVICES");
+ }else if(userModule.isAuthorized("/permission/device-mgt/user/devices/list")){
+ permissions.push("LIST_OWN_DEVICES");
+ }else if(userModule.isAuthorized("/permission/device-mgt/admin/policies/list")){
+ permissions.push("LIST_POLICIES");
+ }
+ permissions.push("LIST_OWN_DEVICES");
+ context.permissions = stringify(permissions);
+
+ var groupId = request.getParameter("groupId");
+ if (groupId){
+ context.groupId = groupId;
+ }else{
+ context.groupId = 0;
+ }
+ context.user = session.get(constants.USER_SESSION_KEY).username;
+ return context;
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/appbar/appbar.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/device-listing.json
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/appbar/appbar.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/device-listing.json
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/android.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/android.png
new file mode 100644
index 0000000000..7fee78a646
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/android.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/arduino.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/arduino.png
new file mode 100644
index 0000000000..31cb9fa364
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/arduino.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/digital_display.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/digital_display.png
new file mode 100644
index 0000000000..fb1f624c3f
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/digital_display.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/firealarm.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/firealarm.png
new file mode 100644
index 0000000000..aaf16925fd
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/firealarm.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/ios.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/ios.png
new file mode 100644
index 0000000000..4b09796f83
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/ios.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/raspberrypi.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/raspberrypi.png
new file mode 100644
index 0000000000..eb0e28cb26
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/raspberrypi.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/sensebot.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/sensebot.png
new file mode 100644
index 0000000000..04e5752a3f
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/images/sensebot.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/js/device-listing.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/js/device-listing.js
new file mode 100644
index 0000000000..f4552fad5e
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/js/device-listing.js
@@ -0,0 +1,678 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var groupId, username;
+
+(function () {
+ var cache = {};
+ var permissionSet = {};
+ var validateAndReturn = function (value) {
+ return (value == undefined || value == null) ? "Unspecified" : value;
+ };
+ Handlebars.registerHelper("groupMap", function (group) {
+ group.id = validateAndReturn(group.id);
+ });
+ Handlebars.registerHelper("deviceMap", function (device) {
+ device.owner = validateAndReturn(device.owner);
+ device.ownership = validateAndReturn(device.ownership);
+ var arr = device.properties;
+ if (arr) {
+ device.properties = arr.reduce(function (total, current) {
+ total[current.name] = validateAndReturn(current.value);
+ return total;
+ }, {});
+ }
+ });
+ Handlebars.registerHelper("if_owner", function (owner, opts) {
+ if (owner == username) {
+ return opts.fn(this);
+ } else {
+ opts.inverse(this);
+ }
+ });
+
+ //This method is used to setup permission for device listing
+ $.setPermission = function (permission) {
+ permissionSet[permission] = true;
+ };
+
+ $.hasPermission = function (permission) {
+ return permissionSet[permission];
+ };
+})();
+
+/*
+ * Setting-up global variables.
+ */
+var deviceCheckbox = "#ast-container-parent .ctrl-wr-asset .itm-select input[type='checkbox']";
+
+/*
+ * DOM ready functions.
+ */
+$(document).ready(function () {
+ /* Adding selected class for selected devices */
+ $(deviceCheckbox).each(function () {
+ addDeviceSelectedClass(this);
+ });
+
+ var i;
+ username = $("#permission").data("user");
+ var permissionList = $("#permission").data("permission");
+ for (i = 0; i < permissionList.length; i++) {
+ $.setPermission(permissionList[i]);
+ }
+
+ /* for device list sorting drop down */
+ $(".ctrl-filter-type-switcher").popover({
+ html: true,
+ content: function () {
+ return $("#content-filter-types").html();
+ }
+ });
+
+ groupId = $("#request-group-id").data("groupid");
+ loadDevices();
+});
+
+/*
+ * On Select All Device button click function.
+ *
+ * @param button: Select All Device button
+ */
+function selectAllDevices(button) {
+ if (!$(button).data('select')) {
+ $(deviceCheckbox).each(function (index) {
+ $(this).prop('checked', true);
+ addDeviceSelectedClass(this);
+ });
+ $(button).data('select', true);
+ $(button).html('Deselect All Devices');
+ } else {
+ $(deviceCheckbox).each(function (index) {
+ $(this).prop('checked', false);
+ addDeviceSelectedClass(this);
+ });
+ $(button).data('select', false);
+ $(button).html('Select All Devices');
+ }
+}
+
+/*
+ * On listing layout toggle buttons click function.
+ *
+ * @param view: Selected view type
+ * @param selection: Selection button
+ */
+function changeDeviceView(view, selection) {
+ $(".view-toggle").each(function () {
+ $(this).removeClass("selected");
+ });
+ $(selection).addClass("selected");
+ if (view == "list") {
+ $(".ast-container .devices-set").addClass("list-view");
+ } else {
+ $(".ast-container .devices-set").removeClass("list-view");
+ }
+}
+
+/*
+ * Add selected style class to the parent element function.
+ *
+ * @param checkbox: Selected checkbox
+ */
+function addDeviceSelectedClass(checkbox) {
+ if ($(checkbox).is(":checked")) {
+ $(checkbox).closest(".ctrl-wr-asset").addClass("selected device-select");
+ } else {
+ $(checkbox).closest(".ctrl-wr-asset").removeClass("selected device-select");
+ }
+}
+
+function loadDevices() {
+ var groupListing = $("#group-listing");
+ var groupListingSrc = groupListing.attr("src");
+ $.template("group-listing", groupListingSrc, function (template) {
+ var serviceURL;
+ if (groupId && groupId != "0") {
+ serviceURL = "/iotserver/api/group/id/" + groupId + "/device/all";
+ } else {
+ serviceURL = "/iotserver/api/devices/all";
+ }
+ var successCallback = function (data) {
+ data = JSON.parse(data);
+ var viewModel = {};
+ var groups;
+ if (groupId && groupId != "0") {
+ groups = data;
+ } else {
+ groups = data.data;
+ }
+ if (groups.length == 1 && groups[0].id == 0 && groups[0].devices.length == 0) {
+ $("#ast-container-parent").html($("#no-devices-div-content").html());
+ } else {
+ viewModel.groups = groups;
+ var content = template(viewModel);
+ $("#ast-container-parent").html(content);
+ var deviceListing = $("#device-listing");
+ var deviceListingSrc = deviceListing.attr("src");
+ var imageResource = deviceListing.data("image-resource");
+ $.template("device-listing", deviceListingSrc, function (template) {
+ for (var g in groups) {
+ if (groups[g].devices && groups[g].devices.length > 0) {
+ viewModel = {};
+ viewModel.devices = groups[g].devices;
+ viewModel.imageLocation = imageResource;
+ content = template(viewModel);
+ } else {
+ if (groupId && groupId != "0") {
+ content = $("#no-grouped-devices-div-content").html();
+ } else {
+ content = $("#no-devices-in-group-div-content").html();
+ }
+ }
+ $("#ast-container-" + groups[g].id).html(content);
+ }
+ /*
+ * On device checkbox select add parent selected style class
+ */
+ $(deviceCheckbox).click(function () {
+ addDeviceSelectedClass(this);
+ });
+ attachGroupEvents();
+ attachDeviceEvents();
+ formatDates();
+ });
+ }
+ };
+ invokerUtil.get(serviceURL,
+ successCallback, function (jqXHR) {
+ displayDeviceErrors(jqXHR);
+ });
+ });
+}
+
+function formatDates() {
+ $(".formatDate").each(function () {
+ var timeStamp = $(this).html();
+ $(this).html(new Date(parseInt(timeStamp)).toUTCString());
+ });
+}
+
+/**
+ * Sorting function of users
+ * listed on User Management page in WSO2 MDM Console.
+ */
+$(function () {
+ var sortableElem = '.wr-sortable';
+ $(sortableElem).sortable({
+ beforeStop: function () {
+ var sortedIDs = $(this).sortable('toArray');
+ console.log(sortedIDs);
+ }
+ });
+ $(sortableElem).disableSelection();
+});
+
+var modalPopup = ".wr-modalpopup";
+var modalPopupContainer = modalPopup + " .modalpopup-container";
+var modalPopupContent = modalPopup + " .modalpopup-content";
+var body = "body";
+
+/*
+ * set popup maximum height function.
+ */
+function setPopupMaxHeight() {
+ $(modalPopupContent).css('max-height', ($(body).height() - ($(body).height() / 100 * 30)));
+ $(modalPopupContainer).css('margin-top', (-($(modalPopupContainer).height() / 2)));
+}
+
+/*
+ * show popup function.
+ */
+function showPopup() {
+ $(modalPopup).show();
+ setPopupMaxHeight();
+}
+
+/*
+ * hide popup function.
+ */
+function hidePopup() {
+ $(modalPopupContent).html('');
+ $(modalPopup).hide();
+}
+
+
+/**
+ * Following functions should be triggered after AJAX request is made.
+ */
+function attachDeviceEvents() {
+ /**
+ * Following click function would execute
+ * when a user clicks on "Remove" link
+ * on Device Management page in WSO2 MDM Console.
+ */
+ $("a.remove-device-link").click(function () {
+ var deviceId = $(this).data("deviceid");
+ var deviceType = $(this).data("devicetype");
+ var removeDeviceAPI = "/iotserver/api/device/" + deviceType + "/" + deviceId + "/remove";
+
+ $(modalPopupContent).html($('#remove-device-modal-content').html());
+ showPopup();
+
+ $("a#remove-device-yes-link").click(function () {
+ invokerUtil.get(
+ removeDeviceAPI,
+ function (data, txtStatus, jqxhr) {
+ var status = jqxhr.status;
+ if (status == 200) {
+ $(modalPopupContent).html($('#remove-device-200-content').html());
+ $('div[data-deviceid="' + deviceId + '"]').remove();
+ setTimeout(function () {
+ hidePopup();
+ }, 2000);
+ } else {
+ displayDeviceErrors(jqXHR);
+ }
+ },
+ function (jqXHR) {
+ displayDeviceErrors(jqXHR);
+ }
+ );
+ });
+
+ $("a#remove-device-cancel-link").click(function () {
+ hidePopup();
+ });
+
+ });
+
+ /**
+ * Following click function would execute
+ * when a user clicks on "Edit" link
+ * on Device Management page in WSO2 MDM Console.
+ */
+ $("a.edit-device-link").click(function () {
+ var deviceId = $(this).data("deviceid");
+ var deviceType = $(this).data("devicetype");
+ var deviceName = $(this).data("devicename");
+ var editDeviceAPI = "/iotserver/api/device/" + deviceType + "/" + deviceId + "/update";
+
+ $(modalPopupContent).html($('#edit-device-modal-content').html());
+ $('#edit-device-name').val(deviceName);
+ showPopup();
+
+ $("a#edit-device-yes-link").click(function () {
+ var newDeviceName = $('#edit-device-name').val();
+ var device = {"device": {"name": newDeviceName}};
+ invokerUtil.post(
+ editDeviceAPI,
+ device,
+ function (data, txtStatus, jqxhr) {
+ var status = jqxhr.status;
+ if (status == 200) {
+ $(modalPopupContent).html($('#edit-device-200-content').html());
+ $("div[data-deviceid='" + deviceId + "'] .ast-name").html(newDeviceName);
+ setTimeout(function () {
+ hidePopup();
+ }, 2000);
+ } else {
+ displayDeviceErrors(jqXHR);
+ }
+ },
+ function (jqXHR) {
+ displayDeviceErrors(jqXHR);
+ }
+ );
+ });
+
+ $("a#edit-device-cancel-link").click(function () {
+ hidePopup();
+ });
+ });
+
+ /**
+ * Following click function would execute
+ * when a user clicks on "Group" link
+ * on Device Management page in WSO2 MDM Console.
+ */
+ if ($("a.group-device-link").length > 0) {
+ $("a.group-device-link").click(function () {
+ var deviceId = $(this).data("deviceid");
+ var deviceType = $(this).data("devicetype");
+ var endPoint = "/iotserver/api/group/all";
+
+ $(modalPopupContent).html($('#group-device-modal-content').html());
+ $('#user-groups').html("Loading...");
+ $("a#group-device-yes-link").hide();
+ showPopup();
+
+ invokerUtil.get(endPoint,
+ function (data, txtStatus, jqxhr) {
+ var groups = JSON.parse(data);
+ var status = jqxhr.status;
+ if (status == 200) {
+ if (groups.length <= 0) {
+ $('#user-groups').html("There is no any groups available");
+ return;
+ }
+ var str = '';
+ for (var group in groups) {
+ str += '' + groups[group].name + ' ';
+ }
+ str += ' ';
+ $('#user-groups').html(str);
+ $("a#group-device-yes-link").show();
+ $("a#group-device-yes-link").click(function () {
+ var selectedGroupId = $('#assign-group-selector').val();
+ endPoint = "/iotserver/api/group/id/" + selectedGroupId + "/assign";
+ var device = {"deviceId": deviceId, "deviceType": deviceType};
+ invokerUtil.post(
+ endPoint,
+ device,
+ function (data, txtStatus, jqxhr) {
+ var status = jqxhr.status;
+ if (status == 200) {
+ $(modalPopupContent).html($('#group-associate-device-200-content').html());
+ loadDevices();
+ setTimeout(function () {
+ hidePopup();
+ }, 2000);
+ } else {
+ displayDeviceErrors(jqXHR);
+ }
+ },
+ function (jqXHR) {
+ displayDeviceErrors(jqXHR);
+ }
+ );
+ });
+ }
+ },
+ function (jqXHR) {
+ displayDeviceErrors(jqXHR);
+ }
+ );
+ $("a#group-device-cancel-link").click(function () {
+ hidePopup();
+ });
+ });
+
+ }
+}
+
+/**
+ * Following functions should be triggered after AJAX request is made.
+ */
+function attachGroupEvents() {
+
+ /**
+ * Following click function would execute
+ * when a user clicks on "Share" link
+ * on Group Management page in WSO2 IoT Server Console.
+ */
+ $("a.share-group-link").click(function () {
+ var groupId = $(this).data("groupid");
+ $(modalPopupContent).html($('#share-group-w1-modal-content').html());
+ $('#user-names').html('Loading...');
+ showPopup();
+ $("a#share-group-next-link").hide();
+ invokerUtil.get("/iotserver/api/users",
+ function (data, txtStatus, jqxhr) {
+ var users = JSON.parse(data);
+ var status = jqxhr.status;
+ if (status == 200) {
+ var str = '';
+ var hasUsers = false;
+ for (var user in users) {
+ if (users[user].username != username) {
+ str += '' + users[user].username + ' ';
+ hasUsers = true;
+ }
+ }
+ str += ' ';
+ if (!hasUsers) {
+ str = "There is no any other users registered";
+ $('#user-names').html(str);
+ return;
+ }
+ $('#user-names').html(str);
+ $("a#share-group-next-link").show();
+ $("a#share-group-next-link").click(function () {
+ var selectedUser = $('#share-user-selector').val();
+ $(modalPopupContent).html($('#share-group-w2-modal-content').html());
+ $('#user-roles').html('Loading...');
+ $("a#share-group-yes-link").hide();
+ invokerUtil.get("/iotserver/api/group/id/" + groupId + "/" + selectedUser + "/rolemapping",
+ function (data, txtStatus, jqxhr) {
+ var roleMap = JSON.parse(data);
+ var status = jqxhr.status;
+ if (status == 200) {
+ var str = '';
+ var isChecked = '';
+ var hasRoles = false;
+ for (var role in roleMap) {
+ if (roleMap[role].assigned == true) {
+ isChecked = 'checked';
+ }
+ str += ' ' + roleMap[role].role + ' ';
+ hasRoles = true;
+ }
+ if (!hasRoles) {
+ str = "There is no any roles for this group";
+ return;
+ }
+ $('#user-roles').html(str);
+ $("a#share-group-yes-link").show();
+ $("a#share-group-yes-link").click(function () {
+ var updatedRoleMap = [];
+ for (var role in roleMap) {
+ if ($('#user-role-' + roleMap[role].role).is(':checked') != roleMap[role].assigned) {
+ roleMap[role].assigned = $('#user-role-' + roleMap[role].role).is(':checked');
+ updatedRoleMap.push(roleMap[role]);
+ }
+ }
+ invokerUtil.post("/iotserver/api/group/id/" + groupId + "/" + selectedUser + "/roleupdate",
+ updatedRoleMap,
+ function (data, txtStatus, jqxhr) {
+ var status = jqxhr.status;
+ if (status == 200) {
+ $(modalPopupContent).html($('#share-group-200-content').html());
+ loadDevices();
+ setTimeout(function () {
+ hidePopup();
+ }, 2000);
+ } else {
+ displayGroupErrors(status);
+ }
+ }, function (jqXHR) {
+ displayGroupErrors(jqXHR);
+ }
+ );
+ });
+ } else {
+ displayGroupErrors(status);
+ }
+ }, function (jqXHR) {
+ displayGroupErrors(jqXHR);
+ }
+ );
+ $("a#share-group-w2-cancel-link").click(function () {
+ hidePopup();
+ });
+ });
+ } else {
+ displayGroupErrors(status);
+ }
+ }, function (jqXHR) {
+ displayGroupErrors(jqXHR);
+ }
+ );
+
+ $("a#share-group-w1-cancel-link").click(function () {
+ hidePopup();
+ });
+
+ });
+
+ /**
+ * Following click function would execute
+ * when a user clicks on "Remove" link
+ * on Group Management page in WSO2 IoT Server Console.
+ */
+ $("a.remove-group-link").click(function () {
+ var groupId = $(this).data("groupid");
+ var removeGroupApi = "/iotserver/api/group/id/" + groupId + "/remove";
+
+ $(modalPopupContent).html($('#remove-group-modal-content').html());
+ showPopup();
+
+ $("a#remove-group-yes-link").click(function () {
+ invokerUtil.delete(
+ removeGroupApi,
+ function (data, txtStatus, jqxhr) {
+ var status = jqxhr.status;
+ if (status == 200) {
+ $(modalPopupContent).html($('#remove-group-200-content').html());
+ loadDevices();
+ setTimeout(function () {
+ hidePopup();
+ }, 2000);
+ } else {
+ displayGroupErrors(status);
+ }
+ },
+ function (jqXHR) {
+ displayGroupErrors(jqXHR);
+ }
+ );
+ });
+
+ $("a#remove-group-cancel-link").click(function () {
+ hidePopup();
+ });
+
+ });
+
+ /**
+ * Following click function would execute
+ * when a user clicks on "Edit" link
+ * on Device Management page in WSO2 MDM Console.
+ */
+ $("a.edit-group-link").click(function () {
+ var groupId = $(this).data("groupid");
+ var groupName = $(this).data("groupname");
+ var groupDescription = $(this).data("groupdescription");
+ var editGroupApi = "/iotserver/api/group/id/" + groupId + "/update";
+
+ $(modalPopupContent).html($('#edit-group-modal-content').html());
+ $('#edit-group-name').val(groupName);
+ $('#edit-group-description').val(groupDescription);
+ showPopup();
+
+ $("a#edit-group-yes-link").click(function () {
+ var newGroupName = $('#edit-group-name').val();
+ var newGroupDescription = $('#edit-group-description').val();
+ var group = {"name": newGroupName, "description": newGroupDescription};
+ invokerUtil.post(
+ editGroupApi,
+ group,
+ function (data, txtStatus, jqxhr) {
+ var status = jqxhr.status;
+ if (status == 200) {
+ if (data != "false") {
+ $(modalPopupContent).html($('#edit-group-200-content').html());
+ loadDevices();
+ setTimeout(function () {
+ hidePopup();
+ }, 2000);
+ } else {
+ $(modalPopupContent).html($('#group-409-content').html());
+ $("a#group-409-link").click(function () {
+ hidePopup();
+ });
+ }
+ } else {
+ displayGroupErrors(status);
+ }
+ },
+ function (jqXHR) {
+ displayGroupErrors(jqXHR);
+ }
+ );
+ });
+
+ $("a#edit-group-cancel-link").click(function () {
+ hidePopup();
+ });
+ });
+}
+
+function displayDeviceErrors(jqXHR) {
+ showPopup();
+ if (jqXHR.status == 400) {
+ $(modalPopupContent).html($('#group-400-content').html());
+ $("a#group-400-link").click(function () {
+ hidePopup();
+ });
+ } else if (jqXHR.status == 403) {
+ $(modalPopupContent).html($('#group-403-content').html());
+ $("a#group-403-link").click(function () {
+ hidePopup();
+ });
+ } else if (jqXHR.status == 409) {
+ $(modalPopupContent).html($('#group-409-content').html());
+ $("a#group-409-link").click(function () {
+ hidePopup();
+ });
+ } else {
+ $(modalPopupContent).html($('#group-unexpected-error-content').html());
+ $("a#group-unexpected-error-link").click(function () {
+ hidePopup();
+ });
+ console.log("Error code: " + jqXHR.status);
+ }
+}
+
+
+function displayGroupErrors(jqXHR) {
+ showPopup();
+ if (jqXHR.status == 400) {
+ $(modalPopupContent).html($('#group-400-content').html());
+ $("a#group-400-link").click(function () {
+ hidePopup();
+ });
+ } else if (jqXHR.status == 403) {
+ $(modalPopupContent).html($('#group-403-content').html());
+ $("a#group-403-link").click(function () {
+ hidePopup();
+ });
+ } else if (jqXHR.status == 409) {
+ $(modalPopupContent).html($('#group-409-content').html());
+ $("a#group-409-link").click(function () {
+ hidePopup();
+ });
+ } else {
+ $(modalPopupContent).html($('#group-unexpected-error-content').html());
+ $("a#group-unexpected-error-link").click(function () {
+ hidePopup();
+ });
+ console.log("Error code: " + jqXHR.status);
+ }
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/templates/device-listing.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/templates/device-listing.hbs
new file mode 100644
index 0000000000..3fc0232612
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/templates/device-listing.hbs
@@ -0,0 +1,71 @@
+{{#each devices}}
+ {{deviceMap this}}
+
+
+{{/each}}
+
+
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/templates/group-listing.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/templates/group-listing.hbs
new file mode 100644
index 0000000000..8b17348647
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/device-listing/public/templates/group-listing.hbs
@@ -0,0 +1,54 @@
+{{#each groups}}
+ {{groupMap this}}
+
+
+
+
+ {{#if name}}
+ {{name}} Devices
+ {{else}}
+ Ungrouped Devices
+ {{/if}}
+
+
+ {{#if name}}
+
+ {{/if}}
+
+
+
+
+
+
+{{/each}}
+
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/downloads/downloads.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/downloads/downloads.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/downloads/downloads.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/downloads/downloads.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/downloads/downloads.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/downloads/downloads.json
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/downloads/downloads.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/downloads/downloads.json
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/downloads/public/android-app.apk b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/downloads/public/android-app.apk
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/downloads/public/android-app.apk
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/downloads/public/android-app.apk
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/events/events.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/events/events.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/events/events.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/events/events.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/events/events.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/events/events.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/events/events.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/events/events.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/events/events.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/events/events.json
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/events/events.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/events/events.json
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/events/public/js/events.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/events/public/js/events.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/events/public/js/events.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/events/public/js/events.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/events/public/templates/event-stream.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/events/public/templates/event-stream.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/events/public/templates/event-stream.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/events/public/templates/event-stream.hbs
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/extended-search-box/extended-search-box.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/extended-search-box/extended-search-box.hbs
new file mode 100644
index 0000000000..edad07c651
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/extended-search-box/extended-search-box.hbs
@@ -0,0 +1,94 @@
+{{#zone "main"}}
+
+{{/zone}}
+{{#zone "bottomJs"}}
+
+{{/zone}}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/extended-search-box/extended-search-box.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/extended-search-box/extended-search-box.json
new file mode 100644
index 0000000000..a5f44dfb2a
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/extended-search-box/extended-search-box.json
@@ -0,0 +1,3 @@
+{
+ "predicate": "false"
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/extended-search-box/public/img/icons/ico-grid.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/extended-search-box/public/img/icons/ico-grid.png
new file mode 100644
index 0000000000..6e60d754a5
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/extended-search-box/public/img/icons/ico-grid.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/extended-search-box/public/img/icons/ico-list.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/extended-search-box/public/img/icons/ico-list.png
new file mode 100644
index 0000000000..6262fbe10b
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/extended-search-box/public/img/icons/ico-list.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/extended-search-box/public/img/icons/ico-sort.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/extended-search-box/public/img/icons/ico-sort.png
new file mode 100644
index 0000000000..246199dd7e
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/extended-search-box/public/img/icons/ico-sort.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/extended-search-box/public/js/extended-search-box.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/extended-search-box/public/js/extended-search-box.js
new file mode 100644
index 0000000000..3ba305e0ec
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/extended-search-box/public/js/extended-search-box.js
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Setting-up global variables.
+ */
+var menuButton = '.ctrl-asset-type-switcher',
+ menu = '.popover.menu',
+ deviceOptions = '#device-filter-options',
+ menuContainer = '#asset-select',
+ menuSubContainer = '#asset-selected',
+ menuItems = '#asset-select ul li',
+ tagsContainer = '.wr-search-tags',
+ searchField = '#search',
+ menuItemsID = 0,
+ prevSelected = 0,
+ searchBtn = ".btn-search";
+
+/*
+ * DOM ready functions.
+ */
+$(document).ready(function(){
+
+ /* Bind filter menu relationship on load */
+ addingIdentity();
+
+ /* Bind filter select function to all assets on load */
+ $(menuItems).each(function(){
+ menuItemsID++;
+ $(this).attr({
+ 'asset':menuItemsID,
+ 'onclick':'selectAsset(this)',
+ 'level': $(this).parents('ul').length
+ });
+ });
+ $(searchBtn).click(function(){
+ var input = $(searchField).html();
+ var searchType = $(searchField).data("search-type");
+ loadGroups(searchType, input);
+ });
+});
+
+/*
+ * Bind filter window hide function to the document.
+ */
+$(document).bind('click', function(e) {
+ if($(e.target).attr('rel') !== 'assetfilter') {
+ $(menu).hide();
+ }
+});
+
+/*
+ * On filter switch button click show filter option window.
+ */
+$(menuButton).click(function(e){
+ e.stopPropagation();
+ $(menu).toggle();
+});
+
+/*
+ * On asset filter options window advance filter radio button change function
+ */
+$('#advance-filter-options input[type=radio]').change(function() {
+ if(this.value !== 'devices'){
+ $(searchField).attr('data-placeholder', 'Search '+ this.value + ' ...');
+ }
+ else {
+ $(deviceOptions).show();
+ }
+ $(searchField).data("search-type", $(this).data("type"));
+});
+
+/*
+ * Update filter container.
+ * @param asset: Selected asset
+ */
+function containerUpdate(asset){
+ var options = $(asset).next('ul').length ? $(asset).next('ul').html() : "";
+
+ $(menuSubContainer).html('' + '');
+
+ prevSelected = ($(menuSubContainer + ' ul.selected li').attr('asset'));
+
+ //$(menuSubContainer + ' ul.options li').length == 0 ? $(menuSubContainer + ' ul.options').hide() :
+ // + $(menuSubContainer + ' ul.options').show();
+
+ addingIdentity();
+}
+
+/*
+ * On asset click selecting filter.
+ * @param asset: Selected asset
+ */
+function selectAsset(asset){
+ var platformType = $(asset).data("type");
+ loadOperationBar(platformType);
+ loadGroups("type", platformType);
+ //$(tagsContainer +' span').each(function(){
+ // if($(this).attr('level') == $(asset).attr('level')){
+ // removeTags(this);
+ // }
+ //});
+
+ containerUpdate(asset);
+
+ $(menuSubContainer).show();
+ $(menuContainer).hide();
+
+ addTags(asset);
+}
+
+/*
+ * Adding asset filtering relationship menu child elements.
+ */
+function addingIdentity(){
+ $(menu).find('*').each(function(){
+ $(this).attr('rel', 'assetfilter');
+ });
+ $(tagsContainer).find('*').each(function(){
+ $(this).attr('rel', 'assetfilter');
+ });
+}
+
+/*
+ * Filter window go back function.
+ * @param backButton: Filter window back button
+ */
+function goBack(backButton){
+ if($(backButton).prev('li').attr('level') == 1){
+ $(menuSubContainer).hide();
+ $(menuContainer).show();
+ }
+ else{
+ containerUpdate($(menuContainer + ' [asset='+prevSelected+']').parent('ul').prev('li'));
+ $(backButton).remove();
+ }
+}
+
+/*
+ * Filter window reset function.
+ * @param backButton: Filter window reset button
+ */
+function resetNav(){
+ $('#goBack').remove();
+ $('#resetNav').remove();
+ $(menuSubContainer).hide();
+ $(menuContainer).show();
+}
+
+/*
+ * Find parent function.
+ * @param selection: Current asset parent search tag on search parent loop
+ */
+function getParent(selection){
+ return $(menuContainer + ' [asset=' + $(selection).attr('asset') + ']').closest('ul').prev('li');
+}
+
+/*
+ * On filter select ad asset & its parents to search field.
+ * @param tag: Selected filter search tag
+ */
+function addTags(tag){
+ var level = $(tag).attr('level'),
+ selection = tag,
+ content = '' + $(tag).find('.tag-name').html() + ' x ';
+
+ if(level !== 1) {
+ for (var i = 1; i < level; i++) {
+ content = '' + $(getParent(selection)).find('.tag-name').html() + ' x '
+ +content;
+
+ selection = getParent(selection);
+ }
+ $(tagsContainer).html(content);
+ }
+ addingIdentity();
+}
+
+/*
+ * On filter tags click remove asset & its child from search field.
+ * @param tag: Selected filter search tag
+ */
+function removeTags(tag){
+ $(tag).nextAll('span').andSelf().each(function(){
+ $($(menuContainer + ' [asset='+ $(this).attr('asset') +']')).removeClass('selected');
+ $(this).remove();
+ });
+ unloadOperationBar();
+ loadGroups();
+}
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/footer/footer.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/footer/footer.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/footer/footer.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/footer/footer.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/footer/footer.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/footer/footer.json
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/footer/footer.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/footer/footer.json
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-add/group-add.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-add/group-add.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-add/group-add.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-add/group-add.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-add/group-add.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-add/group-add.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-add/group-add.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-add/group-add.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-add/group-add.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-add/group-add.json
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-add/group-add.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-add/group-add.json
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-add/public/js/group-add.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-add/public/js/group-add.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-add/public/js/group-add.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-add/public/js/group-add.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/group-detail.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/group-detail.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/group-detail.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/group-detail.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/group-detail.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/group-detail.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/group-detail.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/group-detail.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/group-detail.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/group-detail.json
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/group-detail.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/group-detail.json
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/public/img/graph.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/public/img/graph.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/public/img/graph.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/public/img/graph.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/public/img/group-icon.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/public/img/group-icon.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/public/img/group-icon.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/public/img/group-icon.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/public/js/group-detail.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/public/js/group-detail.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/public/js/group-detail.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-detail/public/js/group-detail.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/group-listing.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/group-listing.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/group-listing.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/group-listing.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/group-listing.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/group-listing.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/group-listing.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/group-listing.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/group-listing.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/group-listing.json
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/group-listing.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/group-listing.json
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/public/images/group-icon.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/public/images/group-icon.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/public/images/group-icon.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/public/images/group-icon.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/public/js/group-listing.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/public/js/group-listing.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/public/js/group-listing.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/public/js/group-listing.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/public/templates/group-listing.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/public/templates/group-listing.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/public/templates/group-listing.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/group-listing/public/templates/group-listing.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/handlebars/handlebars.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/handlebars/handlebars.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/handlebars/handlebars.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/handlebars/handlebars.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/handlebars/handlebars.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/handlebars/handlebars.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/handlebars/handlebars.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/handlebars/handlebars.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/handlebars/handlebars.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/handlebars/handlebars.json
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/handlebars/handlebars.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/handlebars/handlebars.json
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/handlebars/public/js/handlebars-v2.0.0.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/handlebars/public/js/handlebars-v2.0.0.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/handlebars/public/js/handlebars-v2.0.0.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/handlebars/public/js/handlebars-v2.0.0.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/handlebars/public/js/utils.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/handlebars/public/js/utils.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/handlebars/public/js/utils.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/handlebars/public/js/utils.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/header/header.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/header/header.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/header/header.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/header/header.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/header/header.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/header/header.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/header/header.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/header/header.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/header/header.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/header/header.json
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/header/header.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/header/header.json
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/login/login.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/login/login.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/login/login.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/login/login.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/login/login.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/login/login.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/login/login.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/login/login.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/login/login.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/login/login.json
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/login/login.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/login/login.json
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/login/public/js/login-box.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/login/public/js/login-box.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/login/public/js/login-box.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/login/public/js/login-box.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/logo.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/logo.hbs
similarity index 97%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/logo.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/logo.hbs
index d39bd76ab7..c34649147d 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/logo.hbs
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/logo.hbs
@@ -1,7 +1,7 @@
-{{#zone "brand"}}
- IoT Server
-{{/zone}}
-{{#zone "favicon"}}
-
-{{/zone}}
-
+{{#zone "brand"}}
+ IoT Server
+{{/zone}}
+{{#zone "favicon"}}
+
+{{/zone}}
+
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/logo.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/logo.json
similarity index 88%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/logo.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/logo.json
index 795898d09e..5e32dcdac9 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/logo.json
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/logo.json
@@ -1,3 +1,3 @@
-{
- "predicate": "true"
+{
+ "predicate": "true"
}
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/public/img/favicon.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/public/img/favicon.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/public/img/favicon.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/public/img/favicon.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/public/img/logo.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/public/img/logo.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/public/img/logo.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/public/img/logo.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/public/less/logo.less b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/public/less/logo.less
similarity index 95%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/public/less/logo.less
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/public/less/logo.less
index 5c636e65ca..dfb9b65357 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/public/less/logo.less
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/logo/public/less/logo.less
@@ -1,14 +1,14 @@
-@import '/{bootstrap}/variables.less';
-@import '/{theme}/custom-variables.less';
-
-@logo-size : @navbar-height - 20px;
-
-.navbar-brand {
- float: left;
- padding: (@navbar-height - @logo-size - @line-height-computed/2) @navbar-padding-horizontal;
-}
-
-img.@{self-class} {
- display: inline-block;
- width: @logo-size;
-}
+@import '/{bootstrap}/variables.less';
+@import '/{theme}/custom-variables.less';
+
+@logo-size : @navbar-height - 20px;
+
+.navbar-brand {
+ float: left;
+ padding: (@navbar-height - @logo-size - @line-height-computed/2) @navbar-padding-horizontal;
+}
+
+img.@{self-class} {
+ display: inline-block;
+ width: @logo-size;
+}
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/operation-bar.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/operation-bar.hbs
new file mode 100644
index 0000000000..4a7d0251e1
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/operation-bar.hbs
@@ -0,0 +1,20 @@
+{{#zone "main"}}
+
+
+
+
+ Operations
+
+
+
+
+
+
+{{/zone}}
+
+{{#zone "bottomJs"}}
+
+
+
+
+{{/zone}}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/operation-bar.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/operation-bar.js
new file mode 100644
index 0000000000..e99497b9e8
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/operation-bar.js
@@ -0,0 +1,3 @@
+function onRequest(context){
+ return context;
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/user-listing/user-listing.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/operation-bar.json
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/user-listing/user-listing.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/operation-bar.json
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-add-new.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-add-new.png
new file mode 100644
index 0000000000..9dc4ef315d
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-add-new.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-camera.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-camera.png
new file mode 100644
index 0000000000..978d135ee0
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-camera.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-compare.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-compare.png
new file mode 100644
index 0000000000..68657e8f28
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-compare.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-configure.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-configure.png
new file mode 100644
index 0000000000..59484ca350
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-configure.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-grid.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-grid.png
new file mode 100644
index 0000000000..fbd046ddec
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-grid.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-guage.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-guage.png
new file mode 100644
index 0000000000..ee00f4b10e
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-guage.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-list.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-list.png
new file mode 100644
index 0000000000..464b0b5299
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-list.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-lock.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-lock.png
new file mode 100644
index 0000000000..31222fb2e4
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-lock.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-map.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-map.png
new file mode 100644
index 0000000000..368584dfce
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-map.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-menu.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-menu.png
new file mode 100644
index 0000000000..43d0675f36
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-menu.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-message.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-message.png
new file mode 100644
index 0000000000..3767e2c8aa
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-message.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-meter.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-meter.png
new file mode 100644
index 0000000000..df2e8cfad6
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-meter.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-next.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-next.png
new file mode 100644
index 0000000000..22b915a4e2
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-next.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-prev.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-prev.png
new file mode 100644
index 0000000000..02926ea601
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-prev.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-ring.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-ring.png
new file mode 100644
index 0000000000..c59ac06028
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-ring.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-save.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-save.png
new file mode 100644
index 0000000000..ddb425f73e
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-save.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-sort.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-sort.png
new file mode 100644
index 0000000000..d2b6b3b2ff
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-sort.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-user.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-user.png
new file mode 100644
index 0000000000..160fe80331
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-user.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-wifi.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-wifi.png
new file mode 100644
index 0000000000..12920430dc
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-wifi.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-wipe.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-wipe.png
new file mode 100644
index 0000000000..dbf0221fda
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/images/icons/ico-wipe.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/js/operation-bar.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/js/operation-bar.js
new file mode 100644
index 0000000000..699589b908
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/js/operation-bar.js
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Setting-up global variables.
+ */
+
+var operations = '.wr-operations',
+ modalPopup = '.wr-modalpopup',
+ modalPopupContainer = modalPopup + ' .modalpopup-container',
+ modalPopupContent = modalPopup + ' .modalpopup-content',
+ deviceCheckbox = '#ast-container .ctrl-wr-asset .itm-select input[type="checkbox"]',
+ showOperationsBtn = '#showOperationsBtn',
+ navHeight = $('#nav').height(),
+ headerHeight = $('header').height(),
+ offset = (headerHeight + navHeight),
+ maxOperationsLimit = 15,
+ hiddenOperation = '.wr-hidden-operations-content > div',
+ deviceSelection = '.device-select',
+ currentOperationList = [];
+
+/*
+ * DOM ready functions.
+ */
+$(document).ready(function(){
+ if($(operations + "> a").length > maxOperationsLimit){
+ $(showOperationsBtn).show();
+ }
+ else{
+ $(operations).show();
+ }
+ toggleMoreOperationsHeight();
+ //loadOperationBar("ios");
+ /**
+ * Android App type javascript
+ */
+ $(".wr-modalpopup").on("click", ".appTypesInput", function(){
+ var appType = $(".appTypesInput").val();
+ if (appType == "Public") {
+ $('.appURLInput').prop( "disabled", true );
+ }else if (appType == "Enterprise"){
+ $('.appURLInput').prop( "disabled", false );
+ }
+ }).trigger("change");
+});
+
+
+/*
+ * On window loaded functions.
+ */
+$(window).load(function(){
+ setPopupMaxHeight();
+});
+
+/*
+ * On window resize functions.
+ */
+$(window).resize(function(){
+ toggleMoreOperationsHeight();
+ setPopupMaxHeight();
+});
+
+/*
+ * On main div.container resize functions.
+ * @required jquery.resize.js
+ */
+$('.container').resize(function(){
+ toggleMoreOperationsHeight();
+});
+
+/*
+ * On Show Operations click operation show toggling function.
+ */
+function showOperations(){
+ $(operations).toggle('slide');
+}
+
+/*
+ * On operation click function.
+ * @param selection: Selected operation
+ */
+function operationSelect(selection){
+ var deviceIdList = getSelectedDeviceIds();
+ $(modalPopupContent).addClass("operation-data");
+ if (deviceIdList == 0){
+ $(modalPopupContent).html($('#errorOperations').html());
+ }else {
+ $(modalPopupContent).html($(operations + ' .operation[data-operation='+selection+']').html());
+ $(modalPopupContent).data("operation", selection);
+ }
+ showPopup();
+}
+
+/*
+ * show popup function.
+ */
+function showPopup() {
+ $(modalPopup).show();
+}
+
+/*
+ * hide popup function.
+ */
+function hidePopup() {
+ $(modalPopupContent).html('');
+ $(modalPopupContent).removeClass("operation-data");
+ $(modalPopup).hide();
+}
+
+/*
+ * set popup maximum height function.
+ */
+function setPopupMaxHeight() {
+ $(modalPopupContent).css('max-height', ($('body').height() - ($('body').height()/100 * 30)));
+ $(modalPopupContainer).css('margin-top', (-($(modalPopupContainer).height()/2)));
+}
+
+
+/*
+ * Function to open hidden device operations list
+ */
+function toggleMoreOperations(){
+ $('.wr-hidden-operations, .wr-page-content').toggleClass('toggled');
+ $(showOperationsBtn).toggleClass('selected');
+ //$('.footer').toggleClass('wr-hidden-operations-toggled');
+}
+
+/*
+ * Function to fit hidden device operation window height with the screen
+ */
+function toggleMoreOperationsHeight(){
+ $('.wr-hidden-operations').css('min-height', $('html').height() - (offset+140));
+}
+
+/*
+ * Advance operations sub categories show/hide toggle function
+ */
+function showAdvanceOperation(operation, button){
+ $(button).addClass('selected');
+ $(button).siblings().removeClass('selected');
+ $(hiddenOperation + '[data-operation="' + operation + '"]').show();
+ $(hiddenOperation + '[data-operation="' + operation + '"]').siblings().hide();
+}
+
+/*
+ * Function to get selected devices ID's
+ */
+function getSelectedDeviceIds(){
+ var deviceIdentifierList = [];
+ $(deviceSelection).each(function(index){
+ var device = $(this);
+ var deviceId = device.data('deviceid');
+ var deviceType = device.data('type');
+ deviceIdentifierList.push({
+ "id" : deviceId,
+ "type" : deviceType
+ });
+ });
+ return deviceIdentifierList;
+}
+function getDevicesByTypes(deviceList){
+ var deviceTypes = {};
+ jQuery.each(deviceList, function(index, item) {
+ if(!deviceTypes[item.type]){
+ deviceTypes[item.type] = [];
+ }
+ if(item.type == "ios"){
+ //for iOS we are sending only the IDS cause we are sending it to the JAX-RS
+ deviceTypes[item.type].push(item.id);
+ }
+ });
+ return deviceTypes;
+}
+function unloadOperationBar(){
+ $("#showOperationsBtn").addClass("hidden");
+ $(".wr-operations").html("");
+}
+
+function loadOperationBar(deviceType){
+ var operationBar = $("#operations-bar");
+ var operationBarSrc = operationBar.attr("src");
+ var platformType = deviceType;
+ $.template("operations-bar", operationBarSrc, function (template) {
+ var serviceURL = "/mdm-admin/features/" + platformType;
+ var successCallback = function (data) {
+ var viewModel = {};
+ var iconMap = {};
+ data = data.filter(function(current){
+ var iconName;
+ if (deviceType == "android"){
+ var iconName = operationModule.getAndroidIconForFeature(current.code);
+ } else if (deviceType == "ios"){
+ var iconName = operationModule.getiOSIconForFeature(current.code);
+ }
+ if (iconName){
+ current.icon = iconName;
+ return current;
+ }
+ });
+ viewModel.features = data;
+ var content = template(viewModel);
+ $(".wr-operations").html(content);
+ };
+ invokerUtil.get(serviceURL,
+ successCallback, function(message){
+ console.log(message);
+ });
+ });
+ var hiddenOperationBar = $("#hidden-operations-bar-" + deviceType);
+ var hiddenOperationBarSrc = hiddenOperationBar.attr("src");
+ $.template("hidden-operations-bar-" + deviceType, hiddenOperationBarSrc, function (template) {
+ var serviceURL = "/mdm-admin/features/" + platformType;
+ var successCallback = function (data) {
+ var viewModel = {};
+ viewModel.features = data.reduce(function (total, current) {
+ total[current.code] = current;
+ return total;
+ }, {});
+ currentOperationList = viewModel.features;
+ var content = template(viewModel);
+ $(".wr-hidden-operations").html(content);
+ };
+ invokerUtil.get(serviceURL,
+ successCallback, function(message){
+ console.log(message);
+ });
+ });
+ $("#showOperationsBtn").removeClass("hidden");
+}
+
+function runOperation(operationName) {
+ var deviceIdList = getSelectedDeviceIds();
+ var list = getDevicesByTypes(deviceIdList);
+ var successCallback = function(message){
+ console.log(message);
+ $(".wr-notification-bar").append('' + currentOperationList[operationName].name +
+ '- Operation Successful!
');
+ var notificationCount = parseInt($(".wr-notification-bubble").html());
+ notificationCount++;
+ $(".wr-notification-bubble").html(notificationCount);
+ };
+ if(list["ios"]){
+ var payload = operationModule.generatePayload("ios", operationName, list["ios"]);
+ var serviceEndPoint = operationModule.getiOSServiceEndpoint(operationName);
+
+ }
+ if(list["android"]){
+ var payload = operationModule.generatePayload("android", operationName, list["android"]);
+ var serviceEndPoint = operationModule.getAndroidServiceEndpoint(operationName);
+ }
+ invokerUtil.post(serviceEndPoint, payload,
+ successCallback, function(jqXHR, textStatus, errorThrown){
+ console.log(textStatus);
+ });
+ $(modalPopupContent).removeData();
+ hidePopup();
+}
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/templates/hidden-operations-android.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/templates/hidden-operations-android.hbs
new file mode 100644
index 0000000000..8e1900d487
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/templates/hidden-operations-android.hbs
@@ -0,0 +1,246 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Enable Encryption
+
+
+
Configure
+
+
+
+
+
+
+
Maximum Failed Attempts
+
+
+
+
+
Minimum Length
+
+
+
+
+
PIN History
+
+
+
+
+
Minimum complex characters
+
+
+
+
+
Minimum PIN Age in days
+
+
+
+
+
+
+
+ Require Alphanumeric
+
+
+
+
+
+
+ Allow simple PIN
+
+
+
+
Configure
+
+
+
+
+
+
+
+
+
Service Set Identifier
+
+
+
+
+
+
Password
+
+
+
+
+
Configure
+
+
+
+
+
+
+
+
+
+
App Identifier
+
+
+
+
+
+
+ App Type
+
+ Public
+ Enterprise
+
+
+
+
URL
+
+
+
+
+
Install
+
+
+
+
+
+
Title
+
+
+
+
+
URL
+
+
+
+
+
Install
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Enable Camera
+
+
+
Configure
+
+
+
+
+
+
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/templates/hidden-operations-ios.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/templates/hidden-operations-ios.hbs
new file mode 100644
index 0000000000..4cb006ef07
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/templates/hidden-operations-ios.hbs
@@ -0,0 +1,366 @@
+
+
+
+
+
+
+
+
+
+
App identifier
+
+
+
+
iTunes store ID
+
+
+
+
+
Bundle ID
+
+
+
+
+
+
+ Remove App upon dis-enrollment
+
+
+
+
+
+
+ Prevent backup of App data
+
+
+
+
Install
+
+
+
+
+
+
+
App identifier
+
+
+
+
Manifest URL
+
+
+
+
+
Bundle ID
+
+
+
+
+
+
+ Remove App upon dis-enrollment
+
+
+
+
+
+
+ Prevent backup of App data
+
+
+
+
Install
+
+
+
+
+
+
+
+
+
Service Set Identifier
+
+
+
+
+
+
+
+
+ Hidden Network
+
+
+
+
+
+
+
+ Auto Join
+
+
+
+
+
Proxy Setup
+
+
+
+ None
+
+
+
+
Security Type
+
+
+
+ WPA/WPA2 Personal
+
+
+
+
Password
+
+
+
+
+
+
Network Type
+
+
+
+ Standard
+
+
+
Configure
+
+
+
+
+
+
Account Description
+
+
+
+
+
+
Account Type
+
+
+
+
User Display Name
+
+
+
+
+
+
Email Address
+
+
+
+
+
+
+
+
+ Allow user to move messages from this account
+
+
+
+
+
+
+
+ Allow Recent Address syncing
+
+
+
+
+
+
+
+ Use Only in Mail
+
+
+
+
+
+
+
+ Enable S/MIME
+
+
+
+
+
Mail Server and Port
+
+
+
+
Username
+
+
+
+
+
+
Authentication Type
+
+
+
+ Password
+
+
+
+
Password
+
+
+
+
+
+
+
+
+ Use SSL
+
+
+
+
+
+
+
+
+
+
+
+
Location
+
+
+
+
Device Name
+
+
+
AirPlay password
+
+
+
+
Configure
+
+
+
+
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/templates/operations.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/templates/operations.hbs
new file mode 100644
index 0000000000..73dd25e756
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-bar/public/templates/operations.hbs
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+ No Devices selected. Please select a Device before performing an operation
+
+
+
+
+
+
+{{#each features}}
+ {{name}}
+
+
+
+
+
+
+
+
+ {{#equal code "NOTIFICATION"}}
+ Compose Message
+ {{/equal}}
+ {{#equal code "CHANGE_LOCK_CODE"}}
+ Change Lockcode
+ {{/equal}}
+ {{#unequal code "NOTIFICATION"}}
+ Do you want perform "{{name}}" operation on selected device(s)?
+
+ {{/unequal}}
+
+ {{#equal code "NOTIFICATION"}}
+ Type a message and click "SEND" to send it to all the selected device/s
+
+ {{/equal}}
+ {{#equal code "CHANGE_LOCK_CODE"}}
+
+ {{/equal}}
+
+
+
+
+
+{{/each}}
+
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-mod/operation-mod.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-mod/operation-mod.hbs
new file mode 100644
index 0000000000..117c0f03b6
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-mod/operation-mod.hbs
@@ -0,0 +1,6 @@
+{{#zone "main"}}
+
+{{/zone}}
+{{#zone "bottomLibJs"}}
+
+{{/zone}}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-mod/operation-mod.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-mod/operation-mod.js
new file mode 100644
index 0000000000..e99497b9e8
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-mod/operation-mod.js
@@ -0,0 +1,3 @@
+function onRequest(context){
+ return context;
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-mod/operation-mod.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-mod/operation-mod.json
new file mode 100644
index 0000000000..2a2a551fcf
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-mod/operation-mod.json
@@ -0,0 +1,7 @@
+{
+
+
+
+ "predicate": "false"
+
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-mod/public/js/operation-mod.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-mod/public/js/operation-mod.js
new file mode 100644
index 0000000000..6d846117c4
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/operation-mod/public/js/operation-mod.js
@@ -0,0 +1,363 @@
+var operationModule = function () {
+ var module = {};
+
+ module.getiOSServiceEndpoint = function(operationName) {
+ var featureMap = {
+ DEVICE_LOCK: "lock",
+ ALARM: "alarm",
+ LOCATION: "location",
+ AIR_PLAY: "airplay",
+ INSTALL_STORE_APPLICATION: "storeapplication",
+ INSTALL_ENTERPRISE_APPLICATION: "enterpriseapplication",
+ REMOVE_APPLICATION: "removeapplication",
+ RESTRICTION: "restriction",
+ CELLULAR: "cellular",
+ ENTERPRISE_WIPE: "enterprisewipe",
+ WIFI: "wifi"
+ };
+ return "/ios/operation/" + featureMap[operationName];
+ }
+
+ function createiOSPayload(operationName, operationData, devices) {
+ // Command operations doesn't need a payload
+ var payload;
+ var operationType = "profile";
+ if (operationName == "AIR_PLAY") {
+ payload = {
+ "operation": {
+ "airPlayDestinations": [
+ operationData.location
+ ],
+ "airPlayCredentials": [{
+ "deviceName": operationData.deviceName,
+ "password": operationData.password
+ }]
+ }
+ };
+ }else if (operationName == "INSTALL_STORE_APPLICATION") {
+ payload = {
+ "operation": {
+ "identifier": operationData.appIdentifier,
+ "iTunesStoreID": operationData.ituneID,
+ "removeAppUponMDMProfileRemoval": operationData.appRemoval,
+ "preventBackupOfAppData": operationData.backupData,
+ "bundleId": operationData.bundleId
+ }
+ };
+ } else if (operationName == "INSTALL_ENTERPRISE_APPLICATION") {
+ payload = {
+ "operation": {
+ "identifier": operationData.appIdentifier,
+ "manifestURL": operationData.manifestURL,
+ "removeAppUponMDMProfileRemoval": operationData.appRemoval,
+ "preventBackupOfAppData": operationData.backupData,
+ "bundleId": operationData.bundleId
+ }
+ };
+ } else if (operationName == "REMOVE_APPLICATION"){
+ payload = {
+ "operation": {
+ "bundleId": operationData.bundleId
+ }
+ };
+ } else if (operationName == "RESTRICTION"){
+ payload = {
+ "operation": {
+ "allowCamera": operationData.allowCamera,
+ "allowCloudBackup": operationData.allowCloudBackup,
+ "allowSafari": operationData.allowSafari,
+ "allowScreenShot": operationData.allowScreenshot,
+ "allowAirDrop": operationData.allowAirDrop
+ }
+ };
+ } else if (operationName == "CELLULAR"){
+ payload = {
+ "operation": {
+ "attachAPNName": null,
+ "authenticationType": null,
+ "username": null,
+ "password": null,
+ "apnConfigurations": [
+ {
+ "configurationName": null,
+ "authenticationType": null,
+ "username": null,
+ "password": null,
+ "proxyServer": null,
+ "proxyPort": 0
+ }
+ ]
+ }
+ };
+ } else if (operationName == "WIFI"){
+ payload = {
+ "operation": {
+ "hiddenNetwork": operationData.hiddenNetwork,
+ "autoJoin": operationData.autoJoin,
+ "encryptionType": operationData.encryptionType,
+ "hotspot": false,
+ "domainName": null,
+ "serviceProviderRoamingEnabled": false,
+ "displayedOperatorName": null,
+ "proxyType": null,
+ "roamingConsortiumOIs": null,
+ "password": operationData.password,
+ "clientConfiguration": {
+ "username": null,
+ "acceptEAPTypes": null,
+ "userPassword": null,
+ "oneTimePassword": false,
+ "payloadCertificateAnchorUUID": null,
+ "outerIdentity": null,
+ "tlstrustedServerNames": null,
+ "tlsallowTrustExceptions": false,
+ "tlscertificateIsRequired": false,
+ "ttlsinnerAuthentication": null,
+ "eapfastusePAC": false,
+ "eapfastprovisionPAC": false,
+ "eapfastprovisionPACAnonymously": false,
+ "eapsimnumberOfRANDs": 0
+ },
+ "payloadCertificateUUID": null,
+ "proxyServer": null,
+ "proxyPort": 0,
+ "proxyUsername": null,
+ "proxyPassword": null,
+ "proxyPACURL": null,
+ "proxyPACFallbackAllowed": false,
+ "ssid": operationData.ssid,
+ "nairealmNames": null,
+ "mccandMNCs": null
+ }
+ };
+ } else if (operationName == "MAIL"){
+ payload = {
+ "operation": {
+ "attachAPNName": null,
+ "authenticationType": null,
+ "username": null,
+ "password": null,
+ "apnConfigurations": [
+ {
+ "configurationName": null,
+ "authenticationType": null,
+ "username": null,
+ "password": null,
+ "proxyServer": null,
+ "proxyPort": 0
+ }
+ ]
+ }
+ };
+ } else {
+ // The payload of command operations are set as device ids
+ payload = devices;
+ operationType = "command";
+ }
+ if (operationType == "profile" && devices) {
+ payload.deviceIDs = devices;
+ }
+ return payload;
+ }
+
+ function createAndroidPayload(operationName, operationData, devices) {
+ var payload;
+ var operationType = "profile";
+ if (operationName == "CAMERA") {
+ payload = {
+ "operation": {
+ "enabled" : operationData.enableCamera
+ }
+ };
+ } else if (operationName == "CHANGE_LOCK_CODE") {
+ payload = {
+ "operation": {
+ "lockCode" : operationData.lockCode
+ }
+ };
+ } else if (operationName == "ENCRYPT_STORAGE") {
+ payload = {
+ "operation": {
+ "encrypted" : operationData.enableEncryption
+ }
+ };
+ } else if (operationName == "NOTIFICATION"){
+ payload = {
+ "deviceIDs": devices,
+ "operation": {
+ "message" : operationData.message
+ }
+ };
+ } else if (operationName == "WEBCLIP"){
+ payload = {
+ "operation": {
+ "identity": operationData.url,
+ "title": operationData.title
+
+ }
+ };
+ } else if (operationName == "INSTALL_APPLICATION"){
+ payload = {
+ "operation": {
+ "appIdentifier": operationData.packageName,
+ "type": operationData.type,
+ "url": operationData.url
+ }
+ };
+ } else if (operationName == "UNINSTALL_APPLICATION"){
+ payload = {
+ "operation": {
+ "appIdentifier": operationData.packageName
+ }
+ };
+ } else if (operationName == "BLACKLIST_APPLICATIONS"){
+ payload = {
+ "operation": {
+ "appIdentifier": operationData.packageNames
+ }
+ };
+ } else if (operationName == "PASSCODE_POLICY"){
+ payload = {
+ "operation": {
+ "maxFailedAttempts": operationData.maxFailedAttempts,
+ "minLength": operationData.minLength,
+ "pinHistory": operationData.pinHistory,
+ "minComplexChars": operationData.minComplexChars,
+ "maxPINAgeInDays": operationData.maxPINAgeInDays,
+ "requireAlphanumeric": operationData.requireAlphanumeric,
+ "allowSimple": operationData.allowSimple
+
+ }
+ };
+ } else if (operationName == "WIFI"){
+ payload = {
+ "operation": {
+ "ssid": operationData.ssid,
+ "password": operationData.password
+
+ }
+ };
+ } else {
+ operationType = "command";
+ payload = devices;
+ }
+ if (operationType == "profile" && devices) {
+ payload.deviceIDs = devices;
+ }
+ return payload;
+ }
+ module.getAndroidServiceEndpoint = function(operationName) {
+ var featureMap = {
+ DEVICE_LOCK: "lock",
+ DEVICE_LOCATION: "location",
+ CLEAR_PASSWORD: "clear-password",
+ CAMERA: "camera",
+ ENTERPRISE_WIPE: "enterprise-wipe",
+ WIPE_DATA: "wipe-data",
+ APPLICATION_LIST: "get-application-list",
+ DEVICE_RING: "ring-device",
+ DEVICE_MUTE: "mute",
+ NOTIFICATION: "notification",
+ WIFI: "wifi",
+ ENCRYPT_STORAGE: "encrypt",
+ CHANGE_LOCK_CODE: "change-lock-code",
+ WEBCLIP: "webclip",
+ INSTALL_APPLICATION: "install-application",
+ UNINSTALL_APPLICATION: "uninstall-application",
+ BLACKLIST_APPLICATIONS: "blacklist-applications",
+ PASSCODE_POLICY: "password-policy"
+ };
+ return "/mdm-android-agent/operation/" + featureMap[operationName];
+ };
+ /**
+ * Get the icon for the featureCode
+ * @param featureCode
+ * @returns icon class
+ */
+ module.getAndroidIconForFeature = function(featureCode){
+ var featureMap = {
+ DEVICE_LOCK: "fw-lock",
+ DEVICE_LOCATION: "fw-map-location",
+ CLEAR_PASSWORD: "fw-key",
+ ENTERPRISE_WIPE: "fw-clean",
+ WIPE_DATA: "fw-database",
+ DEVICE_RING: "fw-dial-up",
+ DEVICE_MUTE: "fw-incoming-call",
+ NOTIFICATION: "fw-message",
+ CHANGE_LOCK_CODE: "fw-padlock"
+ };
+ return featureMap[featureCode];
+ };
+ /**
+ * Get the icon for the featureCode
+ * @param featureCode
+ * @returns icon class
+ */
+ module.getiOSIconForFeature = function(featureCode){
+ var featureMap = {
+ DEVICE_LOCK: "fw-lock",
+ LOCATION: "fw-map-location",
+ ENTERPRISE_WIPE: "fw-clean",
+ ALARM: "fw-dial-up"
+ };
+ return featureMap[featureCode];
+ };
+ /**
+ * Filter a list by a data attribute
+ * @param prop
+ * @param val
+ * @returns {Array.|*|array|enumeration}
+ */
+ $.fn.filterByData = function(prop, val) {
+ return this.filter(
+ function() { return $(this).data(prop)==val; }
+ );
+ };
+
+ /*
+ @DeviceType = Device Type of the profile
+ @operationCode = Feature Codes to generate the profile from
+ @DeviceList = Optional device list to include in payload body for operations
+ */
+ module.generatePayload = function(deviceType, operationCode, deviceList){
+ var payload;
+ var operationData = {};
+ $(".operation-data").filterByData("operation", operationCode).find(".operationDataKeys").each(
+ function(index){
+ var operationDataObj = $(this);
+ var key = operationDataObj.data("key");
+ var value = operationDataObj.val();
+ if (operationDataObj.is(':checkbox')){
+ value = operationDataObj.is(":checked");
+ }else if (operationDataObj.is('select')){
+ var value = operationDataObj.find("option:selected").data("id");
+ if (!value){
+ value = operationDataObj.find("option:selected").text();
+ }
+ }
+ operationData[key] = value;
+ });
+ if(deviceType == "ios"){
+ payload = createiOSPayload(operationCode, operationData, deviceList);
+ }
+ if(deviceType == "android"){
+ payload = createAndroidPayload(operationCode, operationData, deviceList);
+ }
+ return payload;
+ };
+
+ /*
+ @DeviceType = Device Type of the profile
+ @FeatureCodes = Feature Codes to generate the profile from
+ */
+ module.generateProfile = function(deviceType, featureCodes){
+ var generatedProfile = {};
+ for (var i = 0; i < featureCodes.length; ++i) {
+ var featureCode = featureCodes[i];
+ var payload = module.generatePayload(deviceType, featureCode);
+ generatedProfile[featureCode] = payload.operation;
+ }
+ return generatedProfile;
+ };
+ return module;
+}();
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/policy-create.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/policy-create.hbs
new file mode 100644
index 0000000000..84e168386e
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/policy-create.hbs
@@ -0,0 +1,196 @@
+
+{{#zone "main"}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Policy creation is successful
+ Please click "Finish" to complete the process and go back to the policy list
+
+
+ Finish
+
+
+
+
+
+
+
+
+
+
+
+{{/zone}}
+{{#zone "bottomJs"}}
+
+
+
+
+
+
+{{/zone}}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/policy-create.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/policy-create.js
new file mode 100644
index 0000000000..f2fb495445
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/policy-create.js
@@ -0,0 +1,10 @@
+function onRequest(context){
+ var userModule = require("/modules/user.js").userModule;
+ var roles = userModule.getRoles(true);
+ var users = userModule.getUsers();
+ var actions = ["Enforce"];
+ context.roles = roles;
+ context.users = users;
+ context.actions = actions;
+ return context;
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/policy-create.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/policy-create.json
new file mode 100644
index 0000000000..f2aa29a39b
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/policy-create.json
@@ -0,0 +1,3 @@
+{
+ "predicate": "false"
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/codemirror.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/css/codemirror.css
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/codemirror.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/css/codemirror.css
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/RaspberryPi.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/RaspberryPi.png
new file mode 100644
index 0000000000..eb0e28cb26
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/RaspberryPi.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/android.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/android.png
new file mode 100644
index 0000000000..d38a8d7567
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/android.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/arduino-thumb.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/arduino-thumb.png
new file mode 100644
index 0000000000..31cb9fa364
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/arduino-thumb.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/banner-img-3.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/banner-img-3.png
new file mode 100644
index 0000000000..ce6d43d3b5
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/banner-img-3.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/beagleBone.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/beagleBone.png
new file mode 100644
index 0000000000..8bb45023fe
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/beagleBone.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/digitaldisplay-thumb.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/digitaldisplay-thumb.png
new file mode 100644
index 0000000000..fb1f624c3f
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/digitaldisplay-thumb.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/firealarm-thumb.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/firealarm-thumb.png
new file mode 100644
index 0000000000..aaf16925fd
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/firealarm-thumb.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/intel.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/intel.png
new file mode 100644
index 0000000000..185fed1b83
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/intel.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/ios.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/ios.png
new file mode 100644
index 0000000000..22be2fa39d
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/ios.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/sensebot-thumb.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/sensebot-thumb.png
new file mode 100644
index 0000000000..04e5752a3f
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/sensebot-thumb.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/windows.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/windows.png
new file mode 100644
index 0000000000..3b66825670
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/images/windows.png differ
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/codemirror.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/js/codemirror.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/codemirror.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/js/codemirror.js
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/js/policy-create.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/js/policy-create.js
new file mode 100755
index 0000000000..5705de5265
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/js/policy-create.js
@@ -0,0 +1,124 @@
+$('select.select2').select2({
+ placeholder: 'Select..'
+});
+
+$('select.select2[multiple=multiple]').select2({
+ placeholder: 'Select..',
+ tags: true
+});
+var stepperRegistry = {},
+ hiddenOperation = '.wr-hidden-operations-content > div',
+ advanceOperation = '.wr-advance-operations';
+function initStepper(selector){
+ $(selector).click(function(){
+ var nextStep = $(this).data("next");
+ var currentStep = $(this).data("current");
+ var isBack = $(this).data("back");
+ if (!isBack){
+ var action = stepperRegistry[currentStep];
+ if (action){
+ action(this);
+ }
+ }
+ if (!nextStep) {
+ var direct = $(this).data("direct");
+ window.location.href = direct;
+ }
+ $(".itm-wiz").each(function(){
+ var step = $(this).data("step");
+ if (step == nextStep){
+ $(this).addClass("itm-wiz-current");
+ }else{
+ $(this).removeClass("itm-wiz-current");
+ }
+ });
+ $(".wr-wizard").html($(".wr-steps").html());
+ $("." + nextStep).removeClass("hidden");
+ $("." + currentStep).addClass("hidden");
+
+ });
+}
+function showAdvanceOperation(operation, button){
+ $(button).addClass('selected');
+ $(button).siblings().removeClass('selected');
+ $(hiddenOperation + '[data-operation="' + operation + '"]').show();
+ $(hiddenOperation + '[data-operation="' + operation + '"]').siblings().hide();
+}
+
+var policy = {};
+var configuredProfiles = [];
+
+function savePolicy(){
+
+ var payload = {
+ policyName: policy.policyName,
+ compliance: policy.selectedAction,
+ ownershipType: policy.selectedOwnership,
+ profile: {
+ profileName: policy.policyName,
+ deviceType: {
+ id: policy.devicetypeId,
+ name: policy.devicetype
+ },
+ policyDefinition: policy.policyDefinition,
+ policyDescription: policy.policyDescription
+ }
+ };
+
+ invokerUtil.post("/iotserver/api/policies/add", payload, function(){
+ $(".policy-message").removeClass("hidden");
+ $(".add-policy").addClass("hidden");
+ }, function(){
+
+ });
+}
+
+$(document).ready(function(){
+ initStepper(".wizard-stepper");
+ $( "input[type='radio'].user-select-radio" ).change(function() {
+ $('.user-select').hide();
+ $('#'+$(this).val()).show();
+ });
+ //Adds an event listener to swithc
+ $(advanceOperation).on("click", ".wr-input-control.switch", function(evt){
+ var operation = $(this).parents(".operation-data").data("operation");
+ //prevents event bubbling by figuring out what element it's being called from
+ if (evt.target.tagName == "INPUT") {
+ if(!$(this).hasClass('collapsed')){
+ configuredProfiles.push(operation);
+ }else {
+ //splicing the array if operation is present
+ var index = jQuery.inArray( operation, configuredProfiles );
+ if (index!= -1){
+ configuredProfiles.splice( index, 1 );
+ }
+ }
+ console.log(configuredProfiles);
+ }
+
+ });
+ stepperRegistry['policy-content'] = function (actionButton){
+ policy.policyName = $("#policy-name-input").val();
+ policy.policyDescription = $("#policy-description-input").val();
+ //All data is collected. Policy can now be created.
+ savePolicy();
+ };
+ stepperRegistry['policy-profile'] = function (actionButton){
+ policy.policyDefinition = window.queryEditor.getValue();
+ };
+ stepperRegistry['policy-devicetype'] = function (actionButton){
+ policy.devicetype = $(actionButton).data("devicetype");
+ policy.devicetypeId = $(actionButton).data("devicetype-id");
+
+ };
+ $(".uu").click(function(){
+ var policyName = $("#policy-name-input").val();
+ var selectedProfiles = $("#profile-input").find(":selected");
+ var selectedProfileId = selectedProfiles.data("id");
+ var selectedUserRoles = $("#user-roles-input").val();
+ var selectedUsers = $("#users-input").val();
+ var selectedAction = $("#action-input").val();
+
+
+ });
+});
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/sql.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/js/sql.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/sql.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/js/sql.js
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/js/store-listing.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/js/store-listing.js
new file mode 100644
index 0000000000..2e4000b566
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/js/store-listing.js
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Setting-up global variables.
+ */
+var assetContainer = "#ast-container";
+
+function loadDeviceTypes() {
+ var deviceListing = $("#store-listing");
+ var deviceListingSrc = deviceListing.attr("src");
+
+ $.template("store-listing", deviceListingSrc, function (template) {
+ var serviceURL = "/iotserver/api/devices/types";
+
+ var successCallback = function (data) {
+ var viewModel = {};
+ var deviceTypes = JSON.parse(data);
+ if (!deviceTypes) return;
+
+ for (var i = 0; i < deviceTypes.length; i++) {
+ var deviceType = deviceTypes[i];
+
+ //setting defaults
+ var storeTitle = deviceType.name;
+ var storeDescription = "Connect your " + deviceType.name + " into the WSO2 IoT Server.";
+
+ if (deviceType.storeTitle != null) {
+ storeTitle = deviceType.storeTitle;
+ }
+
+ if (deviceType.storeDescription != null) {
+ storeDescription = deviceType.storeDescription;
+ }
+
+ deviceTypes[i].storeTitle = storeTitle;
+ deviceTypes[i].storeDescription = storeDescription;
+ }
+
+ viewModel.deviceTypes = deviceTypes;
+
+ if (data.length == 0) {
+ $("#ast-container").html("No Devices found");
+ } else {
+ var content = template(viewModel);
+ $("#ast-container").html(content);
+ initStepper(".wizard-stepper");
+ }
+ };
+ invokerUtil.get(serviceURL,
+ successCallback, function (message) {
+ console.log(message);
+ });
+ });
+}
+
+$(document).ready(function () {
+ loadDeviceTypes();
+});
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/templates/store-listing.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/templates/store-listing.hbs
new file mode 100644
index 0000000000..8f1c7958ba
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-create/public/templates/store-listing.hbs
@@ -0,0 +1,19 @@
+{{#each deviceTypes}}
+
+
+
+
{{storeTitle}}
+
{{storeDescription}}
+
+
+
+{{/each}}
+
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-detail/policy-detail.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-detail/policy-detail.hbs
new file mode 100644
index 0000000000..bf566146c7
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-detail/policy-detail.hbs
@@ -0,0 +1,201 @@
+{{#zone "main"}}
+
+
+
+ Device {{device.name}}
+
+ {{#if device.viewModel.vendor}}
+ ({{device.viewModel.vendor}} {{device.viewModel.model}})
+ {{/if}}
+
+
+
+
+
+
+
+
+
+ {{unit "operation-bar" deviceType=device.type}}
+
+
+
+
+
+
+
+
+
+
+
+
Owner: {{device.owner}}
+
Date of Enrollment: {{device.enrollment}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{#if device.viewModel.BatteryLevel}}
+
+
+
BATTERY
+
+
+
{{device.viewModel.BatteryLevel}}%
+
+
+
+ {{/if}}
+
+ {{#if device.viewModel.DeviceCapacity}}
+
+
+
STORAGE
+
+
+
{{device.viewModel.DeviceCapacityPercentage}}%{{device.viewModel.DeviceCapacityUsed}} GB Free
+
+
+
+ {{/if}}
+ {{#if device.viewModel.internal_memory.FreeCapacity}}
+
+
+
LOCAL STORAGE
+
+
+
{{device.viewModel.internal_memory.DeviceCapacityPercentage}}%{{device.viewModel.internal_memory.FreeCapacity}} GB Free
+
+
+
+ {{/if}}
+ {{#if device.viewModel.external_memory.FreeCapacity}}
+
+
+
EXTERNAL STORAGE
+
+
+
{{device.viewModel.external_memory.DeviceCapacityPercentage}}%{{device.viewModel.external_memory.FreeCapacity}} GB Free
+
+
+
+ {{/if}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Not available yet
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{{/zone}}
+{{#zone "bottomJs"}}
+
+
+{{/zone}}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-detail/policy-detail.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-detail/policy-detail.js
new file mode 100644
index 0000000000..769d304154
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-detail/policy-detail.js
@@ -0,0 +1,58 @@
+function onRequest(context) {
+ var uri = request.getRequestURI();
+ var uriMatcher = new URIMatcher(String(uri));
+ var isMatched = uriMatcher.match("/{context}/device/{deviceType}/{+deviceId}");
+ if (isMatched) {
+ var matchedElements = uriMatcher.elements();
+ var deviceType = matchedElements.deviceType;
+ var deviceId = matchedElements.deviceId;
+ context.deviceType = deviceType;
+ context.deviceId = deviceId;
+ var deviceModule = require("/modules/device.js").deviceModule;
+ var device = deviceModule.viewDevice(deviceType, deviceId);
+ if (device){
+ var viewModel = {};
+ var deviceInfo = device.properties.DEVICE_INFO;
+ if (deviceInfo != undefined && String(deviceInfo.toString()).length > 0){
+ deviceInfo = JSON.parse(deviceInfo);
+ if (device.type == "ios"){
+ viewModel.imei = device.properties.IMEI;
+ viewModel.phoneNumber = deviceInfo.PhoneNumber;
+ viewModel.udid = deviceInfo.UDID;
+ viewModel.BatteryLevel = Math.round(deviceInfo.BatteryLevel * 100);
+ viewModel.DeviceCapacity = Math.round(deviceInfo.DeviceCapacity * 100) / 100;
+ viewModel.AvailableDeviceCapacity = Math.round(deviceInfo.AvailableDeviceCapacity * 100) / 100;
+ viewModel.DeviceCapacityUsed = Math.round((viewModel.DeviceCapacity
+ - viewModel.AvailableDeviceCapacity) * 100) / 100;
+ viewModel.DeviceCapacityPercentage = Math.round(viewModel.DeviceCapacityUsed
+ / viewModel.DeviceCapacity * 10000) /100;
+ }else if(device.type == "android"){
+ viewModel.imei = device.properties.IMEI;
+ viewModel.model = device.properties.DEVICE_MODEL;
+ viewModel.vendor = device.properties.VENDOR;
+ viewModel.internal_memory = {};
+ viewModel.external_memory = {};
+ viewModel.location = {
+ latitude: device.properties.LATITUDE,
+ longitude: device.properties.LONGITUDE
+ };
+ viewModel.BatteryLevel = deviceInfo.BATTERY_LEVEL;
+ viewModel.internal_memory.FreeCapacity = Math.round((deviceInfo.INTERNAL_TOTAL_MEMORY -
+ deviceInfo.INTERNAL_AVAILABLE_MEMORY) * 100) / 100;
+ viewModel.internal_memory.DeviceCapacityPercentage = Math.round(deviceInfo.INTERNAL_AVAILABLE_MEMORY
+ / deviceInfo.INTERNAL_TOTAL_MEMORY * 10000) / 100;
+ viewModel.external_memory.FreeCapacity = Math.round((deviceInfo.EXTERNAL_TOTAL_MEMORY -
+ deviceInfo.EXTERNAL_AVAILABLE_MEMORY) * 100) / 100;
+ viewModel.external_memory.DeviceCapacityPercentage = Math.round(deviceInfo.EXTERNAL_AVAILABLE_MEMORY
+ /deviceInfo.EXTERNAL_TOTAL_MEMORY * 10000) /100;
+ }
+ viewModel.enrollment = device.enrollment;
+ device.viewModel = viewModel;
+ }
+ }
+ context.device = device;
+ } else {
+ response.sendError(404);
+ }
+ return context;
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/showcase.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-detail/policy-detail.json
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/showcase.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-detail/policy-detail.json
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-detail/public/js/policy-detail.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-detail/public/js/policy-detail.js
new file mode 100644
index 0000000000..c453c8899c
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-detail/public/js/policy-detail.js
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+function formatDates(){
+ $(".formatDate").each(function(){
+ var timeStamp = $(this).html();
+ $(this).html(new Date(parseInt(timeStamp)).toUTCString());
+ });
+}
+
+(function () {
+ var deviceId = $(".device-id");
+ var deviceIdentifier = deviceId.data("deviceid");
+ var deviceType = deviceId.data("type");
+ var payload = [deviceIdentifier];
+ if (deviceType == "ios") {
+ var serviceUrl = "/ios/operation/deviceinfo";
+ } else if (deviceType == "android") {
+ var serviceUrl = "/mdm-android-agent/operation/device-info";
+ }
+ invokerUtil.post(serviceUrl, payload,
+ function(message){
+ console.log(message);
+ }, function (message) {
+ console.log(message);
+ });
+ $(document).ready(function(){
+ loadOperationBar(deviceType);
+ loadMap();
+ formatDates();
+ });
+ function loadMap(){
+ var map;
+ function initialize() {
+ var mapOptions = {
+ zoom: 18
+ };
+ var lat = 6.9098591;
+ var long = 79.8523753;
+ map = new google.maps.Map(document.getElementById('device-location'),
+ mapOptions);
+
+ var pos = new google.maps.LatLng(lat,
+ long);
+ var marker = new google.maps.Marker({
+ position: pos,
+ map: map
+ });
+
+ map.setCenter(pos);
+ }
+ google.maps.event.addDomListener(window, 'load', initialize);
+ }
+}());
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-listing/policy-listing.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-listing/policy-listing.hbs
new file mode 100644
index 0000000000..77701f63fa
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-listing/policy-listing.hbs
@@ -0,0 +1,184 @@
+{{#zone "main"}}
+
+
+
+
+
{{listPolicyStatus}}
+
+
+ {{#if policies}}
+ {{#each policies}}
+
+
+
+
+
{{policyName}}
+ {{deviceType}} | Last Updated: {{updated}}
+
+
+
+
+
+
+
+
+ Remove
+
+
+
+
+ {{/each}}
+ {{else}}
+
+
+
+ {{/if}}
+
+
+
+
+
+
+
+
+
+
+
+
Do you really want to remove this policy from IoT Server?
+
+
+
+
+
+
+
+
+
+
+
+
Policy was successfully removed.
+
+
+
+
+
+
+
+
+
+
+
+
Exception at backend. Try Later.
+
+
+
+
+
+
+
+
+
+
+
+
Action not permitted.
+
+
+
+
+
+
+
+
+
+
+
+
Policy does not exist.
+
+
+
+
+
+
+
+
+
+
+
+
Policy does not exist.
+
+
+
+
+
+
+
+
+
+{{/zone}}
+{{#zone "common-navigation"}}
+
+{{/zone}}
+{{#zone "action-bar"}}
+
+
+
+
+
+ Add Policy
+
+{{/zone}}
+{{#zone "bottomJs"}}
+
+{{/zone}}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-listing/policy-listing.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-listing/policy-listing.js
new file mode 100644
index 0000000000..d7f2da5c96
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-listing/policy-listing.js
@@ -0,0 +1,20 @@
+function onRequest(context) {
+ // var log = new Log("policy-listing");
+ var policyModule = require("/modules/policy.js").policyModule;
+ var allPolicies = policyModule.getPolicies();
+ //log.info((allPolicies));
+ if (!allPolicies || allPolicies.length == 0) {
+ context.policies = [];
+ context.listPolicyStatus = "";
+ } else {
+ var i, filteredPoliciesList = [];
+ for (i = 0; i < allPolicies.length; i++) {
+ filteredPoliciesList.push(allPolicies[i]);
+ }
+ //log.info(filteredPoliciesList.length);
+ context.policies = filteredPoliciesList;
+ context.listPolicyStatus = "Total number of Policies found : " + filteredPoliciesList.length;
+ }
+ //context.permissions = policyModule.getUIPermissions();
+ return context;
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-listing/policy-listing.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-listing/policy-listing.json
new file mode 100644
index 0000000000..3f78010053
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-listing/policy-listing.json
@@ -0,0 +1,5 @@
+{
+
+
+
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-listing/public/js/policy-listing.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-listing/public/js/policy-listing.js
new file mode 100644
index 0000000000..4ecb748fec
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/policy-listing/public/js/policy-listing.js
@@ -0,0 +1,115 @@
+/**
+ * Sorting function of users
+ * listed on User Management page in WSO2 MDM Console.
+ */
+$(function () {
+ var sortableElem = '.wr-sortable';
+ $(sortableElem).sortable({
+ beforeStop: function () {
+ var sortedIDs = $(this).sortable('toArray');
+ console.log(sortedIDs);
+ }
+ });
+ $(sortableElem).disableSelection();
+});
+
+var modalPopup = ".wr-modalpopup";
+var modalPopupContainer = modalPopup + " .modalpopup-container";
+var modalPopupContent = modalPopup + " .modalpopup-content";
+var body = "body";
+
+/*
+ * set popup maximum height function.
+ */
+function setPopupMaxHeight() {
+ $(modalPopupContent).css('max-height', ($(body).height() - ($(body).height() / 100 * 30)));
+ $(modalPopupContainer).css('margin-top', (-($(modalPopupContainer).height() / 2)));
+}
+
+/*
+ * show popup function.
+ */
+function showPopup() {
+ $(modalPopup).show();
+ setPopupMaxHeight();
+}
+
+/*
+ * hide popup function.
+ */
+function hidePopup() {
+ $(modalPopupContent).html('');
+ $(modalPopup).hide();
+}
+
+$(document).ready(function () {
+ formatDates();
+});
+
+function formatDates() {
+ $(".formatDate").each(function () {
+ var timeStamp = $(this).html();
+ $(this).html(new Date(parseFloat(timeStamp)).toUTCString());
+ });
+}
+
+/**
+ * Following click function would execute
+ * when a user clicks on "Remove" link
+ * on User Management page in WSO2 MDM Console.
+ */
+$("a.remove-policy-link").click(function () {
+ var deviceType = $(this).data("devicetype");
+ var policyName = $(this).data("policyname");
+ var policyUUID = $(this).data("policyuuid");
+ ///{context}/api/policies/{deviceType}/{policyName}/remove
+ var removePolicyAPI = "/iotserver/api/policies/" + deviceType + "/" + policyName + "/remove";
+
+ $(modalPopupContent).html($('#remove-policy-modal-content').html());
+ showPopup();
+
+ $("a#remove-policy-yes-link").click(function () {
+ invokerUtil.get(
+ removePolicyAPI,
+ function (data) {
+ if (data == 200 || data == "true") {
+ $(modalPopupContent).html($('#remove-policy-200-content').html());
+ $('#' + policyUUID).remove();
+ $("a#remove-policy-200-link").click(function () {
+ hidePopup();
+ });
+ } else if (data == 400) {
+ $(modalPopupContent).html($('#remove-policy-400-content').html());
+ $("a#remove-policy-400-link").click(function () {
+ hidePopup();
+ });
+ } else if (data == 403) {
+ $(modalPopupContent).html($('#remove-policy-403-content').html());
+ $("a#remove-policy-403-link").click(function () {
+ hidePopup();
+ });
+ } else if (data == 409 || data == "false") {
+ $(modalPopupContent).html($('#remove-policy-409-content').html());
+ $("a#remove-policy-409-link").click(function () {
+ hidePopup();
+ });
+ } else if (data == 500) {
+ $(modalPopupContent).html($('#remove-policy-unexpected-content').html());
+ $("a#remove-policy-unexpected-link").click(function () {
+ hidePopup();
+ });
+ }
+ },
+ function () {
+ $(modalPopupContent).html($('#remove-policy-unexpected-error-content').html());
+ $("a#remove-policy-unexpected-error-link").click(function () {
+ hidePopup();
+ });
+ }
+ );
+ });
+
+ $("a#remove-policy-cancel-link").click(function () {
+ hidePopup();
+ });
+});
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/register/public/js/validate-register.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/register/public/js/validate-register.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/register/public/js/validate-register.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/register/public/js/validate-register.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/register/register.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/register/register.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/register/register.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/register/register.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/register/register.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/register/register.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/register/register.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/register/register.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/register/register.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/register/register.json
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/register/register.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/register/register.json
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/select2/public/css/select2.min.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/select2/public/css/select2.min.css
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/select2/public/css/select2.min.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/select2/public/css/select2.min.css
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/select2/public/js/select2.full.min.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/select2/public/js/select2.full.min.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/select2/public/js/select2.full.min.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/select2/public/js/select2.full.min.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/select2/select2.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/select2/select2.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/select2/select2.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/select2/select2.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/select2/select2.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/select2/select2.json
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/select2/select2.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/select2/select2.json
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/service-invoker-utility/public/js/invoker-lib.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/service-invoker-utility/public/js/invoker-lib.js
new file mode 100644
index 0000000000..2b4dbc0df7
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/service-invoker-utility/public/js/invoker-lib.js
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+//Using https://github.com/js-cookie/js-cookie
+
+var invokerUtil = function () {
+ var context="/iotserver";
+ var module = {};
+ var flagAuth = false; // A flag to be used to test without oAuth
+ function requestAccessToken(successCallback, errorCallback){
+ $.ajax({
+ url: context+"/token",
+ type: "GET",
+ success: function(){
+ successCallback
+ }
+ }).fail(errorCallback);
+ }
+ function call(method, url, payload, successCallback, errorCallback){
+ var accessToken = Cookies.get('accessToken');
+ var execute = function(){
+ var data = {
+ url: url,
+ type: method,
+ contentType: "application/json",
+ accept: "application/json",
+ //dataType: "json",
+ success: successCallback
+ };
+ if (payload){
+ data.data = JSON.stringify(payload);
+ }
+
+ if (flagAuth){
+ accessToken = Cookies.get('accessToken');
+ data.headers = {
+ "Authorization": "Bearer " + accessToken
+ };
+ }
+ $.ajax(data).fail(function(jqXHR){
+ if(jqXHR.status == "401"){
+ window.location.replace(context);
+ }else{
+ errorCallback(jqXHR);
+ }
+ });
+ }
+ if (flagAuth){
+ if (accessToken){
+ $.ajax({
+ url: context+"/token",
+ type: "GET",
+ success: function(){
+ execute();
+ }
+ }).fail(errorCallback);
+ }
+ }else {
+ execute();
+ }
+ }
+ module.get = function(url, successCallback, errorCallback){
+ var payload = null;
+ call("GET", url, payload, successCallback, errorCallback);
+ };
+ module.post = function(url, payload, successCallback, errorCallback){
+ call("POST", url, payload, successCallback, errorCallback);
+ };
+ module.delete = function(url, successCallback, errorCallback){
+ var payload = null;
+ call("DELETE", url, payload, successCallback, errorCallback);
+ }
+ return module;
+}();
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/js.cookie.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/service-invoker-utility/public/js/js.cookie.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/js.cookie.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/service-invoker-utility/public/js/js.cookie.js
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/service-invoker-utility/service-invoker-utility.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/service-invoker-utility/service-invoker-utility.hbs
new file mode 100644
index 0000000000..6a3b8f1c16
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/service-invoker-utility/service-invoker-utility.hbs
@@ -0,0 +1,4 @@
+{{#zone "bottomLibJs"}}
+
+
+{{/zone}}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/service-invoker-utility/service-invoker-utility.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/service-invoker-utility/service-invoker-utility.json
new file mode 100644
index 0000000000..d03150b899
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/service-invoker-utility/service-invoker-utility.json
@@ -0,0 +1,3 @@
+{
+ "predicate": "true"
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/public/images/enroll-large.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/public/images/enroll-large.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/public/images/enroll-large.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/public/images/enroll-large.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/public/images/manage-large.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/public/images/manage-large.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/public/images/manage-large.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/public/images/manage-large.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/public/images/step-01.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/public/images/step-01.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/public/images/step-01.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/public/images/step-01.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/public/images/step-02.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/public/images/step-02.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/public/images/step-02.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/public/images/step-02.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/public/images/step-03.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/public/images/step-03.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/public/images/step-03.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/public/images/step-03.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/showcase.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/showcase.hbs
similarity index 98%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/showcase.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/showcase.hbs
index 211b3b6747..ea818259b2 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/showcase.hbs
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/showcase.hbs
@@ -1,48 +1,48 @@
-{{#zone "main"}}
-
-
-
-
-
-
- {{unit "store-listing"}}
-
-
-
-
-
-
-
Enroll your device
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris in volutpat sapien. Phasellus sit amet mollis velit, vitae finibus orci. Vestibulum facilisis, neque quis tincidunt pulvinar, dui orci interdum orci, a rhoncus ante neque vitae felis.
-
-
-
-
-
-
-
-
-
Manage your device
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris in volutpat sapien. Phasellus sit amet mollis velit, vitae finibus orci. Vestibulum facilisis, neque quis tincidunt pulvinar, dui orci interdum orci, a rhoncus ante neque vitae felis.
-
-
-
-
-
-
-{{/zone}}
+{{#zone "main"}}
+
+
+
+
+
+
+ {{unit "store-listing"}}
+
+
+
+
+
+
+
Enroll your device
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris in volutpat sapien. Phasellus sit amet mollis velit, vitae finibus orci. Vestibulum facilisis, neque quis tincidunt pulvinar, dui orci interdum orci, a rhoncus ante neque vitae felis.
+
+
+
+
+
+
+
+
+
Manage your device
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris in volutpat sapien. Phasellus sit amet mollis velit, vitae finibus orci. Vestibulum facilisis, neque quis tincidunt pulvinar, dui orci interdum orci, a rhoncus ante neque vitae felis.
+
+
+
+
+
+
+{{/zone}}
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/showcase.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/showcase.js
similarity index 92%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/showcase.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/showcase.js
index 605a70054a..0ba05f3f01 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/showcase.js
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/showcase.js
@@ -1,4 +1,4 @@
-function onRequest(context){
- return context;
-}
-
+function onRequest(context){
+ return context;
+}
+
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/showcase.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/showcase.json
new file mode 100644
index 0000000000..6240cff527
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/showcase/showcase.json
@@ -0,0 +1,3 @@
+{
+ "predicate": "false"
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/RaspberryPi.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/RaspberryPi.png
new file mode 100644
index 0000000000..eb0e28cb26
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/RaspberryPi.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/android.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/android.png
new file mode 100644
index 0000000000..d38a8d7567
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/android.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/arduino-thumb.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/arduino-thumb.png
new file mode 100644
index 0000000000..31cb9fa364
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/arduino-thumb.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/banner-img-3.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/banner-img-3.png
new file mode 100644
index 0000000000..ce6d43d3b5
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/banner-img-3.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/beagleBone.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/beagleBone.png
new file mode 100644
index 0000000000..8bb45023fe
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/beagleBone.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/digitaldisplay-thumb.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/digitaldisplay-thumb.png
new file mode 100644
index 0000000000..fb1f624c3f
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/digitaldisplay-thumb.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/firealarm-thumb.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/firealarm-thumb.png
new file mode 100644
index 0000000000..aaf16925fd
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/firealarm-thumb.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/intel.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/intel.png
new file mode 100644
index 0000000000..185fed1b83
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/intel.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/ios.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/ios.png
new file mode 100644
index 0000000000..22be2fa39d
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/ios.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/sensebot-thumb.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/sensebot-thumb.png
new file mode 100644
index 0000000000..04e5752a3f
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/sensebot-thumb.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/windows.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/windows.png
new file mode 100644
index 0000000000..3b66825670
Binary files /dev/null and b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/images/windows.png differ
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/js/store-listing.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/js/store-listing.js
new file mode 100644
index 0000000000..a10f7ed309
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/js/store-listing.js
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Setting-up global variables.
+ */
+var assetContainer = "#ast-container";
+
+function loadDeviceTypes() {
+ var deviceListing = $("#store-listing");
+ var deviceListingSrc = deviceListing.attr("src");
+
+ $.template("store-listing", deviceListingSrc, function (template) {
+ var serviceURL = "/iotserver/api/devices/types";
+
+ var successCallback = function (data) {
+ var viewModel = {};
+ var deviceTypes = JSON.parse(data);
+ if (!deviceTypes) return;
+
+ for (var i = 0; i < deviceTypes.length; i++) {
+ var deviceType = deviceTypes[i];
+
+ //setting defaults
+ var storeTitle = deviceType.name;
+ var storeDescription = "Connect your " + deviceType.name + " into the WSO2 IoT Server.";
+
+ if (deviceType.storeTitle != null) {
+ storeTitle = deviceType.storeTitle;
+ }
+
+ if (deviceType.storeDescription != null) {
+ storeDescription = deviceType.storeDescription;
+ }
+
+ deviceTypes[i].storeTitle = storeTitle;
+ deviceTypes[i].storeDescription = storeDescription;
+ }
+
+ viewModel.deviceTypes = deviceTypes;
+
+ if (data.length == 0) {
+ $("#ast-container").html("No Devices found");
+ } else {
+ var content = template(viewModel);
+ $("#ast-container").html(content);
+ }
+ };
+ invokerUtil.get(serviceURL,
+ successCallback, function (message) {
+ console.log(message);
+ });
+ });
+}
+
+$(document).ready(function () {
+ loadDeviceTypes();
+});
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/templates/store-listing.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/templates/store-listing.hbs
new file mode 100644
index 0000000000..5beacb44ce
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/public/templates/store-listing.hbs
@@ -0,0 +1,19 @@
+{{#each deviceTypes}}
+
+
+
+
{{storeTitle}}
+
{{storeDescription}}
+
+
+
+{{/each}}
+
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/store-listing.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/store-listing.hbs
new file mode 100644
index 0000000000..32b5ad0999
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/store-listing.hbs
@@ -0,0 +1,11 @@
+{{#zone "main"}}
+
+
+ {{! All "Device Types" registered in CDMF will be listed here. please refer: public/js/store-listing.js }}
+
+{{/zone}}
+
+{{#zone "bottomJs"}}
+
+
+{{/zone}}
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/store-listing.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/store-listing.js
new file mode 100644
index 0000000000..88ff7f97f1
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/store-listing.js
@@ -0,0 +1,3 @@
+function onRequest(context){
+ return context;
+}
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/store-listing.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/store-listing.json
new file mode 100644
index 0000000000..6240cff527
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/store-listing/store-listing.json
@@ -0,0 +1,3 @@
+{
+ "predicate": "false"
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/bootstrap.min.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/bootstrap.min.css
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/bootstrap.min.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/bootstrap.min.css
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/custom-common.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/custom-common.css
similarity index 95%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/custom-common.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/custom-common.css
index 02acdd64e6..cb7f27b6d6 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/custom-common.css
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/custom-common.css
@@ -1,355 +1,355 @@
-@import "font-wso2.css";
-
-/* Regular */
-@font-face {
- font-family: 'Open Sans';
-
- src: url('../fonts/OpenSans-Regular-webfont.eot');
- src: url('../fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'),
- url('../fonts/OpenSans-Regular-webfont.woff') format('woff'),
- url('../fonts/OpenSans-Regular-webfont.ttf') format('truetype'),
- url('../fonts/OpenSans-Regular-webfont.svg#OpenSansRegular') format('svg');
- font-weight: normal;
- font-weight: 400;
- font-style: normal;
-
-}
-
-/* Italic */
-@font-face {
- font-family: 'Open Sans';
- src: url('../fonts/OpenSans-Italic-webfont.eot');
- src: url('../fonts/OpenSans-Italic-webfont.eot?#iefix') format('embedded-opentype'),
- url('../fonts/OpenSans-Italic-webfont.woff') format('woff'),
- url('../fonts/OpenSans-Italic-webfont.ttf') format('truetype'),
- url('../fonts/OpenSans-Italic-webfont.svg#OpenSansItalic') format('svg');
- font-weight: normal;
- font-weight: 400;
- font-style: italic;
-
-}
-
-/* Light */
-@font-face {
- font-family: 'Open Sans';
- src: url('../fonts/OpenSans-Light-webfont.eot');
- src: url('../fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'),
- url('../fonts/OpenSans-Light-webfont.woff') format('woff'),
- url('../fonts/OpenSans-Light-webfont.ttf') format('truetype'),
- url('../fonts/OpenSans-Light-webfont.svg#OpenSansLight') format('svg');
- font-weight: 200;
- font-style: normal;
-
-}
-
-/* Light Italic */
-@font-face {
- font-family: 'Open Sans';
- src: url('../fonts/OpenSans-LightItalic-webfont.eot');
- src: url('../fonts/OpenSans-LightItalic-webfont.eot?#iefix') format('embedded-opentype'),
- url('../fonts/OpenSans-LightItalic-webfont.woff') format('woff'),
- url('../fonts/OpenSans-LightItalic-webfont.ttf') format('truetype'),
- url('../fonts/OpenSans-LightItalic-webfont.svg#OpenSansLightItalic') format('svg');
- font-weight: 200;
- font-style: italic;
-
-}
-
-/* Semibold */
-@font-face {
- font-family: 'Open Sans';
- src: url('../fonts/OpenSans-Semibold-webfont.eot');
- src: url('../fonts/OpenSans-Semibold-webfont.eot?#iefix') format('embedded-opentype'),
- url('../fonts/OpenSans-Semibold-webfont.woff') format('woff'),
- url('../fonts/OpenSans-Semibold-webfont.ttf') format('truetype'),
- url('../fonts/OpenSans-Semibold-webfont.svg#OpenSansSemibold') format('svg');
- font-weight: 500;
- font-style: normal;
-
-}
-
-/* Semibold Italic */
-@font-face {
- font-family: 'Open Sans';
- src: url('../fonts/OpenSans-SemiboldItalic-webfont.eot');
- src: url('../fonts/OpenSans-SemiboldItalic-webfont.eot?#iefix') format('embedded-opentype'),
- url('../fonts/OpenSans-SemiboldItalic-webfont.woff') format('woff'),
- url('../fonts/OpenSans-SemiboldItalic-webfont.ttf') format('truetype'),
- url('../fonts/OpenSans-SemiboldItalic-webfont.svg#OpenSansSemiboldItalic') format('svg');
- font-weight: 500;
- font-style: italic;
-
-}
-
-/* Bold */
-@font-face {
- font-family: 'Open Sans';
- src: url('../fonts/OpenSans-Bold-webfont.eot');
- src: url('../fonts/OpenSans-Bold-webfont.eot?#iefix') format('embedded-opentype'),
- url('../fonts/OpenSans-Bold-webfont.woff') format('woff'),
- url('../fonts/OpenSans-Bold-webfont.ttf') format('truetype'),
- url('../fonts/OpenSans-Bold-webfont.svg#OpenSansBold') format('svg');
- font-weight: bold;
- font-weight: 700;
- font-style: normal;
-
-}
-
-/* Bold Italic */
-@font-face {
- font-family: 'Open Sans';
- src: url('../fonts/OpenSans-BoldItalic-webfont.eot');
- src: url('../fonts/OpenSans-BoldItalic-webfont.eot?#iefix') format('embedded-opentype'),
- url('../fonts/OpenSans-BoldItalic-webfont.woff') format('woff'),
- url('../fonts/OpenSans-BoldItalic-webfont.ttf') format('truetype'),
- url('../fonts/OpenSans-BoldItalic-webfont.svg#OpenSansBoldItalic') format('svg');
- font-weight: bold;
- font-weight: 700;
- font-style: italic;
-
-}
-
-/* Extra Bold */
-@font-face {
- font-family: 'Open Sans';
- src: url('../fonts/OpenSans-ExtraBold-webfont.eot');
- src: url('../fonts/OpenSans-ExtraBold-webfont.eot?#iefix') format('embedded-opentype'),
- url('../fonts/OpenSans-ExtraBold-webfont.woff') format('woff'),
- url('../fonts/OpenSans-ExtraBold-webfont.ttf') format('truetype'),
- url('../fonts/OpenSans-ExtraBold-webfont.svg#OpenSansExtrabold') format('svg');
- font-weight: 900;
- font-style: normal;
-
-}
-
-/* Extra Bold Italic */
-@font-face {
- font-family: 'Open Sans';
- src: url('../fonts/OpenSans-ExtraBoldItalic-webfont.eot');
- src: url('../fonts/OpenSans-ExtraBoldItalic-webfont.eot?#iefix') format('embedded-opentype'),
- url('../fonts/OpenSans-ExtraBoldItalic-webfont.woff') format('woff'),
- url('../fonts/OpenSans-ExtraBoldItalic-webfont.ttf') format('truetype'),
- url('../fonts/OpenSans-ExtraBoldItalic-webfont.svg#OpenSansExtraboldItalic') format('svg');
- font-weight: 900;
- font-style: italic;
-
-}
-
-html {
- position: relative;
- min-height: 100%;
- margin:0;
- padding:0;
- height: 100%;
-}
-
-body {
- font-family:'Open Sans';
- background:#fff;
- font-weight: 100;
- color: #444444;
- font-size: 14px;
- margin:0;
- padding:0;
- height: 100%;
-}
-
-.container {
- position: relative;
- padding-bottom: 50px;
- min-height: 100%;
-}
-
-.wr-content {
- padding-left:0;
-}
-
-/* application top level header */
-h2.app-title {
- font-weight:500;
- font-size:17px;
- margin:0;
- padding:3px 0 0 0;
- color:#fafafa;
- text-transform: uppercase;
-}
-
-.wr-global-header {
- background:#11375B;
-}
-
-.app-logo {
- height:50px;
- padding:12px 10px;
-}
-
-.app-logo a {
- text-decoration: none;
-}
-
-.app-logo img {
- float:left;
- margin-right:10px;
-}
-
-@media (max-width: 768px) {
- .app-logo {
- padding: 16px 10px;
- }
- .app-logo img {
- width: 50px;
- height: auto;
- margin-right:10px;
- }
- h2.app-title {
- font-size: 17px;
- }
-}
-
-.wr-app-bar {
- background:#526A84;
- height:53px;
-}
-
-header {
- height:50px;
-}
-
-#nav.affix {
- position: fixed;
- top: 0;
- width: 100%;
- z-index:100000;
-}
-
-.auth-user {
- display:none;
-}
-
-.wr-auth-container {
- padding-right:0;
-}
-
-.auth-img {
- float: left;
- display:inline-block;
- height:50px;
- padding:8px 10px;
- font-size: 14px;
- color:#fff;
- text-decoration: none;
-}
-
-.auth-img:hover {
- background:#526A84;
-}
-
-.wr-auth.open .auth-img {
- background: #526A84;
-}
-
-
-/* sticky footer styles */
-.footer {
- height: 40px;
- background-color: #fff;
- padding-top:5px;
- color:#444;
- font-weight: 500;
- padding-left:20px;
- font-size:12px;
- letter-spacing: 1px;
- position:absolute;
- bottom: 0;
- margin-right: -5px;
- margin-left: -5px;
-}
-
-/* misc */
-br.c-both {
- clear:both;
-}
-
-/* dhanuka */
-/* panels */
-.panel-body {
- padding:15px !important;
-}
-
-.wr-input-control .helper {
- font-weight:100;
-}
-
-.wr-input-control .cus-col-25 {
- float:left;
- width:25%;
-}
-
-.wr-input-control .cus-col-50 {
- float:left;
- width:60%;
-}
-
-.wr-input-control .cus-col-70 {
- float:left;
- width:70%;
-}
-
-.wr-input-control .cus-col-50 input {
- width:65%;
-}
-
-.wr-input-control .cus-col-70 input {
- width:95%;
-}
-
-.wr-input-control .cus-col-25 input {
- width:65%;
-}
-
-.wr-input-control .cus-col-50 span, .wr-input-control .cus-col-25 span {
- padding-left:20px;
-}
-
-/* wizard */
-.wr-wizard {
- border-bottom:1px solid #f0f0f0;
- padding-bottom:20px;
- margin-bottom:20px;
-}
-
-.itm-wiz-current .wiz-no {
-}
-
-.itm-wiz {
- font-weight:100;
-}
-
-.itm-wiz div {
- display:inline-block;
- float:left;
-}
-
-.wiz-no {
-
-}
-
-.wiz-lbl {
- width:190px;
- font-size:17px;
- border:0px solid #ff0000;
- padding:40px 0px 0px 10px;
-
-}
-
-.wiz-lbl > span {
- padding-top:0;
- display:inline-block;
- font-size:18px;
- font-weight:300 !important;
-}
-
-
-
-
-
+@import "font-wso2.css";
+
+/* Regular */
+@font-face {
+ font-family: 'Open Sans';
+
+ src: url('../fonts/OpenSans-Regular-webfont.eot');
+ src: url('../fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'),
+ url('../fonts/OpenSans-Regular-webfont.woff') format('woff'),
+ url('../fonts/OpenSans-Regular-webfont.ttf') format('truetype'),
+ url('../fonts/OpenSans-Regular-webfont.svg#OpenSansRegular') format('svg');
+ font-weight: normal;
+ font-weight: 400;
+ font-style: normal;
+
+}
+
+/* Italic */
+@font-face {
+ font-family: 'Open Sans';
+ src: url('../fonts/OpenSans-Italic-webfont.eot');
+ src: url('../fonts/OpenSans-Italic-webfont.eot?#iefix') format('embedded-opentype'),
+ url('../fonts/OpenSans-Italic-webfont.woff') format('woff'),
+ url('../fonts/OpenSans-Italic-webfont.ttf') format('truetype'),
+ url('../fonts/OpenSans-Italic-webfont.svg#OpenSansItalic') format('svg');
+ font-weight: normal;
+ font-weight: 400;
+ font-style: italic;
+
+}
+
+/* Light */
+@font-face {
+ font-family: 'Open Sans';
+ src: url('../fonts/OpenSans-Light-webfont.eot');
+ src: url('../fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'),
+ url('../fonts/OpenSans-Light-webfont.woff') format('woff'),
+ url('../fonts/OpenSans-Light-webfont.ttf') format('truetype'),
+ url('../fonts/OpenSans-Light-webfont.svg#OpenSansLight') format('svg');
+ font-weight: 200;
+ font-style: normal;
+
+}
+
+/* Light Italic */
+@font-face {
+ font-family: 'Open Sans';
+ src: url('../fonts/OpenSans-LightItalic-webfont.eot');
+ src: url('../fonts/OpenSans-LightItalic-webfont.eot?#iefix') format('embedded-opentype'),
+ url('../fonts/OpenSans-LightItalic-webfont.woff') format('woff'),
+ url('../fonts/OpenSans-LightItalic-webfont.ttf') format('truetype'),
+ url('../fonts/OpenSans-LightItalic-webfont.svg#OpenSansLightItalic') format('svg');
+ font-weight: 200;
+ font-style: italic;
+
+}
+
+/* Semibold */
+@font-face {
+ font-family: 'Open Sans';
+ src: url('../fonts/OpenSans-Semibold-webfont.eot');
+ src: url('../fonts/OpenSans-Semibold-webfont.eot?#iefix') format('embedded-opentype'),
+ url('../fonts/OpenSans-Semibold-webfont.woff') format('woff'),
+ url('../fonts/OpenSans-Semibold-webfont.ttf') format('truetype'),
+ url('../fonts/OpenSans-Semibold-webfont.svg#OpenSansSemibold') format('svg');
+ font-weight: 500;
+ font-style: normal;
+
+}
+
+/* Semibold Italic */
+@font-face {
+ font-family: 'Open Sans';
+ src: url('../fonts/OpenSans-SemiboldItalic-webfont.eot');
+ src: url('../fonts/OpenSans-SemiboldItalic-webfont.eot?#iefix') format('embedded-opentype'),
+ url('../fonts/OpenSans-SemiboldItalic-webfont.woff') format('woff'),
+ url('../fonts/OpenSans-SemiboldItalic-webfont.ttf') format('truetype'),
+ url('../fonts/OpenSans-SemiboldItalic-webfont.svg#OpenSansSemiboldItalic') format('svg');
+ font-weight: 500;
+ font-style: italic;
+
+}
+
+/* Bold */
+@font-face {
+ font-family: 'Open Sans';
+ src: url('../fonts/OpenSans-Bold-webfont.eot');
+ src: url('../fonts/OpenSans-Bold-webfont.eot?#iefix') format('embedded-opentype'),
+ url('../fonts/OpenSans-Bold-webfont.woff') format('woff'),
+ url('../fonts/OpenSans-Bold-webfont.ttf') format('truetype'),
+ url('../fonts/OpenSans-Bold-webfont.svg#OpenSansBold') format('svg');
+ font-weight: bold;
+ font-weight: 700;
+ font-style: normal;
+
+}
+
+/* Bold Italic */
+@font-face {
+ font-family: 'Open Sans';
+ src: url('../fonts/OpenSans-BoldItalic-webfont.eot');
+ src: url('../fonts/OpenSans-BoldItalic-webfont.eot?#iefix') format('embedded-opentype'),
+ url('../fonts/OpenSans-BoldItalic-webfont.woff') format('woff'),
+ url('../fonts/OpenSans-BoldItalic-webfont.ttf') format('truetype'),
+ url('../fonts/OpenSans-BoldItalic-webfont.svg#OpenSansBoldItalic') format('svg');
+ font-weight: bold;
+ font-weight: 700;
+ font-style: italic;
+
+}
+
+/* Extra Bold */
+@font-face {
+ font-family: 'Open Sans';
+ src: url('../fonts/OpenSans-ExtraBold-webfont.eot');
+ src: url('../fonts/OpenSans-ExtraBold-webfont.eot?#iefix') format('embedded-opentype'),
+ url('../fonts/OpenSans-ExtraBold-webfont.woff') format('woff'),
+ url('../fonts/OpenSans-ExtraBold-webfont.ttf') format('truetype'),
+ url('../fonts/OpenSans-ExtraBold-webfont.svg#OpenSansExtrabold') format('svg');
+ font-weight: 900;
+ font-style: normal;
+
+}
+
+/* Extra Bold Italic */
+@font-face {
+ font-family: 'Open Sans';
+ src: url('../fonts/OpenSans-ExtraBoldItalic-webfont.eot');
+ src: url('../fonts/OpenSans-ExtraBoldItalic-webfont.eot?#iefix') format('embedded-opentype'),
+ url('../fonts/OpenSans-ExtraBoldItalic-webfont.woff') format('woff'),
+ url('../fonts/OpenSans-ExtraBoldItalic-webfont.ttf') format('truetype'),
+ url('../fonts/OpenSans-ExtraBoldItalic-webfont.svg#OpenSansExtraboldItalic') format('svg');
+ font-weight: 900;
+ font-style: italic;
+
+}
+
+html {
+ position: relative;
+ min-height: 100%;
+ margin:0;
+ padding:0;
+ height: 100%;
+}
+
+body {
+ font-family:'Open Sans';
+ background:#fff;
+ font-weight: 100;
+ color: #444444;
+ font-size: 14px;
+ margin:0;
+ padding:0;
+ height: 100%;
+}
+
+.container {
+ position: relative;
+ padding-bottom: 50px;
+ min-height: 100%;
+}
+
+.wr-content {
+ padding-left:0;
+}
+
+/* application top level header */
+h2.app-title {
+ font-weight:500;
+ font-size:17px;
+ margin:0;
+ padding:3px 0 0 0;
+ color:#fafafa;
+ text-transform: uppercase;
+}
+
+.wr-global-header {
+ background:#11375B;
+}
+
+.app-logo {
+ height:50px;
+ padding:12px 10px;
+}
+
+.app-logo a {
+ text-decoration: none;
+}
+
+.app-logo img {
+ float:left;
+ margin-right:10px;
+}
+
+@media (max-width: 768px) {
+ .app-logo {
+ padding: 16px 10px;
+ }
+ .app-logo img {
+ width: 50px;
+ height: auto;
+ margin-right:10px;
+ }
+ h2.app-title {
+ font-size: 17px;
+ }
+}
+
+.wr-app-bar {
+ background:#526A84;
+ height:53px;
+}
+
+header {
+ height:50px;
+}
+
+#nav.affix {
+ position: fixed;
+ top: 0;
+ width: 100%;
+ z-index:100000;
+}
+
+.auth-user {
+ display:none;
+}
+
+.wr-auth-container {
+ padding-right:0;
+}
+
+.auth-img {
+ float: left;
+ display:inline-block;
+ height:50px;
+ padding:8px 10px;
+ font-size: 14px;
+ color:#fff;
+ text-decoration: none;
+}
+
+.auth-img:hover {
+ background:#526A84;
+}
+
+.wr-auth.open .auth-img {
+ background: #526A84;
+}
+
+
+/* sticky footer styles */
+.footer {
+ height: 40px;
+ background-color: #fff;
+ padding-top:5px;
+ color:#444;
+ font-weight: 500;
+ padding-left:20px;
+ font-size:12px;
+ letter-spacing: 1px;
+ position:absolute;
+ bottom: 0;
+ margin-right: -5px;
+ margin-left: -5px;
+}
+
+/* misc */
+br.c-both {
+ clear:both;
+}
+
+/* dhanuka */
+/* panels */
+.panel-body {
+ padding:15px !important;
+}
+
+.wr-input-control .helper {
+ font-weight:100;
+}
+
+.wr-input-control .cus-col-25 {
+ float:left;
+ width:25%;
+}
+
+.wr-input-control .cus-col-50 {
+ float:left;
+ width:60%;
+}
+
+.wr-input-control .cus-col-70 {
+ float:left;
+ width:70%;
+}
+
+.wr-input-control .cus-col-50 input {
+ width:65%;
+}
+
+.wr-input-control .cus-col-70 input {
+ width:95%;
+}
+
+.wr-input-control .cus-col-25 input {
+ width:65%;
+}
+
+.wr-input-control .cus-col-50 span, .wr-input-control .cus-col-25 span {
+ padding-left:20px;
+}
+
+/* wizard */
+.wr-wizard {
+ border-bottom:1px solid #f0f0f0;
+ padding-bottom:20px;
+ margin-bottom:20px;
+}
+
+.itm-wiz-current .wiz-no {
+}
+
+.itm-wiz {
+ font-weight:100;
+}
+
+.itm-wiz div {
+ display:inline-block;
+ float:left;
+}
+
+.wiz-no {
+
+}
+
+.wiz-lbl {
+ width:190px;
+ font-size:17px;
+ border:0px solid #ff0000;
+ padding:40px 0px 0px 10px;
+
+}
+
+.wiz-lbl > span {
+ padding-top:0;
+ display:inline-block;
+ font-size:18px;
+ font-weight:300 !important;
+}
+
+
+
+
+
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/custom-desktop.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/custom-desktop.css
similarity index 94%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/custom-desktop.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/custom-desktop.css
index 8c21141264..a7a3f839e1 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/custom-desktop.css
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/custom-desktop.css
@@ -1,2291 +1,2291 @@
-/*
- * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
- *
- * WSO2 Inc. licenses this file to you under the Apache License,
- * Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-.wr-content {
- padding-top: 30px;
-}
-
-.wr-content-alt {
- padding-top:30px;
-}
-
-.wr-title {
- font-family: 'Open Sans';
- font-weight: 400;
- font-size: 26px;
-}
-
-@media (max-width:500px){
- .wr-content {
- padding: 0;
- }
-}
-
-.wr-asset-type-switcher {
- float:left;
- height:54px;
-}
-
-a.ctrl-asset-type-switcher {
- display:inline-block;
- padding:0;
- font-size:18px;
- color:#fff;
- text-decoration: none;
- font-weight:100;
-}
-
-a.ctrl-asset-type-switcher:hover {
- color:#fff;
-}
-
-.wr-asset-type-switcher span {
- float:left;
-}
-
-.wr-asset-type-switcher span.btn-asset {
- width:54px;
- height:54px;
- margin-right:0;
- display:inline-block;
- text-align: center;
- background: #11375B;
- line-height: 49px;
-}
-
-.wr-asset-type-switcher span.btn-asset:hover {
- background-color: #16436D;
-}
-
-.wr-asset-type-switcher span.btn-text {
- padding-top:14px;
-}
-
-a.ast-type-item {
- width:77px;
- height:77px;
- background:#696969;
- display:block;
- margin:5px;
- float:left;
- text-align: center;
- color:#e4e4e4;
- text-decoration: none;
-}
-
-a.ast-type-item:hover {
- background:#526A84;
- cursor: pointer;
-}
-
-.wr-action-container {
- padding-left:0;
-}
-
-.wr-action-btn-bar {
- padding-top:0;
-}
-
-.wr-action-btn-bar .page-title {
- background-color: #14212E;
- margin: 0;
-}
-
-.wr-action-btn-bar .page-title .fw-stack {
- width: 0;
-}
-
-.page-sub-title {
- font-weight: 300;
- text-transform: uppercase;
- font-size: 24px;
- margin: 0;
-}
-
-.page-sub-title-desc {
- font-weight: 300;
-}
-
-/* device board */
-.wr-device-board {
- background:#fafafa;
- padding:10px 0;
- font-size:20px;
- margin-bottom:10px;
-}
-
-.wr-device-board label {
- font-weight:100;
-}
-
-.lbl-device {
- font-size:14px;
- color:#777;
-}
-
-/* operations panel/board */
-.wr-operations-board {
- background:#fafafa;
- margin-bottom:10px;
-}
-
-.wr-operations-board:hover {
- background:#f0f0f0;
-}
-
-
-/* operations */
-.wr-operations {
- clear:both;
- /*margin-left:17px;*/
- margin-bottom:15px;
- border-bottom:1px solid #f0f0f0;
-}
-
-.wr-operations a {
- display:inline-block;
- float: left;
- text-align: center;
- font-size:12px;
- text-decoration: none;
- margin-right:10px;
- color:#526A84;
- min-width:70px;
- background:#fafafa;
- padding:2px 4px 6px 4px;
- margin-bottom:10px;
-}
-
-.wr-operations a:hover {
- background:#e4e4e4;
-}
-
-.wr-operations .fw {
- margin:10px;
- font-size: 28px;
-}
-
-.wr-operations span {
- display:block;
-}
-
-@media (max-width:768px){
- .wr-operations a { padding:0; min-width: inherit; margin-right:5px; }
- .wr-operations img { width: 50px; }
- .wr-operations span { display:none; }
- .wr-operations .fw { font-size: 25px; }
-}
-
-/* assets */
-
-.wr-select-all {
- clear:both;
- margin-bottom:10px;
-}
-
-.wr-btn, a.wr-btn {
- font-weight: normal;
- font-size: 13px;
- color: #fff;
- background:#11375B;
- padding: 10px 10px;
- display: inline-block;
- margin-right: 5px;
- border: none;
- text-decoration: none;
-}
-
-.wr-btn:disabled, a.wr-btn:disabled {
- opacity: 0.5;
-}
-
-.wr-btn:hover {
- background-color: #16436D;
-}
-
-.wr-btn-grp {
- margin-top: 20px;
-}
-
-.ast-container {
- clear:both;
-}
-
-.ast-device-desc {
- margin: 6px 0;
-}
-
-.ctrl-wr-asset {
- position:relative;
- width:100%;
- min-height:280px;
- float:left;
- margin: 0.5%;
- padding:10px;
- background:#fbfbfb;
- border-bottom:0px solid #fff;
-}
-
-.ast-btn-group {
- margin-top:8px;
-}
-
-@media (min-width: 500px){
- .ctrl-wr-asset { width: 49%; }
-}
-
-@media (min-width: 768px){
- .ctrl-wr-asset { width: 30%; }
-}
-
-@media (min-width: 992px){
- .ctrl-wr-asset { width: 25%; }
-}
-
-@media (min-width:1300px){
- .ctrl-wr-asset { width: 19%; }
-}
-
-@media (min-width:1500px){
- .ctrl-wr-asset { width: 17.5%; }
-}
-
-@media (min-width:1800px){
- .ctrl-wr-asset { width: 15%; }
-}
-
-.ctrl-wr-asset.selected {
- background: #E4E4E4;
- border-bottom:4px solid #526A84;
-}
-
-.ctrl-wr-asset:hover {
- background: #E4E4E4;
-}
-
-.itm-select {
- position:absolute;
- right:10px;
- background:#fafafa;
- width:20px;
- height:20px;
-}
-
-.itm-ast {
- display:block;
- cursor: pointer;
- padding:0;
- margin-bottom:0;
- width:100%;
- border:0 solid #ff0000;
-}
-
-.itm-ast a {
- text-decoration: none;
-}
-
-.itm-ast:hover h3, .itm-ast:hover .ast-auth {
- color:#526A84;
-}
-
-.ast-img {
- width: 100%;
- height: 0;
- padding-bottom: 100%;
- background: #ffffff;
-}
-
-.ast-img img {
- width:100%;
- height: auto;
-}
-
-.ast-desc {
- /*float:left;*/
- margin-left:0;
- overflow:hidden;
- position: relative;
-}
-
-.ast-desc-image img {
- width: auto;
- max-width: 100%;
- max-height: 300px;
-}
-
-.ast-desc span:before {
- content: "";
- pointer-events: none;
- position: absolute;
- width: 25px;
- height: 100%;
- top: 0;
- right: 0;
-
- background: -moz-linear-gradient(left, rgba(251,251,251,0) 0%, rgba(251,251,251,1) 100%); /* FF3.6+ */
- background: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(251,251,251,0)), color-stop(100%,rgba(251,251,251,1))); /* Chrome,Safari4+ */
- background: -webkit-linear-gradient(left, rgba(251,251,251,0) 0%,rgba(251,251,251,1) 100%); /* Chrome10+,Safari5.1+ */
- background: -o-linear-gradient(left, rgba(251,251,251,0) 0%,rgba(251,251,251,1) 100%); /* Opera 11.10+ */
- background: -ms-linear-gradient(left, rgba(251,251,251,0) 0%,rgba(251,251,251,1) 100%); /* IE10+ */
- background: linear-gradient(to right, rgba(251,251,251,0) 0%,rgba(251,251,251,1) 100%); /* W3C */
- filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00fbfbfb', endColorstr='#fbfbfb',GradientType=1 ); /* IE6-9 */
-}
-
-.ctrl-wr-asset.selected .ast-desc span:before, .ctrl-wr-asset:hover .ast-desc span:before {
- background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIxMDAlIiB5Mj0iMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2U0ZTRlNCIgc3RvcC1vcGFjaXR5PSIwIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNlNGU0ZTQiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+);
- background: -moz-linear-gradient(left, rgba(228,228,228,0) 0%, rgba(228,228,228,1) 100%); /* FF3.6+ */
- background: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(228,228,228,0)), color-stop(100%,rgba(228,228,228,1))); /* Chrome,Safari4+ */
- background: -webkit-linear-gradient(left, rgba(228,228,228,0) 0%,rgba(228,228,228,1) 100%); /* Chrome10+,Safari5.1+ */
- background: -o-linear-gradient(left, rgba(228,228,228,0) 0%,rgba(228,228,228,1) 100%); /* Opera 11.10+ */
- background: -ms-linear-gradient(left, rgba(228,228,228,0) 0%,rgba(228,228,228,1) 100%); /* IE10+ */
- background: linear-gradient(to right, rgba(228,228,228,0) 0%,rgba(228,228,228,1) 100%); /* W3C */
- filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00e4e4e4', endColorstr='#e4e4e4',GradientType=1 ); /* IE6-8 */
-}
-
-.ast-title {
- /*height: 70px;*/
- overflow: hidden;
-}
-
-h3.ast-name {
- font-weight:300;
- font-size:20px;
- color:#555;
- margin-bottom:3px;
- height: 23px;
- overflow: hidden;
-}
-
-.ast-ver {
- font-weight:300;
- font-size:13px;
- white-space: nowrap;
- word-break: keep-all;
-}
-
-.ast-auth {
- font-weight:300;
- font-size:13px;
- color:#526A84;
- display:block;
- margin-bottom:12px;
- white-space: nowrap;
- word-break: keep-all;
-}
-
-.ast-published {
- font-weight:300;
- font-size:12px;
- display:block;
- /* text-align: left; */
- color:#aaa;
- white-space: nowrap;
- word-break: keep-all;
-
-}
-
-.ast-container .lbl-action {
- display:none;
-}
-
-/* device list-view styles */
-.ast-container.list-view .itm-select {
- position: static;
- float: left;
-}
-
-.ast-container.list-view .lbl-action {
- display:inline-block;
-}
-
-.ast-container.list-view .ctrl-wr-asset {
- width: 100%;
- min-height: 50px;
- margin: 0;
-}
-
-.ast-container.list-view .itm-ast {
- display: block;
- width: auto;
-}
-
-.ast-container.list-view .ast-img {
- width: 50px;
- padding-bottom: 0;
- height: auto;
- display: inline-block;
- float: left;
- margin-left:20px;
-}
-
-.ast-container.list-view .ast-desc span:before {
- width: 0;
-}
-
-.ast-container.list-view .ast-title {
- height: inherit;
- float: left;
- margin-left: 20px;
-}
-
-.ast-container.list-view .ast-model {
- float: right;
- margin: 0 20px;
- text-align: right;
-}
-
-.ast-container.list-view h3.ast-name, .ast-container.list-view .ast-auth {
- margin: 0;
-}
-
-/* tooltip */
-.tooltip {
- opacity: 1;
- filter: alpha(opacity=100);
-}
-
-.tooltip.top .tooltip-arrow {
- bottom: 0;
- left: 50%;
- margin-left: -5px;
- border-top-color: #333;
- border-width: 5px 5px 0;
-}
-
-.tooltip-inner {
- color: #fff;
- background: #333;
- border: solid 1px #333;
- border-radius: 0px;
-}
-
-/* filter */
-a.filter-item {
- color:#e4e4e4;
- text-transform: uppercase;
- text-decoration: none;
- display:block;
- font-size:12px;
- padding:3px 0px;
- font-weight: 100;
- cursor: pointer;
-}
-
-a.filter-item:hover {
- text-decoration: none;
- color:#fff;
-}
-
-
-/* action buttons */
-.btn-col {
- padding-left: 0;
-}
-
-a.cu-btn, a.cu-btn-inner {
- color:#fff;
- text-decoration: none;
- font-weight:100;
- display: inline-block;
- text-transform: uppercase;
- height: 53px;
- padding: 13px 10px;
-}
-
-a.cu-btn:hover {
- background-color: #132D45;
-}
-
-a.cu-btn-inner {
- color: #333;
- padding: 5px 10px;
- height: 35px;
-}
-a.cu-btn-inner:hover {
- background-color:#e4e4e4;
-}
-
-/* filter */
-.wr-filters {
- padding:14px;
-}
-
-.wr-filters-right {
- padding:22px 14px 22px 0;
-}
-
-@media (max-width:1100px) {
- .wr-filters-right {
- padding: 0 14px 22px 14px;
- }
-}
-
-.wr-secondary-bar {
- border-bottom:0 solid #f0f0f0;
- padding-right:0;
-}
-
-@media (max-width:500px) {
- .wr-secondary-bar {
- padding-left:0;
- }
-}
-
-.wr-filter-sort a.ico-filter {
- display:inline-block;
- width:40px;
- height:40px;
- padding:5px;
-}
-
-.wr-filter-sort a.ico-filter .fw {
- width:30px;
- height:30px;
- line-height: 30px;
- text-align: center;
- color: #333;
- font-size: 15px;
-}
-
-.wr-filter-sort a.ico-filter .fw.fw-list-sort {
- font-size: 23px;
-}
-
-@media (max-width:1100px) {
- .wr-filters, .wr-filter-sort.pull-right {
- float: none !important;
- }
-}
-
-.wr-filter-sort a.ico-filter:hover, .wr-filter-sort a.ico-filter.selected {
- background:#e4e4e4;
-}
-
-.sort-title, .sort-options {
- padding:0 15px;
-}
-
-.sort-title {
- color:#e4e4e4;
- font-size:11px;
- padding-bottom:5px;
- padding-top:5px;
- margin-bottom:5px;
-}
-
-.sort-options > a {
- display:block;
- text-decoration: none;
- color:#cecece;
- text-transform: uppercase;
- font-size:12px;
- padding:4px 0;
- font-weight: 100;
-}
-
-span.ico-sort-asc {
- display:inline-block;
- padding-right:20px;
- width:15px;
- height:15px;
- padding-top:2px;
-}
-
-span.ico-sort-desc {
- display:inline-block;
- padding-right:20px;
- width:15px;
- height:15px;
- padding-top:2px;
-}
-
-
-/* asset filter window styles */
-.wr-asset-type-switcher .popover.menu {
- display:none;
- top: 70px;
- left: 14px !important;
- min-width: 290px;
- color: #ffffff;
- padding-bottom:0;
- z-index: 100000;
-}
-
-.wr-asset-type-switcher .popover.menu .arrow {
- left: 27px !important;
-}
-
-.wr-asset-type-switcher .popover.menu .popover-content .title {
- font-family: 'Open Sans';
- font-size: 16px;
- color:#ffffff;
- font-weight: 100;
- margin: 0 4px 4px 4px;
-}
-
-.wr-asset-type-switcher ul {
- margin: 0;
- padding: 0;
- list-style: none;
-}
-
-.wr-asset-type-switcher ul:after {
- clear: both;
- content: " ";
- height: 0;
- display: block;
-}
-
-.wr-asset-type-switcher ul li, .wr-asset-type-switcher ul a {
- display: block;
- float: left;
- margin: 4px;
- padding: 6px 4px;
- list-style: none;
- width:85px;
- height:85px;
- text-align: center;
- vertical-align: text-bottom;
- color:#e4e4e4;
- text-decoration: none;
-}
-
-.wr-asset-type-switcher ul a {
- cursor: pointer;
- width:30px;
- height:40px;
- margin:30px 0 0 10px;
- line-height: 40px;
- text-align: center;
-}
-.wr-asset-type-switcher ul a:hover {
- background-color: transparent;
- opacity: 0.6;
-}
-
-.wr-asset-type-switcher ul ul { display: none; }
-
-.wr-asset-type-switcher ul.options {
- border-top: 1px solid #333;
- margin-top:5px;
- padding:5px 0 0 0;
-}
-
-.wr-asset-type-switcher ul li:hover {
- background:#526A84;
- cursor: pointer;
-}
-
-#advance-filter-options {
- background:#444444;
- margin: 5px 4px;
- padding: 10px;
-}
-
-#advance-filter-options input {
- margin:0 5px 0 5px;
-}
-
-#device-filter-options li i.fw {
- display: block;
- font-size: 26px;
- margin: 10px 0;
-}
-
-#device-filter-options li h4 {
- margin-bottom: 0;
-}
-
-#device-filter-options li h6 {
- margin-bottom: 0;
-}
-
-#device-filter-options li span {
- float: none;
-}
-
-#asset-selected .selected {
- padding:0 0;
-}
-
-#asset-selected .selected li {
- background: #526A84;
- color: #ffffff;
-}
-
-#asset-selected .options li {
- background:#444;
-}
-
-#asset-select li {
- background:#444;
-}
-
-#asset-select li:hover, #asset-selected .options li:hover {
- background:#555;
-}
-
-/* login page styles */
-
-.wr-login {
- padding-top:50px;
-}
-
-/* form styles */
-.wr-validation-summary p {
- display: block;
- color: #ff2353 !important;
- margin-top: 15px;
- font-weight: 400 !important;
- background: #fff2f2;
- padding: 7px 17px;
- font-size: 13px !important;
- border-left: 3px solid #ff2353;
-}
-
-.wr-input-label {
- font-weight:100;
- font-size:14px;
- color:#555;
- margin-bottom:5px;
-}
-
-.wr-input-control {
- margin-bottom: 20px;
-}
-
-.wr-input-control input, .wr-input-control textarea {
- border: 1px #999 solid;
- width: 100%;
- height: 100%;
- padding: 6px 10px;
- z-index: 1;
- -webkit-appearance: none;
-}
-
-/* asset filter tags on search field styles */
-.wr-search-tags {
- display:block;
- float: left;
- min-height: 54px;
- padding:13px 5px;
- max-width: 350px;
-}
-
-/* search field styles */
-.wr-search-tags:empty {
- padding:0;
-}
-
-.wr-search-tags span {
- color: #ffffff;
- background: #11375B;
- font-size: 11px;
- display: inline-block;
- cursor: pointer;
- padding: 6px 6px;
- margin: 1px;
- border-radius: 2px;
-}
-
-.wr-search-tags span i.fw {
- display: none;
-}
-
-.wr-search-tags span:hover {
- background: #526A84;
- color: #ffffff;
-}
-
-/* search */
-.wr-search {
- margin-left:0;
- border:none;
- background:#bbb;
- min-height: 54px;
- max-width:750px !important;
- width: 100%;
-}
-
-@media (max-width:1100px) {
- .wr-search-tags:not(:empty) {
- float: none;
- padding-left:60px;
- max-width: 100%;
- }
- .wr-search {
- max-width: 100% !important;
- }
- .wr-filters.col-sm-7, .wr-filters.col-sm-7.col-md-8 {
- width: 100%;
- }
-}
-
-.wr-search .input {
- background:#bbb;
- height: 54px;
- border:none;
- color:#fff;
- font-weight: 100;
- line-height: 54px;
- padding:0 20px;
- overflow: hidden;
- font-size:18px;
- white-space: nowrap;
- word-break: keep-all;
- min-width: 200px;
-}
-
-.wr-search .input:focus {
- outline: 0;
-}
-
-[contentEditable=true]:empty:not(:focus):before{
- content:attr(data-placeholder)
-}
-
-.btn-search {
- display:block;
- font-size:21px;
- font-weight:500;
- color:#fff;
- background:#bbb;
- padding:10px 12px;
- height: 54px;
- float: right;
-}
-
-@media (max-width:500px) {
- .btn-search { display: none; }
-}
-
-.wr-search:hover .fw {
- color:#fff;
-}
-
-.wr-filters div.wr-filter-category {
- float:left;
-}
-
-.wr-filters .col-md-1, .col-md-11 {
- padding:0;
- margin: 0;
- height:54px;
-}
-
-::-webkit-input-placeholder {
- color: #fff;
-}
-
-:-moz-placeholder { /* Firefox 18- */
- color: #fff;
-}
-
-::-moz-placeholder { /* Firefox 19+ */
- color: #fff;
-}
-
-:-ms-input-placeholder {
- color: #fff;
-}
-
-.wr-operations, .wr-operations .operation {
- display: none;
-}
-
-a.btn-operations {
- font-weight: normal;
- font-size: 13px;
- color: #fff;
- background: #11375B;
- padding: 10px 10px;
- display: inline-block;
- margin-right: 2px;
- text-decoration: none;
-}
-
-/* modal pop-up styles */
-.wr-modalpopup {
- display: none;
-}
-
-.wr-modalpopup .modalpopup-container {
- display: block;
- min-height: 100px;
- width: 100%;
- position: fixed;
- background: #11375B;
- color: #fff;
- z-index: 1000001;
- align-content: center;
- top: 50%;
-}
-
-.modalpopup-content {
- position: relative;
- overflow-x: hidden;
- overflow-y: auto;
- padding: 60px;
-}
-
-.modalpopup-content h3 {
- font-weight: 300;
-}
-
-.modalpopup-content h3 .fw-stack {
- margin-right: 15px;
-}
-
-.wr-modalpopup .modalpopup-close-btn {
- color: #fff;
- z-index: 1000002;
- cursor: pointer;
- position: absolute;
- top: 30px;
- left: 40px;
- padding: 5px 8px;
- font-size: 18px;
-}
-
-.wr-modalpopup .modalpopup-close-btn:hover {
-
-}
-
-.wr-modalpopup .modalpopup-content .buttons {
- margin-top: 30px;
-}
-
-.wr-modalpopup .modalpopup-content .buttons .btn-operations {
- background: #fff;
- color: #333;
- text-transform: uppercase;
- font-weight: 500;
-}
-
-.wr-modalpopup .modalpopup-bg {
- position: fixed;
- z-index: 1000000;
- width: 100%;
- height: 100%;
- background: #000000;
- opacity: 0.9;
- display: block;
-}
-
-/* notification panel styles */
-.wr-notification-bar, .wr-side-panel {
- width: 400px;
- background: #262933;
- position: absolute;
- right: -400px;
- padding: 10px;
- z-index: 10000;
- color: #fff;
- transition: right 0.4s ease 0s;
- overflow-y: auto;
- overflow-x: hidden;
-}
-
-.wr-side-panel {
- background: #e4e4e4;
- color: #333;
- padding: 0;
-}
-
-.wr-notification-bar::-webkit-scrollbar, .wr-side-panel::-webkit-scrollbar {
- width: 6px;
- background: transparent;
- padding: 0 5px;
- cursor: all-scroll;
-}
-.wr-notification-bar::-webkit-scrollbar-thumb {
- background: #e4e4e4;
-}
-.wr-notification-bar::-webkit-scrollbar-thumb:hover {
- background: #e4e4e4;
-}
-.wr-notification-bar::-webkit-scrollbar-thumb:active {
- background: #e4e4e4;
-}
-
-.wr-side-panel::-webkit-scrollbar-thumb {
- background: #526A84;
-}
-.wr-side-panel::-webkit-scrollbar-thumb:hover {
- background: #526A84;
-}
-.wr-side-panel::-webkit-scrollbar-thumb:active {
- background: #526A84;
-}
-
-.wr-notification-bar.toggled, .wr-side-panel.toggled {
- right: 0;
-}
-
-.wr-notification-desc.new .wr-notification-operation {
- font-weight: 500;
-}
-
-.wr-notification-desc .fw {
- font-size: 12px;
-}
-
-.wr-notification-toggle-btn, .wr-side-panel-toggle-btn {
- float: right;
-}
-
-.wr-notification-bubble {
- display: inline-block;
- background: #fafafa;
- color: #555;
- padding: 2px 4px;
- border-radius: 5px;
- min-width: 10px;
- font-weight: 500;
-}
-
-a.wr-notification-toggle-btn.selected {
- background-color: #262933;
-}
-
-a.wr-side-panel-toggle-btn.selected {
- background-color: #11375B;
- color: #fff;
-}
-
-.wr-side-panel .panel-title a {
- display: block;
- padding: 10px;
- background: #11375B;
- color: #fff;
- border-bottom: 1px solid #e4e4e4;
-}
-
-.wr-side-panel .panel-title a:hover {
- background: #132D45;
-}
-
-.wr-side-panel .panel {
- margin-bottom: 0;
-}
-
-.wr-side-panel .panel-sub-title {
- margin: 10px 0;
-}
-
-.wr-side-panel .wr-input-control.switch input[type="checkbox"]:not(:checked) + .helper:after {
- background: #fff;
-}
-
-.wr-side-panel .panel-body {
- padding: 10px;
-}
-
-.wr-panel-notes textarea {
- resize: vertical;
-}
-
-.wr-panel-notes .wr-btn {
- margin-right: 5px;
-}
-
-.wr-panel-notes .wr-input-control.checkbox {
- margin: 0;
-}
-
-.wr-panel-notes .wr-input-control.checkbox .helper:before {
- border-color: #526A84;
-}
-
-.wr-panel-notes .add-btn {
- margin-bottom: 15px;
- padding-left: 0;
-}
-
-.wr-panel-notes .panel-collapse {
- padding: 10px 0 10px 35px;
-}
-
-.wr-panel-note {
- margin: 0;
-}
-
-.wr-panel-notes .well {
- margin: 5px 0;
- padding: 10px;
-}
-
-.wr-panel-note .wr-panel-msg:hover {
- cursor: pointer;
- background: #f5f5f5;
-}
-
-.wr-panel-notes .wr-panel-desc-icon i {
- width: 30px;
- height: 30px;
- display: inline-block;
- background: #333;
- color: #fff;
- text-align: center;
- margin-right: 10px;
-}
-
-.wr-panel-notes .wr-panel-desc-icon img {
- width: 30px;
- height: auto;
-}
-
-.wr-panel-notes .wr-panel-desc-icon {
- float: left;
- width: 30px;
- height: 30px;
- line-height: 30px;
- white-space: nowrap;
- margin-bottom: 5px;
-}
-
-.wr-panel-msg {
- background: #fff;
- border-right: 2px solid #526A84;
- padding: 8px 35px 8px 10px;
- margin-left: 35px;
- margin-bottom: 5px;
- font-size: 16px;
- position: relative;
-}
-
-
-.wr-panel-msg .dropdown-menu {
- background: #526A84;
- color: #fff;
- left: -167px;
- top: -2px;
-}
-
-.wr-panel-msg .dropdown-menu a {
- color: #fff;
-}
-
-.wr-panel-msg .dropdown-menu a:hover, .wr-panel-msg .dropdown-menu a:focus {
- background-color: #132D45;
- color: #fff;
-}
-
-.wr-panel-msg .msg-options {
- position: absolute;
- top: 0;
- right: 0;
- padding: 0;
- cursor: pointer;
-}
-
-.wr-panel-msg .msg-options .btn.dropdown-toggle {
- padding: 6px;
- border: none;
- color: #333;
- background: transparent;
-}
-
-.wr-panel-msg .msg-options .btn.dropdown-toggle:hover, .wr-panel-msg .msg-options .btn.dropdown-toggle[aria-expanded="true"] {
- color: #fff;
- background-color: #526A84;
-}
-
-.wr-panel-msg-visibility {
- position: absolute;
- bottom: 7px;
- right: 10px;
- font-size: 14px;
-}
-
-.wr-panel-notes .resolve-icon {
- display: none;
- position: absolute;
- bottom: 5px;
- right: 15px;
- font-size: 14px;
-}
-
-.wr-panel-notes .resolved .resolve-icon {
- display: block;
-}
-
-.wr-panel-notes .resolved .wr-panel-msg {
- border-right: none;
- background: #C7CFD0;
-}
-
-.wr-panel-notes .resolved .wr-panel-sub-note .wr-panel-msg .msg-options {
- display: none;
-}
-
-.wr-panel-sub-note .wr-panel-msg {
- background: transparent;
- margin-bottom: 5px;
- padding-top: 0;
- border-right: none;
-}
-
-.wr-panel-msg-details {
- font-size: 10px;
- color: #919191;
- margin-top: 10px;
-}
-
-.wr-panel-notes .more-link {
- display: inline-block;
- margin-bottom: 8px;
-}
-
-
-/* filter type switcher */
-#content-filter-types {
- position:absolute;
- right: -300px !important;
- float: right;
-}
-
-.wr-filter-type-switcher .popover {
- position: absolute;
- top: 0;
- left: 0;
- z-index: 1060;
- display: none;
- width: 200px;
- padding: 1px 1px 8px 1px;
- font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
- font-size: 14px;
- font-weight: 400;
- line-height: 1.42857143;
- text-align: left;
- white-space: normal;
- background-color: #232323;
- -webkit-background-clip: padding-box;
- background-clip: padding-box;
- /*border: 0px solid #232323;*/
- border: 0 solid rgba(0,0,0,.2);
- border-radius: 0;
- -webkit-box-shadow: 0 0 0 rgba(0,0,0,.2);
- box-shadow: 0 0 0 rgba(0,0,0,.2);
- margin-right: -400px !important;
-}
-
-.wr-filter-type-switcher .popover.bottom>.arrow {
- top: -11px;
- left: 50%;
- margin-left: 130px;
- border-top-width: 0;
- border-bottom-color: #232323;
-}
-
-.wr-filter-type-switcher .popover>.arrow {
- border-width: 11px;
-}
-
-.wr-filter-type-switcher .popover.bottom>.arrow:after {
- top: 1px;
- margin-left: -10px;
- content: " ";
- border-top-width: 0;
- border-bottom-color: #232323;
-}
-
-.wr-filter-type-switcher .popover>.arrow, .popover>.arrow:after {
- position: absolute;
- display: block;
- width: 0;
- height: 0;
- border-color: transparent;
- border-style: solid;
-}
-
-.wr-filter-type-switcher {
- position: relative;
-}
-
-.wr-filter-type-switcher .popover-content {
- padding: 6px 6px;
-}
-
-.wr-filter-type-switcher .arrow {
- left:25px !important;
-}
-
-.wr-filter-type-switcher .popover {
- left: -148px !important;
-}
-
-/* stats */
-.wr-stats-board-tile {
- background: #11375B;
- color: #fff;
- padding: 10px 15px;
- height: 110px;
- margin-bottom: 10px;
-}
-
-.wr-stats-board .tiles .row {
- margin: 0 -5px;
-}
-
-.wr-stats-board .tiles .col-lg-2, .wr-stats-board .tiles .col-lg-4, .wr-stats-board .tiles .col-lg-8 {
- padding: 0 5px;
-}
-
-.wr-stats-board-tile .col-lg-4, .wr-stats-board-tile .col-lg-8, .wr-stats-board .tiles .col-lg-6 {
- padding: 0;
-}
-
-.wr-stats-board-tile.lg .tile-stats {
- border-left: 1px solid #9bb6f6;
- height: 90px;
- text-align: left;
- font-size: inherit;
-}
-
-.wr-stats-board-tile.lg .tile-stats .col-lg-6 {
- padding: 0 15px;
-}
-
-.wr-stats-board-tile.lg .tile-graph {
- width:100px;
- float:right;
- text-align: right;
- margin: 0 auto;
-}
-
-.wr-stats-board-tile.lg .tile-graph img {
- width:80px;
-}
-
-.tile-bg {
- background:#11375B;
- color:#fff;
-}
-
-.tile-name {
- font-size:16px;
- font-weight: 100;
- text-transform: uppercase;
-}
-
-.tile-stats {
- width:75%;
- float:right;
- font-size:27px;
- font-weight: 400;
- text-align: right;
-}
-
-.tile-stats-sm {
- font-size:17px;
- font-weight: 700;
-}
-
-.tile-stats-free {
- font-size:13px;
- display:block;
- text-align: right;
-}
-
-.tile-stats-free a {
- color: #B4C2D0;
- text-decoration: none;
- display: inline-block;
- padding: 3px 5px 1px;
-}
-
-.tile-stats-free a:hover {
- color: #fff;
-}
-
-.tile-stats-type {
- font-size:12px;
- display:block;
-}
-
-.tile-icon {
- width:25%;
- float:left;
- margin-top: 10px;
-}
-
-.tile-icon .fw {
- font-size:40px;
-}
-
-.tile-sup-lbl {
- display: block;
- font-size: 12px;
-}
-
-
-.sub-title {
- font-weight:100;
- font-size: 20px;
-}
-
-.wr-device-board label {
- font-weight: 400;
-}
-
-.wr-app-listing > div {
- float:left;
- margin-right:10px;
- margin-bottom:10px;
-}
-
-.wr-app-listing > div > img {
- width:60px;
-}
-
-.wr-form {
- margin: 30px 0;
-}
-
-.wr-form button {
- margin-right: 5px;
-}
-
-.wr-help-tip {
- font-size: 14px;
- padding: 0 10px;
- color: #666;
-}
-
-.wr-form .wr-operation-icon {
- font-size: 32px;
- margin-right: 10px;
- color: #11375B;
-}
-
-
-/* enabled/disabled switch styles */
-.wr-input-control.switch {
- display: inline-block;
- margin-right: 10px;
- cursor: pointer;
- position: relative;
- margin-bottom: 5px;
-}
-.wr-input-control.switch > input[type=checkbox] {
- position: absolute;
- opacity: 0;
-}
-.wr-input-control.switch .helper {
- padding-left: 52px;
- position: relative;
-}
-
-.wr-input-control.switch .text {
- display: none;
- margin-left: 5px;
- font-weight: 100;
-}
-
-.wr-input-control.switch input[type="checkbox"]:checked + .helper + .text {
- display: inline-block;
-}
-
-.wr-input-control.switch .helper:before {
- position: absolute;
- left: 0;
- top: 2px;
- display: block;
- content: "";
- width: 45px;
- height: 16px;
- /*outline: 2px #a6a6a6 solid;*/
- border: 1px #fff solid;
- cursor: pointer;
- /*background: #526A84;*/
- background: #a6a6a6;
- /*margin-left: 2px;*/
- z-index: 1;
- border-radius: 8px;
-}
-.wr-input-control.switch input[type="checkbox"] + .helper:after {
- position: absolute;
- left: 22px;
- top: -2px;
- display: block;
- content: "";
- width: 24px;
- height: 24px;
- /*outline: 2px #333 solid;*/
- border: 1px #333 solid;
- cursor: pointer;
- background: #11375B;
- z-index: 2;
- border-radius: 12px;
- /*box-shadow: 0 1px 2px #888888;*/
-
- -webkit-transition: left 0.2s ease-in-out;
- -moz-transition: left 0.2s ease-in-out;
- -o-transition: left 0.2s ease-in-out;
- transition: left 0.2s ease-in-out;
-}
-.wr-input-control.switch input[type="checkbox"]:not(:checked) + .helper:after {
- left: 0 !important;
- background: #eaeaea;
- border: 1px #eaeaea solid;
-}
-
-.wr-input-control.switch input[type="checkbox"]:not(:checked) + .helper:before {
- background: #a6a6a6 !important;
-}
-.wr-input-control.switch input[type="checkbox"]:disabled + .helper:after {
- background: #a6a6a6 !important;
- outline: 2px #a6a6a6 solid !important;
- border: 1px #a6a6a6 solid !important;
-}
-.wr-input-control.switch input[type="checkbox"]:disabled + .helper:before {
- cursor: default !important;
- background: #e0e0e0 !important;
- outline: 2px #ccc solid !important;
-}
-
-/* radio button style*/
-.wr-input-control.radio {
- display: inline-block;
- margin-right: 10px;
- margin-bottom: 0;
- cursor: pointer;
- font-weight: 100;
-}
-.wr-input-control.radio > input[type=radio] {
- position: absolute;
- opacity: 0;
-}
-.wr-input-control.radio .helper {
- padding-left: 23px;
- position: relative;
-}
-.wr-input-control.radio .helper:before {
- position: absolute;
- display: block;
- height: 20px;
- width: 20px;
- content: "";
- text-indent: -9999px;
- border: 2px #d9d9d9 solid;
- z-index: 1;
- opacity: 1;
- top: 0;
- left: 0;
- border-radius: 100%;
-}
-.wr-input-control.radio input[type="radio"]:checked + .helper:after {
- position: absolute;
- display: block;
- content: "";
- color: #1a1a1a;
- z-index: 2;
- font-size: 16px;
- font-weight: bold;
- left: 5px;
- margin-left: 0;
- top: 50%;
- margin-top: -5px;
- background-color: #1a1a1a;
- width: 10px;
- height: 10px;
- border-radius: 100%;
-}
-.wr-input-control.radio.light input[type="radio"]:checked + .helper:after {
- color: #fff;
- background-color: #fff;
-}
-.wr-input-control.radio input[type="radio"]:disabled + .helper:before {
- cursor: default;
- background: #e6e6e6;
-}
-.wr-input-control.radio input[type="radio"]:disabled + .helper:after {
- background-color: #8a8a8a;
-}
-.wr-input-control.radio:hover input:not(:disabled) + .helper:before {
- border-color: #919191;
-}
-.wr-input-control.radio:active input:not(:disabled) + .helper:before {
- border-color: #919191;
-}
-
-/* checkbox style */
-.wr-input-control.checkbox {
- display: inline-block;
- margin: 0 10px 0 0;
- cursor: pointer;
-}
-.wr-input-control.checkbox > input[type=checkbox] {
- position: absolute;
- opacity: 0;
-}
-.wr-input-control.checkbox .helper {
- padding-left: 23px;
- position: relative;
-}
-.wr-input-control.checkbox .helper:before {
- position: absolute;
- display: block;
- height: 20px;
- width: 20px;
- content: "";
- text-indent: -9999px;
- border: 2px #eaf0f1 solid;
- z-index: 1;
- opacity: 1;
- top: 0;
- left: 0;
-}
-.wr-input-control.checkbox input[type="checkbox"]:checked + .helper:before {
- border: 2px #526A84 solid;
-}
-.wr-input-control.checkbox input[type="checkbox"]:checked + .helper:after {
- position: absolute;
- display: block;
- content: "\e617";
- font-size: 7pt;
- height: 16px;
- width: 16px;
- line-height: 16px;
- z-index: 2;
- top: 2px;
- margin-top: 0;
- left: 2px;
- margin-left: 0;
- text-align: center;
- background: #526A84;
- color: #fff;
- font-family: fontwso2;
-}
-.wr-input-control.checkbox input[type="checkbox"]:not(:checked) + .helper:after {
- display: none;
-}
-.wr-input-control.checkbox input[type="checkbox"]:disabled + .helper:before {
- cursor: default;
- background: #e6e6e6;
-}
-.wr-input-control.checkbox input[type=checkbox]:disabled + .helper:after {
- color: #8a8a8a;
-}
-.wr-input-control.checkbox:hover input:not(:disabled) + .helper:before {
- border-color: #526A84;
-}
-.wr-input-control.checkbox:active input:not(:disabled) + .helper:before {
- border-color: #526A84;
-}
-
-/* list group styles */
-.wr-list-group {
- margin-top: 30px;
-}
-
-.wr-list-group .list-group-item {
- padding: 0;
- position: relative;
- border: none;
- background: #f1f1f1;
- margin-bottom: 4px;
-}
-
-.wr-list-group .list-group-item-actions {
- float: right;
- margin: 0 10px;
- padding: 8px 0;
-}
-
-@media (max-width:500px) {
- .wr-list-group .list-group-item-actions:before {
- clear: both;
- content: " ";
- height: 10px;
- display: block;
- }
- .wr-list-group .list-group-item-actions {
- float: left;
- }
-}
-
-.wr-list-group .wr-list-desc {
- float: left;
- padding: 4px 8px;
- min-height: 50px;
-}
-
-.wr-list-group h3.wr-list-name {
- margin: 0;
- font-weight: 400;
- font-size: 20px;
- color: #555;
-}
-
-.wr-list-group .wr-list-username {
- font-weight: 100;
- font-size: 13px;
-}
-
-.wr-list-email, .wr-list-email:hover {
- font-weight: 300;
- font-size: 13px;
- color: #526A84;
-}
-
-.wr-sortable .list-group-item, tbody.wr-sortable td {
- cursor: move;
-}
-
-.wr-list-group .list-group-item .wr-sortable-icon, tbody.wr-sortable td .wr-sortable-icon {
- opacity: 0.5;
- float: left;
- font-size: 14px;
- margin: 15px;
-}
-
-.wr-list-group .list-group-item .wr-list-icon, tbody.wr-sortable td .fw.wr-list-icon {
- float: left;
- width: 50px;
- height: 50px;
- line-height: 42px;
- background: #526A84;
- color: #fff;
- font-size: 28px;
- text-align: center;
-}
-
-.wr-list-group .wr-sort-index {
- font-size: 18px;
- font-weight: 400;
- background: #14212E;
- color: #fff;
- width: 50px;
- height: 50px;
- margin: 0;
- line-height: 50px;
- text-align: center;
- float: left;
-}
-
-.wr-list-group .wr-desc-list-configs {
- height: 50px;
- padding: 15px;
- background: #14212E;
- color: #fff;
- text-align: center;
-}
-
-.wr-list-group .wr-desc-list-configs b {
- color: #526A84;
-}
-
-.panel-title a .fw-stack {
- font-size: 14px;
-}
-
-.panel-title a.collapsed .fw-arrow:before {
- content: "\e687";
-}
-
-.footer a {
- text-decoration: none;
-}
-
-.footer .fw {
- font-size: 21px;
-}
-
-.wr-hidden-nav {
- background: #132D45;
- margin-right: -15px;
- margin-left: -15px;
- display: none;
- color: #fff;
-}
-
-.wr-hidden-nav ul {
- list-style: none;
- margin: 0;
- padding-left: 7px;
-}
-
-.wr-hidden-nav ul li {
- list-style: none;
- display: inline-block;
- text-align: center;
- margin: 10px 3px;
- line-height: 17px;
-}
-
-.wr-hidden-nav ul li a {
- color: #fff;
- text-decoration: none;
- width: 120px;
- height: 120px;
- padding: 15px;
- background: #132D45;
- display: block;
- overflow: hidden;
-}
-
-.wr-hidden-nav ul li a:hover {
- background: #526A84;
-}
-
-.wr-hidden-nav ul li a i {
- font-size: 46px;
- display: block;
- margin-bottom: 10px;
-}
-
-.cu-btn.wr-hidden-nav-toggle-btn:hover {
- background: #D56613;
- }
-
-.cu-btn.wr-hidden-nav-toggle-btn, .cu-btn.wr-hidden-nav-toggle-btn.active:hover {
- background: #F47415;
-}
-.cu-btn.wr-hidden-nav-toggle-btn.active, .cu-btn.wr-hidden-nav-toggle-btn.active:hover {
- background: #132D45;
-}
-
-
-.wr-device-list {
- position: relative;
-}
-
-.wr-hidden-operations {
- width: 900px;
- position: absolute;
- top: 0;
- bottom: 0;
- left: -900px;
- z-index: 10000;
- -moz-transition: left 0.4s ease;
- transition: left 0.4s ease 0s;
- overflow-y: hidden;
- overflow-x: hidden;
-}
-
-.wr-advance-operations {
- height: 100%;
- background: #e4e4e4;
- border: 1px solid #e4e4e4;
-}
-
-.wr-hidden-operation {
- display: none;
-}
-
-.wr-advance-operations .row:first-child {
- height: 100%;
-}
-
-.wr-hidden-operations.toggled {
- left: 0;
-}
-
-.wr-advance-operations .wr-hidden-operations-nav a {
- display: block;
- background: #fff;
- color: #526A84;
- border-bottom: 1px solid #e4e4e4;
- padding: 10px;
- text-decoration: none;
- font-size: 16px;
-}
-
-.wr-advance-operations .wr-hidden-operations-nav a:hover {
- background: #f4f4f4;
-}
-
-.wr-advance-operations .wr-hidden-operations-nav a.selected, .wr-hidden-operations .wr-hidden-operations-nav a.selected:hover {
- color: #fff;
- background: #526A84;
-}
-
-.wr-hidden-operations-icon {
- margin-right: 10px;
-}
-
-.wr-hidden-operations-content {
- overflow-y: auto;
- overflow-x: hidden;
- height: 100%;
- background: #fff;
- border-left: 1px solid #e4e4e4;
-}
-
-.wr-hidden-operations-content::-webkit-scrollbar {
- width: 6px;
- background: transparent;
- padding: 0 5px;
- cursor: all-scroll;
-}
-.wr-hidden-operations-content::-webkit-scrollbar-thumb {
- background: #e4e4e4;
-}
-.wr-hidden-operations-content::-webkit-scrollbar-thumb:hover {
- background: #e4e4e4;
-}
-.wr-hidden-operations-content::-webkit-scrollbar-thumb:active {
- background: #e4e4e4;
-}
-
-.wr-hidden-operations-content .panel {
- margin-bottom: 0;
-}
-
-.wr-hidden-operations-content .sub-title {
- font-size: 16px;
-}
-
-.wr-hidden-operations-content .panel-title {
- padding: 5px;
- background: #e4e4e4;
- border-bottom: 1px solid #fff;
- color: #555;
-}
-
-.wr-hidden-operations-content .panel-title a {
- padding: 0;
-}
-
-.wr-hidden-operations-content .panel-title .fw-stack.collapsed .fw-down-arrow:before {
- content: "\e634";
-}
-
-.wr-hidden-operations-content .panel-title .wr-input-control.switch {
- margin-top: 8px;
- margin-right: 0;
-}
-
-.wr-hidden-operations-content .panel-title .wr-input-control.switch input[type="checkbox"]:not(:checked) + .helper:after {
- background: #fff;
-}
-
-.wr-hidden-operations-content .panel-title .wr-input-control.switch input[type="checkbox"] + .helper + .text {
- display: inline-block;
- float: left;
- margin-right: 5px;
- margin-top: -1px;
-}
-
-.wr-hidden-operations-content .panel-title .wr-input-control.switch input[type="checkbox"] + .helper + .text:after {
- content: "Disabled";
-}
-
-.wr-hidden-operations-content .panel-title .wr-input-control.switch input[type="checkbox"]:checked + .helper + .text:after {
- content: "Enabled";
-}
-
-.wr-hidden-operations-content .panel-title label {
- float: right;
-}
-
-.wr-hidden-operations-content .panel-title .fw-stack {
- width: 5px;
-}
-
-.wr-hidden-operations-content .panel-title:after {
- clear: both;
- content: " ";
- display: block;
- height: 0;
-}
-
-.wr-hidden-operations-content .panel-body {
- padding: 5px;
-}
-
-.wr-page-content {
- position: relative;
- left: 0;
- -moz-transition: left 0.4s ease;
- transition: left 0.4s ease;
-}
-
-.wr-page-content.toggled {
- left: 900px;
-}
-
-a.show-operations-btn {
- margin-bottom: 10px;
-}
-
-a.show-operations-btn.selected {
- background: #526A84;
- color: #fff;
-}
-
-a.show-operations-btn.selected .fw-right-arrow:before {
- content: "\e662";
-}
-
-a.show-operations-btn.selected .btn-text:before {
- content: "Hide ";
-}
-
-a.show-operations-btn .btn-text:before {
- content: "View All ";
-}
-
-.footer {
- left: 0;
- -moz-transition: left 0.4s ease;
- transition: left 0.4s ease;
-}
-
-.footer.wr-hidden-operations-toggled {
- left: 900px;
-}
-
-
-
-/* resource selectbox specific styles */
-.select2-results .item, .select2-selection .item {
- padding: 5px;
-}
-
-.select2-results .item:after, .select2-selection .item:after {
- clear: both;
- content: " ";
- display: block;
- height: 0;
-}
-
-.select2-results .item .text, .select2-selection .item .text {
- float: left;
-}
-
-.select2-results .item .text .resource-name, .select2-selection .item .text .resource-name {
- font-size: 16px;
- font-weight: 400;
- line-height: normal;
- }
-
-.select2-results .item .text .resource-type, .select2-selection .item .text .resource-type {
- font-size: 13px;
- line-height: normal;
-}
-
-.select2-results .item .icon, .select2-selection .item .icon {
- float: right;
- padding-top: 4px;
- text-align: center;
- width: 40px;
-}
-
-.select2-results .item .icon i, .select2-selection .item .icon i {
- font-size: 30px;
-}
-
-.select-resource.select2-selection {
- height: 60px !important;
- border-color: #E7EAED !important;
- background-color: #444 !important;
-}
-
-.select-resource .select2-selection__rendered {
- color: #fff !important;
- padding-right: 28px !important;
-}
-
-.select-resource .select2-selection__arrow b {
- border-width: 8px 7px 0 7px !important;
- border-color: #FFF transparent transparent transparent !important;
- margin-left: -15px !important;
- margin-top: 12px !important;
-}
-
-.select-resource.select2-dropdown {
- z-index: 1000;
-}
-
-.disabled-area {
- opacity: 0.5;
-}
-
-.disabled-area * {
- outline: none;
-}
-
-/* inner page title buttons */
-
-.tile-buttons-list h4 {
- font-weight: 400;
-}
-
-.tile-buttons {
- list-style: none;
- margin: 0;
- padding-left: 0;
-}
-
-.tile-buttons li {
- list-style: none;
- display: inline-block;
- text-align: center;
- line-height: 17px;
-}
-
-.tile-buttons li a {
- color: #fff;
- text-decoration: none;
- width: 100%;
- height: 120px;
- padding: 20px;
- background: #132D45;
- display: block;
- overflow: hidden;
- text-align: center;
-}
-
-.tile-buttons li a.selected,.tile-buttons li a.selected:hover {
- background: #132D45;
-}
-
-.tile-buttons li a.disabled,.tile-buttons li a.disabled:hover {
- opacity: 0.1;
- background: #132D45;
- cursor: default;
-}
-
-.tile-buttons li a:hover {
- background: #526A84;
-}
-
-.tile-buttons li a i {
- font-size: 50px;
- display: block;
- margin-bottom: 10px;
-}
-
-.wr-associations-list {
- margin-top: 10px;
-}
-
-.wr-associations-list .wr-association-icon,
-.wr-associations-list .wr-security-status,
-.wr-associations-list .wr-asset-desc,
-.wr-associations-list .wr-resource-icon,
-.wr-associations-list .wr-asset-details {
- float: left;
-}
-
-.wr-associations-list .wr-association-operations {
- float: right;
- margin-right: 10px;
- padding-top: 8px;
-}
-
-.wr-associations-list .wr-association {
- background: #f1f1f1;
- /*padding: 10px;*/
- margin-bottom: 4px;
-}
-
-.wr-associations-list .wr-asset-details {
- padding: 5px 10px;
-}
-
-.wr-associations-list .wr-resource-icon {
- font-size: 37px;
- height: 50px;
- line-height: 40px;
-}
-
-.wr-associations-list .wr-asset-desc .resource-name {
- font-weight: 500;
-}
-
-.wr-associations-list .wr-security-status {
- /*background: #97C543;*/
- background: #989898;
- color: #fff;
- height: 50px;
- line-height: 50px;
- padding: 0 10px;
- margin-right: 10px;
-}
-
-.wr-associations-list .wr-association-icon {
- width: 50px;
- height: 50px;
- vertical-align: text-top;
- line-height: 40px;
- text-align: center;
- font-size: 25px;
- background-color: #444;
- color: #fff;
-}
-
-.wr-configurations-table th {
- font-weight: 400;
- text-transform: uppercase;
- padding: 10px 2px;
-}
-
-.wr-configurations-table td {
- padding:5px 2px;
- vertical-align: text-top;
-}
-
-.panel-collapse {
- position: relative;
-}
-
-.loading {
- position: relative;
-}
-
-.loading:before {
- content: "";
- display: block;
- position: absolute;
- top: 0;
- left: 0;
- height: 100%;
- width: 100%;
- z-index: 10;
- background-color: #fff;
- opacity: 0.8;
-}
-
-.loading:after {
- content: "Background operation is running ...";
- z-index: 11;
- background: #fe8;
- color: #333;
- width: 250px;
- opacity: 0.8;
- bottom: 25px;
- display: block;
- padding: 5px 10px;
- position: absolute;
-}
-
-a.cu-btn-inner.inverse {
- background: #11375B;
- color: #fff;
-}
-a.cu-btn-inner.inverse:hover {
- background: #526A84;
-}
-
-.wiz-lbl {
-
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+.wr-content {
+ padding-top: 30px;
+}
+
+.wr-content-alt {
+ padding-top:30px;
+}
+
+.wr-title {
+ font-family: 'Open Sans';
+ font-weight: 400;
+ font-size: 26px;
+}
+
+@media (max-width:500px){
+ .wr-content {
+ padding: 0;
+ }
+}
+
+.wr-asset-type-switcher {
+ float:left;
+ height:54px;
+}
+
+a.ctrl-asset-type-switcher {
+ display:inline-block;
+ padding:0;
+ font-size:18px;
+ color:#fff;
+ text-decoration: none;
+ font-weight:100;
+}
+
+a.ctrl-asset-type-switcher:hover {
+ color:#fff;
+}
+
+.wr-asset-type-switcher span {
+ float:left;
+}
+
+.wr-asset-type-switcher span.btn-asset {
+ width:54px;
+ height:54px;
+ margin-right:0;
+ display:inline-block;
+ text-align: center;
+ background: #11375B;
+ line-height: 49px;
+}
+
+.wr-asset-type-switcher span.btn-asset:hover {
+ background-color: #16436D;
+}
+
+.wr-asset-type-switcher span.btn-text {
+ padding-top:14px;
+}
+
+a.ast-type-item {
+ width:77px;
+ height:77px;
+ background:#696969;
+ display:block;
+ margin:5px;
+ float:left;
+ text-align: center;
+ color:#e4e4e4;
+ text-decoration: none;
+}
+
+a.ast-type-item:hover {
+ background:#526A84;
+ cursor: pointer;
+}
+
+.wr-action-container {
+ padding-left:0;
+}
+
+.wr-action-btn-bar {
+ padding-top:0;
+}
+
+.wr-action-btn-bar .page-title {
+ background-color: #14212E;
+ margin: 0;
+}
+
+.wr-action-btn-bar .page-title .fw-stack {
+ width: 0;
+}
+
+.page-sub-title {
+ font-weight: 300;
+ text-transform: uppercase;
+ font-size: 24px;
+ margin: 0;
+}
+
+.page-sub-title-desc {
+ font-weight: 300;
+}
+
+/* device board */
+.wr-device-board {
+ background:#fafafa;
+ padding:10px 0;
+ font-size:20px;
+ margin-bottom:10px;
+}
+
+.wr-device-board label {
+ font-weight:100;
+}
+
+.lbl-device {
+ font-size:14px;
+ color:#777;
+}
+
+/* operations panel/board */
+.wr-operations-board {
+ background:#fafafa;
+ margin-bottom:10px;
+}
+
+.wr-operations-board:hover {
+ background:#f0f0f0;
+}
+
+
+/* operations */
+.wr-operations {
+ clear:both;
+ /*margin-left:17px;*/
+ margin-bottom:15px;
+ border-bottom:1px solid #f0f0f0;
+}
+
+.wr-operations a {
+ display:inline-block;
+ float: left;
+ text-align: center;
+ font-size:12px;
+ text-decoration: none;
+ margin-right:10px;
+ color:#526A84;
+ min-width:70px;
+ background:#fafafa;
+ padding:2px 4px 6px 4px;
+ margin-bottom:10px;
+}
+
+.wr-operations a:hover {
+ background:#e4e4e4;
+}
+
+.wr-operations .fw {
+ margin:10px;
+ font-size: 28px;
+}
+
+.wr-operations span {
+ display:block;
+}
+
+@media (max-width:768px){
+ .wr-operations a { padding:0; min-width: inherit; margin-right:5px; }
+ .wr-operations img { width: 50px; }
+ .wr-operations span { display:none; }
+ .wr-operations .fw { font-size: 25px; }
+}
+
+/* assets */
+
+.wr-select-all {
+ clear:both;
+ margin-bottom:10px;
+}
+
+.wr-btn, a.wr-btn {
+ font-weight: normal;
+ font-size: 13px;
+ color: #fff;
+ background:#11375B;
+ padding: 10px 10px;
+ display: inline-block;
+ margin-right: 5px;
+ border: none;
+ text-decoration: none;
+}
+
+.wr-btn:disabled, a.wr-btn:disabled {
+ opacity: 0.5;
+}
+
+.wr-btn:hover {
+ background-color: #16436D;
+}
+
+.wr-btn-grp {
+ margin-top: 20px;
+}
+
+.ast-container {
+ clear:both;
+}
+
+.ast-device-desc {
+ margin: 6px 0;
+}
+
+.ctrl-wr-asset {
+ position:relative;
+ width:100%;
+ min-height:280px;
+ float:left;
+ margin: 0.5%;
+ padding:10px;
+ background:#fbfbfb;
+ border-bottom:0px solid #fff;
+}
+
+.ast-btn-group {
+ margin-top:8px;
+}
+
+@media (min-width: 500px){
+ .ctrl-wr-asset { width: 49%; }
+}
+
+@media (min-width: 768px){
+ .ctrl-wr-asset { width: 30%; }
+}
+
+@media (min-width: 992px){
+ .ctrl-wr-asset { width: 25%; }
+}
+
+@media (min-width:1300px){
+ .ctrl-wr-asset { width: 19%; }
+}
+
+@media (min-width:1500px){
+ .ctrl-wr-asset { width: 17.5%; }
+}
+
+@media (min-width:1800px){
+ .ctrl-wr-asset { width: 15%; }
+}
+
+.ctrl-wr-asset.selected {
+ background: #E4E4E4;
+ border-bottom:4px solid #526A84;
+}
+
+.ctrl-wr-asset:hover {
+ background: #E4E4E4;
+}
+
+.itm-select {
+ position:absolute;
+ right:10px;
+ background:#fafafa;
+ width:20px;
+ height:20px;
+}
+
+.itm-ast {
+ display:block;
+ cursor: pointer;
+ padding:0;
+ margin-bottom:0;
+ width:100%;
+ border:0 solid #ff0000;
+}
+
+.itm-ast a {
+ text-decoration: none;
+}
+
+.itm-ast:hover h3, .itm-ast:hover .ast-auth {
+ color:#526A84;
+}
+
+.ast-img {
+ width: 100%;
+ height: 0;
+ padding-bottom: 100%;
+ background: #ffffff;
+}
+
+.ast-img img {
+ width:100%;
+ height: auto;
+}
+
+.ast-desc {
+ /*float:left;*/
+ margin-left:0;
+ overflow:hidden;
+ position: relative;
+}
+
+.ast-desc-image img {
+ width: auto;
+ max-width: 100%;
+ max-height: 300px;
+}
+
+.ast-desc span:before {
+ content: "";
+ pointer-events: none;
+ position: absolute;
+ width: 25px;
+ height: 100%;
+ top: 0;
+ right: 0;
+
+ background: -moz-linear-gradient(left, rgba(251,251,251,0) 0%, rgba(251,251,251,1) 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(251,251,251,0)), color-stop(100%,rgba(251,251,251,1))); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(left, rgba(251,251,251,0) 0%,rgba(251,251,251,1) 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(left, rgba(251,251,251,0) 0%,rgba(251,251,251,1) 100%); /* Opera 11.10+ */
+ background: -ms-linear-gradient(left, rgba(251,251,251,0) 0%,rgba(251,251,251,1) 100%); /* IE10+ */
+ background: linear-gradient(to right, rgba(251,251,251,0) 0%,rgba(251,251,251,1) 100%); /* W3C */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00fbfbfb', endColorstr='#fbfbfb',GradientType=1 ); /* IE6-9 */
+}
+
+.ctrl-wr-asset.selected .ast-desc span:before, .ctrl-wr-asset:hover .ast-desc span:before {
+ background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIxMDAlIiB5Mj0iMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2U0ZTRlNCIgc3RvcC1vcGFjaXR5PSIwIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNlNGU0ZTQiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+);
+ background: -moz-linear-gradient(left, rgba(228,228,228,0) 0%, rgba(228,228,228,1) 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(228,228,228,0)), color-stop(100%,rgba(228,228,228,1))); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(left, rgba(228,228,228,0) 0%,rgba(228,228,228,1) 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(left, rgba(228,228,228,0) 0%,rgba(228,228,228,1) 100%); /* Opera 11.10+ */
+ background: -ms-linear-gradient(left, rgba(228,228,228,0) 0%,rgba(228,228,228,1) 100%); /* IE10+ */
+ background: linear-gradient(to right, rgba(228,228,228,0) 0%,rgba(228,228,228,1) 100%); /* W3C */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00e4e4e4', endColorstr='#e4e4e4',GradientType=1 ); /* IE6-8 */
+}
+
+.ast-title {
+ /*height: 70px;*/
+ overflow: hidden;
+}
+
+h3.ast-name {
+ font-weight:300;
+ font-size:20px;
+ color:#555;
+ margin-bottom:3px;
+ height: 23px;
+ overflow: hidden;
+}
+
+.ast-ver {
+ font-weight:300;
+ font-size:13px;
+ white-space: nowrap;
+ word-break: keep-all;
+}
+
+.ast-auth {
+ font-weight:300;
+ font-size:13px;
+ color:#526A84;
+ display:block;
+ margin-bottom:12px;
+ white-space: nowrap;
+ word-break: keep-all;
+}
+
+.ast-published {
+ font-weight:300;
+ font-size:12px;
+ display:block;
+ /* text-align: left; */
+ color:#aaa;
+ white-space: nowrap;
+ word-break: keep-all;
+
+}
+
+.ast-container .lbl-action {
+ display:none;
+}
+
+/* device list-view styles */
+.ast-container.list-view .itm-select {
+ position: static;
+ float: left;
+}
+
+.ast-container.list-view .lbl-action {
+ display:inline-block;
+}
+
+.ast-container.list-view .ctrl-wr-asset {
+ width: 100%;
+ min-height: 50px;
+ margin: 0;
+}
+
+.ast-container.list-view .itm-ast {
+ display: block;
+ width: auto;
+}
+
+.ast-container.list-view .ast-img {
+ width: 50px;
+ padding-bottom: 0;
+ height: auto;
+ display: inline-block;
+ float: left;
+ margin-left:20px;
+}
+
+.ast-container.list-view .ast-desc span:before {
+ width: 0;
+}
+
+.ast-container.list-view .ast-title {
+ height: inherit;
+ float: left;
+ margin-left: 20px;
+}
+
+.ast-container.list-view .ast-model {
+ float: right;
+ margin: 0 20px;
+ text-align: right;
+}
+
+.ast-container.list-view h3.ast-name, .ast-container.list-view .ast-auth {
+ margin: 0;
+}
+
+/* tooltip */
+.tooltip {
+ opacity: 1;
+ filter: alpha(opacity=100);
+}
+
+.tooltip.top .tooltip-arrow {
+ bottom: 0;
+ left: 50%;
+ margin-left: -5px;
+ border-top-color: #333;
+ border-width: 5px 5px 0;
+}
+
+.tooltip-inner {
+ color: #fff;
+ background: #333;
+ border: solid 1px #333;
+ border-radius: 0px;
+}
+
+/* filter */
+a.filter-item {
+ color:#e4e4e4;
+ text-transform: uppercase;
+ text-decoration: none;
+ display:block;
+ font-size:12px;
+ padding:3px 0px;
+ font-weight: 100;
+ cursor: pointer;
+}
+
+a.filter-item:hover {
+ text-decoration: none;
+ color:#fff;
+}
+
+
+/* action buttons */
+.btn-col {
+ padding-left: 0;
+}
+
+a.cu-btn, a.cu-btn-inner {
+ color:#fff;
+ text-decoration: none;
+ font-weight:100;
+ display: inline-block;
+ text-transform: uppercase;
+ height: 53px;
+ padding: 13px 10px;
+}
+
+a.cu-btn:hover {
+ background-color: #132D45;
+}
+
+a.cu-btn-inner {
+ color: #333;
+ padding: 5px 10px;
+ height: 35px;
+}
+a.cu-btn-inner:hover {
+ background-color:#e4e4e4;
+}
+
+/* filter */
+.wr-filters {
+ padding:14px;
+}
+
+.wr-filters-right {
+ padding:22px 14px 22px 0;
+}
+
+@media (max-width:1100px) {
+ .wr-filters-right {
+ padding: 0 14px 22px 14px;
+ }
+}
+
+.wr-secondary-bar {
+ border-bottom:0 solid #f0f0f0;
+ padding-right:0;
+}
+
+@media (max-width:500px) {
+ .wr-secondary-bar {
+ padding-left:0;
+ }
+}
+
+.wr-filter-sort a.ico-filter {
+ display:inline-block;
+ width:40px;
+ height:40px;
+ padding:5px;
+}
+
+.wr-filter-sort a.ico-filter .fw {
+ width:30px;
+ height:30px;
+ line-height: 30px;
+ text-align: center;
+ color: #333;
+ font-size: 15px;
+}
+
+.wr-filter-sort a.ico-filter .fw.fw-list-sort {
+ font-size: 23px;
+}
+
+@media (max-width:1100px) {
+ .wr-filters, .wr-filter-sort.pull-right {
+ float: none !important;
+ }
+}
+
+.wr-filter-sort a.ico-filter:hover, .wr-filter-sort a.ico-filter.selected {
+ background:#e4e4e4;
+}
+
+.sort-title, .sort-options {
+ padding:0 15px;
+}
+
+.sort-title {
+ color:#e4e4e4;
+ font-size:11px;
+ padding-bottom:5px;
+ padding-top:5px;
+ margin-bottom:5px;
+}
+
+.sort-options > a {
+ display:block;
+ text-decoration: none;
+ color:#cecece;
+ text-transform: uppercase;
+ font-size:12px;
+ padding:4px 0;
+ font-weight: 100;
+}
+
+span.ico-sort-asc {
+ display:inline-block;
+ padding-right:20px;
+ width:15px;
+ height:15px;
+ padding-top:2px;
+}
+
+span.ico-sort-desc {
+ display:inline-block;
+ padding-right:20px;
+ width:15px;
+ height:15px;
+ padding-top:2px;
+}
+
+
+/* asset filter window styles */
+.wr-asset-type-switcher .popover.menu {
+ display:none;
+ top: 70px;
+ left: 14px !important;
+ min-width: 290px;
+ color: #ffffff;
+ padding-bottom:0;
+ z-index: 100000;
+}
+
+.wr-asset-type-switcher .popover.menu .arrow {
+ left: 27px !important;
+}
+
+.wr-asset-type-switcher .popover.menu .popover-content .title {
+ font-family: 'Open Sans';
+ font-size: 16px;
+ color:#ffffff;
+ font-weight: 100;
+ margin: 0 4px 4px 4px;
+}
+
+.wr-asset-type-switcher ul {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.wr-asset-type-switcher ul:after {
+ clear: both;
+ content: " ";
+ height: 0;
+ display: block;
+}
+
+.wr-asset-type-switcher ul li, .wr-asset-type-switcher ul a {
+ display: block;
+ float: left;
+ margin: 4px;
+ padding: 6px 4px;
+ list-style: none;
+ width:85px;
+ height:85px;
+ text-align: center;
+ vertical-align: text-bottom;
+ color:#e4e4e4;
+ text-decoration: none;
+}
+
+.wr-asset-type-switcher ul a {
+ cursor: pointer;
+ width:30px;
+ height:40px;
+ margin:30px 0 0 10px;
+ line-height: 40px;
+ text-align: center;
+}
+.wr-asset-type-switcher ul a:hover {
+ background-color: transparent;
+ opacity: 0.6;
+}
+
+.wr-asset-type-switcher ul ul { display: none; }
+
+.wr-asset-type-switcher ul.options {
+ border-top: 1px solid #333;
+ margin-top:5px;
+ padding:5px 0 0 0;
+}
+
+.wr-asset-type-switcher ul li:hover {
+ background:#526A84;
+ cursor: pointer;
+}
+
+#advance-filter-options {
+ background:#444444;
+ margin: 5px 4px;
+ padding: 10px;
+}
+
+#advance-filter-options input {
+ margin:0 5px 0 5px;
+}
+
+#device-filter-options li i.fw {
+ display: block;
+ font-size: 26px;
+ margin: 10px 0;
+}
+
+#device-filter-options li h4 {
+ margin-bottom: 0;
+}
+
+#device-filter-options li h6 {
+ margin-bottom: 0;
+}
+
+#device-filter-options li span {
+ float: none;
+}
+
+#asset-selected .selected {
+ padding:0 0;
+}
+
+#asset-selected .selected li {
+ background: #526A84;
+ color: #ffffff;
+}
+
+#asset-selected .options li {
+ background:#444;
+}
+
+#asset-select li {
+ background:#444;
+}
+
+#asset-select li:hover, #asset-selected .options li:hover {
+ background:#555;
+}
+
+/* login page styles */
+
+.wr-login {
+ padding-top:50px;
+}
+
+/* form styles */
+.wr-validation-summary p {
+ display: block;
+ color: #ff2353 !important;
+ margin-top: 15px;
+ font-weight: 400 !important;
+ background: #fff2f2;
+ padding: 7px 17px;
+ font-size: 13px !important;
+ border-left: 3px solid #ff2353;
+}
+
+.wr-input-label {
+ font-weight:100;
+ font-size:14px;
+ color:#555;
+ margin-bottom:5px;
+}
+
+.wr-input-control {
+ margin-bottom: 20px;
+}
+
+.wr-input-control input, .wr-input-control textarea {
+ border: 1px #999 solid;
+ width: 100%;
+ height: 100%;
+ padding: 6px 10px;
+ z-index: 1;
+ -webkit-appearance: none;
+}
+
+/* asset filter tags on search field styles */
+.wr-search-tags {
+ display:block;
+ float: left;
+ min-height: 54px;
+ padding:13px 5px;
+ max-width: 350px;
+}
+
+/* search field styles */
+.wr-search-tags:empty {
+ padding:0;
+}
+
+.wr-search-tags span {
+ color: #ffffff;
+ background: #11375B;
+ font-size: 11px;
+ display: inline-block;
+ cursor: pointer;
+ padding: 6px 6px;
+ margin: 1px;
+ border-radius: 2px;
+}
+
+.wr-search-tags span i.fw {
+ display: none;
+}
+
+.wr-search-tags span:hover {
+ background: #526A84;
+ color: #ffffff;
+}
+
+/* search */
+.wr-search {
+ margin-left:0;
+ border:none;
+ background:#bbb;
+ min-height: 54px;
+ max-width:750px !important;
+ width: 100%;
+}
+
+@media (max-width:1100px) {
+ .wr-search-tags:not(:empty) {
+ float: none;
+ padding-left:60px;
+ max-width: 100%;
+ }
+ .wr-search {
+ max-width: 100% !important;
+ }
+ .wr-filters.col-sm-7, .wr-filters.col-sm-7.col-md-8 {
+ width: 100%;
+ }
+}
+
+.wr-search .input {
+ background:#bbb;
+ height: 54px;
+ border:none;
+ color:#fff;
+ font-weight: 100;
+ line-height: 54px;
+ padding:0 20px;
+ overflow: hidden;
+ font-size:18px;
+ white-space: nowrap;
+ word-break: keep-all;
+ min-width: 200px;
+}
+
+.wr-search .input:focus {
+ outline: 0;
+}
+
+[contentEditable=true]:empty:not(:focus):before{
+ content:attr(data-placeholder)
+}
+
+.btn-search {
+ display:block;
+ font-size:21px;
+ font-weight:500;
+ color:#fff;
+ background:#bbb;
+ padding:10px 12px;
+ height: 54px;
+ float: right;
+}
+
+@media (max-width:500px) {
+ .btn-search { display: none; }
+}
+
+.wr-search:hover .fw {
+ color:#fff;
+}
+
+.wr-filters div.wr-filter-category {
+ float:left;
+}
+
+.wr-filters .col-md-1, .col-md-11 {
+ padding:0;
+ margin: 0;
+ height:54px;
+}
+
+::-webkit-input-placeholder {
+ color: #fff;
+}
+
+:-moz-placeholder { /* Firefox 18- */
+ color: #fff;
+}
+
+::-moz-placeholder { /* Firefox 19+ */
+ color: #fff;
+}
+
+:-ms-input-placeholder {
+ color: #fff;
+}
+
+.wr-operations, .wr-operations .operation {
+ display: none;
+}
+
+a.btn-operations {
+ font-weight: normal;
+ font-size: 13px;
+ color: #fff;
+ background: #11375B;
+ padding: 10px 10px;
+ display: inline-block;
+ margin-right: 2px;
+ text-decoration: none;
+}
+
+/* modal pop-up styles */
+.wr-modalpopup {
+ display: none;
+}
+
+.wr-modalpopup .modalpopup-container {
+ display: block;
+ min-height: 100px;
+ width: 100%;
+ position: fixed;
+ background: #11375B;
+ color: #fff;
+ z-index: 1000001;
+ align-content: center;
+ top: 50%;
+}
+
+.modalpopup-content {
+ position: relative;
+ overflow-x: hidden;
+ overflow-y: auto;
+ padding: 60px;
+}
+
+.modalpopup-content h3 {
+ font-weight: 300;
+}
+
+.modalpopup-content h3 .fw-stack {
+ margin-right: 15px;
+}
+
+.wr-modalpopup .modalpopup-close-btn {
+ color: #fff;
+ z-index: 1000002;
+ cursor: pointer;
+ position: absolute;
+ top: 30px;
+ left: 40px;
+ padding: 5px 8px;
+ font-size: 18px;
+}
+
+.wr-modalpopup .modalpopup-close-btn:hover {
+
+}
+
+.wr-modalpopup .modalpopup-content .buttons {
+ margin-top: 30px;
+}
+
+.wr-modalpopup .modalpopup-content .buttons .btn-operations {
+ background: #fff;
+ color: #333;
+ text-transform: uppercase;
+ font-weight: 500;
+}
+
+.wr-modalpopup .modalpopup-bg {
+ position: fixed;
+ z-index: 1000000;
+ width: 100%;
+ height: 100%;
+ background: #000000;
+ opacity: 0.9;
+ display: block;
+}
+
+/* notification panel styles */
+.wr-notification-bar, .wr-side-panel {
+ width: 400px;
+ background: #262933;
+ position: absolute;
+ right: -400px;
+ padding: 10px;
+ z-index: 10000;
+ color: #fff;
+ transition: right 0.4s ease 0s;
+ overflow-y: auto;
+ overflow-x: hidden;
+}
+
+.wr-side-panel {
+ background: #e4e4e4;
+ color: #333;
+ padding: 0;
+}
+
+.wr-notification-bar::-webkit-scrollbar, .wr-side-panel::-webkit-scrollbar {
+ width: 6px;
+ background: transparent;
+ padding: 0 5px;
+ cursor: all-scroll;
+}
+.wr-notification-bar::-webkit-scrollbar-thumb {
+ background: #e4e4e4;
+}
+.wr-notification-bar::-webkit-scrollbar-thumb:hover {
+ background: #e4e4e4;
+}
+.wr-notification-bar::-webkit-scrollbar-thumb:active {
+ background: #e4e4e4;
+}
+
+.wr-side-panel::-webkit-scrollbar-thumb {
+ background: #526A84;
+}
+.wr-side-panel::-webkit-scrollbar-thumb:hover {
+ background: #526A84;
+}
+.wr-side-panel::-webkit-scrollbar-thumb:active {
+ background: #526A84;
+}
+
+.wr-notification-bar.toggled, .wr-side-panel.toggled {
+ right: 0;
+}
+
+.wr-notification-desc.new .wr-notification-operation {
+ font-weight: 500;
+}
+
+.wr-notification-desc .fw {
+ font-size: 12px;
+}
+
+.wr-notification-toggle-btn, .wr-side-panel-toggle-btn {
+ float: right;
+}
+
+.wr-notification-bubble {
+ display: inline-block;
+ background: #fafafa;
+ color: #555;
+ padding: 2px 4px;
+ border-radius: 5px;
+ min-width: 10px;
+ font-weight: 500;
+}
+
+a.wr-notification-toggle-btn.selected {
+ background-color: #262933;
+}
+
+a.wr-side-panel-toggle-btn.selected {
+ background-color: #11375B;
+ color: #fff;
+}
+
+.wr-side-panel .panel-title a {
+ display: block;
+ padding: 10px;
+ background: #11375B;
+ color: #fff;
+ border-bottom: 1px solid #e4e4e4;
+}
+
+.wr-side-panel .panel-title a:hover {
+ background: #132D45;
+}
+
+.wr-side-panel .panel {
+ margin-bottom: 0;
+}
+
+.wr-side-panel .panel-sub-title {
+ margin: 10px 0;
+}
+
+.wr-side-panel .wr-input-control.switch input[type="checkbox"]:not(:checked) + .helper:after {
+ background: #fff;
+}
+
+.wr-side-panel .panel-body {
+ padding: 10px;
+}
+
+.wr-panel-notes textarea {
+ resize: vertical;
+}
+
+.wr-panel-notes .wr-btn {
+ margin-right: 5px;
+}
+
+.wr-panel-notes .wr-input-control.checkbox {
+ margin: 0;
+}
+
+.wr-panel-notes .wr-input-control.checkbox .helper:before {
+ border-color: #526A84;
+}
+
+.wr-panel-notes .add-btn {
+ margin-bottom: 15px;
+ padding-left: 0;
+}
+
+.wr-panel-notes .panel-collapse {
+ padding: 10px 0 10px 35px;
+}
+
+.wr-panel-note {
+ margin: 0;
+}
+
+.wr-panel-notes .well {
+ margin: 5px 0;
+ padding: 10px;
+}
+
+.wr-panel-note .wr-panel-msg:hover {
+ cursor: pointer;
+ background: #f5f5f5;
+}
+
+.wr-panel-notes .wr-panel-desc-icon i {
+ width: 30px;
+ height: 30px;
+ display: inline-block;
+ background: #333;
+ color: #fff;
+ text-align: center;
+ margin-right: 10px;
+}
+
+.wr-panel-notes .wr-panel-desc-icon img {
+ width: 30px;
+ height: auto;
+}
+
+.wr-panel-notes .wr-panel-desc-icon {
+ float: left;
+ width: 30px;
+ height: 30px;
+ line-height: 30px;
+ white-space: nowrap;
+ margin-bottom: 5px;
+}
+
+.wr-panel-msg {
+ background: #fff;
+ border-right: 2px solid #526A84;
+ padding: 8px 35px 8px 10px;
+ margin-left: 35px;
+ margin-bottom: 5px;
+ font-size: 16px;
+ position: relative;
+}
+
+
+.wr-panel-msg .dropdown-menu {
+ background: #526A84;
+ color: #fff;
+ left: -167px;
+ top: -2px;
+}
+
+.wr-panel-msg .dropdown-menu a {
+ color: #fff;
+}
+
+.wr-panel-msg .dropdown-menu a:hover, .wr-panel-msg .dropdown-menu a:focus {
+ background-color: #132D45;
+ color: #fff;
+}
+
+.wr-panel-msg .msg-options {
+ position: absolute;
+ top: 0;
+ right: 0;
+ padding: 0;
+ cursor: pointer;
+}
+
+.wr-panel-msg .msg-options .btn.dropdown-toggle {
+ padding: 6px;
+ border: none;
+ color: #333;
+ background: transparent;
+}
+
+.wr-panel-msg .msg-options .btn.dropdown-toggle:hover, .wr-panel-msg .msg-options .btn.dropdown-toggle[aria-expanded="true"] {
+ color: #fff;
+ background-color: #526A84;
+}
+
+.wr-panel-msg-visibility {
+ position: absolute;
+ bottom: 7px;
+ right: 10px;
+ font-size: 14px;
+}
+
+.wr-panel-notes .resolve-icon {
+ display: none;
+ position: absolute;
+ bottom: 5px;
+ right: 15px;
+ font-size: 14px;
+}
+
+.wr-panel-notes .resolved .resolve-icon {
+ display: block;
+}
+
+.wr-panel-notes .resolved .wr-panel-msg {
+ border-right: none;
+ background: #C7CFD0;
+}
+
+.wr-panel-notes .resolved .wr-panel-sub-note .wr-panel-msg .msg-options {
+ display: none;
+}
+
+.wr-panel-sub-note .wr-panel-msg {
+ background: transparent;
+ margin-bottom: 5px;
+ padding-top: 0;
+ border-right: none;
+}
+
+.wr-panel-msg-details {
+ font-size: 10px;
+ color: #919191;
+ margin-top: 10px;
+}
+
+.wr-panel-notes .more-link {
+ display: inline-block;
+ margin-bottom: 8px;
+}
+
+
+/* filter type switcher */
+#content-filter-types {
+ position:absolute;
+ right: -300px !important;
+ float: right;
+}
+
+.wr-filter-type-switcher .popover {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 1060;
+ display: none;
+ width: 200px;
+ padding: 1px 1px 8px 1px;
+ font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
+ font-size: 14px;
+ font-weight: 400;
+ line-height: 1.42857143;
+ text-align: left;
+ white-space: normal;
+ background-color: #232323;
+ -webkit-background-clip: padding-box;
+ background-clip: padding-box;
+ /*border: 0px solid #232323;*/
+ border: 0 solid rgba(0,0,0,.2);
+ border-radius: 0;
+ -webkit-box-shadow: 0 0 0 rgba(0,0,0,.2);
+ box-shadow: 0 0 0 rgba(0,0,0,.2);
+ margin-right: -400px !important;
+}
+
+.wr-filter-type-switcher .popover.bottom>.arrow {
+ top: -11px;
+ left: 50%;
+ margin-left: 130px;
+ border-top-width: 0;
+ border-bottom-color: #232323;
+}
+
+.wr-filter-type-switcher .popover>.arrow {
+ border-width: 11px;
+}
+
+.wr-filter-type-switcher .popover.bottom>.arrow:after {
+ top: 1px;
+ margin-left: -10px;
+ content: " ";
+ border-top-width: 0;
+ border-bottom-color: #232323;
+}
+
+.wr-filter-type-switcher .popover>.arrow, .popover>.arrow:after {
+ position: absolute;
+ display: block;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+}
+
+.wr-filter-type-switcher {
+ position: relative;
+}
+
+.wr-filter-type-switcher .popover-content {
+ padding: 6px 6px;
+}
+
+.wr-filter-type-switcher .arrow {
+ left:25px !important;
+}
+
+.wr-filter-type-switcher .popover {
+ left: -148px !important;
+}
+
+/* stats */
+.wr-stats-board-tile {
+ background: #11375B;
+ color: #fff;
+ padding: 10px 15px;
+ height: 110px;
+ margin-bottom: 10px;
+}
+
+.wr-stats-board .tiles .row {
+ margin: 0 -5px;
+}
+
+.wr-stats-board .tiles .col-lg-2, .wr-stats-board .tiles .col-lg-4, .wr-stats-board .tiles .col-lg-8 {
+ padding: 0 5px;
+}
+
+.wr-stats-board-tile .col-lg-4, .wr-stats-board-tile .col-lg-8, .wr-stats-board .tiles .col-lg-6 {
+ padding: 0;
+}
+
+.wr-stats-board-tile.lg .tile-stats {
+ border-left: 1px solid #9bb6f6;
+ height: 90px;
+ text-align: left;
+ font-size: inherit;
+}
+
+.wr-stats-board-tile.lg .tile-stats .col-lg-6 {
+ padding: 0 15px;
+}
+
+.wr-stats-board-tile.lg .tile-graph {
+ width:100px;
+ float:right;
+ text-align: right;
+ margin: 0 auto;
+}
+
+.wr-stats-board-tile.lg .tile-graph img {
+ width:80px;
+}
+
+.tile-bg {
+ background:#11375B;
+ color:#fff;
+}
+
+.tile-name {
+ font-size:16px;
+ font-weight: 100;
+ text-transform: uppercase;
+}
+
+.tile-stats {
+ width:75%;
+ float:right;
+ font-size:27px;
+ font-weight: 400;
+ text-align: right;
+}
+
+.tile-stats-sm {
+ font-size:17px;
+ font-weight: 700;
+}
+
+.tile-stats-free {
+ font-size:13px;
+ display:block;
+ text-align: right;
+}
+
+.tile-stats-free a {
+ color: #B4C2D0;
+ text-decoration: none;
+ display: inline-block;
+ padding: 3px 5px 1px;
+}
+
+.tile-stats-free a:hover {
+ color: #fff;
+}
+
+.tile-stats-type {
+ font-size:12px;
+ display:block;
+}
+
+.tile-icon {
+ width:25%;
+ float:left;
+ margin-top: 10px;
+}
+
+.tile-icon .fw {
+ font-size:40px;
+}
+
+.tile-sup-lbl {
+ display: block;
+ font-size: 12px;
+}
+
+
+.sub-title {
+ font-weight:100;
+ font-size: 20px;
+}
+
+.wr-device-board label {
+ font-weight: 400;
+}
+
+.wr-app-listing > div {
+ float:left;
+ margin-right:10px;
+ margin-bottom:10px;
+}
+
+.wr-app-listing > div > img {
+ width:60px;
+}
+
+.wr-form {
+ margin: 30px 0;
+}
+
+.wr-form button {
+ margin-right: 5px;
+}
+
+.wr-help-tip {
+ font-size: 14px;
+ padding: 0 10px;
+ color: #666;
+}
+
+.wr-form .wr-operation-icon {
+ font-size: 32px;
+ margin-right: 10px;
+ color: #11375B;
+}
+
+
+/* enabled/disabled switch styles */
+.wr-input-control.switch {
+ display: inline-block;
+ margin-right: 10px;
+ cursor: pointer;
+ position: relative;
+ margin-bottom: 5px;
+}
+.wr-input-control.switch > input[type=checkbox] {
+ position: absolute;
+ opacity: 0;
+}
+.wr-input-control.switch .helper {
+ padding-left: 52px;
+ position: relative;
+}
+
+.wr-input-control.switch .text {
+ display: none;
+ margin-left: 5px;
+ font-weight: 100;
+}
+
+.wr-input-control.switch input[type="checkbox"]:checked + .helper + .text {
+ display: inline-block;
+}
+
+.wr-input-control.switch .helper:before {
+ position: absolute;
+ left: 0;
+ top: 2px;
+ display: block;
+ content: "";
+ width: 45px;
+ height: 16px;
+ /*outline: 2px #a6a6a6 solid;*/
+ border: 1px #fff solid;
+ cursor: pointer;
+ /*background: #526A84;*/
+ background: #a6a6a6;
+ /*margin-left: 2px;*/
+ z-index: 1;
+ border-radius: 8px;
+}
+.wr-input-control.switch input[type="checkbox"] + .helper:after {
+ position: absolute;
+ left: 22px;
+ top: -2px;
+ display: block;
+ content: "";
+ width: 24px;
+ height: 24px;
+ /*outline: 2px #333 solid;*/
+ border: 1px #333 solid;
+ cursor: pointer;
+ background: #11375B;
+ z-index: 2;
+ border-radius: 12px;
+ /*box-shadow: 0 1px 2px #888888;*/
+
+ -webkit-transition: left 0.2s ease-in-out;
+ -moz-transition: left 0.2s ease-in-out;
+ -o-transition: left 0.2s ease-in-out;
+ transition: left 0.2s ease-in-out;
+}
+.wr-input-control.switch input[type="checkbox"]:not(:checked) + .helper:after {
+ left: 0 !important;
+ background: #eaeaea;
+ border: 1px #eaeaea solid;
+}
+
+.wr-input-control.switch input[type="checkbox"]:not(:checked) + .helper:before {
+ background: #a6a6a6 !important;
+}
+.wr-input-control.switch input[type="checkbox"]:disabled + .helper:after {
+ background: #a6a6a6 !important;
+ outline: 2px #a6a6a6 solid !important;
+ border: 1px #a6a6a6 solid !important;
+}
+.wr-input-control.switch input[type="checkbox"]:disabled + .helper:before {
+ cursor: default !important;
+ background: #e0e0e0 !important;
+ outline: 2px #ccc solid !important;
+}
+
+/* radio button style*/
+.wr-input-control.radio {
+ display: inline-block;
+ margin-right: 10px;
+ margin-bottom: 0;
+ cursor: pointer;
+ font-weight: 100;
+}
+.wr-input-control.radio > input[type=radio] {
+ position: absolute;
+ opacity: 0;
+}
+.wr-input-control.radio .helper {
+ padding-left: 23px;
+ position: relative;
+}
+.wr-input-control.radio .helper:before {
+ position: absolute;
+ display: block;
+ height: 20px;
+ width: 20px;
+ content: "";
+ text-indent: -9999px;
+ border: 2px #d9d9d9 solid;
+ z-index: 1;
+ opacity: 1;
+ top: 0;
+ left: 0;
+ border-radius: 100%;
+}
+.wr-input-control.radio input[type="radio"]:checked + .helper:after {
+ position: absolute;
+ display: block;
+ content: "";
+ color: #1a1a1a;
+ z-index: 2;
+ font-size: 16px;
+ font-weight: bold;
+ left: 5px;
+ margin-left: 0;
+ top: 50%;
+ margin-top: -5px;
+ background-color: #1a1a1a;
+ width: 10px;
+ height: 10px;
+ border-radius: 100%;
+}
+.wr-input-control.radio.light input[type="radio"]:checked + .helper:after {
+ color: #fff;
+ background-color: #fff;
+}
+.wr-input-control.radio input[type="radio"]:disabled + .helper:before {
+ cursor: default;
+ background: #e6e6e6;
+}
+.wr-input-control.radio input[type="radio"]:disabled + .helper:after {
+ background-color: #8a8a8a;
+}
+.wr-input-control.radio:hover input:not(:disabled) + .helper:before {
+ border-color: #919191;
+}
+.wr-input-control.radio:active input:not(:disabled) + .helper:before {
+ border-color: #919191;
+}
+
+/* checkbox style */
+.wr-input-control.checkbox {
+ display: inline-block;
+ margin: 0 10px 0 0;
+ cursor: pointer;
+}
+.wr-input-control.checkbox > input[type=checkbox] {
+ position: absolute;
+ opacity: 0;
+}
+.wr-input-control.checkbox .helper {
+ padding-left: 23px;
+ position: relative;
+}
+.wr-input-control.checkbox .helper:before {
+ position: absolute;
+ display: block;
+ height: 20px;
+ width: 20px;
+ content: "";
+ text-indent: -9999px;
+ border: 2px #eaf0f1 solid;
+ z-index: 1;
+ opacity: 1;
+ top: 0;
+ left: 0;
+}
+.wr-input-control.checkbox input[type="checkbox"]:checked + .helper:before {
+ border: 2px #526A84 solid;
+}
+.wr-input-control.checkbox input[type="checkbox"]:checked + .helper:after {
+ position: absolute;
+ display: block;
+ content: "\e617";
+ font-size: 7pt;
+ height: 16px;
+ width: 16px;
+ line-height: 16px;
+ z-index: 2;
+ top: 2px;
+ margin-top: 0;
+ left: 2px;
+ margin-left: 0;
+ text-align: center;
+ background: #526A84;
+ color: #fff;
+ font-family: fontwso2;
+}
+.wr-input-control.checkbox input[type="checkbox"]:not(:checked) + .helper:after {
+ display: none;
+}
+.wr-input-control.checkbox input[type="checkbox"]:disabled + .helper:before {
+ cursor: default;
+ background: #e6e6e6;
+}
+.wr-input-control.checkbox input[type=checkbox]:disabled + .helper:after {
+ color: #8a8a8a;
+}
+.wr-input-control.checkbox:hover input:not(:disabled) + .helper:before {
+ border-color: #526A84;
+}
+.wr-input-control.checkbox:active input:not(:disabled) + .helper:before {
+ border-color: #526A84;
+}
+
+/* list group styles */
+.wr-list-group {
+ margin-top: 30px;
+}
+
+.wr-list-group .list-group-item {
+ padding: 0;
+ position: relative;
+ border: none;
+ background: #f1f1f1;
+ margin-bottom: 4px;
+}
+
+.wr-list-group .list-group-item-actions {
+ float: right;
+ margin: 0 10px;
+ padding: 8px 0;
+}
+
+@media (max-width:500px) {
+ .wr-list-group .list-group-item-actions:before {
+ clear: both;
+ content: " ";
+ height: 10px;
+ display: block;
+ }
+ .wr-list-group .list-group-item-actions {
+ float: left;
+ }
+}
+
+.wr-list-group .wr-list-desc {
+ float: left;
+ padding: 4px 8px;
+ min-height: 50px;
+}
+
+.wr-list-group h3.wr-list-name {
+ margin: 0;
+ font-weight: 400;
+ font-size: 20px;
+ color: #555;
+}
+
+.wr-list-group .wr-list-username {
+ font-weight: 100;
+ font-size: 13px;
+}
+
+.wr-list-email, .wr-list-email:hover {
+ font-weight: 300;
+ font-size: 13px;
+ color: #526A84;
+}
+
+.wr-sortable .list-group-item, tbody.wr-sortable td {
+ cursor: move;
+}
+
+.wr-list-group .list-group-item .wr-sortable-icon, tbody.wr-sortable td .wr-sortable-icon {
+ opacity: 0.5;
+ float: left;
+ font-size: 14px;
+ margin: 15px;
+}
+
+.wr-list-group .list-group-item .wr-list-icon, tbody.wr-sortable td .fw.wr-list-icon {
+ float: left;
+ width: 50px;
+ height: 50px;
+ line-height: 42px;
+ background: #526A84;
+ color: #fff;
+ font-size: 28px;
+ text-align: center;
+}
+
+.wr-list-group .wr-sort-index {
+ font-size: 18px;
+ font-weight: 400;
+ background: #14212E;
+ color: #fff;
+ width: 50px;
+ height: 50px;
+ margin: 0;
+ line-height: 50px;
+ text-align: center;
+ float: left;
+}
+
+.wr-list-group .wr-desc-list-configs {
+ height: 50px;
+ padding: 15px;
+ background: #14212E;
+ color: #fff;
+ text-align: center;
+}
+
+.wr-list-group .wr-desc-list-configs b {
+ color: #526A84;
+}
+
+.panel-title a .fw-stack {
+ font-size: 14px;
+}
+
+.panel-title a.collapsed .fw-arrow:before {
+ content: "\e687";
+}
+
+.footer a {
+ text-decoration: none;
+}
+
+.footer .fw {
+ font-size: 21px;
+}
+
+.wr-hidden-nav {
+ background: #132D45;
+ margin-right: -15px;
+ margin-left: -15px;
+ display: none;
+ color: #fff;
+}
+
+.wr-hidden-nav ul {
+ list-style: none;
+ margin: 0;
+ padding-left: 7px;
+}
+
+.wr-hidden-nav ul li {
+ list-style: none;
+ display: inline-block;
+ text-align: center;
+ margin: 10px 3px;
+ line-height: 17px;
+}
+
+.wr-hidden-nav ul li a {
+ color: #fff;
+ text-decoration: none;
+ width: 120px;
+ height: 120px;
+ padding: 15px;
+ background: #132D45;
+ display: block;
+ overflow: hidden;
+}
+
+.wr-hidden-nav ul li a:hover {
+ background: #526A84;
+}
+
+.wr-hidden-nav ul li a i {
+ font-size: 46px;
+ display: block;
+ margin-bottom: 10px;
+}
+
+.cu-btn.wr-hidden-nav-toggle-btn:hover {
+ background: #D56613;
+ }
+
+.cu-btn.wr-hidden-nav-toggle-btn, .cu-btn.wr-hidden-nav-toggle-btn.active:hover {
+ background: #F47415;
+}
+.cu-btn.wr-hidden-nav-toggle-btn.active, .cu-btn.wr-hidden-nav-toggle-btn.active:hover {
+ background: #132D45;
+}
+
+
+.wr-device-list {
+ position: relative;
+}
+
+.wr-hidden-operations {
+ width: 900px;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: -900px;
+ z-index: 10000;
+ -moz-transition: left 0.4s ease;
+ transition: left 0.4s ease 0s;
+ overflow-y: hidden;
+ overflow-x: hidden;
+}
+
+.wr-advance-operations {
+ height: 100%;
+ background: #e4e4e4;
+ border: 1px solid #e4e4e4;
+}
+
+.wr-hidden-operation {
+ display: none;
+}
+
+.wr-advance-operations .row:first-child {
+ height: 100%;
+}
+
+.wr-hidden-operations.toggled {
+ left: 0;
+}
+
+.wr-advance-operations .wr-hidden-operations-nav a {
+ display: block;
+ background: #fff;
+ color: #526A84;
+ border-bottom: 1px solid #e4e4e4;
+ padding: 10px;
+ text-decoration: none;
+ font-size: 16px;
+}
+
+.wr-advance-operations .wr-hidden-operations-nav a:hover {
+ background: #f4f4f4;
+}
+
+.wr-advance-operations .wr-hidden-operations-nav a.selected, .wr-hidden-operations .wr-hidden-operations-nav a.selected:hover {
+ color: #fff;
+ background: #526A84;
+}
+
+.wr-hidden-operations-icon {
+ margin-right: 10px;
+}
+
+.wr-hidden-operations-content {
+ overflow-y: auto;
+ overflow-x: hidden;
+ height: 100%;
+ background: #fff;
+ border-left: 1px solid #e4e4e4;
+}
+
+.wr-hidden-operations-content::-webkit-scrollbar {
+ width: 6px;
+ background: transparent;
+ padding: 0 5px;
+ cursor: all-scroll;
+}
+.wr-hidden-operations-content::-webkit-scrollbar-thumb {
+ background: #e4e4e4;
+}
+.wr-hidden-operations-content::-webkit-scrollbar-thumb:hover {
+ background: #e4e4e4;
+}
+.wr-hidden-operations-content::-webkit-scrollbar-thumb:active {
+ background: #e4e4e4;
+}
+
+.wr-hidden-operations-content .panel {
+ margin-bottom: 0;
+}
+
+.wr-hidden-operations-content .sub-title {
+ font-size: 16px;
+}
+
+.wr-hidden-operations-content .panel-title {
+ padding: 5px;
+ background: #e4e4e4;
+ border-bottom: 1px solid #fff;
+ color: #555;
+}
+
+.wr-hidden-operations-content .panel-title a {
+ padding: 0;
+}
+
+.wr-hidden-operations-content .panel-title .fw-stack.collapsed .fw-down-arrow:before {
+ content: "\e634";
+}
+
+.wr-hidden-operations-content .panel-title .wr-input-control.switch {
+ margin-top: 8px;
+ margin-right: 0;
+}
+
+.wr-hidden-operations-content .panel-title .wr-input-control.switch input[type="checkbox"]:not(:checked) + .helper:after {
+ background: #fff;
+}
+
+.wr-hidden-operations-content .panel-title .wr-input-control.switch input[type="checkbox"] + .helper + .text {
+ display: inline-block;
+ float: left;
+ margin-right: 5px;
+ margin-top: -1px;
+}
+
+.wr-hidden-operations-content .panel-title .wr-input-control.switch input[type="checkbox"] + .helper + .text:after {
+ content: "Disabled";
+}
+
+.wr-hidden-operations-content .panel-title .wr-input-control.switch input[type="checkbox"]:checked + .helper + .text:after {
+ content: "Enabled";
+}
+
+.wr-hidden-operations-content .panel-title label {
+ float: right;
+}
+
+.wr-hidden-operations-content .panel-title .fw-stack {
+ width: 5px;
+}
+
+.wr-hidden-operations-content .panel-title:after {
+ clear: both;
+ content: " ";
+ display: block;
+ height: 0;
+}
+
+.wr-hidden-operations-content .panel-body {
+ padding: 5px;
+}
+
+.wr-page-content {
+ position: relative;
+ left: 0;
+ -moz-transition: left 0.4s ease;
+ transition: left 0.4s ease;
+}
+
+.wr-page-content.toggled {
+ left: 900px;
+}
+
+a.show-operations-btn {
+ margin-bottom: 10px;
+}
+
+a.show-operations-btn.selected {
+ background: #526A84;
+ color: #fff;
+}
+
+a.show-operations-btn.selected .fw-right-arrow:before {
+ content: "\e662";
+}
+
+a.show-operations-btn.selected .btn-text:before {
+ content: "Hide ";
+}
+
+a.show-operations-btn .btn-text:before {
+ content: "View All ";
+}
+
+.footer {
+ left: 0;
+ -moz-transition: left 0.4s ease;
+ transition: left 0.4s ease;
+}
+
+.footer.wr-hidden-operations-toggled {
+ left: 900px;
+}
+
+
+
+/* resource selectbox specific styles */
+.select2-results .item, .select2-selection .item {
+ padding: 5px;
+}
+
+.select2-results .item:after, .select2-selection .item:after {
+ clear: both;
+ content: " ";
+ display: block;
+ height: 0;
+}
+
+.select2-results .item .text, .select2-selection .item .text {
+ float: left;
+}
+
+.select2-results .item .text .resource-name, .select2-selection .item .text .resource-name {
+ font-size: 16px;
+ font-weight: 400;
+ line-height: normal;
+ }
+
+.select2-results .item .text .resource-type, .select2-selection .item .text .resource-type {
+ font-size: 13px;
+ line-height: normal;
+}
+
+.select2-results .item .icon, .select2-selection .item .icon {
+ float: right;
+ padding-top: 4px;
+ text-align: center;
+ width: 40px;
+}
+
+.select2-results .item .icon i, .select2-selection .item .icon i {
+ font-size: 30px;
+}
+
+.select-resource.select2-selection {
+ height: 60px !important;
+ border-color: #E7EAED !important;
+ background-color: #444 !important;
+}
+
+.select-resource .select2-selection__rendered {
+ color: #fff !important;
+ padding-right: 28px !important;
+}
+
+.select-resource .select2-selection__arrow b {
+ border-width: 8px 7px 0 7px !important;
+ border-color: #FFF transparent transparent transparent !important;
+ margin-left: -15px !important;
+ margin-top: 12px !important;
+}
+
+.select-resource.select2-dropdown {
+ z-index: 1000;
+}
+
+.disabled-area {
+ opacity: 0.5;
+}
+
+.disabled-area * {
+ outline: none;
+}
+
+/* inner page title buttons */
+
+.tile-buttons-list h4 {
+ font-weight: 400;
+}
+
+.tile-buttons {
+ list-style: none;
+ margin: 0;
+ padding-left: 0;
+}
+
+.tile-buttons li {
+ list-style: none;
+ display: inline-block;
+ text-align: center;
+ line-height: 17px;
+}
+
+.tile-buttons li a {
+ color: #fff;
+ text-decoration: none;
+ width: 100%;
+ height: 120px;
+ padding: 20px;
+ background: #132D45;
+ display: block;
+ overflow: hidden;
+ text-align: center;
+}
+
+.tile-buttons li a.selected,.tile-buttons li a.selected:hover {
+ background: #132D45;
+}
+
+.tile-buttons li a.disabled,.tile-buttons li a.disabled:hover {
+ opacity: 0.1;
+ background: #132D45;
+ cursor: default;
+}
+
+.tile-buttons li a:hover {
+ background: #526A84;
+}
+
+.tile-buttons li a i {
+ font-size: 50px;
+ display: block;
+ margin-bottom: 10px;
+}
+
+.wr-associations-list {
+ margin-top: 10px;
+}
+
+.wr-associations-list .wr-association-icon,
+.wr-associations-list .wr-security-status,
+.wr-associations-list .wr-asset-desc,
+.wr-associations-list .wr-resource-icon,
+.wr-associations-list .wr-asset-details {
+ float: left;
+}
+
+.wr-associations-list .wr-association-operations {
+ float: right;
+ margin-right: 10px;
+ padding-top: 8px;
+}
+
+.wr-associations-list .wr-association {
+ background: #f1f1f1;
+ /*padding: 10px;*/
+ margin-bottom: 4px;
+}
+
+.wr-associations-list .wr-asset-details {
+ padding: 5px 10px;
+}
+
+.wr-associations-list .wr-resource-icon {
+ font-size: 37px;
+ height: 50px;
+ line-height: 40px;
+}
+
+.wr-associations-list .wr-asset-desc .resource-name {
+ font-weight: 500;
+}
+
+.wr-associations-list .wr-security-status {
+ /*background: #97C543;*/
+ background: #989898;
+ color: #fff;
+ height: 50px;
+ line-height: 50px;
+ padding: 0 10px;
+ margin-right: 10px;
+}
+
+.wr-associations-list .wr-association-icon {
+ width: 50px;
+ height: 50px;
+ vertical-align: text-top;
+ line-height: 40px;
+ text-align: center;
+ font-size: 25px;
+ background-color: #444;
+ color: #fff;
+}
+
+.wr-configurations-table th {
+ font-weight: 400;
+ text-transform: uppercase;
+ padding: 10px 2px;
+}
+
+.wr-configurations-table td {
+ padding:5px 2px;
+ vertical-align: text-top;
+}
+
+.panel-collapse {
+ position: relative;
+}
+
+.loading {
+ position: relative;
+}
+
+.loading:before {
+ content: "";
+ display: block;
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 100%;
+ width: 100%;
+ z-index: 10;
+ background-color: #fff;
+ opacity: 0.8;
+}
+
+.loading:after {
+ content: "Background operation is running ...";
+ z-index: 11;
+ background: #fe8;
+ color: #333;
+ width: 250px;
+ opacity: 0.8;
+ bottom: 25px;
+ display: block;
+ padding: 5px 10px;
+ position: absolute;
+}
+
+a.cu-btn-inner.inverse {
+ background: #11375B;
+ color: #fff;
+}
+a.cu-btn-inner.inverse:hover {
+ background: #526A84;
+}
+
+.wiz-lbl {
+
}
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/custom-theme.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/custom-theme.css
similarity index 95%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/custom-theme.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/custom-theme.css
index 5770d72f89..a5864677c4 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/custom-theme.css
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/custom-theme.css
@@ -1,535 +1,535 @@
-body {
- overflow-x: hidden;
- -ms-overflow-x: hidden;
-}
-
-a {
- color: #526A84;
-}
-
-textarea { width: 100%; }
-
-.well {
- border-radius: 0;
- -webkit-box-shadow: none;
- box-shadow: none;
-}
-
-/* asset type switcher */
-.wr-asset-type-switcher .popover {
- position: absolute;
- top: 0;
- left: 0;
- z-index: 1060;
- display: none;
- max-width: 451px;
- padding: 1px;
- font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
- font-size: 14px;
- font-weight: 400;
- line-height: 1.42857143;
- text-align: left;
- white-space: normal;
- background-color: #232323;
- -webkit-background-clip: padding-box;
- background-clip: padding-box;
- border: 0 solid #232323;
- border: 0 solid rgba(0,0,0,.2);
- border-radius: 0;
- -webkit-box-shadow: 0 0 0 rgba(0,0,0,.2);
- box-shadow: 0 0 0 rgba(0,0,0,.2);
- padding-bottom:8px;
-}
-
-.wr-asset-type-switcher .popover.bottom>.arrow {
- top: -11px;
- left: 50%;
- margin-left: -11px;
- border-top-width: 0;
- border-bottom-color: #232323;
-}
-
-.wr-asset-type-switcher .popover>.arrow {
- border-width: 11px;
-}
-
-.wr-asset-type-switcher .popover.bottom>.arrow:after {
- top: 1px;
- margin-left: -10px;
- content: " ";
- border-top-width: 0;
- border-bottom-color: #232323;
-}
-
-.wr-asset-type-switcher .popover>.arrow, .popover>.arrow:after {
- position: absolute;
- display: block;
- width: 0;
- height: 0;
- border-color: transparent;
- border-style: solid;
-}
-
-.wr-asset-type-switcher .popover-content {
- padding: 6px 6px;
-}
-
-.wr-asset-type-switcher .arrow {
- left:25px !important;
-}
-
-.wr-asset-type-switcher .popover {
- left:10px !important;
-}
-
-
-/* sorting */
-.dropdown-menu {
- position: absolute;
- top: 40px;
- left: 0;
- z-index: 1000;
- display: none;
- float: left;
- min-width: 160px;
- padding: 5px 0;
- margin: 2px 10px 0;
- font-size: 14px;
- text-align: left;
- list-style: none;
- background-color: transparent;
- -webkit-background-clip: padding-box;
- background-clip: padding-box;
- border: 0 solid #ccc;
- border: 0 solid rgba(0,0,0,.15);
- border-radius: 0;
- -webkit-box-shadow: 0 0 0 rgba(0,0,0,.175);
- box-shadow: 0 0 0 rgba(0,0,0,.175);
-
-}
-
-.dropdown-menu-content {
- background-color: #e4e4e4;
- padding:10px 20px;
- color:#fff;
-}
-
-.dropdown-menu-content a {
- color:#333;
- cursor:pointer;
- display:block;
-}
-
-.wr-auth .cu-arrow {
- width: 0;
- height: 0;
- border-left: 8px solid transparent;
- border-right: 8px solid transparent;
- border-bottom: 8px solid #e4e4e4;
- left:87%;
- position:relative;
-}
-
-/* filter */
-.dropdown-menu {
- position: absolute;
- top: 40px;
- left: 0;
- z-index: 1000;
- display: none;
- float: left;
- min-width: 160px;
- padding: 5px 0;
- margin: 2px 5px 0;
- font-size: 14px;
- text-align: left;
- list-style: none;
- background-color: transparent;
- -webkit-background-clip: padding-box;
- background-clip: padding-box;
- border: 0 solid #ccc;
- border: 0 solid rgba(0,0,0,.15);
- border-radius: 0;
- -webkit-box-shadow: 0 0px 0px rgba(0,0,0,.175);
- box-shadow: 0 0 0 rgba(0,0,0,.175);
-
-}
-
-.dropdown-menu-content {
- background-color: #e4e4e4;
- padding:5px;
- color:#fff;
-}
-
-.dropdown-menu-content a {
- color: #11375B;
- padding: 8px 10px;
- cursor:pointer;
- display:block;
-}
-
-.dropdown-menu-content a:hover {
- color:#fff;
- background: #11375B;
-}
-
-
-/* category selection */
-a.ctrl-filter-category {
- display:inline-block;
- background:#237bd5;
- border:1px solid #237bd5;
- color:#fff;
- text-decoration:none;
- padding:7px 10px 7px 20px;
- width:230px;
- font-size:18px;
- font-weight:100;
-}
-
-a.ctrl-filter-category:hover {
- background:#666;
- color:#e4e4e4;
- text-decoration: none;
- border:1px solid #666;
-}
-
-.wr-filter-category .dropdown-menu {
- border:0px solid #237bd5;
- background:#237bd5;
- top:53px;
- left:20px;
- width:230px;
- padding-top:0;
- padding-bottom:0;
- color:#fff;
- font-size:17px;
-}
-
-.wr-filter-category .dropdown-menu li a {
- padding-top:7px;
- padding-bottom:7px;
- font-weight:100;
- color:#fff;
-}
-
-.wr-filter-category .dropdown-menu li a:hover {
- background:#61a3e6;
-}
-
-.ctrl-filter-category .glyphicon {
- font-size:13px;
- font-weight:100;
- margin-left:33px;
-}
-
-
-
-/* panel */
-.panel-group .panel {
- margin-bottom: 0;
- border-radius: 0;
-}
-
-.panel-default {
-
-}
-
-.panel {
- margin-bottom: 20px;
- background-color: transparent;
- border: 0 solid #e4e4e4;
- border-radius: 0;
- -webkit-box-shadow: 0 0 0 rgba(0, 0, 0, .05);
- box-shadow: 0 0 0 rgba(0, 0, 0, .05);
-}
-
-.panel-default > .panel-heading {
- color: #fff;
- background-color: #999;
- border-color: #e4e4e4;
-}
-
-.panel-default > .panel-heading {
- color: #fff;
- background-color: #999;
- border-color: #e4e4e4;
-}
-
-.cu-acc-head-title {
- font-weight:400;
- font-size:22px;
-}
-
-.cu-acc-head-title:hover {
- text-decoration: none;
-}
-
-.panel-title a {
- text-decoration: none;
-}
-
-.panel-heading {
- padding: 0 0 0 15px;
- border-bottom: 0 solid transparent;
- border-top-left-radius: 0;
- border-top-right-radius: 0;
-}
-
-.panel-title table, .panel-body table {
- width:100%;
-}
-
-.panel-title a {
- color:#fff;
-}
-
-.cu-acc-head-created {
- font-weight:200;
- font-size:16px;
-}
-
-.cu-acc-head-workflow {
- font-weight:200;
- font-size:16px;
-}
-
-.panel-group .panel-heading + .panel-collapse > .panel-body, .panel-group .panel-heading + .panel-collapse > .list-group {
- border-top: 0 solid #e4e4e4;
-}
-
-.panel-body {
- padding: 10px;
- background:#f9f9f9;
-}
-
-/* input */
-.form-control {
- display: block;
- width: 100%;
- height: 34px;
- padding: 6px 12px;
- font-size: 14px;
- line-height: 1.42857143;
- color: #555;
- background-color: #fff;
- background-image: none;
- border: 1px solid #999;
- border-radius: 0;
- -webkit-box-shadow: inset 0 0 0 rgba(0, 0, 0, .075);
- box-shadow: inset 0 0 0 rgba(0, 0, 0, .075);
- -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
- -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
- transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
-}
-
-.form-control:focus {
- border-color: #555;
- outline: 0;
- -webkit-box-shadow: inset 0 0 0 rgba(0,0,0,.075), 0 0 0 rgba(102, 175, 233, .6);
- box-shadow: inset 0 0 0 rgba(0,0,0,.075), 0 0 0 rgba(102, 175, 233, .6);
-}
-
-
-/* progress bar */
-.progress {
- height: 20px;
- margin-bottom: 20px;
- overflow: hidden;
- background-color: #e4e4e4;
- border-radius: 0;
- -webkit-box-shadow: inset 0 0 0 rgba(0, 0, 0, .1);
- box-shadow: inset 0 0 0 rgba(0, 0, 0, .1);
-}
-
-.progress-bar {
- background-color: #6c5c76;
-}
-
-.t-data-file {
- padding-right:20px;
-}
-
-/* tabs */
-.nav-tabs {
- border-bottom: 1px solid #6c5c76;
-}
-
-.nav-tabs > li > a {
- margin-right: 2px;
- line-height: 1.42857143;
- border: 1px solid transparent;
- border-radius: 0;
- color:#6c5c76;
-}
-
-.nav-tabs > li.active > a, .nav-tabs > li.active > a:hover, .nav-tabs > li.active > a:focus {
- color: #555;
- cursor: default;
- background-color: #fff;
- border: 1px solid #6c5c76;
- border-top:1px solid #6c5c76;
- border-bottom-color: transparent;
-}
-
-.nav-tabs > li > a:hover {
- border-color: #6c5c76 #6c5c76 #6c5c76;
-}
-.nav > li > a:hover, .nav > li > a:focus {
- text-decoration: none;
- background-color: #6c5c76;
- color:#fff;
-}
-
-/* nav pills */
-.wr-tabs-grphs .nav-pills > li.active > a, .wr-tabs-grphs .nav-pills > li.active > a:hover, .wr-tabs-grphs .nav-pills > li.active > a:focus {
- color: #fff;
- background-color: #888;
-}
-
-.wr-tabs-grphs .nav-pills > li > a {
- border-radius: 0;
-}
-
-.wr-tabs-grphs {
- border-bottom:1px solid #e4e4e4;
- padding-bottom:10px;
-}
-
-/* buttons */
-.btn-primary {
- color: #fff;
- background-color: #526A84;
- border-color: #526A84;
-}
-
-.btn-primary:hover, .btn-primary:focus, .btn-primary.focus, .btn-primary:active, .btn-primary.active, .open > .dropdown-toggle.btn-primary {
- color: #fff;
- background-color: #444;
- border-color: #444;
-}
-
-.btn {
- display: inline-block;
- padding: 6px 12px;
- margin-bottom: 0;
- font-size: 14px;
- font-weight: normal;
- line-height: 1.42857143;
- text-align: center;
- white-space: nowrap;
- vertical-align: middle;
- -ms-touch-action: manipulation;
- touch-action: manipulation;
- cursor: pointer;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- background-image: none;
- border: 1px solid transparent;
- border-radius: 0;
-}
-
-.col-centered {
- float: none;
- margin: 0 auto;
-}
-
-b, strong {
- font-weight: 500;
-}
-
-.panel-group .panel-heading + .panel-collapse > .panel-body, .panel-group .panel-heading + .panel-collapse > .list-group {
- border-top: none;
-}
-
-.panel-default > .panel-heading {
- background: transparent;
- padding: 0;
-}
-
-.panel-title a {
- color: #333333;
- padding:15px 0;
- display: inline-block;
-}
-
-.panel-body {
- background: transparent;
- padding: 0;
-}
-
-.list-group-item:first-child, .list-group-item:last-child { border-radius: 0; }
-
-.row.no-gutter {
- margin-right: 0;
- margin-left: 0;
-}
-
-.row.no-gutter [class*='col-']:not(:first-child), .row.no-gutter [class*='col-']:not(:last-child) {
- padding-right:0;
- padding-left:0;
-}
-
-select.select2 {
- height:0 !important;
- overflow: hidden;
- padding: 0;
- margin: 0;
- border: none;
- outline: none;
-}
-
-.select2-container {
- width: 100% !important;
-}
-
-.select2-container--default .select2-selection--multiple, .select2-container--default .select2-selection--single {
- border-radius: 0;
- height: 34px;
- border: 1px solid #999;
-}
-
-.select2-container .select2-search--inline .select2-search__field {
- margin-top: 0;
- padding: 0;
-}
-.select2-container--default .select2-selection--multiple .select2-selection__rendered {
- padding: 5px 8px;
-}
-
-.select2-container--default .select2-selection--single .select2-selection__rendered {
- line-height: 34px;
-}
-
-.select2-container--default .select2-selection--multiple .select2-selection__choice {
- margin-bottom: 0;
- margin-top: 0;
- color: #ffffff;
- background: #526A84;
- font-size: 11px;
- display: inline-block;
- cursor: pointer;
- padding: 3px 6px;
- border-radius: 0;
- border: none;
-}
-
-.select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
- color: #ffffff;
- font-weight: 500;
- font-size: 11px;
-}
-
-.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
- color: #ffffff;
-}
-.select2-container--default .select2-results__option--highlighted[aria-selected] {
- background-color: #526A84;
-}
-
-.select2-dropdown {
- z-index: 10000;
-}
-
+body {
+ overflow-x: hidden;
+ -ms-overflow-x: hidden;
+}
+
+a {
+ color: #526A84;
+}
+
+textarea { width: 100%; }
+
+.well {
+ border-radius: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+/* asset type switcher */
+.wr-asset-type-switcher .popover {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 1060;
+ display: none;
+ max-width: 451px;
+ padding: 1px;
+ font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
+ font-size: 14px;
+ font-weight: 400;
+ line-height: 1.42857143;
+ text-align: left;
+ white-space: normal;
+ background-color: #232323;
+ -webkit-background-clip: padding-box;
+ background-clip: padding-box;
+ border: 0 solid #232323;
+ border: 0 solid rgba(0,0,0,.2);
+ border-radius: 0;
+ -webkit-box-shadow: 0 0 0 rgba(0,0,0,.2);
+ box-shadow: 0 0 0 rgba(0,0,0,.2);
+ padding-bottom:8px;
+}
+
+.wr-asset-type-switcher .popover.bottom>.arrow {
+ top: -11px;
+ left: 50%;
+ margin-left: -11px;
+ border-top-width: 0;
+ border-bottom-color: #232323;
+}
+
+.wr-asset-type-switcher .popover>.arrow {
+ border-width: 11px;
+}
+
+.wr-asset-type-switcher .popover.bottom>.arrow:after {
+ top: 1px;
+ margin-left: -10px;
+ content: " ";
+ border-top-width: 0;
+ border-bottom-color: #232323;
+}
+
+.wr-asset-type-switcher .popover>.arrow, .popover>.arrow:after {
+ position: absolute;
+ display: block;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+}
+
+.wr-asset-type-switcher .popover-content {
+ padding: 6px 6px;
+}
+
+.wr-asset-type-switcher .arrow {
+ left:25px !important;
+}
+
+.wr-asset-type-switcher .popover {
+ left:10px !important;
+}
+
+
+/* sorting */
+.dropdown-menu {
+ position: absolute;
+ top: 40px;
+ left: 0;
+ z-index: 1000;
+ display: none;
+ float: left;
+ min-width: 160px;
+ padding: 5px 0;
+ margin: 2px 10px 0;
+ font-size: 14px;
+ text-align: left;
+ list-style: none;
+ background-color: transparent;
+ -webkit-background-clip: padding-box;
+ background-clip: padding-box;
+ border: 0 solid #ccc;
+ border: 0 solid rgba(0,0,0,.15);
+ border-radius: 0;
+ -webkit-box-shadow: 0 0 0 rgba(0,0,0,.175);
+ box-shadow: 0 0 0 rgba(0,0,0,.175);
+
+}
+
+.dropdown-menu-content {
+ background-color: #e4e4e4;
+ padding:10px 20px;
+ color:#fff;
+}
+
+.dropdown-menu-content a {
+ color:#333;
+ cursor:pointer;
+ display:block;
+}
+
+.wr-auth .cu-arrow {
+ width: 0;
+ height: 0;
+ border-left: 8px solid transparent;
+ border-right: 8px solid transparent;
+ border-bottom: 8px solid #e4e4e4;
+ left:87%;
+ position:relative;
+}
+
+/* filter */
+.dropdown-menu {
+ position: absolute;
+ top: 40px;
+ left: 0;
+ z-index: 1000;
+ display: none;
+ float: left;
+ min-width: 160px;
+ padding: 5px 0;
+ margin: 2px 5px 0;
+ font-size: 14px;
+ text-align: left;
+ list-style: none;
+ background-color: transparent;
+ -webkit-background-clip: padding-box;
+ background-clip: padding-box;
+ border: 0 solid #ccc;
+ border: 0 solid rgba(0,0,0,.15);
+ border-radius: 0;
+ -webkit-box-shadow: 0 0px 0px rgba(0,0,0,.175);
+ box-shadow: 0 0 0 rgba(0,0,0,.175);
+
+}
+
+.dropdown-menu-content {
+ background-color: #e4e4e4;
+ padding:5px;
+ color:#fff;
+}
+
+.dropdown-menu-content a {
+ color: #11375B;
+ padding: 8px 10px;
+ cursor:pointer;
+ display:block;
+}
+
+.dropdown-menu-content a:hover {
+ color:#fff;
+ background: #11375B;
+}
+
+
+/* category selection */
+a.ctrl-filter-category {
+ display:inline-block;
+ background:#237bd5;
+ border:1px solid #237bd5;
+ color:#fff;
+ text-decoration:none;
+ padding:7px 10px 7px 20px;
+ width:230px;
+ font-size:18px;
+ font-weight:100;
+}
+
+a.ctrl-filter-category:hover {
+ background:#666;
+ color:#e4e4e4;
+ text-decoration: none;
+ border:1px solid #666;
+}
+
+.wr-filter-category .dropdown-menu {
+ border:0px solid #237bd5;
+ background:#237bd5;
+ top:53px;
+ left:20px;
+ width:230px;
+ padding-top:0;
+ padding-bottom:0;
+ color:#fff;
+ font-size:17px;
+}
+
+.wr-filter-category .dropdown-menu li a {
+ padding-top:7px;
+ padding-bottom:7px;
+ font-weight:100;
+ color:#fff;
+}
+
+.wr-filter-category .dropdown-menu li a:hover {
+ background:#61a3e6;
+}
+
+.ctrl-filter-category .glyphicon {
+ font-size:13px;
+ font-weight:100;
+ margin-left:33px;
+}
+
+
+
+/* panel */
+.panel-group .panel {
+ margin-bottom: 0;
+ border-radius: 0;
+}
+
+.panel-default {
+
+}
+
+.panel {
+ margin-bottom: 20px;
+ background-color: transparent;
+ border: 0 solid #e4e4e4;
+ border-radius: 0;
+ -webkit-box-shadow: 0 0 0 rgba(0, 0, 0, .05);
+ box-shadow: 0 0 0 rgba(0, 0, 0, .05);
+}
+
+.panel-default > .panel-heading {
+ color: #fff;
+ background-color: #999;
+ border-color: #e4e4e4;
+}
+
+.panel-default > .panel-heading {
+ color: #fff;
+ background-color: #999;
+ border-color: #e4e4e4;
+}
+
+.cu-acc-head-title {
+ font-weight:400;
+ font-size:22px;
+}
+
+.cu-acc-head-title:hover {
+ text-decoration: none;
+}
+
+.panel-title a {
+ text-decoration: none;
+}
+
+.panel-heading {
+ padding: 0 0 0 15px;
+ border-bottom: 0 solid transparent;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+
+.panel-title table, .panel-body table {
+ width:100%;
+}
+
+.panel-title a {
+ color:#fff;
+}
+
+.cu-acc-head-created {
+ font-weight:200;
+ font-size:16px;
+}
+
+.cu-acc-head-workflow {
+ font-weight:200;
+ font-size:16px;
+}
+
+.panel-group .panel-heading + .panel-collapse > .panel-body, .panel-group .panel-heading + .panel-collapse > .list-group {
+ border-top: 0 solid #e4e4e4;
+}
+
+.panel-body {
+ padding: 10px;
+ background:#f9f9f9;
+}
+
+/* input */
+.form-control {
+ display: block;
+ width: 100%;
+ height: 34px;
+ padding: 6px 12px;
+ font-size: 14px;
+ line-height: 1.42857143;
+ color: #555;
+ background-color: #fff;
+ background-image: none;
+ border: 1px solid #999;
+ border-radius: 0;
+ -webkit-box-shadow: inset 0 0 0 rgba(0, 0, 0, .075);
+ box-shadow: inset 0 0 0 rgba(0, 0, 0, .075);
+ -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
+ -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+ transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+}
+
+.form-control:focus {
+ border-color: #555;
+ outline: 0;
+ -webkit-box-shadow: inset 0 0 0 rgba(0,0,0,.075), 0 0 0 rgba(102, 175, 233, .6);
+ box-shadow: inset 0 0 0 rgba(0,0,0,.075), 0 0 0 rgba(102, 175, 233, .6);
+}
+
+
+/* progress bar */
+.progress {
+ height: 20px;
+ margin-bottom: 20px;
+ overflow: hidden;
+ background-color: #e4e4e4;
+ border-radius: 0;
+ -webkit-box-shadow: inset 0 0 0 rgba(0, 0, 0, .1);
+ box-shadow: inset 0 0 0 rgba(0, 0, 0, .1);
+}
+
+.progress-bar {
+ background-color: #6c5c76;
+}
+
+.t-data-file {
+ padding-right:20px;
+}
+
+/* tabs */
+.nav-tabs {
+ border-bottom: 1px solid #6c5c76;
+}
+
+.nav-tabs > li > a {
+ margin-right: 2px;
+ line-height: 1.42857143;
+ border: 1px solid transparent;
+ border-radius: 0;
+ color:#6c5c76;
+}
+
+.nav-tabs > li.active > a, .nav-tabs > li.active > a:hover, .nav-tabs > li.active > a:focus {
+ color: #555;
+ cursor: default;
+ background-color: #fff;
+ border: 1px solid #6c5c76;
+ border-top:1px solid #6c5c76;
+ border-bottom-color: transparent;
+}
+
+.nav-tabs > li > a:hover {
+ border-color: #6c5c76 #6c5c76 #6c5c76;
+}
+.nav > li > a:hover, .nav > li > a:focus {
+ text-decoration: none;
+ background-color: #6c5c76;
+ color:#fff;
+}
+
+/* nav pills */
+.wr-tabs-grphs .nav-pills > li.active > a, .wr-tabs-grphs .nav-pills > li.active > a:hover, .wr-tabs-grphs .nav-pills > li.active > a:focus {
+ color: #fff;
+ background-color: #888;
+}
+
+.wr-tabs-grphs .nav-pills > li > a {
+ border-radius: 0;
+}
+
+.wr-tabs-grphs {
+ border-bottom:1px solid #e4e4e4;
+ padding-bottom:10px;
+}
+
+/* buttons */
+.btn-primary {
+ color: #fff;
+ background-color: #526A84;
+ border-color: #526A84;
+}
+
+.btn-primary:hover, .btn-primary:focus, .btn-primary.focus, .btn-primary:active, .btn-primary.active, .open > .dropdown-toggle.btn-primary {
+ color: #fff;
+ background-color: #444;
+ border-color: #444;
+}
+
+.btn {
+ display: inline-block;
+ padding: 6px 12px;
+ margin-bottom: 0;
+ font-size: 14px;
+ font-weight: normal;
+ line-height: 1.42857143;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: middle;
+ -ms-touch-action: manipulation;
+ touch-action: manipulation;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ background-image: none;
+ border: 1px solid transparent;
+ border-radius: 0;
+}
+
+.col-centered {
+ float: none;
+ margin: 0 auto;
+}
+
+b, strong {
+ font-weight: 500;
+}
+
+.panel-group .panel-heading + .panel-collapse > .panel-body, .panel-group .panel-heading + .panel-collapse > .list-group {
+ border-top: none;
+}
+
+.panel-default > .panel-heading {
+ background: transparent;
+ padding: 0;
+}
+
+.panel-title a {
+ color: #333333;
+ padding:15px 0;
+ display: inline-block;
+}
+
+.panel-body {
+ background: transparent;
+ padding: 0;
+}
+
+.list-group-item:first-child, .list-group-item:last-child { border-radius: 0; }
+
+.row.no-gutter {
+ margin-right: 0;
+ margin-left: 0;
+}
+
+.row.no-gutter [class*='col-']:not(:first-child), .row.no-gutter [class*='col-']:not(:last-child) {
+ padding-right:0;
+ padding-left:0;
+}
+
+select.select2 {
+ height:0 !important;
+ overflow: hidden;
+ padding: 0;
+ margin: 0;
+ border: none;
+ outline: none;
+}
+
+.select2-container {
+ width: 100% !important;
+}
+
+.select2-container--default .select2-selection--multiple, .select2-container--default .select2-selection--single {
+ border-radius: 0;
+ height: 34px;
+ border: 1px solid #999;
+}
+
+.select2-container .select2-search--inline .select2-search__field {
+ margin-top: 0;
+ padding: 0;
+}
+.select2-container--default .select2-selection--multiple .select2-selection__rendered {
+ padding: 5px 8px;
+}
+
+.select2-container--default .select2-selection--single .select2-selection__rendered {
+ line-height: 34px;
+}
+
+.select2-container--default .select2-selection--multiple .select2-selection__choice {
+ margin-bottom: 0;
+ margin-top: 0;
+ color: #ffffff;
+ background: #526A84;
+ font-size: 11px;
+ display: inline-block;
+ cursor: pointer;
+ padding: 3px 6px;
+ border-radius: 0;
+ border: none;
+}
+
+.select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
+ color: #ffffff;
+ font-weight: 500;
+ font-size: 11px;
+}
+
+.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
+ color: #ffffff;
+}
+.select2-container--default .select2-results__option--highlighted[aria-selected] {
+ background-color: #526A84;
+}
+
+.select2-dropdown {
+ z-index: 10000;
+}
+
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/customx-theme.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/customx-theme.css
similarity index 96%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/customx-theme.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/customx-theme.css
index b848637ed4..a425603213 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/customx-theme.css
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/customx-theme.css
@@ -1,74 +1,74 @@
-.navbar-default {
- background-color: #2a2a2a;
- border-color:#2a2a2a ;
-}
-.navbar-nav{color: #a5a5a5; font-weight:300; padding-top: 5px; padding-left:0px;}
-.form-control {background-color: #121212; border: 0px;}
-.btn-default {background-color: #121212; border: 1px solid #121212;}
-.container { padding:0px;}
-.container-fluid{padding-left:0px;}
-.navbar-default .navbar-nav > li > a {color: #a5a5a5; font-size: 14px; font-weight: 500;}
-.navbar-form .input-group > .form-control { height: 39px; margin-top: 0; }
-.input-group-btn:last-child > .btn, .input-group-btn:last-child > .btn-group { height: 39px;}
-.container-bg{background-image: url("../images/content-bg.png"); background-repeat: no-repeat; background-position: top left; min-height: 550px; overflow: hidden; padding: 0 15px;}
-.navbar-default .navbar-nav > li > a :focus,.navbar-default .navbar-nav>li>a:hover{color:#ccc;background-color:transparent;}
-.btn-default.active,
-.btn-default.focus,
-.btn-default:active,
-.btn-default:focus,
-.btn-default:hover,
-.open>.dropdown-toggle.btn-default {
- color: #ccc;
- background-color: #121212;
- border-color: #121212;
-}
-input {
- background-color: #333;
- border: 1px solid #2a2a2a;
- border-radius: 3px;
- height: 45px;
- margin: 5px 0;
- width: 100%;
- padding-left: 10px;
-}
-input[type="checkbox"], input[type="radio"] {
- line-height: normal;
- margin-top: -3px;
- width: 30px;
-}
-.navbar-default .navbar-nav>li>a:focus,
-.navbar-default .navbar-nav>li>a:hover {
- color: #747474;
- outline: 0;
-}
-.navbar {
- margin-bottom: 5px;
-}
-.navbar-brand {
- padding: 15px 10px;
-}
-.navbar-default .navbar-nav > .open > a, .navbar-default .navbar-nav > .open > a:focus, .navbar-default .navbar-nav > .open > a:hover {
- color: #fff;
- background-color:#202020 ;
-}
-.dropdown-menu {
- background-clip: padding-box;
- background-color: #202020;
- border: 0px solid rgba(0, 0, 0, 0.15);
- border-radius: 0;
- box-shadow: none;
- display: none;
- float: left;
- font-size: 14px;
- left: 0;
- color: #a5a5a5;
-}
-.dropdown-menu > li > a {
- color: #a5a5a5;
-}
-.dropdown-menu>li>a:focus,
-.dropdown-menu>li>a:hover {
- color: #fff;
- text-decoration: none;
- background-color: #313131;
+.navbar-default {
+ background-color: #2a2a2a;
+ border-color:#2a2a2a ;
+}
+.navbar-nav{color: #a5a5a5; font-weight:300; padding-top: 5px; padding-left:0px;}
+.form-control {background-color: #121212; border: 0px;}
+.btn-default {background-color: #121212; border: 1px solid #121212;}
+.container { padding:0px;}
+.container-fluid{padding-left:0px;}
+.navbar-default .navbar-nav > li > a {color: #a5a5a5; font-size: 14px; font-weight: 500;}
+.navbar-form .input-group > .form-control { height: 39px; margin-top: 0; }
+.input-group-btn:last-child > .btn, .input-group-btn:last-child > .btn-group { height: 39px;}
+.container-bg{background-image: url("../images/content-bg.png"); background-repeat: no-repeat; background-position: top left; min-height: 550px; overflow: hidden; padding: 0 15px;}
+.navbar-default .navbar-nav > li > a :focus,.navbar-default .navbar-nav>li>a:hover{color:#ccc;background-color:transparent;}
+.btn-default.active,
+.btn-default.focus,
+.btn-default:active,
+.btn-default:focus,
+.btn-default:hover,
+.open>.dropdown-toggle.btn-default {
+ color: #ccc;
+ background-color: #121212;
+ border-color: #121212;
+}
+input {
+ background-color: #333;
+ border: 1px solid #2a2a2a;
+ border-radius: 3px;
+ height: 45px;
+ margin: 5px 0;
+ width: 100%;
+ padding-left: 10px;
+}
+input[type="checkbox"], input[type="radio"] {
+ line-height: normal;
+ margin-top: -3px;
+ width: 30px;
+}
+.navbar-default .navbar-nav>li>a:focus,
+.navbar-default .navbar-nav>li>a:hover {
+ color: #747474;
+ outline: 0;
+}
+.navbar {
+ margin-bottom: 5px;
+}
+.navbar-brand {
+ padding: 15px 10px;
+}
+.navbar-default .navbar-nav > .open > a, .navbar-default .navbar-nav > .open > a:focus, .navbar-default .navbar-nav > .open > a:hover {
+ color: #fff;
+ background-color:#202020 ;
+}
+.dropdown-menu {
+ background-clip: padding-box;
+ background-color: #202020;
+ border: 0px solid rgba(0, 0, 0, 0.15);
+ border-radius: 0;
+ box-shadow: none;
+ display: none;
+ float: left;
+ font-size: 14px;
+ left: 0;
+ color: #a5a5a5;
+}
+.dropdown-menu > li > a {
+ color: #a5a5a5;
+}
+.dropdown-menu>li>a:focus,
+.dropdown-menu>li>a:hover {
+ color: #fff;
+ text-decoration: none;
+ background-color: #313131;
}
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/font-wso2.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/font-wso2.css
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/font-wso2.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/font-wso2.css
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/main.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/main.css
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/main.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/css/main.css
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Bold-webfont.eot b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Bold-webfont.eot
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Bold-webfont.eot
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Bold-webfont.eot
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Bold-webfont.svg b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Bold-webfont.svg
similarity index 99%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Bold-webfont.svg
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Bold-webfont.svg
index 1557f68074..7cda1026b9 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Bold-webfont.svg
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Bold-webfont.svg
@@ -1,251 +1,251 @@
-
-
-
-
-This is a custom SVG webfont generated by Font Squirrel.
-Copyright : Digitized data copyright 20102011 Google Corporation
-Foundry : Ascender Corporation
-Foundry URL : httpwwwascendercorpcom
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+This is a custom SVG webfont generated by Font Squirrel.
+Copyright : Digitized data copyright 20102011 Google Corporation
+Foundry : Ascender Corporation
+Foundry URL : httpwwwascendercorpcom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Bold-webfont.ttf b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Bold-webfont.ttf
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Bold-webfont.ttf
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Bold-webfont.ttf
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Bold-webfont.woff b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Bold-webfont.woff
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Bold-webfont.woff
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Bold-webfont.woff
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-BoldItalic-webfont.eot b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-BoldItalic-webfont.eot
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-BoldItalic-webfont.eot
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-BoldItalic-webfont.eot
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-BoldItalic-webfont.svg b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-BoldItalic-webfont.svg
similarity index 99%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-BoldItalic-webfont.svg
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-BoldItalic-webfont.svg
index 24661f35f9..914912014c 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-BoldItalic-webfont.svg
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-BoldItalic-webfont.svg
@@ -1,251 +1,251 @@
-
-
-
-
-This is a custom SVG webfont generated by Font Squirrel.
-Copyright : Digitized data copyright 20102011 Google Corporation
-Foundry : Ascender Corporation
-Foundry URL : httpwwwascendercorpcom
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+This is a custom SVG webfont generated by Font Squirrel.
+Copyright : Digitized data copyright 20102011 Google Corporation
+Foundry : Ascender Corporation
+Foundry URL : httpwwwascendercorpcom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-BoldItalic-webfont.ttf b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-BoldItalic-webfont.ttf
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-BoldItalic-webfont.ttf
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-BoldItalic-webfont.ttf
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-BoldItalic-webfont.woff b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-BoldItalic-webfont.woff
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-BoldItalic-webfont.woff
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-BoldItalic-webfont.woff
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBold-webfont.eot b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBold-webfont.eot
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBold-webfont.eot
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBold-webfont.eot
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBold-webfont.svg b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBold-webfont.svg
similarity index 99%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBold-webfont.svg
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBold-webfont.svg
index c3d6642a2c..009e1d7be7 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBold-webfont.svg
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBold-webfont.svg
@@ -1,251 +1,251 @@
-
-
-
-
-This is a custom SVG webfont generated by Font Squirrel.
-Copyright : Digitized data copyright 2011 Google Corporation
-Foundry : Ascender Corporation
-Foundry URL : httpwwwascendercorpcom
-
-
-
+
+
+
+
+This is a custom SVG webfont generated by Font Squirrel.
+Copyright : Digitized data copyright 2011 Google Corporation
+Foundry : Ascender Corporation
+Foundry URL : httpwwwascendercorpcom
+
+
+
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBold-webfont.ttf b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBold-webfont.ttf
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBold-webfont.ttf
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBold-webfont.ttf
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBold-webfont.woff b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBold-webfont.woff
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBold-webfont.woff
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBold-webfont.woff
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBoldItalic-webfont.eot b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBoldItalic-webfont.eot
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBoldItalic-webfont.eot
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBoldItalic-webfont.eot
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBoldItalic-webfont.svg b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBoldItalic-webfont.svg
similarity index 99%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBoldItalic-webfont.svg
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBoldItalic-webfont.svg
index a699015a37..a0612586bd 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBoldItalic-webfont.svg
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBoldItalic-webfont.svg
@@ -1,251 +1,251 @@
-
-
-
-
-This is a custom SVG webfont generated by Font Squirrel.
-Copyright : Digitized data copyright 20102011 Google Corporation
-Foundry : Ascender Corporation
-Foundry URL : httpwwwascendercorpcom
-
-
-
+
+
+
+
+This is a custom SVG webfont generated by Font Squirrel.
+Copyright : Digitized data copyright 20102011 Google Corporation
+Foundry : Ascender Corporation
+Foundry URL : httpwwwascendercorpcom
+
+
+
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBoldItalic-webfont.ttf b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBoldItalic-webfont.ttf
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBoldItalic-webfont.ttf
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBoldItalic-webfont.ttf
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBoldItalic-webfont.woff b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBoldItalic-webfont.woff
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBoldItalic-webfont.woff
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-ExtraBoldItalic-webfont.woff
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Italic-webfont.eot b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Italic-webfont.eot
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Italic-webfont.eot
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Italic-webfont.eot
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Italic-webfont.svg b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Italic-webfont.svg
similarity index 99%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Italic-webfont.svg
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Italic-webfont.svg
index 537d20ca6f..be508574ee 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Italic-webfont.svg
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Italic-webfont.svg
@@ -1,251 +1,251 @@
-
-
-
-
-This is a custom SVG webfont generated by Font Squirrel.
-Copyright : Digitized data copyright 20102011 Google Corporation
-Foundry : Ascender Corporation
-Foundry URL : httpwwwascendercorpcom
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+This is a custom SVG webfont generated by Font Squirrel.
+Copyright : Digitized data copyright 20102011 Google Corporation
+Foundry : Ascender Corporation
+Foundry URL : httpwwwascendercorpcom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Italic-webfont.ttf b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Italic-webfont.ttf
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Italic-webfont.ttf
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Italic-webfont.ttf
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Italic-webfont.woff b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Italic-webfont.woff
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Italic-webfont.woff
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Italic-webfont.woff
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Light-webfont.eot b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Light-webfont.eot
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Light-webfont.eot
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Light-webfont.eot
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Light-webfont.svg b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Light-webfont.svg
similarity index 99%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Light-webfont.svg
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Light-webfont.svg
index c7ae13a29c..deadc3ef1a 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Light-webfont.svg
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Light-webfont.svg
@@ -1,252 +1,252 @@
-
-
-
-
-This is a custom SVG webfont generated by Font Squirrel.
-Copyright : Digitized data copyright 20102011 Google Corporation
-Foundry : Ascender Corporation
-Foundry URL : httpwwwascendercorpcom
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+This is a custom SVG webfont generated by Font Squirrel.
+Copyright : Digitized data copyright 20102011 Google Corporation
+Foundry : Ascender Corporation
+Foundry URL : httpwwwascendercorpcom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Light-webfont.ttf b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Light-webfont.ttf
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Light-webfont.ttf
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Light-webfont.ttf
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Light-webfont.woff b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Light-webfont.woff
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Light-webfont.woff
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Light-webfont.woff
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-LightItalic-webfont.eot b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-LightItalic-webfont.eot
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-LightItalic-webfont.eot
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-LightItalic-webfont.eot
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-LightItalic-webfont.svg b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-LightItalic-webfont.svg
similarity index 99%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-LightItalic-webfont.svg
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-LightItalic-webfont.svg
index 535e688236..1ac169c06f 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-LightItalic-webfont.svg
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-LightItalic-webfont.svg
@@ -1,252 +1,252 @@
-
-
-
-
-This is a custom SVG webfont generated by Font Squirrel.
-Copyright : Digitized data copyright 20102011 Google Corporation
-Foundry : Ascender Corporation
-Foundry URL : httpwwwascendercorpcom
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+This is a custom SVG webfont generated by Font Squirrel.
+Copyright : Digitized data copyright 20102011 Google Corporation
+Foundry : Ascender Corporation
+Foundry URL : httpwwwascendercorpcom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-LightItalic-webfont.ttf b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-LightItalic-webfont.ttf
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-LightItalic-webfont.ttf
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-LightItalic-webfont.ttf
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-LightItalic-webfont.woff b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-LightItalic-webfont.woff
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-LightItalic-webfont.woff
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-LightItalic-webfont.woff
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Regular-webfont.eot b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Regular-webfont.eot
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Regular-webfont.eot
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Regular-webfont.eot
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Regular-webfont.svg b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Regular-webfont.svg
similarity index 99%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Regular-webfont.svg
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Regular-webfont.svg
index ead219a569..46a8f4c6ca 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Regular-webfont.svg
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Regular-webfont.svg
@@ -1,252 +1,252 @@
-
-
-
-
-This is a custom SVG webfont generated by Font Squirrel.
-Copyright : Digitized data copyright 20102011 Google Corporation
-Foundry : Ascender Corporation
-Foundry URL : httpwwwascendercorpcom
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+This is a custom SVG webfont generated by Font Squirrel.
+Copyright : Digitized data copyright 20102011 Google Corporation
+Foundry : Ascender Corporation
+Foundry URL : httpwwwascendercorpcom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Regular-webfont.ttf b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Regular-webfont.ttf
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Regular-webfont.ttf
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Regular-webfont.ttf
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Regular-webfont.woff b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Regular-webfont.woff
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Regular-webfont.woff
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Regular-webfont.woff
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Semibold-webfont.eot b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Semibold-webfont.eot
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Semibold-webfont.eot
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Semibold-webfont.eot
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Semibold-webfont.svg b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Semibold-webfont.svg
similarity index 99%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Semibold-webfont.svg
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Semibold-webfont.svg
index 9eaa0b710f..ef8b7a2bca 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Semibold-webfont.svg
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Semibold-webfont.svg
@@ -1,251 +1,251 @@
-
-
-
-
-This is a custom SVG webfont generated by Font Squirrel.
-Copyright : Digitized data copyright 2011 Google Corporation
-Foundry : Ascender Corporation
-Foundry URL : httpwwwascendercorpcom
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+This is a custom SVG webfont generated by Font Squirrel.
+Copyright : Digitized data copyright 2011 Google Corporation
+Foundry : Ascender Corporation
+Foundry URL : httpwwwascendercorpcom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Semibold-webfont.ttf b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Semibold-webfont.ttf
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Semibold-webfont.ttf
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Semibold-webfont.ttf
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Semibold-webfont.woff b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Semibold-webfont.woff
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Semibold-webfont.woff
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-Semibold-webfont.woff
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-SemiboldItalic-webfont.eot b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-SemiboldItalic-webfont.eot
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-SemiboldItalic-webfont.eot
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-SemiboldItalic-webfont.eot
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-SemiboldItalic-webfont.svg b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-SemiboldItalic-webfont.svg
similarity index 99%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-SemiboldItalic-webfont.svg
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-SemiboldItalic-webfont.svg
index 316b8186d4..46cfd5c8b8 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-SemiboldItalic-webfont.svg
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-SemiboldItalic-webfont.svg
@@ -1,251 +1,251 @@
-
-
-
-
-This is a custom SVG webfont generated by Font Squirrel.
-Copyright : Digitized data copyright 20102011 Google Corporation
-Foundry : Ascender Corporation
-Foundry URL : httpwwwascendercorpcom
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+This is a custom SVG webfont generated by Font Squirrel.
+Copyright : Digitized data copyright 20102011 Google Corporation
+Foundry : Ascender Corporation
+Foundry URL : httpwwwascendercorpcom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-SemiboldItalic-webfont.ttf b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-SemiboldItalic-webfont.ttf
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-SemiboldItalic-webfont.ttf
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-SemiboldItalic-webfont.ttf
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-SemiboldItalic-webfont.woff b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-SemiboldItalic-webfont.woff
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-SemiboldItalic-webfont.woff
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/OpenSans-SemiboldItalic-webfont.woff
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/font-wso2.eot b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/font-wso2.eot
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/font-wso2.eot
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/font-wso2.eot
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/font-wso2.svg b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/font-wso2.svg
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/font-wso2.svg
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/font-wso2.svg
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/font-wso2.ttf b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/font-wso2.ttf
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/font-wso2.ttf
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/font-wso2.ttf
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/font-wso2.woff b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/font-wso2.woff
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/font-wso2.woff
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/font-wso2.woff
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/glyphicons-halflings-regular.eot b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/glyphicons-halflings-regular.eot
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/glyphicons-halflings-regular.eot
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/glyphicons-halflings-regular.eot
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/glyphicons-halflings-regular.svg b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/glyphicons-halflings-regular.svg
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/glyphicons-halflings-regular.svg
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/glyphicons-halflings-regular.svg
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/glyphicons-halflings-regular.ttf b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/glyphicons-halflings-regular.ttf
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/glyphicons-halflings-regular.ttf
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/glyphicons-halflings-regular.ttf
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/glyphicons-halflings-regular.woff b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/glyphicons-halflings-regular.woff
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/glyphicons-halflings-regular.woff
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/fonts/glyphicons-halflings-regular.woff
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/images/content-bg-1.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/images/content-bg-1.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/images/content-bg-1.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/images/content-bg-1.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/images/content-bg.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/images/content-bg.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/images/content-bg.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/images/content-bg.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/assetmenu.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/assetmenu.js
similarity index 96%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/assetmenu.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/assetmenu.js
index b4d6031fca..870398f588 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/assetmenu.js
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/assetmenu.js
@@ -1,217 +1,217 @@
-/*
- * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
- *
- * WSO2 Inc. licenses this file to you under the Apache License,
- * Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/*
- * Setting-up global variables.
- */
-var menuButton = '.ctrl-asset-type-switcher',
- menu = '.popover.menu',
- deviceOptions = '#device-filter-options',
- menuContainer = '#asset-select',
- menuSubContainer = '#asset-selected',
- menuItems = '#asset-select ul li',
- tagsContainer = '.wr-search-tags',
- searchField = '#search',
- menuItemsID = 0,
- prevSelected = 0;
-
-/*
- * DOM ready functions.
- */
-$(document).ready(function(){
-
- /* Bind filter menu relationship on load */
- addingIdentity();
-
- /* Bind filter select function to all assets on load */
- $(menuItems).each(function(){
- menuItemsID++;
- $(this).attr({
- 'asset':menuItemsID,
- 'onclick':'selectAsset(this)',
- 'level': $(this).parents('ul').length
- });
- });
-});
-
-/*
- * Bind filter window hide function to the document.
- */
-$(document).bind('click', function(e) {
- if($(e.target).attr('rel') !== 'assetfilter') {
- $(menu).hide();
- }
-});
-
-/*
- * On filter switch button click show filter option window.
- */
-$(menuButton).click(function(e){
- e.stopPropagation();
- $(menu).toggle();
-});
-
-/*
- * On asset filter options window advance filter radio button change function
- */
-$('#advance-filter-options input[type=radio]').change(function() {
- if(this.value !== 'devices'){
- $(deviceOptions).hide();
- resetNav();
- $(tagsContainer).html('');
- }
- else {
- $(deviceOptions).show();
- }
-
- $(searchField).attr('data-placeholder', 'Search '+ this.value + ' ...');
-});
-
-/*
- * Update filter container.
- * @param asset: Selected asset
- */
-function containerUpdate(asset){
- var options = $(asset).next('ul').length ? $(asset).next('ul').html() : "";
-
- $(menuSubContainer).html('' + '');
-
- prevSelected = ($(menuSubContainer + ' ul.selected li').attr('asset'));
-
- //$(menuSubContainer + ' ul.options li').length == 0 ? $(menuSubContainer + ' ul.options').hide() :
- // + $(menuSubContainer + ' ul.options').show();
-
- addingIdentity();
-}
-
-/*
- * On asset click selecting filter.
- * @param asset: Selected asset
- */
-function selectAsset(asset){
-
- console.log(this);
-
- $(tagsContainer +' span').each(function(){
- if($(this).attr('level') == $(asset).attr('level')){
- removeTags(this);
- }
- });
-
- containerUpdate(asset);
-
- $(menuSubContainer).show();
- $(menuContainer).hide();
-
- addTags(asset);
-}
-
-/*
- * Adding asset filtering relationship menu child elements.
- */
-function addingIdentity(){
- $(menu).find('*').each(function(){
- $(this).attr('rel', 'assetfilter');
- });
- $(tagsContainer).find('*').each(function(){
- $(this).attr('rel', 'assetfilter');
- });
-}
-
-/*
- * Filter window go back function.
- * @param backButton: Filter window back button
- */
-function goBack(backButton){
- if($(backButton).prev('li').attr('level') == 1){
- $(menuSubContainer).hide();
- $(menuContainer).show();
- }
- else{
- containerUpdate($(menuContainer + ' [asset='+prevSelected+']').parent('ul').prev('li'));
- $(backButton).remove();
- }
-}
-
-/*
- * Filter window reset function.
- * @param backButton: Filter window reset button
- */
-function resetNav(){
- $('#goBack').remove();
- $('#resetNav').remove();
- $(menuSubContainer).hide();
- $(menuContainer).show();
-}
-
-/*
- * Find parent function.
- * @param selection: Current asset parent search tag on search parent loop
- */
-function getParent(selection){
- return $(menuContainer + ' [asset=' + $(selection).attr('asset') + ']').closest('ul').prev('li');
-}
-
-/*
- * On filter select ad asset & its parents to search field.
- * @param tag: Selected filter search tag
- */
-function addTags(tag){
- var level = $(tag).attr('level'),
- selection = tag,
- content = '' + $(tag).find('.tag-name').html() + ' x ';
-
- if(level !== 1) {
- for (var i = 1; i < level; i++) {
- content = '' + $(getParent(selection)).find('.tag-name').html() + ' x '
- +content;
-
- selection = getParent(selection);
- }
- $(tagsContainer).html(content);
- }
- addingIdentity();
-}
-
-/*
- * On filter tags click remove asset & its child from search field.
- * @param tag: Selected filter search tag
- */
-function removeTags(tag){
- $(tag).nextAll('span').andSelf().each(function(){
- $($(menuContainer + ' [asset='+ $(this).attr('asset') +']')).removeClass('selected');
- $(this).remove();
- });
-}
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Setting-up global variables.
+ */
+var menuButton = '.ctrl-asset-type-switcher',
+ menu = '.popover.menu',
+ deviceOptions = '#device-filter-options',
+ menuContainer = '#asset-select',
+ menuSubContainer = '#asset-selected',
+ menuItems = '#asset-select ul li',
+ tagsContainer = '.wr-search-tags',
+ searchField = '#search',
+ menuItemsID = 0,
+ prevSelected = 0;
+
+/*
+ * DOM ready functions.
+ */
+$(document).ready(function(){
+
+ /* Bind filter menu relationship on load */
+ addingIdentity();
+
+ /* Bind filter select function to all assets on load */
+ $(menuItems).each(function(){
+ menuItemsID++;
+ $(this).attr({
+ 'asset':menuItemsID,
+ 'onclick':'selectAsset(this)',
+ 'level': $(this).parents('ul').length
+ });
+ });
+});
+
+/*
+ * Bind filter window hide function to the document.
+ */
+$(document).bind('click', function(e) {
+ if($(e.target).attr('rel') !== 'assetfilter') {
+ $(menu).hide();
+ }
+});
+
+/*
+ * On filter switch button click show filter option window.
+ */
+$(menuButton).click(function(e){
+ e.stopPropagation();
+ $(menu).toggle();
+});
+
+/*
+ * On asset filter options window advance filter radio button change function
+ */
+$('#advance-filter-options input[type=radio]').change(function() {
+ if(this.value !== 'devices'){
+ $(deviceOptions).hide();
+ resetNav();
+ $(tagsContainer).html('');
+ }
+ else {
+ $(deviceOptions).show();
+ }
+
+ $(searchField).attr('data-placeholder', 'Search '+ this.value + ' ...');
+});
+
+/*
+ * Update filter container.
+ * @param asset: Selected asset
+ */
+function containerUpdate(asset){
+ var options = $(asset).next('ul').length ? $(asset).next('ul').html() : "";
+
+ $(menuSubContainer).html('' + '');
+
+ prevSelected = ($(menuSubContainer + ' ul.selected li').attr('asset'));
+
+ //$(menuSubContainer + ' ul.options li').length == 0 ? $(menuSubContainer + ' ul.options').hide() :
+ // + $(menuSubContainer + ' ul.options').show();
+
+ addingIdentity();
+}
+
+/*
+ * On asset click selecting filter.
+ * @param asset: Selected asset
+ */
+function selectAsset(asset){
+
+ console.log(this);
+
+ $(tagsContainer +' span').each(function(){
+ if($(this).attr('level') == $(asset).attr('level')){
+ removeTags(this);
+ }
+ });
+
+ containerUpdate(asset);
+
+ $(menuSubContainer).show();
+ $(menuContainer).hide();
+
+ addTags(asset);
+}
+
+/*
+ * Adding asset filtering relationship menu child elements.
+ */
+function addingIdentity(){
+ $(menu).find('*').each(function(){
+ $(this).attr('rel', 'assetfilter');
+ });
+ $(tagsContainer).find('*').each(function(){
+ $(this).attr('rel', 'assetfilter');
+ });
+}
+
+/*
+ * Filter window go back function.
+ * @param backButton: Filter window back button
+ */
+function goBack(backButton){
+ if($(backButton).prev('li').attr('level') == 1){
+ $(menuSubContainer).hide();
+ $(menuContainer).show();
+ }
+ else{
+ containerUpdate($(menuContainer + ' [asset='+prevSelected+']').parent('ul').prev('li'));
+ $(backButton).remove();
+ }
+}
+
+/*
+ * Filter window reset function.
+ * @param backButton: Filter window reset button
+ */
+function resetNav(){
+ $('#goBack').remove();
+ $('#resetNav').remove();
+ $(menuSubContainer).hide();
+ $(menuContainer).show();
+}
+
+/*
+ * Find parent function.
+ * @param selection: Current asset parent search tag on search parent loop
+ */
+function getParent(selection){
+ return $(menuContainer + ' [asset=' + $(selection).attr('asset') + ']').closest('ul').prev('li');
+}
+
+/*
+ * On filter select ad asset & its parents to search field.
+ * @param tag: Selected filter search tag
+ */
+function addTags(tag){
+ var level = $(tag).attr('level'),
+ selection = tag,
+ content = '' + $(tag).find('.tag-name').html() + ' x ';
+
+ if(level !== 1) {
+ for (var i = 1; i < level; i++) {
+ content = '' + $(getParent(selection)).find('.tag-name').html() + ' x '
+ +content;
+
+ selection = getParent(selection);
+ }
+ $(tagsContainer).html(content);
+ }
+ addingIdentity();
+}
+
+/*
+ * On filter tags click remove asset & its child from search field.
+ * @param tag: Selected filter search tag
+ */
+function removeTags(tag){
+ $(tag).nextAll('span').andSelf().each(function(){
+ $($(menuContainer + ' [asset='+ $(this).attr('asset') +']')).removeClass('selected');
+ $(this).remove();
+ });
+}
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/bootstrap.min.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/bootstrap.min.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/bootstrap.min.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/bootstrap.min.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/deviceview.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/deviceview.js
similarity index 96%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/deviceview.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/deviceview.js
index c4d42ccfa3..cda9212d91 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/deviceview.js
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/deviceview.js
@@ -1,94 +1,94 @@
-/*
- * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
- *
- * WSO2 Inc. licenses this file to you under the Apache License,
- * Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/*
- * Setting-up global variables.
- */
-var deviceCheckbox = '#ast-container .ctrl-wr-asset .itm-select input[type="checkbox"]',
- assetContainer = '#ast-container';
-
-/*
- * DOM ready functions.
- */
-$(document).ready(function(){
- /* Adding selected class for selected devices */
- $(deviceCheckbox).each(function(){
- addDeviceSelectedClass(this);
- });
-});
-
-/*
- * On Select All Device button click function.
- * @param button: Select All Device button
- */
-function selectAllDevices(button){
- if(!$(button).data('select')){
- $(deviceCheckbox).each(function(index){
- $(this).prop('checked', true);
- addDeviceSelectedClass(this);
- });
- $(button).data('select', true);
- $(button).html('Deselect All Devices');
- }else{
- $(deviceCheckbox).each(function(index){
- $(this).prop('checked', false);
- addDeviceSelectedClass(this);
- });
- $(button).data('select', false);
- $(button).html('Select All Devices');
- }
-}
-
-/*
- * On listing layout toggle buttons click function
- * @param view: Selected view type
- * @param selection: Selection button
- */
-function changeDeviceView(view, selection){
- $('.view-toggle').each(function() {
- $(this).removeClass('selected');
- });
- $(selection).addClass('selected');
-
- if(view == 'list'){
- $(assetContainer).addClass('list-view');
- }
- else {
- $(assetContainer).removeClass('list-view');
- }
-}
-
-/*
- * Add selected style class to the parent element function
- * @param checkbox: Selected checkbox
- */
-function addDeviceSelectedClass(checkbox){
- if($(checkbox).is(':checked')){
- $(checkbox).closest('.ctrl-wr-asset').addClass('selected');
- }
- else{
- $(checkbox).closest('.ctrl-wr-asset').removeClass('selected');
- }
-}
-
-/*
- * On device checkbox select add parent selected style class
- */
-$(deviceCheckbox).click(function(){
- addDeviceSelectedClass(this);
-});
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Setting-up global variables.
+ */
+var deviceCheckbox = '#ast-container .ctrl-wr-asset .itm-select input[type="checkbox"]',
+ assetContainer = '#ast-container';
+
+/*
+ * DOM ready functions.
+ */
+$(document).ready(function(){
+ /* Adding selected class for selected devices */
+ $(deviceCheckbox).each(function(){
+ addDeviceSelectedClass(this);
+ });
+});
+
+/*
+ * On Select All Device button click function.
+ * @param button: Select All Device button
+ */
+function selectAllDevices(button){
+ if(!$(button).data('select')){
+ $(deviceCheckbox).each(function(index){
+ $(this).prop('checked', true);
+ addDeviceSelectedClass(this);
+ });
+ $(button).data('select', true);
+ $(button).html('Deselect All Devices');
+ }else{
+ $(deviceCheckbox).each(function(index){
+ $(this).prop('checked', false);
+ addDeviceSelectedClass(this);
+ });
+ $(button).data('select', false);
+ $(button).html('Select All Devices');
+ }
+}
+
+/*
+ * On listing layout toggle buttons click function
+ * @param view: Selected view type
+ * @param selection: Selection button
+ */
+function changeDeviceView(view, selection){
+ $('.view-toggle').each(function() {
+ $(this).removeClass('selected');
+ });
+ $(selection).addClass('selected');
+
+ if(view == 'list'){
+ $(assetContainer).addClass('list-view');
+ }
+ else {
+ $(assetContainer).removeClass('list-view');
+ }
+}
+
+/*
+ * Add selected style class to the parent element function
+ * @param checkbox: Selected checkbox
+ */
+function addDeviceSelectedClass(checkbox){
+ if($(checkbox).is(':checked')){
+ $(checkbox).closest('.ctrl-wr-asset').addClass('selected');
+ }
+ else{
+ $(checkbox).closest('.ctrl-wr-asset').removeClass('selected');
+ }
+}
+
+/*
+ * On device checkbox select add parent selected style class
+ */
+$(deviceCheckbox).click(function(){
+ addDeviceSelectedClass(this);
+});
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/html5shiv.min.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/html5shiv.min.js
similarity index 97%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/html5shiv.min.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/html5shiv.min.js
index 235cdbc8a3..8aff8f650f 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/html5shiv.min.js
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/html5shiv.min.js
@@ -1,7 +1,7 @@
-/**
- * Created by Sharon on 5/14/2015.
- */
-/**
- * @preserve HTML5 Shiv 3.7.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
- */
+/**
+ * Created by Sharon on 5/14/2015.
+ */
+/**
+ * @preserve HTML5 Shiv 3.7.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
+ */
!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.2",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML=" ",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b)}(this,document);
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/jquery-1.11.2.min.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/jquery-1.11.2.min.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/jquery-1.11.2.min.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/jquery-1.11.2.min.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/jquery-ui.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/jquery-ui.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/jquery-ui.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/jquery-ui.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/jquery.min.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/jquery.min.js
similarity index 99%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/jquery.min.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/jquery.min.js
index 18bdbed7f7..15baa006f0 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/jquery.min.js
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/public/js/jquery.min.js
@@ -1,5 +1,5 @@
-/*! jQuery v2.1.3 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
-!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.3",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=hb(),z=hb(),A=hb(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},eb=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fb){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function gb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+rb(o[l]);w=ab.test(a)&&pb(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function hb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ib(a){return a[u]=!0,a}function jb(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function kb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function lb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function nb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function ob(a){return ib(function(b){return b=+b,ib(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pb(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=gb.support={},f=gb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=gb.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",eb,!1):e.attachEvent&&e.attachEvent("onunload",eb)),p=!f(g),c.attributes=jb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=jb(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=jb(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(jb(function(a){o.appendChild(a).innerHTML=" ",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),jb(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&jb(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return lb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?lb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},gb.matches=function(a,b){return gb(a,null,null,b)},gb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return gb(b,n,null,[a]).length>0},gb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},gb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},gb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},gb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=gb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=gb.selectors={cacheLength:50,createPseudo:ib,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||gb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&gb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=gb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||gb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ib(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ib(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ib(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ib(function(a){return function(b){return gb(a,b).length>0}}),contains:ib(function(a){return a=a.replace(cb,db),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ib(function(a){return W.test(a||"")||gb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:ob(function(){return[0]}),last:ob(function(a,b){return[b-1]}),eq:ob(function(a,b,c){return[0>c?c+b:c]}),even:ob(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:ob(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:ob(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:ob(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function sb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function tb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ub(a,b,c){for(var d=0,e=b.length;e>d;d++)gb(a,b[d],c);return c}function vb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wb(a,b,c,d,e,f){return d&&!d[u]&&(d=wb(d)),e&&!e[u]&&(e=wb(e,f)),ib(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ub(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:vb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=vb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=vb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sb(function(a){return a===b},h,!0),l=sb(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sb(tb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wb(i>1&&tb(m),i>1&&rb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xb(a.slice(i,e)),f>e&&xb(a=a.slice(e)),f>e&&rb(a))}m.push(c)}return tb(m)}function yb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=vb(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&gb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ib(f):f}return h=gb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,yb(e,d)),f.selector=a}return f},i=gb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&pb(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&rb(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&pb(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=jb(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),jb(function(a){return a.innerHTML=" ","#"===a.firstChild.getAttribute("href")})||kb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&jb(function(a){return a.innerHTML=" ",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||kb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),jb(function(a){return null==a.getAttribute("disabled")})||kb(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),gb}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+K.uid++}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c)
-},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthx",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*\s*$/g,ib={option:[1,""," "],thead:[1,""],col:[2,""],tr:[2,""],td:[3,""],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1>$2>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(ob(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1>$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(ob(c,"script"),kb),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(hb,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function tb(a){var b=l,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||n("")).appendTo(b.documentElement),b=qb[0].contentDocument,b.write(),b.close(),c=sb(a,b),qb.detach()),rb[a]=c),c}var ub=/^margin/,vb=new RegExp("^("+Q+")(?!px)[a-z%]+$","i"),wb=function(b){return b.ownerDocument.defaultView.opener?b.ownerDocument.defaultView.getComputedStyle(b,null):a.getComputedStyle(b,null)};function xb(a,b,c){var d,e,f,g,h=a.style;return c=c||wb(a),c&&(g=c.getPropertyValue(b)||c[b]),c&&(""!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),vb.test(g)&&ub.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function yb(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d=l.documentElement,e=l.createElement("div"),f=l.createElement("div");if(f.style){f.style.backgroundClip="content-box",f.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===f.style.backgroundClip,e.style.cssText="border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;position:absolute",e.appendChild(f);function g(){f.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",f.innerHTML="",d.appendChild(e);var g=a.getComputedStyle(f,null);b="1%"!==g.top,c="4px"===g.width,d.removeChild(e)}a.getComputedStyle&&n.extend(k,{pixelPosition:function(){return g(),b},boxSizingReliable:function(){return null==c&&g(),c},reliableMarginRight:function(){var b,c=f.appendChild(l.createElement("div"));return c.style.cssText=f.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",c.style.marginRight=c.style.width="0",f.style.width="1px",d.appendChild(e),b=!parseFloat(a.getComputedStyle(c,null).marginRight),d.removeChild(e),f.removeChild(c),b}})}}(),n.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var zb=/^(none|table(?!-c[ea]).+)/,Ab=new RegExp("^("+Q+")(.*)$","i"),Bb=new RegExp("^([+-])=("+Q+")","i"),Cb={position:"absolute",visibility:"hidden",display:"block"},Db={letterSpacing:"0",fontWeight:"400"},Eb=["Webkit","O","Moz","ms"];function Fb(a,b){if(b in a)return b;var c=b[0].toUpperCase()+b.slice(1),d=b,e=Eb.length;while(e--)if(b=Eb[e]+c,b in a)return b;return d}function Gb(a,b,c){var d=Ab.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Hb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+R[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+R[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+R[f]+"Width",!0,e))):(g+=n.css(a,"padding"+R[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+R[f]+"Width",!0,e)));return g}function Ib(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=wb(a),g="border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=xb(a,b,f),(0>e||null==e)&&(e=a.style[b]),vb.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Hb(a,b,c||(g?"border":"content"),d,f)+"px"}function Jb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=L.get(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&S(d)&&(f[g]=L.access(d,"olddisplay",tb(d.nodeName)))):(e=S(d),"none"===c&&e||L.set(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=xb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;return b=n.cssProps[h]||(n.cssProps[h]=Fb(i,h)),g=n.cssHooks[b]||n.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=Bb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(n.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||n.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Fb(a.style,h)),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=xb(a,b,d)),"normal"===e&&b in Db&&(e=Db[b]),""===c||c?(f=parseFloat(e),c===!0||n.isNumeric(f)?f||0:e):e}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?zb.test(n.css(a,"display"))&&0===a.offsetWidth?n.swap(a,Cb,function(){return Ib(a,b,d)}):Ib(a,b,d):void 0},set:function(a,c,d){var e=d&&wb(a);return Gb(a,c,d?Hb(a,b,d,"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),n.cssHooks.marginRight=yb(k.reliableMarginRight,function(a,b){return b?n.swap(a,{display:"inline-block"},xb,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+R[d]+b]=f[d]||f[d-2]||f[0];return e}},ub.test(a)||(n.cssHooks[a+b].set=Gb)}),n.fn.extend({css:function(a,b){return J(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=wb(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return Jb(this,!0)},hide:function(){return Jb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){S(this)?n(this).show():n(this).hide()})}});function Kb(a,b,c,d,e){return new Kb.prototype.init(a,b,c,d,e)}n.Tween=Kb,Kb.prototype={constructor:Kb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=Kb.propHooks[this.prop];return a&&a.get?a.get(this):Kb.propHooks._default.get(this)},run:function(a){var b,c=Kb.propHooks[this.prop];return this.pos=b=this.options.duration?n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Kb.propHooks._default.set(this),this}},Kb.prototype.init.prototype=Kb.prototype,Kb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[n.cssProps[a.prop]]||n.cssHooks[a.prop])?n.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Kb.propHooks.scrollTop=Kb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},n.fx=Kb.prototype.init,n.fx.step={};var Lb,Mb,Nb=/^(?:toggle|show|hide)$/,Ob=new RegExp("^(?:([+-])=|)("+Q+")([a-z%]*)$","i"),Pb=/queueHooks$/,Qb=[Vb],Rb={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=Ob.exec(b),f=e&&e[3]||(n.cssNumber[a]?"":"px"),g=(n.cssNumber[a]||"px"!==f&&+d)&&Ob.exec(n.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,n.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function Sb(){return setTimeout(function(){Lb=void 0}),Lb=n.now()}function Tb(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=R[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function Ub(a,b,c){for(var d,e=(Rb[b]||[]).concat(Rb["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function Vb(a,b,c){var d,e,f,g,h,i,j,k,l=this,m={},o=a.style,p=a.nodeType&&S(a),q=L.get(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,l.always(function(){l.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=n.css(a,"display"),k="none"===j?L.get(a,"olddisplay")||tb(a.nodeName):j,"inline"===k&&"none"===n.css(a,"float")&&(o.display="inline-block")),c.overflow&&(o.overflow="hidden",l.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],Nb.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}m[d]=q&&q[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(m))"inline"===("none"===j?tb(a.nodeName):j)&&(o.display=j);else{q?"hidden"in q&&(p=q.hidden):q=L.access(a,"fxshow",{}),f&&(q.hidden=!p),p?n(a).show():l.done(function(){n(a).hide()}),l.done(function(){var b;L.remove(a,"fxshow");for(b in m)n.style(a,b,m[b])});for(d in m)g=Ub(p?q[d]:0,d,l),d in q||(q[d]=g.start,p&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function Wb(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function Xb(a,b,c){var d,e,f=0,g=Qb.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=Lb||Sb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:Lb||Sb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(Wb(k,j.opts.specialEasing);g>f;f++)if(d=Qb[f].call(j,a,k,j.opts))return d;return n.map(k,Ub,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(Xb,{tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],Rb[c]=Rb[c]||[],Rb[c].unshift(b)},prefilter:function(a,b){b?Qb.unshift(a):Qb.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(S).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=Xb(this,n.extend({},a),f);(e||L.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=L.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&Pb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=L.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(Tb(b,!0),a,d,e)}}),n.each({slideDown:Tb("show"),slideUp:Tb("hide"),slideToggle:Tb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=0,c=n.timers;for(Lb=n.now();b1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===U?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),d=n.attrHooks[b]||(n.expr.match.bool.test(b)?Zb:Yb)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b))
-},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),Zb={set:function(a,b,c){return b===!1?n.removeAttr(a,c):a.setAttribute(c,c),c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=$b[b]||n.find.attr;$b[b]=function(a,b,d){var e,f;return d||(f=$b[b],$b[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,$b[b]=f),e}});var _b=/^(?:input|select|textarea|button)$/i;n.fn.extend({prop:function(a,b){return J(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[n.propFix[a]||a]})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){return a.hasAttribute("tabindex")||_b.test(a.nodeName)||a.href?a.tabIndex:-1}}}}),k.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this});var ac=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h="string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0===arguments.length||"string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===U||"boolean"===c)&&(this.className&&L.set(this,"__className__",this.className),this.className=this.className||a===!1?"":L.get(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ac," ").indexOf(b)>=0)return!0;return!1}});var bc=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(bc,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.trim(n.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=n.inArray(d.value,f)>=0)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>=0:void 0}},k.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var cc=n.now(),dc=/\?/;n.parseJSON=function(a){return JSON.parse(a+"")},n.parseXML=function(a){var b,c;if(!a||"string"!=typeof a)return null;try{c=new DOMParser,b=c.parseFromString(a,"text/xml")}catch(d){b=void 0}return(!b||b.getElementsByTagName("parsererror").length)&&n.error("Invalid XML: "+a),b};var ec=/#.*$/,fc=/([?&])_=[^&]*/,gc=/^(.*?):[ \t]*([^\r\n]*)$/gm,hc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,ic=/^(?:GET|HEAD)$/,jc=/^\/\//,kc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,lc={},mc={},nc="*/".concat("*"),oc=a.location.href,pc=kc.exec(oc.toLowerCase())||[];function qc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(n.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function rc(a,b,c,d){var e={},f=a===mc;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function sc(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&n.extend(!0,a,d),a}function tc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function uc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:oc,type:"GET",isLocal:hc.test(pc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":nc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?sc(sc(a,n.ajaxSettings),b):sc(n.ajaxSettings,a)},ajaxPrefilter:qc(lc),ajaxTransport:qc(mc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=n.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?n(l):n.event,o=n.Deferred(),p=n.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!f){f={};while(b=gc.exec(e))f[b[1].toLowerCase()]=b[2]}b=f[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?e:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return c&&c.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||oc)+"").replace(ec,"").replace(jc,pc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=n.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(h=kc.exec(k.url.toLowerCase()),k.crossDomain=!(!h||h[1]===pc[1]&&h[2]===pc[2]&&(h[3]||("http:"===h[1]?"80":"443"))===(pc[3]||("http:"===pc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=n.param(k.data,k.traditional)),rc(lc,k,b,v),2===t)return v;i=n.event&&k.global,i&&0===n.active++&&n.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!ic.test(k.type),d=k.url,k.hasContent||(k.data&&(d=k.url+=(dc.test(d)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=fc.test(d)?d.replace(fc,"$1_="+cc++):d+(dc.test(d)?"&":"?")+"_="+cc++)),k.ifModified&&(n.lastModified[d]&&v.setRequestHeader("If-Modified-Since",n.lastModified[d]),n.etag[d]&&v.setRequestHeader("If-None-Match",n.etag[d])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+nc+"; q=0.01":""):k.accepts["*"]);for(j in k.headers)v.setRequestHeader(j,k.headers[j]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(j in{success:1,error:1,complete:1})v[j](k[j]);if(c=rc(mc,k,b,v)){v.readyState=1,i&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,c.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,f,h){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),c=void 0,e=h||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,f&&(u=tc(k,v,f)),u=uc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(n.lastModified[d]=w),w=v.getResponseHeader("etag"),w&&(n.etag[d]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,i&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),i&&(m.trigger("ajaxComplete",[v,k]),--n.active||n.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){var b;return n.isFunction(a)?this.each(function(b){n(this).wrapAll(a.call(this,b))}):(this[0]&&(b=n(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return this.each(n.isFunction(a)?function(b){n(this).wrapInner(a.call(this,b))}:function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var vc=/%20/g,wc=/\[\]$/,xc=/\r?\n/g,yc=/^(?:submit|button|image|reset|file)$/i,zc=/^(?:input|select|textarea|keygen)/i;function Ac(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||wc.test(a)?d(a,e):Ac(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Ac(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Ac(c,a[c],b,e);return d.join("&").replace(vc,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&zc.test(this.nodeName)&&!yc.test(a)&&(this.checked||!T.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(xc,"\r\n")}}):{name:b.name,value:c.replace(xc,"\r\n")}}).get()}}),n.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(a){}};var Bc=0,Cc={},Dc={0:200,1223:204},Ec=n.ajaxSettings.xhr();a.attachEvent&&a.attachEvent("onunload",function(){for(var a in Cc)Cc[a]()}),k.cors=!!Ec&&"withCredentials"in Ec,k.ajax=Ec=!!Ec,n.ajaxTransport(function(a){var b;return k.cors||Ec&&!a.crossDomain?{send:function(c,d){var e,f=a.xhr(),g=++Bc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)f.setRequestHeader(e,c[e]);b=function(a){return function(){b&&(delete Cc[g],b=f.onload=f.onerror=null,"abort"===a?f.abort():"error"===a?d(f.status,f.statusText):d(Dc[f.status]||f.status,f.statusText,"string"==typeof f.responseText?{text:f.responseText}:void 0,f.getAllResponseHeaders()))}},f.onload=b(),f.onerror=b("error"),b=Cc[g]=b("abort");try{f.send(a.hasContent&&a.data||null)}catch(h){if(b)throw h}},abort:function(){b&&b()}}:void 0}),n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(d,e){b=n("
-
-
-
-
-
-
-
-
-{{/zone}}
-{{#zone "topJs"}}
-{{/zone}}
-{{#zone "bottomJs"}}
-{{/zone}}
-{{#zone "bottomLibJs"}}
-
-
-{{/zone}}
-
-
-
+
+
+
+
+
+
+
+
+{{/zone}}
+{{#zone "topJs"}}
+{{/zone}}
+{{#zone "bottomJs"}}
+{{/zone}}
+{{#zone "bottomLibJs"}}
+
+
+{{/zone}}
+
+
+
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/theme.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/theme.json
similarity index 93%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/theme.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/theme.json
index d17cd635d6..549224bc09 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/theme.json
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/theme/theme.json
@@ -1,3 +1,3 @@
-{
- "predicate": "config.theme == 'default'"
+{
+ "predicate": "config.theme == 'default'"
}
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/user-listing/public/js/user-listing.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/user-listing/public/js/user-listing.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/user-listing/public/js/user-listing.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/user-listing/public/js/user-listing.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/user-listing/user-listing.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/user-listing/user-listing.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/user-listing/user-listing.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/user-listing/user-listing.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/user-listing/user-listing.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/user-listing/user-listing.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/user-listing/user-listing.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/user-listing/user-listing.js
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/user-listing/user-listing.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/user-listing/user-listing.json
new file mode 100644
index 0000000000..3f78010053
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/iotserver/units/user-listing/user-listing.json
@@ -0,0 +1,5 @@
+{
+
+
+
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/config/publisher-tenant.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/config/publisher-tenant.json
new file mode 100644
index 0000000000..e39d571f9d
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/config/publisher-tenant.json
@@ -0,0 +1,68 @@
+{
+ "roles": {
+ "Internal/publisher": {
+ "/permission/admin/login": ["ui.execute"]
+ },
+ "Internal/reviewer": {
+ "/permission/admin/login": ["ui.execute"]
+ }
+ },
+ "user": {
+ "username": "admin",
+ "password": "admin"
+ },
+ "application": {
+ "landingPage": "/assets/gadget/list"
+ },
+ "features": {
+ "assetTypesHotDelploy": {
+ "enabled": false
+ }
+ },
+ "assets":["gadget","site", "deviceType"],
+ "disabledAssets":[],
+ "userRoles": ["Internal/publisher"],
+ "permissions": {
+ "login": {
+ "/permission/admin/login": ["ui.execute"]
+ }
+ },
+ "userSpace": "/_system/governance/users",
+ "accessible": [{
+ "context": "/_system/governance",
+ "collections": ["gadgets", "sites", "ebooks", "deviceTypes"],
+ "actions": ["http://www.wso2.org/projects/registry/actions/get", "http://www.wso2.org/projects/registry/actions/add", "http://www.wso2.org/projects/registry/actions/delete", "authorize"]
+ }],
+ "app": {
+ "RXT_MANAGER": "rxt_manager",
+ "ROUTE_MANAGER": "route_manager",
+ "MODEL_MANAGER": "model_manager"
+ },
+ "paths": {
+ "ASSET_EXT_PATH": "/assets",
+ "ASSET_DEFAULT_PATH": "/assets/default",
+ "ASSETS_EXT_PATH": "/assets",
+ "ASSETS_DEFAULT_PATH": "/assets/default",
+ "RXT_EXTENSION_PATH": "/config/ext/"
+ },
+ "urls": {
+ "ASSET": "/asset",
+ "ASSETS": "/assets"
+ },
+ "defaultAssets": {
+ "root": "/samples/assets",
+ "assetData": [{
+ "type": "gadgets",
+ "ignore": ["agricultural-land", "intro-gadget-1", "intro-gadget-2", "gadget-template-explorer", "gadget-explorer", "co2-emission", "electric-power", "energy-use", "greenhouse-gas"]
+ }, {
+ "type": "ebooks"
+ }, {
+ "type": "sites"
+ }, {
+ "type": "deviceTypes"
+ }]
+ },
+ "router": {
+ "RENDERER": "/modules/router.caramel-renderer.js"
+ }
+}
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/asset.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/asset.jag
new file mode 100644
index 0000000000..6598a893f0
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/asset.jag
@@ -0,0 +1,93 @@
+<%
+/*
+ * Copyright (c) WSO2 Inc. (http://wso2.com) All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ Description :to route api calls to endpoints
+ Filename: assets.jag
+
+ */
+var log = new Log('assets_api_router');
+var matcher = new URIMatcher(request.getRequestURI());
+var apiEndpoint = '/{context}/apis/{+suffix}';
+var asset = require('rxt').asset;
+var req = require('utils').request;
+var responseProcessor = require('utils').response;
+var response = response;
+response.contentType = 'application/json';
+
+/**
+ * getPage context
+ * @param {uri} uri : request uri
+ */
+var getPage = function (uri) {
+ var comps = uri.split('/');
+ return comps.length > 0 ? comps[0] : null;
+};
+
+var mapper = function (path) {
+ return function () {
+ return path;
+ };
+};
+
+/**
+ * To rout to asset endpoints
+ * @param request The request object in the request call
+ * @param session The sessionID of the logged in user
+ * @param uriParams URI parameters sent in request
+ */
+var handleApiEndpoint = function (request, session, uriParams) {
+ var options = req.getQueryOptions(request.getQueryString());
+ var type = options.type;
+ var page = getPage(uriParams.suffix);
+ try {
+ var endPoints = asset.getAssetApiEndpoints(session, type);
+ var endpoint;
+ for (var index in endPoints) {
+ if (endPoints[index].url == page) {
+ endpoint = asset.getAssetApiEndpoint(type, endPoints[index].path);
+ }
+ }
+ if (endpoint) {
+ request.getMappedPath = mapper(endpoint);
+ include(endpoint);
+ } else {
+ response = responseProcessor.buildErrorResponse(response, 404, 'Unable to locate an api endpoint for the type: ' + type)
+ }
+ } catch (e) {
+ log.error(e);
+ response = responseProcessor.buildErrorResponse(response, 404, e);
+
+ }
+};
+
+var server = require('store').server;
+var user = server.current(session);
+//remove
+if (!user) {//unless user is authenticated
+ log.error('Auth failure');
+ response = responseProcessor.buildErrorResponse(response, constants.STATUS_CODES.UNAUTHORIZED, "Authorization Error");
+}
+else {
+ if (matcher.match(apiEndpoint)) {// if endpoint is defined
+ handleApiEndpoint(request, session, matcher.elements()); //route to the endpoint
+ }
+ else {
+ response = responseProcessor.buildErrorResponse(response, 404, 'Unable to route the request to an appropriate endpoint');
+ }
+}
+
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/assets.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/assets.jag
new file mode 100644
index 0000000000..91e7745066
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/assets.jag
@@ -0,0 +1,98 @@
+<%
+/*
+ * Copyright (c) WSO2 Inc. (http://wso2.com) All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ Description :to route api calls to endpoints
+ Filename: assets.jag
+
+ */
+var log = new Log('assets_api_router');
+var matcher = new URIMatcher(request.getRequestURI());
+var apiEndpoint = '/{context}/apis/{+suffix}';
+var asset = require('rxt').asset;
+var req = require('utils').request;
+var responseProcessor = require('utils').response;
+var response = response;
+response.contentType = 'application/json';
+/**
+ * getPage context
+ * @param {uri} uri : request uri
+ */
+var getPage = function(uri) {
+ var comps = uri.split('/');
+ return comps.length > 0 ? comps[0] : null;
+};
+var mapper = function(path) {
+ return function() {
+ return path;
+ };
+};
+var getDefaultAssetSearchEndpoint = function() {
+ return '/extensions/assets/default/apis/assets.jag';
+};
+/**
+ * To route to asset endpoints
+ * @param request The request object in the request call
+ * @param session The sessionID of the logged in user
+ * @param uriParams URI parameters sent in request
+ */
+var handleApiEndpoint = function(request, session, uriParams) {
+ var options = req.getQueryOptions(request.getQueryString());
+ var type = options.type;
+ var page = getPage(uriParams.suffix);
+ try {
+ if (type) {
+ var endPoints = asset.getAssetApiEndpoints(session, type);
+ var endpoint;
+ for (var index in endPoints) {
+ if (endPoints[index].url == page) {
+ endpoint = asset.getAssetApiEndpoint(type, endPoints[index].path);
+ }
+ }
+ } else {
+ if (request.getMethod() === 'GET') {
+ if(log.isDebugEnabled()){
+ log.debug('Using default search endpoint');
+ }
+ endpoint = getDefaultAssetSearchEndpoint();
+ } else {
+ throw 'Method ' + request.getMethod() + ' is not supported';
+ }
+ }
+ if (endpoint) {
+ request.getMappedPath = mapper(endpoint);
+ include(endpoint);
+ } else {
+ response = responseProcessor.buildErrorResponse(response, 404, 'Unable to locate an api endpoint for the type: ' + type)
+ }
+ } catch (e) {
+ log.error(e);
+ response = responseProcessor.buildErrorResponse(response, 404, e);
+ }
+};
+var server = require('store').server;
+var user = server.current(session);
+//remove
+if (!user) { //unless user is authenticated
+ log.error('Auth failure');
+ response = responseProcessor.buildErrorResponse(response, constants.STATUS_CODES.UNAUTHORIZED, "Authorization Error");
+} else {
+ if (matcher.match(apiEndpoint)) { // if endpoint is defined
+ handleApiEndpoint(request, session, matcher.elements()); //route to the endpoint
+ } else {
+ response = responseProcessor.buildErrorResponse(response, 404, 'Unable to route the request to an appropriate endpoint');
+ }
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/authenticate.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/authenticate.jag
new file mode 100644
index 0000000000..3bd37c3ad2
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/authenticate.jag
@@ -0,0 +1,106 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/**
+ * Description: The API accepts a set of credentials which it attempts to verify.If the
+ provided credentials are authenticated , the logged in user is set to the provided
+ username and the session id is returned.If the authentication fails then the
+ a message indicating the failure is returned.
+
+ E.g. invocation
+ POST /api/authenticate
+ username={name}
+ password={password}
+ */
+var log = new Log('login-api');
+var user = require('store').user;
+var constants = require("rxt").constants;
+var credentials = {};
+var result = {};
+var METHOD = request.getMethod();
+var responseProcessor = require('utils').response;
+response.contentType = 'application/json';
+var SESSION_MAP = 'sso_sessions'; //We need to create the session map as it is required by the session listener
+
+/**
+ * The function adds the session to a session map.If a session map is not present
+ * in the application context it is added
+ * @param app :Application context
+ * @param sessionInstance :The session to be added
+ */
+var addToSessionMap = function (app, sessionInstance) {
+ var ssoSessions = app.get(SESSION_MAP);
+ var sessionId = sessionInstance.getId();
+ if (!ssoSessions) {
+ app.put(SESSION_MAP, {});
+ ssoSessions = app.get(SESSION_MAP);
+ if (log.isDebugEnabled){
+ log.debug('Created session as session was not present');
+ }
+ }
+ if (!ssoSessions[sessionId]) {
+ ssoSessions[sessionId] = '';
+ if (log.isDebugEnabled){
+ log.debug('Added session: ' + sessionId + ' to session map');
+ }
+ } else {
+ log.warn('Session already exists in the session map');
+ }
+};
+
+switch (METHOD) {
+ case 'POST'://request method is POST
+ //TODO change the authorization model to oauth or a proper on
+ //this is a temporary authorization logic, will be finalized after discussions
+ credentials.username = request.getParameter('username');
+ credentials.password = request.getParameter('password');
+ //Check if a username and password is provided
+ if ((!credentials.username) || (!credentials.password)) {
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.BAD_REQUEST, 'error on authentication api', response, 'Username and Password must be provided', '', []);
+
+
+ } else {
+ try{
+ var isAuthenticated = user.login(credentials.username, credentials.password, session);//authenticate the user
+ if (isAuthenticated) {
+ session.put("LOGGED_IN_USER", credentials.username);
+ session.put("Logged", "true");
+
+ //Add to the session map as it is required by the session listener
+ addToSessionMap(application, session);
+ response = responseProcessor.buildSuccessResponse(response, constants.STATUS_CODES.OK, {'sessionId': session.getId()});
+ }
+ else {
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.UNAUTHORIZED, 'error on authentication api', response, 'username/password is incorrect', '', []);
+
+ }
+ }catch(e){
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.NOT_FOUND, 'error on authentication api', response, 'Non existing domain name',e.message, []);
+
+ }
+
+ }
+ break;
+
+ default:// other methods
+ result = responseProcessor.buildErrorResponse(response, constants.STATUS_CODES.BAD_REQUEST, 'Your request malformed!');
+}
+
+%>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/lifecycles.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/lifecycles.jag
new file mode 100644
index 0000000000..b3abed2f9d
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/lifecycles.jag
@@ -0,0 +1,97 @@
+<%
+/*
+ * Copyright (c) WSO2 Inc. (http://wso2.com) All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ Description: Invoke routed api endpoints
+ * ENDPOINTS: /apis/lifecycles/
+ /apis/lifecycles/{lifecycleName}
+ /apis/lifecycles/{lifecycleName}/{currentState}
+ */
+
+require('/modules/publisher.js').exec(function (ctx) {
+ var log = new Log('lifecycle-api');
+
+ var utils = require('utils');
+ var rxt = require('rxt');
+ var lcCore = require('lifecycle').core;
+ var lcApi = require('/modules/lifecycle/lifecycle-api.js').api;
+ var server = require('store').server;
+ var assetApi = require('/modules/asset-api.js').api;
+
+ var ref = utils.request;
+ var responseProcessor = utils.response;
+ var constants = rxt.constants;
+
+ var response = ctx.response;
+ var req = ctx.request;
+ var session = ctx.session;
+ var tenantId = server.current(session).tenantId;
+ var uriMatcher = new URIMatcher(ctx.request.getRequestURI());
+
+ var method = req.getMethod();
+ var options = ref.getQueryOptions(req.getQueryString());
+ response.contentType = 'application/json';
+ var lifecycleName = '';
+
+ switch (method) {
+ case 'GET':
+ if (uriMatcher.match(constants.GET_LIFECYCLES_URL)) {
+ // to return available lifecycle list
+ try {
+ var lcList = lcApi.getLifecycles(options, req, response, session);
+ //call lifecycle module to get list
+ response = responseProcessor.buildSuccessResponse(response, constants.STATUS_CODES.OK, lcList);// return list
+ } catch (e) {
+ log.error(e);
+ response = responseProcessor.buildErrorResponse(response, e.code, e.message);//return error response
+ }
+
+ } else if (uriMatcher.match(constants.GET_LIFECYCLE_DEFINITION_BY_NAME_URL)) {
+ // to return lifecycle definition by name
+ try {
+ options.name = uriMatcher.elements().lifecycleName;// required lifecycle's name
+ var lcDefinition = lcApi.getLifecycle(options, req, response, session);
+ //call lifecycle module to get definition
+ response = responseProcessor.buildSuccessResponse(response, constants.STATUS_CODES.OK, lcDefinition);//send response
+ } catch (e) {
+ log.error(e);
+ response = responseProcessor.buildErrorResponse(response, e.code, e.messagee);//send error response
+ }
+
+ } else if (uriMatcher.match(constants.GET_LIFECYCLE_STATE_URL)) {
+ //to return details on lifecycle state of a lifecycle definition
+ options.name = uriMatcher.elements().lifecycleName;//set lifecycle name
+ var currentState = uriMatcher.elements().currentState;//set required state name
+ try {
+ var lc = lcApi.getLifecycle(options, req, response, session);
+ //call lifecycle module to get state details
+ var state = lc.state(currentState);
+ response = responseProcessor.buildSuccessResponse(response, constants.STATUS_CODES.OK, state);
+ } catch (e) {
+ log.error(e);
+ response = responseProcessor.buildErrorResponse(response, e.code, e.message);
+ }
+
+ } else {//unimplemented http GET endpoint
+ response = responseProcessor.buildErrorResponse(response, constants.STATUS_CODES.NOT_IMPLEMENTED, 'Unable to locate this GET endpoint!');
+ }
+ break;
+
+ default://unimplemented http request method
+ response = responseProcessor.buildErrorResponse(response, constants.STATUS_CODES.NOT_IMPLEMENTED, 'Unable to locate this endpoint for ' + method)
+ }
+}, request, response, session);
+%>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/logout.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/logout.jag
new file mode 100644
index 0000000000..4c8b72fd1d
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/logout.jag
@@ -0,0 +1,47 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+/**
+ * Description: The session of the currently authenticated user is invalidated
+ E.g. Invocation
+ POST /api/logout
+ */
+var log = new Log('logout-api');
+var result = {};
+var method = request.getMethod();
+var constants = require("rxt").constants;
+var responseProcessor = require('utils').response;
+response.contentType = 'application/json';
+
+switch (method) {
+ case 'POST':
+ try {
+ var user = require('store').user;//get current user
+ user.logout();
+ session.invalidate();
+ response = responseProcessor.buildSuccessResponse(response, constants.STATUS_CODES.OK, {'message': 'User Logged out successfully'});
+ }
+ catch (e) {
+ response = responseProcessor.buildErrorResponse(response, constants.STATUS_CODES.INTERNAL_SERVER_ERROR, 'Unable to logout user!');
+ }
+ break;
+ default:
+ result = responseProcessor.buildErrorResponse(response, constants.STATUS_CODES.BAD_REQUEST, 'Your request is malformed');
+}
+%>
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/partials.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/partials.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/partials.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/partials.jag
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/statistics.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/statistics.jag
new file mode 100644
index 0000000000..a99fc7afa1
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/statistics.jag
@@ -0,0 +1,95 @@
+<%
+/*
+ * Copyright (c) WSO2 Inc. (http://wso2.com) All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ Description :to route api calls to endpoints
+ Filename: assets.jag
+
+ */
+var log = new Log('statistics_api_router');
+var matcher = new URIMatcher(request.getRequestURI());
+var apiEndpoint = '/{context}/apis/{+suffix}';
+var asset = require('rxt').asset;
+var req = require('utils').request;
+var constants = require('rxt').constants;
+var responseProcessor = require('utils').response;
+var response = response;
+response.contentType = 'application/json';
+
+/**
+ * getPage context
+ * @param {uri} uri : request uri
+ */
+var getPage = function (uri) {
+ var comps = uri.split('/');
+ return comps.length > 0 ? comps[0] : null;
+};
+
+var mapper = function (path) {
+ return function () {
+ return path;
+ };
+};
+
+/**
+ * To rout to asset endpoints
+ * @param request The request object in the request call
+ * @param session The sessionID of the logged in user
+ * @param uriParams URI parameters sent in request
+ */
+var handleApiEndpoint = function (request, session, uriParams) {
+ var options = req.getQueryOptions(request.getQueryString());
+ var type = options.type;
+ var page = getPage(uriParams.suffix);
+
+ try {
+ var endPoints = asset.getAssetApiEndpoints(session, type);
+ var endpoint;
+ for (var index in endPoints) {
+ if (endPoints[index].url == page) {
+ endpoint = asset.getAssetApiEndpoint(type, endPoints[index].path);
+ }
+ }
+ if (endpoint) {
+ request.getMappedPath = mapper(endpoint);
+ include(endpoint);
+ } else {
+ response = responseProcessor.buildErrorResponse(response, 404, 'Unable to locate an api endpoint for the type: ' + type)
+ }
+ } catch (e) {
+ log.error(e);
+ response = responseProcessor.buildErrorResponse(response, 404, e);
+
+ }
+};
+
+var server = require('store').server;
+var user = server.current(session);
+//remove
+if (!user) {//unless user is authenticated
+ log.error('Auth failure');
+ response = responseProcessor.buildErrorResponse(response, constants.STATUS_CODES.UNAUTHORIZED, "Authorization Error");
+}
+else {
+ if (matcher.match(apiEndpoint)) {// if endpoint is defined
+ handleApiEndpoint(request, session, matcher.elements()); //route to the endpoint
+ }
+ else {
+ response = responseProcessor.buildErrorResponse(response, 404, 'Unable to route the request to an appropriate endpoint');
+ }
+}
+
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/tags.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/tags.jag
new file mode 100644
index 0000000000..e99b6ced56
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/apis/tags.jag
@@ -0,0 +1,52 @@
+<%
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+require('/modules/publisher.js').exec(function (ctx) {
+ var utils = require('utils');
+ var rxt = require('rxt');
+ var ref = utils.request;
+ var GET_TAGS_PATTERN = '/{context}/apis/tags';
+ var responseProcessor = utils.response;
+ var constants = rxt.constants;
+ var response = ctx.response;
+ var req = ctx.request;
+ var uriMatcher = new URIMatcher(ctx.request.getRequestURI());
+ var method = req.getMethod();
+ var options = ref.getQueryOptions(req.getQueryString());
+ var asset = rxt.asset;
+ var assetManager = asset.createUserAssetManager(ctx.session, options.type);
+ var tagsResults;
+ var log = new Log();
+ switch (method) {
+ case 'GET':
+ if (uriMatcher.match(GET_TAGS_PATTERN)) {
+ var query;
+ var q = ctx.request.getParameter('q');
+ if (q) {
+ var qString = '{' + q + '}';
+ query = utils.request.validateQuery(qString);
+ }
+ print(assetManager.tags(query));
+ }
+ break;
+ default:
+ response = responseProcessor.buildErrorResponse(response, constants.STATUS_CODES.NOT_IMPLEMENTED, 'Unable to locate this endpoint for ' + method)
+ }
+}, request, response, session);
+%>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/app.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/app.js
new file mode 100644
index 0000000000..7be92dbdbb
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-apis/app.js
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+app.server = function(ctx) {
+ return {
+ endpoints: {
+ apis: [{
+ url: 'assets',
+ path: 'assets.jag',
+ secured: true
+ }, {
+ url: 'lifecycles',
+ path: 'lifecycles.jag',
+ secured: true
+ },{
+ url: 'tags',
+ path: 'tags.jag',
+ secured: true
+ }, {
+ url: 'asset',
+ path: 'asset.jag',
+ secured: true
+ }, {
+ url: 'authenticate',
+ path: 'authenticate.jag'
+ }, {
+ url: 'logout',
+ path: 'logout.jag'
+ }, {
+ url: 'statistics',
+ path: 'statistics.jag'
+ }, {
+ url: 'partials',
+ path: 'partials.jag'
+ }]
+ }
+ };
+};
+app.apiHandlers = function(ctx) {
+ return {
+ onApiLoad: function() {
+ if ((ctx.isAnonContext) && (ctx.endpoint.secured)) {
+ print('{ error:"Authentication error" }'); //TODO: Fix this to return a proper status code
+ return false;
+ }
+ return true;
+ }
+ };
+};
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/app.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/app.js
new file mode 100644
index 0000000000..08e04108ec
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/app.js
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+app.server = function(ctx) {
+ return {
+ endpoints: {
+ pages: [{
+ title: 'Publisher | Splash page',
+ url: 'splash',
+ path: 'splash.jag'
+ },{
+ url:'sso-login',
+ path:'sso-auth-login-controller.jag'
+ },{
+ url:'basic-auth-login',
+ path:'basic-auth-login-controller.jag'
+ },{
+ url:'sso-logout',
+ path:'sso-auth-logout-controller.jag'
+ },{
+ url:'basic-auth-logout',
+ path:'basic-auth-logout-controller.jag'
+ },{
+ url:'basic-authenticator',
+ path:'basic-authenticator.jag'
+ },{
+ title:'Advanced Search',
+ url:'advanced-search',
+ path:'advanced-search.jag'
+ }]
+ },
+ configs: {
+ landingPage: '/assets/gadget/list',
+ disabledAssets: ['ebook', 'api', 'wsdl', 'service','policy','proxy','schema','sequence','servicex','uri','wadl','endpoint','swagger','restservice','comments','soapservice'],
+ uiDisabledAssets: []
+ },
+ onLoadedServerConfigs:function(configs){
+ }
+ }
+};
+
+app.renderer = function(ctx) {
+ var decoratorApi = require('/modules/page-decorators.js').pageDecorators;
+ return {
+ pageDecorators: {
+ navigationBar: function(page) {
+ return decoratorApi.navigationBar(ctx, page, this);
+ }
+ }
+ }
+};
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/pages/advanced-search.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/pages/advanced-search.jag
new file mode 100644
index 0000000000..6f6a4fe442
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/pages/advanced-search.jag
@@ -0,0 +1,37 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+var caramel;
+require('/modules/publisher.js').exec(function(ctx) {
+ caramel = require('caramel');
+ var app = require('rxt').app;
+ var constants = require('rxt').constants;
+ var server = require('store').server;
+ var user = server.current(ctx.session);
+ var ui = require('rxt').ui;
+ var page = ui.buildPage(ctx.session, ctx.request);
+ var appManager;
+
+ appManager = app.createUserAppManager(session);
+ var output = appManager.render([], page);
+ caramel.render(output);
+
+
+}, request, response, session);
+%>
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/basic-auth-login-controller.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/pages/basic-auth-login-controller.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/basic-auth-login-controller.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/pages/basic-auth-login-controller.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/basic-auth-logout-controller.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/pages/basic-auth-logout-controller.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/basic-auth-logout-controller.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/pages/basic-auth-logout-controller.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/basic-authenticator.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/pages/basic-authenticator.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/basic-authenticator.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/pages/basic-authenticator.jag
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/pages/splash.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/pages/splash.jag
new file mode 100644
index 0000000000..7a9a91583e
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/pages/splash.jag
@@ -0,0 +1,21 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+ print('This is a splash page!');
+%>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/pages/sso-auth-login-controller.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/pages/sso-auth-login-controller.jag
new file mode 100644
index 0000000000..f2ea6e74e7
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/pages/sso-auth-login-controller.jag
@@ -0,0 +1,59 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+(function(){
+ var config = require('/config/publisher.js').config();
+ var sso = require("sso");
+ var sessionId = session.getId();
+ var requestedPage = request.getParameter("requestedPage");
+ var referer=request.getHeader('referer');
+ var ignoreReferer = request.getParameter("ignoreReferer");
+ var attr = config.authentication.methods.sso.attributes;
+ var encodedSAMLAuthRequest = sso.client.getEncodedSAMLAuthRequest(attr.issuer);
+ var log = new Log();
+ var postUrl = attr.identityProviderURL;
+ if(log.isDebugEnabled()) {
+ log.debug('Login URL: '+postUrl);
+ }
+ if(ignoreReferer){
+ referer = null;
+ }
+ var relayState = (referer? referer:'/publisher');
+
+ if (!session.get("Loged")) {
+ %>
+
+
You are now being redirected to Identity Server. If the
+ redirection fails, please click on the button below.
+
+
+
+ <%
+ }
+}());
+%>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/pages/sso-auth-logout-controller.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/pages/sso-auth-logout-controller.jag
new file mode 100644
index 0000000000..0dc460f84f
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/pages/sso-auth-logout-controller.jag
@@ -0,0 +1,64 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+(function(){
+ var user = session.get("LOGGED_IN_USER");//require('store').server.current(session).username;
+ var caramel = require('caramel');
+ var context = caramel.configs().context;
+ var log = new Log("sso-auth-logout-controller");
+ if(user === null) {
+ response.sendRedirect(context);
+ } else {
+ var config = require('/config/publisher.js').config(),
+ sso = require('sso'),
+ sso_sessions = application.get('sso_sessions'),
+ sessionId = session.getId(),
+ attr = config.authentication.methods.sso.attributes,
+ encodedSAMLLogoutRequest = sso.client.getEncodedSAMLLogoutRequest(user, sso_sessions[session.getId()], attr.issuer),
+ postUrl = attr.identityProviderURL,
+ ignoreReferer = request.getParameter("ignoreReferer"),
+ relayState = request.getHeader('referer') ? request.getHeader('referer') : caramel.configs().context;
+
+ relayState = (!ignoreReferer) ? relayState : context + '/login?ignoreReferer=true';
+
+ log.debug("portal session index : " + sso_sessions[session.getId()]);
+ session.invalidate();
+ %>
+
+
You are now redirected to Stratos Identity. If the
+ redirection fails, please click the post button.
+
+
+
+
+
+ <%
+ }
+}());
+%>
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/css/basic-login-header.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/css/basic-login-header.css
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/css/basic-login-header.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/css/basic-login-header.css
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/helpers/advanced-search-body.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/helpers/advanced-search-body.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/helpers/advanced-search-body.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/helpers/advanced-search-body.js
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/helpers/basic-login-form.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/helpers/basic-login-form.js
new file mode 100644
index 0000000000..f759b6d1e9
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/helpers/basic-login-form.js
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+var resources = function(){
+ return {
+ js:['libs/jquery.form.min.js','basic-login.js'],
+ css:['basic-login-header.css']
+ }
+};
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/js/advance-search-api.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/js/advance-search-api.js
new file mode 100644
index 0000000000..71c394fc28
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/js/advance-search-api.js
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+$(function(){
+ var SEARCH_API = '/apis/assets?q=';
+ var SEARCH_BUTTON = '#search-btn';
+ var SEARCH_FORM = '#search-form';
+ var rows_added = 0;
+ var last_to = 0;
+ var items_per_row = 0;
+ var doPagination = true;
+ store.infiniteScroll ={};
+ store.infiniteScroll.recalculateRowsAdded = function(){
+ return (last_to - last_to%items_per_row)/items_per_row;
+ };
+ store.infiniteScroll.addItemsToPage = function(query){
+
+ var screen_width = $(window).width();
+ var screen_height = $(window).height();
+
+
+ var header_height = 400;
+ var thumb_width = 170;
+ var thumb_height = 280;
+ var gutter_width = 20;
+
+ screen_width = screen_width - gutter_width; // reduce the padding from the screen size
+ screen_height = screen_height - header_height;
+
+ items_per_row = (screen_width-screen_width%thumb_width)/thumb_width;
+ //var rows_per_page = (screen_height-screen_height%thumb_height)/thumb_height;
+ var scroll_pos = $(document).scrollTop();
+ var row_current = (screen_height+scroll_pos-(screen_height+scroll_pos)%thumb_height)/thumb_height;
+ row_current +=3 ; // We increase the row current by 2 since we need to provide one additional row to scroll down without loading it from backend
+
+
+ var from = 0;
+ var to = 0;
+ if(row_current > rows_added && doPagination){
+ from = rows_added * items_per_row;
+ to = row_current*items_per_row;
+ last_to = to; //We store this os we can recalculate rows_added when resolution change
+ rows_added = row_current;
+ store.infiniteScroll.getItems(from,to,query);
+ //console.info('getting items from ' + from + " to " + to + " screen_width " + screen_width + " items_per_row " + items_per_row);
+ }
+
+ };
+ store.infiniteScroll.getItems = function(from, to, query ){
+ var count = to-from;
+ var dynamicData = {};
+ dynamicData["from"] = from;
+ dynamicData["to"] = to;
+ var path = window.location.href; //current page path
+ // Returns the jQuery ajax method
+ var url = caramel.tenantedUrl(SEARCH_API+query+"&paginationLimit=" + to + "&start="+from+"&count="+count);
+
+ caramel.render('loading','Loading assets from ' + from + ' to ' + to + '.', function( info , content ){
+ $('.loading-animation-big').remove();
+ $('body').append($(content));
+ });
+
+ $.ajax({
+ url:url,
+ method:'GET',
+ success:function(data){
+ var results = [];
+ if(data){
+ results = data.list || [];
+ }
+ for(var i = 0; i < results.length; i++){
+ results[i].showType = true;
+ }
+ if(results.length==0) {
+ if(from == 0) {
+ $('#search-results').html('We are sorry but we could not find any matching assets');
+ }
+ $('.loading-animation-big').remove();
+ doPagination = false;
+ } else {
+ loadPartials('list-assets', function(partials) {
+ caramel.partials(partials, function () {
+ caramel.render('list_assets_table_body', results, function (info, content) {
+ $('#search-results').append($(content));
+ $('.loading-animation-big').remove();
+ });
+ });
+ });
+ }
+ },error:function(){
+ doPagination = false;
+ $('.loading-animation-big').remove();
+ }
+ });
+ };
+ store.infiniteScroll.showAll = function(query){
+ store.infiniteScroll.addItemsToPage(query);
+ $(window).scroll(function(){
+ store.infiniteScroll.addItemsToPage(query);
+ });
+ $(window).resize(function () {
+ //recalculate "rows_added"
+ rows_added = store.infiniteScroll.recalculateRowsAdded();
+ store.infiniteScroll.addItemsToPage(query);
+ });
+ };
+
+ var processInputField = function(field){
+ var result = field;
+ switch(field.type) {
+ case 'text':
+ result = field;
+ break;
+ default:
+ break;
+ }
+ return result;
+ };
+ var getInputFields = function(){
+ var obj = {};
+ var fields = $(SEARCH_FORM).find(':input');
+ var field;
+ for(var index = 0; index < fields.length; index++){
+ field = fields[index];
+ field = processInputField(field);
+ if((field.name)&&(field.value)){
+ obj[field.name] = field.value;
+ }
+ }
+ return obj;
+ };
+ var createQueryString = function(key,value){
+ return '"'+key+'":"'+value+'"';
+ };
+ var buildQuery = function(){
+ var fields = getInputFields();
+ var queryString =[];
+ var value;
+ for(var key in fields){
+ value = fields[key];
+ queryString.push(createQueryString(key,value));
+ }
+ return queryString.join(',');
+ };
+ var isEmptyQuery = function(query) {
+ query = query.trim();
+ return (query.length <= 0);
+ };
+ var loadPartials = function (partial, done) {
+ $.ajax({
+ url: caramel.url('/apis/partials') + '?partial=' + partial,
+ success: function (data) {
+ done(data);
+ },
+ error: function () {
+ done(err);
+ }
+ });
+ };
+ $(SEARCH_BUTTON).on('click',function(e){
+ e.preventDefault();
+ doPagination = true;
+ rows_added = 0;
+ $('#search-results').html('');
+ var query = buildQuery();
+ if(isEmptyQuery(query)) {
+ console.log('User has not entered anything');
+ return;
+ }
+ store.infiniteScroll.showAll(query);
+ });
+});
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/js/basic-login.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/js/basic-login.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/js/basic-login.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/js/basic-login.js
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/partials/advanced-search-body.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/partials/advanced-search-body.hbs
new file mode 100644
index 0000000000..724c7ec2b6
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/partials/advanced-search-body.hbs
@@ -0,0 +1,22 @@
+
+
+
+
+ {{> advanced-search-results .}}
+
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/advanced-search-buttons.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/partials/advanced-search-buttons.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/advanced-search-buttons.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/partials/advanced-search-buttons.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/advanced-search-results.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/partials/advanced-search-results.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/advanced-search-results.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/partials/advanced-search-results.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/basic-login-form.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/partials/basic-login-form.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/basic-login-form.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/partials/basic-login-form.hbs
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/partials/basic-login-header.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/partials/basic-login-header.hbs
new file mode 100644
index 0000000000..798f2bb3d4
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/partials/basic-login-header.hbs
@@ -0,0 +1,10 @@
+
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/extended-search-attributes.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/partials/extended-search-attributes.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/extended-search-attributes.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/partials/extended-search-attributes.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/primary-search-attributes.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/partials/primary-search-attributes.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/primary-search-attributes.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/partials/primary-search-attributes.hbs
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/renderers/pages/advanced-search.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/renderers/pages/advanced-search.js
new file mode 100644
index 0000000000..34f673ca38
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/renderers/pages/advanced-search.js
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+var render = function(theme, data, meta, require) {
+ theme('single-col-fluid', {
+ title: 'Asset',
+ header: [{
+ partial: 'header',
+ context: data
+ }],
+ ribbon: [{
+ partial: 'ribbon',
+ context: data
+ }],
+ // leftnav: [{
+ // partial:'left-nav',
+ // context:data
+ // }],
+ listassets: [{
+ partial: 'advanced-search-body',
+ context: data
+ }]
+ });
+};
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/renderers/pages/basic-auth-login-controller.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/renderers/pages/basic-auth-login-controller.js
new file mode 100644
index 0000000000..48039407a8
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/themes/default/renderers/pages/basic-auth-login-controller.js
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+var render = function(theme, data, meta, require) {
+ theme('single-col-fluid', {
+ title: 'Publisher Login',
+ header: [{
+ partial: 'basic-login-header',
+ context: data
+ }],
+ listassets: [{
+ partial: 'basic-login-form',
+ context: data
+ }]
+ });
+};
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/workflows/self_signup.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/workflows/self_signup.js
new file mode 100644
index 0000000000..fe7396a879
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-common/workflows/self_signup.js
@@ -0,0 +1,7 @@
+ var log = new Log();
+ var execute = function(req, res, session) {
+ log.info('Executing the self sign up')
+ };
+ var process = function(req, res, session) {
+ log.info('Processing the self sign up');
+ };
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-device-type/app.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-device-type/app.js
new file mode 100644
index 0000000000..04a227dbc0
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-device-type/app.js
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+app.dependencies = ['publisher-common'];
+app.server = function(ctx) {
+ return {
+ endpoints: {
+ //pages: [{
+ // title: 'Publisher | Servicex Page',
+ // url: 'devices_global',
+ // path: 'device_global.jag'
+ //}, {
+ // title: 'Publisher | Servicex Splash page',
+ // url: 'devices',
+ // path: 'device_top_assets.jag'
+ //}]
+ },
+ configs:{
+ landingPage:'/assets/deviceType/list',
+ disabledAssets:['ebook', 'api', 'wsdl', 'service','policy','proxy','schema','sequence','servicex','uri','wadl','endpoint','swagger','restservice','comments','soapservice', 'license', 'gadget', 'site', 'server']
+ }
+ }
+};
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-device-type/pages/device_global.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-device-type/pages/device_global.jag
new file mode 100644
index 0000000000..265423784a
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-device-type/pages/device_global.jag
@@ -0,0 +1,6 @@
+
+
+
+ New Global Page
+
+
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-device-type/pages/device_top_assets.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-device-type/pages/device_top_assets.jag
new file mode 100644
index 0000000000..2aae610221
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/app/publisher-device-type/pages/device_top_assets.jag
@@ -0,0 +1,6 @@
+
+
+
+ Overriden Top Assets Page
+
+
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/apis/asset.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/apis/asset.jag
new file mode 100644
index 0000000000..3d47350dbc
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/apis/asset.jag
@@ -0,0 +1,54 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+require('/modules/publisher.js').exec(function(ctx) {
+ var log = new Log();
+ var assetActionAPI = require('/modules/asset-action-api.js').api;
+ var utils = require('utils');
+ var ref = utils.request;
+ var reflectionAPI = utils.reflection;
+ var responseProcessor = utils.response;
+ var ACTION_PATTERN = '/{context}/apis/asset/{id}/{action}';
+ var uriMatcher = new URIMatcher(ctx.request.getRequestURI());
+ var req = ctx.request;
+ var qOptions = ref.getQueryOptions(req.getQueryString());
+ var options = uriMatcher.match(ACTION_PATTERN);
+ var result = {};
+ var response = ctx.response;
+ if (!options.id) {
+ response.sendError(404, 'Asset not found');
+ return;
+ }
+ //options.type = qOptions.type;
+ //Merge the query parameters and the URI pattern components
+ reflectionAPI.copyProps(qOptions,options);
+ try {
+ result = assetActionAPI.resolve(ctx.request, ctx.response, ctx.session, options);
+ } catch (e) {
+ log.error(e);
+ result.success = false;
+ result.code = 500;
+ result.message = 'Oops, something has gone wrong.Check the server logs for more information.';
+ }
+ if (result.success) {
+ response = responseProcessor.buildSuccessResponse(response, result.code, result.data);
+ } else {
+ response = responseProcessor.buildErrorResponse(response, result.code, result.message);
+ }
+}, request, response, session); %>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/apis/assets.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/apis/assets.jag
new file mode 100644
index 0000000000..9dd66b5a20
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/apis/assets.jag
@@ -0,0 +1,275 @@
+<%
+/*
+ * Copyright (c) WSO2 Inc. (http://wso2.com) All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ Description: Invoke routed api endpoints
+ Filename : assets.jag
+ * can be extended by asset type
+
+ ENDPOINTS:
+ GET
+ /apis/assets/
+ /apis/assets/{id}
+ /apis/assets/{id}/state
+
+ POST
+ /apis/assets/
+ /apis/assets/{id}
+ /apis/assets/{id}/state
+
+ DELETE
+ /apis/assets/{id}
+
+ */
+
+
+require('/modules/publisher.js').exec(function (ctx) {
+ var log = new Log('asset_api_endpoints');
+ var ref = require('utils').request;
+ var responseProcessor = require('utils').response;
+ var res = ctx.response;
+ var req = ctx.request;
+ var session = ctx.session;
+ var uriMatcher = new URIMatcher(req.getRequestURI());
+ var assetApi = require('/modules/asset-api.js').api;
+ var lcApi = require('/modules/lifecycle/lifecycle-api.js').api;
+ var CREATE_URL = '/{context}/apis/assets/';
+ var UPDATE_URL = '/{context}/apis/assets/{id}';
+ var LIST_ASSETS_URL = '/{context}/apis/assets/';
+ var GET_ASSET_URL = '/{context}/apis/assets/{id}';
+ var DELETE_ASSET_URL = '/{context}/apis/assets/{id}';
+ var ASSET_STATE_URL = '/{context}/apis/assets/{id}/state';
+ var method = req.getMethod();
+ var options = ref.getQueryOptions(req.getQueryString());
+ var response;
+ //response.contentType = 'application/json';
+ var constants = require('rxt').constants;
+ var contentTypeheader, jsonHeader, multipartHeader, formHeader, acceptHeader, jsonHeaderAccept;
+ var addAsset = function (options, req, res, session) {
+ var requestURI = req.getRequestURI();
+ var newAsset = assetApi.create(options, req, res, session);
+ if (!newAsset) {
+ return responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.INTERNAL_SERVER_ERROR, 'error on create asset', res, 'Failed to create asset of type: ' + options.type, 'more information on create asset error', []);
+ }
+ response = responseProcessor.buildSuccessResponseDefault(constants.STATUS_CODES.CREATED, res, newAsset);
+ response.addHeader('Location', requestURI + '/' + newAsset.id + '?type=' + newAsset.type);
+ };
+ var updateAsset = function (options, req, res, session) {
+ var updatedAsset = assetApi.update(options, req, res, session);
+ if (!updatedAsset) {
+ return responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.NOT_FOUND, 'error on update api', res, 'No matching asset found by id : ' + options.id, 'this is more information', []);
+ }
+ response = responseProcessor.buildSuccessResponseDefault(constants.STATUS_CODES.ACCEPTED, res, updatedAsset);
+ };
+ var getAsset = function (options, req, res, session) {
+ var asset = assetApi.get(options, req, res, session);
+ if (!asset) {
+ return responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.NOT_FOUND, 'error on get api', res, 'No matching asset found by id : ' + options.id, 'this is more information', []);
+ }
+ response = responseProcessor.buildSuccessResponseDefault(constants.STATUS_CODES.OK, res, asset);
+ };
+ var deleteAsset = function (options, req, res, session) {
+ var done = assetApi.remove(options, req, res, session);
+ if (!done) {
+ return responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.NOT_FOUND, 'error on delete api', res, 'No matching asset found by id : ' + options.id, 'this is more information', []);
+ }
+ response = responseProcessor.buildSuccessResponseDefault(constants.STATUS_CODES.OK, res,
+ {'message':'Asset Deleted Successfully'});
+ };
+ var getAssetState = function (options, req, res, session) {
+ var state = lcApi.getState(options, req, res, session);
+ if (!state) {
+ return responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.NOT_FOUND, 'error on get lifecycle api', res, 'No matching lifecycle found for asset id : ' + options.id, 'this is more information', []);
+ }
+ response = responseProcessor.buildSuccessResponseDefaultLC(constants.STATUS_CODES.OK, res, state);
+ };
+ switch (method) {
+ case 'POST':// POST endpoints
+ if (uriMatcher.match(CREATE_URL)) {//to create asset
+ contentTypeheader = req.getHeader('Content-Type') || '';
+ jsonHeader = contentTypeheader.indexOf('application/json');
+ multipartHeader = contentTypeheader.indexOf('multipart/form-data');
+ formHeader = contentTypeheader.indexOf('application/x-www-form-urlencoded');
+ try {
+ if (!contentTypeheader) {
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.UNSUPPORTED_MEDIATYPE, 'error on create asset', res, 'Unsupported Media Type of creating ' + options.type, 'more information on create asset error', []);
+ return;
+ }
+ if (jsonHeader < 0 && multipartHeader < 0 && formHeader < 0) {
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.UNSUPPORTED_MEDIATYPE, 'error on create asset', res, 'Unsupported Media Type of creating ' + options.type, 'more information on create asset error', []);
+ return;
+ }
+ addAsset(options, req, res, session);
+ } catch (e) {
+ if (e.hasOwnProperty('message') && e.hasOwnProperty('code')) {
+ log.error("Error while creating asset for the request due to " + e.message);
+
+ response = responseProcessor.buildErrorResponseDefault(e.code, 'error on create asset', res,
+ 'Failed to create asset of type: ' + options.type, e.message, []);
+ return;
+ }
+ log.error(e.message, e);
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.INTERNAL_SERVER_ERROR, 'error on create asset', res, 'Failed to create asset of type: ' + options.type, 'more information on create asset error', []);
+ if (log.isDebugEnabled()) {
+ log.debug("Error while creating asset for the request : " + e);
+ }
+ }
+ } else if (uriMatcher.match(UPDATE_URL)) {//to update asset
+ contentTypeheader = req.getHeader('Content-Type') || '';
+ jsonHeader = contentTypeheader.indexOf('application/json');
+ multipartHeader = contentTypeheader.indexOf('multipart/form-data');
+ formHeader = contentTypeheader.indexOf('application/x-www-form-urlencoded');
+ options.id = uriMatcher.elements().id;
+ try {
+ if (!contentTypeheader) {
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.UNSUPPORTED_MEDIATYPE, 'error on update asset', res, 'Unsupported Media Type of updating ' + options.type, 'more information on update asset error', []);
+ return;
+ }
+ if (jsonHeader < 0 && multipartHeader < 0 && formHeader < 0) {
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.UNSUPPORTED_MEDIATYPE, 'error on update asset', res, 'Unsupported Media Type of updating ' + options.type, 'more information on update asset error', []);
+ return;
+ }
+ updateAsset(options, req, res, session);
+ } catch (e) {
+ if (e.hasOwnProperty('message') && e.hasOwnProperty('code')) {
+ log.error(e.message, e);
+ response = responseProcessor.buildErrorResponseDefault(e.code, 'error on update asset', res, 'Failed to update asset of asset: ' + options.id, e.message, []);
+ return;
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("Error while updating asset for the request : " + e);
+ return;
+ }
+ log.error(e.message, e);
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.INTERNAL_SERVER_ERROR, 'error on update asset', res, 'Failed to update asset of asset: ' + options.id, 'more information on update asset error', []);
+ }
+ } else if (uriMatcher.match(ASSET_STATE_URL)) {//change asset's LC state
+ var elements = uriMatcher.elements();
+ options.id = elements.id;
+ try {
+ var out = lcApi.invokeStateTransition(options, req, res, session);
+ response = responseProcessor.buildSuccessResponseDefaultLC(constants.STATUS_CODES.OK, res, out);
+ } catch (e) {
+ if (e.hasOwnProperty('message') && e.hasOwnProperty('code')) {
+ log.error(e.message, e);
+ response = responseProcessor.buildErrorResponseDefault(e.code, 'error on update asset life cycle', res, 'Failed to update asset lifecycle of asset: ' + options.id, e.message, []);
+ return;
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("Error while changing asset lifecycle for the request : " + e);
+ return;
+ }
+ log.error(e.message, e);
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.INTERNAL_SERVER_ERROR, 'error on update asset lifecycle of asset', res, 'Failed to update asset lifecycle of asset: ' + options.id, 'more information on update asset lifecycle error', []);
+ }
+ } else {
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.NOT_IMPLEMENTED, 'Not found API endpoints', res, 'Unable to locate this POST endpoint', 'this is more information about not implemented api', []);
+ }
+ break;
+ case 'GET':// GET endpoints
+ options.type = req.getParameter('type');
+ if (uriMatcher.match(LIST_ASSETS_URL)) {//return assets by type
+ //it always return */* when Accept header is not defined
+ acceptHeader = req.getHeader('Accept');
+ jsonHeaderAccept = acceptHeader.indexOf('application/json');
+ try {
+ if (jsonHeaderAccept >= 0 || acceptHeader === '*/*') {
+ var assets = [];
+ if(options.type) {
+ if(log.isDebugEnabled()){
+ log.debug('Type specific advanced search');
+ }
+ assets = assetApi.advanceSearch(options, req, res, session);
+ } else {
+ if(log.isDebugEnabled()){
+ log.debug('Generic advanced search');
+ }
+ assets = assetApi.genericAdvanceSearch(options,req,res,session);
+ }
+ response = responseProcessor.buildSuccessResponseDefault(constants.STATUS_CODES.OK, res, assets);
+ return;
+ }
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.NOT_ACCEPTABLE, 'error on get api', res, 'The requested media type is not supported', 'this is more information about accept header', []);
+ } catch (e) {
+ if (log.isDebugEnabled()) {
+ log.debug("Error while getting assets for the request : " + e);
+ return;
+ }
+ log.error(e.message, e);
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.INTERNAL_SERVER_ERROR, 'error on get assets', res, 'Failed to get assets', 'more information on get asset list error', []);
+ }
+ } else if (uriMatcher.match(GET_ASSET_URL)) {//return asset by id
+ options.id = uriMatcher.elements().id;
+ //it always return */* when Accept header is not defined
+ acceptHeader = req.getHeader('Accept');
+ jsonHeaderAccept = acceptHeader.indexOf('application/json');
+ try {
+ if (jsonHeaderAccept >= 0 || acceptHeader === '*/*') {
+ getAsset(options, req, res, session);
+ return;
+ }
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.NOT_ACCEPTABLE, 'error on get api', res, 'The requested media type is not supported or add content-type for request', 'this is more information about accept header', []);
+ } catch (e) {
+ if (log.isDebugEnabled()) {
+ log.debug("Error while getting a asset for the request : " + e);
+ return;
+ }
+ log.error(e.message, e);
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.INTERNAL_SERVER_ERROR, 'error on get asset', res, 'Failed to get asset', 'more information on get asset error', []);
+ }
+ //TODO life cycle get state
+ } else if (uriMatcher.match(ASSET_STATE_URL)) {//return asset state by id
+ try {
+ options.id = uriMatcher.elements().id;
+ acceptHeader = req.getHeader('Accept');
+ jsonHeaderAccept = acceptHeader.indexOf('application/json');
+ if (jsonHeaderAccept >= 0 || acceptHeader === '*/*') {
+ getAssetState(options, req, res, session);
+ return;
+ }
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.NOT_ACCEPTABLE, 'error on get api', res, 'The requested media type is not supported', 'this is more information about accept header', []);
+ } catch (e) {
+ if (e.hasOwnProperty('message') && e.hasOwnProperty('code')) {
+ log.error(e.message, e);
+ response = responseProcessor.buildErrorResponseDefault(e.code, 'error on get state asset', res, 'Failed to get state of asset: ' + options.id, e.message, []);
+ return;
+ }
+ log.error(e.message, e);
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.INTERNAL_SERVER_ERROR, 'error on get state asset', res, 'Failed to get state of asset: ' + options.id, 'more information on get state of asset error', []);
+ }
+ } else {
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.NOT_IMPLEMENTED, 'Not found API endpoints', res, 'Unable to locate this GET endpoint', 'this is more information about not implemented api', []);
+ }
+ break;
+ case 'DELETE': // DELETE endpoints
+ options.type = req.getParameter('type');
+ if (uriMatcher.match(DELETE_ASSET_URL)) {
+ try {
+ options.id = uriMatcher.elements().id;
+ deleteAsset(options, req, res, session);
+ } catch (e) {
+ log.error(e.message, e);
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.INTERNAL_SERVER_ERROR, 'error on delete API end points', res, 'Unable to Delete Asset of id:' + options.id, 'this more information', []);
+ }
+ } else {
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.NOT_IMPLEMENTED, 'Not found API endpoints', res, 'Unable to locate this GET endpoint', 'this is more information about not implemented api', []);
+ }
+ break;
+ default://other un-implemented endpoints
+ response = responseProcessor.buildErrorResponseDefault(constants.STATUS_CODES.NOT_IMPLEMENTED, 'Not Implemented API endpoints', res, 'The endpoint that you have requested is not implemented for the ' + method + ' method.Try making the request with the appropriate verb' + '(hint: create/update operations use POST).', []);
+ }
+}, request, response, session); %>
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/apis/statistics.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/apis/statistics.jag
new file mode 100644
index 0000000000..9a6749f57e
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/apis/statistics.jag
@@ -0,0 +1,64 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+require('/modules/publisher.js').exec(function(ctx) {
+ var log = new Log('statistics-api');
+ var ref = require('utils').request;
+ var options = ref.getQueryOptions(ctx.request.getQueryString());
+ var rxtModule = require('rxt');
+ var statsModule = require('/modules/statistics-api.js');
+ var storeModule = require('store');
+ var am;
+ var type = options.type;
+ var startDate = options.start||statsModule.getTodaysDate();
+ var endDate = options.end;
+ var onChoice = options.onchoice || false;
+ var userDetails = storeModule.server.current(ctx.session);
+ var username = userDetails.username;
+ var tenantId = userDetails.tenantId;
+ var output = {};
+ var statOptions = {};
+ statOptions.username = username;
+ statOptions.tenantId = tenantId;
+ statOptions.type = type;
+ statOptions.am = null;
+ if ((!type) || (!endDate)) {
+ ctx.response.sendError(500, 'Cannot retrieve statistics if both a type and end date are not provided');
+ } else {
+ //Fix to compensate issue with Datepicker plugin used in the client side
+ var tempEndDate = new Date(Date.parse(endDate.replace(/-/g, "/")));
+ tempEndDate.setDate(tempEndDate.getDate() + 1);
+ am = rxtModule.asset.createUserAssetManager(ctx.session, type);
+ statOptions.am = am;
+ statOptions.startDate = startDate;
+ statOptions.endDate = statsModule.normalizeDate(tempEndDate.toDateString());
+
+ //Create the structure of the output object
+ //Obtain the Bookmark statistics
+ var bookmarkResults = statsModule.getBookmarkAssetStats(statOptions);
+ output.bookmarkStats = bookmarkResults.bookmarkStats;
+ output.bookmarkTicks = bookmarkResults.bookmarkTicks;
+
+ //Obtain the Hot asset statistics
+ var hotResults = statsModule.getHotAssetStats(statOptions);
+ output.hotAssetStats = hotResults.hotAssetStats;
+ output.hotAssetTicks = hotResults.hotAssetTicks;
+ print(output);
+ }
+}, request, response, session); %>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/asset.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/asset.js
new file mode 100644
index 0000000000..360775fb07
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/asset.js
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) WSO2 Inc. (http://wso2.com) All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+asset.manager = function(ctx) {
+ var notifier = require('store').notificationManager;
+ var storeConstants = require('store').storeConstants;
+ var COMMENT = 'User comment';
+ var carbon = require('carbon');
+ var social = carbon.server.osgiService('org.wso2.carbon.social.core.service.SocialActivityService');
+ var log = new Log('default-asset');
+ return {
+ create: function(options) {
+ var ref = require('utils').time;
+ //Check if the options object has a createdtime attribute and populate it
+ if ((options.attributes) && ctx.rxtManager.getRxtField(ctx.assetType, 'overview_createdtime')) {
+ options.attributes.overview_createdtime = ref.getCurrentTime();
+ }
+ this._super.create.call(this, options);
+ var asset = this.get(options.id); //TODO avoid get: expensive operation
+ var assetPath = asset.path;
+ var user = ctx.username;
+ var userRoles = ctx.userManager.getRoleListOfUser(user);
+ try {
+ social.warmUpRatingCache(ctx.assetType + ':' + options.id);
+ } catch (e) {
+ log.warn("Unable to publish the asset: " + ctx.assetType + ":" + options.id + " to social cache. This may affect on sort by popularity function.");
+ }
+ //Check whether the user has admin role
+ var endpoint = storeConstants.PRIVATE_ROLE_ENDPOINT + user;
+ for (var role in userRoles) {
+ if (userRoles.hasOwnProperty(role) && userRoles[role] == storeConstants.ADMIN_ROLE) {
+ endpoint = storeConstants.ADMIN_ROLE_ENDPOINT;
+ }
+ }
+
+ var provider = ctx.username;
+
+ if(options.attributes.overview_provider){
+ provider = options.attributes.overview_provider;
+ }
+ provider = provider.replace(':', '@');
+ //Subscribe the asset author for LC update event and asset update event
+ notifier.subscribeToEvent(provider, assetPath, endpoint, storeConstants.LC_STATE_CHANGE);
+ notifier.subscribeToEvent(provider, assetPath, endpoint, storeConstants.ASSET_UPDATE);
+ },
+ update: function(options) {
+ this._super.update.call(this, options);
+ var asset = this.get(options.id); //TODO avoid get: expensive operation
+ //trigger notification on asset update
+ notifier.notifyEvent(storeConstants.ASSET_UPDATE_EVENT, asset.type, asset.name, null, asset.path, ctx.tenantId);
+ },
+ search: function(query, paging) {
+ return this._super.search.call(this, query, paging);
+ },
+ list: function(paging) {
+ return this._super.list.call(this, paging);
+ },
+ get: function(id) {
+ return this._super.get.call(this, id);
+ },
+ invokeLcAction: function(asset, action, lcName) {
+ var success;
+ if (lcName) {
+ success = this._super.invokeLcAction.call(this, asset, action, lcName);
+ } else {
+ success = this._super.invokeLcAction.call(this, asset, action);
+ }
+ //trigger notification on LC state change
+ notifier.notifyEvent(storeConstants.LC_STATE_CHANGE_EVENT, asset.type, asset.name, COMMENT, asset.path, ctx.tenantId);
+ return success;
+ }
+ };
+};
+asset.server = function(ctx) {
+ var type = ctx.type;
+ return {
+ onUserLoggedIn: function() {},
+ endpoints: {
+ apis: [{
+ url: 'assets',
+ path: 'assets.jag'
+ }, {
+ url: 'asset',
+ path: 'asset.jag'
+ }, {
+ url: 'statistics',
+ path: 'statistics.jag'
+ }],
+ pages: [{
+ title: 'Asset: ' + type,
+ url: 'asset',
+ path: 'asset.jag'
+ }, {
+ title: 'Assets ' + type,
+ url: 'assets',
+ path: 'assets.jag'
+ }, {
+ title: 'Create ' + type,
+ url: 'create',
+ path: 'create.jag',
+ permission: 'ASSET_CREATE'
+ }, {
+ title: 'Update ' + type,
+ url: 'update',
+ path: 'update.jag',
+ permission: 'ASSET_UPDATE'
+ }, {
+ title: 'Details ' + type,
+ url: 'details',
+ path: 'details.jag'
+ }, {
+ title: 'List ' + type,
+ url: 'list',
+ path: 'list.jag',
+ permission: 'ASSET_LIST'
+ }, {
+ title: 'Lifecycle',
+ url: 'lifecycle',
+ path: 'lifecycle.jag',
+ permission: 'ASSET_LIFECYCLE'
+ }, {
+ title: 'Old lifecycle ',
+ url: 'old-lifecycle',
+ path: 'old-lifecycle.jag'
+ }, {
+ title: 'Statistics',
+ url: 'statistics',
+ path: 'statistics.jag'
+ }, {
+ title: 'Copy ' + type,
+ url: 'copy',
+ path: 'copy.jag',
+ permission: 'ASSET_CREATE'
+ }, {
+ title: 'Delete ' + type,
+ url: 'delete',
+ path: 'delete.jag'
+ }]
+ }
+ };
+};
+asset.configure = function() {
+ return {
+ table: {
+ overview: {
+ fields: {
+ provider: {
+ auto: true
+ },
+ name: {
+ name: {
+ name: 'name',
+ label: 'Name'
+ },
+ readonly: true,
+ required:true,
+ validation: function() {}
+ },
+ version: {
+ name: {
+ label: 'Version'
+ },
+ readonly: true,
+ required:true
+ },
+ createdtime: {
+ hidden: true
+ }
+ }
+ },
+ images: {
+ fields: {
+ thumbnail: {
+ type: 'file'
+ },
+ banner: {
+ type: 'file'
+ }
+ }
+ }
+ },
+ meta: {
+ lifecycle: {
+ name: 'SampleLifeCycle2',
+ commentRequired: false,
+ defaultLifecycleEnabled: true,
+ defaultAction: 'Promote',
+ deletableStates: ['Unpublished'],
+ publishedStates: ['Published'],
+ lifecycleEnabled: true
+ },
+ ui: {
+ icon: 'fw fw-resource'
+ },
+ categories: {
+ categoryField: 'overview_category'
+ },
+ thumbnail: 'images_thumbnail',
+ banner: 'images_banner',
+ nameAttribute: 'overview_name',
+ versionAttribute: 'overview_version',
+ providerAttribute: 'overview_provider',
+ timestamp: 'overview_createdtime',
+ grouping: {
+ groupingEnabled: false,
+ groupingAttributes: ['overview_name']
+ },
+ permissions: {
+ configureRegistryPermissions: function(ctx) {
+ }
+ }
+ }
+ };
+};
+asset.renderer = function(ctx) {
+ var type = ctx.assetType;
+ var permissionAPI = require('rxt').permissions;
+ var isAssetWithLifecycle = function(asset) {
+ if ((asset.lifecycle) && (asset.lifecycleState)) {
+ return true;
+ }
+ if (log.isDebugEnabled()) {
+ log.debug('asset: ' + asset.name + ' does not have a lifecycle or a state.The lifecycle view will not be rendered for this asset');
+ }
+ return false;
+ };
+ var buildListLeftNav = function(page, util) {
+ var navList = util.navList();
+ if (permissionAPI.hasAssetPermission(permissionAPI.ASSET_CREATE, ctx.assetType, ctx.session)) {
+ navList.push('Add ' + type, 'btn-add-new', util.buildUrl('create'));
+ navList.push('Statistics', 'btn-stats', '/assets/' + type + '/statistics');
+ }
+ //navList.push('Configuration', 'icon-dashboard', util.buildUrl('configuration'));
+ return navList.list();
+ };
+ var buildDefaultLeftNav = function(page, util) {
+ var id = page.assets.id;
+ var path = page.assets.path;
+ var navList = util.navList();
+ var isLCViewEnabled = ctx.rxtManager.isLifecycleViewEnabled(ctx.assetType);
+ var user = require('store').server.current(session);
+ var username = user? user.username : null;
+ if (permissionAPI.hasActionPermissionforPath(path, 'write', ctx.session) && permissionAPI.hasAssetPagePermission(type,'update',user.tenantId,username)) {
+ navList.push('Edit', 'btn-edit', util.buildUrl('update') + '/' + id);
+ navList.push('Version', 'btn-copy', util.buildUrl('copy') + '/' + id);
+ }
+ navList.push('Overview', 'btn-overview', util.buildUrl('details') + '/' + id);
+ //Only render the view if the asset has a
+ if ((isLCViewEnabled) && (isAssetWithLifecycle(page.assets))) {
+ if (permissionAPI.hasAssetPermission(permissionAPI.ASSET_LIFECYCLE, ctx.assetType, ctx.session)) {
+ navList.push('Life Cycle', 'btn-lifecycle', util.buildUrl('lifecycle') + '/' + id);
+ }
+ }
+ if (permissionAPI.hasActionPermissionforPath(path, 'delete', ctx.session)) {
+ navList.push('Delete', 'btn-delete', util.buildUrl('delete') + '/' + id);
+ }
+ return navList.list();
+ };
+ var buildAddLeftNav = function(page, util) {
+ return [];
+ };
+ var isActivatedAsset = function(assetType) {
+ var app = require('rxt').app;
+ var activatedAssets = app.getUIActivatedAssets(ctx.tenantId); //ctx.tenantConfigs.assets;
+ //return true;
+ if (!activatedAssets) {
+ throw 'Unable to load all activated assets for current tenant: ' + ctx.tenatId + '.Make sure that the assets property is present in the tenant config';
+ }
+ for (var index in activatedAssets) {
+ if (activatedAssets[index] == assetType) {
+ return true;
+ }
+ }
+ return false;
+ };
+ return {
+ list: function(page) {
+ var assets = page.assets;
+ for (var index in assets) {
+ var asset = assets[index];
+ var timestampAttribute = ctx.rxtManager.getTimeStampAttribute(ctx.assetType);
+ if (asset.attributes.hasOwnProperty(timestampAttribute)) {
+ var value = asset.attributes[timestampAttribute];
+ var date = new Date();
+ date.setTime(value);
+ asset.attributes[timestampAttribute] = date.toUTCString();
+ }
+ }
+ require('/modules/page-decorators.js').pageDecorators.assetCategoryDetails(ctx, page, this);
+ },
+ details: function(page) {
+ var tables = page.assets.tables;
+ //TODO:This cannot be hardcoded
+ var timestampAttribute = 'createdtime'; //ctx.rxtManager.getTimeStampAttribute(this.assetType);
+ for (var index in tables) {
+ var table = tables[index];
+ if ((table.name == 'overview') && (table.fields.hasOwnProperty(timestampAttribute))) {
+ var value = table.fields[timestampAttribute].value || '';
+ var date = new Date();
+ date.setTime(value);
+ table.fields[timestampAttribute].value = date.toUTCString();
+ }
+ }
+ },
+ create: function(page) {
+ var tables = page.assets.tables;
+ var providerAttribute = 'provider';
+ for (var index in tables) {
+ var table = tables[index];
+ if ((table.name == 'overview') && (table.fields.hasOwnProperty(providerAttribute))) {
+ table.fields[providerAttribute].value = page.cuser.username;
+ }
+ }
+ },
+ update: function(page) {
+ var tables = page.assets.tables;
+ var timestampAttribute = 'createdtime';
+ for (var index in tables) {
+ var table = tables[index];
+ if ((table.name == 'overview') && (table.fields.hasOwnProperty(timestampAttribute))) {
+ var value = table.fields[timestampAttribute].value;
+ var date = new Date();
+ date.setTime(value);
+ table.fields[timestampAttribute].value = date.toUTCString();
+ }
+ }
+ },
+ pageDecorators: {
+ leftNav: function(page) {
+ if (log.isDebugEnabled()) {
+ log.debug('Using default leftNav');
+ }
+ switch (page.meta.pageName) {
+ case 'list':
+ page.leftNav = buildListLeftNav(page, this);
+ break;
+ case 'create':
+ page.leftNav = buildAddLeftNav(page, this);
+ break;
+ case 'statistics':
+ page.leftNav = buildListLeftNav(page, this);
+ break;
+ default:
+ page.leftNav = buildDefaultLeftNav(page, this);
+ break;
+ }
+ if (page.leftNav) {
+ for (var navItem in page.leftNav) {
+ if (page.leftNav[navItem].name) {
+ page.leftNav[navItem].id = page.leftNav[navItem].name.replace(/\s/g, "");
+ }
+ }
+ }
+ return page;
+ },
+ ribbon: function(page) {
+ var ribbon = page.ribbon = {};
+ var DEFAULT_ICON = 'fw fw-circle';
+ var assetTypes = [];
+ var assetType;
+ var assetList = ctx.rxtManager.listRxtTypeDetails();
+ for (var index in assetList) {
+ assetType = assetList[index];
+ //Only populate the link if the asset type is activated and the logged in user has permission to that asset
+ if ((isActivatedAsset(assetType.shortName)) && (permissionAPI.hasAssetPermission(permissionAPI.ASSET_LIST, assetType.shortName, ctx.session))) {
+ assetTypes.push({
+ url: this.buildBaseUrl(assetType.shortName) + '/list',
+ assetIcon: assetType.ui.icon || DEFAULT_ICON,
+ assetTitle: assetType.singularLabel
+ });
+ }
+ }
+ ribbon.currentType = page.rxt.singularLabel;
+ ribbon.currentTitle = page.rxt.singularLabel;
+ ribbon.currentUrl = this.buildBaseUrl(type) + '/list'; //page.meta.currentPage;
+ ribbon.shortName = page.rxt.singularLabel;
+ ribbon.query = 'Query';
+ ribbon.breadcrumb = assetTypes;
+ return page;
+ },
+ populateAttachedLifecycles: function(page) {
+ if (page.assets.id) {
+ require('/modules/page-decorators.js').pageDecorators.populateAttachedLifecycles(ctx, page, this);
+ }
+ },
+ populateAssetVersionDetails: function(page) {
+ if (page.assets.id) {
+ require('/modules/page-decorators.js').pageDecorators.populateAssetVersionDetails(ctx, page, this);
+ }
+ },
+ populateGroupingFeatureDetails: function(page) {
+ require('/modules/page-decorators.js').pageDecorators.populateGroupingFeatureDetails(ctx, page);
+ },
+ populateTags: function(page){
+ if(page.assets.id){
+ require('/modules/page-decorators.js').pageDecorators.populateTagDetails(ctx,page);
+ }
+ },
+ sorting: function(page){
+ require('/modules/page-decorators.js').pageDecorators.sorting(ctx,page);
+ }
+ }
+ };
+};
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/mail_templates/asset-default.html b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/mail_templates/asset-default.html
new file mode 100644
index 0000000000..64fd5fd2eb
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/mail_templates/asset-default.html
@@ -0,0 +1 @@
+Notification Message: <%=msg%>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/mail_templates/asset-updated.html b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/mail_templates/asset-updated.html
new file mode 100644
index 0000000000..5c3301e3f7
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/mail_templates/asset-updated.html
@@ -0,0 +1 @@
+Notification for <%=assetType%>:'<%=assetName%>' Event:<%=assetName%> updated
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/mail_templates/lifecycle-state-changed.html b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/mail_templates/lifecycle-state-changed.html
new file mode 100644
index 0000000000..4755eea89e
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/mail_templates/lifecycle-state-changed.html
@@ -0,0 +1 @@
+Notification for <%=assetType%>:'<%=assetName%>' Event:lifecycle state changed Comment: <%=msg%>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/mail_templates/new-version-created.html b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/mail_templates/new-version-created.html
new file mode 100644
index 0000000000..1ddd892dc2
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/mail_templates/new-version-created.html
@@ -0,0 +1 @@
+Notification for <%=assetType%>:'<%=assetName%>' Event:new version created
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/copy.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/copy.jag
new file mode 100644
index 0000000000..81d3bdd337
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/copy.jag
@@ -0,0 +1,46 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+var caramel;
+require('/modules/publisher.js').exec(function(ctx) {
+ caramel = require('caramel');
+ var ui = require('rxt').ui;
+ var asset = require('rxt').asset;
+ var uriMatcher = new URIMatcher(ctx.request.getRequestURI());
+ var options = uriMatcher.match('/{context}/assets/{type}/{pageName}/{+id}')||uriMatcher.match('/{context}/assets/{type}/{pageName}');
+
+ if(!options){
+ response.sendError(400,'Could not locate an endpoint for your request.Make sure that you provide an id');
+ }
+ else if (!options.id) {
+ response.sendError(400, 'An id must be provided when viewing details of a particular asset');
+ } else {
+ var type = options.type;
+ var am = asset.createUserAssetManager(session, type);
+ var page = ui.buildPage(session, request);
+ var assets = am.get(options.id);
+ if (assets == null) {
+ response.sendError(404, 'The asset with id: ' + options.id + ' could not be located.');
+ } else {
+ //print(assets);
+ var output = am.render(assets, page).details();
+ caramel.render(output);
+ }
+ }
+}, request, response, session); %>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/create.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/create.jag
new file mode 100644
index 0000000000..6a21c323ad
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/create.jag
@@ -0,0 +1,33 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+var caramel;
+require('/modules/publisher.js').exec(function(ctx) {
+ caramel = require('caramel');
+ var ui = require('rxt').ui;
+ var asset = require('rxt').asset;
+ var uriMatcher = new URIMatcher(ctx.request.getRequestURI());
+ var options = uriMatcher.match('/{context}/assets/{type}/{pageName}');
+ var type = options.type;
+ var am = asset.createUserAssetManager(ctx.session, type);
+ var page = ui.buildPage(ctx.session, ctx.request);
+ var assets = {};
+ var output = am.render(assets, page).create();
+ caramel.render(output);
+}, request, response, session); %>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/delete.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/delete.jag
new file mode 100644
index 0000000000..29a3178e9c
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/delete.jag
@@ -0,0 +1,46 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+var caramel;
+require('/modules/publisher.js').exec(function(ctx) {
+ caramel = require('caramel');
+ var ui = require('rxt').ui;
+ var asset = require('rxt').asset;
+ var uriMatcher = new URIMatcher(ctx.request.getRequestURI());
+ var options = uriMatcher.match('/{context}/assets/{type}/{pageName}/{+id}')||uriMatcher.match('/{context}/assets/{type}/{pageName}');
+
+ if(!options){
+ response.sendError(400,'Could not locate an endpoint for your request.Make sure that you provide an id');
+ }
+ else if (!options.id) {
+ response.sendError(400, 'An id must be provided when deleting a particular asset');
+ } else {
+ var type = options.type;
+ var am = asset.createUserAssetManager(session, type);
+ var page = ui.buildPage(session, request);
+ var assets = am.get(options.id);
+ if (assets == null) {
+ response.sendError(404, 'The asset with id: ' + options.id + ' could not be located.');
+ } else {
+ //print(assets);
+ var output = am.render(assets, page).details();
+ caramel.render(output);
+ }
+ }
+}, request, response, session); %>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/details.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/details.jag
new file mode 100644
index 0000000000..81d3bdd337
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/details.jag
@@ -0,0 +1,46 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+var caramel;
+require('/modules/publisher.js').exec(function(ctx) {
+ caramel = require('caramel');
+ var ui = require('rxt').ui;
+ var asset = require('rxt').asset;
+ var uriMatcher = new URIMatcher(ctx.request.getRequestURI());
+ var options = uriMatcher.match('/{context}/assets/{type}/{pageName}/{+id}')||uriMatcher.match('/{context}/assets/{type}/{pageName}');
+
+ if(!options){
+ response.sendError(400,'Could not locate an endpoint for your request.Make sure that you provide an id');
+ }
+ else if (!options.id) {
+ response.sendError(400, 'An id must be provided when viewing details of a particular asset');
+ } else {
+ var type = options.type;
+ var am = asset.createUserAssetManager(session, type);
+ var page = ui.buildPage(session, request);
+ var assets = am.get(options.id);
+ if (assets == null) {
+ response.sendError(404, 'The asset with id: ' + options.id + ' could not be located.');
+ } else {
+ //print(assets);
+ var output = am.render(assets, page).details();
+ caramel.render(output);
+ }
+ }
+}, request, response, session); %>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/lifecycle.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/lifecycle.jag
new file mode 100644
index 0000000000..7d374ded38
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/lifecycle.jag
@@ -0,0 +1,48 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+var caramel;
+require('/modules/publisher.js').exec(function(ctx) {
+ var log = new Log();
+ var rxtModule = require('rxt');
+ var asset = rxtModule.asset;
+ caramel = require('caramel');
+ var am;
+ var uriMatcher = new URIMatcher(ctx.request.getRequestURI());
+ var options = uriMatcher.match('/{context}/assets/{type}/{pageName}/{+id}') || uriMatcher.match('/{context}/assets/{type}/{pageName}');
+ var page;
+ var output;
+ var asset;
+ if (!options.id) {
+ ctx.response.sendError(400, 'Cannot render the lifecycle details without an asset id');
+ return;
+ }
+ am = asset.createUserAssetManager(ctx.session, options.type);
+ try {
+ asset = am.get(options.id);
+ }
+ catch(e){
+ log.error(e);
+ ctx.response.sendError(404,'Asset was not found');
+ return;
+ }
+ page = rxtModule.ui.buildPage(ctx.session, ctx.request);
+ output = am.render(asset,page)._custom();
+ caramel.render(output);
+}, request, response, session); %>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/list.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/list.jag
new file mode 100644
index 0000000000..9243143b32
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/list.jag
@@ -0,0 +1,44 @@
+<%
+/*
+ * Copyright (c) WSO2 Inc. (http://wso2.com) All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var caramel;
+var constant = require("rxt").constants;
+var PAGING = constant.DEFAULT_ASSET_PAGIN;
+require('/modules/publisher.js').exec(function(ctx) {
+ caramel = require('caramel');
+ var ui = require('rxt').ui;
+ var reqUtil = require('utils').request;
+ var asset = require('rxt').asset;
+ var uriMatcher = new URIMatcher(ctx.request.getRequestURI());
+ //fixing STORE-818
+ ctx.response.addHeader('Pragma' ,'no-cache');
+ ctx.response.addHeader('Cache-Control' ,'no-cache, no-store, must revalidate');
+ ctx.response.addHeader('Expires' ,'0');
+ var options = uriMatcher.match('/{context}/assets/{type}/{pageName}');
+ //var q = ctx.request.getParameter('query');
+ //var sortBy = ctx.request.getParameter('sortby');
+ //var sort = ctx.request.getParameter('sort');
+ var category = ctx.request.getParameter('category');
+ var type = options.type;
+ var assetApi = require('/modules/asset-api.js').api;
+ var am = asset.createUserAssetManager(ctx.session, type);
+ var page = ui.buildPage(ctx.session, ctx.request);
+ var assets;
+ //Do an advanced search
+ assets = assetApi.advanceSearch(options,ctx.request,ctx.response,ctx.session)||[];
+ var output = am.render(assets, page).list();
+ caramel.render(output);
+}, request, response, session); %>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/old-lifecycle.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/old-lifecycle.jag
new file mode 100644
index 0000000000..d5b8b9dc44
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/old-lifecycle.jag
@@ -0,0 +1,44 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+var caramel;
+require('/modules/publisher.js').exec(function(ctx) {
+ caramel = require('caramel');
+ var ui = require('rxt').ui;
+ var asset = require('rxt').asset;
+ var uriMatcher = new URIMatcher(ctx.request.getRequestURI());
+ var options = uriMatcher.match('/{context}/assets/{type}/{pageName}/{+id}') || uriMatcher.match('/{context}/assets/{type}/{pageName}');
+ if (!options) {
+ response.sendError(400, 'Could not locate an endpoint for your request.Make sure that you provide an id');
+ } else if (!options.id) {
+ response.sendError(400, 'An id must be provided when viewing details of a particular asset');
+ } else {
+ var type = options.type;
+ var am = asset.createUserAssetManager(session, type);
+ var page = ui.buildPage(session, request);
+ var assets = am.get(options.id);
+ if (assets == null) {
+ response.sendError(404, 'The asset with id: ' + options.id + ' could not be located.');
+ } else {
+ //print(assets);
+ var output = am.render(assets, page).lifecycle();
+ caramel.render(output);
+ }
+ }
+}, request, response, session); %>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/statistics.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/statistics.jag
new file mode 100644
index 0000000000..8d4b0af478
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/statistics.jag
@@ -0,0 +1,43 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+var caramel;
+require('/modules/publisher.js').exec(function(ctx) {
+ caramel = require('caramel');
+ var log = new Log('statistics-page');
+ var uriMatcher = new URIMatcher(ctx.request.getRequestURI());
+ var options = uriMatcher.match('/{context}/assets/{type}/{pageName}');
+ var type = options.type;
+ var rxtModule = require('rxt');
+ var page;
+ var am;
+ var output;
+ if (!type) {
+ log.error('Cannot generate a statistics page when a type is not provided');
+ ctx.response.sendError(500, 'Cannot generate a statistics page when a type is not provided');
+ } else {
+ am = rxtModule.asset.createUserAssetManager(ctx.session,type);
+ page = rxtModule.ui.buildPage(ctx.session,ctx.request);
+ output = am.render(page)._custom(options.pageName);
+ output.shortName = type;
+ output.title = type;
+ output.cuser = require('store').server.current(ctx.session);
+ caramel.render(output);
+ }
+}, request, response, session); %>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/update.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/update.jag
new file mode 100644
index 0000000000..e60ef1d0f3
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/pages/update.jag
@@ -0,0 +1,35 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+var caramel;
+require('/modules/publisher.js').exec(function(ctx) {
+ caramel = require('caramel');
+ var ui = require('rxt').ui;
+ var asset = require('rxt').asset;
+ var uriMatcher = new URIMatcher(ctx.request.getRequestURI());
+ var options = uriMatcher.match('/{context}/assets/{type}/{pageName}/{id}');
+ var type = options.type;
+ var id = options.id;
+ var am = asset.createUserAssetManager(ctx.session, type);
+ var page = ui.buildPage(ctx.session, ctx.request);
+ var assets = am.get(id);
+ var output = am.render(assets, page).update();
+ caramel.render(output);
+}, request, response, session);
+%>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/permissions.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/permissions.js
new file mode 100644
index 0000000000..c257df7fc0
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/permissions.js
@@ -0,0 +1,149 @@
+var tenantLoad = function(ctx) {
+ var log = new Log('default-permissions');
+ var Utils = ctx.utils;
+ var Permissions = ctx.permissions;
+ var rxtManager = ctx.rxtManager;
+ var DEFAULT_ROLE = 'Internal/publisher';
+ var REVIEWER_ROLE = 'Internal/reviewer';
+ var tenantId = ctx.tenantId;
+ var createPermission = function(type) {
+ return '/permission/admin/manage/resources/govern/' + type + '/add';
+ };
+ var listPermission = function(type) {
+ return '/permission/admin/manage/resources/govern/' + type + '/list';
+ };
+ var updatePermission = function(type) {
+ return Utils.assetFeaturePermissionString('update', type);
+ };
+ var loginPermission = function() {
+ return '/permission/admin/login';
+ };
+ var publisherLoginPermission = function(){
+ return Utils.appFeaturePermissionString('login');
+ };
+ var assignAllPermissionsToDefaultRole = function() {
+ var types = rxtManager.listRxtTypes();
+ var type;
+ var permissions;
+ //Type specific permissions
+ for (var index = 0; index < types.length; index++) {
+ type = types[index];
+ permissions = {};
+ permissions.APP_LOGIN = publisherLoginPermission();
+ permissions.ASSET_CREATE = createPermission(type);
+ permissions.ASSET_LIST = listPermission(type);
+ permissions.ASSET_UPDATE = updatePermission(type);
+ Utils.addPermissionsToRole(permissions, DEFAULT_ROLE, tenantId);
+
+ var staticPath = rxtManager.getStaticRxtStoragePath(type);
+ staticPath = Utils.governanceRooted(staticPath);
+ var actions = [constants.REGISTRY_ADD_ACTION];
+ log.debug('authorized ' + DEFAULT_ROLE + ' for all actions in ' + staticPath);
+ Utils.authorizeActionsForRole(tenantId, staticPath, DEFAULT_ROLE, actions);
+ }
+ //Non asset type specific permissions
+ permissions = {};
+ permissions.ASSET_LIFECYCLE = '/permission/admin/manage/resources/govern/lifecycles';
+ Utils.addPermissionsToRole(permissions, DEFAULT_ROLE, tenantId);
+ };
+ var assignPermissionToReviewer = function(){
+ var types = rxtManager.listRxtTypes();
+ var type;
+ var permissions;
+ for(var index = 0; index < types.length; index++){
+ type = types[index];
+ permissions = {};
+ permissions.ASSET_LIST = listPermission(type);
+
+ Utils.addPermissionsToRole(permissions,REVIEWER_ROLE,tenantId);
+ }
+ permissions = {};
+ permissions.LOGIN = publisherLoginPermission ();
+ permissions.ASSET_LIFECYCLE = '/permission/admin/manage/resources/govern/lifecycles';
+ Utils.addPermissionsToRole(permissions,REVIEWER_ROLE,tenantId);
+ };
+ /**
+ * Populates permissions that are not handled in the WSO2 permission tree
+ */
+ var populateAssetPermissions = function(tenantId) {
+ var types = rxtManager.listRxtTypes();
+ var type;
+ var permissions = Permissions;
+ var key;
+ var permission;
+ var features = ['update'];
+ var feature;
+ var obj;
+ for (var index = 0; index < types.length; index++) {
+ type = types[index];
+ obj = {};
+ for (var featureIndex = 0; featureIndex < features.length; featureIndex++) {
+ feature = features[featureIndex];
+ key = Utils.assetFeaturePermissionKey(feature, type);
+ permission = Utils.assetFeaturePermissionString(feature, type);
+ permissions[key] = permission;
+ obj[key] = permission;
+ }
+ Utils.registerPermissions(obj, tenantId);
+ }
+ };
+ var populateAppPermissions = function(tenantId) {
+ var permissions = Permissions;
+ var permission;
+ var key;
+ var features = ['login'];
+ var feature;
+ var obj = {};
+ for(var index = 0; index < features.length; index++){
+ feature = features[index];
+ key = Utils.appFeaturePermissionKey(feature);
+ permission = Utils.appFeaturePermissionString(feature);
+ permissions[key] = permission;
+ obj[key] = permission;
+ //log.info('New app permission: '+key+' : '+permission);
+ }
+ Utils.registerPermissions(obj,tenantId);
+ };
+
+ if(log.isDebugEnabled()){
+ log.debug('Starting permission operations and registering default permissions');
+ }
+ Permissions.APP_LOGIN = function(ctx){
+ return ctx.utils.appFeaturePermissionString('login');
+ };
+ Permissions.ASSET_CREATE = function(ctx) {
+ if (!ctx.type) {
+ throw 'Unable to resolve type to determine the ASSET_CREATE permission';
+ }
+ return '/permission/admin/manage/resources/govern/' + ctx.type + '/add';
+ };
+ Permissions.ASSET_LIST = function(ctx) {
+ if (!ctx.type) {
+ throw 'Unable to resolve type to determine the ASSET_LIST permission';
+ }
+ return '/permission/admin/manage/resources/govern/' + ctx.type + '/list';
+ };
+ Permissions.ASSET_UPDATE = function(ctx) {
+ if (!ctx.type) {
+ throw 'Unable to resolve type to determine the ASSET_UPDATE permission';
+ }
+ return ctx.utils.assetFeaturePermissionString('update', ctx.type);
+ };
+ Permissions.ASSET_LIFECYCLE = '/permission/admin/manage/resources/govern/lifecycles';
+ if(log.isDebugEnabled()){
+ log.debug('Registering asset permissions not in the WSO2 permission tree');
+ }
+ populateAssetPermissions(tenantId);
+ populateAppPermissions(tenantId);
+ if(log.isDebugEnabled()){
+ log.debug('Adding permissions to the role : ' + DEFAULT_ROLE);
+ }
+ assignAllPermissionsToDefaultRole();
+ if(log.isDebugEnabled()){
+ log.debug('Adding permissions to reviewer role');
+ }
+ assignPermissionToReviewer();
+ if(log.isDebugEnabled()){
+ log.debug('Permission operations have finished');
+ }
+};
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/workflows/asset_create.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/workflows/asset_create.js
new file mode 100644
index 0000000000..2adc5109fa
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/default/workflows/asset_create.js
@@ -0,0 +1,8 @@
+var log = new Log();
+var execute = function(req,res,session){
+ log.info('Executing the default asset create ');
+};
+
+var process = function(req,res,session){
+ log.info('Processing the default asset create');
+};
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/deviceType/asset.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/deviceType/asset.js
new file mode 100644
index 0000000000..a3ce70261b
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/deviceType/asset.js
@@ -0,0 +1,32 @@
+asset.configure = function () {
+ return {
+ table: {
+ overview: {
+ fields: {
+ thumbnail: {
+ type: 'file'
+ },
+ name: {
+ placeholder: "Device Name Here..."
+ }
+ }
+ },
+ setupGuide: {
+ fields: {
+ guideImage: {
+ type: 'file'
+ }
+ }
+ }
+ },
+ meta: {
+ lifecycle: {
+ name: 'DeviceLifeCycle',
+ defaultAction: 'Create',
+ defaultLifecycleEnabled: true
+ },
+ thumbnail: 'overview_thumbnail',
+ banner: 'overview_thumbnail'
+ }
+ };
+};
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/deviceType/themes/default/partials/product-title.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/deviceType/themes/default/partials/product-title.hbs
new file mode 100644
index 0000000000..9dc4cb7824
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/deviceType/themes/default/partials/product-title.hbs
@@ -0,0 +1 @@
+{{t "IoT Server Device Store Publisher"}}
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/workflows/asset_create.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/deviceType/workflows/asset_create.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/workflows/asset_create.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/deviceType/workflows/asset_create.js
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/gadget/apis/config.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/gadget/apis/config.jag
new file mode 100644
index 0000000000..f2779227de
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/gadget/apis/config.jag
@@ -0,0 +1,26 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+ var log=new Log();
+
+ log.info('config endpoint called');
+
+ print('["a","b","c"]');
+
+%>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/gadget/pages/configuration.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/gadget/pages/configuration.jag
new file mode 100644
index 0000000000..ebb42bc472
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/gadget/pages/configuration.jag
@@ -0,0 +1,34 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+var caramel;
+require('/modules/publisher.js').exec(function(ctx) {
+ caramel = require('caramel');
+ var ui = require('rxt').ui;
+ var asset = require('rxt').asset;
+ var uriMatcher = new URIMatcher(ctx.request.getRequestURI());
+ var options = uriMatcher.match('/{context}/assets/{type}/{pageName}');
+ var type = options.type;
+ var am = asset.createUserAssetManager(ctx.session, type);
+ var page = ui.buildPage(ctx.session, ctx.request);
+ // var assets = {};
+ var output = am.render(page)._custom();
+ caramel.render(output);
+}, request, response, session);
+%>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/gadget/themes/default/partials/configuration.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/gadget/themes/default/partials/configuration.hbs
new file mode 100644
index 0000000000..47f12e971e
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/gadget/themes/default/partials/configuration.hbs
@@ -0,0 +1,3 @@
+Configuration page
+This is a test
+{{dump .}}
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/gadget/themes/default/renderers/pages/configuration.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/gadget/themes/default/renderers/pages/configuration.js
new file mode 100644
index 0000000000..bbf72268fd
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/gadget/themes/default/renderers/pages/configuration.js
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+var render = function(theme, data, meta, require) {
+
+ theme('single-col-fluid', {
+ title: 'Asset',
+ header: [{
+ partial: 'header',
+ context: data
+ }],
+ ribbon: [{
+ partial: 'ribbon',
+ context: data
+ }],
+ leftnav: [{
+ partial:'left-nav',
+ context:data
+ }],
+ listassets: [{
+ partial: 'configuration',
+ context: data
+ }]
+ });
+};
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/gadget/workflows/asset_create.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/gadget/workflows/asset_create.js
new file mode 100644
index 0000000000..7516a2cb17
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/assets/gadget/workflows/asset_create.js
@@ -0,0 +1,8 @@
+var log = new Log();
+var execute = function(req,res,session){
+ log.info('Executing the gadget asset create ');
+};
+
+var process = function(req,res,session){
+ log.info('Processing the gadget asset create');
+};
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/lifecycles/DeviceLifeCycle.xml b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/lifecycles/DeviceLifeCycle.xml
new file mode 100644
index 0000000000..139316f86d
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/lifecycles/DeviceLifeCycle.xml
@@ -0,0 +1,258 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/lifecycles/MobileAppLifeCycle.xml b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/lifecycles/MobileAppLifeCycle.xml
new file mode 100644
index 0000000000..dd7243aa1d
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/lifecycles/MobileAppLifeCycle.xml
@@ -0,0 +1,240 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/lifecycles/SampleLifeCycle.xml b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/lifecycles/SampleLifeCycle.xml
new file mode 100644
index 0000000000..0d020f8310
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/publisher/extensions/lifecycles/SampleLifeCycle.xml
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/sso/views/themes/iotserver/includes/header.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/sso/views/themes/iotserver/includes/header.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/sso/views/themes/iotserver/includes/header.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/sso/views/themes/iotserver/includes/header.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/config/iot-config.json b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/config/iot-config.json
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/config/iot-config.json
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/config/iot-config.json
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/asset.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/asset.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/asset.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/asset.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/assets.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/assets.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/assets.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/assets.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/authenticate.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/authenticate.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/authenticate.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/authenticate.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/lifecycles.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/lifecycles.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/lifecycles.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/lifecycles.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/logout.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/logout.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/logout.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/logout.jag
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/partials.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/partials.jag
new file mode 100644
index 0000000000..f3441328ad
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/partials.jag
@@ -0,0 +1,69 @@
+<%
+var log = new Log();
+var caramel = require('caramel');
+var Handlebars = require('handlebars').Handlebars;
+
+var resolve = function (path, type) {
+ var theme = caramel.theme();
+ var extensionResPath = '/extensions/assets/' + type + '/themes/' + theme.name + '/' + path;
+ var resFile = new File(extensionResPath);
+ if (resFile.isExists()) {
+ return extensionResPath;
+ }
+ return theme.resolve(path);
+};
+
+var analyzePartials = function (partials, ast) {
+ switch (ast.type) {
+ case 'program':
+ if (ast.statements) {
+ ast.statements.forEach(function (program) {
+ analyzePartials(partials, program);
+ });
+ }
+ if (ast.inverse) {
+ analyzePartials(partials, ast.inverse);
+ }
+ break;
+ case 'block':
+ analyzePartials(partials, ast.program);
+ break;
+ case 'partial':
+ partials.push(ast.id.original);
+ }
+};
+
+var findPartials = function (partials, type, partial) {
+ var file, o, ast, path;
+ if (partials[partial]) {
+ return;
+ }
+ path = resolve('partials/' + partial + '.hbs', type);
+ file = new File(path);
+ file.open('r');
+ ast = Handlebars.parse(file.readAll());
+ file.close();
+ partials[partial] = path;
+ o = [];
+ analyzePartials(o, ast);
+ o.forEach(function (partial) {
+ findPartials(partials, type, partial);
+ });
+};
+
+var find = function (type, partials) {
+ var data = {};
+ partials.forEach(function(partial) {
+ findPartials(data, type, partial);
+ });
+ return data;
+};
+
+
+var type = request.getParameter('type');
+var partials = request.getParameter('partial');
+partials = partials instanceof Array ? partials : [partials];
+
+response.contentType = 'application/json';
+print(find(type, partials));
+%>
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/rate.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/rate.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/rate.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/rate.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/subscriptions.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/subscriptions.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/subscriptions.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/subscriptions.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/tags.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/tags.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/tags.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/apis/tags.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/app.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/app.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/app.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-apis/app.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/app.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/app.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/app.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/app.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/advanced-search.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/advanced-search.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/advanced-search.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/advanced-search.jag
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/basic-auth-login-controller.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/basic-auth-login-controller.jag
new file mode 100644
index 0000000000..0afbde60f1
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/basic-auth-login-controller.jag
@@ -0,0 +1,22 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+var caramel = require('caramel');
+caramel.render({});
+%>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/basic-auth-logout-controller.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/basic-auth-logout-controller.jag
new file mode 100644
index 0000000000..a770e27e82
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/basic-auth-logout-controller.jag
@@ -0,0 +1,36 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+(function(request, response, session) {
+ var storeAPI = require('store');
+ var rxtAPI = require('rxt');
+ var user = storeAPI.server.current(session);
+ var context = rxtAPI.app.getContext();
+ //If there is no logged in user then redirect
+ if (!user) {
+ response.sendRedirect(context);
+ return;
+ }
+ try {
+ storeAPI.user.logout();
+ } catch (e) {
+ log.error('Unable to logout the user', e);
+ }
+ response.sendRedirect(context);
+}(request, response, session)) %>
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/basic-authenticator.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/basic-authenticator.jag
new file mode 100644
index 0000000000..f89b02c4a5
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/basic-authenticator.jag
@@ -0,0 +1,47 @@
+<%
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+(function(session, request, response) {
+ var storeAPI = require('store');
+ var params = request.getAllParameters();
+ var hasUsernamePassword = params.username && params.password;
+ var authenticated; //Assume that the authentication will fail
+ if (!hasUsernamePassword) {
+ response.sendError(400,'Please provide the username and password to login');
+ if(log.isDebugEnabled) {
+ log.debug('Attempt to login without username and password');
+ }
+ return;
+ }
+ try {
+ authenticated = storeAPI.user.login(params.username,params.password,session);
+ } catch (e) {
+ log.error("Unable to authenticate user : "+username,e);
+ }
+
+ if(authenticated){
+ session.put("LOGGED_IN_USER", params.username);
+ session.put("Loged", "true");
+ response.code = 200;
+ } else {
+ response.sendError(401);
+ }
+
+}(session, request, response));
+%>
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/my_items.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/my_items.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/my_items.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/my_items.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/sso-auth-login-controller.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/sso-auth-login-controller.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/sso-auth-login-controller.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/sso-auth-login-controller.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/sso-auth-logout-controller.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/sso-auth-logout-controller.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/sso-auth-logout-controller.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/sso-auth-logout-controller.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/top_assets.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/top_assets.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/top_assets.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/pages/top_assets.jag
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/css/basic-login-header.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/css/basic-login-header.css
new file mode 100644
index 0000000000..10d415facc
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/css/basic-login-header.css
@@ -0,0 +1,254 @@
+body{
+ background:#f9f9f9;}
+
+/* application top level header */
+h2.app-title {
+ font-weight:500;
+ font-size:17px;
+ margin:0;
+ padding:3px 0 0 0;
+ color:#fafafa;
+ text-transform: uppercase;
+}
+
+.wr-global-header {
+ background:#444444;
+}
+
+.app-logo {
+ height:50px;
+ padding:12px 20px 12px 16px;
+}
+
+.app-logo a:hover {
+ text-decoration: none;
+ color:#e4e4e4 !important;
+}
+
+.app-logo img {
+ float:left;
+ margin-right:20px;
+}
+
+.wr-app-bar {
+ background:#237bd5;
+ height:54px;
+}
+
+header {
+ height:50px;
+}
+
+@media (max-width: 768px) {
+ .app-logo {
+ padding: 16px 10px;
+ }
+ .app-logo img {
+ width: 50px;
+ height: auto;
+ margin-right:10px;
+ }
+ h2.app-title {
+ font-size: 17px;
+ }
+}
+header {
+ height:50px;
+}
+
+*:focus {
+ outline: 0;
+}
+input:focus {outline:none; border: 0px;}
+
+
+hr {
+ float:left;
+ width:100%;
+ margin:0
+}
+footer{float:left; width:100%;}
+
+/* _____________________________________________________________________________
+
+ TYPOGRAPHY & COLOR
+ _____________________________________________________________________________ */
+
+h2, h3, h4, h5, h6, body{font-family: 'Open Sans';}
+
+.font-large{font-size:16px;}
+button.font-extra-large{font-size:20px;}
+
+.uppercase{text-transform:uppercase;}
+
+
+.blue-bg{background-color: #237bd5;}
+button.grey-bg{background-color: #222222;}
+button.grey-bg:hover{background-color: #3A9ECF;}
+
+.white{color:#FFF;}
+
+.padding-double{padding:20px;}
+
+.margin-none{margin: 0px;}
+
+
+.float-left{float:left;}
+.clear{ clear:both;}
+
+
+
+/* _____________________________________________________________________________
+
+ LOGIN & REGISTER
+ _____________________________________________________________________________ */
+
+.boarder-bottom-blue{border-bottom: 2px solid #006596;}
+input::-moz-placeholder, textarea::-moz-placeholder {
+ padding: 10px 5px 12px 8px;
+ color: #aba8a8;
+ font-size: 18px;
+}
+input::-webkit-input-placeholder{
+
+ color: #aba8a8;
+ font-size: 18px;
+}
+input:-ms-input-placeholder{
+ padding: 10px 5px 12px 8px;
+ color: #aba8a8;
+ font-size: 18px;
+}
+.boarder-all{border: 1px solid #d8d8d8; background: #FFF;margin-bottom: 20px;}
+
+.wr-content {
+ padding-left: inherit;
+}
+
+@media (max-width:500px){
+
+ .wr-content { padding: 0; }
+}
+
+@media (max-width:768px){
+
+}
+
+/* assets */
+.wr-btn {
+ font-weight: normal;
+ font-size:13px;
+ color:#fff;
+ background:#5d81d2;
+ padding:10px 10px;
+ display:inline-block;
+ margin-right:20px;
+ border: none;
+}
+.wr-btn:hover {
+ text-decoration: none;
+ color: #ffffff;
+ background-color: #6b94f1;
+}
+@media (min-width: 360px){
+ . col-xs-5 {padding-left: 10px padding-right: 0 width: 43%;}
+
+}
+
+@media (min-width: 500px){
+ . col-xs-5 {padding-left: 10px; padding-right: 0; width: 43%;}
+}
+/* login page styles */
+
+.wr-login {
+ padding-top:50px;
+}
+
+/* form styles */
+
+
+.wr-input-control {
+ margin-bottom: 20px;
+}
+
+.wr-input-control input[type="text"], .wr-input-control input[type="password"]{
+ border: 1px #d2d2d2 solid;
+ width: 100%;
+ height: 50px;
+ padding: 6px 10px;
+ z-index: 1;
+ -webkit-appearance: none;
+}
+.wr-input-control select{
+ width: 100%;
+}
+
+::-webkit-input-placeholder {
+ color: #fff;
+}
+
+:-moz-placeholder { /* Firefox 18- */
+ color: #fff;
+}
+
+::-moz-placeholder { /* Firefox 19+ */
+ color: #fff;
+}
+
+:-ms-input-placeholder {
+ color: #fff;
+}
+.wr-modelpopup {
+ display: none;
+}
+
+.wr-modelpopup .modelpopup-content {
+ display: block;
+ min-height: 100px;
+ width: 100%;
+ position: fixed;
+ background: #ffffff;
+ top: 200px;
+ z-index: 10001;
+ align-content: center;
+ text-align: center;
+ padding: 30px;
+}
+.wr-modelpopup .modelpopup-bg {
+ position:absolute;
+ z-index: 10000;
+ width: 100%;
+ height: 100%;
+ background: #000000;
+ opacity: 0.7;
+ display: block;
+}
+a.ctrl-filter-category:hover {
+ background:#666;
+ color:#e4e4e4;
+ text-decoration: none;
+ border:1px solid #666;
+}
+.col-centered {
+ float: none;
+ margin: 0 auto;
+}
+.login-link{
+ cursor: pointer;
+}
+.error-msg{
+ color: #aa2d1e;
+ text-align: left;
+ padding: 10px 0 10px 0;
+ display: block;
+}
+label.error{
+ color:#aa2d1e;
+ margin-top:5px;
+ font-weight: normal;
+}
+input[type="text"].error, input[type="password"].error{
+ -webkit-box-shadow: 2px 2px 5px 0px rgba(255,117,117,1);
+ -moz-box-shadow: 2px 2px 5px 0px rgba(255,117,117,1);
+ box-shadow: 2px 2px 5px 0px rgba(255,117,117,1);
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/helpers/advance-search-navigation.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/helpers/advance-search-navigation.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/helpers/advance-search-navigation.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/helpers/advance-search-navigation.js
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/helpers/advanced-search-body.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/helpers/advanced-search-body.js
new file mode 100644
index 0000000000..b2e34f791a
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/helpers/advanced-search-body.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+var resources = function(){
+ return {
+ js:['libs/jquery.form.min.js','advance-search-api.js']
+ }
+};
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/helpers/basic-login-form.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/helpers/basic-login-form.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/helpers/basic-login-form.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/helpers/basic-login-form.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/js/advance-search-api.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/js/advance-search-api.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/js/advance-search-api.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/js/advance-search-api.js
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/js/basic-login.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/js/basic-login.js
new file mode 100644
index 0000000000..4ca55119e5
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/js/basic-login.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+$(function(){
+ $('#basic-login-form').ajaxForm({
+ success:function(){
+ //alert('You have been logged in!'+caramel.url(''));
+ window.location = caramel.url('');
+ },
+ error:function(){
+ alert('Failed to log in!');
+ }
+ });
+});
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/js/libs/jquery.form.min.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/js/libs/jquery.form.min.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/js/libs/jquery.form.min.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/js/libs/jquery.form.min.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/advance-search-navigation.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/advance-search-navigation.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/advance-search-navigation.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/advance-search-navigation.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/advanced-search-body.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/advanced-search-body.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/advanced-search-body.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/advanced-search-body.hbs
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/advanced-search-buttons.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/advanced-search-buttons.hbs
new file mode 100644
index 0000000000..9e9be62c26
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/advanced-search-buttons.hbs
@@ -0,0 +1 @@
+ SEARCH
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/advanced-search-results.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/advanced-search-results.hbs
new file mode 100644
index 0000000000..2651ffb98e
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/advanced-search-results.hbs
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/basic-login-form.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/basic-login-form.hbs
new file mode 100644
index 0000000000..910244d4d0
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/basic-login-form.hbs
@@ -0,0 +1,26 @@
+
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/basic-login-header.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/basic-login-header.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/basic-login-header.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/basic-login-header.hbs
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/extended-search-attributes.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/extended-search-attributes.hbs
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/primary-search-attributes.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/primary-search-attributes.hbs
new file mode 100644
index 0000000000..428e82fda3
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/partials/primary-search-attributes.hbs
@@ -0,0 +1,20 @@
+
+ Name
+
+
+
+ Provider
+
+
+
+ Version
+
+
+
+ Lifecycle State
+
+
+
+ Tags
+
+
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/renderers/pages/advanced-search.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/renderers/pages/advanced-search.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/renderers/pages/advanced-search.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/renderers/pages/advanced-search.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/renderers/pages/basic-auth-login-controller.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/renderers/pages/basic-auth-login-controller.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/renderers/pages/basic-auth-login-controller.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-common/themes/store/renderers/pages/basic-auth-login-controller.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/device-api.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/device-api.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/device-api.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/device-api.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/group-api.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/group-api.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/group-api.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/group-api.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/operation-api.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/operation-api.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/operation-api.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/operation-api.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/policy-api.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/policy-api.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/policy-api.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/policy-api.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/stats-api.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/stats-api.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/stats-api.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/stats-api.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/user-api.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/user-api.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/user-api.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/apis/user-api.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/app.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/app.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/app.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/app.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/constants.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/constants.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/constants.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/constants.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/custom-page-decorators.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/custom-page-decorators.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/custom-page-decorators.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/custom-page-decorators.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/device.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/device.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/device.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/device.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/event.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/event.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/event.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/event.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/group.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/group.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/group.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/group.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/operation.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/operation.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/operation.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/operation.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/policy.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/policy.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/policy.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/policy.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/user.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/user.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/user.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/user.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/utility.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/utility.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/utility.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/modules/utility.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/advanced-search.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/advanced-search.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/advanced-search.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/advanced-search.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/analytics.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/analytics.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/analytics.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/analytics.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/device_analytics.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/device_analytics.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/device_analytics.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/device_analytics.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/device_details.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/device_details.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/device_details.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/device_details.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/device_listing.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/device_listing.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/device_listing.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/device_listing.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/events.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/events.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/events.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/events.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/groups.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/groups.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/groups.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/groups.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/policies.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/policies.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/policies.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/policies.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/sso-auth-login-controller.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/sso-auth-login-controller.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/sso-auth-login-controller.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/sso-auth-login-controller.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/users.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/users.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/users.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/pages/users.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/analytics.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/analytics.css
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/analytics.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/analytics.css
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/codemirror.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/codemirror.css
new file mode 100644
index 0000000000..47c6f0b0bd
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/codemirror.css
@@ -0,0 +1,344 @@
+/*Copyright (C) 2015 by Marijn Haverbeke and others
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.*/
+
+/* BASICS */
+
+.CodeMirror {
+ /* Set height, width, borders, and global font properties here */
+ font-family: monospace;
+ height: 300px;
+ color: black;
+}
+
+/* PADDING */
+
+.CodeMirror-lines {
+ padding: 4px 0; /* Vertical padding around content */
+}
+.CodeMirror pre {
+ padding: 0 4px; /* Horizontal padding of content */
+}
+
+.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+ background-color: white; /* The little square between H and V scrollbars */
+}
+
+/* GUTTER */
+
+.CodeMirror-gutters {
+ border-right: 1px solid #ddd;
+ background-color: #f7f7f7;
+ white-space: nowrap;
+}
+.CodeMirror-linenumbers {}
+.CodeMirror-linenumber {
+ padding: 0 3px 0 5px;
+ min-width: 20px;
+ text-align: right;
+ color: #999;
+ white-space: nowrap;
+ left: -30px;
+}
+
+.CodeMirror-guttermarker { color: black; }
+.CodeMirror-guttermarker-subtle { color: #999; }
+
+/* CURSOR */
+
+.CodeMirror div.CodeMirror-cursor {
+ border-left: 1px solid black;
+}
+/* Shown when moving in bi-directional text */
+.CodeMirror div.CodeMirror-secondarycursor {
+ border-left: 1px solid silver;
+}
+.CodeMirror.cm-fat-cursor div.CodeMirror-cursor {
+ width: auto;
+ border: 0;
+ background: #7e7;
+}
+.CodeMirror.cm-fat-cursor div.CodeMirror-cursors {
+ z-index: 1;
+}
+
+.cm-animate-fat-cursor {
+ width: auto;
+ border: 0;
+ -webkit-animation: blink 1.06s steps(1) infinite;
+ -moz-animation: blink 1.06s steps(1) infinite;
+ animation: blink 1.06s steps(1) infinite;
+}
+@-moz-keyframes blink {
+ 0% { background: #7e7; }
+ 50% { background: none; }
+ 100% { background: #7e7; }
+}
+@-webkit-keyframes blink {
+ 0% { background: #7e7; }
+ 50% { background: none; }
+ 100% { background: #7e7; }
+}
+@keyframes blink {
+ 0% { background: #7e7; }
+ 50% { background: none; }
+ 100% { background: #7e7; }
+}
+
+/* Can style cursor different in overwrite (non-insert) mode */
+div.CodeMirror-overwrite div.CodeMirror-cursor {}
+
+.cm-tab { display: inline-block; text-decoration: inherit; }
+
+.CodeMirror-ruler {
+ border-left: 1px solid #ccc;
+ position: absolute;
+}
+
+/* DEFAULT THEME */
+
+.cm-s-default .cm-keyword {color: #708;}
+.cm-s-default .cm-atom {color: #219;}
+.cm-s-default .cm-number {color: #164;}
+.cm-s-default .cm-def {color: #00f;}
+.cm-s-default .cm-variable,
+.cm-s-default .cm-punctuation,
+.cm-s-default .cm-property,
+.cm-s-default .cm-operator {}
+.cm-s-default .cm-variable-2 {color: #05a;}
+.cm-s-default .cm-variable-3 {color: #085;}
+.cm-s-default .cm-comment {color: #a50;}
+.cm-s-default .cm-string {color: #a11;}
+.cm-s-default .cm-string-2 {color: #f50;}
+.cm-s-default .cm-meta {color: #555;}
+.cm-s-default .cm-qualifier {color: #555;}
+.cm-s-default .cm-builtin {color: #30a;}
+.cm-s-default .cm-bracket {color: #997;}
+.cm-s-default .cm-tag {color: #170;}
+.cm-s-default .cm-attribute {color: #00c;}
+.cm-s-default .cm-header {color: blue;}
+.cm-s-default .cm-quote {color: #090;}
+.cm-s-default .cm-hr {color: #999;}
+.cm-s-default .cm-link {color: #00c;}
+
+.cm-negative {color: #d44;}
+.cm-positive {color: #292;}
+.cm-header, .cm-strong {font-weight: bold;}
+.cm-em {font-style: italic;}
+.cm-link {text-decoration: underline;}
+.cm-strikethrough {text-decoration: line-through;}
+
+.cm-s-default .cm-error {color: #f00;}
+.cm-invalidchar {color: #f00;}
+
+/* Default styles for common addons */
+
+div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
+div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
+.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
+.CodeMirror-activeline-background {background: #e8f2ff;}
+
+/* STOP */
+
+/* The rest of this file contains styles related to the mechanics of
+ the editor. You probably shouldn't touch them. */
+
+.CodeMirror {
+ position: relative;
+ overflow: hidden;
+ background: white;
+}
+
+.CodeMirror-scroll {
+ overflow: scroll !important; /* Things will break if this is overridden */
+ /* 30px is the magic margin used to hide the element's real scrollbars */
+ /* See overflow: hidden in .CodeMirror */
+ margin-bottom: -30px; margin-right: -30px;
+ padding-bottom: 30px;
+ height: 100%;
+ outline: none; /* Prevent dragging from highlighting the element */
+ position: relative;
+}
+.CodeMirror-sizer {
+ position: relative;
+ border-right: 30px solid transparent;
+}
+
+/* The fake, visible scrollbars. Used to force redraw during scrolling
+ before actuall scrolling happens, thus preventing shaking and
+ flickering artifacts. */
+.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+ position: absolute;
+ z-index: 6;
+ display: none;
+}
+.CodeMirror-vscrollbar {
+ right: 0; top: 0;
+ overflow-x: hidden;
+ overflow-y: scroll;
+}
+.CodeMirror-hscrollbar {
+ bottom: 0; left: 0;
+ overflow-y: hidden;
+ overflow-x: scroll;
+}
+.CodeMirror-scrollbar-filler {
+ right: 0; bottom: 0;
+}
+.CodeMirror-gutter-filler {
+ left: 0; bottom: 0;
+}
+
+.CodeMirror-gutters {
+ position: absolute; left: 0; top: 0;
+ z-index: 3;
+}
+.CodeMirror-gutter {
+ white-space: normal;
+ height: 100%;
+ display: inline-block;
+ /* Hack to make IE7 behave */
+ *zoom:1;
+ *display:inline;
+}
+.CodeMirror-gutter-wrapper {
+ position: absolute;
+ z-index: 4;
+ height: 100%;
+}
+.CodeMirror-gutter-elt {
+ position: absolute;
+ cursor: default;
+ z-index: 4;
+ left: -30px;
+}
+.CodeMirror-gutter-wrapper {
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+}
+
+.CodeMirror-lines {
+ cursor: text;
+ min-height: 1px; /* prevents collapsing before first draw */
+}
+.CodeMirror pre {
+ /* Reset some styles that the rest of the page might have set */
+ -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
+ border-width: 0;
+ background: transparent;
+ font-family: inherit;
+ font-size: inherit;
+ margin: 0;
+ white-space: pre;
+ word-wrap: normal;
+ line-height: inherit;
+ color: inherit;
+ z-index: 2;
+ position: relative;
+ overflow: visible;
+ -webkit-tap-highlight-color: transparent;
+}
+.CodeMirror-wrap pre {
+ word-wrap: break-word;
+ white-space: pre-wrap;
+ word-break: normal;
+}
+
+.CodeMirror-linebackground {
+ position: absolute;
+ left: 0; right: 0; top: 0; bottom: 0;
+ z-index: 0;
+}
+
+.CodeMirror-linewidget {
+ position: relative;
+ z-index: 2;
+ overflow: auto;
+}
+
+.CodeMirror-widget {}
+
+.CodeMirror-code {
+ outline: none;
+}
+
+/* Force content-box sizing for the elements where we expect it */
+.CodeMirror-scroll,
+.CodeMirror-sizer,
+.CodeMirror-gutter,
+.CodeMirror-gutters,
+.CodeMirror-linenumber {
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+}
+
+.CodeMirror-measure {
+ position: absolute;
+ width: 100%;
+ height: 0;
+ overflow: hidden;
+ visibility: hidden;
+}
+.CodeMirror-measure pre { position: static; }
+
+.CodeMirror div.CodeMirror-cursor {
+ position: absolute;
+ border-right: none;
+ width: 0;
+}
+
+div.CodeMirror-cursors {
+ visibility: hidden;
+ position: relative;
+ z-index: 3;
+}
+.CodeMirror-focused div.CodeMirror-cursors {
+ visibility: visible;
+}
+
+.CodeMirror-selected { background: #d9d9d9; }
+.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
+.CodeMirror-crosshair { cursor: crosshair; }
+.CodeMirror ::selection { background: #d7d4f0; }
+.CodeMirror ::-moz-selection { background: #d7d4f0; }
+
+.cm-searching {
+ background: #ffa;
+ background: rgba(255, 255, 0, .4);
+}
+
+/* IE7 hack to prevent it from returning funny offsetTops on the spans */
+.CodeMirror span { *vertical-align: text-bottom; }
+
+/* Used to force a border model for a node */
+.cm-force-border { padding-right: .1px; }
+
+@media print {
+ /* Hide the cursor when printing */
+ .CodeMirror div.CodeMirror-cursors {
+ visibility: hidden;
+ }
+}
+
+/* See issue #2901 */
+.cm-tab-wrap-hack:after { content: ''; }
+
+/* Help users use markselection to safely style text background */
+span.CodeMirror-selectedtext { background: none; }
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/custom-extensions.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/custom-extensions.css
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/custom-extensions.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/custom-extensions.css
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/daterangepicker.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/daterangepicker.css
new file mode 100644
index 0000000000..71bcee06a6
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/daterangepicker.css
@@ -0,0 +1,331 @@
+.date-picker {
+ width: 170px;
+ height: 25px;
+ padding: 0;
+ border: 0;
+ line-height: 25px;
+ padding-left: 10px;
+ font-size: 12px;
+ font-family: Arial;
+ font-weight: bold;
+ cursor: pointer;
+ color: #303030;
+ position: relative;
+ z-index: 2;
+}
+
+.date-picker-wrapper {
+ position: absolute;
+ z-index: 1;
+ border: 1px solid #bfbfbf;
+ background-color: #efefef;
+ width: 448px;
+ padding: 5px 12px;
+ font-size: 12px;
+ line-height: 20px;
+ color: #aaa;
+ font-family: Arial;
+ box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.5);
+}
+
+.date-picker-wrapper.single-date {
+ width: auto;
+}
+
+.date-picker-wrapper.no-shortcuts {
+ padding-bottom: 12px;
+}
+
+.date-picker-wrapper .footer {
+ display: none;
+ font-size: 11px;
+ padding-top: 3px;
+}
+
+.date-picker-wrapper b {
+ color: #666;
+ font-weight: 700;
+}
+
+.date-picker-wrapper a {
+ color: rgb(107, 180, 214);
+ text-decoration: underline;
+}
+
+.date-picker-wrapper .month-wrapper {
+ border: 1px solid #bfbfbf;
+ border-radius: 3px;
+ background-color: #fff;
+ padding: 5px;
+ cursor: default;
+ position: relative;
+ _overflow: hidden;
+}
+
+.date-picker-wrapper .month-wrapper table {
+ width: 190px;
+ float: left;
+}
+
+.date-picker-wrapper .month-wrapper table.month2 {
+ width: 190px;
+ float: right;
+}
+
+.date-picker-wrapper .month-wrapper table th,
+.date-picker-wrapper .month-wrapper table td {
+ vertical-align: middle;
+ text-align: center;
+ line-height: 14px;
+ margin: 0px;
+ padding: 0px;
+}
+
+.date-picker-wrapper .month-wrapper table .day {
+ height: 19px;
+ line-height: 19px;
+ font-size: 12px;
+ margin-bottom: 1px;
+ color: #999;
+ cursor: default;
+}
+
+.date-picker-wrapper .month-wrapper table div.day.lastMonth,
+.date-picker-wrapper .month-wrapper table div.day.nextMonth {
+ color: #999;
+ cursor: default;
+}
+
+.date-picker-wrapper .month-wrapper table .day.checked {
+ background-color: rgb(156, 219, 247);
+}
+
+.date-picker-wrapper .month-wrapper table .week-name {
+ height: 20px;
+ line-height: 20px;
+ font-weight: 100;
+}
+
+.date-picker-wrapper .month-wrapper table .day.has-tooltip {
+ cursor: help !important;
+}
+
+.date-picker-wrapper .month-wrapper table .day.toMonth.valid {
+ color: #333;
+ cursor: pointer;
+}
+
+.date-picker-wrapper .month-wrapper table .day.real-today {
+ background-color: rgb(255, 230, 132);
+}
+
+.date-picker-wrapper .month-wrapper table .day.real-today.checked {
+ background-color: rgb(112, 204, 213);
+}
+
+.date-picker-wrapper table .caption {
+ height: 40px;
+}
+
+.date-picker-wrapper table .caption .next,
+.date-picker-wrapper table .caption .prev {
+ padding: 0 5px;
+ cursor: pointer;
+}
+
+.date-picker-wrapper table .caption .next:hover,
+.date-picker-wrapper table .caption .prev:hover {
+ background-color: #ccc;
+ color: white;
+}
+
+.date-picker-wrapper .gap {
+ position: absolute;
+ display: none;
+ top: 0px;
+ left: 204px;
+ z-index: 1;
+ width: 15px;
+ height: 100%;
+ background-color: red;
+ font-size: 0;
+ line-height: 0;
+}
+
+.date-picker-wrapper .gap .gap-lines {
+ height: 100%;
+ overflow: hidden;
+}
+
+.date-picker-wrapper .gap .gap-line {
+ height: 15px;
+ width: 15px;
+ position: relative;
+}
+
+.date-picker-wrapper .gap .gap-line .gap-1 {
+ z-index: 1;
+ height: 0;
+ border-left: 8px solid white;
+ border-top: 8px solid #eee;
+ border-bottom: 8px solid #eee;
+}
+
+.date-picker-wrapper .gap .gap-line .gap-2 {
+ position: absolute;
+ right: 0;
+ top: 0px;
+ z-index: 2;
+ height: 0;
+ border-left: 8px solid transparent;
+ border-top: 8px solid white;
+}
+
+.date-picker-wrapper .gap .gap-line .gap-3 {
+ position: absolute;
+ right: 0;
+ top: 8px;
+ z-index: 2;
+ height: 0;
+ border-left: 8px solid transparent;
+ border-bottom: 8px solid white;
+}
+
+.date-picker-wrapper .gap .gap-top-mask {
+ width: 6px;
+ height: 1px;
+ position: absolute;
+ top: -1px;
+ left: 1px;
+ background-color: #eee;
+ z-index: 3;
+}
+
+.date-picker-wrapper .gap .gap-bottom-mask {
+ width: 6px;
+ height: 1px;
+ position: absolute;
+ bottom: -1px;
+ left: 7px;
+ background-color: #eee;
+ z-index: 3;
+}
+
+.date-picker-wrapper .selected-days {
+ display: none;
+}
+
+.date-picker-wrapper .drp_top-bar {
+ line-height: 40px;
+ height: 40px;
+ position: relative;
+}
+
+.date-picker-wrapper .drp_top-bar .error-top {
+ display: none;
+}
+
+.date-picker-wrapper .drp_top-bar .normal-top {
+ display: none;
+}
+
+.date-picker-wrapper .drp_top-bar .default-top {
+ display: block;
+}
+
+.date-picker-wrapper .drp_top-bar.error .default-top {
+ display: none;
+}
+
+.date-picker-wrapper .drp_top-bar.error .error-top {
+ display: block;
+ color: red;
+}
+
+.date-picker-wrapper .drp_top-bar.normal .default-top {
+ display: none;
+}
+
+.date-picker-wrapper .drp_top-bar.normal .normal-top {
+ display: block;
+}
+
+.date-picker-wrapper .drp_top-bar .apply-btn {
+ position: absolute;
+ right: 0px;
+ top: 6px;
+ padding: 3px 5px;
+ margin: 0;
+ font-size: 12px;
+ border-radius: 4px;
+ cursor: pointer;
+
+ color: #d9eef7;
+ border: solid 1px #0076a3;
+ background: #0095cd;
+ background: -webkit-gradient(linear, left top, left bottom, from(#00adee), to(#0078a5));
+ background: -moz-linear-gradient(top, #00adee, #0078a5);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00adee', endColorstr='#0078a5');
+ color: white;
+}
+
+.date-picker-wrapper .drp_top-bar .apply-btn.disabled {
+ pointer-events: none;
+ color: #606060;
+ border: solid 1px #b7b7b7;
+ background: #fff;
+ background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#ededed));
+ background: -moz-linear-gradient(top, #fff, #ededed);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#ededed');
+}
+
+/*time styling*/
+.time {
+ position: relative;
+}
+
+.time input[type=range] {
+ vertical-align: middle;
+}
+
+.time1, .time2 {
+ width: 180px;
+ padding: 0 5px;
+ text-align: center;
+}
+
+.time1 {
+ float: left;
+}
+
+.time2 {
+ float: right;
+}
+
+.hour, .minute {
+ text-align: left;
+}
+
+.hide {
+ display: none;
+}
+
+input.hour-range, input.minute-range {
+ width: 150px;
+}
+
+#dateRangePickerContainer .date-range, #dateRangePickerContainer .input-append {
+ background: none !important;
+}
+
+#date-range{
+ padding-right:30px;
+ width:300px;
+ height:100%;
+ display:inline-block;
+}
+
+#dateRangePickerContainer{
+ float:right;
+ margin-top:-6px;
+}
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/device-details.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/device-details.css
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/device-details.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/device-details.css
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/font-wso2.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/font-wso2.css
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/font-wso2.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/font-wso2.css
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/graph.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/graph.css
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/graph.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/graph.css
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/group-add.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/group-add.css
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/group-add.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/group-add.css
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/modal.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/modal.css
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/modal.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/modal.css
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/navigation-custom.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/navigation-custom.css
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/navigation-custom.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/navigation-custom.css
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/policy-add.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/policy-add.css
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/policy-add.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/policy-add.css
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/select2.min.css b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/select2.min.css
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/select2.min.css
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/css/select2.min.css
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/fonts/font-wso2.eot b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/fonts/font-wso2.eot
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/fonts/font-wso2.eot
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/fonts/font-wso2.eot
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/fonts/font-wso2.svg b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/fonts/font-wso2.svg
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/fonts/font-wso2.svg
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/fonts/font-wso2.svg
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/fonts/font-wso2.ttf b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/fonts/font-wso2.ttf
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/fonts/font-wso2.ttf
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/fonts/font-wso2.ttf
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/fonts/font-wso2.woff b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/fonts/font-wso2.woff
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/fonts/font-wso2.woff
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/fonts/font-wso2.woff
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/advanced-search-body.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/advanced-search-body.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/advanced-search-body.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/advanced-search-body.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/analytics.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/analytics.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/analytics.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/analytics.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/device-details.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/device-details.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/device-details.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/device-details.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/device-listing.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/device-listing.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/device-listing.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/device-listing.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/events.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/events.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/events.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/events.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/group-add.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/group-add.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/group-add.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/group-add.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/group-listing.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/group-listing.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/group-listing.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/group-listing.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/navigation.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/navigation.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/navigation.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/navigation.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/policy-add.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/policy-add.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/policy-add.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/policy-add.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/policy-listing.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/policy-listing.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/policy-listing.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/helpers/policy-listing.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/img/group-icon.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/img/group-icon.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/img/group-icon.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/img/group-icon.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/img/map-marker-1.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/img/map-marker-1.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/img/map-marker-1.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/img/map-marker-1.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/img/map-marker-2.png b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/img/map-marker-2.png
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/img/map-marker-2.png
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/img/map-marker-2.png
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/advance-search-api.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/advance-search-api.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/advance-search-api.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/advance-search-api.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/device-details.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/device-details.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/device-details.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/device-details.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/device-listing.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/device-listing.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/device-listing.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/device-listing.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/events.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/events.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/events.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/events.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/graph_util.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/graph_util.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/graph_util.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/graph_util.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/group-add.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/group-add.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/group-add.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/group-add.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/group-listing.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/group-listing.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/group-listing.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/group-listing.js
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/codemirror.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/codemirror.js
new file mode 100644
index 0000000000..d7bb9c0209
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/codemirror.js
@@ -0,0 +1,8722 @@
+/*Copyright (C) 2015 by Marijn Haverbeke and others
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+// This is CodeMirror (http://codemirror.net), a code editor
+// implemented in JavaScript on top of the browser's DOM.
+//
+// You can find some technical background for some of the code below
+// at http://marijnhaverbeke.nl/blog/#cm-internals .
+
+(function(mod) {
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
+ module.exports = mod();
+ else if (typeof define == "function" && define.amd) // AMD
+ return define([], mod);
+ else // Plain browser env
+ this.CodeMirror = mod();
+})(function() {
+ "use strict";
+
+ // BROWSER SNIFFING
+
+ // Kludges for bugs and behavior differences that can't be feature
+ // detected are enabled based on userAgent etc sniffing.
+
+ var gecko = /gecko\/\d/i.test(navigator.userAgent);
+ var ie_upto10 = /MSIE \d/.test(navigator.userAgent);
+ var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);
+ var ie = ie_upto10 || ie_11up;
+ var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]);
+ var webkit = /WebKit\//.test(navigator.userAgent);
+ var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
+ var chrome = /Chrome\//.test(navigator.userAgent);
+ var presto = /Opera\//.test(navigator.userAgent);
+ var safari = /Apple Computer/.test(navigator.vendor);
+ var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
+ var phantom = /PhantomJS/.test(navigator.userAgent);
+
+ var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
+ // This is woefully incomplete. Suggestions for alternative methods welcome.
+ var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
+ var mac = ios || /Mac/.test(navigator.platform);
+ var windows = /win/i.test(navigator.platform);
+
+ var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/);
+ if (presto_version) presto_version = Number(presto_version[1]);
+ if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
+ // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
+ var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));
+ var captureRightClick = gecko || (ie && ie_version >= 9);
+
+ // Optimize some code when these features are not used.
+ var sawReadOnlySpans = false, sawCollapsedSpans = false;
+
+ // EDITOR CONSTRUCTOR
+
+ // A CodeMirror instance represents an editor. This is the object
+ // that user code is usually dealing with.
+
+ function CodeMirror(place, options) {
+ if (!(this instanceof CodeMirror)) return new CodeMirror(place, options);
+
+ this.options = options = options ? copyObj(options) : {};
+ // Determine effective options based on given values and defaults.
+ copyObj(defaults, options, false);
+ setGuttersForLineNumbers(options);
+
+ var doc = options.value;
+ if (typeof doc == "string") doc = new Doc(doc, options.mode);
+ this.doc = doc;
+
+ var input = new CodeMirror.inputStyles[options.inputStyle](this);
+ var display = this.display = new Display(place, doc, input);
+ display.wrapper.CodeMirror = this;
+ updateGutters(this);
+ themeChanged(this);
+ if (options.lineWrapping)
+ this.display.wrapper.className += " CodeMirror-wrap";
+ if (options.autofocus && !mobile) display.input.focus();
+ initScrollbars(this);
+
+ this.state = {
+ keyMaps: [], // stores maps added by addKeyMap
+ overlays: [], // highlighting overlays, as added by addOverlay
+ modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info
+ overwrite: false,
+ delayingBlurEvent: false,
+ focused: false,
+ suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
+ pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
+ draggingText: false,
+ highlight: new Delayed(), // stores highlight worker timeout
+ keySeq: null, // Unfinished key sequence
+ specialChars: null
+ };
+
+ var cm = this;
+
+ // Override magic textarea content restore that IE sometimes does
+ // on our hidden textarea on reload
+ if (ie && ie_version < 11) setTimeout(function() { cm.display.input.reset(true); }, 20);
+
+ registerEventHandlers(this);
+ ensureGlobalHandlers();
+
+ startOperation(this);
+ this.curOp.forceUpdate = true;
+ attachDoc(this, doc);
+
+ if ((options.autofocus && !mobile) || cm.hasFocus())
+ setTimeout(bind(onFocus, this), 20);
+ else
+ onBlur(this);
+
+ for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt))
+ optionHandlers[opt](this, options[opt], Init);
+ maybeUpdateLineNumberWidth(this);
+ if (options.finishInit) options.finishInit(this);
+ for (var i = 0; i < initHooks.length; ++i) initHooks[i](this);
+ endOperation(this);
+ // Suppress optimizelegibility in Webkit, since it breaks text
+ // measuring on line wrapping boundaries.
+ if (webkit && options.lineWrapping &&
+ getComputedStyle(display.lineDiv).textRendering == "optimizelegibility")
+ display.lineDiv.style.textRendering = "auto";
+ }
+
+ // DISPLAY CONSTRUCTOR
+
+ // The display handles the DOM integration, both for input reading
+ // and content drawing. It holds references to DOM nodes and
+ // display-related state.
+
+ function Display(place, doc, input) {
+ var d = this;
+ this.input = input;
+
+ // Covers bottom-right square when both scrollbars are present.
+ d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
+ d.scrollbarFiller.setAttribute("cm-not-content", "true");
+ // Covers bottom of gutter when coverGutterNextToScrollbar is on
+ // and h scrollbar is present.
+ d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
+ d.gutterFiller.setAttribute("cm-not-content", "true");
+ // Will contain the actual code, positioned to cover the viewport.
+ d.lineDiv = elt("div", null, "CodeMirror-code");
+ // Elements are added to these to represent selection and cursors.
+ d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
+ d.cursorDiv = elt("div", null, "CodeMirror-cursors");
+ // A visibility: hidden element used to find the size of things.
+ d.measure = elt("div", null, "CodeMirror-measure");
+ // When lines outside of the viewport are measured, they are drawn in this.
+ d.lineMeasure = elt("div", null, "CodeMirror-measure");
+ // Wraps everything that needs to exist inside the vertically-padded coordinate system
+ d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
+ null, "position: relative; outline: none");
+ // Moved around its parent to cover visible view.
+ d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative");
+ // Set to the height of the document, allowing scrolling.
+ d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
+ d.sizerWidth = null;
+ // Behavior of elts with overflow: auto and padding is
+ // inconsistent across browsers. This is used to ensure the
+ // scrollable area is big enough.
+ d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;");
+ // Will contain the gutters, if any.
+ d.gutters = elt("div", null, "CodeMirror-gutters");
+ d.lineGutter = null;
+ // Actual scrollable element.
+ d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
+ d.scroller.setAttribute("tabIndex", "-1");
+ // The element in which the editor lives.
+ d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
+
+ // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
+ if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
+ if (!webkit && !(gecko && mobile)) d.scroller.draggable = true;
+
+ if (place) {
+ if (place.appendChild) place.appendChild(d.wrapper);
+ else place(d.wrapper);
+ }
+
+ // Current rendered range (may be bigger than the view window).
+ d.viewFrom = d.viewTo = doc.first;
+ d.reportedViewFrom = d.reportedViewTo = doc.first;
+ // Information about the rendered lines.
+ d.view = [];
+ d.renderedView = null;
+ // Holds info about a single rendered line when it was rendered
+ // for measurement, while not in view.
+ d.externalMeasured = null;
+ // Empty space (in pixels) above the view
+ d.viewOffset = 0;
+ d.lastWrapHeight = d.lastWrapWidth = 0;
+ d.updateLineNumbers = null;
+
+ d.nativeBarWidth = d.barHeight = d.barWidth = 0;
+ d.scrollbarsClipped = false;
+
+ // Used to only resize the line number gutter when necessary (when
+ // the amount of lines crosses a boundary that makes its width change)
+ d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
+ // Set to true when a non-horizontal-scrolling line widget is
+ // added. As an optimization, line widget aligning is skipped when
+ // this is false.
+ d.alignWidgets = false;
+
+ d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
+
+ // Tracks the maximum line length so that the horizontal scrollbar
+ // can be kept static when scrolling.
+ d.maxLine = null;
+ d.maxLineLength = 0;
+ d.maxLineChanged = false;
+
+ // Used for measuring wheel scrolling granularity
+ d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
+
+ // True when shift is held down.
+ d.shift = false;
+
+ // Used to track whether anything happened since the context menu
+ // was opened.
+ d.selForContextMenu = null;
+
+ d.activeTouch = null;
+
+ input.init(d);
+ }
+
+ // STATE UPDATES
+
+ // Used to get the editor into a consistent state again when options change.
+
+ function loadMode(cm) {
+ cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption);
+ resetModeState(cm);
+ }
+
+ function resetModeState(cm) {
+ cm.doc.iter(function(line) {
+ if (line.stateAfter) line.stateAfter = null;
+ if (line.styles) line.styles = null;
+ });
+ cm.doc.frontier = cm.doc.first;
+ startWorker(cm, 100);
+ cm.state.modeGen++;
+ if (cm.curOp) regChange(cm);
+ }
+
+ function wrappingChanged(cm) {
+ if (cm.options.lineWrapping) {
+ addClass(cm.display.wrapper, "CodeMirror-wrap");
+ cm.display.sizer.style.minWidth = "";
+ cm.display.sizerWidth = null;
+ } else {
+ rmClass(cm.display.wrapper, "CodeMirror-wrap");
+ findMaxLine(cm);
+ }
+ estimateLineHeights(cm);
+ regChange(cm);
+ clearCaches(cm);
+ setTimeout(function(){updateScrollbars(cm);}, 100);
+ }
+
+ // Returns a function that estimates the height of a line, to use as
+ // first approximation until the line becomes visible (and is thus
+ // properly measurable).
+ function estimateHeight(cm) {
+ var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
+ var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
+ return function(line) {
+ if (lineIsHidden(cm.doc, line)) return 0;
+
+ var widgetsHeight = 0;
+ if (line.widgets) for (var i = 0; i < line.widgets.length; i++) {
+ if (line.widgets[i].height) widgetsHeight += line.widgets[i].height;
+ }
+
+ if (wrapping)
+ return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th;
+ else
+ return widgetsHeight + th;
+ };
+ }
+
+ function estimateLineHeights(cm) {
+ var doc = cm.doc, est = estimateHeight(cm);
+ doc.iter(function(line) {
+ var estHeight = est(line);
+ if (estHeight != line.height) updateLineHeight(line, estHeight);
+ });
+ }
+
+ function themeChanged(cm) {
+ cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
+ cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
+ clearCaches(cm);
+ }
+
+ function guttersChanged(cm) {
+ updateGutters(cm);
+ regChange(cm);
+ setTimeout(function(){alignHorizontally(cm);}, 20);
+ }
+
+ // Rebuild the gutter elements, ensure the margin to the left of the
+ // code matches their width.
+ function updateGutters(cm) {
+ var gutters = cm.display.gutters, specs = cm.options.gutters;
+ removeChildren(gutters);
+ for (var i = 0; i < specs.length; ++i) {
+ var gutterClass = specs[i];
+ var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
+ if (gutterClass == "CodeMirror-linenumbers") {
+ cm.display.lineGutter = gElt;
+ gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
+ }
+ }
+ gutters.style.display = i ? "" : "none";
+ updateGutterSpace(cm);
+ }
+
+ function updateGutterSpace(cm) {
+ var width = cm.display.gutters.offsetWidth;
+ cm.display.sizer.style.marginLeft = width + "px";
+ }
+
+ // Compute the character length of a line, taking into account
+ // collapsed ranges (see markText) that might hide parts, and join
+ // other lines onto it.
+ function lineLength(line) {
+ if (line.height == 0) return 0;
+ var len = line.text.length, merged, cur = line;
+ while (merged = collapsedSpanAtStart(cur)) {
+ var found = merged.find(0, true);
+ cur = found.from.line;
+ len += found.from.ch - found.to.ch;
+ }
+ cur = line;
+ while (merged = collapsedSpanAtEnd(cur)) {
+ var found = merged.find(0, true);
+ len -= cur.text.length - found.from.ch;
+ cur = found.to.line;
+ len += cur.text.length - found.to.ch;
+ }
+ return len;
+ }
+
+ // Find the longest line in the document.
+ function findMaxLine(cm) {
+ var d = cm.display, doc = cm.doc;
+ d.maxLine = getLine(doc, doc.first);
+ d.maxLineLength = lineLength(d.maxLine);
+ d.maxLineChanged = true;
+ doc.iter(function(line) {
+ var len = lineLength(line);
+ if (len > d.maxLineLength) {
+ d.maxLineLength = len;
+ d.maxLine = line;
+ }
+ });
+ }
+
+ // Make sure the gutters options contains the element
+ // "CodeMirror-linenumbers" when the lineNumbers option is true.
+ function setGuttersForLineNumbers(options) {
+ var found = indexOf(options.gutters, "CodeMirror-linenumbers");
+ if (found == -1 && options.lineNumbers) {
+ options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
+ } else if (found > -1 && !options.lineNumbers) {
+ options.gutters = options.gutters.slice(0);
+ options.gutters.splice(found, 1);
+ }
+ }
+
+ // SCROLLBARS
+
+ // Prepare DOM reads needed to update the scrollbars. Done in one
+ // shot to minimize update/measure roundtrips.
+ function measureForScrollbars(cm) {
+ var d = cm.display, gutterW = d.gutters.offsetWidth;
+ var docH = Math.round(cm.doc.height + paddingVert(cm.display));
+ return {
+ clientHeight: d.scroller.clientHeight,
+ viewHeight: d.wrapper.clientHeight,
+ scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
+ viewWidth: d.wrapper.clientWidth,
+ barLeft: cm.options.fixedGutter ? gutterW : 0,
+ docHeight: docH,
+ scrollHeight: docH + scrollGap(cm) + d.barHeight,
+ nativeBarWidth: d.nativeBarWidth,
+ gutterWidth: gutterW
+ };
+ }
+
+ function NativeScrollbars(place, scroll, cm) {
+ this.cm = cm;
+ var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
+ var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
+ place(vert); place(horiz);
+
+ on(vert, "scroll", function() {
+ if (vert.clientHeight) scroll(vert.scrollTop, "vertical");
+ });
+ on(horiz, "scroll", function() {
+ if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal");
+ });
+
+ this.checkedOverlay = false;
+ // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
+ if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px";
+ }
+
+ NativeScrollbars.prototype = copyObj({
+ update: function(measure) {
+ var needsH = measure.scrollWidth > measure.clientWidth + 1;
+ var needsV = measure.scrollHeight > measure.clientHeight + 1;
+ var sWidth = measure.nativeBarWidth;
+
+ if (needsV) {
+ this.vert.style.display = "block";
+ this.vert.style.bottom = needsH ? sWidth + "px" : "0";
+ var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);
+ // A bug in IE8 can cause this value to be negative, so guard it.
+ this.vert.firstChild.style.height =
+ Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px";
+ } else {
+ this.vert.style.display = "";
+ this.vert.firstChild.style.height = "0";
+ }
+
+ if (needsH) {
+ this.horiz.style.display = "block";
+ this.horiz.style.right = needsV ? sWidth + "px" : "0";
+ this.horiz.style.left = measure.barLeft + "px";
+ var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);
+ this.horiz.firstChild.style.width =
+ (measure.scrollWidth - measure.clientWidth + totalWidth) + "px";
+ } else {
+ this.horiz.style.display = "";
+ this.horiz.firstChild.style.width = "0";
+ }
+
+ if (!this.checkedOverlay && measure.clientHeight > 0) {
+ if (sWidth == 0) this.overlayHack();
+ this.checkedOverlay = true;
+ }
+
+ return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0};
+ },
+ setScrollLeft: function(pos) {
+ if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos;
+ },
+ setScrollTop: function(pos) {
+ if (this.vert.scrollTop != pos) this.vert.scrollTop = pos;
+ },
+ overlayHack: function() {
+ var w = mac && !mac_geMountainLion ? "12px" : "18px";
+ this.horiz.style.minHeight = this.vert.style.minWidth = w;
+ var self = this;
+ var barMouseDown = function(e) {
+ if (e_target(e) != self.vert && e_target(e) != self.horiz)
+ operation(self.cm, onMouseDown)(e);
+ };
+ on(this.vert, "mousedown", barMouseDown);
+ on(this.horiz, "mousedown", barMouseDown);
+ },
+ clear: function() {
+ var parent = this.horiz.parentNode;
+ parent.removeChild(this.horiz);
+ parent.removeChild(this.vert);
+ }
+ }, NativeScrollbars.prototype);
+
+ function NullScrollbars() {}
+
+ NullScrollbars.prototype = copyObj({
+ update: function() { return {bottom: 0, right: 0}; },
+ setScrollLeft: function() {},
+ setScrollTop: function() {},
+ clear: function() {}
+ }, NullScrollbars.prototype);
+
+ CodeMirror.scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars};
+
+ function initScrollbars(cm) {
+ if (cm.display.scrollbars) {
+ cm.display.scrollbars.clear();
+ if (cm.display.scrollbars.addClass)
+ rmClass(cm.display.wrapper, cm.display.scrollbars.addClass);
+ }
+
+ cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node) {
+ cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
+ // Prevent clicks in the scrollbars from killing focus
+ on(node, "mousedown", function() {
+ if (cm.state.focused) setTimeout(function() { cm.display.input.focus(); }, 0);
+ });
+ node.setAttribute("cm-not-content", "true");
+ }, function(pos, axis) {
+ if (axis == "horizontal") setScrollLeft(cm, pos);
+ else setScrollTop(cm, pos);
+ }, cm);
+ if (cm.display.scrollbars.addClass)
+ addClass(cm.display.wrapper, cm.display.scrollbars.addClass);
+ }
+
+ function updateScrollbars(cm, measure) {
+ if (!measure) measure = measureForScrollbars(cm);
+ var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
+ updateScrollbarsInner(cm, measure);
+ for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
+ if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
+ updateHeightsInViewport(cm);
+ updateScrollbarsInner(cm, measureForScrollbars(cm));
+ startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
+ }
+ }
+
+ // Re-synchronize the fake scrollbars with the actual size of the
+ // content.
+ function updateScrollbarsInner(cm, measure) {
+ var d = cm.display;
+ var sizes = d.scrollbars.update(measure);
+
+ d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
+ d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
+
+ if (sizes.right && sizes.bottom) {
+ d.scrollbarFiller.style.display = "block";
+ d.scrollbarFiller.style.height = sizes.bottom + "px";
+ d.scrollbarFiller.style.width = sizes.right + "px";
+ } else d.scrollbarFiller.style.display = "";
+ if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
+ d.gutterFiller.style.display = "block";
+ d.gutterFiller.style.height = sizes.bottom + "px";
+ d.gutterFiller.style.width = measure.gutterWidth + "px";
+ } else d.gutterFiller.style.display = "";
+ }
+
+ // Compute the lines that are visible in a given viewport (defaults
+ // the the current scroll position). viewport may contain top,
+ // height, and ensure (see op.scrollToPos) properties.
+ function visibleLines(display, doc, viewport) {
+ var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;
+ top = Math.floor(top - paddingTop(display));
+ var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;
+
+ var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
+ // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
+ // forces those lines into the viewport (if possible).
+ if (viewport && viewport.ensure) {
+ var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
+ if (ensureFrom < from) {
+ from = ensureFrom;
+ to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
+ } else if (Math.min(ensureTo, doc.lastLine()) >= to) {
+ from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
+ to = ensureTo;
+ }
+ }
+ return {from: from, to: Math.max(to, from + 1)};
+ }
+
+ // LINE NUMBERS
+
+ // Re-align line numbers and gutter marks to compensate for
+ // horizontal scrolling.
+ function alignHorizontally(cm) {
+ var display = cm.display, view = display.view;
+ if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return;
+ var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
+ var gutterW = display.gutters.offsetWidth, left = comp + "px";
+ for (var i = 0; i < view.length; i++) if (!view[i].hidden) {
+ if (cm.options.fixedGutter && view[i].gutter)
+ view[i].gutter.style.left = left;
+ var align = view[i].alignable;
+ if (align) for (var j = 0; j < align.length; j++)
+ align[j].style.left = left;
+ }
+ if (cm.options.fixedGutter)
+ display.gutters.style.left = (comp + gutterW) + "px";
+ }
+
+ // Used to ensure that the line number gutter is still the right
+ // size for the current document size. Returns true when an update
+ // is needed.
+ function maybeUpdateLineNumberWidth(cm) {
+ if (!cm.options.lineNumbers) return false;
+ var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
+ if (last.length != display.lineNumChars) {
+ var test = display.measure.appendChild(elt("div", [elt("div", last)],
+ "CodeMirror-linenumber CodeMirror-gutter-elt"));
+ var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
+ display.lineGutter.style.width = "";
+ display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;
+ display.lineNumWidth = display.lineNumInnerWidth + padding;
+ display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
+ display.lineGutter.style.width = display.lineNumWidth + "px";
+ updateGutterSpace(cm);
+ return true;
+ }
+ return false;
+ }
+
+ function lineNumberFor(options, i) {
+ return String(options.lineNumberFormatter(i + options.firstLineNumber));
+ }
+
+ // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
+ // but using getBoundingClientRect to get a sub-pixel-accurate
+ // result.
+ function compensateForHScroll(display) {
+ return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left;
+ }
+
+ // DISPLAY DRAWING
+
+ function DisplayUpdate(cm, viewport, force) {
+ var display = cm.display;
+
+ this.viewport = viewport;
+ // Store some values that we'll need later (but don't want to force a relayout for)
+ this.visible = visibleLines(display, cm.doc, viewport);
+ this.editorIsHidden = !display.wrapper.offsetWidth;
+ this.wrapperHeight = display.wrapper.clientHeight;
+ this.wrapperWidth = display.wrapper.clientWidth;
+ this.oldDisplayWidth = displayWidth(cm);
+ this.force = force;
+ this.dims = getDimensions(cm);
+ this.events = [];
+ }
+
+ DisplayUpdate.prototype.signal = function(emitter, type) {
+ if (hasHandler(emitter, type))
+ this.events.push(arguments);
+ };
+ DisplayUpdate.prototype.finish = function() {
+ for (var i = 0; i < this.events.length; i++)
+ signal.apply(null, this.events[i]);
+ };
+
+ function maybeClipScrollbars(cm) {
+ var display = cm.display;
+ if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
+ display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;
+ display.heightForcer.style.height = scrollGap(cm) + "px";
+ display.sizer.style.marginBottom = -display.nativeBarWidth + "px";
+ display.sizer.style.borderRightWidth = scrollGap(cm) + "px";
+ display.scrollbarsClipped = true;
+ }
+ }
+
+ // Does the actual updating of the line display. Bails out
+ // (returning false) when there is nothing to be done and forced is
+ // false.
+ function updateDisplayIfNeeded(cm, update) {
+ var display = cm.display, doc = cm.doc;
+
+ if (update.editorIsHidden) {
+ resetView(cm);
+ return false;
+ }
+
+ // Bail out if the visible area is already rendered and nothing changed.
+ if (!update.force &&
+ update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
+ (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
+ display.renderedView == display.view && countDirtyView(cm) == 0)
+ return false;
+
+ if (maybeUpdateLineNumberWidth(cm)) {
+ resetView(cm);
+ update.dims = getDimensions(cm);
+ }
+
+ // Compute a suitable new viewport (from & to)
+ var end = doc.first + doc.size;
+ var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
+ var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
+ if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom);
+ if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo);
+ if (sawCollapsedSpans) {
+ from = visualLineNo(cm.doc, from);
+ to = visualLineEndNo(cm.doc, to);
+ }
+
+ var different = from != display.viewFrom || to != display.viewTo ||
+ display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;
+ adjustView(cm, from, to);
+
+ display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
+ // Position the mover div to align with the current scroll position
+ cm.display.mover.style.top = display.viewOffset + "px";
+
+ var toUpdate = countDirtyView(cm);
+ if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&
+ (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
+ return false;
+
+ // For big changes, we hide the enclosing element during the
+ // update, since that speeds up the operations on most browsers.
+ var focused = activeElt();
+ if (toUpdate > 4) display.lineDiv.style.display = "none";
+ patchDisplay(cm, display.updateLineNumbers, update.dims);
+ if (toUpdate > 4) display.lineDiv.style.display = "";
+ display.renderedView = display.view;
+ // There might have been a widget with a focused element that got
+ // hidden or updated, if so re-focus it.
+ if (focused && activeElt() != focused && focused.offsetHeight) focused.focus();
+
+ // Prevent selection and cursors from interfering with the scroll
+ // width and height.
+ removeChildren(display.cursorDiv);
+ removeChildren(display.selectionDiv);
+ display.gutters.style.height = 0;
+
+ if (different) {
+ display.lastWrapHeight = update.wrapperHeight;
+ display.lastWrapWidth = update.wrapperWidth;
+ startWorker(cm, 400);
+ }
+
+ display.updateLineNumbers = null;
+
+ return true;
+ }
+
+ function postUpdateDisplay(cm, update) {
+ var force = update.force, viewport = update.viewport;
+ for (var first = true;; first = false) {
+ if (first && cm.options.lineWrapping && update.oldDisplayWidth != displayWidth(cm)) {
+ force = true;
+ } else {
+ force = false;
+ // Clip forced viewport to actual scrollable area.
+ if (viewport && viewport.top != null)
+ viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)};
+ // Updated line heights might result in the drawn area not
+ // actually covering the viewport. Keep looping until it does.
+ update.visible = visibleLines(cm.display, cm.doc, viewport);
+ if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
+ break;
+ }
+ if (!updateDisplayIfNeeded(cm, update)) break;
+ updateHeightsInViewport(cm);
+ var barMeasure = measureForScrollbars(cm);
+ updateSelection(cm);
+ setDocumentHeight(cm, barMeasure);
+ updateScrollbars(cm, barMeasure);
+ }
+
+ update.signal(cm, "update", cm);
+ if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
+ update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
+ cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;
+ }
+ }
+
+ function updateDisplaySimple(cm, viewport) {
+ var update = new DisplayUpdate(cm, viewport);
+ if (updateDisplayIfNeeded(cm, update)) {
+ updateHeightsInViewport(cm);
+ postUpdateDisplay(cm, update);
+ var barMeasure = measureForScrollbars(cm);
+ updateSelection(cm);
+ setDocumentHeight(cm, barMeasure);
+ updateScrollbars(cm, barMeasure);
+ update.finish();
+ }
+ }
+
+ function setDocumentHeight(cm, measure) {
+ cm.display.sizer.style.minHeight = measure.docHeight + "px";
+ var total = measure.docHeight + cm.display.barHeight;
+ cm.display.heightForcer.style.top = total + "px";
+ cm.display.gutters.style.height = Math.max(total + scrollGap(cm), measure.clientHeight) + "px";
+ }
+
+ // Read the actual heights of the rendered lines, and update their
+ // stored heights to match.
+ function updateHeightsInViewport(cm) {
+ var display = cm.display;
+ var prevBottom = display.lineDiv.offsetTop;
+ for (var i = 0; i < display.view.length; i++) {
+ var cur = display.view[i], height;
+ if (cur.hidden) continue;
+ if (ie && ie_version < 8) {
+ var bot = cur.node.offsetTop + cur.node.offsetHeight;
+ height = bot - prevBottom;
+ prevBottom = bot;
+ } else {
+ var box = cur.node.getBoundingClientRect();
+ height = box.bottom - box.top;
+ }
+ var diff = cur.line.height - height;
+ if (height < 2) height = textHeight(display);
+ if (diff > .001 || diff < -.001) {
+ updateLineHeight(cur.line, height);
+ updateWidgetHeight(cur.line);
+ if (cur.rest) for (var j = 0; j < cur.rest.length; j++)
+ updateWidgetHeight(cur.rest[j]);
+ }
+ }
+ }
+
+ // Read and store the height of line widgets associated with the
+ // given line.
+ function updateWidgetHeight(line) {
+ if (line.widgets) for (var i = 0; i < line.widgets.length; ++i)
+ line.widgets[i].height = line.widgets[i].node.offsetHeight;
+ }
+
+ // Do a bulk-read of the DOM positions and sizes needed to draw the
+ // view, so that we don't interleave reading and writing to the DOM.
+ function getDimensions(cm) {
+ var d = cm.display, left = {}, width = {};
+ var gutterLeft = d.gutters.clientLeft;
+ for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
+ left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;
+ width[cm.options.gutters[i]] = n.clientWidth;
+ }
+ return {fixedPos: compensateForHScroll(d),
+ gutterTotalWidth: d.gutters.offsetWidth,
+ gutterLeft: left,
+ gutterWidth: width,
+ wrapperWidth: d.wrapper.clientWidth};
+ }
+
+ // Sync the actual display DOM structure with display.view, removing
+ // nodes for lines that are no longer in view, and creating the ones
+ // that are not there yet, and updating the ones that are out of
+ // date.
+ function patchDisplay(cm, updateNumbersFrom, dims) {
+ var display = cm.display, lineNumbers = cm.options.lineNumbers;
+ var container = display.lineDiv, cur = container.firstChild;
+
+ function rm(node) {
+ var next = node.nextSibling;
+ // Works around a throw-scroll bug in OS X Webkit
+ if (webkit && mac && cm.display.currentWheelTarget == node)
+ node.style.display = "none";
+ else
+ node.parentNode.removeChild(node);
+ return next;
+ }
+
+ var view = display.view, lineN = display.viewFrom;
+ // Loop over the elements in the view, syncing cur (the DOM nodes
+ // in display.lineDiv) with the view as we go.
+ for (var i = 0; i < view.length; i++) {
+ var lineView = view[i];
+ if (lineView.hidden) {
+ } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
+ var node = buildLineElement(cm, lineView, lineN, dims);
+ container.insertBefore(node, cur);
+ } else { // Already drawn
+ while (cur != lineView.node) cur = rm(cur);
+ var updateNumber = lineNumbers && updateNumbersFrom != null &&
+ updateNumbersFrom <= lineN && lineView.lineNumber;
+ if (lineView.changes) {
+ if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false;
+ updateLineForChanges(cm, lineView, lineN, dims);
+ }
+ if (updateNumber) {
+ removeChildren(lineView.lineNumber);
+ lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
+ }
+ cur = lineView.node.nextSibling;
+ }
+ lineN += lineView.size;
+ }
+ while (cur) cur = rm(cur);
+ }
+
+ // When an aspect of a line changes, a string is added to
+ // lineView.changes. This updates the relevant part of the line's
+ // DOM structure.
+ function updateLineForChanges(cm, lineView, lineN, dims) {
+ for (var j = 0; j < lineView.changes.length; j++) {
+ var type = lineView.changes[j];
+ if (type == "text") updateLineText(cm, lineView);
+ else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims);
+ else if (type == "class") updateLineClasses(lineView);
+ else if (type == "widget") updateLineWidgets(cm, lineView, dims);
+ }
+ lineView.changes = null;
+ }
+
+ // Lines with gutter elements, widgets or a background class need to
+ // be wrapped, and have the extra elements added to the wrapper div
+ function ensureLineWrapped(lineView) {
+ if (lineView.node == lineView.text) {
+ lineView.node = elt("div", null, null, "position: relative");
+ if (lineView.text.parentNode)
+ lineView.text.parentNode.replaceChild(lineView.node, lineView.text);
+ lineView.node.appendChild(lineView.text);
+ if (ie && ie_version < 8) lineView.node.style.zIndex = 2;
+ }
+ return lineView.node;
+ }
+
+ function updateLineBackground(lineView) {
+ var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
+ if (cls) cls += " CodeMirror-linebackground";
+ if (lineView.background) {
+ if (cls) lineView.background.className = cls;
+ else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
+ } else if (cls) {
+ var wrap = ensureLineWrapped(lineView);
+ lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
+ }
+ }
+
+ // Wrapper around buildLineContent which will reuse the structure
+ // in display.externalMeasured when possible.
+ function getLineContent(cm, lineView) {
+ var ext = cm.display.externalMeasured;
+ if (ext && ext.line == lineView.line) {
+ cm.display.externalMeasured = null;
+ lineView.measure = ext.measure;
+ return ext.built;
+ }
+ return buildLineContent(cm, lineView);
+ }
+
+ // Redraw the line's text. Interacts with the background and text
+ // classes because the mode may output tokens that influence these
+ // classes.
+ function updateLineText(cm, lineView) {
+ var cls = lineView.text.className;
+ var built = getLineContent(cm, lineView);
+ if (lineView.text == lineView.node) lineView.node = built.pre;
+ lineView.text.parentNode.replaceChild(built.pre, lineView.text);
+ lineView.text = built.pre;
+ if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
+ lineView.bgClass = built.bgClass;
+ lineView.textClass = built.textClass;
+ updateLineClasses(lineView);
+ } else if (cls) {
+ lineView.text.className = cls;
+ }
+ }
+
+ function updateLineClasses(lineView) {
+ updateLineBackground(lineView);
+ if (lineView.line.wrapClass)
+ ensureLineWrapped(lineView).className = lineView.line.wrapClass;
+ else if (lineView.node != lineView.text)
+ lineView.node.className = "";
+ var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
+ lineView.text.className = textClass || "";
+ }
+
+ function updateLineGutter(cm, lineView, lineN, dims) {
+ if (lineView.gutter) {
+ lineView.node.removeChild(lineView.gutter);
+ lineView.gutter = null;
+ }
+ var markers = lineView.line.gutterMarkers;
+ if (cm.options.lineNumbers || markers) {
+ var wrap = ensureLineWrapped(lineView);
+ var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " +
+ (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) +
+ "px; width: " + dims.gutterTotalWidth + "px");
+ cm.display.input.setUneditable(gutterWrap);
+ wrap.insertBefore(gutterWrap, lineView.text);
+ if (lineView.line.gutterClass)
+ gutterWrap.className += " " + lineView.line.gutterClass;
+ if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
+ lineView.lineNumber = gutterWrap.appendChild(
+ elt("div", lineNumberFor(cm.options, lineN),
+ "CodeMirror-linenumber CodeMirror-gutter-elt",
+ "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: "
+ + cm.display.lineNumInnerWidth + "px"));
+ if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) {
+ var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
+ if (found)
+ gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " +
+ dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px"));
+ }
+ }
+ }
+
+ function updateLineWidgets(cm, lineView, dims) {
+ if (lineView.alignable) lineView.alignable = null;
+ for (var node = lineView.node.firstChild, next; node; node = next) {
+ var next = node.nextSibling;
+ if (node.className == "CodeMirror-linewidget")
+ lineView.node.removeChild(node);
+ }
+ insertLineWidgets(cm, lineView, dims);
+ }
+
+ // Build a line's DOM representation from scratch
+ function buildLineElement(cm, lineView, lineN, dims) {
+ var built = getLineContent(cm, lineView);
+ lineView.text = lineView.node = built.pre;
+ if (built.bgClass) lineView.bgClass = built.bgClass;
+ if (built.textClass) lineView.textClass = built.textClass;
+
+ updateLineClasses(lineView);
+ updateLineGutter(cm, lineView, lineN, dims);
+ insertLineWidgets(cm, lineView, dims);
+ return lineView.node;
+ }
+
+ // A lineView may contain multiple logical lines (when merged by
+ // collapsed spans). The widgets for all of them need to be drawn.
+ function insertLineWidgets(cm, lineView, dims) {
+ insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);
+ if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
+ insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false);
+ }
+
+ function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
+ if (!line.widgets) return;
+ var wrap = ensureLineWrapped(lineView);
+ for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
+ var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
+ if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true");
+ positionLineWidget(widget, node, lineView, dims);
+ cm.display.input.setUneditable(node);
+ if (allowAbove && widget.above)
+ wrap.insertBefore(node, lineView.gutter || lineView.text);
+ else
+ wrap.appendChild(node);
+ signalLater(widget, "redraw");
+ }
+ }
+
+ function positionLineWidget(widget, node, lineView, dims) {
+ if (widget.noHScroll) {
+ (lineView.alignable || (lineView.alignable = [])).push(node);
+ var width = dims.wrapperWidth;
+ node.style.left = dims.fixedPos + "px";
+ if (!widget.coverGutter) {
+ width -= dims.gutterTotalWidth;
+ node.style.paddingLeft = dims.gutterTotalWidth + "px";
+ }
+ node.style.width = width + "px";
+ }
+ if (widget.coverGutter) {
+ node.style.zIndex = 5;
+ node.style.position = "relative";
+ if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px";
+ }
+ }
+
+ // POSITION OBJECT
+
+ // A Pos instance represents a position within the text.
+ var Pos = CodeMirror.Pos = function(line, ch) {
+ if (!(this instanceof Pos)) return new Pos(line, ch);
+ this.line = line; this.ch = ch;
+ };
+
+ // Compare two positions, return 0 if they are the same, a negative
+ // number when a is less, and a positive number otherwise.
+ var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || a.ch - b.ch; };
+
+ function copyPos(x) {return Pos(x.line, x.ch);}
+ function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; }
+ function minPos(a, b) { return cmp(a, b) < 0 ? a : b; }
+
+ // INPUT HANDLING
+
+ function ensureFocus(cm) {
+ if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
+ }
+
+ function isReadOnly(cm) {
+ return cm.options.readOnly || cm.doc.cantEdit;
+ }
+
+ // This will be set to an array of strings when copying, so that,
+ // when pasting, we know what kind of selections the copied text
+ // was made out of.
+ var lastCopied = null;
+
+ function applyTextInput(cm, inserted, deleted, sel) {
+ var doc = cm.doc;
+ cm.display.shift = false;
+ if (!sel) sel = doc.sel;
+
+ var textLines = splitLines(inserted), multiPaste = null;
+ // When pasing N lines into N selections, insert one line per selection
+ if (cm.state.pasteIncoming && sel.ranges.length > 1) {
+ if (lastCopied && lastCopied.join("\n") == inserted)
+ multiPaste = sel.ranges.length % lastCopied.length == 0 && map(lastCopied, splitLines);
+ else if (textLines.length == sel.ranges.length)
+ multiPaste = map(textLines, function(l) { return [l]; });
+ }
+
+ // Normal behavior is to insert the new text into every selection
+ for (var i = sel.ranges.length - 1; i >= 0; i--) {
+ var range = sel.ranges[i];
+ var from = range.from(), to = range.to();
+ if (range.empty()) {
+ if (deleted && deleted > 0) // Handle deletion
+ from = Pos(from.line, from.ch - deleted);
+ else if (cm.state.overwrite && !cm.state.pasteIncoming) // Handle overwrite
+ to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length));
+ }
+ var updateInput = cm.curOp.updateInput;
+ var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines,
+ origin: cm.state.pasteIncoming ? "paste" : cm.state.cutIncoming ? "cut" : "+input"};
+ makeChange(cm.doc, changeEvent);
+ signalLater(cm, "inputRead", cm, changeEvent);
+ // When an 'electric' character is inserted, immediately trigger a reindent
+ if (inserted && !cm.state.pasteIncoming && cm.options.electricChars &&
+ cm.options.smartIndent && range.head.ch < 100 &&
+ (!i || sel.ranges[i - 1].head.line != range.head.line)) {
+ var mode = cm.getModeAt(range.head);
+ var end = changeEnd(changeEvent);
+ if (mode.electricChars) {
+ for (var j = 0; j < mode.electricChars.length; j++)
+ if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
+ indentLine(cm, end.line, "smart");
+ break;
+ }
+ } else if (mode.electricInput) {
+ if (mode.electricInput.test(getLine(doc, end.line).text.slice(0, end.ch)))
+ indentLine(cm, end.line, "smart");
+ }
+ }
+ }
+ ensureCursorVisible(cm);
+ cm.curOp.updateInput = updateInput;
+ cm.curOp.typing = true;
+ cm.state.pasteIncoming = cm.state.cutIncoming = false;
+ }
+
+ function copyableRanges(cm) {
+ var text = [], ranges = [];
+ for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
+ var line = cm.doc.sel.ranges[i].head.line;
+ var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
+ ranges.push(lineRange);
+ text.push(cm.getRange(lineRange.anchor, lineRange.head));
+ }
+ return {text: text, ranges: ranges};
+ }
+
+ function disableBrowserMagic(field) {
+ field.setAttribute("autocorrect", "off");
+ field.setAttribute("autocapitalize", "off");
+ field.setAttribute("spellcheck", "false");
+ }
+
+ // TEXTAREA INPUT STYLE
+
+ function TextareaInput(cm) {
+ this.cm = cm;
+ // See input.poll and input.reset
+ this.prevInput = "";
+
+ // Flag that indicates whether we expect input to appear real soon
+ // now (after some event like 'keypress' or 'input') and are
+ // polling intensively.
+ this.pollingFast = false;
+ // Self-resetting timeout for the poller
+ this.polling = new Delayed();
+ // Tracks when input.reset has punted to just putting a short
+ // string into the textarea instead of the full selection.
+ this.inaccurateSelection = false;
+ // Used to work around IE issue with selection being forgotten when focus moves away from textarea
+ this.hasSelection = false;
+ };
+
+ function hiddenTextarea() {
+ var te = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none");
+ var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
+ // The textarea is kept positioned near the cursor to prevent the
+ // fact that it'll be scrolled into view on input from scrolling
+ // our fake cursor out of view. On webkit, when wrap=off, paste is
+ // very slow. So make the area wide instead.
+ if (webkit) te.style.width = "1000px";
+ else te.setAttribute("wrap", "off");
+ // If border: 0; -- iOS fails to open keyboard (issue #1287)
+ if (ios) te.style.border = "1px solid black";
+ disableBrowserMagic(te);
+ return div;
+ }
+
+ TextareaInput.prototype = copyObj({
+ init: function(display) {
+ var input = this, cm = this.cm;
+
+ // Wraps and hides input textarea
+ var div = this.wrapper = hiddenTextarea();
+ // The semihidden textarea that is focused when the editor is
+ // focused, and receives input.
+ var te = this.textarea = div.firstChild;
+ display.wrapper.insertBefore(div, display.wrapper.firstChild);
+
+ // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
+ if (ios) te.style.width = "0px";
+
+ on(te, "input", function() {
+ if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null;
+ input.poll();
+ });
+
+ on(te, "paste", function() {
+ // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206
+ // Add a char to the end of textarea before paste occur so that
+ // selection doesn't span to the end of textarea.
+ if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleDown < 200)) {
+ var start = te.selectionStart, end = te.selectionEnd;
+ te.value += "$";
+ // The selection end needs to be set before the start, otherwise there
+ // can be an intermediate non-empty selection between the two, which
+ // can override the middle-click paste buffer on linux and cause the
+ // wrong thing to get pasted.
+ te.selectionEnd = end;
+ te.selectionStart = start;
+ cm.state.fakedLastChar = true;
+ }
+ cm.state.pasteIncoming = true;
+ input.fastPoll();
+ });
+
+ function prepareCopyCut(e) {
+ if (cm.somethingSelected()) {
+ lastCopied = cm.getSelections();
+ if (input.inaccurateSelection) {
+ input.prevInput = "";
+ input.inaccurateSelection = false;
+ te.value = lastCopied.join("\n");
+ selectInput(te);
+ }
+ } else if (!cm.options.lineWiseCopyCut) {
+ return;
+ } else {
+ var ranges = copyableRanges(cm);
+ lastCopied = ranges.text;
+ if (e.type == "cut") {
+ cm.setSelections(ranges.ranges, null, sel_dontScroll);
+ } else {
+ input.prevInput = "";
+ te.value = ranges.text.join("\n");
+ selectInput(te);
+ }
+ }
+ if (e.type == "cut") cm.state.cutIncoming = true;
+ }
+ on(te, "cut", prepareCopyCut);
+ on(te, "copy", prepareCopyCut);
+
+ on(display.scroller, "paste", function(e) {
+ if (eventInWidget(display, e)) return;
+ cm.state.pasteIncoming = true;
+ input.focus();
+ });
+
+ // Prevent normal selection in the editor (we handle our own)
+ on(display.lineSpace, "selectstart", function(e) {
+ if (!eventInWidget(display, e)) e_preventDefault(e);
+ });
+ },
+
+ prepareSelection: function() {
+ // Redraw the selection and/or cursor
+ var cm = this.cm, display = cm.display, doc = cm.doc;
+ var result = prepareSelection(cm);
+
+ // Move the hidden textarea near the cursor to prevent scrolling artifacts
+ if (cm.options.moveInputWithCursor) {
+ var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
+ var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
+ result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
+ headPos.top + lineOff.top - wrapOff.top));
+ result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
+ headPos.left + lineOff.left - wrapOff.left));
+ }
+
+ return result;
+ },
+
+ showSelection: function(drawn) {
+ var cm = this.cm, display = cm.display;
+ removeChildrenAndAdd(display.cursorDiv, drawn.cursors);
+ removeChildrenAndAdd(display.selectionDiv, drawn.selection);
+ if (drawn.teTop != null) {
+ this.wrapper.style.top = drawn.teTop + "px";
+ this.wrapper.style.left = drawn.teLeft + "px";
+ }
+ },
+
+ // Reset the input to correspond to the selection (or to be empty,
+ // when not typing and nothing is selected)
+ reset: function(typing) {
+ if (this.contextMenuPending) return;
+ var minimal, selected, cm = this.cm, doc = cm.doc;
+ if (cm.somethingSelected()) {
+ this.prevInput = "";
+ var range = doc.sel.primary();
+ minimal = hasCopyEvent &&
+ (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000);
+ var content = minimal ? "-" : selected || cm.getSelection();
+ this.textarea.value = content;
+ if (cm.state.focused) selectInput(this.textarea);
+ if (ie && ie_version >= 9) this.hasSelection = content;
+ } else if (!typing) {
+ this.prevInput = this.textarea.value = "";
+ if (ie && ie_version >= 9) this.hasSelection = null;
+ }
+ this.inaccurateSelection = minimal;
+ },
+
+ getField: function() { return this.textarea; },
+
+ supportsTouch: function() { return false; },
+
+ focus: function() {
+ if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) {
+ try { this.textarea.focus(); }
+ catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM
+ }
+ },
+
+ blur: function() { this.textarea.blur(); },
+
+ resetPosition: function() {
+ this.wrapper.style.top = this.wrapper.style.left = 0;
+ },
+
+ receivedFocus: function() { this.slowPoll(); },
+
+ // Poll for input changes, using the normal rate of polling. This
+ // runs as long as the editor is focused.
+ slowPoll: function() {
+ var input = this;
+ if (input.pollingFast) return;
+ input.polling.set(this.cm.options.pollInterval, function() {
+ input.poll();
+ if (input.cm.state.focused) input.slowPoll();
+ });
+ },
+
+ // When an event has just come in that is likely to add or change
+ // something in the input textarea, we poll faster, to ensure that
+ // the change appears on the screen quickly.
+ fastPoll: function() {
+ var missed = false, input = this;
+ input.pollingFast = true;
+ function p() {
+ var changed = input.poll();
+ if (!changed && !missed) {missed = true; input.polling.set(60, p);}
+ else {input.pollingFast = false; input.slowPoll();}
+ }
+ input.polling.set(20, p);
+ },
+
+ // Read input from the textarea, and update the document to match.
+ // When something is selected, it is present in the textarea, and
+ // selected (unless it is huge, in which case a placeholder is
+ // used). When nothing is selected, the cursor sits after previously
+ // seen text (can be empty), which is stored in prevInput (we must
+ // not reset the textarea when typing, because that breaks IME).
+ poll: function() {
+ var cm = this.cm, input = this.textarea, prevInput = this.prevInput;
+ // Since this is called a *lot*, try to bail out as cheaply as
+ // possible when it is clear that nothing happened. hasSelection
+ // will be the case when there is a lot of text in the textarea,
+ // in which case reading its value would be expensive.
+ if (!cm.state.focused || (hasSelection(input) && !prevInput) ||
+ isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq)
+ return false;
+ // See paste handler for more on the fakedLastChar kludge
+ if (cm.state.pasteIncoming && cm.state.fakedLastChar) {
+ input.value = input.value.substring(0, input.value.length - 1);
+ cm.state.fakedLastChar = false;
+ }
+ var text = input.value;
+ // If nothing changed, bail.
+ if (text == prevInput && !cm.somethingSelected()) return false;
+ // Work around nonsensical selection resetting in IE9/10, and
+ // inexplicable appearance of private area unicode characters on
+ // some key combos in Mac (#2689).
+ if (ie && ie_version >= 9 && this.hasSelection === text ||
+ mac && /[\uf700-\uf7ff]/.test(text)) {
+ cm.display.input.reset();
+ return false;
+ }
+
+ if (cm.doc.sel == cm.display.selForContextMenu) {
+ var first = text.charCodeAt(0);
+ if (first == 0x200b && !prevInput) prevInput = "\u200b";
+ if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo"); }
+ }
+ // Find the part of the input that is actually new
+ var same = 0, l = Math.min(prevInput.length, text.length);
+ while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same;
+
+ var self = this;
+ runInOp(cm, function() {
+ applyTextInput(cm, text.slice(same), prevInput.length - same);
+
+ // Don't leave long text in the textarea, since it makes further polling slow
+ if (text.length > 1000 || text.indexOf("\n") > -1) input.value = self.prevInput = "";
+ else self.prevInput = text;
+ });
+ return true;
+ },
+
+ ensurePolled: function() {
+ if (this.pollingFast && this.poll()) this.pollingFast = false;
+ },
+
+ onKeyPress: function() {
+ if (ie && ie_version >= 9) this.hasSelection = null;
+ this.fastPoll();
+ },
+
+ onContextMenu: function(e) {
+ var input = this, cm = input.cm, display = cm.display, te = input.textarea;
+ var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
+ if (!pos || presto) return; // Opera is difficult.
+
+ // Reset the current text selection only if the click is done outside of the selection
+ // and 'resetSelectionOnContextMenu' option is true.
+ var reset = cm.options.resetSelectionOnContextMenu;
+ if (reset && cm.doc.sel.contains(pos) == -1)
+ operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll);
+
+ var oldCSS = te.style.cssText;
+ input.wrapper.style.position = "absolute";
+ te.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
+ "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " +
+ (ie ? "rgba(255, 255, 255, .05)" : "transparent") +
+ "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
+ if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712)
+ display.input.focus();
+ if (webkit) window.scrollTo(null, oldScrollY);
+ display.input.reset();
+ // Adds "Select all" to context menu in FF
+ if (!cm.somethingSelected()) te.value = input.prevInput = " ";
+ input.contextMenuPending = true;
+ display.selForContextMenu = cm.doc.sel;
+ clearTimeout(display.detectingSelectAll);
+
+ // Select-all will be greyed out if there's nothing to select, so
+ // this adds a zero-width space so that we can later check whether
+ // it got selected.
+ function prepareSelectAllHack() {
+ if (te.selectionStart != null) {
+ var selected = cm.somethingSelected();
+ var extval = "\u200b" + (selected ? te.value : "");
+ te.value = "\u21da"; // Used to catch context-menu undo
+ te.value = extval;
+ input.prevInput = selected ? "" : "\u200b";
+ te.selectionStart = 1; te.selectionEnd = extval.length;
+ // Re-set this, in case some other handler touched the
+ // selection in the meantime.
+ display.selForContextMenu = cm.doc.sel;
+ }
+ }
+ function rehide() {
+ input.contextMenuPending = false;
+ input.wrapper.style.position = "relative";
+ te.style.cssText = oldCSS;
+ if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos);
+
+ // Try to detect the user choosing select-all
+ if (te.selectionStart != null) {
+ if (!ie || (ie && ie_version < 9)) prepareSelectAllHack();
+ var i = 0, poll = function() {
+ if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&
+ te.selectionEnd > 0 && input.prevInput == "\u200b")
+ operation(cm, commands.selectAll)(cm);
+ else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500);
+ else display.input.reset();
+ };
+ display.detectingSelectAll = setTimeout(poll, 200);
+ }
+ }
+
+ if (ie && ie_version >= 9) prepareSelectAllHack();
+ if (captureRightClick) {
+ e_stop(e);
+ var mouseup = function() {
+ off(window, "mouseup", mouseup);
+ setTimeout(rehide, 20);
+ };
+ on(window, "mouseup", mouseup);
+ } else {
+ setTimeout(rehide, 50);
+ }
+ },
+
+ setUneditable: nothing,
+
+ needsContentAttribute: false
+ }, TextareaInput.prototype);
+
+ // CONTENTEDITABLE INPUT STYLE
+
+ function ContentEditableInput(cm) {
+ this.cm = cm;
+ this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;
+ this.polling = new Delayed();
+ this.gracePeriod = false;
+ }
+
+ ContentEditableInput.prototype = copyObj({
+ init: function(display) {
+ var input = this, cm = input.cm;
+ var div = input.div = display.lineDiv;
+ div.contentEditable = "true";
+ disableBrowserMagic(div);
+
+ on(div, "paste", function(e) {
+ var pasted = e.clipboardData && e.clipboardData.getData("text/plain");
+ if (pasted) {
+ e.preventDefault();
+ cm.replaceSelection(pasted, null, "paste");
+ }
+ });
+
+ on(div, "compositionstart", function(e) {
+ var data = e.data;
+ input.composing = {sel: cm.doc.sel, data: data, startData: data};
+ if (!data) return;
+ var prim = cm.doc.sel.primary();
+ var line = cm.getLine(prim.head.line);
+ var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length));
+ if (found > -1 && found <= prim.head.ch)
+ input.composing.sel = simpleSelection(Pos(prim.head.line, found),
+ Pos(prim.head.line, found + data.length));
+ });
+ on(div, "compositionupdate", function(e) {
+ input.composing.data = e.data;
+ });
+ on(div, "compositionend", function(e) {
+ var ours = input.composing;
+ if (!ours) return;
+ if (e.data != ours.startData && !/\u200b/.test(e.data))
+ ours.data = e.data;
+ // Need a small delay to prevent other code (input event,
+ // selection polling) from doing damage when fired right after
+ // compositionend.
+ setTimeout(function() {
+ if (!ours.handled)
+ input.applyComposition(ours);
+ if (input.composing == ours)
+ input.composing = null;
+ }, 50);
+ });
+
+ on(div, "touchstart", function() {
+ input.forceCompositionEnd();
+ });
+
+ on(div, "input", function() {
+ if (input.composing) return;
+ if (!input.pollContent())
+ runInOp(input.cm, function() {regChange(cm);});
+ });
+
+ function onCopyCut(e) {
+ if (cm.somethingSelected()) {
+ lastCopied = cm.getSelections();
+ if (e.type == "cut") cm.replaceSelection("", null, "cut");
+ } else if (!cm.options.lineWiseCopyCut) {
+ return;
+ } else {
+ var ranges = copyableRanges(cm);
+ lastCopied = ranges.text;
+ if (e.type == "cut") {
+ cm.operation(function() {
+ cm.setSelections(ranges.ranges, 0, sel_dontScroll);
+ cm.replaceSelection("", null, "cut");
+ });
+ }
+ }
+ // iOS exposes the clipboard API, but seems to discard content inserted into it
+ if (e.clipboardData && !ios) {
+ e.preventDefault();
+ e.clipboardData.clearData();
+ e.clipboardData.setData("text/plain", lastCopied.join("\n"));
+ } else {
+ // Old-fashioned briefly-focus-a-textarea hack
+ var kludge = hiddenTextarea(), te = kludge.firstChild;
+ cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);
+ te.value = lastCopied.join("\n");
+ var hadFocus = document.activeElement;
+ selectInput(te);
+ setTimeout(function() {
+ cm.display.lineSpace.removeChild(kludge);
+ hadFocus.focus();
+ }, 50);
+ }
+ }
+ on(div, "copy", onCopyCut);
+ on(div, "cut", onCopyCut);
+ },
+
+ prepareSelection: function() {
+ var result = prepareSelection(this.cm, false);
+ result.focus = this.cm.state.focused;
+ return result;
+ },
+
+ showSelection: function(info) {
+ if (!info || !this.cm.display.view.length) return;
+ if (info.focus) this.showPrimarySelection();
+ this.showMultipleSelections(info);
+ },
+
+ showPrimarySelection: function() {
+ var sel = window.getSelection(), prim = this.cm.doc.sel.primary();
+ var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset);
+ var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset);
+ if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
+ cmp(minPos(curAnchor, curFocus), prim.from()) == 0 &&
+ cmp(maxPos(curAnchor, curFocus), prim.to()) == 0)
+ return;
+
+ var start = posToDOM(this.cm, prim.from());
+ var end = posToDOM(this.cm, prim.to());
+ if (!start && !end) return;
+
+ var view = this.cm.display.view;
+ var old = sel.rangeCount && sel.getRangeAt(0);
+ if (!start) {
+ start = {node: view[0].measure.map[2], offset: 0};
+ } else if (!end) { // FIXME dangerously hacky
+ var measure = view[view.length - 1].measure;
+ var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;
+ end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]};
+ }
+
+ try { var rng = range(start.node, start.offset, end.offset, end.node); }
+ catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
+ if (rng) {
+ sel.removeAllRanges();
+ sel.addRange(rng);
+ if (old && sel.anchorNode == null) sel.addRange(old);
+ else if (gecko) this.startGracePeriod();
+ }
+ this.rememberSelection();
+ },
+
+ startGracePeriod: function() {
+ var input = this;
+ clearTimeout(this.gracePeriod);
+ this.gracePeriod = setTimeout(function() {
+ input.gracePeriod = false;
+ if (input.selectionChanged())
+ input.cm.operation(function() { input.cm.curOp.selectionChanged = true; });
+ }, 20);
+ },
+
+ showMultipleSelections: function(info) {
+ removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);
+ removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);
+ },
+
+ rememberSelection: function() {
+ var sel = window.getSelection();
+ this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;
+ this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;
+ },
+
+ selectionInEditor: function() {
+ var sel = window.getSelection();
+ if (!sel.rangeCount) return false;
+ var node = sel.getRangeAt(0).commonAncestorContainer;
+ return contains(this.div, node);
+ },
+
+ focus: function() {
+ if (this.cm.options.readOnly != "nocursor") this.div.focus();
+ },
+ blur: function() { this.div.blur(); },
+ getField: function() { return this.div; },
+
+ supportsTouch: function() { return true; },
+
+ receivedFocus: function() {
+ var input = this;
+ if (this.selectionInEditor())
+ this.pollSelection();
+ else
+ runInOp(this.cm, function() { input.cm.curOp.selectionChanged = true; });
+
+ function poll() {
+ if (input.cm.state.focused) {
+ input.pollSelection();
+ input.polling.set(input.cm.options.pollInterval, poll);
+ }
+ }
+ this.polling.set(this.cm.options.pollInterval, poll);
+ },
+
+ selectionChanged: function() {
+ var sel = window.getSelection();
+ return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
+ sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset;
+ },
+
+ pollSelection: function() {
+ if (!this.composing && !this.gracePeriod && this.selectionChanged()) {
+ var sel = window.getSelection(), cm = this.cm;
+ this.rememberSelection();
+ var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
+ var head = domToPos(cm, sel.focusNode, sel.focusOffset);
+ if (anchor && head) runInOp(cm, function() {
+ setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);
+ if (anchor.bad || head.bad) cm.curOp.selectionChanged = true;
+ });
+ }
+ },
+
+ pollContent: function() {
+ var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();
+ var from = sel.from(), to = sel.to();
+ if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false;
+
+ var fromIndex;
+ if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
+ var fromLine = lineNo(display.view[0].line);
+ var fromNode = display.view[0].node;
+ } else {
+ var fromLine = lineNo(display.view[fromIndex].line);
+ var fromNode = display.view[fromIndex - 1].node.nextSibling;
+ }
+ var toIndex = findViewIndex(cm, to.line);
+ if (toIndex == display.view.length - 1) {
+ var toLine = display.viewTo - 1;
+ var toNode = display.view[toIndex].node;
+ } else {
+ var toLine = lineNo(display.view[toIndex + 1].line) - 1;
+ var toNode = display.view[toIndex + 1].node.previousSibling;
+ }
+
+ var newText = splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));
+ var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));
+ while (newText.length > 1 && oldText.length > 1) {
+ if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }
+ else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }
+ else break;
+ }
+
+ var cutFront = 0, cutEnd = 0;
+ var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);
+ while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
+ ++cutFront;
+ var newBot = lst(newText), oldBot = lst(oldText);
+ var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
+ oldBot.length - (oldText.length == 1 ? cutFront : 0));
+ while (cutEnd < maxCutEnd &&
+ newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
+ ++cutEnd;
+
+ newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd);
+ newText[0] = newText[0].slice(cutFront);
+
+ var chFrom = Pos(fromLine, cutFront);
+ var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);
+ if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
+ replaceRange(cm.doc, newText, chFrom, chTo, "+input");
+ return true;
+ }
+ },
+
+ ensurePolled: function() {
+ this.forceCompositionEnd();
+ },
+ reset: function() {
+ this.forceCompositionEnd();
+ },
+ forceCompositionEnd: function() {
+ if (!this.composing || this.composing.handled) return;
+ this.applyComposition(this.composing);
+ this.composing.handled = true;
+ this.div.blur();
+ this.div.focus();
+ },
+ applyComposition: function(composing) {
+ if (composing.data && composing.data != composing.startData)
+ operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel);
+ },
+
+ setUneditable: function(node) {
+ node.setAttribute("contenteditable", "false");
+ },
+
+ onKeyPress: function(e) {
+ e.preventDefault();
+ operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0);
+ },
+
+ onContextMenu: nothing,
+ resetPosition: nothing,
+
+ needsContentAttribute: true
+ }, ContentEditableInput.prototype);
+
+ function posToDOM(cm, pos) {
+ var view = findViewForLine(cm, pos.line);
+ if (!view || view.hidden) return null;
+ var line = getLine(cm.doc, pos.line);
+ var info = mapFromLineView(view, line, pos.line);
+
+ var order = getOrder(line), side = "left";
+ if (order) {
+ var partPos = getBidiPartAt(order, pos.ch);
+ side = partPos % 2 ? "right" : "left";
+ }
+ var result = nodeAndOffsetInLineMap(info.map, pos.ch, "left");
+ result.offset = result.collapse == "right" ? result.end : result.start;
+ return result;
+ }
+
+ function badPos(pos, bad) { if (bad) pos.bad = true; return pos; }
+
+ function domToPos(cm, node, offset) {
+ var lineNode;
+ if (node == cm.display.lineDiv) {
+ lineNode = cm.display.lineDiv.childNodes[offset];
+ if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true);
+ node = null; offset = 0;
+ } else {
+ for (lineNode = node;; lineNode = lineNode.parentNode) {
+ if (!lineNode || lineNode == cm.display.lineDiv) return null;
+ if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break;
+ }
+ }
+ for (var i = 0; i < cm.display.view.length; i++) {
+ var lineView = cm.display.view[i];
+ if (lineView.node == lineNode)
+ return locateNodeInLineView(lineView, node, offset);
+ }
+ }
+
+ function locateNodeInLineView(lineView, node, offset) {
+ var wrapper = lineView.text.firstChild, bad = false;
+ if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true);
+ if (node == wrapper) {
+ bad = true;
+ node = wrapper.childNodes[offset];
+ offset = 0;
+ if (!node) {
+ var line = lineView.rest ? lst(lineView.rest) : lineView.line;
+ return badPos(Pos(lineNo(line), line.text.length), bad);
+ }
+ }
+
+ var textNode = node.nodeType == 3 ? node : null, topNode = node;
+ if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
+ textNode = node.firstChild;
+ if (offset) offset = textNode.nodeValue.length;
+ }
+ while (topNode.parentNode != wrapper) topNode = topNode.parentNode;
+ var measure = lineView.measure, maps = measure.maps;
+
+ function find(textNode, topNode, offset) {
+ for (var i = -1; i < (maps ? maps.length : 0); i++) {
+ var map = i < 0 ? measure.map : maps[i];
+ for (var j = 0; j < map.length; j += 3) {
+ var curNode = map[j + 2];
+ if (curNode == textNode || curNode == topNode) {
+ var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);
+ var ch = map[j] + offset;
+ if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)];
+ return Pos(line, ch);
+ }
+ }
+ }
+ }
+ var found = find(textNode, topNode, offset);
+ if (found) return badPos(found, bad);
+
+ // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
+ for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
+ found = find(after, after.firstChild, 0);
+ if (found)
+ return badPos(Pos(found.line, found.ch - dist), bad);
+ else
+ dist += after.textContent.length;
+ }
+ for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) {
+ found = find(before, before.firstChild, -1);
+ if (found)
+ return badPos(Pos(found.line, found.ch + dist), bad);
+ else
+ dist += after.textContent.length;
+ }
+ }
+
+ function domTextBetween(cm, from, to, fromLine, toLine) {
+ var text = "", closing = false;
+ function recognizeMarker(id) { return function(marker) { return marker.id == id; }; }
+ function walk(node) {
+ if (node.nodeType == 1) {
+ var cmText = node.getAttribute("cm-text");
+ if (cmText != null) {
+ if (cmText == "") cmText = node.textContent.replace(/\u200b/g, "");
+ text += cmText;
+ return;
+ }
+ var markerID = node.getAttribute("cm-marker"), range;
+ if (markerID) {
+ var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
+ if (found.length && (range = found[0].find()))
+ text += getBetween(cm.doc, range.from, range.to).join("\n");
+ return;
+ }
+ if (node.getAttribute("contenteditable") == "false") return;
+ for (var i = 0; i < node.childNodes.length; i++)
+ walk(node.childNodes[i]);
+ if (/^(pre|div|p)$/i.test(node.nodeName))
+ closing = true;
+ } else if (node.nodeType == 3) {
+ var val = node.nodeValue;
+ if (!val) return;
+ if (closing) {
+ text += "\n";
+ closing = false;
+ }
+ text += val;
+ }
+ }
+ for (;;) {
+ walk(from);
+ if (from == to) break;
+ from = from.nextSibling;
+ }
+ return text;
+ }
+
+ CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput};
+
+ // SELECTION / CURSOR
+
+ // Selection objects are immutable. A new one is created every time
+ // the selection changes. A selection is one or more non-overlapping
+ // (and non-touching) ranges, sorted, and an integer that indicates
+ // which one is the primary selection (the one that's scrolled into
+ // view, that getCursor returns, etc).
+ function Selection(ranges, primIndex) {
+ this.ranges = ranges;
+ this.primIndex = primIndex;
+ }
+
+ Selection.prototype = {
+ primary: function() { return this.ranges[this.primIndex]; },
+ equals: function(other) {
+ if (other == this) return true;
+ if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false;
+ for (var i = 0; i < this.ranges.length; i++) {
+ var here = this.ranges[i], there = other.ranges[i];
+ if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false;
+ }
+ return true;
+ },
+ deepCopy: function() {
+ for (var out = [], i = 0; i < this.ranges.length; i++)
+ out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head));
+ return new Selection(out, this.primIndex);
+ },
+ somethingSelected: function() {
+ for (var i = 0; i < this.ranges.length; i++)
+ if (!this.ranges[i].empty()) return true;
+ return false;
+ },
+ contains: function(pos, end) {
+ if (!end) end = pos;
+ for (var i = 0; i < this.ranges.length; i++) {
+ var range = this.ranges[i];
+ if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
+ return i;
+ }
+ return -1;
+ }
+ };
+
+ function Range(anchor, head) {
+ this.anchor = anchor; this.head = head;
+ }
+
+ Range.prototype = {
+ from: function() { return minPos(this.anchor, this.head); },
+ to: function() { return maxPos(this.anchor, this.head); },
+ empty: function() {
+ return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch;
+ }
+ };
+
+ // Take an unsorted, potentially overlapping set of ranges, and
+ // build a selection out of it. 'Consumes' ranges array (modifying
+ // it).
+ function normalizeSelection(ranges, primIndex) {
+ var prim = ranges[primIndex];
+ ranges.sort(function(a, b) { return cmp(a.from(), b.from()); });
+ primIndex = indexOf(ranges, prim);
+ for (var i = 1; i < ranges.length; i++) {
+ var cur = ranges[i], prev = ranges[i - 1];
+ if (cmp(prev.to(), cur.from()) >= 0) {
+ var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());
+ var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;
+ if (i <= primIndex) --primIndex;
+ ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
+ }
+ }
+ return new Selection(ranges, primIndex);
+ }
+
+ function simpleSelection(anchor, head) {
+ return new Selection([new Range(anchor, head || anchor)], 0);
+ }
+
+ // Most of the external API clips given positions to make sure they
+ // actually exist within the document.
+ function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));}
+ function clipPos(doc, pos) {
+ if (pos.line < doc.first) return Pos(doc.first, 0);
+ var last = doc.first + doc.size - 1;
+ if (pos.line > last) return Pos(last, getLine(doc, last).text.length);
+ return clipToLen(pos, getLine(doc, pos.line).text.length);
+ }
+ function clipToLen(pos, linelen) {
+ var ch = pos.ch;
+ if (ch == null || ch > linelen) return Pos(pos.line, linelen);
+ else if (ch < 0) return Pos(pos.line, 0);
+ else return pos;
+ }
+ function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;}
+ function clipPosArray(doc, array) {
+ for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]);
+ return out;
+ }
+
+ // SELECTION UPDATES
+
+ // The 'scroll' parameter given to many of these indicated whether
+ // the new cursor position should be scrolled into view after
+ // modifying the selection.
+
+ // If shift is held or the extend flag is set, extends a range to
+ // include a given position (and optionally a second position).
+ // Otherwise, simply returns the range between the given positions.
+ // Used for cursor motion and such.
+ function extendRange(doc, range, head, other) {
+ if (doc.cm && doc.cm.display.shift || doc.extend) {
+ var anchor = range.anchor;
+ if (other) {
+ var posBefore = cmp(head, anchor) < 0;
+ if (posBefore != (cmp(other, anchor) < 0)) {
+ anchor = head;
+ head = other;
+ } else if (posBefore != (cmp(head, other) < 0)) {
+ head = other;
+ }
+ }
+ return new Range(anchor, head);
+ } else {
+ return new Range(other || head, head);
+ }
+ }
+
+ // Extend the primary selection range, discard the rest.
+ function extendSelection(doc, head, other, options) {
+ setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options);
+ }
+
+ // Extend all selections (pos is an array of selections with length
+ // equal the number of selections)
+ function extendSelections(doc, heads, options) {
+ for (var out = [], i = 0; i < doc.sel.ranges.length; i++)
+ out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null);
+ var newSel = normalizeSelection(out, doc.sel.primIndex);
+ setSelection(doc, newSel, options);
+ }
+
+ // Updates a single range in the selection.
+ function replaceOneSelection(doc, i, range, options) {
+ var ranges = doc.sel.ranges.slice(0);
+ ranges[i] = range;
+ setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options);
+ }
+
+ // Reset the selection to a single range.
+ function setSimpleSelection(doc, anchor, head, options) {
+ setSelection(doc, simpleSelection(anchor, head), options);
+ }
+
+ // Give beforeSelectionChange handlers a change to influence a
+ // selection update.
+ function filterSelectionChange(doc, sel) {
+ var obj = {
+ ranges: sel.ranges,
+ update: function(ranges) {
+ this.ranges = [];
+ for (var i = 0; i < ranges.length; i++)
+ this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
+ clipPos(doc, ranges[i].head));
+ }
+ };
+ signal(doc, "beforeSelectionChange", doc, obj);
+ if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj);
+ if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1);
+ else return sel;
+ }
+
+ function setSelectionReplaceHistory(doc, sel, options) {
+ var done = doc.history.done, last = lst(done);
+ if (last && last.ranges) {
+ done[done.length - 1] = sel;
+ setSelectionNoUndo(doc, sel, options);
+ } else {
+ setSelection(doc, sel, options);
+ }
+ }
+
+ // Set a new selection.
+ function setSelection(doc, sel, options) {
+ setSelectionNoUndo(doc, sel, options);
+ addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
+ }
+
+ function setSelectionNoUndo(doc, sel, options) {
+ if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
+ sel = filterSelectionChange(doc, sel);
+
+ var bias = options && options.bias ||
+ (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
+ setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
+
+ if (!(options && options.scroll === false) && doc.cm)
+ ensureCursorVisible(doc.cm);
+ }
+
+ function setSelectionInner(doc, sel) {
+ if (sel.equals(doc.sel)) return;
+
+ doc.sel = sel;
+
+ if (doc.cm) {
+ doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;
+ signalCursorActivity(doc.cm);
+ }
+ signalLater(doc, "cursorActivity", doc);
+ }
+
+ // Verify that the selection does not partially select any atomic
+ // marked ranges.
+ function reCheckSelection(doc) {
+ setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll);
+ }
+
+ // Return a selection that does not partially select any atomic
+ // ranges.
+ function skipAtomicInSelection(doc, sel, bias, mayClear) {
+ var out;
+ for (var i = 0; i < sel.ranges.length; i++) {
+ var range = sel.ranges[i];
+ var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear);
+ var newHead = skipAtomic(doc, range.head, bias, mayClear);
+ if (out || newAnchor != range.anchor || newHead != range.head) {
+ if (!out) out = sel.ranges.slice(0, i);
+ out[i] = new Range(newAnchor, newHead);
+ }
+ }
+ return out ? normalizeSelection(out, sel.primIndex) : sel;
+ }
+
+ // Ensure a given position is not inside an atomic range.
+ function skipAtomic(doc, pos, bias, mayClear) {
+ var flipped = false, curPos = pos;
+ var dir = bias || 1;
+ doc.cantEdit = false;
+ search: for (;;) {
+ var line = getLine(doc, curPos.line);
+ if (line.markedSpans) {
+ for (var i = 0; i < line.markedSpans.length; ++i) {
+ var sp = line.markedSpans[i], m = sp.marker;
+ if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) &&
+ (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) {
+ if (mayClear) {
+ signal(m, "beforeCursorEnter");
+ if (m.explicitlyCleared) {
+ if (!line.markedSpans) break;
+ else {--i; continue;}
+ }
+ }
+ if (!m.atomic) continue;
+ var newPos = m.find(dir < 0 ? -1 : 1);
+ if (cmp(newPos, curPos) == 0) {
+ newPos.ch += dir;
+ if (newPos.ch < 0) {
+ if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1));
+ else newPos = null;
+ } else if (newPos.ch > line.text.length) {
+ if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0);
+ else newPos = null;
+ }
+ if (!newPos) {
+ if (flipped) {
+ // Driven in a corner -- no valid cursor position found at all
+ // -- try again *with* clearing, if we didn't already
+ if (!mayClear) return skipAtomic(doc, pos, bias, true);
+ // Otherwise, turn off editing until further notice, and return the start of the doc
+ doc.cantEdit = true;
+ return Pos(doc.first, 0);
+ }
+ flipped = true; newPos = pos; dir = -dir;
+ }
+ }
+ curPos = newPos;
+ continue search;
+ }
+ }
+ }
+ return curPos;
+ }
+ }
+
+ // SELECTION DRAWING
+
+ function updateSelection(cm) {
+ cm.display.input.showSelection(cm.display.input.prepareSelection());
+ }
+
+ function prepareSelection(cm, primary) {
+ var doc = cm.doc, result = {};
+ var curFragment = result.cursors = document.createDocumentFragment();
+ var selFragment = result.selection = document.createDocumentFragment();
+
+ for (var i = 0; i < doc.sel.ranges.length; i++) {
+ if (primary === false && i == doc.sel.primIndex) continue;
+ var range = doc.sel.ranges[i];
+ var collapsed = range.empty();
+ if (collapsed || cm.options.showCursorWhenSelecting)
+ drawSelectionCursor(cm, range, curFragment);
+ if (!collapsed)
+ drawSelectionRange(cm, range, selFragment);
+ }
+ return result;
+ }
+
+ // Draws a cursor for the given range
+ function drawSelectionCursor(cm, range, output) {
+ var pos = cursorCoords(cm, range.head, "div", null, null, !cm.options.singleCursorHeightPerLine);
+
+ var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
+ cursor.style.left = pos.left + "px";
+ cursor.style.top = pos.top + "px";
+ cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
+
+ if (pos.other) {
+ // Secondary cursor, shown when on a 'jump' in bi-directional text
+ var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"));
+ otherCursor.style.display = "";
+ otherCursor.style.left = pos.other.left + "px";
+ otherCursor.style.top = pos.other.top + "px";
+ otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
+ }
+ }
+
+ // Draws the given range as a highlighted selection
+ function drawSelectionRange(cm, range, output) {
+ var display = cm.display, doc = cm.doc;
+ var fragment = document.createDocumentFragment();
+ var padding = paddingH(cm.display), leftSide = padding.left;
+ var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;
+
+ function add(left, top, width, bottom) {
+ if (top < 0) top = 0;
+ top = Math.round(top);
+ bottom = Math.round(bottom);
+ fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left +
+ "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) +
+ "px; height: " + (bottom - top) + "px"));
+ }
+
+ function drawForLine(line, fromArg, toArg) {
+ var lineObj = getLine(doc, line);
+ var lineLen = lineObj.text.length;
+ var start, end;
+ function coords(ch, bias) {
+ return charCoords(cm, Pos(line, ch), "div", lineObj, bias);
+ }
+
+ iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) {
+ var leftPos = coords(from, "left"), rightPos, left, right;
+ if (from == to) {
+ rightPos = leftPos;
+ left = right = leftPos.left;
+ } else {
+ rightPos = coords(to - 1, "right");
+ if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; }
+ left = leftPos.left;
+ right = rightPos.right;
+ }
+ if (fromArg == null && from == 0) left = leftSide;
+ if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
+ add(left, leftPos.top, null, leftPos.bottom);
+ left = leftSide;
+ if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top);
+ }
+ if (toArg == null && to == lineLen) right = rightSide;
+ if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
+ start = leftPos;
+ if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
+ end = rightPos;
+ if (left < leftSide + 1) left = leftSide;
+ add(left, rightPos.top, right - left, rightPos.bottom);
+ });
+ return {start: start, end: end};
+ }
+
+ var sFrom = range.from(), sTo = range.to();
+ if (sFrom.line == sTo.line) {
+ drawForLine(sFrom.line, sFrom.ch, sTo.ch);
+ } else {
+ var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);
+ var singleVLine = visualLine(fromLine) == visualLine(toLine);
+ var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;
+ var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;
+ if (singleVLine) {
+ if (leftEnd.top < rightStart.top - 2) {
+ add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
+ add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);
+ } else {
+ add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
+ }
+ }
+ if (leftEnd.bottom < rightStart.top)
+ add(leftSide, leftEnd.bottom, null, rightStart.top);
+ }
+
+ output.appendChild(fragment);
+ }
+
+ // Cursor-blinking
+ function restartBlink(cm) {
+ if (!cm.state.focused) return;
+ var display = cm.display;
+ clearInterval(display.blinker);
+ var on = true;
+ display.cursorDiv.style.visibility = "";
+ if (cm.options.cursorBlinkRate > 0)
+ display.blinker = setInterval(function() {
+ display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden";
+ }, cm.options.cursorBlinkRate);
+ else if (cm.options.cursorBlinkRate < 0)
+ display.cursorDiv.style.visibility = "hidden";
+ }
+
+ // HIGHLIGHT WORKER
+
+ function startWorker(cm, time) {
+ if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo)
+ cm.state.highlight.set(time, bind(highlightWorker, cm));
+ }
+
+ function highlightWorker(cm) {
+ var doc = cm.doc;
+ if (doc.frontier < doc.first) doc.frontier = doc.first;
+ if (doc.frontier >= cm.display.viewTo) return;
+ var end = +new Date + cm.options.workTime;
+ var state = copyState(doc.mode, getStateBefore(cm, doc.frontier));
+ var changedLines = [];
+
+ doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) {
+ if (doc.frontier >= cm.display.viewFrom) { // Visible
+ var oldStyles = line.styles;
+ var highlighted = highlightLine(cm, line, state, true);
+ line.styles = highlighted.styles;
+ var oldCls = line.styleClasses, newCls = highlighted.classes;
+ if (newCls) line.styleClasses = newCls;
+ else if (oldCls) line.styleClasses = null;
+ var ischange = !oldStyles || oldStyles.length != line.styles.length ||
+ oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
+ for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
+ if (ischange) changedLines.push(doc.frontier);
+ line.stateAfter = copyState(doc.mode, state);
+ } else {
+ processLine(cm, line.text, state);
+ line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;
+ }
+ ++doc.frontier;
+ if (+new Date > end) {
+ startWorker(cm, cm.options.workDelay);
+ return true;
+ }
+ });
+ if (changedLines.length) runInOp(cm, function() {
+ for (var i = 0; i < changedLines.length; i++)
+ regLineChange(cm, changedLines[i], "text");
+ });
+ }
+
+ // Finds the line to start with when starting a parse. Tries to
+ // find a line with a stateAfter, so that it can start with a
+ // valid state. If that fails, it returns the line with the
+ // smallest indentation, which tends to need the least context to
+ // parse correctly.
+ function findStartLine(cm, n, precise) {
+ var minindent, minline, doc = cm.doc;
+ var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
+ for (var search = n; search > lim; --search) {
+ if (search <= doc.first) return doc.first;
+ var line = getLine(doc, search - 1);
+ if (line.stateAfter && (!precise || search <= doc.frontier)) return search;
+ var indented = countColumn(line.text, null, cm.options.tabSize);
+ if (minline == null || minindent > indented) {
+ minline = search - 1;
+ minindent = indented;
+ }
+ }
+ return minline;
+ }
+
+ function getStateBefore(cm, n, precise) {
+ var doc = cm.doc, display = cm.display;
+ if (!doc.mode.startState) return true;
+ var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter;
+ if (!state) state = startState(doc.mode);
+ else state = copyState(doc.mode, state);
+ doc.iter(pos, n, function(line) {
+ processLine(cm, line.text, state);
+ var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo;
+ line.stateAfter = save ? copyState(doc.mode, state) : null;
+ ++pos;
+ });
+ if (precise) doc.frontier = pos;
+ return state;
+ }
+
+ // POSITION MEASUREMENT
+
+ function paddingTop(display) {return display.lineSpace.offsetTop;}
+ function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;}
+ function paddingH(display) {
+ if (display.cachedPaddingH) return display.cachedPaddingH;
+ var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
+ var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
+ var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
+ if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data;
+ return data;
+ }
+
+ function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; }
+ function displayWidth(cm) {
+ return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth;
+ }
+ function displayHeight(cm) {
+ return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight;
+ }
+
+ // Ensure the lineView.wrapping.heights array is populated. This is
+ // an array of bottom offsets for the lines that make up a drawn
+ // line. When lineWrapping is on, there might be more than one
+ // height.
+ function ensureLineHeights(cm, lineView, rect) {
+ var wrapping = cm.options.lineWrapping;
+ var curWidth = wrapping && displayWidth(cm);
+ if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
+ var heights = lineView.measure.heights = [];
+ if (wrapping) {
+ lineView.measure.width = curWidth;
+ var rects = lineView.text.firstChild.getClientRects();
+ for (var i = 0; i < rects.length - 1; i++) {
+ var cur = rects[i], next = rects[i + 1];
+ if (Math.abs(cur.bottom - next.bottom) > 2)
+ heights.push((cur.bottom + next.top) / 2 - rect.top);
+ }
+ }
+ heights.push(rect.bottom - rect.top);
+ }
+ }
+
+ // Find a line map (mapping character offsets to text nodes) and a
+ // measurement cache for the given line number. (A line view might
+ // contain multiple lines when collapsed ranges are present.)
+ function mapFromLineView(lineView, line, lineN) {
+ if (lineView.line == line)
+ return {map: lineView.measure.map, cache: lineView.measure.cache};
+ for (var i = 0; i < lineView.rest.length; i++)
+ if (lineView.rest[i] == line)
+ return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]};
+ for (var i = 0; i < lineView.rest.length; i++)
+ if (lineNo(lineView.rest[i]) > lineN)
+ return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true};
+ }
+
+ // Render a line into the hidden node display.externalMeasured. Used
+ // when measurement is needed for a line that's not in the viewport.
+ function updateExternalMeasurement(cm, line) {
+ line = visualLine(line);
+ var lineN = lineNo(line);
+ var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);
+ view.lineN = lineN;
+ var built = view.built = buildLineContent(cm, view);
+ view.text = built.pre;
+ removeChildrenAndAdd(cm.display.lineMeasure, built.pre);
+ return view;
+ }
+
+ // Get a {top, bottom, left, right} box (in line-local coordinates)
+ // for a given character.
+ function measureChar(cm, line, ch, bias) {
+ return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias);
+ }
+
+ // Find a line view that corresponds to the given line number.
+ function findViewForLine(cm, lineN) {
+ if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
+ return cm.display.view[findViewIndex(cm, lineN)];
+ var ext = cm.display.externalMeasured;
+ if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
+ return ext;
+ }
+
+ // Measurement can be split in two steps, the set-up work that
+ // applies to the whole line, and the measurement of the actual
+ // character. Functions like coordsChar, that need to do a lot of
+ // measurements in a row, can thus ensure that the set-up work is
+ // only done once.
+ function prepareMeasureForLine(cm, line) {
+ var lineN = lineNo(line);
+ var view = findViewForLine(cm, lineN);
+ if (view && !view.text)
+ view = null;
+ else if (view && view.changes)
+ updateLineForChanges(cm, view, lineN, getDimensions(cm));
+ if (!view)
+ view = updateExternalMeasurement(cm, line);
+
+ var info = mapFromLineView(view, line, lineN);
+ return {
+ line: line, view: view, rect: null,
+ map: info.map, cache: info.cache, before: info.before,
+ hasHeights: false
+ };
+ }
+
+ // Given a prepared measurement object, measures the position of an
+ // actual character (or fetches it from the cache).
+ function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
+ if (prepared.before) ch = -1;
+ var key = ch + (bias || ""), found;
+ if (prepared.cache.hasOwnProperty(key)) {
+ found = prepared.cache[key];
+ } else {
+ if (!prepared.rect)
+ prepared.rect = prepared.view.text.getBoundingClientRect();
+ if (!prepared.hasHeights) {
+ ensureLineHeights(cm, prepared.view, prepared.rect);
+ prepared.hasHeights = true;
+ }
+ found = measureCharInner(cm, prepared, ch, bias);
+ if (!found.bogus) prepared.cache[key] = found;
+ }
+ return {left: found.left, right: found.right,
+ top: varHeight ? found.rtop : found.top,
+ bottom: varHeight ? found.rbottom : found.bottom};
+ }
+
+ var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
+
+ function nodeAndOffsetInLineMap(map, ch, bias) {
+ var node, start, end, collapse;
+ // First, search the line map for the text node corresponding to,
+ // or closest to, the target character.
+ for (var i = 0; i < map.length; i += 3) {
+ var mStart = map[i], mEnd = map[i + 1];
+ if (ch < mStart) {
+ start = 0; end = 1;
+ collapse = "left";
+ } else if (ch < mEnd) {
+ start = ch - mStart;
+ end = start + 1;
+ } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) {
+ end = mEnd - mStart;
+ start = end - 1;
+ if (ch >= mEnd) collapse = "right";
+ }
+ if (start != null) {
+ node = map[i + 2];
+ if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
+ collapse = bias;
+ if (bias == "left" && start == 0)
+ while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) {
+ node = map[(i -= 3) + 2];
+ collapse = "left";
+ }
+ if (bias == "right" && start == mEnd - mStart)
+ while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) {
+ node = map[(i += 3) + 2];
+ collapse = "right";
+ }
+ break;
+ }
+ }
+ return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd};
+ }
+
+ function measureCharInner(cm, prepared, ch, bias) {
+ var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);
+ var node = place.node, start = place.start, end = place.end, collapse = place.collapse;
+
+ var rect;
+ if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
+ for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned
+ while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start;
+ while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end;
+ if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) {
+ rect = node.parentNode.getBoundingClientRect();
+ } else if (ie && cm.options.lineWrapping) {
+ var rects = range(node, start, end).getClientRects();
+ if (rects.length)
+ rect = rects[bias == "right" ? rects.length - 1 : 0];
+ else
+ rect = nullRect;
+ } else {
+ rect = range(node, start, end).getBoundingClientRect() || nullRect;
+ }
+ if (rect.left || rect.right || start == 0) break;
+ end = start;
+ start = start - 1;
+ collapse = "right";
+ }
+ if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect);
+ } else { // If it is a widget, simply get the box for the whole widget.
+ if (start > 0) collapse = bias = "right";
+ var rects;
+ if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
+ rect = rects[bias == "right" ? rects.length - 1 : 0];
+ else
+ rect = node.getBoundingClientRect();
+ }
+ if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
+ var rSpan = node.parentNode.getClientRects()[0];
+ if (rSpan)
+ rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom};
+ else
+ rect = nullRect;
+ }
+
+ var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;
+ var mid = (rtop + rbot) / 2;
+ var heights = prepared.view.measure.heights;
+ for (var i = 0; i < heights.length - 1; i++)
+ if (mid < heights[i]) break;
+ var top = i ? heights[i - 1] : 0, bot = heights[i];
+ var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
+ right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
+ top: top, bottom: bot};
+ if (!rect.left && !rect.right) result.bogus = true;
+ if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }
+
+ return result;
+ }
+
+ // Work around problem with bounding client rects on ranges being
+ // returned incorrectly when zoomed on IE10 and below.
+ function maybeUpdateRectForZooming(measure, rect) {
+ if (!window.screen || screen.logicalXDPI == null ||
+ screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
+ return rect;
+ var scaleX = screen.logicalXDPI / screen.deviceXDPI;
+ var scaleY = screen.logicalYDPI / screen.deviceYDPI;
+ return {left: rect.left * scaleX, right: rect.right * scaleX,
+ top: rect.top * scaleY, bottom: rect.bottom * scaleY};
+ }
+
+ function clearLineMeasurementCacheFor(lineView) {
+ if (lineView.measure) {
+ lineView.measure.cache = {};
+ lineView.measure.heights = null;
+ if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
+ lineView.measure.caches[i] = {};
+ }
+ }
+
+ function clearLineMeasurementCache(cm) {
+ cm.display.externalMeasure = null;
+ removeChildren(cm.display.lineMeasure);
+ for (var i = 0; i < cm.display.view.length; i++)
+ clearLineMeasurementCacheFor(cm.display.view[i]);
+ }
+
+ function clearCaches(cm) {
+ clearLineMeasurementCache(cm);
+ cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;
+ if (!cm.options.lineWrapping) cm.display.maxLineChanged = true;
+ cm.display.lineNumChars = null;
+ }
+
+ function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; }
+ function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; }
+
+ // Converts a {top, bottom, left, right} box from line-local
+ // coordinates into another coordinate system. Context may be one of
+ // "line", "div" (display.lineDiv), "local"/null (editor), "window",
+ // or "page".
+ function intoCoordSystem(cm, lineObj, rect, context) {
+ if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) {
+ var size = widgetHeight(lineObj.widgets[i]);
+ rect.top += size; rect.bottom += size;
+ }
+ if (context == "line") return rect;
+ if (!context) context = "local";
+ var yOff = heightAtLine(lineObj);
+ if (context == "local") yOff += paddingTop(cm.display);
+ else yOff -= cm.display.viewOffset;
+ if (context == "page" || context == "window") {
+ var lOff = cm.display.lineSpace.getBoundingClientRect();
+ yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
+ var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
+ rect.left += xOff; rect.right += xOff;
+ }
+ rect.top += yOff; rect.bottom += yOff;
+ return rect;
+ }
+
+ // Coverts a box from "div" coords to another coordinate system.
+ // Context may be "window", "page", "div", or "local"/null.
+ function fromCoordSystem(cm, coords, context) {
+ if (context == "div") return coords;
+ var left = coords.left, top = coords.top;
+ // First move into "page" coordinate system
+ if (context == "page") {
+ left -= pageScrollX();
+ top -= pageScrollY();
+ } else if (context == "local" || !context) {
+ var localBox = cm.display.sizer.getBoundingClientRect();
+ left += localBox.left;
+ top += localBox.top;
+ }
+
+ var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();
+ return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top};
+ }
+
+ function charCoords(cm, pos, context, lineObj, bias) {
+ if (!lineObj) lineObj = getLine(cm.doc, pos.line);
+ return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context);
+ }
+
+ // Returns a box for a given cursor position, which may have an
+ // 'other' property containing the position of the secondary cursor
+ // on a bidi boundary.
+ function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
+ lineObj = lineObj || getLine(cm.doc, pos.line);
+ if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj);
+ function get(ch, right) {
+ var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight);
+ if (right) m.left = m.right; else m.right = m.left;
+ return intoCoordSystem(cm, lineObj, m, context);
+ }
+ function getBidi(ch, partPos) {
+ var part = order[partPos], right = part.level % 2;
+ if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) {
+ part = order[--partPos];
+ ch = bidiRight(part) - (part.level % 2 ? 0 : 1);
+ right = true;
+ } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) {
+ part = order[++partPos];
+ ch = bidiLeft(part) - part.level % 2;
+ right = false;
+ }
+ if (right && ch == part.to && ch > part.from) return get(ch - 1);
+ return get(ch, right);
+ }
+ var order = getOrder(lineObj), ch = pos.ch;
+ if (!order) return get(ch);
+ var partPos = getBidiPartAt(order, ch);
+ var val = getBidi(ch, partPos);
+ if (bidiOther != null) val.other = getBidi(ch, bidiOther);
+ return val;
+ }
+
+ // Used to cheaply estimate the coordinates for a position. Used for
+ // intermediate scroll updates.
+ function estimateCoords(cm, pos) {
+ var left = 0, pos = clipPos(cm.doc, pos);
+ if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch;
+ var lineObj = getLine(cm.doc, pos.line);
+ var top = heightAtLine(lineObj) + paddingTop(cm.display);
+ return {left: left, right: left, top: top, bottom: top + lineObj.height};
+ }
+
+ // Positions returned by coordsChar contain some extra information.
+ // xRel is the relative x position of the input coordinates compared
+ // to the found position (so xRel > 0 means the coordinates are to
+ // the right of the character position, for example). When outside
+ // is true, that means the coordinates lie outside the line's
+ // vertical range.
+ function PosWithInfo(line, ch, outside, xRel) {
+ var pos = Pos(line, ch);
+ pos.xRel = xRel;
+ if (outside) pos.outside = true;
+ return pos;
+ }
+
+ // Compute the character position closest to the given coordinates.
+ // Input must be lineSpace-local ("div" coordinate system).
+ function coordsChar(cm, x, y) {
+ var doc = cm.doc;
+ y += cm.display.viewOffset;
+ if (y < 0) return PosWithInfo(doc.first, 0, true, -1);
+ var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
+ if (lineN > last)
+ return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1);
+ if (x < 0) x = 0;
+
+ var lineObj = getLine(doc, lineN);
+ for (;;) {
+ var found = coordsCharInner(cm, lineObj, lineN, x, y);
+ var merged = collapsedSpanAtEnd(lineObj);
+ var mergedPos = merged && merged.find(0, true);
+ if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
+ lineN = lineNo(lineObj = mergedPos.to.line);
+ else
+ return found;
+ }
+ }
+
+ function coordsCharInner(cm, lineObj, lineNo, x, y) {
+ var innerOff = y - heightAtLine(lineObj);
+ var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth;
+ var preparedMeasure = prepareMeasureForLine(cm, lineObj);
+
+ function getX(ch) {
+ var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure);
+ wrongLine = true;
+ if (innerOff > sp.bottom) return sp.left - adjust;
+ else if (innerOff < sp.top) return sp.left + adjust;
+ else wrongLine = false;
+ return sp.left;
+ }
+
+ var bidi = getOrder(lineObj), dist = lineObj.text.length;
+ var from = lineLeft(lineObj), to = lineRight(lineObj);
+ var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine;
+
+ if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1);
+ // Do a binary search between these bounds.
+ for (;;) {
+ if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
+ var ch = x < fromX || x - fromX <= toX - x ? from : to;
+ var xDiff = x - (ch == from ? fromX : toX);
+ while (isExtendingChar(lineObj.text.charAt(ch))) ++ch;
+ var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside,
+ xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0);
+ return pos;
+ }
+ var step = Math.ceil(dist / 2), middle = from + step;
+ if (bidi) {
+ middle = from;
+ for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1);
+ }
+ var middleX = getX(middle);
+ if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;}
+ else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;}
+ }
+ }
+
+ var measureText;
+ // Compute the default text height.
+ function textHeight(display) {
+ if (display.cachedTextHeight != null) return display.cachedTextHeight;
+ if (measureText == null) {
+ measureText = elt("pre");
+ // Measure a bunch of lines, for browsers that compute
+ // fractional heights.
+ for (var i = 0; i < 49; ++i) {
+ measureText.appendChild(document.createTextNode("x"));
+ measureText.appendChild(elt("br"));
+ }
+ measureText.appendChild(document.createTextNode("x"));
+ }
+ removeChildrenAndAdd(display.measure, measureText);
+ var height = measureText.offsetHeight / 50;
+ if (height > 3) display.cachedTextHeight = height;
+ removeChildren(display.measure);
+ return height || 1;
+ }
+
+ // Compute the default character width.
+ function charWidth(display) {
+ if (display.cachedCharWidth != null) return display.cachedCharWidth;
+ var anchor = elt("span", "xxxxxxxxxx");
+ var pre = elt("pre", [anchor]);
+ removeChildrenAndAdd(display.measure, pre);
+ var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
+ if (width > 2) display.cachedCharWidth = width;
+ return width || 10;
+ }
+
+ // OPERATIONS
+
+ // Operations are used to wrap a series of changes to the editor
+ // state in such a way that each change won't have to update the
+ // cursor and display (which would be awkward, slow, and
+ // error-prone). Instead, display updates are batched and then all
+ // combined and executed at once.
+
+ var operationGroup = null;
+
+ var nextOpId = 0;
+ // Start a new operation.
+ function startOperation(cm) {
+ cm.curOp = {
+ cm: cm,
+ viewChanged: false, // Flag that indicates that lines might need to be redrawn
+ startHeight: cm.doc.height, // Used to detect need to update scrollbar
+ forceUpdate: false, // Used to force a redraw
+ updateInput: null, // Whether to reset the input textarea
+ typing: false, // Whether this reset should be careful to leave existing text (for compositing)
+ changeObjs: null, // Accumulated changes, for firing change events
+ cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
+ cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
+ selectionChanged: false, // Whether the selection needs to be redrawn
+ updateMaxLine: false, // Set when the widest line needs to be determined anew
+ scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
+ scrollToPos: null, // Used to scroll to a specific position
+ focus: false,
+ id: ++nextOpId // Unique ID
+ };
+ if (operationGroup) {
+ operationGroup.ops.push(cm.curOp);
+ } else {
+ cm.curOp.ownsGroup = operationGroup = {
+ ops: [cm.curOp],
+ delayedCallbacks: []
+ };
+ }
+ }
+
+ function fireCallbacksForOps(group) {
+ // Calls delayed callbacks and cursorActivity handlers until no
+ // new ones appear
+ var callbacks = group.delayedCallbacks, i = 0;
+ do {
+ for (; i < callbacks.length; i++)
+ callbacks[i]();
+ for (var j = 0; j < group.ops.length; j++) {
+ var op = group.ops[j];
+ if (op.cursorActivityHandlers)
+ while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
+ op.cursorActivityHandlers[op.cursorActivityCalled++](op.cm);
+ }
+ } while (i < callbacks.length);
+ }
+
+ // Finish an operation, updating the display and signalling delayed events
+ function endOperation(cm) {
+ var op = cm.curOp, group = op.ownsGroup;
+ if (!group) return;
+
+ try { fireCallbacksForOps(group); }
+ finally {
+ operationGroup = null;
+ for (var i = 0; i < group.ops.length; i++)
+ group.ops[i].cm.curOp = null;
+ endOperations(group);
+ }
+ }
+
+ // The DOM updates done when an operation finishes are batched so
+ // that the minimum number of relayouts are required.
+ function endOperations(group) {
+ var ops = group.ops;
+ for (var i = 0; i < ops.length; i++) // Read DOM
+ endOperation_R1(ops[i]);
+ for (var i = 0; i < ops.length; i++) // Write DOM (maybe)
+ endOperation_W1(ops[i]);
+ for (var i = 0; i < ops.length; i++) // Read DOM
+ endOperation_R2(ops[i]);
+ for (var i = 0; i < ops.length; i++) // Write DOM (maybe)
+ endOperation_W2(ops[i]);
+ for (var i = 0; i < ops.length; i++) // Read DOM
+ endOperation_finish(ops[i]);
+ }
+
+ function endOperation_R1(op) {
+ var cm = op.cm, display = cm.display;
+ maybeClipScrollbars(cm);
+ if (op.updateMaxLine) findMaxLine(cm);
+
+ op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
+ op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
+ op.scrollToPos.to.line >= display.viewTo) ||
+ display.maxLineChanged && cm.options.lineWrapping;
+ op.update = op.mustUpdate &&
+ new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
+ }
+
+ function endOperation_W1(op) {
+ op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);
+ }
+
+ function endOperation_R2(op) {
+ var cm = op.cm, display = cm.display;
+ if (op.updatedDisplay) updateHeightsInViewport(cm);
+
+ op.barMeasure = measureForScrollbars(cm);
+
+ // If the max line changed since it was last measured, measure it,
+ // and ensure the document's width matches it.
+ // updateDisplay_W2 will use these properties to do the actual resizing
+ if (display.maxLineChanged && !cm.options.lineWrapping) {
+ op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
+ cm.display.sizerWidth = op.adjustWidthTo;
+ op.barMeasure.scrollWidth =
+ Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);
+ op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));
+ }
+
+ if (op.updatedDisplay || op.selectionChanged)
+ op.preparedSelection = display.input.prepareSelection();
+ }
+
+ function endOperation_W2(op) {
+ var cm = op.cm;
+
+ if (op.adjustWidthTo != null) {
+ cm.display.sizer.style.minWidth = op.adjustWidthTo + "px";
+ if (op.maxScrollLeft < cm.doc.scrollLeft)
+ setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true);
+ cm.display.maxLineChanged = false;
+ }
+
+ if (op.preparedSelection)
+ cm.display.input.showSelection(op.preparedSelection);
+ if (op.updatedDisplay)
+ setDocumentHeight(cm, op.barMeasure);
+ if (op.updatedDisplay || op.startHeight != cm.doc.height)
+ updateScrollbars(cm, op.barMeasure);
+
+ if (op.selectionChanged) restartBlink(cm);
+
+ if (cm.state.focused && op.updateInput)
+ cm.display.input.reset(op.typing);
+ if (op.focus && op.focus == activeElt()) ensureFocus(op.cm);
+ }
+
+ function endOperation_finish(op) {
+ var cm = op.cm, display = cm.display, doc = cm.doc;
+
+ if (op.updatedDisplay) postUpdateDisplay(cm, op.update);
+
+ // Abort mouse wheel delta measurement, when scrolling explicitly
+ if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
+ display.wheelStartX = display.wheelStartY = null;
+
+ // Propagate the scroll position to the actual DOM scroller
+ if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) {
+ doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop));
+ display.scrollbars.setScrollTop(doc.scrollTop);
+ display.scroller.scrollTop = doc.scrollTop;
+ }
+ if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) {
+ doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft));
+ display.scrollbars.setScrollLeft(doc.scrollLeft);
+ display.scroller.scrollLeft = doc.scrollLeft;
+ alignHorizontally(cm);
+ }
+ // If we need to scroll a specific position into view, do so.
+ if (op.scrollToPos) {
+ var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
+ clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);
+ if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords);
+ }
+
+ // Fire events for markers that are hidden/unidden by editing or
+ // undoing
+ var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
+ if (hidden) for (var i = 0; i < hidden.length; ++i)
+ if (!hidden[i].lines.length) signal(hidden[i], "hide");
+ if (unhidden) for (var i = 0; i < unhidden.length; ++i)
+ if (unhidden[i].lines.length) signal(unhidden[i], "unhide");
+
+ if (display.wrapper.offsetHeight)
+ doc.scrollTop = cm.display.scroller.scrollTop;
+
+ // Fire change events, and delayed event handlers
+ if (op.changeObjs)
+ signal(cm, "changes", cm, op.changeObjs);
+ if (op.update)
+ op.update.finish();
+ }
+
+ // Run the given function in an operation
+ function runInOp(cm, f) {
+ if (cm.curOp) return f();
+ startOperation(cm);
+ try { return f(); }
+ finally { endOperation(cm); }
+ }
+ // Wraps a function in an operation. Returns the wrapped function.
+ function operation(cm, f) {
+ return function() {
+ if (cm.curOp) return f.apply(cm, arguments);
+ startOperation(cm);
+ try { return f.apply(cm, arguments); }
+ finally { endOperation(cm); }
+ };
+ }
+ // Used to add methods to editor and doc instances, wrapping them in
+ // operations.
+ function methodOp(f) {
+ return function() {
+ if (this.curOp) return f.apply(this, arguments);
+ startOperation(this);
+ try { return f.apply(this, arguments); }
+ finally { endOperation(this); }
+ };
+ }
+ function docMethodOp(f) {
+ return function() {
+ var cm = this.cm;
+ if (!cm || cm.curOp) return f.apply(this, arguments);
+ startOperation(cm);
+ try { return f.apply(this, arguments); }
+ finally { endOperation(cm); }
+ };
+ }
+
+ // VIEW TRACKING
+
+ // These objects are used to represent the visible (currently drawn)
+ // part of the document. A LineView may correspond to multiple
+ // logical lines, if those are connected by collapsed ranges.
+ function LineView(doc, line, lineN) {
+ // The starting line
+ this.line = line;
+ // Continuing lines, if any
+ this.rest = visualLineContinued(line);
+ // Number of logical lines in this visual line
+ this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;
+ this.node = this.text = null;
+ this.hidden = lineIsHidden(doc, line);
+ }
+
+ // Create a range of LineView objects for the given lines.
+ function buildViewArray(cm, from, to) {
+ var array = [], nextPos;
+ for (var pos = from; pos < to; pos = nextPos) {
+ var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);
+ nextPos = pos + view.size;
+ array.push(view);
+ }
+ return array;
+ }
+
+ // Updates the display.view data structure for a given change to the
+ // document. From and to are in pre-change coordinates. Lendiff is
+ // the amount of lines added or subtracted by the change. This is
+ // used for changes that span multiple lines, or change the way
+ // lines are divided into visual lines. regLineChange (below)
+ // registers single-line changes.
+ function regChange(cm, from, to, lendiff) {
+ if (from == null) from = cm.doc.first;
+ if (to == null) to = cm.doc.first + cm.doc.size;
+ if (!lendiff) lendiff = 0;
+
+ var display = cm.display;
+ if (lendiff && to < display.viewTo &&
+ (display.updateLineNumbers == null || display.updateLineNumbers > from))
+ display.updateLineNumbers = from;
+
+ cm.curOp.viewChanged = true;
+
+ if (from >= display.viewTo) { // Change after
+ if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
+ resetView(cm);
+ } else if (to <= display.viewFrom) { // Change before
+ if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
+ resetView(cm);
+ } else {
+ display.viewFrom += lendiff;
+ display.viewTo += lendiff;
+ }
+ } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
+ resetView(cm);
+ } else if (from <= display.viewFrom) { // Top overlap
+ var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
+ if (cut) {
+ display.view = display.view.slice(cut.index);
+ display.viewFrom = cut.lineN;
+ display.viewTo += lendiff;
+ } else {
+ resetView(cm);
+ }
+ } else if (to >= display.viewTo) { // Bottom overlap
+ var cut = viewCuttingPoint(cm, from, from, -1);
+ if (cut) {
+ display.view = display.view.slice(0, cut.index);
+ display.viewTo = cut.lineN;
+ } else {
+ resetView(cm);
+ }
+ } else { // Gap in the middle
+ var cutTop = viewCuttingPoint(cm, from, from, -1);
+ var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
+ if (cutTop && cutBot) {
+ display.view = display.view.slice(0, cutTop.index)
+ .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
+ .concat(display.view.slice(cutBot.index));
+ display.viewTo += lendiff;
+ } else {
+ resetView(cm);
+ }
+ }
+
+ var ext = display.externalMeasured;
+ if (ext) {
+ if (to < ext.lineN)
+ ext.lineN += lendiff;
+ else if (from < ext.lineN + ext.size)
+ display.externalMeasured = null;
+ }
+ }
+
+ // Register a change to a single line. Type must be one of "text",
+ // "gutter", "class", "widget"
+ function regLineChange(cm, line, type) {
+ cm.curOp.viewChanged = true;
+ var display = cm.display, ext = cm.display.externalMeasured;
+ if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
+ display.externalMeasured = null;
+
+ if (line < display.viewFrom || line >= display.viewTo) return;
+ var lineView = display.view[findViewIndex(cm, line)];
+ if (lineView.node == null) return;
+ var arr = lineView.changes || (lineView.changes = []);
+ if (indexOf(arr, type) == -1) arr.push(type);
+ }
+
+ // Clear the view.
+ function resetView(cm) {
+ cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
+ cm.display.view = [];
+ cm.display.viewOffset = 0;
+ }
+
+ // Find the view element corresponding to a given line. Return null
+ // when the line isn't visible.
+ function findViewIndex(cm, n) {
+ if (n >= cm.display.viewTo) return null;
+ n -= cm.display.viewFrom;
+ if (n < 0) return null;
+ var view = cm.display.view;
+ for (var i = 0; i < view.length; i++) {
+ n -= view[i].size;
+ if (n < 0) return i;
+ }
+ }
+
+ function viewCuttingPoint(cm, oldN, newN, dir) {
+ var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
+ if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
+ return {index: index, lineN: newN};
+ for (var i = 0, n = cm.display.viewFrom; i < index; i++)
+ n += view[i].size;
+ if (n != oldN) {
+ if (dir > 0) {
+ if (index == view.length - 1) return null;
+ diff = (n + view[index].size) - oldN;
+ index++;
+ } else {
+ diff = n - oldN;
+ }
+ oldN += diff; newN += diff;
+ }
+ while (visualLineNo(cm.doc, newN) != newN) {
+ if (index == (dir < 0 ? 0 : view.length - 1)) return null;
+ newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
+ index += dir;
+ }
+ return {index: index, lineN: newN};
+ }
+
+ // Force the view to cover a given range, adding empty view element
+ // or clipping off existing ones as needed.
+ function adjustView(cm, from, to) {
+ var display = cm.display, view = display.view;
+ if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
+ display.view = buildViewArray(cm, from, to);
+ display.viewFrom = from;
+ } else {
+ if (display.viewFrom > from)
+ display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view);
+ else if (display.viewFrom < from)
+ display.view = display.view.slice(findViewIndex(cm, from));
+ display.viewFrom = from;
+ if (display.viewTo < to)
+ display.view = display.view.concat(buildViewArray(cm, display.viewTo, to));
+ else if (display.viewTo > to)
+ display.view = display.view.slice(0, findViewIndex(cm, to));
+ }
+ display.viewTo = to;
+ }
+
+ // Count the number of lines in the view whose DOM representation is
+ // out of date (or nonexistent).
+ function countDirtyView(cm) {
+ var view = cm.display.view, dirty = 0;
+ for (var i = 0; i < view.length; i++) {
+ var lineView = view[i];
+ if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty;
+ }
+ return dirty;
+ }
+
+ // EVENT HANDLERS
+
+ // Attach the necessary event handlers when initializing the editor
+ function registerEventHandlers(cm) {
+ var d = cm.display;
+ on(d.scroller, "mousedown", operation(cm, onMouseDown));
+ // Older IE's will not fire a second mousedown for a double click
+ if (ie && ie_version < 11)
+ on(d.scroller, "dblclick", operation(cm, function(e) {
+ if (signalDOMEvent(cm, e)) return;
+ var pos = posFromMouse(cm, e);
+ if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return;
+ e_preventDefault(e);
+ var word = cm.findWordAt(pos);
+ extendSelection(cm.doc, word.anchor, word.head);
+ }));
+ else
+ on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); });
+ // Some browsers fire contextmenu *after* opening the menu, at
+ // which point we can't mess with it anymore. Context menu is
+ // handled in onMouseDown for these browsers.
+ if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);});
+
+ // Used to suppress mouse event handling when a touch happens
+ var touchFinished, prevTouch = {end: 0};
+ function finishTouch() {
+ if (d.activeTouch) {
+ touchFinished = setTimeout(function() {d.activeTouch = null;}, 1000);
+ prevTouch = d.activeTouch;
+ prevTouch.end = +new Date;
+ }
+ };
+ function isMouseLikeTouchEvent(e) {
+ if (e.touches.length != 1) return false;
+ var touch = e.touches[0];
+ return touch.radiusX <= 1 && touch.radiusY <= 1;
+ }
+ function farAway(touch, other) {
+ if (other.left == null) return true;
+ var dx = other.left - touch.left, dy = other.top - touch.top;
+ return dx * dx + dy * dy > 20 * 20;
+ }
+ on(d.scroller, "touchstart", function(e) {
+ if (!isMouseLikeTouchEvent(e)) {
+ clearTimeout(touchFinished);
+ var now = +new Date;
+ d.activeTouch = {start: now, moved: false,
+ prev: now - prevTouch.end <= 300 ? prevTouch : null};
+ if (e.touches.length == 1) {
+ d.activeTouch.left = e.touches[0].pageX;
+ d.activeTouch.top = e.touches[0].pageY;
+ }
+ }
+ });
+ on(d.scroller, "touchmove", function() {
+ if (d.activeTouch) d.activeTouch.moved = true;
+ });
+ on(d.scroller, "touchend", function(e) {
+ var touch = d.activeTouch;
+ if (touch && !eventInWidget(d, e) && touch.left != null &&
+ !touch.moved && new Date - touch.start < 300) {
+ var pos = cm.coordsChar(d.activeTouch, "page"), range;
+ if (!touch.prev || farAway(touch, touch.prev)) // Single tap
+ range = new Range(pos, pos);
+ else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap
+ range = cm.findWordAt(pos);
+ else // Triple tap
+ range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0)));
+ cm.setSelection(range.anchor, range.head);
+ cm.focus();
+ e_preventDefault(e);
+ }
+ finishTouch();
+ });
+ on(d.scroller, "touchcancel", finishTouch);
+
+ // Sync scrolling between fake scrollbars and real scrollable
+ // area, ensure viewport is updated when scrolling.
+ on(d.scroller, "scroll", function() {
+ if (d.scroller.clientHeight) {
+ setScrollTop(cm, d.scroller.scrollTop);
+ setScrollLeft(cm, d.scroller.scrollLeft, true);
+ signal(cm, "scroll", cm);
+ }
+ });
+
+ // Listen to wheel events in order to try and update the viewport on time.
+ on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);});
+ on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);});
+
+ // Prevent wrapper from ever scrolling
+ on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
+
+ d.dragFunctions = {
+ simple: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);},
+ start: function(e){onDragStart(cm, e);},
+ drop: operation(cm, onDrop)
+ };
+
+ var inp = d.input.getField();
+ on(inp, "keyup", function(e) { onKeyUp.call(cm, e); });
+ on(inp, "keydown", operation(cm, onKeyDown));
+ on(inp, "keypress", operation(cm, onKeyPress));
+ on(inp, "focus", bind(onFocus, cm));
+ on(inp, "blur", bind(onBlur, cm));
+ }
+
+ function dragDropChanged(cm, value, old) {
+ var wasOn = old && old != CodeMirror.Init;
+ if (!value != !wasOn) {
+ var funcs = cm.display.dragFunctions;
+ var toggle = value ? on : off;
+ toggle(cm.display.scroller, "dragstart", funcs.start);
+ toggle(cm.display.scroller, "dragenter", funcs.simple);
+ toggle(cm.display.scroller, "dragover", funcs.simple);
+ toggle(cm.display.scroller, "drop", funcs.drop);
+ }
+ }
+
+ // Called when the window resizes
+ function onResize(cm) {
+ var d = cm.display;
+ if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth)
+ return;
+ // Might be a text scaling operation, clear size caches.
+ d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
+ d.scrollbarsClipped = false;
+ cm.setSize();
+ }
+
+ // MOUSE EVENTS
+
+ // Return true when the given mouse event happened in a widget
+ function eventInWidget(display, e) {
+ for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
+ if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
+ (n.parentNode == display.sizer && n != display.mover))
+ return true;
+ }
+ }
+
+ // Given a mouse event, find the corresponding position. If liberal
+ // is false, it checks whether a gutter or scrollbar was clicked,
+ // and returns null if it was. forRect is used by rectangular
+ // selections, and tries to estimate a character position even for
+ // coordinates beyond the right of the text.
+ function posFromMouse(cm, e, liberal, forRect) {
+ var display = cm.display;
+ if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") return null;
+
+ var x, y, space = display.lineSpace.getBoundingClientRect();
+ // Fails unpredictably on IE[67] when mouse is dragged around quickly.
+ try { x = e.clientX - space.left; y = e.clientY - space.top; }
+ catch (e) { return null; }
+ var coords = coordsChar(cm, x, y), line;
+ if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
+ var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
+ coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
+ }
+ return coords;
+ }
+
+ // A mouse down can be a single click, double click, triple click,
+ // start of selection drag, start of text drag, new cursor
+ // (ctrl-click), rectangle drag (alt-drag), or xwin
+ // middle-click-paste. Or it might be a click on something we should
+ // not interfere with, such as a scrollbar or widget.
+ function onMouseDown(e) {
+ var cm = this, display = cm.display;
+ if (display.activeTouch && display.input.supportsTouch() || signalDOMEvent(cm, e)) return;
+ display.shift = e.shiftKey;
+
+ if (eventInWidget(display, e)) {
+ if (!webkit) {
+ // Briefly turn off draggability, to allow widgets to do
+ // normal dragging things.
+ display.scroller.draggable = false;
+ setTimeout(function(){display.scroller.draggable = true;}, 100);
+ }
+ return;
+ }
+ if (clickInGutter(cm, e)) return;
+ var start = posFromMouse(cm, e);
+ window.focus();
+
+ switch (e_button(e)) {
+ case 1:
+ if (start)
+ leftButtonDown(cm, e, start);
+ else if (e_target(e) == display.scroller)
+ e_preventDefault(e);
+ break;
+ case 2:
+ if (webkit) cm.state.lastMiddleDown = +new Date;
+ if (start) extendSelection(cm.doc, start);
+ setTimeout(function() {display.input.focus();}, 20);
+ e_preventDefault(e);
+ break;
+ case 3:
+ if (captureRightClick) onContextMenu(cm, e);
+ else delayBlurEvent(cm);
+ break;
+ }
+ }
+
+ var lastClick, lastDoubleClick;
+ function leftButtonDown(cm, e, start) {
+ if (ie) setTimeout(bind(ensureFocus, cm), 0);
+ else cm.curOp.focus = activeElt();
+
+ var now = +new Date, type;
+ if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) {
+ type = "triple";
+ } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) {
+ type = "double";
+ lastDoubleClick = {time: now, pos: start};
+ } else {
+ type = "single";
+ lastClick = {time: now, pos: start};
+ }
+
+ var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained;
+ if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) &&
+ type == "single" && (contained = sel.contains(start)) > -1 &&
+ !sel.ranges[contained].empty())
+ leftButtonStartDrag(cm, e, start, modifier);
+ else
+ leftButtonSelect(cm, e, start, type, modifier);
+ }
+
+ // Start a text drag. When it ends, see if any dragging actually
+ // happen, and treat as a click if it didn't.
+ function leftButtonStartDrag(cm, e, start, modifier) {
+ var display = cm.display;
+ var dragEnd = operation(cm, function(e2) {
+ if (webkit) display.scroller.draggable = false;
+ cm.state.draggingText = false;
+ off(document, "mouseup", dragEnd);
+ off(display.scroller, "drop", dragEnd);
+ if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
+ e_preventDefault(e2);
+ if (!modifier)
+ extendSelection(cm.doc, start);
+ // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
+ if (webkit || ie && ie_version == 9)
+ setTimeout(function() {document.body.focus(); display.input.focus();}, 20);
+ else
+ display.input.focus();
+ }
+ });
+ // Let the drag handler handle this.
+ if (webkit) display.scroller.draggable = true;
+ cm.state.draggingText = dragEnd;
+ // IE's approach to draggable
+ if (display.scroller.dragDrop) display.scroller.dragDrop();
+ on(document, "mouseup", dragEnd);
+ on(display.scroller, "drop", dragEnd);
+ }
+
+ // Normal selection, as opposed to text dragging.
+ function leftButtonSelect(cm, e, start, type, addNew) {
+ var display = cm.display, doc = cm.doc;
+ e_preventDefault(e);
+
+ var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;
+ if (addNew && !e.shiftKey) {
+ ourIndex = doc.sel.contains(start);
+ if (ourIndex > -1)
+ ourRange = ranges[ourIndex];
+ else
+ ourRange = new Range(start, start);
+ } else {
+ ourRange = doc.sel.primary();
+ ourIndex = doc.sel.primIndex;
+ }
+
+ if (e.altKey) {
+ type = "rect";
+ if (!addNew) ourRange = new Range(start, start);
+ start = posFromMouse(cm, e, true, true);
+ ourIndex = -1;
+ } else if (type == "double") {
+ var word = cm.findWordAt(start);
+ if (cm.display.shift || doc.extend)
+ ourRange = extendRange(doc, ourRange, word.anchor, word.head);
+ else
+ ourRange = word;
+ } else if (type == "triple") {
+ var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0)));
+ if (cm.display.shift || doc.extend)
+ ourRange = extendRange(doc, ourRange, line.anchor, line.head);
+ else
+ ourRange = line;
+ } else {
+ ourRange = extendRange(doc, ourRange, start);
+ }
+
+ if (!addNew) {
+ ourIndex = 0;
+ setSelection(doc, new Selection([ourRange], 0), sel_mouse);
+ startSel = doc.sel;
+ } else if (ourIndex == -1) {
+ ourIndex = ranges.length;
+ setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),
+ {scroll: false, origin: "*mouse"});
+ } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) {
+ setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0));
+ startSel = doc.sel;
+ } else {
+ replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
+ }
+
+ var lastPos = start;
+ function extendTo(pos) {
+ if (cmp(lastPos, pos) == 0) return;
+ lastPos = pos;
+
+ if (type == "rect") {
+ var ranges = [], tabSize = cm.options.tabSize;
+ var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);
+ var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);
+ var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);
+ for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));
+ line <= end; line++) {
+ var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);
+ if (left == right)
+ ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos)));
+ else if (text.length > leftPos)
+ ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize))));
+ }
+ if (!ranges.length) ranges.push(new Range(start, start));
+ setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),
+ {origin: "*mouse", scroll: false});
+ cm.scrollIntoView(pos);
+ } else {
+ var oldRange = ourRange;
+ var anchor = oldRange.anchor, head = pos;
+ if (type != "single") {
+ if (type == "double")
+ var range = cm.findWordAt(pos);
+ else
+ var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0)));
+ if (cmp(range.anchor, anchor) > 0) {
+ head = range.head;
+ anchor = minPos(oldRange.from(), range.anchor);
+ } else {
+ head = range.anchor;
+ anchor = maxPos(oldRange.to(), range.head);
+ }
+ }
+ var ranges = startSel.ranges.slice(0);
+ ranges[ourIndex] = new Range(clipPos(doc, anchor), head);
+ setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse);
+ }
+ }
+
+ var editorSize = display.wrapper.getBoundingClientRect();
+ // Used to ensure timeout re-tries don't fire when another extend
+ // happened in the meantime (clearTimeout isn't reliable -- at
+ // least on Chrome, the timeouts still happen even when cleared,
+ // if the clear happens after their scheduled firing time).
+ var counter = 0;
+
+ function extend(e) {
+ var curCount = ++counter;
+ var cur = posFromMouse(cm, e, true, type == "rect");
+ if (!cur) return;
+ if (cmp(cur, lastPos) != 0) {
+ cm.curOp.focus = activeElt();
+ extendTo(cur);
+ var visible = visibleLines(display, doc);
+ if (cur.line >= visible.to || cur.line < visible.from)
+ setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150);
+ } else {
+ var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
+ if (outside) setTimeout(operation(cm, function() {
+ if (counter != curCount) return;
+ display.scroller.scrollTop += outside;
+ extend(e);
+ }), 50);
+ }
+ }
+
+ function done(e) {
+ counter = Infinity;
+ e_preventDefault(e);
+ display.input.focus();
+ off(document, "mousemove", move);
+ off(document, "mouseup", up);
+ doc.history.lastSelOrigin = null;
+ }
+
+ var move = operation(cm, function(e) {
+ if (!e_button(e)) done(e);
+ else extend(e);
+ });
+ var up = operation(cm, done);
+ on(document, "mousemove", move);
+ on(document, "mouseup", up);
+ }
+
+ // Determines whether an event happened in the gutter, and fires the
+ // handlers for the corresponding event.
+ function gutterEvent(cm, e, type, prevent, signalfn) {
+ try { var mX = e.clientX, mY = e.clientY; }
+ catch(e) { return false; }
+ if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false;
+ if (prevent) e_preventDefault(e);
+
+ var display = cm.display;
+ var lineBox = display.lineDiv.getBoundingClientRect();
+
+ if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e);
+ mY -= lineBox.top - display.viewOffset;
+
+ for (var i = 0; i < cm.options.gutters.length; ++i) {
+ var g = display.gutters.childNodes[i];
+ if (g && g.getBoundingClientRect().right >= mX) {
+ var line = lineAtHeight(cm.doc, mY);
+ var gutter = cm.options.gutters[i];
+ signalfn(cm, type, cm, line, gutter, e);
+ return e_defaultPrevented(e);
+ }
+ }
+ }
+
+ function clickInGutter(cm, e) {
+ return gutterEvent(cm, e, "gutterClick", true, signalLater);
+ }
+
+ // Kludge to work around strange IE behavior where it'll sometimes
+ // re-fire a series of drag-related events right after the drop (#1551)
+ var lastDrop = 0;
+
+ function onDrop(e) {
+ var cm = this;
+ if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
+ return;
+ e_preventDefault(e);
+ if (ie) lastDrop = +new Date;
+ var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
+ if (!pos || isReadOnly(cm)) return;
+ // Might be a file drop, in which case we simply extract the text
+ // and insert it.
+ if (files && files.length && window.FileReader && window.File) {
+ var n = files.length, text = Array(n), read = 0;
+ var loadFile = function(file, i) {
+ var reader = new FileReader;
+ reader.onload = operation(cm, function() {
+ text[i] = reader.result;
+ if (++read == n) {
+ pos = clipPos(cm.doc, pos);
+ var change = {from: pos, to: pos, text: splitLines(text.join("\n")), origin: "paste"};
+ makeChange(cm.doc, change);
+ setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
+ }
+ });
+ reader.readAsText(file);
+ };
+ for (var i = 0; i < n; ++i) loadFile(files[i], i);
+ } else { // Normal drop
+ // Don't do a replace if the drop happened inside of the selected text.
+ if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
+ cm.state.draggingText(e);
+ // Ensure the editor is re-focused
+ setTimeout(function() {cm.display.input.focus();}, 20);
+ return;
+ }
+ try {
+ var text = e.dataTransfer.getData("Text");
+ if (text) {
+ if (cm.state.draggingText && !(mac ? e.altKey : e.ctrlKey))
+ var selected = cm.listSelections();
+ setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
+ if (selected) for (var i = 0; i < selected.length; ++i)
+ replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag");
+ cm.replaceSelection(text, "around", "paste");
+ cm.display.input.focus();
+ }
+ }
+ catch(e){}
+ }
+ }
+
+ function onDragStart(cm, e) {
+ if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; }
+ if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return;
+
+ e.dataTransfer.setData("Text", cm.getSelection());
+
+ // Use dummy image instead of default browsers image.
+ // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
+ if (e.dataTransfer.setDragImage && !safari) {
+ var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
+ img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
+ if (presto) {
+ img.width = img.height = 1;
+ cm.display.wrapper.appendChild(img);
+ // Force a relayout, or Opera won't use our image for some obscure reason
+ img._top = img.offsetTop;
+ }
+ e.dataTransfer.setDragImage(img, 0, 0);
+ if (presto) img.parentNode.removeChild(img);
+ }
+ }
+
+ // SCROLL EVENTS
+
+ // Sync the scrollable area and scrollbars, ensure the viewport
+ // covers the visible area.
+ function setScrollTop(cm, val) {
+ if (Math.abs(cm.doc.scrollTop - val) < 2) return;
+ cm.doc.scrollTop = val;
+ if (!gecko) updateDisplaySimple(cm, {top: val});
+ if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;
+ cm.display.scrollbars.setScrollTop(val);
+ if (gecko) updateDisplaySimple(cm);
+ startWorker(cm, 100);
+ }
+ // Sync scroller and scrollbar, ensure the gutter elements are
+ // aligned.
+ function setScrollLeft(cm, val, isScroller) {
+ if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return;
+ val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
+ cm.doc.scrollLeft = val;
+ alignHorizontally(cm);
+ if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
+ cm.display.scrollbars.setScrollLeft(val);
+ }
+
+ // Since the delta values reported on mouse wheel events are
+ // unstandardized between browsers and even browser versions, and
+ // generally horribly unpredictable, this code starts by measuring
+ // the scroll effect that the first few mouse wheel events have,
+ // and, from that, detects the way it can convert deltas to pixel
+ // offsets afterwards.
+ //
+ // The reason we want to know the amount a wheel event will scroll
+ // is that it gives us a chance to update the display before the
+ // actual scrolling happens, reducing flickering.
+
+ var wheelSamples = 0, wheelPixelsPerUnit = null;
+ // Fill in a browser-detected starting value on browsers where we
+ // know one. These don't have to be accurate -- the result of them
+ // being wrong would just be a slight flicker on the first wheel
+ // scroll (if it is large enough).
+ if (ie) wheelPixelsPerUnit = -.53;
+ else if (gecko) wheelPixelsPerUnit = 15;
+ else if (chrome) wheelPixelsPerUnit = -.7;
+ else if (safari) wheelPixelsPerUnit = -1/3;
+
+ var wheelEventDelta = function(e) {
+ var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
+ if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail;
+ if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail;
+ else if (dy == null) dy = e.wheelDelta;
+ return {x: dx, y: dy};
+ };
+ CodeMirror.wheelEventPixels = function(e) {
+ var delta = wheelEventDelta(e);
+ delta.x *= wheelPixelsPerUnit;
+ delta.y *= wheelPixelsPerUnit;
+ return delta;
+ };
+
+ function onScrollWheel(cm, e) {
+ var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;
+
+ var display = cm.display, scroll = display.scroller;
+ // Quit if there's nothing to scroll here
+ if (!(dx && scroll.scrollWidth > scroll.clientWidth ||
+ dy && scroll.scrollHeight > scroll.clientHeight)) return;
+
+ // Webkit browsers on OS X abort momentum scrolls when the target
+ // of the scroll event is removed from the scrollable element.
+ // This hack (see related code in patchDisplay) makes sure the
+ // element is kept around.
+ if (dy && mac && webkit) {
+ outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {
+ for (var i = 0; i < view.length; i++) {
+ if (view[i].node == cur) {
+ cm.display.currentWheelTarget = cur;
+ break outer;
+ }
+ }
+ }
+ }
+
+ // On some browsers, horizontal scrolling will cause redraws to
+ // happen before the gutter has been realigned, causing it to
+ // wriggle around in a most unseemly way. When we have an
+ // estimated pixels/delta value, we just handle horizontal
+ // scrolling entirely here. It'll be slightly off from native, but
+ // better than glitching out.
+ if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
+ if (dy)
+ setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));
+ setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));
+ e_preventDefault(e);
+ display.wheelStartX = null; // Abort measurement, if in progress
+ return;
+ }
+
+ // 'Project' the visible viewport to cover the area that is being
+ // scrolled into view (if we know enough to estimate it).
+ if (dy && wheelPixelsPerUnit != null) {
+ var pixels = dy * wheelPixelsPerUnit;
+ var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
+ if (pixels < 0) top = Math.max(0, top + pixels - 50);
+ else bot = Math.min(cm.doc.height, bot + pixels + 50);
+ updateDisplaySimple(cm, {top: top, bottom: bot});
+ }
+
+ if (wheelSamples < 20) {
+ if (display.wheelStartX == null) {
+ display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
+ display.wheelDX = dx; display.wheelDY = dy;
+ setTimeout(function() {
+ if (display.wheelStartX == null) return;
+ var movedX = scroll.scrollLeft - display.wheelStartX;
+ var movedY = scroll.scrollTop - display.wheelStartY;
+ var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
+ (movedX && display.wheelDX && movedX / display.wheelDX);
+ display.wheelStartX = display.wheelStartY = null;
+ if (!sample) return;
+ wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
+ ++wheelSamples;
+ }, 200);
+ } else {
+ display.wheelDX += dx; display.wheelDY += dy;
+ }
+ }
+ }
+
+ // KEY EVENTS
+
+ // Run a handler that was bound to a key.
+ function doHandleBinding(cm, bound, dropShift) {
+ if (typeof bound == "string") {
+ bound = commands[bound];
+ if (!bound) return false;
+ }
+ // Ensure previous input has been read, so that the handler sees a
+ // consistent view of the document
+ cm.display.input.ensurePolled();
+ var prevShift = cm.display.shift, done = false;
+ try {
+ if (isReadOnly(cm)) cm.state.suppressEdits = true;
+ if (dropShift) cm.display.shift = false;
+ done = bound(cm) != Pass;
+ } finally {
+ cm.display.shift = prevShift;
+ cm.state.suppressEdits = false;
+ }
+ return done;
+ }
+
+ function lookupKeyForEditor(cm, name, handle) {
+ for (var i = 0; i < cm.state.keyMaps.length; i++) {
+ var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);
+ if (result) return result;
+ }
+ return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))
+ || lookupKey(name, cm.options.keyMap, handle, cm);
+ }
+
+ var stopSeq = new Delayed;
+ function dispatchKey(cm, name, e, handle) {
+ var seq = cm.state.keySeq;
+ if (seq) {
+ if (isModifierKey(name)) return "handled";
+ stopSeq.set(50, function() {
+ if (cm.state.keySeq == seq) {
+ cm.state.keySeq = null;
+ cm.display.input.reset();
+ }
+ });
+ name = seq + " " + name;
+ }
+ var result = lookupKeyForEditor(cm, name, handle);
+
+ if (result == "multi")
+ cm.state.keySeq = name;
+ if (result == "handled")
+ signalLater(cm, "keyHandled", cm, name, e);
+
+ if (result == "handled" || result == "multi") {
+ e_preventDefault(e);
+ restartBlink(cm);
+ }
+
+ if (seq && !result && /\'$/.test(name)) {
+ e_preventDefault(e);
+ return true;
+ }
+ return !!result;
+ }
+
+ // Handle a key from the keydown event.
+ function handleKeyBinding(cm, e) {
+ var name = keyName(e, true);
+ if (!name) return false;
+
+ if (e.shiftKey && !cm.state.keySeq) {
+ // First try to resolve full name (including 'Shift-'). Failing
+ // that, see if there is a cursor-motion command (starting with
+ // 'go') bound to the keyname without 'Shift-'.
+ return dispatchKey(cm, "Shift-" + name, e, function(b) {return doHandleBinding(cm, b, true);})
+ || dispatchKey(cm, name, e, function(b) {
+ if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
+ return doHandleBinding(cm, b);
+ });
+ } else {
+ return dispatchKey(cm, name, e, function(b) { return doHandleBinding(cm, b); });
+ }
+ }
+
+ // Handle a key from the keypress event
+ function handleCharBinding(cm, e, ch) {
+ return dispatchKey(cm, "'" + ch + "'", e,
+ function(b) { return doHandleBinding(cm, b, true); });
+ }
+
+ var lastStoppedKey = null;
+ function onKeyDown(e) {
+ var cm = this;
+ cm.curOp.focus = activeElt();
+ if (signalDOMEvent(cm, e)) return;
+ // IE does strange things with escape.
+ if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false;
+ var code = e.keyCode;
+ cm.display.shift = code == 16 || e.shiftKey;
+ var handled = handleKeyBinding(cm, e);
+ if (presto) {
+ lastStoppedKey = handled ? code : null;
+ // Opera has no cut event... we try to at least catch the key combo
+ if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
+ cm.replaceSelection("", null, "cut");
+ }
+
+ // Turn mouse into crosshair when Alt is held on Mac.
+ if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
+ showCrossHair(cm);
+ }
+
+ function showCrossHair(cm) {
+ var lineDiv = cm.display.lineDiv;
+ addClass(lineDiv, "CodeMirror-crosshair");
+
+ function up(e) {
+ if (e.keyCode == 18 || !e.altKey) {
+ rmClass(lineDiv, "CodeMirror-crosshair");
+ off(document, "keyup", up);
+ off(document, "mouseover", up);
+ }
+ }
+ on(document, "keyup", up);
+ on(document, "mouseover", up);
+ }
+
+ function onKeyUp(e) {
+ if (e.keyCode == 16) this.doc.sel.shift = false;
+ signalDOMEvent(this, e);
+ }
+
+ function onKeyPress(e) {
+ var cm = this;
+ if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return;
+ var keyCode = e.keyCode, charCode = e.charCode;
+ if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
+ if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return;
+ var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
+ if (handleCharBinding(cm, e, ch)) return;
+ cm.display.input.onKeyPress(e);
+ }
+
+ // FOCUS/BLUR EVENTS
+
+ function delayBlurEvent(cm) {
+ cm.state.delayingBlurEvent = true;
+ setTimeout(function() {
+ if (cm.state.delayingBlurEvent) {
+ cm.state.delayingBlurEvent = false;
+ onBlur(cm);
+ }
+ }, 100);
+ }
+
+ function onFocus(cm) {
+ if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false;
+
+ if (cm.options.readOnly == "nocursor") return;
+ if (!cm.state.focused) {
+ signal(cm, "focus", cm);
+ cm.state.focused = true;
+ addClass(cm.display.wrapper, "CodeMirror-focused");
+ // This test prevents this from firing when a context
+ // menu is closed (since the input reset would kill the
+ // select-all detection hack)
+ if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
+ cm.display.input.reset();
+ if (webkit) setTimeout(function() { cm.display.input.reset(true); }, 20); // Issue #1730
+ }
+ cm.display.input.receivedFocus();
+ }
+ restartBlink(cm);
+ }
+ function onBlur(cm) {
+ if (cm.state.delayingBlurEvent) return;
+
+ if (cm.state.focused) {
+ signal(cm, "blur", cm);
+ cm.state.focused = false;
+ rmClass(cm.display.wrapper, "CodeMirror-focused");
+ }
+ clearInterval(cm.display.blinker);
+ setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150);
+ }
+
+ // CONTEXT MENU HANDLING
+
+ // To make the context menu work, we need to briefly unhide the
+ // textarea (making it as unobtrusive as possible) to let the
+ // right-click take effect on it.
+ function onContextMenu(cm, e) {
+ if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return;
+ cm.display.input.onContextMenu(e);
+ }
+
+ function contextMenuInGutter(cm, e) {
+ if (!hasHandler(cm, "gutterContextMenu")) return false;
+ return gutterEvent(cm, e, "gutterContextMenu", false, signal);
+ }
+
+ // UPDATING
+
+ // Compute the position of the end of a change (its 'to' property
+ // refers to the pre-change end).
+ var changeEnd = CodeMirror.changeEnd = function(change) {
+ if (!change.text) return change.to;
+ return Pos(change.from.line + change.text.length - 1,
+ lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0));
+ };
+
+ // Adjust a position to refer to the post-change position of the
+ // same text, or the end of the change if the change covers it.
+ function adjustForChange(pos, change) {
+ if (cmp(pos, change.from) < 0) return pos;
+ if (cmp(pos, change.to) <= 0) return changeEnd(change);
+
+ var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
+ if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch;
+ return Pos(line, ch);
+ }
+
+ function computeSelAfterChange(doc, change) {
+ var out = [];
+ for (var i = 0; i < doc.sel.ranges.length; i++) {
+ var range = doc.sel.ranges[i];
+ out.push(new Range(adjustForChange(range.anchor, change),
+ adjustForChange(range.head, change)));
+ }
+ return normalizeSelection(out, doc.sel.primIndex);
+ }
+
+ function offsetPos(pos, old, nw) {
+ if (pos.line == old.line)
+ return Pos(nw.line, pos.ch - old.ch + nw.ch);
+ else
+ return Pos(nw.line + (pos.line - old.line), pos.ch);
+ }
+
+ // Used by replaceSelections to allow moving the selection to the
+ // start or around the replaced test. Hint may be "start" or "around".
+ function computeReplacedSel(doc, changes, hint) {
+ var out = [];
+ var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;
+ for (var i = 0; i < changes.length; i++) {
+ var change = changes[i];
+ var from = offsetPos(change.from, oldPrev, newPrev);
+ var to = offsetPos(changeEnd(change), oldPrev, newPrev);
+ oldPrev = change.to;
+ newPrev = to;
+ if (hint == "around") {
+ var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;
+ out[i] = new Range(inv ? to : from, inv ? from : to);
+ } else {
+ out[i] = new Range(from, from);
+ }
+ }
+ return new Selection(out, doc.sel.primIndex);
+ }
+
+ // Allow "beforeChange" event handlers to influence a change
+ function filterChange(doc, change, update) {
+ var obj = {
+ canceled: false,
+ from: change.from,
+ to: change.to,
+ text: change.text,
+ origin: change.origin,
+ cancel: function() { this.canceled = true; }
+ };
+ if (update) obj.update = function(from, to, text, origin) {
+ if (from) this.from = clipPos(doc, from);
+ if (to) this.to = clipPos(doc, to);
+ if (text) this.text = text;
+ if (origin !== undefined) this.origin = origin;
+ };
+ signal(doc, "beforeChange", doc, obj);
+ if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj);
+
+ if (obj.canceled) return null;
+ return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin};
+ }
+
+ // Apply a change to a document, and add it to the document's
+ // history, and propagating it to all linked documents.
+ function makeChange(doc, change, ignoreReadOnly) {
+ if (doc.cm) {
+ if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly);
+ if (doc.cm.state.suppressEdits) return;
+ }
+
+ if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
+ change = filterChange(doc, change, true);
+ if (!change) return;
+ }
+
+ // Possibly split or suppress the update based on the presence
+ // of read-only spans in its range.
+ var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
+ if (split) {
+ for (var i = split.length - 1; i >= 0; --i)
+ makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text});
+ } else {
+ makeChangeInner(doc, change);
+ }
+ }
+
+ function makeChangeInner(doc, change) {
+ if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return;
+ var selAfter = computeSelAfterChange(doc, change);
+ addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
+
+ makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
+ var rebased = [];
+
+ linkedDocs(doc, function(doc, sharedHist) {
+ if (!sharedHist && indexOf(rebased, doc.history) == -1) {
+ rebaseHist(doc.history, change);
+ rebased.push(doc.history);
+ }
+ makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
+ });
+ }
+
+ // Revert a change stored in a document's history.
+ function makeChangeFromHistory(doc, type, allowSelectionOnly) {
+ if (doc.cm && doc.cm.state.suppressEdits) return;
+
+ var hist = doc.history, event, selAfter = doc.sel;
+ var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done;
+
+ // Verify that there is a useable event (so that ctrl-z won't
+ // needlessly clear selection events)
+ for (var i = 0; i < source.length; i++) {
+ event = source[i];
+ if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
+ break;
+ }
+ if (i == source.length) return;
+ hist.lastOrigin = hist.lastSelOrigin = null;
+
+ for (;;) {
+ event = source.pop();
+ if (event.ranges) {
+ pushSelectionToHistory(event, dest);
+ if (allowSelectionOnly && !event.equals(doc.sel)) {
+ setSelection(doc, event, {clearRedo: false});
+ return;
+ }
+ selAfter = event;
+ }
+ else break;
+ }
+
+ // Build up a reverse change object to add to the opposite history
+ // stack (redo when undoing, and vice versa).
+ var antiChanges = [];
+ pushSelectionToHistory(selAfter, dest);
+ dest.push({changes: antiChanges, generation: hist.generation});
+ hist.generation = event.generation || ++hist.maxGeneration;
+
+ var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
+
+ for (var i = event.changes.length - 1; i >= 0; --i) {
+ var change = event.changes[i];
+ change.origin = type;
+ if (filter && !filterChange(doc, change, false)) {
+ source.length = 0;
+ return;
+ }
+
+ antiChanges.push(historyChangeFromChange(doc, change));
+
+ var after = i ? computeSelAfterChange(doc, change) : lst(source);
+ makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
+ if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)});
+ var rebased = [];
+
+ // Propagate to the linked documents
+ linkedDocs(doc, function(doc, sharedHist) {
+ if (!sharedHist && indexOf(rebased, doc.history) == -1) {
+ rebaseHist(doc.history, change);
+ rebased.push(doc.history);
+ }
+ makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
+ });
+ }
+ }
+
+ // Sub-views need their line numbers shifted when text is added
+ // above or below them in the parent document.
+ function shiftDoc(doc, distance) {
+ if (distance == 0) return;
+ doc.first += distance;
+ doc.sel = new Selection(map(doc.sel.ranges, function(range) {
+ return new Range(Pos(range.anchor.line + distance, range.anchor.ch),
+ Pos(range.head.line + distance, range.head.ch));
+ }), doc.sel.primIndex);
+ if (doc.cm) {
+ regChange(doc.cm, doc.first, doc.first - distance, distance);
+ for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
+ regLineChange(doc.cm, l, "gutter");
+ }
+ }
+
+ // More lower-level change function, handling only a single document
+ // (not linked ones).
+ function makeChangeSingleDoc(doc, change, selAfter, spans) {
+ if (doc.cm && !doc.cm.curOp)
+ return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans);
+
+ if (change.to.line < doc.first) {
+ shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
+ return;
+ }
+ if (change.from.line > doc.lastLine()) return;
+
+ // Clip the change to the size of this doc
+ if (change.from.line < doc.first) {
+ var shift = change.text.length - 1 - (doc.first - change.from.line);
+ shiftDoc(doc, shift);
+ change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
+ text: [lst(change.text)], origin: change.origin};
+ }
+ var last = doc.lastLine();
+ if (change.to.line > last) {
+ change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
+ text: [change.text[0]], origin: change.origin};
+ }
+
+ change.removed = getBetween(doc, change.from, change.to);
+
+ if (!selAfter) selAfter = computeSelAfterChange(doc, change);
+ if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans);
+ else updateDoc(doc, change, spans);
+ setSelectionNoUndo(doc, selAfter, sel_dontScroll);
+ }
+
+ // Handle the interaction of a change to a document with the editor
+ // that this document is part of.
+ function makeChangeSingleDocInEditor(cm, change, spans) {
+ var doc = cm.doc, display = cm.display, from = change.from, to = change.to;
+
+ var recomputeMaxLength = false, checkWidthStart = from.line;
+ if (!cm.options.lineWrapping) {
+ checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));
+ doc.iter(checkWidthStart, to.line + 1, function(line) {
+ if (line == display.maxLine) {
+ recomputeMaxLength = true;
+ return true;
+ }
+ });
+ }
+
+ if (doc.sel.contains(change.from, change.to) > -1)
+ signalCursorActivity(cm);
+
+ updateDoc(doc, change, spans, estimateHeight(cm));
+
+ if (!cm.options.lineWrapping) {
+ doc.iter(checkWidthStart, from.line + change.text.length, function(line) {
+ var len = lineLength(line);
+ if (len > display.maxLineLength) {
+ display.maxLine = line;
+ display.maxLineLength = len;
+ display.maxLineChanged = true;
+ recomputeMaxLength = false;
+ }
+ });
+ if (recomputeMaxLength) cm.curOp.updateMaxLine = true;
+ }
+
+ // Adjust frontier, schedule worker
+ doc.frontier = Math.min(doc.frontier, from.line);
+ startWorker(cm, 400);
+
+ var lendiff = change.text.length - (to.line - from.line) - 1;
+ // Remember that these lines changed, for updating the display
+ if (change.full)
+ regChange(cm);
+ else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
+ regLineChange(cm, from.line, "text");
+ else
+ regChange(cm, from.line, to.line + 1, lendiff);
+
+ var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
+ if (changeHandler || changesHandler) {
+ var obj = {
+ from: from, to: to,
+ text: change.text,
+ removed: change.removed,
+ origin: change.origin
+ };
+ if (changeHandler) signalLater(cm, "change", cm, obj);
+ if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj);
+ }
+ cm.display.selForContextMenu = null;
+ }
+
+ function replaceRange(doc, code, from, to, origin) {
+ if (!to) to = from;
+ if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; }
+ if (typeof code == "string") code = splitLines(code);
+ makeChange(doc, {from: from, to: to, text: code, origin: origin});
+ }
+
+ // SCROLLING THINGS INTO VIEW
+
+ // If an editor sits on the top or bottom of the window, partially
+ // scrolled out of view, this ensures that the cursor is visible.
+ function maybeScrollWindow(cm, coords) {
+ if (signalDOMEvent(cm, "scrollCursorIntoView")) return;
+
+ var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
+ if (coords.top + box.top < 0) doScroll = true;
+ else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
+ if (doScroll != null && !phantom) {
+ var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " +
+ (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " +
+ (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " +
+ coords.left + "px; width: 2px;");
+ cm.display.lineSpace.appendChild(scrollNode);
+ scrollNode.scrollIntoView(doScroll);
+ cm.display.lineSpace.removeChild(scrollNode);
+ }
+ }
+
+ // Scroll a given position into view (immediately), verifying that
+ // it actually became visible (as line heights are accurately
+ // measured, the position of something may 'drift' during drawing).
+ function scrollPosIntoView(cm, pos, end, margin) {
+ if (margin == null) margin = 0;
+ for (var limit = 0; limit < 5; limit++) {
+ var changed = false, coords = cursorCoords(cm, pos);
+ var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
+ var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left),
+ Math.min(coords.top, endCoords.top) - margin,
+ Math.max(coords.left, endCoords.left),
+ Math.max(coords.bottom, endCoords.bottom) + margin);
+ var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
+ if (scrollPos.scrollTop != null) {
+ setScrollTop(cm, scrollPos.scrollTop);
+ if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true;
+ }
+ if (scrollPos.scrollLeft != null) {
+ setScrollLeft(cm, scrollPos.scrollLeft);
+ if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true;
+ }
+ if (!changed) break;
+ }
+ return coords;
+ }
+
+ // Scroll a given set of coordinates into view (immediately).
+ function scrollIntoView(cm, x1, y1, x2, y2) {
+ var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2);
+ if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop);
+ if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft);
+ }
+
+ // Calculate a new scroll position needed to scroll the given
+ // rectangle into view. Returns an object with scrollTop and
+ // scrollLeft properties. When these are undefined, the
+ // vertical/horizontal position does not need to be adjusted.
+ function calculateScrollPos(cm, x1, y1, x2, y2) {
+ var display = cm.display, snapMargin = textHeight(cm.display);
+ if (y1 < 0) y1 = 0;
+ var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
+ var screen = displayHeight(cm), result = {};
+ if (y2 - y1 > screen) y2 = y1 + screen;
+ var docBottom = cm.doc.height + paddingVert(display);
+ var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin;
+ if (y1 < screentop) {
+ result.scrollTop = atTop ? 0 : y1;
+ } else if (y2 > screentop + screen) {
+ var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen);
+ if (newTop != screentop) result.scrollTop = newTop;
+ }
+
+ var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
+ var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);
+ var tooWide = x2 - x1 > screenw;
+ if (tooWide) x2 = x1 + screenw;
+ if (x1 < 10)
+ result.scrollLeft = 0;
+ else if (x1 < screenleft)
+ result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10));
+ else if (x2 > screenw + screenleft - 3)
+ result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw;
+ return result;
+ }
+
+ // Store a relative adjustment to the scroll position in the current
+ // operation (to be applied when the operation finishes).
+ function addToScrollPos(cm, left, top) {
+ if (left != null || top != null) resolveScrollToPos(cm);
+ if (left != null)
+ cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left;
+ if (top != null)
+ cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;
+ }
+
+ // Make sure that at the end of the operation the current cursor is
+ // shown.
+ function ensureCursorVisible(cm) {
+ resolveScrollToPos(cm);
+ var cur = cm.getCursor(), from = cur, to = cur;
+ if (!cm.options.lineWrapping) {
+ from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur;
+ to = Pos(cur.line, cur.ch + 1);
+ }
+ cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true};
+ }
+
+ // When an operation has its scrollToPos property set, and another
+ // scroll action is applied before the end of the operation, this
+ // 'simulates' scrolling that position into view in a cheap way, so
+ // that the effect of intermediate scroll commands is not ignored.
+ function resolveScrollToPos(cm) {
+ var range = cm.curOp.scrollToPos;
+ if (range) {
+ cm.curOp.scrollToPos = null;
+ var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to);
+ var sPos = calculateScrollPos(cm, Math.min(from.left, to.left),
+ Math.min(from.top, to.top) - range.margin,
+ Math.max(from.right, to.right),
+ Math.max(from.bottom, to.bottom) + range.margin);
+ cm.scrollTo(sPos.scrollLeft, sPos.scrollTop);
+ }
+ }
+
+ // API UTILITIES
+
+ // Indent the given line. The how parameter can be "smart",
+ // "add"/null, "subtract", or "prev". When aggressive is false
+ // (typically set to true for forced single-line indents), empty
+ // lines are not indented, and places where the mode returns Pass
+ // are left alone.
+ function indentLine(cm, n, how, aggressive) {
+ var doc = cm.doc, state;
+ if (how == null) how = "add";
+ if (how == "smart") {
+ // Fall back to "prev" when the mode doesn't have an indentation
+ // method.
+ if (!doc.mode.indent) how = "prev";
+ else state = getStateBefore(cm, n);
+ }
+
+ var tabSize = cm.options.tabSize;
+ var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
+ if (line.stateAfter) line.stateAfter = null;
+ var curSpaceString = line.text.match(/^\s*/)[0], indentation;
+ if (!aggressive && !/\S/.test(line.text)) {
+ indentation = 0;
+ how = "not";
+ } else if (how == "smart") {
+ indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
+ if (indentation == Pass || indentation > 150) {
+ if (!aggressive) return;
+ how = "prev";
+ }
+ }
+ if (how == "prev") {
+ if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize);
+ else indentation = 0;
+ } else if (how == "add") {
+ indentation = curSpace + cm.options.indentUnit;
+ } else if (how == "subtract") {
+ indentation = curSpace - cm.options.indentUnit;
+ } else if (typeof how == "number") {
+ indentation = curSpace + how;
+ }
+ indentation = Math.max(0, indentation);
+
+ var indentString = "", pos = 0;
+ if (cm.options.indentWithTabs)
+ for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
+ if (pos < indentation) indentString += spaceStr(indentation - pos);
+
+ if (indentString != curSpaceString) {
+ replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
+ } else {
+ // Ensure that, if the cursor was in the whitespace at the start
+ // of the line, it is moved to the end of that space.
+ for (var i = 0; i < doc.sel.ranges.length; i++) {
+ var range = doc.sel.ranges[i];
+ if (range.head.line == n && range.head.ch < curSpaceString.length) {
+ var pos = Pos(n, curSpaceString.length);
+ replaceOneSelection(doc, i, new Range(pos, pos));
+ break;
+ }
+ }
+ }
+ line.stateAfter = null;
+ }
+
+ // Utility for applying a change to a line by handle or number,
+ // returning the number and optionally registering the line as
+ // changed.
+ function changeLine(doc, handle, changeType, op) {
+ var no = handle, line = handle;
+ if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle));
+ else no = lineNo(handle);
+ if (no == null) return null;
+ if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType);
+ return line;
+ }
+
+ // Helper for deleting text near the selection(s), used to implement
+ // backspace, delete, and similar functionality.
+ function deleteNearSelection(cm, compute) {
+ var ranges = cm.doc.sel.ranges, kill = [];
+ // Build up a set of ranges to kill first, merging overlapping
+ // ranges.
+ for (var i = 0; i < ranges.length; i++) {
+ var toKill = compute(ranges[i]);
+ while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
+ var replaced = kill.pop();
+ if (cmp(replaced.from, toKill.from) < 0) {
+ toKill.from = replaced.from;
+ break;
+ }
+ }
+ kill.push(toKill);
+ }
+ // Next, remove those actual ranges.
+ runInOp(cm, function() {
+ for (var i = kill.length - 1; i >= 0; i--)
+ replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete");
+ ensureCursorVisible(cm);
+ });
+ }
+
+ // Used for horizontal relative motion. Dir is -1 or 1 (left or
+ // right), unit can be "char", "column" (like char, but doesn't
+ // cross line boundaries), "word" (across next word), or "group" (to
+ // the start of next group of word or non-word-non-whitespace
+ // chars). The visually param controls whether, in right-to-left
+ // text, direction 1 means to move towards the next index in the
+ // string, or towards the character to the right of the current
+ // position. The resulting position will have a hitSide=true
+ // property if it reached the end of the document.
+ function findPosH(doc, pos, dir, unit, visually) {
+ var line = pos.line, ch = pos.ch, origDir = dir;
+ var lineObj = getLine(doc, line);
+ var possible = true;
+ function findNextLine() {
+ var l = line + dir;
+ if (l < doc.first || l >= doc.first + doc.size) return (possible = false);
+ line = l;
+ return lineObj = getLine(doc, l);
+ }
+ function moveOnce(boundToLine) {
+ var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true);
+ if (next == null) {
+ if (!boundToLine && findNextLine()) {
+ if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);
+ else ch = dir < 0 ? lineObj.text.length : 0;
+ } else return (possible = false);
+ } else ch = next;
+ return true;
+ }
+
+ if (unit == "char") moveOnce();
+ else if (unit == "column") moveOnce(true);
+ else if (unit == "word" || unit == "group") {
+ var sawType = null, group = unit == "group";
+ var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
+ for (var first = true;; first = false) {
+ if (dir < 0 && !moveOnce(!first)) break;
+ var cur = lineObj.text.charAt(ch) || "\n";
+ var type = isWordChar(cur, helper) ? "w"
+ : group && cur == "\n" ? "n"
+ : !group || /\s/.test(cur) ? null
+ : "p";
+ if (group && !first && !type) type = "s";
+ if (sawType && sawType != type) {
+ if (dir < 0) {dir = 1; moveOnce();}
+ break;
+ }
+
+ if (type) sawType = type;
+ if (dir > 0 && !moveOnce(!first)) break;
+ }
+ }
+ var result = skipAtomic(doc, Pos(line, ch), origDir, true);
+ if (!possible) result.hitSide = true;
+ return result;
+ }
+
+ // For relative vertical movement. Dir may be -1 or 1. Unit can be
+ // "page" or "line". The resulting position will have a hitSide=true
+ // property if it reached the end of the document.
+ function findPosV(cm, pos, dir, unit) {
+ var doc = cm.doc, x = pos.left, y;
+ if (unit == "page") {
+ var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
+ y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display));
+ } else if (unit == "line") {
+ y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
+ }
+ for (;;) {
+ var target = coordsChar(cm, x, y);
+ if (!target.outside) break;
+ if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; }
+ y += dir * 5;
+ }
+ return target;
+ }
+
+ // EDITOR METHODS
+
+ // The publicly visible API. Note that methodOp(f) means
+ // 'wrap f in an operation, performed on its `this` parameter'.
+
+ // This is not the complete set of editor methods. Most of the
+ // methods defined on the Doc type are also injected into
+ // CodeMirror.prototype, for backwards compatibility and
+ // convenience.
+
+ CodeMirror.prototype = {
+ constructor: CodeMirror,
+ focus: function(){window.focus(); this.display.input.focus();},
+
+ setOption: function(option, value) {
+ var options = this.options, old = options[option];
+ if (options[option] == value && option != "mode") return;
+ options[option] = value;
+ if (optionHandlers.hasOwnProperty(option))
+ operation(this, optionHandlers[option])(this, value, old);
+ },
+
+ getOption: function(option) {return this.options[option];},
+ getDoc: function() {return this.doc;},
+
+ addKeyMap: function(map, bottom) {
+ this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map));
+ },
+ removeKeyMap: function(map) {
+ var maps = this.state.keyMaps;
+ for (var i = 0; i < maps.length; ++i)
+ if (maps[i] == map || maps[i].name == map) {
+ maps.splice(i, 1);
+ return true;
+ }
+ },
+
+ addOverlay: methodOp(function(spec, options) {
+ var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
+ if (mode.startState) throw new Error("Overlays may not be stateful.");
+ this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque});
+ this.state.modeGen++;
+ regChange(this);
+ }),
+ removeOverlay: methodOp(function(spec) {
+ var overlays = this.state.overlays;
+ for (var i = 0; i < overlays.length; ++i) {
+ var cur = overlays[i].modeSpec;
+ if (cur == spec || typeof spec == "string" && cur.name == spec) {
+ overlays.splice(i, 1);
+ this.state.modeGen++;
+ regChange(this);
+ return;
+ }
+ }
+ }),
+
+ indentLine: methodOp(function(n, dir, aggressive) {
+ if (typeof dir != "string" && typeof dir != "number") {
+ if (dir == null) dir = this.options.smartIndent ? "smart" : "prev";
+ else dir = dir ? "add" : "subtract";
+ }
+ if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive);
+ }),
+ indentSelection: methodOp(function(how) {
+ var ranges = this.doc.sel.ranges, end = -1;
+ for (var i = 0; i < ranges.length; i++) {
+ var range = ranges[i];
+ if (!range.empty()) {
+ var from = range.from(), to = range.to();
+ var start = Math.max(end, from.line);
+ end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
+ for (var j = start; j < end; ++j)
+ indentLine(this, j, how);
+ var newRanges = this.doc.sel.ranges;
+ if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
+ replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll);
+ } else if (range.head.line > end) {
+ indentLine(this, range.head.line, how, true);
+ end = range.head.line;
+ if (i == this.doc.sel.primIndex) ensureCursorVisible(this);
+ }
+ }
+ }),
+
+ // Fetch the parser token for a given character. Useful for hacks
+ // that want to inspect the mode state (say, for completion).
+ getTokenAt: function(pos, precise) {
+ return takeToken(this, pos, precise);
+ },
+
+ getLineTokens: function(line, precise) {
+ return takeToken(this, Pos(line), precise, true);
+ },
+
+ getTokenTypeAt: function(pos) {
+ pos = clipPos(this.doc, pos);
+ var styles = getLineStyles(this, getLine(this.doc, pos.line));
+ var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
+ var type;
+ if (ch == 0) type = styles[2];
+ else for (;;) {
+ var mid = (before + after) >> 1;
+ if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid;
+ else if (styles[mid * 2 + 1] < ch) before = mid + 1;
+ else { type = styles[mid * 2 + 2]; break; }
+ }
+ var cut = type ? type.indexOf("cm-overlay ") : -1;
+ return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1);
+ },
+
+ getModeAt: function(pos) {
+ var mode = this.doc.mode;
+ if (!mode.innerMode) return mode;
+ return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode;
+ },
+
+ getHelper: function(pos, type) {
+ return this.getHelpers(pos, type)[0];
+ },
+
+ getHelpers: function(pos, type) {
+ var found = [];
+ if (!helpers.hasOwnProperty(type)) return found;
+ var help = helpers[type], mode = this.getModeAt(pos);
+ if (typeof mode[type] == "string") {
+ if (help[mode[type]]) found.push(help[mode[type]]);
+ } else if (mode[type]) {
+ for (var i = 0; i < mode[type].length; i++) {
+ var val = help[mode[type][i]];
+ if (val) found.push(val);
+ }
+ } else if (mode.helperType && help[mode.helperType]) {
+ found.push(help[mode.helperType]);
+ } else if (help[mode.name]) {
+ found.push(help[mode.name]);
+ }
+ for (var i = 0; i < help._global.length; i++) {
+ var cur = help._global[i];
+ if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)
+ found.push(cur.val);
+ }
+ return found;
+ },
+
+ getStateAfter: function(line, precise) {
+ var doc = this.doc;
+ line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
+ return getStateBefore(this, line + 1, precise);
+ },
+
+ cursorCoords: function(start, mode) {
+ var pos, range = this.doc.sel.primary();
+ if (start == null) pos = range.head;
+ else if (typeof start == "object") pos = clipPos(this.doc, start);
+ else pos = start ? range.from() : range.to();
+ return cursorCoords(this, pos, mode || "page");
+ },
+
+ charCoords: function(pos, mode) {
+ return charCoords(this, clipPos(this.doc, pos), mode || "page");
+ },
+
+ coordsChar: function(coords, mode) {
+ coords = fromCoordSystem(this, coords, mode || "page");
+ return coordsChar(this, coords.left, coords.top);
+ },
+
+ lineAtHeight: function(height, mode) {
+ height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
+ return lineAtHeight(this.doc, height + this.display.viewOffset);
+ },
+ heightAtLine: function(line, mode) {
+ var end = false, lineObj;
+ if (typeof line == "number") {
+ var last = this.doc.first + this.doc.size - 1;
+ if (line < this.doc.first) line = this.doc.first;
+ else if (line > last) { line = last; end = true; }
+ lineObj = getLine(this.doc, line);
+ } else {
+ lineObj = line;
+ }
+ return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top +
+ (end ? this.doc.height - heightAtLine(lineObj) : 0);
+ },
+
+ defaultTextHeight: function() { return textHeight(this.display); },
+ defaultCharWidth: function() { return charWidth(this.display); },
+
+ setGutterMarker: methodOp(function(line, gutterID, value) {
+ return changeLine(this.doc, line, "gutter", function(line) {
+ var markers = line.gutterMarkers || (line.gutterMarkers = {});
+ markers[gutterID] = value;
+ if (!value && isEmpty(markers)) line.gutterMarkers = null;
+ return true;
+ });
+ }),
+
+ clearGutter: methodOp(function(gutterID) {
+ var cm = this, doc = cm.doc, i = doc.first;
+ doc.iter(function(line) {
+ if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
+ line.gutterMarkers[gutterID] = null;
+ regLineChange(cm, i, "gutter");
+ if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null;
+ }
+ ++i;
+ });
+ }),
+
+ lineInfo: function(line) {
+ if (typeof line == "number") {
+ if (!isLine(this.doc, line)) return null;
+ var n = line;
+ line = getLine(this.doc, line);
+ if (!line) return null;
+ } else {
+ var n = lineNo(line);
+ if (n == null) return null;
+ }
+ return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
+ textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
+ widgets: line.widgets};
+ },
+
+ getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};},
+
+ addWidget: function(pos, node, scroll, vert, horiz) {
+ var display = this.display;
+ pos = cursorCoords(this, clipPos(this.doc, pos));
+ var top = pos.bottom, left = pos.left;
+ node.style.position = "absolute";
+ node.setAttribute("cm-ignore-events", "true");
+ this.display.input.setUneditable(node);
+ display.sizer.appendChild(node);
+ if (vert == "over") {
+ top = pos.top;
+ } else if (vert == "above" || vert == "near") {
+ var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
+ hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
+ // Default to positioning above (if specified and possible); otherwise default to positioning below
+ if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
+ top = pos.top - node.offsetHeight;
+ else if (pos.bottom + node.offsetHeight <= vspace)
+ top = pos.bottom;
+ if (left + node.offsetWidth > hspace)
+ left = hspace - node.offsetWidth;
+ }
+ node.style.top = top + "px";
+ node.style.left = node.style.right = "";
+ if (horiz == "right") {
+ left = display.sizer.clientWidth - node.offsetWidth;
+ node.style.right = "0px";
+ } else {
+ if (horiz == "left") left = 0;
+ else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2;
+ node.style.left = left + "px";
+ }
+ if (scroll)
+ scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight);
+ },
+
+ triggerOnKeyDown: methodOp(onKeyDown),
+ triggerOnKeyPress: methodOp(onKeyPress),
+ triggerOnKeyUp: onKeyUp,
+
+ execCommand: function(cmd) {
+ if (commands.hasOwnProperty(cmd))
+ return commands[cmd](this);
+ },
+
+ findPosH: function(from, amount, unit, visually) {
+ var dir = 1;
+ if (amount < 0) { dir = -1; amount = -amount; }
+ for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
+ cur = findPosH(this.doc, cur, dir, unit, visually);
+ if (cur.hitSide) break;
+ }
+ return cur;
+ },
+
+ moveH: methodOp(function(dir, unit) {
+ var cm = this;
+ cm.extendSelectionsBy(function(range) {
+ if (cm.display.shift || cm.doc.extend || range.empty())
+ return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually);
+ else
+ return dir < 0 ? range.from() : range.to();
+ }, sel_move);
+ }),
+
+ deleteH: methodOp(function(dir, unit) {
+ var sel = this.doc.sel, doc = this.doc;
+ if (sel.somethingSelected())
+ doc.replaceSelection("", null, "+delete");
+ else
+ deleteNearSelection(this, function(range) {
+ var other = findPosH(doc, range.head, dir, unit, false);
+ return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other};
+ });
+ }),
+
+ findPosV: function(from, amount, unit, goalColumn) {
+ var dir = 1, x = goalColumn;
+ if (amount < 0) { dir = -1; amount = -amount; }
+ for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
+ var coords = cursorCoords(this, cur, "div");
+ if (x == null) x = coords.left;
+ else coords.left = x;
+ cur = findPosV(this, coords, dir, unit);
+ if (cur.hitSide) break;
+ }
+ return cur;
+ },
+
+ moveV: methodOp(function(dir, unit) {
+ var cm = this, doc = this.doc, goals = [];
+ var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected();
+ doc.extendSelectionsBy(function(range) {
+ if (collapse)
+ return dir < 0 ? range.from() : range.to();
+ var headPos = cursorCoords(cm, range.head, "div");
+ if (range.goalColumn != null) headPos.left = range.goalColumn;
+ goals.push(headPos.left);
+ var pos = findPosV(cm, headPos, dir, unit);
+ if (unit == "page" && range == doc.sel.primary())
+ addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top);
+ return pos;
+ }, sel_move);
+ if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++)
+ doc.sel.ranges[i].goalColumn = goals[i];
+ }),
+
+ // Find the word at the given position (as returned by coordsChar).
+ findWordAt: function(pos) {
+ var doc = this.doc, line = getLine(doc, pos.line).text;
+ var start = pos.ch, end = pos.ch;
+ if (line) {
+ var helper = this.getHelper(pos, "wordChars");
+ if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end;
+ var startChar = line.charAt(start);
+ var check = isWordChar(startChar, helper)
+ ? function(ch) { return isWordChar(ch, helper); }
+ : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);}
+ : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);};
+ while (start > 0 && check(line.charAt(start - 1))) --start;
+ while (end < line.length && check(line.charAt(end))) ++end;
+ }
+ return new Range(Pos(pos.line, start), Pos(pos.line, end));
+ },
+
+ toggleOverwrite: function(value) {
+ if (value != null && value == this.state.overwrite) return;
+ if (this.state.overwrite = !this.state.overwrite)
+ addClass(this.display.cursorDiv, "CodeMirror-overwrite");
+ else
+ rmClass(this.display.cursorDiv, "CodeMirror-overwrite");
+
+ signal(this, "overwriteToggle", this, this.state.overwrite);
+ },
+ hasFocus: function() { return this.display.input.getField() == activeElt(); },
+
+ scrollTo: methodOp(function(x, y) {
+ if (x != null || y != null) resolveScrollToPos(this);
+ if (x != null) this.curOp.scrollLeft = x;
+ if (y != null) this.curOp.scrollTop = y;
+ }),
+ getScrollInfo: function() {
+ var scroller = this.display.scroller;
+ return {left: scroller.scrollLeft, top: scroller.scrollTop,
+ height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
+ width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
+ clientHeight: displayHeight(this), clientWidth: displayWidth(this)};
+ },
+
+ scrollIntoView: methodOp(function(range, margin) {
+ if (range == null) {
+ range = {from: this.doc.sel.primary().head, to: null};
+ if (margin == null) margin = this.options.cursorScrollMargin;
+ } else if (typeof range == "number") {
+ range = {from: Pos(range, 0), to: null};
+ } else if (range.from == null) {
+ range = {from: range, to: null};
+ }
+ if (!range.to) range.to = range.from;
+ range.margin = margin || 0;
+
+ if (range.from.line != null) {
+ resolveScrollToPos(this);
+ this.curOp.scrollToPos = range;
+ } else {
+ var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left),
+ Math.min(range.from.top, range.to.top) - range.margin,
+ Math.max(range.from.right, range.to.right),
+ Math.max(range.from.bottom, range.to.bottom) + range.margin);
+ this.scrollTo(sPos.scrollLeft, sPos.scrollTop);
+ }
+ }),
+
+ setSize: methodOp(function(width, height) {
+ var cm = this;
+ function interpret(val) {
+ return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val;
+ }
+ if (width != null) cm.display.wrapper.style.width = interpret(width);
+ if (height != null) cm.display.wrapper.style.height = interpret(height);
+ if (cm.options.lineWrapping) clearLineMeasurementCache(this);
+ var lineNo = cm.display.viewFrom;
+ cm.doc.iter(lineNo, cm.display.viewTo, function(line) {
+ if (line.widgets) for (var i = 0; i < line.widgets.length; i++)
+ if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; }
+ ++lineNo;
+ });
+ cm.curOp.forceUpdate = true;
+ signal(cm, "refresh", this);
+ }),
+
+ operation: function(f){return runInOp(this, f);},
+
+ refresh: methodOp(function() {
+ var oldHeight = this.display.cachedTextHeight;
+ regChange(this);
+ this.curOp.forceUpdate = true;
+ clearCaches(this);
+ this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop);
+ updateGutterSpace(this);
+ if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
+ estimateLineHeights(this);
+ signal(this, "refresh", this);
+ }),
+
+ swapDoc: methodOp(function(doc) {
+ var old = this.doc;
+ old.cm = null;
+ attachDoc(this, doc);
+ clearCaches(this);
+ this.display.input.reset();
+ this.scrollTo(doc.scrollLeft, doc.scrollTop);
+ this.curOp.forceScroll = true;
+ signalLater(this, "swapDoc", this, old);
+ return old;
+ }),
+
+ getInputField: function(){return this.display.input.getField();},
+ getWrapperElement: function(){return this.display.wrapper;},
+ getScrollerElement: function(){return this.display.scroller;},
+ getGutterElement: function(){return this.display.gutters;}
+ };
+ eventMixin(CodeMirror);
+
+ // OPTION DEFAULTS
+
+ // The default configuration options.
+ var defaults = CodeMirror.defaults = {};
+ // Functions to run when options are changed.
+ var optionHandlers = CodeMirror.optionHandlers = {};
+
+ function option(name, deflt, handle, notOnInit) {
+ CodeMirror.defaults[name] = deflt;
+ if (handle) optionHandlers[name] =
+ notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle;
+ }
+
+ // Passed to option handlers when there is no old value.
+ var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}};
+
+ // These two are, on init, called from the constructor because they
+ // have to be initialized before the editor can start at all.
+ option("value", "", function(cm, val) {
+ cm.setValue(val);
+ }, true);
+ option("mode", null, function(cm, val) {
+ cm.doc.modeOption = val;
+ loadMode(cm);
+ }, true);
+
+ option("indentUnit", 2, loadMode, true);
+ option("indentWithTabs", false);
+ option("smartIndent", true);
+ option("tabSize", 4, function(cm) {
+ resetModeState(cm);
+ clearCaches(cm);
+ regChange(cm);
+ }, true);
+ option("specialChars", /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val, old) {
+ cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
+ if (old != CodeMirror.Init) cm.refresh();
+ });
+ option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true);
+ option("electricChars", true);
+ option("inputStyle", mobile ? "contenteditable" : "textarea", function() {
+ throw new Error("inputStyle can not (yet) be changed in a running editor"); // FIXME
+ }, true);
+ option("rtlMoveVisually", !windows);
+ option("wholeLineUpdateBefore", true);
+
+ option("theme", "default", function(cm) {
+ themeChanged(cm);
+ guttersChanged(cm);
+ }, true);
+ option("keyMap", "default", function(cm, val, old) {
+ var next = getKeyMap(val);
+ var prev = old != CodeMirror.Init && getKeyMap(old);
+ if (prev && prev.detach) prev.detach(cm, next);
+ if (next.attach) next.attach(cm, prev || null);
+ });
+ option("extraKeys", null);
+
+ option("lineWrapping", false, wrappingChanged, true);
+ option("gutters", [], function(cm) {
+ setGuttersForLineNumbers(cm.options);
+ guttersChanged(cm);
+ }, true);
+ option("fixedGutter", true, function(cm, val) {
+ cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
+ cm.refresh();
+ }, true);
+ option("coverGutterNextToScrollbar", false, function(cm) {updateScrollbars(cm);}, true);
+ option("scrollbarStyle", "native", function(cm) {
+ initScrollbars(cm);
+ updateScrollbars(cm);
+ cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
+ cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
+ }, true);
+ option("lineNumbers", false, function(cm) {
+ setGuttersForLineNumbers(cm.options);
+ guttersChanged(cm);
+ }, true);
+ option("firstLineNumber", 1, guttersChanged, true);
+ option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true);
+ option("showCursorWhenSelecting", false, updateSelection, true);
+
+ option("resetSelectionOnContextMenu", true);
+ option("lineWiseCopyCut", true);
+
+ option("readOnly", false, function(cm, val) {
+ if (val == "nocursor") {
+ onBlur(cm);
+ cm.display.input.blur();
+ cm.display.disabled = true;
+ } else {
+ cm.display.disabled = false;
+ if (!val) cm.display.input.reset();
+ }
+ });
+ option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true);
+ option("dragDrop", true, dragDropChanged);
+
+ option("cursorBlinkRate", 530);
+ option("cursorScrollMargin", 0);
+ option("cursorHeight", 1, updateSelection, true);
+ option("singleCursorHeightPerLine", true, updateSelection, true);
+ option("workTime", 100);
+ option("workDelay", 100);
+ option("flattenSpans", true, resetModeState, true);
+ option("addModeClass", false, resetModeState, true);
+ option("pollInterval", 100);
+ option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;});
+ option("historyEventDelay", 1250);
+ option("viewportMargin", 10, function(cm){cm.refresh();}, true);
+ option("maxHighlightLength", 10000, resetModeState, true);
+ option("moveInputWithCursor", true, function(cm, val) {
+ if (!val) cm.display.input.resetPosition();
+ });
+
+ option("tabindex", null, function(cm, val) {
+ cm.display.input.getField().tabIndex = val || "";
+ });
+ option("autofocus", null);
+
+ // MODE DEFINITION AND QUERYING
+
+ // Known modes, by name and by MIME
+ var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
+
+ // Extra arguments are stored as the mode's dependencies, which is
+ // used by (legacy) mechanisms like loadmode.js to automatically
+ // load a mode. (Preferred mechanism is the require/define calls.)
+ CodeMirror.defineMode = function(name, mode) {
+ if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
+ if (arguments.length > 2)
+ mode.dependencies = Array.prototype.slice.call(arguments, 2);
+ modes[name] = mode;
+ };
+
+ CodeMirror.defineMIME = function(mime, spec) {
+ mimeModes[mime] = spec;
+ };
+
+ // Given a MIME type, a {name, ...options} config object, or a name
+ // string, return a mode config object.
+ CodeMirror.resolveMode = function(spec) {
+ if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
+ spec = mimeModes[spec];
+ } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
+ var found = mimeModes[spec.name];
+ if (typeof found == "string") found = {name: found};
+ spec = createObj(found, spec);
+ spec.name = found.name;
+ } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
+ return CodeMirror.resolveMode("application/xml");
+ }
+ if (typeof spec == "string") return {name: spec};
+ else return spec || {name: "null"};
+ };
+
+ // Given a mode spec (anything that resolveMode accepts), find and
+ // initialize an actual mode object.
+ CodeMirror.getMode = function(options, spec) {
+ var spec = CodeMirror.resolveMode(spec);
+ var mfactory = modes[spec.name];
+ if (!mfactory) return CodeMirror.getMode(options, "text/plain");
+ var modeObj = mfactory(options, spec);
+ if (modeExtensions.hasOwnProperty(spec.name)) {
+ var exts = modeExtensions[spec.name];
+ for (var prop in exts) {
+ if (!exts.hasOwnProperty(prop)) continue;
+ if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop];
+ modeObj[prop] = exts[prop];
+ }
+ }
+ modeObj.name = spec.name;
+ if (spec.helperType) modeObj.helperType = spec.helperType;
+ if (spec.modeProps) for (var prop in spec.modeProps)
+ modeObj[prop] = spec.modeProps[prop];
+
+ return modeObj;
+ };
+
+ // Minimal default mode.
+ CodeMirror.defineMode("null", function() {
+ return {token: function(stream) {stream.skipToEnd();}};
+ });
+ CodeMirror.defineMIME("text/plain", "null");
+
+ // This can be used to attach properties to mode objects from
+ // outside the actual mode definition.
+ var modeExtensions = CodeMirror.modeExtensions = {};
+ CodeMirror.extendMode = function(mode, properties) {
+ var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
+ copyObj(properties, exts);
+ };
+
+ // EXTENSIONS
+
+ CodeMirror.defineExtension = function(name, func) {
+ CodeMirror.prototype[name] = func;
+ };
+ CodeMirror.defineDocExtension = function(name, func) {
+ Doc.prototype[name] = func;
+ };
+ CodeMirror.defineOption = option;
+
+ var initHooks = [];
+ CodeMirror.defineInitHook = function(f) {initHooks.push(f);};
+
+ var helpers = CodeMirror.helpers = {};
+ CodeMirror.registerHelper = function(type, name, value) {
+ if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []};
+ helpers[type][name] = value;
+ };
+ CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
+ CodeMirror.registerHelper(type, name, value);
+ helpers[type]._global.push({pred: predicate, val: value});
+ };
+
+ // MODE STATE HANDLING
+
+ // Utility functions for working with state. Exported because nested
+ // modes need to do this for their inner modes.
+
+ var copyState = CodeMirror.copyState = function(mode, state) {
+ if (state === true) return state;
+ if (mode.copyState) return mode.copyState(state);
+ var nstate = {};
+ for (var n in state) {
+ var val = state[n];
+ if (val instanceof Array) val = val.concat([]);
+ nstate[n] = val;
+ }
+ return nstate;
+ };
+
+ var startState = CodeMirror.startState = function(mode, a1, a2) {
+ return mode.startState ? mode.startState(a1, a2) : true;
+ };
+
+ // Given a mode and a state (for that mode), find the inner mode and
+ // state at the position that the state refers to.
+ CodeMirror.innerMode = function(mode, state) {
+ while (mode.innerMode) {
+ var info = mode.innerMode(state);
+ if (!info || info.mode == mode) break;
+ state = info.state;
+ mode = info.mode;
+ }
+ return info || {mode: mode, state: state};
+ };
+
+ // STANDARD COMMANDS
+
+ // Commands are parameter-less actions that can be performed on an
+ // editor, mostly used for keybindings.
+ var commands = CodeMirror.commands = {
+ selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);},
+ singleSelection: function(cm) {
+ cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll);
+ },
+ killLine: function(cm) {
+ deleteNearSelection(cm, function(range) {
+ if (range.empty()) {
+ var len = getLine(cm.doc, range.head.line).text.length;
+ if (range.head.ch == len && range.head.line < cm.lastLine())
+ return {from: range.head, to: Pos(range.head.line + 1, 0)};
+ else
+ return {from: range.head, to: Pos(range.head.line, len)};
+ } else {
+ return {from: range.from(), to: range.to()};
+ }
+ });
+ },
+ deleteLine: function(cm) {
+ deleteNearSelection(cm, function(range) {
+ return {from: Pos(range.from().line, 0),
+ to: clipPos(cm.doc, Pos(range.to().line + 1, 0))};
+ });
+ },
+ delLineLeft: function(cm) {
+ deleteNearSelection(cm, function(range) {
+ return {from: Pos(range.from().line, 0), to: range.from()};
+ });
+ },
+ delWrappedLineLeft: function(cm) {
+ deleteNearSelection(cm, function(range) {
+ var top = cm.charCoords(range.head, "div").top + 5;
+ var leftPos = cm.coordsChar({left: 0, top: top}, "div");
+ return {from: leftPos, to: range.from()};
+ });
+ },
+ delWrappedLineRight: function(cm) {
+ deleteNearSelection(cm, function(range) {
+ var top = cm.charCoords(range.head, "div").top + 5;
+ var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
+ return {from: range.from(), to: rightPos };
+ });
+ },
+ undo: function(cm) {cm.undo();},
+ redo: function(cm) {cm.redo();},
+ undoSelection: function(cm) {cm.undoSelection();},
+ redoSelection: function(cm) {cm.redoSelection();},
+ goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));},
+ goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));},
+ goLineStart: function(cm) {
+ cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); },
+ {origin: "+move", bias: 1});
+ },
+ goLineStartSmart: function(cm) {
+ cm.extendSelectionsBy(function(range) {
+ return lineStartSmart(cm, range.head);
+ }, {origin: "+move", bias: 1});
+ },
+ goLineEnd: function(cm) {
+ cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); },
+ {origin: "+move", bias: -1});
+ },
+ goLineRight: function(cm) {
+ cm.extendSelectionsBy(function(range) {
+ var top = cm.charCoords(range.head, "div").top + 5;
+ return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
+ }, sel_move);
+ },
+ goLineLeft: function(cm) {
+ cm.extendSelectionsBy(function(range) {
+ var top = cm.charCoords(range.head, "div").top + 5;
+ return cm.coordsChar({left: 0, top: top}, "div");
+ }, sel_move);
+ },
+ goLineLeftSmart: function(cm) {
+ cm.extendSelectionsBy(function(range) {
+ var top = cm.charCoords(range.head, "div").top + 5;
+ var pos = cm.coordsChar({left: 0, top: top}, "div");
+ if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head);
+ return pos;
+ }, sel_move);
+ },
+ goLineUp: function(cm) {cm.moveV(-1, "line");},
+ goLineDown: function(cm) {cm.moveV(1, "line");},
+ goPageUp: function(cm) {cm.moveV(-1, "page");},
+ goPageDown: function(cm) {cm.moveV(1, "page");},
+ goCharLeft: function(cm) {cm.moveH(-1, "char");},
+ goCharRight: function(cm) {cm.moveH(1, "char");},
+ goColumnLeft: function(cm) {cm.moveH(-1, "column");},
+ goColumnRight: function(cm) {cm.moveH(1, "column");},
+ goWordLeft: function(cm) {cm.moveH(-1, "word");},
+ goGroupRight: function(cm) {cm.moveH(1, "group");},
+ goGroupLeft: function(cm) {cm.moveH(-1, "group");},
+ goWordRight: function(cm) {cm.moveH(1, "word");},
+ delCharBefore: function(cm) {cm.deleteH(-1, "char");},
+ delCharAfter: function(cm) {cm.deleteH(1, "char");},
+ delWordBefore: function(cm) {cm.deleteH(-1, "word");},
+ delWordAfter: function(cm) {cm.deleteH(1, "word");},
+ delGroupBefore: function(cm) {cm.deleteH(-1, "group");},
+ delGroupAfter: function(cm) {cm.deleteH(1, "group");},
+ indentAuto: function(cm) {cm.indentSelection("smart");},
+ indentMore: function(cm) {cm.indentSelection("add");},
+ indentLess: function(cm) {cm.indentSelection("subtract");},
+ insertTab: function(cm) {cm.replaceSelection("\t");},
+ insertSoftTab: function(cm) {
+ var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;
+ for (var i = 0; i < ranges.length; i++) {
+ var pos = ranges[i].from();
+ var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);
+ spaces.push(new Array(tabSize - col % tabSize + 1).join(" "));
+ }
+ cm.replaceSelections(spaces);
+ },
+ defaultTab: function(cm) {
+ if (cm.somethingSelected()) cm.indentSelection("add");
+ else cm.execCommand("insertTab");
+ },
+ transposeChars: function(cm) {
+ runInOp(cm, function() {
+ var ranges = cm.listSelections(), newSel = [];
+ for (var i = 0; i < ranges.length; i++) {
+ var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
+ if (line) {
+ if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1);
+ if (cur.ch > 0) {
+ cur = new Pos(cur.line, cur.ch + 1);
+ cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
+ Pos(cur.line, cur.ch - 2), cur, "+transpose");
+ } else if (cur.line > cm.doc.first) {
+ var prev = getLine(cm.doc, cur.line - 1).text;
+ if (prev)
+ cm.replaceRange(line.charAt(0) + "\n" + prev.charAt(prev.length - 1),
+ Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose");
+ }
+ }
+ newSel.push(new Range(cur, cur));
+ }
+ cm.setSelections(newSel);
+ });
+ },
+ newlineAndIndent: function(cm) {
+ runInOp(cm, function() {
+ var len = cm.listSelections().length;
+ for (var i = 0; i < len; i++) {
+ var range = cm.listSelections()[i];
+ cm.replaceRange("\n", range.anchor, range.head, "+input");
+ cm.indentLine(range.from().line + 1, null, true);
+ ensureCursorVisible(cm);
+ }
+ });
+ },
+ toggleOverwrite: function(cm) {cm.toggleOverwrite();}
+ };
+
+
+ // STANDARD KEYMAPS
+
+ var keyMap = CodeMirror.keyMap = {};
+
+ keyMap.basic = {
+ "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
+ "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
+ "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
+ "Tab": "defaultTab", "Shift-Tab": "indentAuto",
+ "Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
+ "Esc": "singleSelection"
+ };
+ // Note that the save and find-related commands aren't defined by
+ // default. User code or addons can define them. Unknown commands
+ // are simply ignored.
+ keyMap.pcDefault = {
+ "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
+ "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
+ "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
+ "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
+ "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
+ "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
+ "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
+ fallthrough: "basic"
+ };
+ // Very basic readline/emacs-style bindings, which are standard on Mac.
+ keyMap.emacsy = {
+ "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
+ "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
+ "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
+ "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
+ };
+ keyMap.macDefault = {
+ "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
+ "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
+ "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
+ "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
+ "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
+ "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
+ "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
+ fallthrough: ["basic", "emacsy"]
+ };
+ keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
+
+ // KEYMAP DISPATCH
+
+ function normalizeKeyName(name) {
+ var parts = name.split(/-(?!$)/), name = parts[parts.length - 1];
+ var alt, ctrl, shift, cmd;
+ for (var i = 0; i < parts.length - 1; i++) {
+ var mod = parts[i];
+ if (/^(cmd|meta|m)$/i.test(mod)) cmd = true;
+ else if (/^a(lt)?$/i.test(mod)) alt = true;
+ else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true;
+ else if (/^s(hift)$/i.test(mod)) shift = true;
+ else throw new Error("Unrecognized modifier name: " + mod);
+ }
+ if (alt) name = "Alt-" + name;
+ if (ctrl) name = "Ctrl-" + name;
+ if (cmd) name = "Cmd-" + name;
+ if (shift) name = "Shift-" + name;
+ return name;
+ }
+
+ // This is a kludge to keep keymaps mostly working as raw objects
+ // (backwards compatibility) while at the same time support features
+ // like normalization and multi-stroke key bindings. It compiles a
+ // new normalized keymap, and then updates the old object to reflect
+ // this.
+ CodeMirror.normalizeKeyMap = function(keymap) {
+ var copy = {};
+ for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) {
+ var value = keymap[keyname];
+ if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue;
+ if (value == "...") { delete keymap[keyname]; continue; }
+
+ var keys = map(keyname.split(" "), normalizeKeyName);
+ for (var i = 0; i < keys.length; i++) {
+ var val, name;
+ if (i == keys.length - 1) {
+ name = keyname;
+ val = value;
+ } else {
+ name = keys.slice(0, i + 1).join(" ");
+ val = "...";
+ }
+ var prev = copy[name];
+ if (!prev) copy[name] = val;
+ else if (prev != val) throw new Error("Inconsistent bindings for " + name);
+ }
+ delete keymap[keyname];
+ }
+ for (var prop in copy) keymap[prop] = copy[prop];
+ return keymap;
+ };
+
+ var lookupKey = CodeMirror.lookupKey = function(key, map, handle, context) {
+ map = getKeyMap(map);
+ var found = map.call ? map.call(key, context) : map[key];
+ if (found === false) return "nothing";
+ if (found === "...") return "multi";
+ if (found != null && handle(found)) return "handled";
+
+ if (map.fallthrough) {
+ if (Object.prototype.toString.call(map.fallthrough) != "[object Array]")
+ return lookupKey(key, map.fallthrough, handle, context);
+ for (var i = 0; i < map.fallthrough.length; i++) {
+ var result = lookupKey(key, map.fallthrough[i], handle, context);
+ if (result) return result;
+ }
+ }
+ };
+
+ // Modifier key presses don't count as 'real' key presses for the
+ // purpose of keymap fallthrough.
+ var isModifierKey = CodeMirror.isModifierKey = function(value) {
+ var name = typeof value == "string" ? value : keyNames[value.keyCode];
+ return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
+ };
+
+ // Look up the name of a key as indicated by an event object.
+ var keyName = CodeMirror.keyName = function(event, noShift) {
+ if (presto && event.keyCode == 34 && event["char"]) return false;
+ var base = keyNames[event.keyCode], name = base;
+ if (name == null || event.altGraphKey) return false;
+ if (event.altKey && base != "Alt") name = "Alt-" + name;
+ if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name;
+ if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") name = "Cmd-" + name;
+ if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name;
+ return name;
+ };
+
+ function getKeyMap(val) {
+ return typeof val == "string" ? keyMap[val] : val;
+ }
+
+ // FROMTEXTAREA
+
+ CodeMirror.fromTextArea = function(textarea, options) {
+ options = options ? copyObj(options) : {};
+ options.value = textarea.value;
+ if (!options.tabindex && textarea.tabIndex)
+ options.tabindex = textarea.tabIndex;
+ if (!options.placeholder && textarea.placeholder)
+ options.placeholder = textarea.placeholder;
+ // Set autofocus to true if this textarea is focused, or if it has
+ // autofocus and no other element is focused.
+ if (options.autofocus == null) {
+ var hasFocus = activeElt();
+ options.autofocus = hasFocus == textarea ||
+ textarea.getAttribute("autofocus") != null && hasFocus == document.body;
+ }
+
+ function save() {textarea.value = cm.getValue();}
+ if (textarea.form) {
+ on(textarea.form, "submit", save);
+ // Deplorable hack to make the submit method do the right thing.
+ if (!options.leaveSubmitMethodAlone) {
+ var form = textarea.form, realSubmit = form.submit;
+ try {
+ var wrappedSubmit = form.submit = function() {
+ save();
+ form.submit = realSubmit;
+ form.submit();
+ form.submit = wrappedSubmit;
+ };
+ } catch(e) {}
+ }
+ }
+
+ options.finishInit = function(cm) {
+ cm.save = save;
+ cm.getTextArea = function() { return textarea; };
+ cm.toTextArea = function() {
+ cm.toTextArea = isNaN; // Prevent this from being ran twice
+ save();
+ textarea.parentNode.removeChild(cm.getWrapperElement());
+ textarea.style.display = "";
+ if (textarea.form) {
+ off(textarea.form, "submit", save);
+ if (typeof textarea.form.submit == "function")
+ textarea.form.submit = realSubmit;
+ }
+ };
+ };
+
+ textarea.style.display = "none";
+ var cm = CodeMirror(function(node) {
+ textarea.parentNode.insertBefore(node, textarea.nextSibling);
+ }, options);
+ return cm;
+ };
+
+ // STRING STREAM
+
+ // Fed to the mode parsers, provides helper functions to make
+ // parsers more succinct.
+
+ var StringStream = CodeMirror.StringStream = function(string, tabSize) {
+ this.pos = this.start = 0;
+ this.string = string;
+ this.tabSize = tabSize || 8;
+ this.lastColumnPos = this.lastColumnValue = 0;
+ this.lineStart = 0;
+ };
+
+ StringStream.prototype = {
+ eol: function() {return this.pos >= this.string.length;},
+ sol: function() {return this.pos == this.lineStart;},
+ peek: function() {return this.string.charAt(this.pos) || undefined;},
+ next: function() {
+ if (this.pos < this.string.length)
+ return this.string.charAt(this.pos++);
+ },
+ eat: function(match) {
+ var ch = this.string.charAt(this.pos);
+ if (typeof match == "string") var ok = ch == match;
+ else var ok = ch && (match.test ? match.test(ch) : match(ch));
+ if (ok) {++this.pos; return ch;}
+ },
+ eatWhile: function(match) {
+ var start = this.pos;
+ while (this.eat(match)){}
+ return this.pos > start;
+ },
+ eatSpace: function() {
+ var start = this.pos;
+ while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
+ return this.pos > start;
+ },
+ skipToEnd: function() {this.pos = this.string.length;},
+ skipTo: function(ch) {
+ var found = this.string.indexOf(ch, this.pos);
+ if (found > -1) {this.pos = found; return true;}
+ },
+ backUp: function(n) {this.pos -= n;},
+ column: function() {
+ if (this.lastColumnPos < this.start) {
+ this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
+ this.lastColumnPos = this.start;
+ }
+ return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
+ },
+ indentation: function() {
+ return countColumn(this.string, null, this.tabSize) -
+ (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
+ },
+ match: function(pattern, consume, caseInsensitive) {
+ if (typeof pattern == "string") {
+ var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
+ var substr = this.string.substr(this.pos, pattern.length);
+ if (cased(substr) == cased(pattern)) {
+ if (consume !== false) this.pos += pattern.length;
+ return true;
+ }
+ } else {
+ var match = this.string.slice(this.pos).match(pattern);
+ if (match && match.index > 0) return null;
+ if (match && consume !== false) this.pos += match[0].length;
+ return match;
+ }
+ },
+ current: function(){return this.string.slice(this.start, this.pos);},
+ hideFirstChars: function(n, inner) {
+ this.lineStart += n;
+ try { return inner(); }
+ finally { this.lineStart -= n; }
+ }
+ };
+
+ // TEXTMARKERS
+
+ // Created with markText and setBookmark methods. A TextMarker is a
+ // handle that can be used to clear or find a marked position in the
+ // document. Line objects hold arrays (markedSpans) containing
+ // {from, to, marker} object pointing to such marker objects, and
+ // indicating that such a marker is present on that line. Multiple
+ // lines may point to the same marker when it spans across lines.
+ // The spans will have null for their from/to properties when the
+ // marker continues beyond the start/end of the line. Markers have
+ // links back to the lines they currently touch.
+
+ var nextMarkerId = 0;
+
+ var TextMarker = CodeMirror.TextMarker = function(doc, type) {
+ this.lines = [];
+ this.type = type;
+ this.doc = doc;
+ this.id = ++nextMarkerId;
+ };
+ eventMixin(TextMarker);
+
+ // Clear the marker.
+ TextMarker.prototype.clear = function() {
+ if (this.explicitlyCleared) return;
+ var cm = this.doc.cm, withOp = cm && !cm.curOp;
+ if (withOp) startOperation(cm);
+ if (hasHandler(this, "clear")) {
+ var found = this.find();
+ if (found) signalLater(this, "clear", found.from, found.to);
+ }
+ var min = null, max = null;
+ for (var i = 0; i < this.lines.length; ++i) {
+ var line = this.lines[i];
+ var span = getMarkedSpanFor(line.markedSpans, this);
+ if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text");
+ else if (cm) {
+ if (span.to != null) max = lineNo(line);
+ if (span.from != null) min = lineNo(line);
+ }
+ line.markedSpans = removeMarkedSpan(line.markedSpans, span);
+ if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm)
+ updateLineHeight(line, textHeight(cm.display));
+ }
+ if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) {
+ var visual = visualLine(this.lines[i]), len = lineLength(visual);
+ if (len > cm.display.maxLineLength) {
+ cm.display.maxLine = visual;
+ cm.display.maxLineLength = len;
+ cm.display.maxLineChanged = true;
+ }
+ }
+
+ if (min != null && cm && this.collapsed) regChange(cm, min, max + 1);
+ this.lines.length = 0;
+ this.explicitlyCleared = true;
+ if (this.atomic && this.doc.cantEdit) {
+ this.doc.cantEdit = false;
+ if (cm) reCheckSelection(cm.doc);
+ }
+ if (cm) signalLater(cm, "markerCleared", cm, this);
+ if (withOp) endOperation(cm);
+ if (this.parent) this.parent.clear();
+ };
+
+ // Find the position of the marker in the document. Returns a {from,
+ // to} object by default. Side can be passed to get a specific side
+ // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
+ // Pos objects returned contain a line object, rather than a line
+ // number (used to prevent looking up the same line twice).
+ TextMarker.prototype.find = function(side, lineObj) {
+ if (side == null && this.type == "bookmark") side = 1;
+ var from, to;
+ for (var i = 0; i < this.lines.length; ++i) {
+ var line = this.lines[i];
+ var span = getMarkedSpanFor(line.markedSpans, this);
+ if (span.from != null) {
+ from = Pos(lineObj ? line : lineNo(line), span.from);
+ if (side == -1) return from;
+ }
+ if (span.to != null) {
+ to = Pos(lineObj ? line : lineNo(line), span.to);
+ if (side == 1) return to;
+ }
+ }
+ return from && {from: from, to: to};
+ };
+
+ // Signals that the marker's widget changed, and surrounding layout
+ // should be recomputed.
+ TextMarker.prototype.changed = function() {
+ var pos = this.find(-1, true), widget = this, cm = this.doc.cm;
+ if (!pos || !cm) return;
+ runInOp(cm, function() {
+ var line = pos.line, lineN = lineNo(pos.line);
+ var view = findViewForLine(cm, lineN);
+ if (view) {
+ clearLineMeasurementCacheFor(view);
+ cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;
+ }
+ cm.curOp.updateMaxLine = true;
+ if (!lineIsHidden(widget.doc, line) && widget.height != null) {
+ var oldHeight = widget.height;
+ widget.height = null;
+ var dHeight = widgetHeight(widget) - oldHeight;
+ if (dHeight)
+ updateLineHeight(line, line.height + dHeight);
+ }
+ });
+ };
+
+ TextMarker.prototype.attachLine = function(line) {
+ if (!this.lines.length && this.doc.cm) {
+ var op = this.doc.cm.curOp;
+ if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
+ (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this);
+ }
+ this.lines.push(line);
+ };
+ TextMarker.prototype.detachLine = function(line) {
+ this.lines.splice(indexOf(this.lines, line), 1);
+ if (!this.lines.length && this.doc.cm) {
+ var op = this.doc.cm.curOp;
+ (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
+ }
+ };
+
+ // Collapsed markers have unique ids, in order to be able to order
+ // them, which is needed for uniquely determining an outer marker
+ // when they overlap (they may nest, but not partially overlap).
+ var nextMarkerId = 0;
+
+ // Create a marker, wire it up to the right lines, and
+ function markText(doc, from, to, options, type) {
+ // Shared markers (across linked documents) are handled separately
+ // (markTextShared will call out to this again, once per
+ // document).
+ if (options && options.shared) return markTextShared(doc, from, to, options, type);
+ // Ensure we are in an operation.
+ if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type);
+
+ var marker = new TextMarker(doc, type), diff = cmp(from, to);
+ if (options) copyObj(options, marker, false);
+ // Don't connect empty markers unless clearWhenEmpty is false
+ if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
+ return marker;
+ if (marker.replacedWith) {
+ // Showing up as a widget implies collapsed (widget replaces text)
+ marker.collapsed = true;
+ marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget");
+ if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true");
+ if (options.insertLeft) marker.widgetNode.insertLeft = true;
+ }
+ if (marker.collapsed) {
+ if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
+ from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
+ throw new Error("Inserting collapsed marker partially overlapping an existing one");
+ sawCollapsedSpans = true;
+ }
+
+ if (marker.addToHistory)
+ addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN);
+
+ var curLine = from.line, cm = doc.cm, updateMaxLine;
+ doc.iter(curLine, to.line + 1, function(line) {
+ if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
+ updateMaxLine = true;
+ if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0);
+ addMarkedSpan(line, new MarkedSpan(marker,
+ curLine == from.line ? from.ch : null,
+ curLine == to.line ? to.ch : null));
+ ++curLine;
+ });
+ // lineIsHidden depends on the presence of the spans, so needs a second pass
+ if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) {
+ if (lineIsHidden(doc, line)) updateLineHeight(line, 0);
+ });
+
+ if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); });
+
+ if (marker.readOnly) {
+ sawReadOnlySpans = true;
+ if (doc.history.done.length || doc.history.undone.length)
+ doc.clearHistory();
+ }
+ if (marker.collapsed) {
+ marker.id = ++nextMarkerId;
+ marker.atomic = true;
+ }
+ if (cm) {
+ // Sync editor state
+ if (updateMaxLine) cm.curOp.updateMaxLine = true;
+ if (marker.collapsed)
+ regChange(cm, from.line, to.line + 1);
+ else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)
+ for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text");
+ if (marker.atomic) reCheckSelection(cm.doc);
+ signalLater(cm, "markerAdded", cm, marker);
+ }
+ return marker;
+ }
+
+ // SHARED TEXTMARKERS
+
+ // A shared marker spans multiple linked documents. It is
+ // implemented as a meta-marker-object controlling multiple normal
+ // markers.
+ var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) {
+ this.markers = markers;
+ this.primary = primary;
+ for (var i = 0; i < markers.length; ++i)
+ markers[i].parent = this;
+ };
+ eventMixin(SharedTextMarker);
+
+ SharedTextMarker.prototype.clear = function() {
+ if (this.explicitlyCleared) return;
+ this.explicitlyCleared = true;
+ for (var i = 0; i < this.markers.length; ++i)
+ this.markers[i].clear();
+ signalLater(this, "clear");
+ };
+ SharedTextMarker.prototype.find = function(side, lineObj) {
+ return this.primary.find(side, lineObj);
+ };
+
+ function markTextShared(doc, from, to, options, type) {
+ options = copyObj(options);
+ options.shared = false;
+ var markers = [markText(doc, from, to, options, type)], primary = markers[0];
+ var widget = options.widgetNode;
+ linkedDocs(doc, function(doc) {
+ if (widget) options.widgetNode = widget.cloneNode(true);
+ markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
+ for (var i = 0; i < doc.linked.length; ++i)
+ if (doc.linked[i].isParent) return;
+ primary = lst(markers);
+ });
+ return new SharedTextMarker(markers, primary);
+ }
+
+ function findSharedMarkers(doc) {
+ return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())),
+ function(m) { return m.parent; });
+ }
+
+ function copySharedMarkers(doc, markers) {
+ for (var i = 0; i < markers.length; i++) {
+ var marker = markers[i], pos = marker.find();
+ var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
+ if (cmp(mFrom, mTo)) {
+ var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
+ marker.markers.push(subMark);
+ subMark.parent = marker;
+ }
+ }
+ }
+
+ function detachSharedMarkers(markers) {
+ for (var i = 0; i < markers.length; i++) {
+ var marker = markers[i], linked = [marker.primary.doc];;
+ linkedDocs(marker.primary.doc, function(d) { linked.push(d); });
+ for (var j = 0; j < marker.markers.length; j++) {
+ var subMarker = marker.markers[j];
+ if (indexOf(linked, subMarker.doc) == -1) {
+ subMarker.parent = null;
+ marker.markers.splice(j--, 1);
+ }
+ }
+ }
+ }
+
+ // TEXTMARKER SPANS
+
+ function MarkedSpan(marker, from, to) {
+ this.marker = marker;
+ this.from = from; this.to = to;
+ }
+
+ // Search an array of spans for a span matching the given marker.
+ function getMarkedSpanFor(spans, marker) {
+ if (spans) for (var i = 0; i < spans.length; ++i) {
+ var span = spans[i];
+ if (span.marker == marker) return span;
+ }
+ }
+ // Remove a span from an array, returning undefined if no spans are
+ // left (we don't store arrays for lines without spans).
+ function removeMarkedSpan(spans, span) {
+ for (var r, i = 0; i < spans.length; ++i)
+ if (spans[i] != span) (r || (r = [])).push(spans[i]);
+ return r;
+ }
+ // Add a span to a line.
+ function addMarkedSpan(line, span) {
+ line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
+ span.marker.attachLine(line);
+ }
+
+ // Used for the algorithm that adjusts markers for a change in the
+ // document. These functions cut an array of spans at a given
+ // character position, returning an array of remaining chunks (or
+ // undefined if nothing remains).
+ function markedSpansBefore(old, startCh, isInsert) {
+ if (old) for (var i = 0, nw; i < old.length; ++i) {
+ var span = old[i], marker = span.marker;
+ var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
+ if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
+ var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);
+ (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));
+ }
+ }
+ return nw;
+ }
+ function markedSpansAfter(old, endCh, isInsert) {
+ if (old) for (var i = 0, nw; i < old.length; ++i) {
+ var span = old[i], marker = span.marker;
+ var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
+ if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
+ var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);
+ (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
+ span.to == null ? null : span.to - endCh));
+ }
+ }
+ return nw;
+ }
+
+ // Given a change object, compute the new set of marker spans that
+ // cover the line in which the change took place. Removes spans
+ // entirely within the change, reconnects spans belonging to the
+ // same marker that appear on both sides of the change, and cuts off
+ // spans partially within the change. Returns an array of span
+ // arrays with one element for each line in (after) the change.
+ function stretchSpansOverChange(doc, change) {
+ if (change.full) return null;
+ var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
+ var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
+ if (!oldFirst && !oldLast) return null;
+
+ var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
+ // Get the spans that 'stick out' on both sides
+ var first = markedSpansBefore(oldFirst, startCh, isInsert);
+ var last = markedSpansAfter(oldLast, endCh, isInsert);
+
+ // Next, merge those two ends
+ var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
+ if (first) {
+ // Fix up .to properties of first
+ for (var i = 0; i < first.length; ++i) {
+ var span = first[i];
+ if (span.to == null) {
+ var found = getMarkedSpanFor(last, span.marker);
+ if (!found) span.to = startCh;
+ else if (sameLine) span.to = found.to == null ? null : found.to + offset;
+ }
+ }
+ }
+ if (last) {
+ // Fix up .from in last (or move them into first in case of sameLine)
+ for (var i = 0; i < last.length; ++i) {
+ var span = last[i];
+ if (span.to != null) span.to += offset;
+ if (span.from == null) {
+ var found = getMarkedSpanFor(first, span.marker);
+ if (!found) {
+ span.from = offset;
+ if (sameLine) (first || (first = [])).push(span);
+ }
+ } else {
+ span.from += offset;
+ if (sameLine) (first || (first = [])).push(span);
+ }
+ }
+ }
+ // Make sure we didn't create any zero-length spans
+ if (first) first = clearEmptySpans(first);
+ if (last && last != first) last = clearEmptySpans(last);
+
+ var newMarkers = [first];
+ if (!sameLine) {
+ // Fill gap with whole-line-spans
+ var gap = change.text.length - 2, gapMarkers;
+ if (gap > 0 && first)
+ for (var i = 0; i < first.length; ++i)
+ if (first[i].to == null)
+ (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null));
+ for (var i = 0; i < gap; ++i)
+ newMarkers.push(gapMarkers);
+ newMarkers.push(last);
+ }
+ return newMarkers;
+ }
+
+ // Remove spans that are empty and don't have a clearWhenEmpty
+ // option of false.
+ function clearEmptySpans(spans) {
+ for (var i = 0; i < spans.length; ++i) {
+ var span = spans[i];
+ if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
+ spans.splice(i--, 1);
+ }
+ if (!spans.length) return null;
+ return spans;
+ }
+
+ // Used for un/re-doing changes from the history. Combines the
+ // result of computing the existing spans with the set of spans that
+ // existed in the history (so that deleting around a span and then
+ // undoing brings back the span).
+ function mergeOldSpans(doc, change) {
+ var old = getOldSpans(doc, change);
+ var stretched = stretchSpansOverChange(doc, change);
+ if (!old) return stretched;
+ if (!stretched) return old;
+
+ for (var i = 0; i < old.length; ++i) {
+ var oldCur = old[i], stretchCur = stretched[i];
+ if (oldCur && stretchCur) {
+ spans: for (var j = 0; j < stretchCur.length; ++j) {
+ var span = stretchCur[j];
+ for (var k = 0; k < oldCur.length; ++k)
+ if (oldCur[k].marker == span.marker) continue spans;
+ oldCur.push(span);
+ }
+ } else if (stretchCur) {
+ old[i] = stretchCur;
+ }
+ }
+ return old;
+ }
+
+ // Used to 'clip' out readOnly ranges when making a change.
+ function removeReadOnlyRanges(doc, from, to) {
+ var markers = null;
+ doc.iter(from.line, to.line + 1, function(line) {
+ if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
+ var mark = line.markedSpans[i].marker;
+ if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
+ (markers || (markers = [])).push(mark);
+ }
+ });
+ if (!markers) return null;
+ var parts = [{from: from, to: to}];
+ for (var i = 0; i < markers.length; ++i) {
+ var mk = markers[i], m = mk.find(0);
+ for (var j = 0; j < parts.length; ++j) {
+ var p = parts[j];
+ if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue;
+ var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
+ if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
+ newParts.push({from: p.from, to: m.from});
+ if (dto > 0 || !mk.inclusiveRight && !dto)
+ newParts.push({from: m.to, to: p.to});
+ parts.splice.apply(parts, newParts);
+ j += newParts.length - 1;
+ }
+ }
+ return parts;
+ }
+
+ // Connect or disconnect spans from a line.
+ function detachMarkedSpans(line) {
+ var spans = line.markedSpans;
+ if (!spans) return;
+ for (var i = 0; i < spans.length; ++i)
+ spans[i].marker.detachLine(line);
+ line.markedSpans = null;
+ }
+ function attachMarkedSpans(line, spans) {
+ if (!spans) return;
+ for (var i = 0; i < spans.length; ++i)
+ spans[i].marker.attachLine(line);
+ line.markedSpans = spans;
+ }
+
+ // Helpers used when computing which overlapping collapsed span
+ // counts as the larger one.
+ function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; }
+ function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; }
+
+ // Returns a number indicating which of two overlapping collapsed
+ // spans is larger (and thus includes the other). Falls back to
+ // comparing ids when the spans cover exactly the same range.
+ function compareCollapsedMarkers(a, b) {
+ var lenDiff = a.lines.length - b.lines.length;
+ if (lenDiff != 0) return lenDiff;
+ var aPos = a.find(), bPos = b.find();
+ var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
+ if (fromCmp) return -fromCmp;
+ var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
+ if (toCmp) return toCmp;
+ return b.id - a.id;
+ }
+
+ // Find out whether a line ends or starts in a collapsed span. If
+ // so, return the marker for that span.
+ function collapsedSpanAtSide(line, start) {
+ var sps = sawCollapsedSpans && line.markedSpans, found;
+ if (sps) for (var sp, i = 0; i < sps.length; ++i) {
+ sp = sps[i];
+ if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
+ (!found || compareCollapsedMarkers(found, sp.marker) < 0))
+ found = sp.marker;
+ }
+ return found;
+ }
+ function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); }
+ function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); }
+
+ // Test whether there exists a collapsed span that partially
+ // overlaps (covers the start or end, but not both) of a new span.
+ // Such overlap is not allowed.
+ function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
+ var line = getLine(doc, lineNo);
+ var sps = sawCollapsedSpans && line.markedSpans;
+ if (sps) for (var i = 0; i < sps.length; ++i) {
+ var sp = sps[i];
+ if (!sp.marker.collapsed) continue;
+ var found = sp.marker.find(0);
+ var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
+ var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
+ if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue;
+ if (fromCmp <= 0 && (cmp(found.to, from) > 0 || (sp.marker.inclusiveRight && marker.inclusiveLeft)) ||
+ fromCmp >= 0 && (cmp(found.from, to) < 0 || (sp.marker.inclusiveLeft && marker.inclusiveRight)))
+ return true;
+ }
+ }
+
+ // A visual line is a line as drawn on the screen. Folding, for
+ // example, can cause multiple logical lines to appear on the same
+ // visual line. This finds the start of the visual line that the
+ // given line is part of (usually that is the line itself).
+ function visualLine(line) {
+ var merged;
+ while (merged = collapsedSpanAtStart(line))
+ line = merged.find(-1, true).line;
+ return line;
+ }
+
+ // Returns an array of logical lines that continue the visual line
+ // started by the argument, or undefined if there are no such lines.
+ function visualLineContinued(line) {
+ var merged, lines;
+ while (merged = collapsedSpanAtEnd(line)) {
+ line = merged.find(1, true).line;
+ (lines || (lines = [])).push(line);
+ }
+ return lines;
+ }
+
+ // Get the line number of the start of the visual line that the
+ // given line number is part of.
+ function visualLineNo(doc, lineN) {
+ var line = getLine(doc, lineN), vis = visualLine(line);
+ if (line == vis) return lineN;
+ return lineNo(vis);
+ }
+ // Get the line number of the start of the next visual line after
+ // the given line.
+ function visualLineEndNo(doc, lineN) {
+ if (lineN > doc.lastLine()) return lineN;
+ var line = getLine(doc, lineN), merged;
+ if (!lineIsHidden(doc, line)) return lineN;
+ while (merged = collapsedSpanAtEnd(line))
+ line = merged.find(1, true).line;
+ return lineNo(line) + 1;
+ }
+
+ // Compute whether a line is hidden. Lines count as hidden when they
+ // are part of a visual line that starts with another line, or when
+ // they are entirely covered by collapsed, non-widget span.
+ function lineIsHidden(doc, line) {
+ var sps = sawCollapsedSpans && line.markedSpans;
+ if (sps) for (var sp, i = 0; i < sps.length; ++i) {
+ sp = sps[i];
+ if (!sp.marker.collapsed) continue;
+ if (sp.from == null) return true;
+ if (sp.marker.widgetNode) continue;
+ if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
+ return true;
+ }
+ }
+ function lineIsHiddenInner(doc, line, span) {
+ if (span.to == null) {
+ var end = span.marker.find(1, true);
+ return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker));
+ }
+ if (span.marker.inclusiveRight && span.to == line.text.length)
+ return true;
+ for (var sp, i = 0; i < line.markedSpans.length; ++i) {
+ sp = line.markedSpans[i];
+ if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
+ (sp.to == null || sp.to != span.from) &&
+ (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
+ lineIsHiddenInner(doc, line, sp)) return true;
+ }
+ }
+
+ // LINE WIDGETS
+
+ // Line widgets are block elements displayed above or below a line.
+
+ var LineWidget = CodeMirror.LineWidget = function(doc, node, options) {
+ if (options) for (var opt in options) if (options.hasOwnProperty(opt))
+ this[opt] = options[opt];
+ this.doc = doc;
+ this.node = node;
+ };
+ eventMixin(LineWidget);
+
+ function adjustScrollWhenAboveVisible(cm, line, diff) {
+ if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
+ addToScrollPos(cm, null, diff);
+ }
+
+ LineWidget.prototype.clear = function() {
+ var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
+ if (no == null || !ws) return;
+ for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1);
+ if (!ws.length) line.widgets = null;
+ var height = widgetHeight(this);
+ updateLineHeight(line, Math.max(0, line.height - height));
+ if (cm) runInOp(cm, function() {
+ adjustScrollWhenAboveVisible(cm, line, -height);
+ regLineChange(cm, no, "widget");
+ });
+ };
+ LineWidget.prototype.changed = function() {
+ var oldH = this.height, cm = this.doc.cm, line = this.line;
+ this.height = null;
+ var diff = widgetHeight(this) - oldH;
+ if (!diff) return;
+ updateLineHeight(line, line.height + diff);
+ if (cm) runInOp(cm, function() {
+ cm.curOp.forceUpdate = true;
+ adjustScrollWhenAboveVisible(cm, line, diff);
+ });
+ };
+
+ function widgetHeight(widget) {
+ if (widget.height != null) return widget.height;
+ var cm = widget.doc.cm;
+ if (!cm) return 0;
+ if (!contains(document.body, widget.node)) {
+ var parentStyle = "position: relative;";
+ if (widget.coverGutter)
+ parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;";
+ if (widget.noHScroll)
+ parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;";
+ removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle));
+ }
+ return widget.height = widget.node.offsetHeight;
+ }
+
+ function addLineWidget(doc, handle, node, options) {
+ var widget = new LineWidget(doc, node, options);
+ var cm = doc.cm;
+ if (cm && widget.noHScroll) cm.display.alignWidgets = true;
+ changeLine(doc, handle, "widget", function(line) {
+ var widgets = line.widgets || (line.widgets = []);
+ if (widget.insertAt == null) widgets.push(widget);
+ else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget);
+ widget.line = line;
+ if (cm && !lineIsHidden(doc, line)) {
+ var aboveVisible = heightAtLine(line) < doc.scrollTop;
+ updateLineHeight(line, line.height + widgetHeight(widget));
+ if (aboveVisible) addToScrollPos(cm, null, widget.height);
+ cm.curOp.forceUpdate = true;
+ }
+ return true;
+ });
+ return widget;
+ }
+
+ // LINE DATA STRUCTURE
+
+ // Line objects. These hold state related to a line, including
+ // highlighting info (the styles array).
+ var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) {
+ this.text = text;
+ attachMarkedSpans(this, markedSpans);
+ this.height = estimateHeight ? estimateHeight(this) : 1;
+ };
+ eventMixin(Line);
+ Line.prototype.lineNo = function() { return lineNo(this); };
+
+ // Change the content (text, markers) of a line. Automatically
+ // invalidates cached information and tries to re-estimate the
+ // line's height.
+ function updateLine(line, text, markedSpans, estimateHeight) {
+ line.text = text;
+ if (line.stateAfter) line.stateAfter = null;
+ if (line.styles) line.styles = null;
+ if (line.order != null) line.order = null;
+ detachMarkedSpans(line);
+ attachMarkedSpans(line, markedSpans);
+ var estHeight = estimateHeight ? estimateHeight(line) : 1;
+ if (estHeight != line.height) updateLineHeight(line, estHeight);
+ }
+
+ // Detach a line from the document tree and its markers.
+ function cleanUpLine(line) {
+ line.parent = null;
+ detachMarkedSpans(line);
+ }
+
+ function extractLineClasses(type, output) {
+ if (type) for (;;) {
+ var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
+ if (!lineClass) break;
+ type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
+ var prop = lineClass[1] ? "bgClass" : "textClass";
+ if (output[prop] == null)
+ output[prop] = lineClass[2];
+ else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
+ output[prop] += " " + lineClass[2];
+ }
+ return type;
+ }
+
+ function callBlankLine(mode, state) {
+ if (mode.blankLine) return mode.blankLine(state);
+ if (!mode.innerMode) return;
+ var inner = CodeMirror.innerMode(mode, state);
+ if (inner.mode.blankLine) return inner.mode.blankLine(inner.state);
+ }
+
+ function readToken(mode, stream, state, inner) {
+ for (var i = 0; i < 10; i++) {
+ if (inner) inner[0] = CodeMirror.innerMode(mode, state).mode;
+ var style = mode.token(stream, state);
+ if (stream.pos > stream.start) return style;
+ }
+ throw new Error("Mode " + mode.name + " failed to advance stream.");
+ }
+
+ // Utility for getTokenAt and getLineTokens
+ function takeToken(cm, pos, precise, asArray) {
+ function getObj(copy) {
+ return {start: stream.start, end: stream.pos,
+ string: stream.current(),
+ type: style || null,
+ state: copy ? copyState(doc.mode, state) : state};
+ }
+
+ var doc = cm.doc, mode = doc.mode, style;
+ pos = clipPos(doc, pos);
+ var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise);
+ var stream = new StringStream(line.text, cm.options.tabSize), tokens;
+ if (asArray) tokens = [];
+ while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
+ stream.start = stream.pos;
+ style = readToken(mode, stream, state);
+ if (asArray) tokens.push(getObj(true));
+ }
+ return asArray ? tokens : getObj();
+ }
+
+ // Run the given mode's parser over a line, calling f for each token.
+ function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {
+ var flattenSpans = mode.flattenSpans;
+ if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;
+ var curStart = 0, curStyle = null;
+ var stream = new StringStream(text, cm.options.tabSize), style;
+ var inner = cm.options.addModeClass && [null];
+ if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses);
+ while (!stream.eol()) {
+ if (stream.pos > cm.options.maxHighlightLength) {
+ flattenSpans = false;
+ if (forceToEnd) processLine(cm, text, state, stream.pos);
+ stream.pos = text.length;
+ style = null;
+ } else {
+ style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses);
+ }
+ if (inner) {
+ var mName = inner[0].name;
+ if (mName) style = "m-" + (style ? mName + " " + style : mName);
+ }
+ if (!flattenSpans || curStyle != style) {
+ while (curStart < stream.start) {
+ curStart = Math.min(stream.start, curStart + 50000);
+ f(curStart, curStyle);
+ }
+ curStyle = style;
+ }
+ stream.start = stream.pos;
+ }
+ while (curStart < stream.pos) {
+ // Webkit seems to refuse to render text nodes longer than 57444 characters
+ var pos = Math.min(stream.pos, curStart + 50000);
+ f(pos, curStyle);
+ curStart = pos;
+ }
+ }
+
+ // Compute a style array (an array starting with a mode generation
+ // -- for invalidation -- followed by pairs of end positions and
+ // style strings), which is used to highlight the tokens on the
+ // line.
+ function highlightLine(cm, line, state, forceToEnd) {
+ // A styles array always starts with a number identifying the
+ // mode/overlays that it is based on (for easy invalidation).
+ var st = [cm.state.modeGen], lineClasses = {};
+ // Compute the base array of styles
+ runMode(cm, line.text, cm.doc.mode, state, function(end, style) {
+ st.push(end, style);
+ }, lineClasses, forceToEnd);
+
+ // Run overlays, adjust style array.
+ for (var o = 0; o < cm.state.overlays.length; ++o) {
+ var overlay = cm.state.overlays[o], i = 1, at = 0;
+ runMode(cm, line.text, overlay.mode, true, function(end, style) {
+ var start = i;
+ // Ensure there's a token end at the current position, and that i points at it
+ while (at < end) {
+ var i_end = st[i];
+ if (i_end > end)
+ st.splice(i, 1, end, st[i+1], i_end);
+ i += 2;
+ at = Math.min(end, i_end);
+ }
+ if (!style) return;
+ if (overlay.opaque) {
+ st.splice(start, i - start, end, "cm-overlay " + style);
+ i = start + 2;
+ } else {
+ for (; start < i; start += 2) {
+ var cur = st[start+1];
+ st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style;
+ }
+ }
+ }, lineClasses);
+ }
+
+ return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null};
+ }
+
+ function getLineStyles(cm, line, updateFrontier) {
+ if (!line.styles || line.styles[0] != cm.state.modeGen) {
+ var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
+ line.styles = result.styles;
+ if (result.classes) line.styleClasses = result.classes;
+ else if (line.styleClasses) line.styleClasses = null;
+ if (updateFrontier === cm.doc.frontier) cm.doc.frontier++;
+ }
+ return line.styles;
+ }
+
+ // Lightweight form of highlight -- proceed over this line and
+ // update state, but don't save a style array. Used for lines that
+ // aren't currently visible.
+ function processLine(cm, text, state, startAt) {
+ var mode = cm.doc.mode;
+ var stream = new StringStream(text, cm.options.tabSize);
+ stream.start = stream.pos = startAt || 0;
+ if (text == "") callBlankLine(mode, state);
+ while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) {
+ readToken(mode, stream, state);
+ stream.start = stream.pos;
+ }
+ }
+
+ // Convert a style as returned by a mode (either null, or a string
+ // containing one or more styles) to a CSS style. This is cached,
+ // and also looks for line-wide styles.
+ var styleToClassCache = {}, styleToClassCacheWithMode = {};
+ function interpretTokenStyle(style, options) {
+ if (!style || /^\s*$/.test(style)) return null;
+ var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
+ return cache[style] ||
+ (cache[style] = style.replace(/\S+/g, "cm-$&"));
+ }
+
+ // Render the DOM representation of the text of a line. Also builds
+ // up a 'line map', which points at the DOM nodes that represent
+ // specific stretches of text, and is used by the measuring code.
+ // The returned object contains the DOM node, this map, and
+ // information about line-wide styles that were set by the mode.
+ function buildLineContent(cm, lineView) {
+ // The padding-right forces the element to have a 'border', which
+ // is needed on Webkit to be able to get line-level bounding
+ // rectangles for it (in measureChar).
+ var content = elt("span", null, null, webkit ? "padding-right: .1px" : null);
+ var builder = {pre: elt("pre", [content]), content: content,
+ col: 0, pos: 0, cm: cm,
+ splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")};
+ lineView.measure = {};
+
+ // Iterate over the logical lines that make up this visual line.
+ for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
+ var line = i ? lineView.rest[i - 1] : lineView.line, order;
+ builder.pos = 0;
+ builder.addToken = buildToken;
+ // Optionally wire in some hacks into the token-rendering
+ // algorithm, to deal with browser quirks.
+ if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line)))
+ builder.addToken = buildTokenBadBidi(builder.addToken, order);
+ builder.map = [];
+ var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);
+ insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));
+ if (line.styleClasses) {
+ if (line.styleClasses.bgClass)
+ builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "");
+ if (line.styleClasses.textClass)
+ builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || "");
+ }
+
+ // Ensure at least a single node is present, for measuring.
+ if (builder.map.length == 0)
+ builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure)));
+
+ // Store the map and a cache object for the current logical line
+ if (i == 0) {
+ lineView.measure.map = builder.map;
+ lineView.measure.cache = {};
+ } else {
+ (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map);
+ (lineView.measure.caches || (lineView.measure.caches = [])).push({});
+ }
+ }
+
+ // See issue #2901
+ if (webkit && /\bcm-tab\b/.test(builder.content.lastChild.className))
+ builder.content.className = "cm-tab-wrap-hack";
+
+ signal(cm, "renderLine", cm, lineView.line, builder.pre);
+ if (builder.pre.className)
+ builder.textClass = joinClasses(builder.pre.className, builder.textClass || "");
+
+ return builder;
+ }
+
+ function defaultSpecialCharPlaceholder(ch) {
+ var token = elt("span", "\u2022", "cm-invalidchar");
+ token.title = "\\u" + ch.charCodeAt(0).toString(16);
+ token.setAttribute("aria-label", token.title);
+ return token;
+ }
+
+ // Build up the DOM representation for a single token, and add it to
+ // the line map. Takes care to render special characters separately.
+ function buildToken(builder, text, style, startStyle, endStyle, title, css) {
+ if (!text) return;
+ var displayText = builder.splitSpaces ? text.replace(/ {3,}/g, splitSpaces) : text;
+ var special = builder.cm.state.specialChars, mustWrap = false;
+ if (!special.test(text)) {
+ builder.col += text.length;
+ var content = document.createTextNode(displayText);
+ builder.map.push(builder.pos, builder.pos + text.length, content);
+ if (ie && ie_version < 9) mustWrap = true;
+ builder.pos += text.length;
+ } else {
+ var content = document.createDocumentFragment(), pos = 0;
+ while (true) {
+ special.lastIndex = pos;
+ var m = special.exec(text);
+ var skipped = m ? m.index - pos : text.length - pos;
+ if (skipped) {
+ var txt = document.createTextNode(displayText.slice(pos, pos + skipped));
+ if (ie && ie_version < 9) content.appendChild(elt("span", [txt]));
+ else content.appendChild(txt);
+ builder.map.push(builder.pos, builder.pos + skipped, txt);
+ builder.col += skipped;
+ builder.pos += skipped;
+ }
+ if (!m) break;
+ pos += skipped + 1;
+ if (m[0] == "\t") {
+ var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
+ var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
+ txt.setAttribute("role", "presentation");
+ txt.setAttribute("cm-text", "\t");
+ builder.col += tabWidth;
+ } else {
+ var txt = builder.cm.options.specialCharPlaceholder(m[0]);
+ txt.setAttribute("cm-text", m[0]);
+ if (ie && ie_version < 9) content.appendChild(elt("span", [txt]));
+ else content.appendChild(txt);
+ builder.col += 1;
+ }
+ builder.map.push(builder.pos, builder.pos + 1, txt);
+ builder.pos++;
+ }
+ }
+ if (style || startStyle || endStyle || mustWrap || css) {
+ var fullStyle = style || "";
+ if (startStyle) fullStyle += startStyle;
+ if (endStyle) fullStyle += endStyle;
+ var token = elt("span", [content], fullStyle, css);
+ if (title) token.title = title;
+ return builder.content.appendChild(token);
+ }
+ builder.content.appendChild(content);
+ }
+
+ function splitSpaces(old) {
+ var out = " ";
+ for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0";
+ out += " ";
+ return out;
+ }
+
+ // Work around nonsense dimensions being reported for stretches of
+ // right-to-left text.
+ function buildTokenBadBidi(inner, order) {
+ return function(builder, text, style, startStyle, endStyle, title, css) {
+ style = style ? style + " cm-force-border" : "cm-force-border";
+ var start = builder.pos, end = start + text.length;
+ for (;;) {
+ // Find the part that overlaps with the start of this text
+ for (var i = 0; i < order.length; i++) {
+ var part = order[i];
+ if (part.to > start && part.from <= start) break;
+ }
+ if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css);
+ inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css);
+ startStyle = null;
+ text = text.slice(part.to - start);
+ start = part.to;
+ }
+ };
+ }
+
+ function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
+ var widget = !ignoreWidget && marker.widgetNode;
+ if (widget) builder.map.push(builder.pos, builder.pos + size, widget);
+ if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {
+ if (!widget)
+ widget = builder.content.appendChild(document.createElement("span"));
+ widget.setAttribute("cm-marker", marker.id);
+ }
+ if (widget) {
+ builder.cm.display.input.setUneditable(widget);
+ builder.content.appendChild(widget);
+ }
+ builder.pos += size;
+ }
+
+ // Outputs a number of spans to make up a line, taking highlighting
+ // and marked text into account.
+ function insertLineContent(line, builder, styles) {
+ var spans = line.markedSpans, allText = line.text, at = 0;
+ if (!spans) {
+ for (var i = 1; i < styles.length; i+=2)
+ builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options));
+ return;
+ }
+
+ var len = allText.length, pos = 0, i = 1, text = "", style, css;
+ var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
+ for (;;) {
+ if (nextChange == pos) { // Update current marker set
+ spanStyle = spanEndStyle = spanStartStyle = title = css = "";
+ collapsed = null; nextChange = Infinity;
+ var foundBookmarks = [];
+ for (var j = 0; j < spans.length; ++j) {
+ var sp = spans[j], m = sp.marker;
+ if (sp.from <= pos && (sp.to == null || sp.to > pos)) {
+ if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; }
+ if (m.className) spanStyle += " " + m.className;
+ if (m.css) css = m.css;
+ if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
+ if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
+ if (m.title && !title) title = m.title;
+ if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
+ collapsed = sp;
+ } else if (sp.from > pos && nextChange > sp.from) {
+ nextChange = sp.from;
+ }
+ if (m.type == "bookmark" && sp.from == pos && m.widgetNode) foundBookmarks.push(m);
+ }
+ if (collapsed && (collapsed.from || 0) == pos) {
+ buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
+ collapsed.marker, collapsed.from == null);
+ if (collapsed.to == null) return;
+ }
+ if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j)
+ buildCollapsedSpan(builder, 0, foundBookmarks[j]);
+ }
+ if (pos >= len) break;
+
+ var upto = Math.min(len, nextChange);
+ while (true) {
+ if (text) {
+ var end = pos + text.length;
+ if (!collapsed) {
+ var tokenText = end > upto ? text.slice(0, upto - pos) : text;
+ builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
+ spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css);
+ }
+ if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
+ pos = end;
+ spanStartStyle = "";
+ }
+ text = allText.slice(at, at = styles[i++]);
+ style = interpretTokenStyle(styles[i++], builder.cm.options);
+ }
+ }
+ }
+
+ // DOCUMENT DATA STRUCTURE
+
+ // By default, updates that start and end at the beginning of a line
+ // are treated specially, in order to make the association of line
+ // widgets and marker elements with the text behave more intuitive.
+ function isWholeLineUpdate(doc, change) {
+ return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
+ (!doc.cm || doc.cm.options.wholeLineUpdateBefore);
+ }
+
+ // Perform a change on the document data structure.
+ function updateDoc(doc, change, markedSpans, estimateHeight) {
+ function spansFor(n) {return markedSpans ? markedSpans[n] : null;}
+ function update(line, text, spans) {
+ updateLine(line, text, spans, estimateHeight);
+ signalLater(line, "change", line, change);
+ }
+ function linesFor(start, end) {
+ for (var i = start, result = []; i < end; ++i)
+ result.push(new Line(text[i], spansFor(i), estimateHeight));
+ return result;
+ }
+
+ var from = change.from, to = change.to, text = change.text;
+ var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
+ var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
+
+ // Adjust the line structure
+ if (change.full) {
+ doc.insert(0, linesFor(0, text.length));
+ doc.remove(text.length, doc.size - text.length);
+ } else if (isWholeLineUpdate(doc, change)) {
+ // This is a whole-line replace. Treated specially to make
+ // sure line objects move the way they are supposed to.
+ var added = linesFor(0, text.length - 1);
+ update(lastLine, lastLine.text, lastSpans);
+ if (nlines) doc.remove(from.line, nlines);
+ if (added.length) doc.insert(from.line, added);
+ } else if (firstLine == lastLine) {
+ if (text.length == 1) {
+ update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
+ } else {
+ var added = linesFor(1, text.length - 1);
+ added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight));
+ update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
+ doc.insert(from.line + 1, added);
+ }
+ } else if (text.length == 1) {
+ update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
+ doc.remove(from.line + 1, nlines);
+ } else {
+ update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
+ update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
+ var added = linesFor(1, text.length - 1);
+ if (nlines > 1) doc.remove(from.line + 1, nlines - 1);
+ doc.insert(from.line + 1, added);
+ }
+
+ signalLater(doc, "change", doc, change);
+ }
+
+ // The document is represented as a BTree consisting of leaves, with
+ // chunk of lines in them, and branches, with up to ten leaves or
+ // other branch nodes below them. The top node is always a branch
+ // node, and is the document object itself (meaning it has
+ // additional methods and properties).
+ //
+ // All nodes have parent links. The tree is used both to go from
+ // line numbers to line objects, and to go from objects to numbers.
+ // It also indexes by height, and is used to convert between height
+ // and line object, and to find the total height of the document.
+ //
+ // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
+
+ function LeafChunk(lines) {
+ this.lines = lines;
+ this.parent = null;
+ for (var i = 0, height = 0; i < lines.length; ++i) {
+ lines[i].parent = this;
+ height += lines[i].height;
+ }
+ this.height = height;
+ }
+
+ LeafChunk.prototype = {
+ chunkSize: function() { return this.lines.length; },
+ // Remove the n lines at offset 'at'.
+ removeInner: function(at, n) {
+ for (var i = at, e = at + n; i < e; ++i) {
+ var line = this.lines[i];
+ this.height -= line.height;
+ cleanUpLine(line);
+ signalLater(line, "delete");
+ }
+ this.lines.splice(at, n);
+ },
+ // Helper used to collapse a small branch into a single leaf.
+ collapse: function(lines) {
+ lines.push.apply(lines, this.lines);
+ },
+ // Insert the given array of lines at offset 'at', count them as
+ // having the given height.
+ insertInner: function(at, lines, height) {
+ this.height += height;
+ this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
+ for (var i = 0; i < lines.length; ++i) lines[i].parent = this;
+ },
+ // Used to iterate over a part of the tree.
+ iterN: function(at, n, op) {
+ for (var e = at + n; at < e; ++at)
+ if (op(this.lines[at])) return true;
+ }
+ };
+
+ function BranchChunk(children) {
+ this.children = children;
+ var size = 0, height = 0;
+ for (var i = 0; i < children.length; ++i) {
+ var ch = children[i];
+ size += ch.chunkSize(); height += ch.height;
+ ch.parent = this;
+ }
+ this.size = size;
+ this.height = height;
+ this.parent = null;
+ }
+
+ BranchChunk.prototype = {
+ chunkSize: function() { return this.size; },
+ removeInner: function(at, n) {
+ this.size -= n;
+ for (var i = 0; i < this.children.length; ++i) {
+ var child = this.children[i], sz = child.chunkSize();
+ if (at < sz) {
+ var rm = Math.min(n, sz - at), oldHeight = child.height;
+ child.removeInner(at, rm);
+ this.height -= oldHeight - child.height;
+ if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
+ if ((n -= rm) == 0) break;
+ at = 0;
+ } else at -= sz;
+ }
+ // If the result is smaller than 25 lines, ensure that it is a
+ // single leaf node.
+ if (this.size - n < 25 &&
+ (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
+ var lines = [];
+ this.collapse(lines);
+ this.children = [new LeafChunk(lines)];
+ this.children[0].parent = this;
+ }
+ },
+ collapse: function(lines) {
+ for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines);
+ },
+ insertInner: function(at, lines, height) {
+ this.size += lines.length;
+ this.height += height;
+ for (var i = 0; i < this.children.length; ++i) {
+ var child = this.children[i], sz = child.chunkSize();
+ if (at <= sz) {
+ child.insertInner(at, lines, height);
+ if (child.lines && child.lines.length > 50) {
+ while (child.lines.length > 50) {
+ var spilled = child.lines.splice(child.lines.length - 25, 25);
+ var newleaf = new LeafChunk(spilled);
+ child.height -= newleaf.height;
+ this.children.splice(i + 1, 0, newleaf);
+ newleaf.parent = this;
+ }
+ this.maybeSpill();
+ }
+ break;
+ }
+ at -= sz;
+ }
+ },
+ // When a node has grown, check whether it should be split.
+ maybeSpill: function() {
+ if (this.children.length <= 10) return;
+ var me = this;
+ do {
+ var spilled = me.children.splice(me.children.length - 5, 5);
+ var sibling = new BranchChunk(spilled);
+ if (!me.parent) { // Become the parent node
+ var copy = new BranchChunk(me.children);
+ copy.parent = me;
+ me.children = [copy, sibling];
+ me = copy;
+ } else {
+ me.size -= sibling.size;
+ me.height -= sibling.height;
+ var myIndex = indexOf(me.parent.children, me);
+ me.parent.children.splice(myIndex + 1, 0, sibling);
+ }
+ sibling.parent = me.parent;
+ } while (me.children.length > 10);
+ me.parent.maybeSpill();
+ },
+ iterN: function(at, n, op) {
+ for (var i = 0; i < this.children.length; ++i) {
+ var child = this.children[i], sz = child.chunkSize();
+ if (at < sz) {
+ var used = Math.min(n, sz - at);
+ if (child.iterN(at, used, op)) return true;
+ if ((n -= used) == 0) break;
+ at = 0;
+ } else at -= sz;
+ }
+ }
+ };
+
+ var nextDocId = 0;
+ var Doc = CodeMirror.Doc = function(text, mode, firstLine) {
+ if (!(this instanceof Doc)) return new Doc(text, mode, firstLine);
+ if (firstLine == null) firstLine = 0;
+
+ BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
+ this.first = firstLine;
+ this.scrollTop = this.scrollLeft = 0;
+ this.cantEdit = false;
+ this.cleanGeneration = 1;
+ this.frontier = firstLine;
+ var start = Pos(firstLine, 0);
+ this.sel = simpleSelection(start);
+ this.history = new History(null);
+ this.id = ++nextDocId;
+ this.modeOption = mode;
+
+ if (typeof text == "string") text = splitLines(text);
+ updateDoc(this, {from: start, to: start, text: text});
+ setSelection(this, simpleSelection(start), sel_dontScroll);
+ };
+
+ Doc.prototype = createObj(BranchChunk.prototype, {
+ constructor: Doc,
+ // Iterate over the document. Supports two forms -- with only one
+ // argument, it calls that for each line in the document. With
+ // three, it iterates over the range given by the first two (with
+ // the second being non-inclusive).
+ iter: function(from, to, op) {
+ if (op) this.iterN(from - this.first, to - from, op);
+ else this.iterN(this.first, this.first + this.size, from);
+ },
+
+ // Non-public interface for adding and removing lines.
+ insert: function(at, lines) {
+ var height = 0;
+ for (var i = 0; i < lines.length; ++i) height += lines[i].height;
+ this.insertInner(at - this.first, lines, height);
+ },
+ remove: function(at, n) { this.removeInner(at - this.first, n); },
+
+ // From here, the methods are part of the public interface. Most
+ // are also available from CodeMirror (editor) instances.
+
+ getValue: function(lineSep) {
+ var lines = getLines(this, this.first, this.first + this.size);
+ if (lineSep === false) return lines;
+ return lines.join(lineSep || "\n");
+ },
+ setValue: docMethodOp(function(code) {
+ var top = Pos(this.first, 0), last = this.first + this.size - 1;
+ makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
+ text: splitLines(code), origin: "setValue", full: true}, true);
+ setSelection(this, simpleSelection(top));
+ }),
+ replaceRange: function(code, from, to, origin) {
+ from = clipPos(this, from);
+ to = to ? clipPos(this, to) : from;
+ replaceRange(this, code, from, to, origin);
+ },
+ getRange: function(from, to, lineSep) {
+ var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
+ if (lineSep === false) return lines;
+ return lines.join(lineSep || "\n");
+ },
+
+ getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;},
+
+ getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);},
+ getLineNumber: function(line) {return lineNo(line);},
+
+ getLineHandleVisualStart: function(line) {
+ if (typeof line == "number") line = getLine(this, line);
+ return visualLine(line);
+ },
+
+ lineCount: function() {return this.size;},
+ firstLine: function() {return this.first;},
+ lastLine: function() {return this.first + this.size - 1;},
+
+ clipPos: function(pos) {return clipPos(this, pos);},
+
+ getCursor: function(start) {
+ var range = this.sel.primary(), pos;
+ if (start == null || start == "head") pos = range.head;
+ else if (start == "anchor") pos = range.anchor;
+ else if (start == "end" || start == "to" || start === false) pos = range.to();
+ else pos = range.from();
+ return pos;
+ },
+ listSelections: function() { return this.sel.ranges; },
+ somethingSelected: function() {return this.sel.somethingSelected();},
+
+ setCursor: docMethodOp(function(line, ch, options) {
+ setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options);
+ }),
+ setSelection: docMethodOp(function(anchor, head, options) {
+ setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);
+ }),
+ extendSelection: docMethodOp(function(head, other, options) {
+ extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
+ }),
+ extendSelections: docMethodOp(function(heads, options) {
+ extendSelections(this, clipPosArray(this, heads, options));
+ }),
+ extendSelectionsBy: docMethodOp(function(f, options) {
+ extendSelections(this, map(this.sel.ranges, f), options);
+ }),
+ setSelections: docMethodOp(function(ranges, primary, options) {
+ if (!ranges.length) return;
+ for (var i = 0, out = []; i < ranges.length; i++)
+ out[i] = new Range(clipPos(this, ranges[i].anchor),
+ clipPos(this, ranges[i].head));
+ if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex);
+ setSelection(this, normalizeSelection(out, primary), options);
+ }),
+ addSelection: docMethodOp(function(anchor, head, options) {
+ var ranges = this.sel.ranges.slice(0);
+ ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));
+ setSelection(this, normalizeSelection(ranges, ranges.length - 1), options);
+ }),
+
+ getSelection: function(lineSep) {
+ var ranges = this.sel.ranges, lines;
+ for (var i = 0; i < ranges.length; i++) {
+ var sel = getBetween(this, ranges[i].from(), ranges[i].to());
+ lines = lines ? lines.concat(sel) : sel;
+ }
+ if (lineSep === false) return lines;
+ else return lines.join(lineSep || "\n");
+ },
+ getSelections: function(lineSep) {
+ var parts = [], ranges = this.sel.ranges;
+ for (var i = 0; i < ranges.length; i++) {
+ var sel = getBetween(this, ranges[i].from(), ranges[i].to());
+ if (lineSep !== false) sel = sel.join(lineSep || "\n");
+ parts[i] = sel;
+ }
+ return parts;
+ },
+ replaceSelection: function(code, collapse, origin) {
+ var dup = [];
+ for (var i = 0; i < this.sel.ranges.length; i++)
+ dup[i] = code;
+ this.replaceSelections(dup, collapse, origin || "+input");
+ },
+ replaceSelections: docMethodOp(function(code, collapse, origin) {
+ var changes = [], sel = this.sel;
+ for (var i = 0; i < sel.ranges.length; i++) {
+ var range = sel.ranges[i];
+ changes[i] = {from: range.from(), to: range.to(), text: splitLines(code[i]), origin: origin};
+ }
+ var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
+ for (var i = changes.length - 1; i >= 0; i--)
+ makeChange(this, changes[i]);
+ if (newSel) setSelectionReplaceHistory(this, newSel);
+ else if (this.cm) ensureCursorVisible(this.cm);
+ }),
+ undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
+ redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
+ undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
+ redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}),
+
+ setExtending: function(val) {this.extend = val;},
+ getExtending: function() {return this.extend;},
+
+ historySize: function() {
+ var hist = this.history, done = 0, undone = 0;
+ for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done;
+ for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone;
+ return {undo: done, redo: undone};
+ },
+ clearHistory: function() {this.history = new History(this.history.maxGeneration);},
+
+ markClean: function() {
+ this.cleanGeneration = this.changeGeneration(true);
+ },
+ changeGeneration: function(forceSplit) {
+ if (forceSplit)
+ this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null;
+ return this.history.generation;
+ },
+ isClean: function (gen) {
+ return this.history.generation == (gen || this.cleanGeneration);
+ },
+
+ getHistory: function() {
+ return {done: copyHistoryArray(this.history.done),
+ undone: copyHistoryArray(this.history.undone)};
+ },
+ setHistory: function(histData) {
+ var hist = this.history = new History(this.history.maxGeneration);
+ hist.done = copyHistoryArray(histData.done.slice(0), null, true);
+ hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
+ },
+
+ addLineClass: docMethodOp(function(handle, where, cls) {
+ return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) {
+ var prop = where == "text" ? "textClass"
+ : where == "background" ? "bgClass"
+ : where == "gutter" ? "gutterClass" : "wrapClass";
+ if (!line[prop]) line[prop] = cls;
+ else if (classTest(cls).test(line[prop])) return false;
+ else line[prop] += " " + cls;
+ return true;
+ });
+ }),
+ removeLineClass: docMethodOp(function(handle, where, cls) {
+ return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) {
+ var prop = where == "text" ? "textClass"
+ : where == "background" ? "bgClass"
+ : where == "gutter" ? "gutterClass" : "wrapClass";
+ var cur = line[prop];
+ if (!cur) return false;
+ else if (cls == null) line[prop] = null;
+ else {
+ var found = cur.match(classTest(cls));
+ if (!found) return false;
+ var end = found.index + found[0].length;
+ line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
+ }
+ return true;
+ });
+ }),
+
+ addLineWidget: docMethodOp(function(handle, node, options) {
+ return addLineWidget(this, handle, node, options);
+ }),
+ removeLineWidget: function(widget) { widget.clear(); },
+
+ markText: function(from, to, options) {
+ return markText(this, clipPos(this, from), clipPos(this, to), options, "range");
+ },
+ setBookmark: function(pos, options) {
+ var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
+ insertLeft: options && options.insertLeft,
+ clearWhenEmpty: false, shared: options && options.shared,
+ handleMouseEvents: options && options.handleMouseEvents};
+ pos = clipPos(this, pos);
+ return markText(this, pos, pos, realOpts, "bookmark");
+ },
+ findMarksAt: function(pos) {
+ pos = clipPos(this, pos);
+ var markers = [], spans = getLine(this, pos.line).markedSpans;
+ if (spans) for (var i = 0; i < spans.length; ++i) {
+ var span = spans[i];
+ if ((span.from == null || span.from <= pos.ch) &&
+ (span.to == null || span.to >= pos.ch))
+ markers.push(span.marker.parent || span.marker);
+ }
+ return markers;
+ },
+ findMarks: function(from, to, filter) {
+ from = clipPos(this, from); to = clipPos(this, to);
+ var found = [], lineNo = from.line;
+ this.iter(from.line, to.line + 1, function(line) {
+ var spans = line.markedSpans;
+ if (spans) for (var i = 0; i < spans.length; i++) {
+ var span = spans[i];
+ if (!(lineNo == from.line && from.ch > span.to ||
+ span.from == null && lineNo != from.line||
+ lineNo == to.line && span.from > to.ch) &&
+ (!filter || filter(span.marker)))
+ found.push(span.marker.parent || span.marker);
+ }
+ ++lineNo;
+ });
+ return found;
+ },
+ getAllMarks: function() {
+ var markers = [];
+ this.iter(function(line) {
+ var sps = line.markedSpans;
+ if (sps) for (var i = 0; i < sps.length; ++i)
+ if (sps[i].from != null) markers.push(sps[i].marker);
+ });
+ return markers;
+ },
+
+ posFromIndex: function(off) {
+ var ch, lineNo = this.first;
+ this.iter(function(line) {
+ var sz = line.text.length + 1;
+ if (sz > off) { ch = off; return true; }
+ off -= sz;
+ ++lineNo;
+ });
+ return clipPos(this, Pos(lineNo, ch));
+ },
+ indexFromPos: function (coords) {
+ coords = clipPos(this, coords);
+ var index = coords.ch;
+ if (coords.line < this.first || coords.ch < 0) return 0;
+ this.iter(this.first, coords.line, function (line) {
+ index += line.text.length + 1;
+ });
+ return index;
+ },
+
+ copy: function(copyHistory) {
+ var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first);
+ doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
+ doc.sel = this.sel;
+ doc.extend = false;
+ if (copyHistory) {
+ doc.history.undoDepth = this.history.undoDepth;
+ doc.setHistory(this.getHistory());
+ }
+ return doc;
+ },
+
+ linkedDoc: function(options) {
+ if (!options) options = {};
+ var from = this.first, to = this.first + this.size;
+ if (options.from != null && options.from > from) from = options.from;
+ if (options.to != null && options.to < to) to = options.to;
+ var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from);
+ if (options.sharedHist) copy.history = this.history;
+ (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
+ copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
+ copySharedMarkers(copy, findSharedMarkers(this));
+ return copy;
+ },
+ unlinkDoc: function(other) {
+ if (other instanceof CodeMirror) other = other.doc;
+ if (this.linked) for (var i = 0; i < this.linked.length; ++i) {
+ var link = this.linked[i];
+ if (link.doc != other) continue;
+ this.linked.splice(i, 1);
+ other.unlinkDoc(this);
+ detachSharedMarkers(findSharedMarkers(this));
+ break;
+ }
+ // If the histories were shared, split them again
+ if (other.history == this.history) {
+ var splitIds = [other.id];
+ linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true);
+ other.history = new History(null);
+ other.history.done = copyHistoryArray(this.history.done, splitIds);
+ other.history.undone = copyHistoryArray(this.history.undone, splitIds);
+ }
+ },
+ iterLinkedDocs: function(f) {linkedDocs(this, f);},
+
+ getMode: function() {return this.mode;},
+ getEditor: function() {return this.cm;}
+ });
+
+ // Public alias.
+ Doc.prototype.eachLine = Doc.prototype.iter;
+
+ // Set up methods on CodeMirror's prototype to redirect to the editor's document.
+ var dontDelegate = "iter insert remove copy getEditor".split(" ");
+ for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
+ CodeMirror.prototype[prop] = (function(method) {
+ return function() {return method.apply(this.doc, arguments);};
+ })(Doc.prototype[prop]);
+
+ eventMixin(Doc);
+
+ // Call f for all linked documents.
+ function linkedDocs(doc, f, sharedHistOnly) {
+ function propagate(doc, skip, sharedHist) {
+ if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) {
+ var rel = doc.linked[i];
+ if (rel.doc == skip) continue;
+ var shared = sharedHist && rel.sharedHist;
+ if (sharedHistOnly && !shared) continue;
+ f(rel.doc, shared);
+ propagate(rel.doc, doc, shared);
+ }
+ }
+ propagate(doc, null, true);
+ }
+
+ // Attach a document to an editor.
+ function attachDoc(cm, doc) {
+ if (doc.cm) throw new Error("This document is already in use.");
+ cm.doc = doc;
+ doc.cm = cm;
+ estimateLineHeights(cm);
+ loadMode(cm);
+ if (!cm.options.lineWrapping) findMaxLine(cm);
+ cm.options.mode = doc.modeOption;
+ regChange(cm);
+ }
+
+ // LINE UTILITIES
+
+ // Find the line object corresponding to the given line number.
+ function getLine(doc, n) {
+ n -= doc.first;
+ if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document.");
+ for (var chunk = doc; !chunk.lines;) {
+ for (var i = 0;; ++i) {
+ var child = chunk.children[i], sz = child.chunkSize();
+ if (n < sz) { chunk = child; break; }
+ n -= sz;
+ }
+ }
+ return chunk.lines[n];
+ }
+
+ // Get the part of a document between two positions, as an array of
+ // strings.
+ function getBetween(doc, start, end) {
+ var out = [], n = start.line;
+ doc.iter(start.line, end.line + 1, function(line) {
+ var text = line.text;
+ if (n == end.line) text = text.slice(0, end.ch);
+ if (n == start.line) text = text.slice(start.ch);
+ out.push(text);
+ ++n;
+ });
+ return out;
+ }
+ // Get the lines between from and to, as array of strings.
+ function getLines(doc, from, to) {
+ var out = [];
+ doc.iter(from, to, function(line) { out.push(line.text); });
+ return out;
+ }
+
+ // Update the height of a line, propagating the height change
+ // upwards to parent nodes.
+ function updateLineHeight(line, height) {
+ var diff = height - line.height;
+ if (diff) for (var n = line; n; n = n.parent) n.height += diff;
+ }
+
+ // Given a line object, find its line number by walking up through
+ // its parent links.
+ function lineNo(line) {
+ if (line.parent == null) return null;
+ var cur = line.parent, no = indexOf(cur.lines, line);
+ for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
+ for (var i = 0;; ++i) {
+ if (chunk.children[i] == cur) break;
+ no += chunk.children[i].chunkSize();
+ }
+ }
+ return no + cur.first;
+ }
+
+ // Find the line at the given vertical position, using the height
+ // information in the document tree.
+ function lineAtHeight(chunk, h) {
+ var n = chunk.first;
+ outer: do {
+ for (var i = 0; i < chunk.children.length; ++i) {
+ var child = chunk.children[i], ch = child.height;
+ if (h < ch) { chunk = child; continue outer; }
+ h -= ch;
+ n += child.chunkSize();
+ }
+ return n;
+ } while (!chunk.lines);
+ for (var i = 0; i < chunk.lines.length; ++i) {
+ var line = chunk.lines[i], lh = line.height;
+ if (h < lh) break;
+ h -= lh;
+ }
+ return n + i;
+ }
+
+
+ // Find the height above the given line.
+ function heightAtLine(lineObj) {
+ lineObj = visualLine(lineObj);
+
+ var h = 0, chunk = lineObj.parent;
+ for (var i = 0; i < chunk.lines.length; ++i) {
+ var line = chunk.lines[i];
+ if (line == lineObj) break;
+ else h += line.height;
+ }
+ for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
+ for (var i = 0; i < p.children.length; ++i) {
+ var cur = p.children[i];
+ if (cur == chunk) break;
+ else h += cur.height;
+ }
+ }
+ return h;
+ }
+
+ // Get the bidi ordering for the given line (and cache it). Returns
+ // false for lines that are fully left-to-right, and an array of
+ // BidiSpan objects otherwise.
+ function getOrder(line) {
+ var order = line.order;
+ if (order == null) order = line.order = bidiOrdering(line.text);
+ return order;
+ }
+
+ // HISTORY
+
+ function History(startGen) {
+ // Arrays of change events and selections. Doing something adds an
+ // event to done and clears undo. Undoing moves events from done
+ // to undone, redoing moves them in the other direction.
+ this.done = []; this.undone = [];
+ this.undoDepth = Infinity;
+ // Used to track when changes can be merged into a single undo
+ // event
+ this.lastModTime = this.lastSelTime = 0;
+ this.lastOp = this.lastSelOp = null;
+ this.lastOrigin = this.lastSelOrigin = null;
+ // Used by the isClean() method
+ this.generation = this.maxGeneration = startGen || 1;
+ }
+
+ // Create a history change event from an updateDoc-style change
+ // object.
+ function historyChangeFromChange(doc, change) {
+ var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
+ attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
+ linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true);
+ return histChange;
+ }
+
+ // Pop all selection events off the end of a history array. Stop at
+ // a change event.
+ function clearSelectionEvents(array) {
+ while (array.length) {
+ var last = lst(array);
+ if (last.ranges) array.pop();
+ else break;
+ }
+ }
+
+ // Find the top change event in the history. Pop off selection
+ // events that are in the way.
+ function lastChangeEvent(hist, force) {
+ if (force) {
+ clearSelectionEvents(hist.done);
+ return lst(hist.done);
+ } else if (hist.done.length && !lst(hist.done).ranges) {
+ return lst(hist.done);
+ } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
+ hist.done.pop();
+ return lst(hist.done);
+ }
+ }
+
+ // Register a change in the history. Merges changes that are within
+ // a single operation, ore are close together with an origin that
+ // allows merging (starting with "+") into a single event.
+ function addChangeToHistory(doc, change, selAfter, opId) {
+ var hist = doc.history;
+ hist.undone.length = 0;
+ var time = +new Date, cur;
+
+ if ((hist.lastOp == opId ||
+ hist.lastOrigin == change.origin && change.origin &&
+ ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) ||
+ change.origin.charAt(0) == "*")) &&
+ (cur = lastChangeEvent(hist, hist.lastOp == opId))) {
+ // Merge this change into the last event
+ var last = lst(cur.changes);
+ if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
+ // Optimized case for simple insertion -- don't want to add
+ // new changesets for every character typed
+ last.to = changeEnd(change);
+ } else {
+ // Add new sub-event
+ cur.changes.push(historyChangeFromChange(doc, change));
+ }
+ } else {
+ // Can not be merged, start a new event.
+ var before = lst(hist.done);
+ if (!before || !before.ranges)
+ pushSelectionToHistory(doc.sel, hist.done);
+ cur = {changes: [historyChangeFromChange(doc, change)],
+ generation: hist.generation};
+ hist.done.push(cur);
+ while (hist.done.length > hist.undoDepth) {
+ hist.done.shift();
+ if (!hist.done[0].ranges) hist.done.shift();
+ }
+ }
+ hist.done.push(selAfter);
+ hist.generation = ++hist.maxGeneration;
+ hist.lastModTime = hist.lastSelTime = time;
+ hist.lastOp = hist.lastSelOp = opId;
+ hist.lastOrigin = hist.lastSelOrigin = change.origin;
+
+ if (!last) signal(doc, "historyAdded");
+ }
+
+ function selectionEventCanBeMerged(doc, origin, prev, sel) {
+ var ch = origin.charAt(0);
+ return ch == "*" ||
+ ch == "+" &&
+ prev.ranges.length == sel.ranges.length &&
+ prev.somethingSelected() == sel.somethingSelected() &&
+ new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500);
+ }
+
+ // Called whenever the selection changes, sets the new selection as
+ // the pending selection in the history, and pushes the old pending
+ // selection into the 'done' array when it was significantly
+ // different (in number of selected ranges, emptiness, or time).
+ function addSelectionToHistory(doc, sel, opId, options) {
+ var hist = doc.history, origin = options && options.origin;
+
+ // A new event is started when the previous origin does not match
+ // the current, or the origins don't allow matching. Origins
+ // starting with * are always merged, those starting with + are
+ // merged when similar and close together in time.
+ if (opId == hist.lastSelOp ||
+ (origin && hist.lastSelOrigin == origin &&
+ (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
+ selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
+ hist.done[hist.done.length - 1] = sel;
+ else
+ pushSelectionToHistory(sel, hist.done);
+
+ hist.lastSelTime = +new Date;
+ hist.lastSelOrigin = origin;
+ hist.lastSelOp = opId;
+ if (options && options.clearRedo !== false)
+ clearSelectionEvents(hist.undone);
+ }
+
+ function pushSelectionToHistory(sel, dest) {
+ var top = lst(dest);
+ if (!(top && top.ranges && top.equals(sel)))
+ dest.push(sel);
+ }
+
+ // Used to store marked span information in the history.
+ function attachLocalSpans(doc, change, from, to) {
+ var existing = change["spans_" + doc.id], n = 0;
+ doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) {
+ if (line.markedSpans)
+ (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans;
+ ++n;
+ });
+ }
+
+ // When un/re-doing restores text containing marked spans, those
+ // that have been explicitly cleared should not be restored.
+ function removeClearedSpans(spans) {
+ if (!spans) return null;
+ for (var i = 0, out; i < spans.length; ++i) {
+ if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); }
+ else if (out) out.push(spans[i]);
+ }
+ return !out ? spans : out.length ? out : null;
+ }
+
+ // Retrieve and filter the old marked spans stored in a change event.
+ function getOldSpans(doc, change) {
+ var found = change["spans_" + doc.id];
+ if (!found) return null;
+ for (var i = 0, nw = []; i < change.text.length; ++i)
+ nw.push(removeClearedSpans(found[i]));
+ return nw;
+ }
+
+ // Used both to provide a JSON-safe object in .getHistory, and, when
+ // detaching a document, to split the history in two
+ function copyHistoryArray(events, newGroup, instantiateSel) {
+ for (var i = 0, copy = []; i < events.length; ++i) {
+ var event = events[i];
+ if (event.ranges) {
+ copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);
+ continue;
+ }
+ var changes = event.changes, newChanges = [];
+ copy.push({changes: newChanges});
+ for (var j = 0; j < changes.length; ++j) {
+ var change = changes[j], m;
+ newChanges.push({from: change.from, to: change.to, text: change.text});
+ if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) {
+ if (indexOf(newGroup, Number(m[1])) > -1) {
+ lst(newChanges)[prop] = change[prop];
+ delete change[prop];
+ }
+ }
+ }
+ }
+ return copy;
+ }
+
+ // Rebasing/resetting history to deal with externally-sourced changes
+
+ function rebaseHistSelSingle(pos, from, to, diff) {
+ if (to < pos.line) {
+ pos.line += diff;
+ } else if (from < pos.line) {
+ pos.line = from;
+ pos.ch = 0;
+ }
+ }
+
+ // Tries to rebase an array of history events given a change in the
+ // document. If the change touches the same lines as the event, the
+ // event, and everything 'behind' it, is discarded. If the change is
+ // before the event, the event's positions are updated. Uses a
+ // copy-on-write scheme for the positions, to avoid having to
+ // reallocate them all on every rebase, but also avoid problems with
+ // shared position objects being unsafely updated.
+ function rebaseHistArray(array, from, to, diff) {
+ for (var i = 0; i < array.length; ++i) {
+ var sub = array[i], ok = true;
+ if (sub.ranges) {
+ if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }
+ for (var j = 0; j < sub.ranges.length; j++) {
+ rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);
+ rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);
+ }
+ continue;
+ }
+ for (var j = 0; j < sub.changes.length; ++j) {
+ var cur = sub.changes[j];
+ if (to < cur.from.line) {
+ cur.from = Pos(cur.from.line + diff, cur.from.ch);
+ cur.to = Pos(cur.to.line + diff, cur.to.ch);
+ } else if (from <= cur.to.line) {
+ ok = false;
+ break;
+ }
+ }
+ if (!ok) {
+ array.splice(0, i + 1);
+ i = 0;
+ }
+ }
+ }
+
+ function rebaseHist(hist, change) {
+ var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;
+ rebaseHistArray(hist.done, from, to, diff);
+ rebaseHistArray(hist.undone, from, to, diff);
+ }
+
+ // EVENT UTILITIES
+
+ // Due to the fact that we still support jurassic IE versions, some
+ // compatibility wrappers are needed.
+
+ var e_preventDefault = CodeMirror.e_preventDefault = function(e) {
+ if (e.preventDefault) e.preventDefault();
+ else e.returnValue = false;
+ };
+ var e_stopPropagation = CodeMirror.e_stopPropagation = function(e) {
+ if (e.stopPropagation) e.stopPropagation();
+ else e.cancelBubble = true;
+ };
+ function e_defaultPrevented(e) {
+ return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false;
+ }
+ var e_stop = CodeMirror.e_stop = function(e) {e_preventDefault(e); e_stopPropagation(e);};
+
+ function e_target(e) {return e.target || e.srcElement;}
+ function e_button(e) {
+ var b = e.which;
+ if (b == null) {
+ if (e.button & 1) b = 1;
+ else if (e.button & 2) b = 3;
+ else if (e.button & 4) b = 2;
+ }
+ if (mac && e.ctrlKey && b == 1) b = 3;
+ return b;
+ }
+
+ // EVENT HANDLING
+
+ // Lightweight event framework. on/off also work on DOM nodes,
+ // registering native DOM handlers.
+
+ var on = CodeMirror.on = function(emitter, type, f) {
+ if (emitter.addEventListener)
+ emitter.addEventListener(type, f, false);
+ else if (emitter.attachEvent)
+ emitter.attachEvent("on" + type, f);
+ else {
+ var map = emitter._handlers || (emitter._handlers = {});
+ var arr = map[type] || (map[type] = []);
+ arr.push(f);
+ }
+ };
+
+ var off = CodeMirror.off = function(emitter, type, f) {
+ if (emitter.removeEventListener)
+ emitter.removeEventListener(type, f, false);
+ else if (emitter.detachEvent)
+ emitter.detachEvent("on" + type, f);
+ else {
+ var arr = emitter._handlers && emitter._handlers[type];
+ if (!arr) return;
+ for (var i = 0; i < arr.length; ++i)
+ if (arr[i] == f) { arr.splice(i, 1); break; }
+ }
+ };
+
+ var signal = CodeMirror.signal = function(emitter, type /*, values...*/) {
+ var arr = emitter._handlers && emitter._handlers[type];
+ if (!arr) return;
+ var args = Array.prototype.slice.call(arguments, 2);
+ for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args);
+ };
+
+ var orphanDelayedCallbacks = null;
+
+ // Often, we want to signal events at a point where we are in the
+ // middle of some work, but don't want the handler to start calling
+ // other methods on the editor, which might be in an inconsistent
+ // state or simply not expect any other events to happen.
+ // signalLater looks whether there are any handlers, and schedules
+ // them to be executed when the last operation ends, or, if no
+ // operation is active, when a timeout fires.
+ function signalLater(emitter, type /*, values...*/) {
+ var arr = emitter._handlers && emitter._handlers[type];
+ if (!arr) return;
+ var args = Array.prototype.slice.call(arguments, 2), list;
+ if (operationGroup) {
+ list = operationGroup.delayedCallbacks;
+ } else if (orphanDelayedCallbacks) {
+ list = orphanDelayedCallbacks;
+ } else {
+ list = orphanDelayedCallbacks = [];
+ setTimeout(fireOrphanDelayed, 0);
+ }
+ function bnd(f) {return function(){f.apply(null, args);};};
+ for (var i = 0; i < arr.length; ++i)
+ list.push(bnd(arr[i]));
+ }
+
+ function fireOrphanDelayed() {
+ var delayed = orphanDelayedCallbacks;
+ orphanDelayedCallbacks = null;
+ for (var i = 0; i < delayed.length; ++i) delayed[i]();
+ }
+
+ // The DOM events that CodeMirror handles can be overridden by
+ // registering a (non-DOM) handler on the editor for the event name,
+ // and preventDefault-ing the event in that handler.
+ function signalDOMEvent(cm, e, override) {
+ if (typeof e == "string")
+ e = {type: e, preventDefault: function() { this.defaultPrevented = true; }};
+ signal(cm, override || e.type, cm, e);
+ return e_defaultPrevented(e) || e.codemirrorIgnore;
+ }
+
+ function signalCursorActivity(cm) {
+ var arr = cm._handlers && cm._handlers.cursorActivity;
+ if (!arr) return;
+ var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
+ for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1)
+ set.push(arr[i]);
+ }
+
+ function hasHandler(emitter, type) {
+ var arr = emitter._handlers && emitter._handlers[type];
+ return arr && arr.length > 0;
+ }
+
+ // Add on and off methods to a constructor's prototype, to make
+ // registering events on such objects more convenient.
+ function eventMixin(ctor) {
+ ctor.prototype.on = function(type, f) {on(this, type, f);};
+ ctor.prototype.off = function(type, f) {off(this, type, f);};
+ }
+
+ // MISC UTILITIES
+
+ // Number of pixels added to scroller and sizer to hide scrollbar
+ var scrollerGap = 30;
+
+ // Returned or thrown by various protocols to signal 'I'm not
+ // handling this'.
+ var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
+
+ // Reused option objects for setSelection & friends
+ var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"};
+
+ function Delayed() {this.id = null;}
+ Delayed.prototype.set = function(ms, f) {
+ clearTimeout(this.id);
+ this.id = setTimeout(f, ms);
+ };
+
+ // Counts the column offset in a string, taking tabs into account.
+ // Used mostly to find indentation.
+ var countColumn = CodeMirror.countColumn = function(string, end, tabSize, startIndex, startValue) {
+ if (end == null) {
+ end = string.search(/[^\s\u00a0]/);
+ if (end == -1) end = string.length;
+ }
+ for (var i = startIndex || 0, n = startValue || 0;;) {
+ var nextTab = string.indexOf("\t", i);
+ if (nextTab < 0 || nextTab >= end)
+ return n + (end - i);
+ n += nextTab - i;
+ n += tabSize - (n % tabSize);
+ i = nextTab + 1;
+ }
+ };
+
+ // The inverse of countColumn -- find the offset that corresponds to
+ // a particular column.
+ function findColumn(string, goal, tabSize) {
+ for (var pos = 0, col = 0;;) {
+ var nextTab = string.indexOf("\t", pos);
+ if (nextTab == -1) nextTab = string.length;
+ var skipped = nextTab - pos;
+ if (nextTab == string.length || col + skipped >= goal)
+ return pos + Math.min(skipped, goal - col);
+ col += nextTab - pos;
+ col += tabSize - (col % tabSize);
+ pos = nextTab + 1;
+ if (col >= goal) return pos;
+ }
+ }
+
+ var spaceStrs = [""];
+ function spaceStr(n) {
+ while (spaceStrs.length <= n)
+ spaceStrs.push(lst(spaceStrs) + " ");
+ return spaceStrs[n];
+ }
+
+ function lst(arr) { return arr[arr.length-1]; }
+
+ var selectInput = function(node) { node.select(); };
+ if (ios) // Mobile Safari apparently has a bug where select() is broken.
+ selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; };
+ else if (ie) // Suppress mysterious IE10 errors
+ selectInput = function(node) { try { node.select(); } catch(_e) {} };
+
+ function indexOf(array, elt) {
+ for (var i = 0; i < array.length; ++i)
+ if (array[i] == elt) return i;
+ return -1;
+ }
+ function map(array, f) {
+ var out = [];
+ for (var i = 0; i < array.length; i++) out[i] = f(array[i], i);
+ return out;
+ }
+
+ function nothing() {}
+
+ function createObj(base, props) {
+ var inst;
+ if (Object.create) {
+ inst = Object.create(base);
+ } else {
+ nothing.prototype = base;
+ inst = new nothing();
+ }
+ if (props) copyObj(props, inst);
+ return inst;
+ };
+
+ function copyObj(obj, target, overwrite) {
+ if (!target) target = {};
+ for (var prop in obj)
+ if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
+ target[prop] = obj[prop];
+ return target;
+ }
+
+ function bind(f) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ return function(){return f.apply(null, args);};
+ }
+
+ var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
+ var isWordCharBasic = CodeMirror.isWordChar = function(ch) {
+ return /\w/.test(ch) || ch > "\x80" &&
+ (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch));
+ };
+ function isWordChar(ch, helper) {
+ if (!helper) return isWordCharBasic(ch);
+ if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true;
+ return helper.test(ch);
+ }
+
+ function isEmpty(obj) {
+ for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false;
+ return true;
+ }
+
+ // Extending unicode characters. A series of a non-extending char +
+ // any number of extending chars is treated as a single unit as far
+ // as editing and measuring is concerned. This is not fully correct,
+ // since some scripts/fonts/browsers also treat other configurations
+ // of code points as a group.
+ var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
+ function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); }
+
+ // DOM UTILITIES
+
+ function elt(tag, content, className, style) {
+ var e = document.createElement(tag);
+ if (className) e.className = className;
+ if (style) e.style.cssText = style;
+ if (typeof content == "string") e.appendChild(document.createTextNode(content));
+ else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);
+ return e;
+ }
+
+ var range;
+ if (document.createRange) range = function(node, start, end, endNode) {
+ var r = document.createRange();
+ r.setEnd(endNode || node, end);
+ r.setStart(node, start);
+ return r;
+ };
+ else range = function(node, start, end) {
+ var r = document.body.createTextRange();
+ try { r.moveToElementText(node.parentNode); }
+ catch(e) { return r; }
+ r.collapse(true);
+ r.moveEnd("character", end);
+ r.moveStart("character", start);
+ return r;
+ };
+
+ function removeChildren(e) {
+ for (var count = e.childNodes.length; count > 0; --count)
+ e.removeChild(e.firstChild);
+ return e;
+ }
+
+ function removeChildrenAndAdd(parent, e) {
+ return removeChildren(parent).appendChild(e);
+ }
+
+ var contains = CodeMirror.contains = function(parent, child) {
+ if (child.nodeType == 3) // Android browser always returns false when child is a textnode
+ child = child.parentNode;
+ if (parent.contains)
+ return parent.contains(child);
+ do {
+ if (child.nodeType == 11) child = child.host;
+ if (child == parent) return true;
+ } while (child = child.parentNode);
+ };
+
+ function activeElt() { return document.activeElement; }
+ // Older versions of IE throws unspecified error when touching
+ // document.activeElement in some cases (during loading, in iframe)
+ if (ie && ie_version < 11) activeElt = function() {
+ try { return document.activeElement; }
+ catch(e) { return document.body; }
+ };
+
+ function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*"); }
+ var rmClass = CodeMirror.rmClass = function(node, cls) {
+ var current = node.className;
+ var match = classTest(cls).exec(current);
+ if (match) {
+ var after = current.slice(match.index + match[0].length);
+ node.className = current.slice(0, match.index) + (after ? match[1] + after : "");
+ }
+ };
+ var addClass = CodeMirror.addClass = function(node, cls) {
+ var current = node.className;
+ if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls;
+ };
+ function joinClasses(a, b) {
+ var as = a.split(" ");
+ for (var i = 0; i < as.length; i++)
+ if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i];
+ return b;
+ }
+
+ // WINDOW-WIDE EVENTS
+
+ // These must be handled carefully, because naively registering a
+ // handler for each editor will cause the editors to never be
+ // garbage collected.
+
+ function forEachCodeMirror(f) {
+ if (!document.body.getElementsByClassName) return;
+ var byClass = document.body.getElementsByClassName("CodeMirror");
+ for (var i = 0; i < byClass.length; i++) {
+ var cm = byClass[i].CodeMirror;
+ if (cm) f(cm);
+ }
+ }
+
+ var globalsRegistered = false;
+ function ensureGlobalHandlers() {
+ if (globalsRegistered) return;
+ registerGlobalHandlers();
+ globalsRegistered = true;
+ }
+ function registerGlobalHandlers() {
+ // When the window resizes, we need to refresh active editors.
+ var resizeTimer;
+ on(window, "resize", function() {
+ if (resizeTimer == null) resizeTimer = setTimeout(function() {
+ resizeTimer = null;
+ forEachCodeMirror(onResize);
+ }, 100);
+ });
+ // When the window loses focus, we want to show the editor as blurred
+ on(window, "blur", function() {
+ forEachCodeMirror(onBlur);
+ });
+ }
+
+ // FEATURE DETECTION
+
+ // Detect drag-and-drop
+ var dragAndDrop = function() {
+ // There is *some* kind of drag-and-drop support in IE6-8, but I
+ // couldn't get it to work yet.
+ if (ie && ie_version < 9) return false;
+ var div = elt('div');
+ return "draggable" in div || "dragDrop" in div;
+ }();
+
+ var zwspSupported;
+ function zeroWidthElement(measure) {
+ if (zwspSupported == null) {
+ var test = elt("span", "\u200b");
+ removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
+ if (measure.firstChild.offsetHeight != 0)
+ zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8);
+ }
+ var node = zwspSupported ? elt("span", "\u200b") :
+ elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
+ node.setAttribute("cm-text", "");
+ return node;
+ }
+
+ // Feature-detect IE's crummy client rect reporting for bidi text
+ var badBidiRects;
+ function hasBadBidiRects(measure) {
+ if (badBidiRects != null) return badBidiRects;
+ var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
+ var r0 = range(txt, 0, 1).getBoundingClientRect();
+ if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780)
+ var r1 = range(txt, 1, 2).getBoundingClientRect();
+ return badBidiRects = (r1.right - r0.right < 3);
+ }
+
+ // See if "".split is the broken IE version, if so, provide an
+ // alternative way to split lines.
+ var splitLines = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
+ var pos = 0, result = [], l = string.length;
+ while (pos <= l) {
+ var nl = string.indexOf("\n", pos);
+ if (nl == -1) nl = string.length;
+ var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
+ var rt = line.indexOf("\r");
+ if (rt != -1) {
+ result.push(line.slice(0, rt));
+ pos += rt + 1;
+ } else {
+ result.push(line);
+ pos = nl + 1;
+ }
+ }
+ return result;
+ } : function(string){return string.split(/\r\n?|\n/);};
+
+ var hasSelection = window.getSelection ? function(te) {
+ try { return te.selectionStart != te.selectionEnd; }
+ catch(e) { return false; }
+ } : function(te) {
+ try {var range = te.ownerDocument.selection.createRange();}
+ catch(e) {}
+ if (!range || range.parentElement() != te) return false;
+ return range.compareEndPoints("StartToEnd", range) != 0;
+ };
+
+ var hasCopyEvent = (function() {
+ var e = elt("div");
+ if ("oncopy" in e) return true;
+ e.setAttribute("oncopy", "return;");
+ return typeof e.oncopy == "function";
+ })();
+
+ var badZoomedRects = null;
+ function hasBadZoomedRects(measure) {
+ if (badZoomedRects != null) return badZoomedRects;
+ var node = removeChildrenAndAdd(measure, elt("span", "x"));
+ var normal = node.getBoundingClientRect();
+ var fromRange = range(node, 0, 1).getBoundingClientRect();
+ return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1;
+ }
+
+ // KEY NAMES
+
+ var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
+ 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
+ 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
+ 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete",
+ 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
+ 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
+ 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"};
+ CodeMirror.keyNames = keyNames;
+ (function() {
+ // Number keys
+ for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i);
+ // Alphabetic keys
+ for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
+ // Function keys
+ for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
+ })();
+
+ // BIDI HELPERS
+
+ function iterateBidiSections(order, from, to, f) {
+ if (!order) return f(from, to, "ltr");
+ var found = false;
+ for (var i = 0; i < order.length; ++i) {
+ var part = order[i];
+ if (part.from < to && part.to > from || from == to && part.to == from) {
+ f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr");
+ found = true;
+ }
+ }
+ if (!found) f(from, to, "ltr");
+ }
+
+ function bidiLeft(part) { return part.level % 2 ? part.to : part.from; }
+ function bidiRight(part) { return part.level % 2 ? part.from : part.to; }
+
+ function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; }
+ function lineRight(line) {
+ var order = getOrder(line);
+ if (!order) return line.text.length;
+ return bidiRight(lst(order));
+ }
+
+ function lineStart(cm, lineN) {
+ var line = getLine(cm.doc, lineN);
+ var visual = visualLine(line);
+ if (visual != line) lineN = lineNo(visual);
+ var order = getOrder(visual);
+ var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual);
+ return Pos(lineN, ch);
+ }
+ function lineEnd(cm, lineN) {
+ var merged, line = getLine(cm.doc, lineN);
+ while (merged = collapsedSpanAtEnd(line)) {
+ line = merged.find(1, true).line;
+ lineN = null;
+ }
+ var order = getOrder(line);
+ var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line);
+ return Pos(lineN == null ? lineNo(line) : lineN, ch);
+ }
+ function lineStartSmart(cm, pos) {
+ var start = lineStart(cm, pos.line);
+ var line = getLine(cm.doc, start.line);
+ var order = getOrder(line);
+ if (!order || order[0].level == 0) {
+ var firstNonWS = Math.max(0, line.text.search(/\S/));
+ var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
+ return Pos(start.line, inWS ? 0 : firstNonWS);
+ }
+ return start;
+ }
+
+ function compareBidiLevel(order, a, b) {
+ var linedir = order[0].level;
+ if (a == linedir) return true;
+ if (b == linedir) return false;
+ return a < b;
+ }
+ var bidiOther;
+ function getBidiPartAt(order, pos) {
+ bidiOther = null;
+ for (var i = 0, found; i < order.length; ++i) {
+ var cur = order[i];
+ if (cur.from < pos && cur.to > pos) return i;
+ if ((cur.from == pos || cur.to == pos)) {
+ if (found == null) {
+ found = i;
+ } else if (compareBidiLevel(order, cur.level, order[found].level)) {
+ if (cur.from != cur.to) bidiOther = found;
+ return i;
+ } else {
+ if (cur.from != cur.to) bidiOther = i;
+ return found;
+ }
+ }
+ }
+ return found;
+ }
+
+ function moveInLine(line, pos, dir, byUnit) {
+ if (!byUnit) return pos + dir;
+ do pos += dir;
+ while (pos > 0 && isExtendingChar(line.text.charAt(pos)));
+ return pos;
+ }
+
+ // This is needed in order to move 'visually' through bi-directional
+ // text -- i.e., pressing left should make the cursor go left, even
+ // when in RTL text. The tricky part is the 'jumps', where RTL and
+ // LTR text touch each other. This often requires the cursor offset
+ // to move more than one unit, in order to visually move one unit.
+ function moveVisually(line, start, dir, byUnit) {
+ var bidi = getOrder(line);
+ if (!bidi) return moveLogically(line, start, dir, byUnit);
+ var pos = getBidiPartAt(bidi, start), part = bidi[pos];
+ var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit);
+
+ for (;;) {
+ if (target > part.from && target < part.to) return target;
+ if (target == part.from || target == part.to) {
+ if (getBidiPartAt(bidi, target) == pos) return target;
+ part = bidi[pos += dir];
+ return (dir > 0) == part.level % 2 ? part.to : part.from;
+ } else {
+ part = bidi[pos += dir];
+ if (!part) return null;
+ if ((dir > 0) == part.level % 2)
+ target = moveInLine(line, part.to, -1, byUnit);
+ else
+ target = moveInLine(line, part.from, 1, byUnit);
+ }
+ }
+ }
+
+ function moveLogically(line, start, dir, byUnit) {
+ var target = start + dir;
+ if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir;
+ return target < 0 || target > line.text.length ? null : target;
+ }
+
+ // Bidirectional ordering algorithm
+ // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
+ // that this (partially) implements.
+
+ // One-char codes used for character types:
+ // L (L): Left-to-Right
+ // R (R): Right-to-Left
+ // r (AL): Right-to-Left Arabic
+ // 1 (EN): European Number
+ // + (ES): European Number Separator
+ // % (ET): European Number Terminator
+ // n (AN): Arabic Number
+ // , (CS): Common Number Separator
+ // m (NSM): Non-Spacing Mark
+ // b (BN): Boundary Neutral
+ // s (B): Paragraph Separator
+ // t (S): Segment Separator
+ // w (WS): Whitespace
+ // N (ON): Other Neutrals
+
+ // Returns null if characters are ordered as they appear
+ // (left-to-right), or an array of sections ({from, to, level}
+ // objects) in the order in which they occur visually.
+ var bidiOrdering = (function() {
+ // Character types for codepoints 0 to 0xff
+ var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
+ // Character types for codepoints 0x600 to 0x6ff
+ var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm";
+ function charType(code) {
+ if (code <= 0xf7) return lowTypes.charAt(code);
+ else if (0x590 <= code && code <= 0x5f4) return "R";
+ else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600);
+ else if (0x6ee <= code && code <= 0x8ac) return "r";
+ else if (0x2000 <= code && code <= 0x200b) return "w";
+ else if (code == 0x200c) return "b";
+ else return "L";
+ }
+
+ var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
+ var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
+ // Browsers seem to always treat the boundaries of block elements as being L.
+ var outerType = "L";
+
+ function BidiSpan(level, from, to) {
+ this.level = level;
+ this.from = from; this.to = to;
+ }
+
+ return function(str) {
+ if (!bidiRE.test(str)) return false;
+ var len = str.length, types = [];
+ for (var i = 0, type; i < len; ++i)
+ types.push(type = charType(str.charCodeAt(i)));
+
+ // W1. Examine each non-spacing mark (NSM) in the level run, and
+ // change the type of the NSM to the type of the previous
+ // character. If the NSM is at the start of the level run, it will
+ // get the type of sor.
+ for (var i = 0, prev = outerType; i < len; ++i) {
+ var type = types[i];
+ if (type == "m") types[i] = prev;
+ else prev = type;
+ }
+
+ // W2. Search backwards from each instance of a European number
+ // until the first strong type (R, L, AL, or sor) is found. If an
+ // AL is found, change the type of the European number to Arabic
+ // number.
+ // W3. Change all ALs to R.
+ for (var i = 0, cur = outerType; i < len; ++i) {
+ var type = types[i];
+ if (type == "1" && cur == "r") types[i] = "n";
+ else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; }
+ }
+
+ // W4. A single European separator between two European numbers
+ // changes to a European number. A single common separator between
+ // two numbers of the same type changes to that type.
+ for (var i = 1, prev = types[0]; i < len - 1; ++i) {
+ var type = types[i];
+ if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1";
+ else if (type == "," && prev == types[i+1] &&
+ (prev == "1" || prev == "n")) types[i] = prev;
+ prev = type;
+ }
+
+ // W5. A sequence of European terminators adjacent to European
+ // numbers changes to all European numbers.
+ // W6. Otherwise, separators and terminators change to Other
+ // Neutral.
+ for (var i = 0; i < len; ++i) {
+ var type = types[i];
+ if (type == ",") types[i] = "N";
+ else if (type == "%") {
+ for (var end = i + 1; end < len && types[end] == "%"; ++end) {}
+ var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
+ for (var j = i; j < end; ++j) types[j] = replace;
+ i = end - 1;
+ }
+ }
+
+ // W7. Search backwards from each instance of a European number
+ // until the first strong type (R, L, or sor) is found. If an L is
+ // found, then change the type of the European number to L.
+ for (var i = 0, cur = outerType; i < len; ++i) {
+ var type = types[i];
+ if (cur == "L" && type == "1") types[i] = "L";
+ else if (isStrong.test(type)) cur = type;
+ }
+
+ // N1. A sequence of neutrals takes the direction of the
+ // surrounding strong text if the text on both sides has the same
+ // direction. European and Arabic numbers act as if they were R in
+ // terms of their influence on neutrals. Start-of-level-run (sor)
+ // and end-of-level-run (eor) are used at level run boundaries.
+ // N2. Any remaining neutrals take the embedding direction.
+ for (var i = 0; i < len; ++i) {
+ if (isNeutral.test(types[i])) {
+ for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {}
+ var before = (i ? types[i-1] : outerType) == "L";
+ var after = (end < len ? types[end] : outerType) == "L";
+ var replace = before || after ? "L" : "R";
+ for (var j = i; j < end; ++j) types[j] = replace;
+ i = end - 1;
+ }
+ }
+
+ // Here we depart from the documented algorithm, in order to avoid
+ // building up an actual levels array. Since there are only three
+ // levels (0, 1, 2) in an implementation that doesn't take
+ // explicit embedding into account, we can build up the order on
+ // the fly, without following the level-based algorithm.
+ var order = [], m;
+ for (var i = 0; i < len;) {
+ if (countsAsLeft.test(types[i])) {
+ var start = i;
+ for (++i; i < len && countsAsLeft.test(types[i]); ++i) {}
+ order.push(new BidiSpan(0, start, i));
+ } else {
+ var pos = i, at = order.length;
+ for (++i; i < len && types[i] != "L"; ++i) {}
+ for (var j = pos; j < i;) {
+ if (countsAsNum.test(types[j])) {
+ if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j));
+ var nstart = j;
+ for (++j; j < i && countsAsNum.test(types[j]); ++j) {}
+ order.splice(at, 0, new BidiSpan(2, nstart, j));
+ pos = j;
+ } else ++j;
+ }
+ if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i));
+ }
+ }
+ if (order[0].level == 1 && (m = str.match(/^\s+/))) {
+ order[0].from = m[0].length;
+ order.unshift(new BidiSpan(0, 0, m[0].length));
+ }
+ if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
+ lst(order).to -= m[0].length;
+ order.push(new BidiSpan(0, len - m[0].length, len));
+ }
+ if (order[0].level != lst(order).level)
+ order.push(new BidiSpan(order[0].level, len, len));
+
+ return order;
+ };
+ })();
+
+ // THE END
+
+ CodeMirror.version = "5.1.1";
+
+ return CodeMirror;
+});
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/d3.min.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/d3.min.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/d3.min.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/d3.min.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/invoker-lib.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/invoker-lib.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/invoker-lib.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/invoker-lib.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/jquery-ui.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/jquery-ui.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/jquery-ui.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/jquery-ui.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/jquery.daterangepicker.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/jquery.daterangepicker.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/jquery.daterangepicker.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/jquery.daterangepicker.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/jquery.form.min.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/jquery.form.min.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/jquery.form.min.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/jquery.form.min.js
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/js.cookie.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/js.cookie.js
new file mode 100644
index 0000000000..0d5b970c87
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/js.cookie.js
@@ -0,0 +1,147 @@
+/*!
+ * Javascript Cookie v2.0.0-pre
+ * https://github.com/js-cookie/js-cookie
+ *
+ * Copyright 2006, 2014 Klaus Hartl
+ * Released under the MIT license
+ */
+(function (factory) {
+ var jQuery;
+ if (typeof define === 'function' && define.amd) {
+ // AMD (Register as an anonymous module)
+ define(['jquery'], factory);
+ } else if (typeof exports === 'object') {
+ // Node/CommonJS
+ try {
+ jQuery = require('jquery');
+ } catch(e) {}
+ module.exports = factory(jQuery);
+ } else {
+ // Browser globals
+ var _OldCookies = window.Cookies;
+ var api = window.Cookies = factory(window.jQuery);
+ api.noConflict = function() {
+ window.Cookies = _OldCookies;
+ return api;
+ };
+ }
+}(function ($) {
+
+ var pluses = /\+/g;
+
+ function encode(s) {
+ return api.raw ? s : encodeURIComponent(s);
+ }
+
+ function decode(s) {
+ return api.raw ? s : decodeURIComponent(s);
+ }
+
+ function stringifyCookieValue(value) {
+ return encode(api.json ? JSON.stringify(value) : String(value));
+ }
+
+ function parseCookieValue(s) {
+ if (s.indexOf('"') === 0) {
+ // This is a quoted cookie as according to RFC2068, unescape...
+ s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
+ }
+
+ try {
+ // Replace server-side written pluses with spaces.
+ // If we can't decode the cookie, ignore it, it's unusable.
+ // If we can't parse the cookie, ignore it, it's unusable.
+ s = decodeURIComponent(s.replace(pluses, ' '));
+ return api.json ? JSON.parse(s) : s;
+ } catch(e) {}
+ }
+
+ function read(s, converter) {
+ var value = api.raw ? s : parseCookieValue(s);
+ return isFunction(converter) ? converter(value) : value;
+ }
+
+ function extend() {
+ var key, options;
+ var i = 0;
+ var result = {};
+ for (; i < arguments.length; i++) {
+ options = arguments[ i ];
+ for (key in options) {
+ result[key] = options[key];
+ }
+ }
+ return result;
+ }
+
+ function isFunction(obj) {
+ return Object.prototype.toString.call(obj) === '[object Function]';
+ }
+
+ var api = function (key, value, options) {
+
+ // Write
+
+ if (arguments.length > 1 && !isFunction(value)) {
+ options = extend(api.defaults, options);
+
+ if (typeof options.expires === 'number') {
+ var days = options.expires, t = options.expires = new Date();
+ t.setMilliseconds(t.getMilliseconds() + days * 864e+5);
+ }
+
+ return (document.cookie = [
+ encode(key), '=', stringifyCookieValue(value),
+ options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
+ options.path ? '; path=' + options.path : '',
+ options.domain ? '; domain=' + options.domain : '',
+ options.secure ? '; secure' : ''
+ ].join(''));
+ }
+
+ // Read
+
+ var result = key ? undefined : {},
+ // To prevent the for loop in the first place assign an empty array
+ // in case there are no cookies at all. Also prevents odd result when
+ // calling "get()".
+ cookies = document.cookie ? document.cookie.split('; ') : [],
+ i = 0,
+ l = cookies.length;
+
+ for (; i < l; i++) {
+ var parts = cookies[i].split('='),
+ name = decode(parts.shift()),
+ cookie = parts.join('=');
+
+ if (key === name) {
+ // If second argument (value) is a function it's a converter...
+ result = read(cookie, value);
+ break;
+ }
+
+ // Prevent storing a cookie that we couldn't decode.
+ if (!key && (cookie = read(cookie)) !== undefined) {
+ result[name] = cookie;
+ }
+ }
+
+ return result;
+ };
+
+ api.get = api.set = api;
+ api.defaults = {};
+
+ api.remove = function (key, options) {
+ // Must not alter options, thus extending a fresh object...
+ api(key, '', extend(options, { expires: -1 }));
+ return !api(key);
+ };
+
+ if ( $ ) {
+ $.cookie = api;
+ $.removeCookie = api.remove;
+ }
+
+ return api;
+}));
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/moment.min.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/moment.min.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/moment.min.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/moment.min.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/rickshaw.min.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/rickshaw.min.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/rickshaw.min.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/rickshaw.min.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/select2.full.min.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/select2.full.min.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/select2.full.min.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/select2.full.min.js
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/sql.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/sql.js
new file mode 100644
index 0000000000..9097d1074f
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/sql.js
@@ -0,0 +1,312 @@
+/*Copyright (C) 2015 by Marijn Haverbeke and others
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.*/
+
+/*Annotations, Annotation Names and relevant tokens*/
+var ANNOTATION_IMPORT = "Import";
+var ANNOTATION_EXPORT = "Export";
+
+var ANNOTATION_TOKEN_AT = "@";
+var ANNOTATION_TOKEN_OPENING_BRACKET = "(";
+var ANNOTATION_TOKEN_CLOSING_BRACKET = ")";
+
+var REGEX_LINE_STARTING_WITH_PLAN = /^@Plan.*/g;
+var REGEX_LINE_STARTING_WITH_SINGLE_LINE_COMMENT = /^--.*/g;
+var REGEX_LINE_STARTING_WITH_MULTI_LINE_COMMENT = /^\/\*.*\*\//g;
+var REGEX_LINE_STARTING_WITH_IMPORT_STATEMENT = /^@Import.*/g;
+
+var SIDDHI_STATEMENT_DELIMETER = ";";
+var SIDDHI_LINE_BREAK = "\n";
+var SIDDHI_LINE_BREAK_CHARACTER = '\n';
+var SIDDHI_SINGLE_QUOTE = "'";
+var SIDDHI_SPACE_LITERAL = " ";
+
+var SIDDHI_LITERAL_DEFINE_STREAM = "define stream";
+
+var MIME_TYPE_SIDDHI_QL = "text/siddhi-ql";
+
+
+CodeMirror.defineMode("sql", function (config, parserConfig) {
+ "use strict";
+
+ var client = parserConfig.client || {},
+ atoms = parserConfig.atoms || {"false":true, "true":true, "null":true},
+ builtin = parserConfig.builtin || {},
+ keywords = parserConfig.keywords || {},
+ operatorChars = parserConfig.operatorChars || /^[*+\-%<>!=&|~^]/,
+ support = parserConfig.support || {},
+ hooks = parserConfig.hooks || {},
+ dateSQL = parserConfig.dateSQL || {"date":true, "time":true, "timestamp":true};
+
+ function tokenBase(stream, state) {
+ var ch = stream.next();
+
+ // call hooks from the mime type
+ if (hooks[ch]) {
+ var result = hooks[ch](stream, state);
+ if (result !== false) return result;
+ }
+
+ if (ch.charCodeAt(0) > 47 && ch.charCodeAt(0) < 58) {
+ // numbers
+ // ref: http://dev.mysql.com/doc/refman/5.5/en/number-literals.html
+ stream.match(/^[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/);
+ support.decimallessFloat == true && stream.eat('.');
+ return "number";
+ } else if (ch == "'" || (ch == '"' && support.doubleQuote)) {
+ // strings
+ // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html
+ state.tokenize = tokenLiteral(ch);
+ return state.tokenize(stream, state);
+ } else if (/^[\(\),\;\[\]]/.test(ch)) {
+ // no highlightning
+ return null;
+ } else if ((ch == "-" && stream.eat("-") && (!support.commentSpaceRequired || stream.eat(" ")))) {
+ // 1-line comments
+ // ref: https://kb.askmonty.org/en/comment-syntax/
+ stream.skipToEnd();
+ return "comment";
+ } else if (ch == "/" && stream.eat("*")) {
+ // multi-line comments
+ // ref: https://kb.askmonty.org/en/comment-syntax/
+ state.tokenize = tokenComment;
+ return state.tokenize(stream, state);
+ } else if (ch == ".") {
+ // .1 for 0.1
+ if (support.zerolessFloat == true && stream.match(/^(?:\d+(?:e[+-]?\d+)?)/i)) {
+ return "number";
+ }
+ } else {
+ stream.eatWhile(/^[_\-\w\d]/); /* Character '-' will also be eaten, to prevent the highlight happening in keywords being embedded in non-keyword strings. For example, 'all' in 'all-nonkeyword' */
+ var word = stream.current().toLowerCase(); // Added toLowerCase() to highlight keywords in a case insensitive manner.
+ // dates (standard SQL syntax)
+ // ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html
+ if (dateSQL.hasOwnProperty(word) && (stream.match(/^( )+'[^']*'/) || stream.match(/^( )+"[^"]*"/)))
+ return "number";
+ if (atoms.hasOwnProperty(word)) return "atom";
+ if (builtin.hasOwnProperty(word)) return "builtin";
+ if (keywords.hasOwnProperty(word)) return "keyword";
+ if (client.hasOwnProperty(word)) return "string-2";
+ return null;
+ }
+ }
+
+ // 'string', with char specified in quote escaped by '\'
+ function tokenLiteral(quote) {
+ return function (stream, state) {
+ var escaped = false, ch;
+ while ((ch = stream.next()) != null) {
+ if (ch == quote && !escaped) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ escaped = !escaped && ch == "\\";
+ }
+ return "string";
+ };
+ }
+
+ function tokenComment(stream, state) {
+ while (true) {
+ if (stream.skipTo("*")) {
+ stream.next();
+ if (stream.eat("/")) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ } else {
+ stream.skipToEnd();
+ break;
+ }
+ }
+ return "comment";
+ }
+
+ function pushContext(stream, state, type) {
+ state.context = {
+ prev:state.context,
+ indent:stream.indentation(),
+ col:stream.column(),
+ type:type
+ };
+ }
+
+ function popContext(state) {
+ state.indent = state.context.indent;
+ state.context = state.context.prev;
+ }
+
+ return {
+ startState:function () {
+ return {tokenize:tokenBase, context:null};
+ },
+
+ token:function (stream, state) {
+ if (stream.sol()) {
+ if (state.context && state.context.align == null)
+ state.context.align = false;
+ }
+ if (stream.eatSpace()) return null;
+
+ var style = state.tokenize(stream, state);
+ if (style == "comment") return style;
+
+ if (state.context && state.context.align == null)
+ state.context.align = true;
+
+ var tok = stream.current();
+ if (tok == "(")
+ pushContext(stream, state, ")");
+ else if (tok == "[")
+ pushContext(stream, state, "]");
+ else if (state.context && state.context.type == tok)
+ popContext(state);
+ return style;
+ },
+
+ indent:function (state, textAfter) {
+ var cx = state.context;
+ if (!cx) return CodeMirror.Pass;
+ var closing = textAfter.charAt(0) == cx.type;
+ if (cx.align) return cx.col + (closing ? 0 : 1);
+ else return cx.indent + (closing ? 0 : config.indentUnit);
+ },
+
+ blockCommentStart: "/*",
+ blockCommentEnd: "*/",
+ lineComment: "--"
+ };
+});
+
+(function () {
+ "use strict";
+
+ // `identifier`
+ function hookIdentifier(stream) {
+ // MySQL/MariaDB identifiers
+ // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html
+ var ch;
+ while ((ch = stream.next()) != null) {
+ if (ch == "`" && !stream.eat("`")) return "variable-2";
+ }
+ stream.backUp(stream.current().length - 1);
+ return stream.eatWhile(/\w/) ? "variable-2" : null;
+ }
+
+ // variable token
+ function hookVar(stream) {
+ // variables
+ // @@prefix.varName @varName
+ // varName can be quoted with ` or ' or "
+ // ref: http://dev.mysql.com/doc/refman/5.5/en/user-variables.html
+ if (stream.eat("@")) {
+ stream.match(/^session\./);
+ stream.match(/^local\./);
+ stream.match(/^global\./);
+ }
+
+ if (stream.eat("'")) {
+ stream.match(/^.*'/);
+ return "variable-2";
+ } else if (stream.eat('"')) {
+ stream.match(/^.*"/);
+ return "variable-2";
+ } else if (stream.eat("`")) {
+ stream.match(/^.*`/);
+ return "variable-2";
+ } else if (stream.match(/^[0-9a-zA-Z$\.\_]+/)) {
+ return "variable-2";
+ }
+ return null;
+ }
+
+ ;
+
+ // short client keyword token
+ function hookClient(stream) {
+ // \N means NULL
+ // ref: http://dev.mysql.com/doc/refman/5.5/en/null-values.html
+ if (stream.eat("N")) {
+ return "atom";
+ }
+ // \g, etc
+ // ref: http://dev.mysql.com/doc/refman/5.5/en/mysql-commands.html
+ return stream.match(/^[a-zA-Z.#!?]/) ? "variable-2" : null;
+ }
+
+ // these keywords are used by all SQL dialects (however, a mode can still overwrite it)
+ var sqlKeywordsWithoutSymbols = "all and as begin by contains define delete end events " +
+ "every first for from full group having inner insert into join last " +
+ "left not of on or outer output partition raw return right select snapshot stream table ";
+ var sqlKeywords = ", : ? # ( ) " + sqlKeywordsWithoutSymbols;
+ var builtIn = "bool double float int long object string ";
+ var atoms = "false true null ";
+ var dateSQL = "days hours milliseconds minutes months seconds ";
+ var allSqlSuggestions = sqlKeywordsWithoutSymbols + builtIn + atoms + dateSQL;
+
+ // turn a space-separated list into an array
+ function set(str) {
+ var obj = {}, words = str.split(" ");
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+ return obj;
+ }
+
+ // A generic SQL Mode. It's not a standard, it just try to support what is generally supported
+ CodeMirror.defineMIME(MIME_TYPE_SIDDHI_QL, {
+ name:"sql",
+ keywords:set(sqlKeywords),
+ builtin:set(builtIn),
+ atoms:set(atoms),
+ operatorChars:/^[*+%<>!=/]/,
+ dateSQL:set(dateSQL),
+ support:set("doubleQuote "),
+ allSqlSuggestions:set(allSqlSuggestions)
+ });
+}());
+
+/*
+ How Properties of Mime Types are used by SQL Mode
+ =================================================
+
+ keywords:
+ A list of keywords you want to be highlighted.
+ functions:
+ A list of function names you want to be highlighted.
+ builtin:
+ A list of builtin types you want to be highlighted (if you want types to be of class "builtin" instead of "keyword").
+ operatorChars:
+ All characters that must be handled as operators.
+ client:
+ Commands parsed and executed by the client (not the server).
+ support:
+ A list of supported syntaxes which are not common, but are supported by more than 1 DBMS.
+ * ODBCdotTable: .tableName
+ * zerolessFloat: .1
+ * doubleQuote
+ * nCharCast: N'string'
+ * charsetCast: _utf8'string'
+ * commentHash: use # char for comments
+ * commentSlashSlash: use // for comments
+ * commentSpaceRequired: require a space after -- for comments
+ atoms:
+ Keywords that must be highlighted as atoms,. Some DBMS's support more atoms than others:
+ UNKNOWN, INFINITY, UNDERFLOW, NaN...
+ dateSQL:
+ Used for date/time SQL standard syntax, because not all DBMS's support same temporal types.
+ */
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/utils.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/utils.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/utils.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/libs/utils.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/policy-add.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/policy-add.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/policy-add.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/policy-add.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/policy-listing.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/policy-listing.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/policy-listing.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/js/policy-listing.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/pages/2-column-right.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/pages/2-column-right.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/pages/2-column-right.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/pages/2-column-right.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/advanced-search-body.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/advanced-search-body.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/advanced-search-body.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/advanced-search-body.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/analytics.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/analytics.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/analytics.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/analytics.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/device-details.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/device-details.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/device-details.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/device-details.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/device-listing.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/device-listing.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/device-listing.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/device-listing.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/events.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/events.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/events.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/events.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/footer.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/footer.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/footer.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/footer.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/group-add.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/group-add.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/group-add.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/group-add.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/group-listing.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/group-listing.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/group-listing.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/group-listing.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/navigation.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/navigation.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/navigation.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/navigation.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/policies-body.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/policies-body.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/policies-body.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/policies-body.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/policy-add.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/policy-add.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/policy-add.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/policy-add.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/policy-listing.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/policy-listing.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/policy-listing.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/policy-listing.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/product-title.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/product-title.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/product-title.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/product-title.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/users-body.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/users-body.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/users-body.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/partials/users-body.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/advanced-search.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/advanced-search.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/advanced-search.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/advanced-search.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/analytics.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/analytics.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/analytics.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/analytics.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/details.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/details.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/details.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/details.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/device_details.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/device_details.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/device_details.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/device_details.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/device_listing.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/device_listing.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/device_listing.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/device_listing.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/events.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/events.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/events.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/events.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/groups.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/groups.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/groups.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/groups.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/policies.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/policies.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/policies.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/policies.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/users.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/users.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/users.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/app/store-device-type/themes/store/renderers/pages/users.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/apis/assets.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/apis/assets.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/apis/assets.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/apis/assets.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/apis/rate.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/apis/rate.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/apis/rate.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/apis/rate.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/apis/subscriptions.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/apis/subscriptions.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/apis/subscriptions.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/apis/subscriptions.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/asset.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/asset.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/asset.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/asset.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/pages/details.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/pages/details.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/pages/details.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/pages/details.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/pages/list.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/pages/list.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/pages/list.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/pages/list.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/pages/subscriptions.jag b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/pages/subscriptions.jag
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/pages/subscriptions.jag
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/pages/subscriptions.jag
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/permissions.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/permissions.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/permissions.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/default/permissions.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/asset.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/asset.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/asset.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/asset.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/helpers/asset.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/helpers/asset.js
similarity index 96%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/helpers/asset.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/helpers/asset.js
index 3adef209d4..c0d921d8a7 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/helpers/asset.js
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/helpers/asset.js
@@ -1,78 +1,78 @@
-/*
- * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
- *
- * WSO2 Inc. licenses this file to you under the Apache License,
- * Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-var resources = function (page, meta) {
- return {
- js: ['jquery.rating.pack.js', 'async.min.js', 'asset-core.js', 'asset.js','porthole.min.js', 'device-details.js', 'assets.js'],
- css: ['jquery.rating.css', 'asset.css'],
- code: ['store.asset.hbs']
- };
-};
-
-var format = function (context) {
- //adding enriched context for paginating template
- var log = new Log();
- var avg = context.asset.rating.average;
-
- if(context.type === 'gadget') {
- context.asset_css = "cog";
-
- }else if (context.type === 'site'){
- context.asset_css = "globe";
-
- }else if(context.type === 'ebook'){
- context.asset_css = "book";
-
- }else{
- context.asset_css = "link";
- }
-
- context.asset.rating.ratingPx = ratingToPixels(avg);
-
- return context;
-};
-
-var formatRatings = function(context){
- var avg;
- for(var i in context){
- avg = context[i].rating;
- context[i].ratingPx = ratingToPixels(avg);
- }
-
- return context;
-}
-
-var formatAssetFromProviderRatings=function(context){
- var avg;
- var assets=context.assets;
- for(var i in assets){
- avg = assets[i].rating.average;
- assets[i].ratingPx = ratingToPixels(avg);
- }
-
- return context;
-};
-
-var ratingToPixels = function(avg) {
- var STAR_WIDTH = 84;
- var MAX_RATING = 5;
-
- var ratingPx = (avg / MAX_RATING) * STAR_WIDTH;
- return ratingPx;
-}
-
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+var resources = function (page, meta) {
+ return {
+ js: ['jquery.rating.pack.js', 'async.min.js', 'asset-core.js', 'asset.js','porthole.min.js', 'device-details.js', 'assets.js'],
+ css: ['jquery.rating.css', 'asset.css'],
+ code: ['store.asset.hbs']
+ };
+};
+
+var format = function (context) {
+ //adding enriched context for paginating template
+ var log = new Log();
+ var avg = context.asset.rating.average;
+
+ if(context.type === 'gadget') {
+ context.asset_css = "cog";
+
+ }else if (context.type === 'site'){
+ context.asset_css = "globe";
+
+ }else if(context.type === 'ebook'){
+ context.asset_css = "book";
+
+ }else{
+ context.asset_css = "link";
+ }
+
+ context.asset.rating.ratingPx = ratingToPixels(avg);
+
+ return context;
+};
+
+var formatRatings = function(context){
+ var avg;
+ for(var i in context){
+ avg = context[i].rating;
+ context[i].ratingPx = ratingToPixels(avg);
+ }
+
+ return context;
+}
+
+var formatAssetFromProviderRatings=function(context){
+ var avg;
+ var assets=context.assets;
+ for(var i in assets){
+ avg = assets[i].rating.average;
+ assets[i].ratingPx = ratingToPixels(avg);
+ }
+
+ return context;
+};
+
+var ratingToPixels = function(avg) {
+ var STAR_WIDTH = 84;
+ var MAX_RATING = 5;
+
+ var ratingPx = (avg / MAX_RATING) * STAR_WIDTH;
+ return ratingPx;
+}
+
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/js/assets.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/js/assets.js
similarity index 96%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/js/assets.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/js/assets.js
index c849d98ae3..b6c2531f7a 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/js/assets.js
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/js/assets.js
@@ -1,21 +1,21 @@
-var strVirtual = "virtual_";
-var foundVirtual = false;
-
-$('.real_devices .ast-name.truncate').each(function(){
- if($(this).attr('title').substr(0, strVirtual.length) == 'virtual_'){
- var parent = $(this).closest('.ctrl-wr-asset');
- parent.hide();
- foundVirtual = true;
- }
-});
-
-$('.virtual_devices .ast-name.truncate').each(function(){
- if($(this).attr('title').substr(0, strVirtual.length) != 'virtual_'){
- var parent = $(this).closest('.ctrl-wr-asset');
- parent.hide();
- }
-});
-
-if(foundVirtual){
- $(".try-device-message").removeClass("hidden");
+var strVirtual = "virtual_";
+var foundVirtual = false;
+
+$('.real_devices .ast-name.truncate').each(function(){
+ if($(this).attr('title').substr(0, strVirtual.length) == 'virtual_'){
+ var parent = $(this).closest('.ctrl-wr-asset');
+ parent.hide();
+ foundVirtual = true;
+ }
+});
+
+$('.virtual_devices .ast-name.truncate').each(function(){
+ if($(this).attr('title').substr(0, strVirtual.length) != 'virtual_'){
+ var parent = $(this).closest('.ctrl-wr-asset');
+ parent.hide();
+ }
+});
+
+if(foundVirtual){
+ $(".try-device-message").removeClass("hidden");
}
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/js/device-details.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/js/device-details.js
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/js/device-details.js
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/js/device-details.js
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/pages/2-column-right.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/pages/2-column-right.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/pages/2-column-right.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/pages/2-column-right.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/assert-action-link.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/assert-action-link.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/assert-action-link.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/assert-action-link.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/asset.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/asset.hbs
similarity index 98%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/asset.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/asset.hbs
index 7da84f21c9..c27bdd6325 100644
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/asset.hbs
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/asset.hbs
@@ -1,112 +1,112 @@
-
-
-
- {{#with assets}}
-
-
- {{#with attributes}}
-
-
-
-
-
-
Summary
-
{{>overview .}}
-
- {{>tags ../../.}}
- {{>share ../..}}
-
-
-
-
-
-
-
-
-
-
-
- {{>overview .}}
- {{>quick-startup-steps}}
-
-
-
-
- {{>hardware-setup ..}}
-
-
-
- {{#hasAssetPermission . key="ASSET_REVIEWS" type=../../rxt.shortName username=../../cuser.username tenantId=../../cuser.tenantId}}
-
- {{#if ../../../features.social.enabled}}
-
- {{/if}}
- {{#if ../../../inDashboard}}
-
- {{else}}
-
- {{/if}}
-
- {{/hasAssetPermission}}
-
-
- {{/with}}
- {{/with}}
+
+
+
+ {{#with assets}}
+
+
+ {{#with attributes}}
+
+
+
+
+
+
Summary
+
{{>overview .}}
+
+ {{>tags ../../.}}
+ {{>share ../..}}
+
+
+
+
+
+
+
+
+
+
+
+ {{>overview .}}
+ {{>quick-startup-steps}}
+
+
+
+
+ {{>hardware-setup ..}}
+
+
+
+ {{#hasAssetPermission . key="ASSET_REVIEWS" type=../../rxt.shortName username=../../cuser.username tenantId=../../cuser.tenantId}}
+
+ {{#if ../../../features.social.enabled}}
+
+ {{/if}}
+ {{#if ../../../inDashboard}}
+
+ {{else}}
+
+ {{/if}}
+
+ {{/hasAssetPermission}}
+
+
+ {{/with}}
+ {{/with}}
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/assets.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/assets.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/assets.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/assets.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/footer.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/footer.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/footer.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/footer.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/hardware-setup.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/hardware-setup.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/hardware-setup.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/hardware-setup.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/navigation.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/navigation.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/navigation.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/navigation.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/overview.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/overview.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/overview.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/overview.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/process-asset-text.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/process-asset-text.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/process-asset-text.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/process-asset-text.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/processed-asset-text.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/processed-asset-text.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/processed-asset-text.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/processed-asset-text.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/product-title.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/product-title.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/product-title.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/product-title.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/quick-startup-steps.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/quick-startup-steps.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/quick-startup-steps.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/quick-startup-steps.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/share.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/share.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/share.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/share.hbs
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/sort-assets.hbs b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/sort-assets.hbs
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/sort-assets.hbs
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/themes/store/partials/sort-assets.hbs
diff --git a/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/workflows/asset_create.js b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/workflows/asset_create.js
new file mode 100644
index 0000000000..813f5dd35f
--- /dev/null
+++ b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/jaggeryapps/store/extensions/assets/deviceType/workflows/asset_create.js
@@ -0,0 +1,8 @@
+var log = new Log();
+var execute = function(req,res,session){
+ log.info('Executing the Device-Type asset create ');
+};
+
+var process = function(req,res,session){
+ log.info('Processing the Device-Type asset create');
+};
\ No newline at end of file
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/p2.inf b/features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/p2.inf
similarity index 100%
rename from features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/p2.inf
rename to features/device-mgt-iot-feature/org.wso2.carbon.device.mgt.iot.feature/src/main/resources/p2.inf
diff --git a/features/device-mgt-iot/pom.xml b/features/device-mgt-iot-feature/pom.xml
similarity index 100%
rename from features/device-mgt-iot/pom.xml
rename to features/device-mgt-iot-feature/pom.xml
diff --git a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/pom.xml b/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/pom.xml
deleted file mode 100644
index 8fad3d33bb..0000000000
--- a/features/device-mgt-iot/org.wso2.carbon.device.mgt.iot.feature/pom.xml
+++ /dev/null
@@ -1,168 +0,0 @@
-
-
-
-
-
- org.wso2.carbon.devicemgt-plugins
- device-mgt-iot-feature
- 1.9.2-SNAPSHOT
- ../pom.xml
-
-
- 4.0.0
- org.wso2.carbon.device.mgt.iot.feature
- pom
- 1.9.2-SNAPSHOT
- WSO2 Carbon - IoT Server - Features
- http://wso2.org
- This feature contains the core bundles required for IoT Server
-
-
-
- org.wso2.carbon.devicemgt-plugins
- org.wso2.carbon.device.mgt.iot
-
-
-
- org.wso2.carbon.devicemgt-plugins
- org.wso2.carbon.device.mgt.iot.api
- war
-
-
-
- org.json.wso2
- json
-
-
-
-
- org.igniterealtime.smack.wso2
- smack
-
-
- org.igniterealtime.smack.wso2
- smackx
-
-
-
- net.sf.ehcache.wso2
- ehcache
- 1.5.0.wso2v3
-
-
-
-
-
-
-
- maven-resources-plugin
-
-
- copy-resources
- generate-resources
-
- copy-resources
-
-
- src/main/resources
-
-
- resources
-
- build.properties
- p2.inf
-
-
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-dependency-plugin
-
-
- copy
- package
-
- copy
-
-
-
-
- org.wso2.carbon.devicemgt-plugins
- org.wso2.carbon.device.mgt.iot.api
- war
- true
- ${basedir}/src/main/resources/webapps/
- common.war
-
-
-
-
-
-
-
- org.wso2.maven
- carbon-p2-plugin
-
-
- p2-feature-generation
- package
-
- p2-feature-gen
-
-
- org.wso2.carbon.device.mgt.iot
- ../../../features/etc/feature.properties
-
-
- org.wso2.carbon.p2.category.type:server
- org.eclipse.equinox.p2.type.group:false
-
-
-
-
- org.wso2.carbon.devicemgt-plugins:org.wso2.carbon.device.mgt.iot:${carbon.iot.device.mgt.version}
-
-
- org.json.wso2:json:${commons-json.version}
-
-
- org.igniterealtime.smack.wso2:smack:${smack.wso2.version}
-
-
- org.igniterealtime.smack.wso2:smackx:${smackx.wso2.version}
-
-
- net.sf.ehcache.wso2:ehcache
-
-
-
- org.wso2.carbon.core.server:${carbon.kernel.version}
- org.wso2.carbon.device.mgt.server:${carbon.device.mgt.version}
-
-
-
-
-
-
-
-
diff --git a/pom.xml b/pom.xml
index b8c7f80f73..f1b1f1ee18 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,7 +12,7 @@
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- ~ KIND, either express or implied. See the License for the
+ ~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->
@@ -41,7 +41,7 @@
components/device-mgt-mdm
components/device-mgt-mdm-android
components/device-mgt-mdm-windows
-
features/device-mgt-iot
+
features/device-mgt-iot-feature
features/device-mgt-mdm
features/device-mgt-mdm-android
features/device-mgt-mdm-windows