From 797fcaf14ca1bfeb5778cbe526b3110f256862f2 Mon Sep 17 00:00:00 2001 From: Fraser Adams Date: Mon, 8 Apr 2013 15:19:04 +0000 Subject: QPID-3675: Java QMF2 API, REST API, QMF GUI and Java Broker QMF Management Plugin added to /tools/src/java git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1465662 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/tools/src/java/README-Java-Broker.txt | 350 ++ qpid/tools/src/java/README.txt | 73 + qpid/tools/src/java/bin/ConnectionAudit.sh | 35 + qpid/tools/src/java/bin/ConnectionLogger.sh | 35 + qpid/tools/src/java/bin/QpidConfig.sh | 35 + qpid/tools/src/java/bin/QpidCtrl.sh | 35 + qpid/tools/src/java/bin/QpidPrintEvents.sh | 35 + qpid/tools/src/java/bin/QpidQueueStats.sh | 35 + qpid/tools/src/java/bin/QpidRestAPI.sh | 35 + qpid/tools/src/java/bin/QueueFuse.sh | 35 + qpid/tools/src/java/bin/log4j.xml | 50 + .../bin/qpid-web/authentication/account.properties | 3 + .../src/java/bin/qpid-web/web/apple-touch-icon.png | Bin 0 -> 25357 bytes qpid/tools/src/java/bin/qpid-web/web/favicon.ico | Bin 0 -> 4286 bytes qpid/tools/src/java/bin/qpid-web/web/index.html | 38 + .../src/java/bin/qpid-web/web/itablet/css/LICENCE | 29 + .../bin/qpid-web/web/itablet/css/itablet-ie6.css | 302 ++ .../bin/qpid-web/web/itablet/css/itablet-ie7.css | 193 ++ .../bin/qpid-web/web/itablet/css/itablet-ie8.css | 140 + .../bin/qpid-web/web/itablet/css/itablet-ie9.css | 24 + .../java/bin/qpid-web/web/itablet/css/itablet.css | 973 ++++++ .../bin/qpid-web/web/itablet/images/action.png | Bin 0 -> 1253 bytes .../java/bin/qpid-web/web/itablet/images/add.png | Bin 0 -> 2042 bytes .../java/bin/qpid-web/web/itablet/images/bin.png | Bin 0 -> 889 bytes .../web/itablet/images/blue-button-sprite.png | Bin 0 -> 2102 bytes .../qpid-web/web/itablet/images/blue-chevron.png | Bin 0 -> 1615 bytes .../bin/qpid-web/web/itablet/images/blueball.png | Bin 0 -> 851 bytes .../qpid-web/web/itablet/images/button-sprite.png | Bin 0 -> 2405 bytes .../qpid-web/web/itablet/images/chevron-active.png | Bin 0 -> 308 bytes .../bin/qpid-web/web/itablet/images/chevron.png | Bin 0 -> 259 bytes .../bin/qpid-web/web/itablet/images/delete.png | Bin 0 -> 5361 bytes .../java/bin/qpid-web/web/itablet/images/flag.png | Bin 0 -> 1068 bytes .../java/bin/qpid-web/web/itablet/images/home.png | Bin 0 -> 727 bytes .../web/itablet/images/ie/active-gradient.png | Bin 0 -> 174 bytes .../web/itablet/images/ie/blue-button-sprite.gif | Bin 0 -> 2214 bytes .../web/itablet/images/ie/blue-chevron.gif | Bin 0 -> 763 bytes .../web/itablet/images/ie/button-sprite.gif | Bin 0 -> 2287 bytes .../web/itablet/images/ie/chevron-active.gif | Bin 0 -> 166 bytes .../bin/qpid-web/web/itablet/images/ie/chevron.gif | Bin 0 -> 97 bytes .../web/itablet/images/ie/header-gradient.png | Bin 0 -> 204 bytes .../web/itablet/images/ie/radial-gradient.png | Bin 0 -> 865 bytes .../web/itablet/images/ie/radius-10px-sprite.png | Bin 0 -> 750 bytes .../web/itablet/images/ie/radius-5px-sprite.png | Bin 0 -> 212 bytes .../bin/qpid-web/web/itablet/images/ie/red6.png | Bin 0 -> 187 bytes .../bin/qpid-web/web/itablet/images/ie/smoked.png | Bin 0 -> 187 bytes .../qpid-web/web/itablet/images/ie/tick-active.gif | Bin 0 -> 101 bytes .../bin/qpid-web/web/itablet/images/ie/tick.gif | Bin 0 -> 167 bytes .../qpid-web/web/itablet/images/ie/transparent.gif | Bin 0 -> 49 bytes .../qpid-web/web/itablet/images/ie/transparent.png | Bin 0 -> 178 bytes .../java/bin/qpid-web/web/itablet/images/mask.png | Bin 0 -> 941 bytes .../java/bin/qpid-web/web/itablet/images/move.png | Bin 0 -> 1061 bytes .../bin/qpid-web/web/itablet/images/on_off.png | Bin 0 -> 3398 bytes .../qpid-web/web/itablet/images/tick-active.png | Bin 0 -> 380 bytes .../java/bin/qpid-web/web/itablet/images/tick.png | Bin 0 -> 559 bytes .../bin/qpid-web/web/itablet/images/toggle-off.png | Bin 0 -> 181 bytes .../web/itablet/images/toggle-on-border.png | Bin 0 -> 452 bytes .../bin/qpid-web/web/itablet/images/toggle-on.png | Bin 0 -> 211 bytes .../java/bin/qpid-web/web/itablet/images/write.png | Bin 0 -> 1200 bytes .../java/bin/qpid-web/web/itablet/scripts/LICENCE | 72 + .../bin/qpid-web/web/itablet/scripts/iscroll.js | 1117 +++++++ .../bin/qpid-web/web/itablet/scripts/itablet.js | 1492 +++++++++ .../bin/qpid-web/web/itablet/scripts/jquery.js | 4 + .../src/java/bin/qpid-web/web/qmf-ui/css/LICENCE | 26 + .../src/java/bin/qpid-web/web/qmf-ui/css/index.css | 43 + .../src/java/bin/qpid-web/web/qmf-ui/css/qmf.css | 124 + .../bin/qpid-web/web/qmf-ui/images/brokers.png | Bin 0 -> 1794 bytes .../bin/qpid-web/web/qmf-ui/images/connections.png | Bin 0 -> 1931 bytes .../java/bin/qpid-web/web/qmf-ui/images/events.png | Bin 0 -> 2419 bytes .../bin/qpid-web/web/qmf-ui/images/exchanges.png | Bin 0 -> 2428 bytes .../bin/qpid-web/web/qmf-ui/images/gradient.png | Bin 0 -> 89 bytes .../java/bin/qpid-web/web/qmf-ui/images/links.png | Bin 0 -> 2499 bytes .../bin/qpid-web/web/qmf-ui/images/loading.gif | Bin 0 -> 3208 bytes .../bin/qpid-web/web/qmf-ui/images/qpid-logo.png | Bin 0 -> 32948 bytes .../java/bin/qpid-web/web/qmf-ui/images/queues.png | Bin 0 -> 2293 bytes .../qpid-web/web/qmf-ui/images/route-topology.png | Bin 0 -> 2014 bytes .../bin/qpid-web/web/qmf-ui/images/settings.png | Bin 0 -> 2687 bytes .../java/bin/qpid-web/web/qmf-ui/scripts/LICENCE | 63 + .../bin/qpid-web/web/qmf-ui/scripts/excanvas.js | 1416 ++++++++ .../java/bin/qpid-web/web/qmf-ui/scripts/qmf-ui.js | 3526 ++++++++++++++++++++ .../src/java/bin/qpid-web/web/qpid/scripts/LICENCE | 23 + .../src/java/bin/qpid-web/web/qpid/scripts/qpid.js | 745 +++++ qpid/tools/src/java/bin/qpid-web/web/ui/config.js | 15 + qpid/tools/src/java/bin/qpid-web/web/ui/qmf.html | 1292 +++++++ qpid/tools/src/java/bin/whitelist.xml | 33 + qpid/tools/src/java/build.xml | 241 ++ .../java/org/apache/qpid/qmf2/agent/Agent.java | 1461 ++++++++ .../org/apache/qpid/qmf2/agent/AgentExternal.java | 259 ++ .../apache/qpid/qmf2/agent/MethodCallParams.java | 123 + .../apache/qpid/qmf2/agent/MethodCallWorkItem.java | 64 + .../org/apache/qpid/qmf2/agent/QmfAgentData.java | 364 ++ .../org/apache/qpid/qmf2/agent/QueryWorkItem.java | 85 + .../apache/qpid/qmf2/agent/ResubscribeParams.java | 78 + .../qmf2/agent/ResubscribeRequestWorkItem.java | 66 + .../apache/qpid/qmf2/agent/SubscribableAgent.java | 70 + .../qpid/qmf2/agent/SubscribeRequestWorkItem.java | 69 + .../org/apache/qpid/qmf2/agent/Subscription.java | 280 ++ .../apache/qpid/qmf2/agent/SubscriptionParams.java | 102 + .../qmf2/agent/UnsubscribeRequestWorkItem.java | 65 + .../apache/qpid/qmf2/agent/doc-files/QmfData.png | Bin 0 -> 3876 bytes .../qmf2/agent/doc-files/QmfEventListenerModel.png | Bin 0 -> 5412 bytes .../apache/qpid/qmf2/agent/doc-files/QmfQuery.png | Bin 0 -> 8444 bytes .../apache/qpid/qmf2/agent/doc-files/Schema.png | Bin 0 -> 4911 bytes .../qpid/qmf2/agent/doc-files/Subscriptions.png | Bin 0 -> 3365 bytes .../qmf2/agent/doc-files/WorkQueueEventModel.png | Bin 0 -> 7521 bytes .../org/apache/qpid/qmf2/common/AMQPMessage.java | 309 ++ .../apache/qpid/qmf2/common/BlockingNotifier.java | 65 + .../org/apache/qpid/qmf2/common/BooleanEquals.java | 79 + .../org/apache/qpid/qmf2/common/BooleanExists.java | 72 + .../apache/qpid/qmf2/common/BooleanExpression.java | 221 ++ .../org/apache/qpid/qmf2/common/BooleanFalse.java | 60 + .../qpid/qmf2/common/BooleanGreaterEqual.java | 89 + .../qpid/qmf2/common/BooleanGreaterThan.java | 89 + .../apache/qpid/qmf2/common/BooleanLessEqual.java | 89 + .../apache/qpid/qmf2/common/BooleanLessThan.java | 89 + .../apache/qpid/qmf2/common/BooleanNotEquals.java | 79 + .../apache/qpid/qmf2/common/BooleanRegexMatch.java | 95 + .../org/apache/qpid/qmf2/common/BooleanTrue.java | 60 + .../org/apache/qpid/qmf2/common/Expression.java | 77 + .../java/org/apache/qpid/qmf2/common/Handle.java | 107 + .../org/apache/qpid/qmf2/common/LogicalAnd.java | 62 + .../apache/qpid/qmf2/common/LogicalExpression.java | 64 + .../org/apache/qpid/qmf2/common/LogicalNot.java | 62 + .../org/apache/qpid/qmf2/common/LogicalOr.java | 62 + .../java/org/apache/qpid/qmf2/common/Notifier.java | 67 + .../apache/qpid/qmf2/common/NotifierWrapper.java | 57 + .../qpid/qmf2/common/NullQmfEventListener.java | 43 + .../java/org/apache/qpid/qmf2/common/ObjectId.java | 159 + .../org/apache/qpid/qmf2/common/QmfCallback.java | 33 + .../java/org/apache/qpid/qmf2/common/QmfData.java | 443 +++ .../org/apache/qpid/qmf2/common/QmfDescribed.java | 84 + .../java/org/apache/qpid/qmf2/common/QmfEvent.java | 224 ++ .../apache/qpid/qmf2/common/QmfEventListener.java | 51 + .../org/apache/qpid/qmf2/common/QmfException.java | 42 + .../org/apache/qpid/qmf2/common/QmfManaged.java | 83 + .../java/org/apache/qpid/qmf2/common/QmfQuery.java | 343 ++ .../apache/qpid/qmf2/common/QmfQueryTarget.java | 36 + .../java/org/apache/qpid/qmf2/common/QmfType.java | 39 + .../org/apache/qpid/qmf2/common/SchemaClass.java | 135 + .../org/apache/qpid/qmf2/common/SchemaClassId.java | 202 ++ .../apache/qpid/qmf2/common/SchemaEventClass.java | 266 ++ .../org/apache/qpid/qmf2/common/SchemaMethod.java | 275 ++ .../apache/qpid/qmf2/common/SchemaObjectClass.java | 378 +++ .../apache/qpid/qmf2/common/SchemaProperty.java | 364 ++ .../java/org/apache/qpid/qmf2/common/WorkItem.java | 399 +++ .../org/apache/qpid/qmf2/common/WorkQueue.java | 106 + .../apache/qpid/qmf2/common/doc-files/Console.png | Bin 0 -> 6234 bytes .../apache/qpid/qmf2/common/doc-files/QmfData.png | Bin 0 -> 3876 bytes .../common/doc-files/QmfEventListenerModel.png | Bin 0 -> 5412 bytes .../apache/qpid/qmf2/common/doc-files/QmfQuery.png | Bin 0 -> 8444 bytes .../apache/qpid/qmf2/common/doc-files/Schema.png | Bin 0 -> 4911 bytes .../qpid/qmf2/common/doc-files/Subscriptions.png | Bin 0 -> 5382 bytes .../apache/qpid/qmf2/common/doc-files/WorkItem.png | Bin 0 -> 9007 bytes .../qmf2/common/doc-files/WorkQueueEventModel.png | Bin 0 -> 7521 bytes .../java/org/apache/qpid/qmf2/console/Agent.java | 482 +++ .../qpid/qmf2/console/AgentAccessWorkItem.java | 80 + .../qpid/qmf2/console/AgentAddedWorkItem.java | 49 + .../qpid/qmf2/console/AgentDeletedWorkItem.java | 50 + .../qpid/qmf2/console/AgentHeartbeatWorkItem.java | 48 + .../org/apache/qpid/qmf2/console/AgentProxy.java | 85 + .../qpid/qmf2/console/AgentRestartedWorkItem.java | 46 + .../java/org/apache/qpid/qmf2/console/Console.java | 2237 +++++++++++++ .../qpid/qmf2/console/EventReceivedWorkItem.java | 63 + .../qpid/qmf2/console/MethodResponseWorkItem.java | 65 + .../org/apache/qpid/qmf2/console/MethodResult.java | 151 + .../qpid/qmf2/console/ObjectUpdateWorkItem.java | 65 + .../apache/qpid/qmf2/console/QmfConsoleData.java | 277 ++ .../qpid/qmf2/console/SubscribeIndication.java | 66 + .../apache/qpid/qmf2/console/SubscribeParams.java | 130 + .../qmf2/console/SubscribeResponseWorkItem.java | 80 + .../console/SubscriptionIndicationWorkItem.java | 62 + .../qpid/qmf2/console/SubscriptionManager.java | 255 ++ .../apache/qpid/qmf2/console/doc-files/Console.png | Bin 0 -> 6234 bytes .../console/doc-files/QmfEventListenerModel.png | Bin 0 -> 5412 bytes .../qpid/qmf2/console/doc-files/Subscriptions.png | Bin 0 -> 2789 bytes .../qmf2/console/doc-files/WorkQueueEventModel.png | Bin 0 -> 7521 bytes .../apache/qpid/qmf2/tools/ConnectionAudit.java | 474 +++ .../apache/qpid/qmf2/tools/ConnectionLogger.java | 383 +++ .../org/apache/qpid/qmf2/tools/QpidConfig.java | 1564 +++++++++ .../java/org/apache/qpid/qmf2/tools/QpidCtrl.java | 358 ++ .../apache/qpid/qmf2/tools/QpidPrintEvents.java | 210 ++ .../org/apache/qpid/qmf2/tools/QpidQueueStats.java | 374 +++ .../java/org/apache/qpid/qmf2/tools/QueueFuse.java | 364 ++ .../apache/qpid/qmf2/util/ConnectionHelper.java | 862 +++++ .../java/org/apache/qpid/qmf2/util/GetOpt.java | 208 ++ .../src/patch/java/AMQMessageDelegate_0_10.java | 958 ++++++ .../qpid/server/qmf2/QmfManagementAgent.java | 592 ++++ .../qpid/server/qmf2/QmfManagementFactory.java | 79 + .../qpid/server/qmf2/QmfManagementPlugin.java | 300 ++ .../apache/qpid/server/qmf2/agentdata/Binding.java | 203 ++ .../apache/qpid/server/qmf2/agentdata/Broker.java | 678 ++++ .../qpid/server/qmf2/agentdata/Connection.java | 203 ++ .../qpid/server/qmf2/agentdata/Exchange.java | 252 ++ .../apache/qpid/server/qmf2/agentdata/Queue.java | 287 ++ .../qpid/server/qmf2/agentdata/Subscription.java | 207 ++ .../org/apache/qpid/restapi/ConnectionProxy.java | 287 ++ .../org/apache/qpid/restapi/ConnectionStore.java | 138 + .../java/org/apache/qpid/restapi/FileServer.java | 369 ++ .../org/apache/qpid/restapi/HttpTransaction.java | 165 + .../restapi/java/org/apache/qpid/restapi/JSON.java | 265 ++ .../org/apache/qpid/restapi/JSONMapParser.java | 402 +++ .../java/org/apache/qpid/restapi/QpidRestAPI.java | 206 ++ .../java/org/apache/qpid/restapi/QpidServer.java | 654 ++++ .../java/org/apache/qpid/restapi/Server.java | 95 + .../qpid/restapi/httpserver/Authenticator.java | 151 + .../apache/qpid/restapi/httpserver/Delegator.java | 89 + .../httpserver/HttpExchangeTransaction.java | 311 ++ .../java/org/apache/qpid/restapi/servlet/TODO | 4 + .../apache/qpid/qmf2/test/AgentExternalTest.java | 558 ++++ .../qmf2/test/AgentSubscriptionTestConsole.java | 224 ++ .../java/org/apache/qpid/qmf2/test/AgentTest.java | 298 ++ .../apache/qpid/qmf2/test/AgentTestConsole.java | 308 ++ .../apache/qpid/qmf2/test/BigPayloadAgentTest.java | 174 + .../qpid/qmf2/test/BigPayloadAgentTestConsole.java | 155 + .../qmf2/test/BrokerSubscriptionTestConsole.java | 262 ++ .../apache/qpid/qmf2/test/InvokeMethodTest.java | 112 + .../qpid/qmf2/test/PartialGetObjectsTest.java | 177 + .../java/org/apache/qpid/qmf2/test/SchemaTest.java | 126 + .../test/java/org/apache/qpid/qmf2/test/Test1.java | 140 + .../test/java/org/apache/qpid/qmf2/test/Test2.java | 121 + .../test/java/org/apache/qpid/qmf2/test/Test3.java | 137 + .../test/java/org/apache/qpid/qmf2/test/Test4.java | 339 ++ .../java/org/apache/qpid/qmf2/test/URLTest.java | 82 + qpid/tools/src/java/test/bin/AgentExternalTest.sh | 30 + .../java/test/bin/AgentSubscriptionTestConsole.sh | 30 + qpid/tools/src/java/test/bin/AgentTest.sh | 30 + qpid/tools/src/java/test/bin/AgentTestConsole.sh | 30 + .../tools/src/java/test/bin/BigPayloadAgentTest.sh | 30 + .../java/test/bin/BigPayloadAgentTestConsole.sh | 30 + .../java/test/bin/BrokerSubscriptionTestConsole.sh | 30 + qpid/tools/src/java/test/bin/InvokeMethodTest.sh | 30 + .../src/java/test/bin/PartialGetObjectsTest.sh | 30 + qpid/tools/src/java/test/bin/SchemaTest.sh | 30 + qpid/tools/src/java/test/bin/Test1.sh | 30 + qpid/tools/src/java/test/bin/Test2.sh | 30 + qpid/tools/src/java/test/bin/Test3.sh | 30 + qpid/tools/src/java/test/bin/Test4.sh | 30 + qpid/tools/src/java/test/bin/URLTest.sh | 30 + qpid/tools/src/java/test/bin/log4j.xml | 50 + 238 files changed, 41128 insertions(+) create mode 100644 qpid/tools/src/java/README-Java-Broker.txt create mode 100644 qpid/tools/src/java/README.txt create mode 100755 qpid/tools/src/java/bin/ConnectionAudit.sh create mode 100755 qpid/tools/src/java/bin/ConnectionLogger.sh create mode 100755 qpid/tools/src/java/bin/QpidConfig.sh create mode 100755 qpid/tools/src/java/bin/QpidCtrl.sh create mode 100755 qpid/tools/src/java/bin/QpidPrintEvents.sh create mode 100755 qpid/tools/src/java/bin/QpidQueueStats.sh create mode 100755 qpid/tools/src/java/bin/QpidRestAPI.sh create mode 100755 qpid/tools/src/java/bin/QueueFuse.sh create mode 100644 qpid/tools/src/java/bin/log4j.xml create mode 100644 qpid/tools/src/java/bin/qpid-web/authentication/account.properties create mode 100644 qpid/tools/src/java/bin/qpid-web/web/apple-touch-icon.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/favicon.ico create mode 100755 qpid/tools/src/java/bin/qpid-web/web/index.html create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/css/LICENCE create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/css/itablet-ie6.css create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/css/itablet-ie7.css create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/css/itablet-ie8.css create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/css/itablet-ie9.css create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/css/itablet.css create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/action.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/add.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/bin.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/blue-button-sprite.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/blue-chevron.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/blueball.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/button-sprite.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/chevron-active.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/chevron.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/delete.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/flag.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/home.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/active-gradient.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/blue-button-sprite.gif create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/blue-chevron.gif create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/button-sprite.gif create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/chevron-active.gif create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/chevron.gif create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/header-gradient.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/radial-gradient.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/radius-10px-sprite.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/radius-5px-sprite.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/red6.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/smoked.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/tick-active.gif create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/tick.gif create mode 100755 qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/transparent.gif create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/transparent.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/mask.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/move.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/on_off.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/tick-active.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/tick.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/toggle-off.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/toggle-on-border.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/toggle-on.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/images/write.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/scripts/LICENCE create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/scripts/iscroll.js create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/scripts/itablet.js create mode 100644 qpid/tools/src/java/bin/qpid-web/web/itablet/scripts/jquery.js create mode 100644 qpid/tools/src/java/bin/qpid-web/web/qmf-ui/css/LICENCE create mode 100644 qpid/tools/src/java/bin/qpid-web/web/qmf-ui/css/index.css create mode 100644 qpid/tools/src/java/bin/qpid-web/web/qmf-ui/css/qmf.css create mode 100644 qpid/tools/src/java/bin/qpid-web/web/qmf-ui/images/brokers.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/qmf-ui/images/connections.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/qmf-ui/images/events.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/qmf-ui/images/exchanges.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/qmf-ui/images/gradient.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/qmf-ui/images/links.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/qmf-ui/images/loading.gif create mode 100644 qpid/tools/src/java/bin/qpid-web/web/qmf-ui/images/qpid-logo.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/qmf-ui/images/queues.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/qmf-ui/images/route-topology.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/qmf-ui/images/settings.png create mode 100644 qpid/tools/src/java/bin/qpid-web/web/qmf-ui/scripts/LICENCE create mode 100644 qpid/tools/src/java/bin/qpid-web/web/qmf-ui/scripts/excanvas.js create mode 100644 qpid/tools/src/java/bin/qpid-web/web/qmf-ui/scripts/qmf-ui.js create mode 100644 qpid/tools/src/java/bin/qpid-web/web/qpid/scripts/LICENCE create mode 100644 qpid/tools/src/java/bin/qpid-web/web/qpid/scripts/qpid.js create mode 100644 qpid/tools/src/java/bin/qpid-web/web/ui/config.js create mode 100644 qpid/tools/src/java/bin/qpid-web/web/ui/qmf.html create mode 100644 qpid/tools/src/java/bin/whitelist.xml create mode 100644 qpid/tools/src/java/build.xml create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/agent/Agent.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/agent/AgentExternal.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/agent/MethodCallParams.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/agent/MethodCallWorkItem.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/agent/QmfAgentData.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/agent/QueryWorkItem.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/agent/ResubscribeParams.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/agent/ResubscribeRequestWorkItem.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/agent/SubscribableAgent.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/agent/SubscribeRequestWorkItem.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/agent/Subscription.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/agent/SubscriptionParams.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/agent/UnsubscribeRequestWorkItem.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/agent/doc-files/QmfData.png create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/agent/doc-files/QmfEventListenerModel.png create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/agent/doc-files/QmfQuery.png create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/agent/doc-files/Schema.png create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/agent/doc-files/Subscriptions.png create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/agent/doc-files/WorkQueueEventModel.png create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/AMQPMessage.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/BlockingNotifier.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/BooleanEquals.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/BooleanExists.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/BooleanExpression.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/BooleanFalse.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/BooleanGreaterEqual.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/BooleanGreaterThan.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/BooleanLessEqual.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/BooleanLessThan.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/BooleanNotEquals.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/BooleanRegexMatch.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/BooleanTrue.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/Expression.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/Handle.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/LogicalAnd.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/LogicalExpression.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/LogicalNot.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/LogicalOr.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/Notifier.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/NotifierWrapper.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/NullQmfEventListener.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/ObjectId.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/QmfCallback.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/QmfData.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/QmfDescribed.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/QmfEvent.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/QmfEventListener.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/QmfException.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/QmfManaged.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/QmfQuery.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/QmfQueryTarget.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/QmfType.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/SchemaClass.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/SchemaClassId.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/SchemaEventClass.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/SchemaMethod.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/SchemaObjectClass.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/SchemaProperty.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/WorkItem.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/WorkQueue.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/doc-files/Console.png create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/doc-files/QmfData.png create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/doc-files/QmfEventListenerModel.png create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/doc-files/QmfQuery.png create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/doc-files/Schema.png create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/doc-files/Subscriptions.png create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/doc-files/WorkItem.png create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/common/doc-files/WorkQueueEventModel.png create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/Agent.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/AgentAccessWorkItem.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/AgentAddedWorkItem.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/AgentDeletedWorkItem.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/AgentHeartbeatWorkItem.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/AgentProxy.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/AgentRestartedWorkItem.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/Console.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/EventReceivedWorkItem.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/MethodResponseWorkItem.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/MethodResult.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/ObjectUpdateWorkItem.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/QmfConsoleData.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/SubscribeIndication.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/SubscribeParams.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/SubscribeResponseWorkItem.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/SubscriptionIndicationWorkItem.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/SubscriptionManager.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/doc-files/Console.png create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/doc-files/QmfEventListenerModel.png create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/doc-files/Subscriptions.png create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/console/doc-files/WorkQueueEventModel.png create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/tools/ConnectionAudit.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/tools/ConnectionLogger.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/tools/QpidConfig.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/tools/QpidCtrl.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/tools/QpidPrintEvents.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/tools/QpidQueueStats.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/tools/QueueFuse.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/util/ConnectionHelper.java create mode 100644 qpid/tools/src/java/src/main/java/org/apache/qpid/qmf2/util/GetOpt.java create mode 100644 qpid/tools/src/java/src/patch/java/AMQMessageDelegate_0_10.java create mode 100644 qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementAgent.java create mode 100644 qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementFactory.java create mode 100644 qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementPlugin.java create mode 100644 qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/agentdata/Binding.java create mode 100644 qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/agentdata/Broker.java create mode 100644 qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/agentdata/Connection.java create mode 100644 qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/agentdata/Exchange.java create mode 100644 qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/agentdata/Queue.java create mode 100644 qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/agentdata/Subscription.java create mode 100644 qpid/tools/src/java/src/restapi/java/org/apache/qpid/restapi/ConnectionProxy.java create mode 100644 qpid/tools/src/java/src/restapi/java/org/apache/qpid/restapi/ConnectionStore.java create mode 100644 qpid/tools/src/java/src/restapi/java/org/apache/qpid/restapi/FileServer.java create mode 100644 qpid/tools/src/java/src/restapi/java/org/apache/qpid/restapi/HttpTransaction.java create mode 100644 qpid/tools/src/java/src/restapi/java/org/apache/qpid/restapi/JSON.java create mode 100644 qpid/tools/src/java/src/restapi/java/org/apache/qpid/restapi/JSONMapParser.java create mode 100644 qpid/tools/src/java/src/restapi/java/org/apache/qpid/restapi/QpidRestAPI.java create mode 100644 qpid/tools/src/java/src/restapi/java/org/apache/qpid/restapi/QpidServer.java create mode 100644 qpid/tools/src/java/src/restapi/java/org/apache/qpid/restapi/Server.java create mode 100644 qpid/tools/src/java/src/restapi/java/org/apache/qpid/restapi/httpserver/Authenticator.java create mode 100644 qpid/tools/src/java/src/restapi/java/org/apache/qpid/restapi/httpserver/Delegator.java create mode 100644 qpid/tools/src/java/src/restapi/java/org/apache/qpid/restapi/httpserver/HttpExchangeTransaction.java create mode 100644 qpid/tools/src/java/src/restapi/java/org/apache/qpid/restapi/servlet/TODO create mode 100644 qpid/tools/src/java/src/test/java/org/apache/qpid/qmf2/test/AgentExternalTest.java create mode 100644 qpid/tools/src/java/src/test/java/org/apache/qpid/qmf2/test/AgentSubscriptionTestConsole.java create mode 100644 qpid/tools/src/java/src/test/java/org/apache/qpid/qmf2/test/AgentTest.java create mode 100644 qpid/tools/src/java/src/test/java/org/apache/qpid/qmf2/test/AgentTestConsole.java create mode 100644 qpid/tools/src/java/src/test/java/org/apache/qpid/qmf2/test/BigPayloadAgentTest.java create mode 100644 qpid/tools/src/java/src/test/java/org/apache/qpid/qmf2/test/BigPayloadAgentTestConsole.java create mode 100644 qpid/tools/src/java/src/test/java/org/apache/qpid/qmf2/test/BrokerSubscriptionTestConsole.java create mode 100644 qpid/tools/src/java/src/test/java/org/apache/qpid/qmf2/test/InvokeMethodTest.java create mode 100644 qpid/tools/src/java/src/test/java/org/apache/qpid/qmf2/test/PartialGetObjectsTest.java create mode 100644 qpid/tools/src/java/src/test/java/org/apache/qpid/qmf2/test/SchemaTest.java create mode 100644 qpid/tools/src/java/src/test/java/org/apache/qpid/qmf2/test/Test1.java create mode 100644 qpid/tools/src/java/src/test/java/org/apache/qpid/qmf2/test/Test2.java create mode 100644 qpid/tools/src/java/src/test/java/org/apache/qpid/qmf2/test/Test3.java create mode 100644 qpid/tools/src/java/src/test/java/org/apache/qpid/qmf2/test/Test4.java create mode 100644 qpid/tools/src/java/src/test/java/org/apache/qpid/qmf2/test/URLTest.java create mode 100755 qpid/tools/src/java/test/bin/AgentExternalTest.sh create mode 100755 qpid/tools/src/java/test/bin/AgentSubscriptionTestConsole.sh create mode 100755 qpid/tools/src/java/test/bin/AgentTest.sh create mode 100755 qpid/tools/src/java/test/bin/AgentTestConsole.sh create mode 100755 qpid/tools/src/java/test/bin/BigPayloadAgentTest.sh create mode 100755 qpid/tools/src/java/test/bin/BigPayloadAgentTestConsole.sh create mode 100755 qpid/tools/src/java/test/bin/BrokerSubscriptionTestConsole.sh create mode 100755 qpid/tools/src/java/test/bin/InvokeMethodTest.sh create mode 100755 qpid/tools/src/java/test/bin/PartialGetObjectsTest.sh create mode 100755 qpid/tools/src/java/test/bin/SchemaTest.sh create mode 100755 qpid/tools/src/java/test/bin/Test1.sh create mode 100755 qpid/tools/src/java/test/bin/Test2.sh create mode 100755 qpid/tools/src/java/test/bin/Test3.sh create mode 100755 qpid/tools/src/java/test/bin/Test4.sh create mode 100755 qpid/tools/src/java/test/bin/URLTest.sh create mode 100644 qpid/tools/src/java/test/bin/log4j.xml (limited to 'qpid/tools/src/java') diff --git a/qpid/tools/src/java/README-Java-Broker.txt b/qpid/tools/src/java/README-Java-Broker.txt new file mode 100644 index 0000000000..fccf19a099 --- /dev/null +++ b/qpid/tools/src/java/README-Java-Broker.txt @@ -0,0 +1,350 @@ + +The Qpid Java Broker by default uses either JMX or an HTTP Management GUI & REST API, however by building +a QMF2 Agent as a Java Broker plugin it's possible to provide better synergy between the C++ and Java Brokers +and allow the Java Broker to be controlled by the Qpid Command Line tools and also via the QMF2 REST API +and GUI thus providing a unified view across a mixture of C++ and Java Brokers. + + +To build and install the Java Broker QMF2 plugin do: + +ant all + +*********************************************************************************************************** +* Note that the QmfManagementPlugin requires a version of the Java Broker >= 0.22 * +* * +* The initial version of QmfManagementPlugin released to https://issues.apache.org/jira/browse/QPID-3675 * +* uses the ManagementPlugin and ManagementFactory interfaces which were introduced in Qpid 0.20 but then * +* dropped in Qpid 0.22 so the version linked to the Jira is the only version that will work with the 0.20 * +* Java Broker. * +* * +* As of Qpid 0.22 the Java Broker Plugin and Configuration APIs have changed. The Plugin API implements * +* org.apache.qpid.server.model.Plugin extending org.apache.qpid.server.model.adapter.AbstractPluginAdapter* +* and uses org.apache.qpid.server.plugin.PluginFactory to create the Plugin instance. * +* * +* The Plugin uses the org.apache.qpid.server.model.* classes and maps them to QmfData. * +* * +* The intention is to track changes on Qpid Trunk, but the Plugin API is still under a bit of flux * +*********************************************************************************************************** + +N.B. this requires that the Qpid jars (preferably qpid-all.jar) are on your CLASSPATH and that the +QPID_HOME environment variable is set to point to /java/build (QPID_HOME is needed by the Java +broker anyway). + +The ant all target compiles the Java Broker QMF2 plugin and copies the qpid-broker-plugins-management-qmf2.jar +and qmf2.jar to $QPID_HOME/lib/plugins creating the plugins directory if it doesn't already exist. That +directory is one read by the qpid-server broker startup script and placed on the broker's CLASSPATH. + + + +************************************************* Config ************************************************** + +As of Qpid 0.22 the way of configuring the Java Broker has moved to an initial config.json file in +$QPID_WORK and updates via the Management Plugins. It is IMPORTANT to ensure that the following: + +{ + "name" : "qmf2Management", + "pluginType" : "MANAGEMENT-QMF2", + "connectionURL" : "amqp://guest:guest@/?brokerlist='tcp://0.0.0.0:5672'" + } + +is added to the "plugins" list of $QPID_WORK/config.json or the Plugin will not start. There is also an "id" +property but if this is omitted it will get automatically created the first time the Plugin starts, which +is probably more useful that trying to make a UUID up. + +The "connectionURL" property is particularly important. The Plugin connects to AMQP via the JMS Client so +"connectionURL" represents a valid Java ConnectionURL to the Broker so the username/password and any other +ConnectionURL configuration needs to be valid as for any other AMQP Connection to the Broker. + + +If the QMF GUI is to be used then either the -p option of QpidRestAPI.sh should be used to set the REST Server's +HTTP port to something other than 8080 or the "ports" list of $QPID_WORK/config.json should be modified from e.g. +{ + "id" : "1f2c4c7a-f33a-316b-b0e9-c02fab74469d", + "name" : "8080-HTTP", + "port" : 8080, + "protocols" : [ "HTTP" ] + } + +to + +{ + "id" : "1f2c4c7a-f33a-316b-b0e9-c02fab74469d", + "name" : "9090-HTTP", + "port" : 9090, + "protocols" : [ "HTTP" ] + } + +So that the HTTP ports don't conflict. + + +In the top-level Broker config the "defaultVirtualHost" *MUST* be set to the name of the default Virtual Host +if this property is not set or is set to a name that doesn't match the name of one of the Virtual Hosts +then the Plugin will not start correctly. + + +******************************************** Troubleshooting ********************************************** + +If all has gone well you should see + +[Broker] MNG-1001 : QMF2 Management Startup +[Broker] MNG-1004 : QMF2 Management Ready + +in the Broker log messages when you run qpid-server, if you don't see these then there is likely to be a problem. + +1. Check the directory $QPID_HOME/lib/plugins +That should contain qmf2.jar and qpid-broker-plugins-management-qmf2.jar if it doesn't then the Plugin hasn't been +built or deployed try doing + +ant all + +again. + +2. If the jars mentioned above are present and correct in the plugins directory the most likely cause of failure +is incorrect configuration - see the Config section above, in particular the "plugins" list and "defaultVirtualHost". + + + +******************************* Java Broker Management Plugin - mini HOWTO ******************************** + +The procedure for writing Plugins for the Java Broker isn't documented yet, so the following mini HOWTO +describes what I did. It may not be the *right* way but it seems to result in a Plugin that starts with the broker. + +1. Create a PluginFactory + +Management plugins are instantiated by Factory classes that implement the interface +org.apache.qpid.server.plugin.PluginFactory e.g. + + +package org.apache.qpid.server.qmf2; + +// Misc Imports +import java.util.Map; +import java.util.UUID; + +// Java Broker Management Imports +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.plugin.PluginFactory; + +public class QmfManagementFactory implements PluginFactory +{ + /** + * This factory method creates an instance of QmfManagementPlugin called via the QpidServiceLoader. + * @param id the UUID of the Plugin. + * @param attributes a Map containing configuration information for the Plugin. + * @param broker the root Broker Management Object from which the other Management Objects may be obtained. + * @return the QmfManagementPlugin instance which creates a QMF2 Agent able to interrogate the broker Management + * Objects and return their properties as QmfData. + */ + @Override + public Plugin createInstance(UUID id, Map attributes, Broker broker) + { + if (QmfManagementPlugin.PLUGIN_TYPE.equals(attributes.get(PLUGIN_TYPE))) + { + return new QmfManagementPlugin(id, broker, attributes); + } + else + { + return null; + } + } +} + + +2. Create a Plugin + +Plugins implement the interface org.apache.qpid.server.model.Plugin which seems to be done by extending +org.apache.qpid.server.model.adapter.AbstractPluginAdapter. The main APIs are to override the setState() +and getName() methods and to implement a static initialiser to populate ConfiguredObject ATTRIBUTES. + + +package org.apache.qpid.server.qmf2; + +// Misc Imports +import java.lang.reflect.Type; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.UUID; + +// Java Broker Management Imports +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.ManagementConsoleMessages; + +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.Exchange; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.model.adapter.AbstractPluginAdapter; + +import org.apache.qpid.server.plugin.PluginFactory; +import org.apache.qpid.server.util.MapValueConverter; + +public class QmfManagementPlugin extends AbstractPluginAdapter +{ + private static final String OPERATIONAL_LOGGING_NAME = "QMF2"; + + /************* Static initialiser used to implement org.apache.qpid.server.model.Plugin *************/ + + public static final String PLUGIN_TYPE = "MANAGEMENT-QMF2"; + + // attributes + public static final String NAME = "name"; + public static final String CONNECTION_URL = "connectionURL"; + + // default values + public static final String DEFAULT_NAME = "qmf2Management"; + public static final String DEFAULT_CONNECTION_URL = "amqp://guest:guest@/?brokerlist='tcp://0.0.0.0:5672'"; + + @SuppressWarnings("serial") + private static final Collection AVAILABLE_ATTRIBUTES = Collections.unmodifiableCollection( + new HashSet(Plugin.AVAILABLE_ATTRIBUTES){{ + add(NAME); + add(CONNECTION_URL); + add(PluginFactory.PLUGIN_TYPE); + }}); + + @SuppressWarnings("serial") + private static final Map DEFAULTS = new HashMap(){{ + put(NAME, DEFAULT_NAME); + put(CONNECTION_URL, DEFAULT_CONNECTION_URL); + put(PluginFactory.PLUGIN_TYPE, PLUGIN_TYPE); + }}; + + @SuppressWarnings("serial") + private static final Map ATTRIBUTE_TYPES = new HashMap(){{ + put(NAME, String.class); + put(CONNECTION_URL, String.class); + put(PluginFactory.PLUGIN_TYPE, String.class); + }}; + + /************************************ End of Static initialiser *************************************/ + + /** + * Constructor, called at broker startup by QmfManagementFactory.createInstance(). + * @param id the UUID of the Plugin. + * @param attributes a Map containing configuration information for the Plugin. + * @param broker the root Broker Management Object from which the other Management Objects may be obtained. + */ + public QmfManagementPlugin(UUID id, Broker broker, Map attributes) + { + super(id, DEFAULTS, MapValueConverter.convert(attributes, ATTRIBUTE_TYPES), broker.getTaskExecutor()); + addParent(Broker.class, broker); +System.out.println("************ Constructing QmfManagementPlugin"); + } + + /** + * Set the state of the Plugin, I believe that this is called from the BrokerAdapter object when it + * has its own state set to State.ACTIVE or State.STOPPED. + * When State.ACTIVE is set this calls the start() method to startup the Plugin, when State.STOPPED + * is set this calls the stop() method to shutdown the Plugin. + * @param currentState the current state of the Plugin (ignored). + * @param desiredState the desired state of the Plugin (either State.ACTIVE or State.STOPPED). + * @return true if a valid state has been set, otherwise false. + */ + @Override // From org.apache.qpid.server.model.adapter.AbstractAdapter + protected boolean setState(State currentState, State desiredState) + { + if (desiredState == State.ACTIVE) + { + start(); + return true; + } + else if (desiredState == State.STOPPED) + { + stop(); + return true; + } + else + { + return false; + } + } + + private void start() + { + // Log "QMF2 Management Startup" message. + CurrentActor.get().message(ManagementConsoleMessages.STARTUP(OPERATIONAL_LOGGING_NAME)); + + // Log QMF2 Management Ready message. + CurrentActor.get().message(ManagementConsoleMessages.READY(OPERATIONAL_LOGGING_NAME)); + } + + private void stop() + { + // Log "QMF2 Management Stopped" message (may not get displayed). + CurrentActor.get().message(ManagementConsoleMessages.STOPPED(OPERATIONAL_LOGGING_NAME)); + } + + /** + * Get the name of this Plugin. + * @return the Plugin name (default is "qmf2Management"). + */ + @Override // From org.apache.qpid.server.model.ConfiguredObject + public String getName() + { + return (String)getAttribute(NAME); + } + + /** + * Accessor to retrieve the names of the available attributes. It is important to provide this overridden + * method because the Constructor uses this information when populating the underlying AbstractPlugin + * information. If we don't provide this override method getAttribute(name) will return the default values. + * @return the names of the available Plugin config attributes as a Collection. + */ + @Override // From org.apache.qpid.server.model.adapter.AbstractPluginAdapter + public Collection getAttributeNames() + { + return AVAILABLE_ATTRIBUTES; + } +} + +3. Populate the META-INF + +Qpid Java broker Plugins seem to use a facade over java.util.ServiceLoader called +org.apache.qpid.server.plugin.QpidServiceLoader. In order to use a ServiceLoader the jar containing the Plugin +needs to contain a file: +META-INF/services/org.apache.qpid.server.plugin.PluginFactory + +which contains the fully qualified class name of the class implementing PluginFactory e.g. + +org.apache.qpid.server.qmf2.QmfManagementFactory + + +The most convenient way to achieve this is to include a ServiceProvider block in the jar ant task e.g. + + + + + + + +4. Build the jar using your favourite method. + +5. Deploy the jar to $QPID_HOME/lib/plugins + +6. Ensure the config.json file in $QPID_WORK contains: +{ + "name" : "qmf2Management", + "pluginType" : "MANAGEMENT-QMF2", + "connectionURL" : "amqp://guest:guest@/?brokerlist='tcp://0.0.0.0:5672'" + } + +(or whatever the name/pluginType/etc. of the actual Plugin is) +in the "plugins" list (the id property will be added automatically when the Broker starts) + +7. Start up the Java Broker via qpid-server + + +If all has gone well the Plugin should start up. Clearly you'll probably want to add something to the Plugin so +that it actually does something vaguely useful :-) + + + + diff --git a/qpid/tools/src/java/README.txt b/qpid/tools/src/java/README.txt new file mode 100644 index 0000000000..3cd57605b4 --- /dev/null +++ b/qpid/tools/src/java/README.txt @@ -0,0 +1,73 @@ + +This is a Java JMS implementation of the QMF2 API specified at +https://cwiki.apache.org/qpid/qmfv2-api-proposal.html + +The Qpid Java jar needs to be on your classpath - I tend to use qpid-all.jar but client only jars should be OK too. + +QMF2 support is now available for the Qpid Java Broker see README-Java-Broker.txt for details. + + + +*********************************************** Important!! *********************************************** +* If your version of Qpid is older than 0.12 the QMF2 API won't work unless your setup is as follows: * +*********************************************** Important!! *********************************************** + +For those who are running with Qpid 0.12 or above the patch described below isn't necessary. +The default "api" ant target in build.xml builds everything except the patch, which is the preferred +approach for later Qpid versions, though using the patched version of the older AMQMessageDelegate_0_10.java +still works with Qpid 0.12 (but not with later Qpid versions). + + +To be clear, if you are using Qpid Java jars 0.12 or above you do not need to use the patch described below +even if you are talking to an earlier broker, however do note that if you are talking to a broker < Qpid 0.10 +you need to set "--mgmt-qmf2 yes" when you start up qpidd if you want to get QMF2 Events and heartbeats pushed. +This is particularly important to note if you are using the Qpid GUI, as in default mode its updates are +triggered by the QMF2 heartbeats. If "--mgmt-qmf2 yes" isn't set on a 0.8 broker you'll see "Broker Disconnected" +flash briefly every 30 seconds or so as timeouts occur. Creating a QMF Console Connecton in the GUI with +"Disable Events" selected uses a timed poll rather than a heartbeat so it may be better to do that for cases +where access to the broker configuration is not available. + +*********************************************************************************************************** + +Note 1: This uses QMF2 so requires that the "--mgmt-qmf2 yes" option is applied to the broker (this is + the default from Qpid 0.10 onwards) +Note 2: In order to use QMF2 the app-id field needs to be set. There appears to be no way to set the AMQP + 0-10 specific app-id field on a message which the broker's QMFv2 implementation currently requires. + +Gordon Sim has put together a patch for org.apache.qpid.client.message.AMQMessageDelegate_0_10 +Found in client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java + +public void setStringProperty(String propertyName, String value) throws JMSException +{ + checkPropertyName(propertyName); + checkWritableProperties(); + setApplicationHeader(propertyName, value); + + if ("x-amqp-0-10.app-id".equals(propertyName)) + { + _messageProps.setAppId(value.getBytes()); + } +} + +The jira "https://issues.apache.org/jira/browse/QPID-3302." covers this. + + +This has been fixed in Qpid 0.12, but I've included a patched version of AMQMessageDelegate_0_10.java +in the build directory so that people using earlier versions can get up and running (the QMF2 library +was initially developed using Qpid 0.10). + + +The "api-patched" ant target in build.xml creates a qpid-client-patch.jar in addition to the qmf2.jar and qmf2test.jar + +It is assumed that the qpid-clientxxx.jar is already on your CLASSPATH so one would do: + +CLASSPATH=../../build/lib/qpid-client-patch.jar:$CLASSPATH:../../build/lib/qmf2.jar:../../build/lib/qmf2test.jar + +to put the patched AMQMessageDelegate_0_10 ahead of the unpatched one. This is already done for the scripts that +call the various test and tool classes. + + + + + + diff --git a/qpid/tools/src/java/bin/ConnectionAudit.sh b/qpid/tools/src/java/bin/ConnectionAudit.sh new file mode 100755 index 0000000000..303c61cbc6 --- /dev/null +++ b/qpid/tools/src/java/bin/ConnectionAudit.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# 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. +# + +WHEREAMI=`dirname $0` +if [ -z "$QMF2_HOME" ]; then + export QMF2_HOME=`cd $WHEREAMI/../ && pwd` +fi + +QMF2_LIBS=$QMF2_HOME/build/lib + +CLASSPATH=$QMF2_LIBS/qpid-client-patch.jar:$CLASSPATH:$QMF2_LIBS/qmf2.jar + +# Get the log level from the AMQJ_LOGGING_LEVEL environment variable. +if [ -n "$AMQJ_LOGGING_LEVEL" ]; then + PROPERTIES=-Damqj.logging.level=$AMQJ_LOGGING_LEVEL +fi + +java -cp $CLASSPATH $PROPERTIES org.apache.qpid.qmf2.tools.ConnectionAudit "$@" diff --git a/qpid/tools/src/java/bin/ConnectionLogger.sh b/qpid/tools/src/java/bin/ConnectionLogger.sh new file mode 100755 index 0000000000..77ae9ee334 --- /dev/null +++ b/qpid/tools/src/java/bin/ConnectionLogger.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# 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. +# + +WHEREAMI=`dirname $0` +if [ -z "$QMF2_HOME" ]; then + export QMF2_HOME=`cd $WHEREAMI/../ && pwd` +fi + +QMF2_LIBS=$QMF2_HOME/build/lib + +CLASSPATH=$QMF2_LIBS/qpid-client-patch.jar:$CLASSPATH:$QMF2_LIBS/qmf2.jar + +# Get the log level from the AMQJ_LOGGING_LEVEL environment variable. +if [ -n "$AMQJ_LOGGING_LEVEL" ]; then + PROPERTIES=-Damqj.logging.level=$AMQJ_LOGGING_LEVEL +fi + +java -cp $CLASSPATH $PROPERTIES org.apache.qpid.qmf2.tools.ConnectionLogger "$@" diff --git a/qpid/tools/src/java/bin/QpidConfig.sh b/qpid/tools/src/java/bin/QpidConfig.sh new file mode 100755 index 0000000000..9f191d3d3d --- /dev/null +++ b/qpid/tools/src/java/bin/QpidConfig.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# 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. +# + +WHEREAMI=`dirname $0` +if [ -z "$QMF2_HOME" ]; then + export QMF2_HOME=`cd $WHEREAMI/../ && pwd` +fi + +QMF2_LIBS=$QMF2_HOME/build/lib + +CLASSPATH=$QMF2_LIBS/qpid-client-patch.jar:$CLASSPATH:$QMF2_LIBS/qmf2.jar + +# Get the log level from the AMQJ_LOGGING_LEVEL environment variable. +if [ -n "$AMQJ_LOGGING_LEVEL" ]; then + PROPERTIES=-Damqj.logging.level=$AMQJ_LOGGING_LEVEL +fi + +java -cp $CLASSPATH $PROPERTIES org.apache.qpid.qmf2.tools.QpidConfig "$@" diff --git a/qpid/tools/src/java/bin/QpidCtrl.sh b/qpid/tools/src/java/bin/QpidCtrl.sh new file mode 100755 index 0000000000..8b10338c7b --- /dev/null +++ b/qpid/tools/src/java/bin/QpidCtrl.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# 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. +# + +WHEREAMI=`dirname $0` +if [ -z "$QMF2_HOME" ]; then + export QMF2_HOME=`cd $WHEREAMI/../ && pwd` +fi + +QMF2_LIBS=$QMF2_HOME/build/lib + +CLASSPATH=$QMF2_LIBS/qpid-client-patch.jar:$CLASSPATH:$QMF2_LIBS/qmf2.jar + +# Get the log level from the AMQJ_LOGGING_LEVEL environment variable. +if [ -n "$AMQJ_LOGGING_LEVEL" ]; then + PROPERTIES=-Damqj.logging.level=$AMQJ_LOGGING_LEVEL +fi + +java -cp $CLASSPATH $PROPERTIES org.apache.qpid.qmf2.tools.QpidCtrl "$@" diff --git a/qpid/tools/src/java/bin/QpidPrintEvents.sh b/qpid/tools/src/java/bin/QpidPrintEvents.sh new file mode 100755 index 0000000000..1e8d03093b --- /dev/null +++ b/qpid/tools/src/java/bin/QpidPrintEvents.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# 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. +# + +WHEREAMI=`dirname $0` +if [ -z "$QMF2_HOME" ]; then + export QMF2_HOME=`cd $WHEREAMI/../ && pwd` +fi + +QMF2_LIBS=$QMF2_HOME/build/lib + +CLASSPATH=$QMF2_LIBS/qpid-client-patch.jar:$CLASSPATH:$QMF2_LIBS/qmf2.jar + +# Get the log level from the AMQJ_LOGGING_LEVEL environment variable. +if [ -n "$AMQJ_LOGGING_LEVEL" ]; then + PROPERTIES=-Damqj.logging.level=$AMQJ_LOGGING_LEVEL +fi + +java -cp $CLASSPATH $PROPERTIES org.apache.qpid.qmf2.tools.QpidPrintEvents "$@" diff --git a/qpid/tools/src/java/bin/QpidQueueStats.sh b/qpid/tools/src/java/bin/QpidQueueStats.sh new file mode 100755 index 0000000000..7685562e3b --- /dev/null +++ b/qpid/tools/src/java/bin/QpidQueueStats.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# 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. +# + +WHEREAMI=`dirname $0` +if [ -z "$QMF2_HOME" ]; then + export QMF2_HOME=`cd $WHEREAMI/../ && pwd` +fi + +QMF2_LIBS=$QMF2_HOME/build/lib + +CLASSPATH=$QMF2_LIBS/qpid-client-patch.jar:$CLASSPATH:$QMF2_LIBS/qmf2.jar + +# Get the log level from the AMQJ_LOGGING_LEVEL environment variable. +if [ -n "$AMQJ_LOGGING_LEVEL" ]; then + PROPERTIES=-Damqj.logging.level=$AMQJ_LOGGING_LEVEL +fi + +java -cp $CLASSPATH $PROPERTIES org.apache.qpid.qmf2.tools.QpidQueueStats "$@" diff --git a/qpid/tools/src/java/bin/QpidRestAPI.sh b/qpid/tools/src/java/bin/QpidRestAPI.sh new file mode 100755 index 0000000000..143e2ffde7 --- /dev/null +++ b/qpid/tools/src/java/bin/QpidRestAPI.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# 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. +# + +WHEREAMI=`dirname $0` +if [ -z "$QMF2_HOME" ]; then + export QMF2_HOME=`cd $WHEREAMI/../ && pwd` +fi + +QMF2_LIBS=$QMF2_HOME/build/lib + +CLASSPATH=$QMF2_LIBS/qpid-client-patch.jar:$CLASSPATH:$QMF2_LIBS/qmf2.jar:$QMF2_LIBS/restapi.jar + +# Get the log level from the AMQJ_LOGGING_LEVEL environment variable. +if [ -n "$AMQJ_LOGGING_LEVEL" ]; then + PROPERTIES=-Damqj.logging.level=$AMQJ_LOGGING_LEVEL +fi + +java -cp $CLASSPATH $PROPERTIES org.apache.qpid.restapi.QpidRestAPI "$@" diff --git a/qpid/tools/src/java/bin/QueueFuse.sh b/qpid/tools/src/java/bin/QueueFuse.sh new file mode 100755 index 0000000000..8f04650b72 --- /dev/null +++ b/qpid/tools/src/java/bin/QueueFuse.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# 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. +# + +WHEREAMI=`dirname $0` +if [ -z "$QMF2_HOME" ]; then + export QMF2_HOME=`cd $WHEREAMI/../ && pwd` +fi + +QMF2_LIBS=$QMF2_HOME/build/lib + +CLASSPATH=$QMF2_LIBS/qpid-client-patch.jar:$CLASSPATH:$QMF2_LIBS/qmf2.jar + +# Get the log level from the AMQJ_LOGGING_LEVEL environment variable. +if [ -n "$AMQJ_LOGGING_LEVEL" ]; then + PROPERTIES=-Damqj.logging.level=$AMQJ_LOGGING_LEVEL +fi + +java -cp $CLASSPATH $PROPERTIES org.apache.qpid.qmf2.tools.QueueFuse "$@" diff --git a/qpid/tools/src/java/bin/log4j.xml b/qpid/tools/src/java/bin/log4j.xml new file mode 100644 index 0000000000..434bb73259 --- /dev/null +++ b/qpid/tools/src/java/bin/log4j.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/qpid/tools/src/java/bin/qpid-web/authentication/account.properties b/qpid/tools/src/java/bin/qpid-web/authentication/account.properties new file mode 100644 index 0000000000..082c50fc70 --- /dev/null +++ b/qpid/tools/src/java/bin/qpid-web/authentication/account.properties @@ -0,0 +1,3 @@ +# +guest=guest +admin=admin diff --git a/qpid/tools/src/java/bin/qpid-web/web/apple-touch-icon.png b/qpid/tools/src/java/bin/qpid-web/web/apple-touch-icon.png new file mode 100644 index 0000000000..ad4478ccac Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/apple-touch-icon.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/favicon.ico b/qpid/tools/src/java/bin/qpid-web/web/favicon.ico new file mode 100644 index 0000000000..1f61b0edd2 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/favicon.ico differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/index.html b/qpid/tools/src/java/bin/qpid-web/web/index.html new file mode 100755 index 0000000000..7419feb02e --- /dev/null +++ b/qpid/tools/src/java/bin/qpid-web/web/index.html @@ -0,0 +1,38 @@ + + + + + + QMF Console + + + + + + + + + + + + + + + + + + diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/css/LICENCE b/qpid/tools/src/java/bin/qpid-web/web/itablet/css/LICENCE new file mode 100644 index 0000000000..9951afb272 --- /dev/null +++ b/qpid/tools/src/java/bin/qpid-web/web/itablet/css/LICENCE @@ -0,0 +1,29 @@ +/* + * itablet.css + * itablet-ie9.css + * itablet-ie8.css + * itablet-ie7.css + * itablet-ie6.css + * + * Copyright (c) 2013, Fraser Adams + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * 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. + * + */ + + diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/css/itablet-ie6.css b/qpid/tools/src/java/bin/qpid-web/web/itablet/css/itablet-ie6.css new file mode 100644 index 0000000000..d5bb6e349a --- /dev/null +++ b/qpid/tools/src/java/bin/qpid-web/web/itablet/css/itablet-ie6.css @@ -0,0 +1,302 @@ +/** + * Stylesheet to try and make things look not *too* bad in IE6 and below. Supporting IE6 really is a nightmare :-( + */ + +/* Needed to get rid of annoying "permanent" IE6 scrollbar. */ +html +{ + overflow: hidden; +} + +/* Explicitly setting height to 100% avoids some evil IE6 layout bugs */ +html, .sidebar, .main, .popup-window, .popup-container, .popup, .scroll-area +{ + height: 100%; +} + +/* Explicitly setting width to 100% avoids some evil IE6 layout bugs */ +ul.list, .popup, .scroll-area +{ + width: 100%; +} + +#sidebar-wrapper /* Make sure IE "hasLayout" is enabled by doing zoom: 1. */ +{ + zoom: 1; +} + +/* IE6 doesn't support color: inherit so we have to set it explicitly. */ +ul li.grey a /* Grey text generally used to show inactive fields */ +{ + color: #8f8f8f; +} + +ul li a +{ + color: #060606; +} + +ul li.active a +{ + color: #fff; +} + +/* IE6 form has a default non-zero margin, so we need to zero it. */ +form +{ + margin: 0; +} + +.sidebar .scroll-area +{ + border-right: 1px solid #000; +} + +ul.list li.first-child +{ + border-top: 1px groove #fff; +} + +ul.list li.last-child +{ + border-bottom: 2px groove #fff; +} + +ul.list li a p +{ + right: 0; +} + +ul.list li.arrow a p, ul.list li.multiline a div p +{ + right: 18px; +} + + +ul.list li.multiline a.icon p, ul.list li.multiline a.icon div p +{ + right: 4px; +} + +/** + * white-space: nowrap; doesn't work especially well in IE6, so we set it to normal and constrain height. + * Unfortunately with the approach below ellipses aren't displayed, but it's the lesser of the evils. + * white-space: nowrap; does seem to work with an explicit width set, but doing that breaks loads of other things. + */ +ul li a p.sub, ul li a p.title +{ + white-space: normal; +} + +ul li a p.title, ul li a p.sub +{ + height: 16px; +} + +/* For IE6 we need to use a GIF instead of a PNG to make the input background transparent but still receive events. */ +input, textarea +{ + background: url(/itablet/images/ie/transparent.gif) repeat; +} + +/** + * For IE6 button :before and :after don't work so we have to resort to some JavaScript to add extra classes and tags + * IE6 doesn't support PNG images with alpha transparency, so we use gifs, which are OK but a littly more jagged. + */ + +a.button +{ + background: url(/itablet/images/ie/button-sprite.gif) 0px -30px repeat-x; +} + +a.button .before +{ + position: absolute; + top: 0; + left: -5px; + width: 5px; + height: 30px; + background: url(/itablet/images/ie/button-sprite.gif) -18px 0; +} + +a.button .after +{ + position: absolute; + top: 0; + right: -5px; + width: 5px; + height: 30px; + background: url(/itablet/images/ie/button-sprite.gif) -13px 0; +} + +a.button:active +{ + background-color: #766d69; + background-position: 0px -60px; +} + +a.button:active .before +{ + background-position: -41px 0; +} + +a.button:active .after +{ + background-position: -36px 0; +} + +a.button.back .before +{ + position: absolute; + left: -13px; + width: 13px; + height: 30px; + background-position: 0 0; +} + +a.button.back:active .before +{ + background-position: -23px 0; +} + +a.button.blue +{ + background: url(/itablet/images/ie/blue-button-sprite.gif) 0px -30px repeat-x; +} + +a.button.blue .before +{ + background: url(/itablet/images/ie/blue-button-sprite.gif) -18px 0; +} + +a.button.blue .after +{ + background: url(/itablet/images/ie/blue-button-sprite.gif) -13px 0; +} + +a.button.blue-back .before +{ + background-position: 0 0; +} + +a.button.blue:active +{ + background-color: #6b6f76; + background-position: 0px -60px; +} + +a.button.blue:active .before +{ + background-position: -41px 0; +} + +a.button.blue:active .after +{ + background-position: -36px 0; +} + +a.button.blue-back:active .before +{ + background-position: -23px 0; +} + +.popup-window +{ + background: url(/itablet/images/ie/transparent.gif); + filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/itablet/images/ie/transparent.png', sizingMethod='scale'); +} + +.popup-window.smoked +{ + background: url(/itablet/images/ie/transparent.gif); + filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/itablet/images/ie/smoked.png', sizingMethod='scale'); +} + +div.mask +{ + background: url(/itablet/images/ie/transparent.gif); + filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/itablet/images/mask.png', sizingMethod='crop'); +} + +div.onoff +{ + background: url(/itablet/images/ie/transparent.gif); + filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/itablet/images/on_off.png', sizingMethod='crop'); +} + +/** + * Unfortunately AlphaImageLoader doesn't play nicely with alignment and these images need to be right aligned. + * Fortunately the single level of transparency allowed by gif images is good enough and only a little granier. + */ + +ul.list li.arrow.radio +{ + background: #f7f7f7; +} + +ul.list li.radio label +{ + padding: 0 11px 0 11px; /* top right bottom left */ +} + +ul li.active, ul.list li.radio.active, ul.list li.radio.ie6-checked-active /* Highlight in blue with white text */ +{ + background: #035de7; +} + +ul li.arrow +{ + background: url(/itablet/images/ie/chevron.gif) no-repeat right; +} + +ul.list li.arrow +{ + background: #f7f7f7 url(/itablet/images/ie/chevron.gif) no-repeat right; +} + +ul li.ie6-arrow-active, ul.list li.ie6-arrow-active +{ + background: #035de7 url(/itablet/images/ie/chevron-active.gif) no-repeat right; +} + +ul.list li.radio.checked label +{ + background: url(/itablet/images/ie/tick.gif) no-repeat right; +} + +ul.list li.radio.ie6-checked-active label +{ + background: url(/itablet/images/ie/tick-active.gif) no-repeat right; +} + +ul.list li.ie6-radio-arrow +{ + background: #f7f7f7 url(/itablet/images/ie/blue-chevron.gif) no-repeat right; +} + +ul.list li.ie6-radio-arrow label +{ + padding: 0 11px 0 32px; /* top right bottom left */ +} + +ul.list li.ie6-radio-arrow a +{ + height: 0; + width: 0; +} + +ul.list li.ie6-checked-arrow label +{ + background: url(/itablet/images/ie/tick.gif) no-repeat 11px; +} + +ul.list li.ie6-radio-arrow-active, ul.list li.ie6-checked-arrow-active +{ + background: #035de7 url(/itablet/images/ie/blue-chevron.gif) no-repeat right; +} + +ul.list li.ie6-checked-arrow-active label +{ + background: url(/itablet/images/ie/tick-active.gif) no-repeat 11px; +} + diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/css/itablet-ie7.css b/qpid/tools/src/java/bin/qpid-web/web/itablet/css/itablet-ie7.css new file mode 100644 index 0000000000..d7a5b092eb --- /dev/null +++ b/qpid/tools/src/java/bin/qpid-web/web/itablet/css/itablet-ie7.css @@ -0,0 +1,193 @@ +/** + * Stylesheet to try and make things look not *too* bad in IE7. + */ + +/* Needed to get rid of annoying "permanent" IE7 scrollbar. */ +html +{ + overflow: hidden; +} + +#sidebar-wrapper /* Make sure IE "hasLayout" is enabled by doing zoom: 1. */ +{ + zoom: 1; +} + +/* IE7 doesn't correctly size the scrollbar without this, however it causes IE6 problems. */ +.page +{ + height: 100%; +} + +ul.list +{ + width: 100%; +} + +/* IE < 8 doesn't support color: inherit so we have to set it explicitly. */ +ul li.grey a /* Grey text generally used to show inactive fields */ +{ + color: #8f8f8f; +} + +ul li a +{ + color: #060606; +} + +ul li.active a +{ + color: #fff; +} + +/* IE7 gives this anchor a default size which adds extra visible padding. As the navigable radio button has */ +/* reskinned the markup around this li the anchor doesn't actually need to be visible so we can safely hide it. */ +ul.list li.arrow.radio a +{ + display: none; +} + +/* IE < 8 form has a default non-zero margin, so we need to zero it. */ +form +{ + margin: 0; +} + +/* For IE7 :before and :after don't work so we have to resort to some JavaScript to inject extra classes and tags */ +ul.list li:first-child +{ + border-top: 3px groove #fff; /* IE7 without hasLayout set doesn't show the border if it's less than 3px, why??? */ +} + +ul.list li:first-child > .fbefore, /* Use fbefore not before in case first-child and last-child apply to same element. */ +ul.list li:first-child > .fafter /* Use fafter not after in case first-child and last-child apply to same element. */ +{ + position: absolute; + top: -3px; + left: -2px; + width: 10px; + height: 10px; + z-index: 1; + background: url(/itablet/images/ie/radius-10px-sprite.png); +} + +ul.list li:first-child > .fafter /* Use fafter not after in case first-child and last-child apply to same element. */ +{ + left: auto; + right: -2px; + background-position: -10px 0; +} + +/* The fake rounded corners for the IE8 stylesheet more or less work, but the bottom offset in IE7 is different??? */ +ul.list li.last-child +{ + margin-top: -1px; /* Weird IE7 specific bug needs this set to -1px to render it as 0px!!!! */ +} + +ul.list li.last-child > .before, ul.list li.last-child > .after +{ + bottom: -1px; +} + +/* For IE7 button :before and :after don't work so we have to resort to some JavaScript to add extra classes and tags */ + +a.button .before +{ + position: absolute; + top: 0; + left: -5px; + width: 5px; + height: 30px; + background: url(/itablet/images/button-sprite.png) -18px 0; +} + +a.button .after +{ + position: absolute; + top: 0; + right: -5px; + width: 5px; + height: 30px; + background: url(/itablet/images/button-sprite.png) -13px 0; +} + +a.button:active .before +{ + background-position: -41px 0; +} + +a.button:active .after +{ + background-position: -36px 0; +} + +a.button.back .before +{ + position: absolute; + left: -13px; + width: 13px; + height: 30px; + background-position: 0 0; +} + +a.button.back:active .before +{ + background-position: -23px 0; +} + +a.button.blue .before +{ + background: url(/itablet/images/blue-button-sprite.png) -18px 0; +} + +a.button.blue .after +{ + background: url(/itablet/images/blue-button-sprite.png) -13px 0; +} + +a.button.back.blue .before +{ + background-position: 0 0; +} + +a.button.blue:active .before +{ + background-position: -41px 0; +} + +a.button.blue:active .after +{ + background-position: -36px 0; +} + +a.button.back.blue:active .before +{ + background-position: -23px 0; +} + +/* The horiz-checkbox class hasLayout set so the styles below go back to the correct values. */ +/* Unfortunately simply giving ul.list li hasLayout using zoom: 1 above causes the IE7 margin bug to trigger */ +/* so can't default to that hence the weird values for ul.list li.last-child/ul.list li.last-child > .before */ +/* ul.list li.last-child > .after There may be easier ways, but fixing one IE7 bug seems to cause other ones */ +ul.list li.horiz-checkbox:first-child, ul.list li.textarea:first-child +{ + border-top: 1px groove #fff; +} + +ul.list li.horiz-checkbox.last-child, ul.list li.textarea.last-child +{ + margin-top: 0; +} + +ul.list li.horiz-checkbox:first-child > .fbefore, ul.list li.horiz-checkbox:first-child > .fafter, +ul.list li.textarea:first-child > .fbefore, ul.list li.textarea:first-child > .fafter +{ + top: -1px; +} + +ul.list li.horiz-checkbox.last-child > .before, ul.list li.horiz-checkbox.last-child > .after, +ul.list li.textarea.last-child > .before, ul.list li.textarea.last-child > .after +{ + bottom: -2px; +} + diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/css/itablet-ie8.css b/qpid/tools/src/java/bin/qpid-web/web/itablet/css/itablet-ie8.css new file mode 100644 index 0000000000..455a40a3e2 --- /dev/null +++ b/qpid/tools/src/java/bin/qpid-web/web/itablet/css/itablet-ie8.css @@ -0,0 +1,140 @@ +/** + * Stylesheet to try and make things look not *too* bad in IE8 and below + */ + +/** + * To handle opacity in IE < 9 we animate progid:DXImageTransform.Microsoft.gradient in itablet.js + * We use a transparent background image rather than background: transparent to block mouse events to the main page. + * progid:DXImageTransform messes with the font so we only use it for animating and use a 50% alpha png as end style. + */ +.popup-window, input, textarea +{ + background: url(/itablet/images/ie/transparent.png) repeat; +} + +.popup-window.smoked +{ + background: url(/itablet/images/ie/smoked.png) repeat; +} + +/** + * Create fake top rounded corners using images. Fortunately we can do this using pure CSS as ie8 supports + * :first-child, :before and :after so we supply the images as content. + */ + +.header:before, .header:after +{ + position: absolute; + content: ""; + top: 0; + left: 0; + width: 5px; + height: 5px; + background: url(/itablet/images/ie/radius-5px-sprite.png); +} + +.header:after +{ + left: auto; + right: 0; + background-position: -5px; +} + +ul.list li:first-child:before, ul.list li:first-child:after, +ul.horiz-checkbox li.horiz-checkbox:first-child:before, ul.list li.horiz-checkbox:first-child label.first-child:before, +ul.horiz-checkbox li.horiz-checkbox:first-child:after, ul.list li.horiz-checkbox:first-child label.last-child:after +{ + position: absolute; + content: ""; + top: -2px; + left: -2px; + width: 10px; + height: 10px; + background: url(/itablet/images/ie/radius-10px-sprite.png); +} + +ul.list li:first-child:after, +ul.horiz-checkbox li.horiz-checkbox:first-child:after, ul.list li.horiz-checkbox:first-child label.last-child:after +{ + left: auto; + right: -2px; + background-position: -10px 0; +} + +/** + * Create fake bottom rounded corners using images. Unfortunately this isn't as easy as the top corners because + * a) ie8 doesn't support :last-child and b) if we have a single list item we've already used :before and :after + * Unfortunately we have to resort to some JavaScript so itablet.js has some ie8 specific code to add a + * "last-child" class and prepend/append div elements with "before" and "after" classes. Fortunately this is + * fairly clean to do using jQuery using $("ul.list li:last-child") to find the item that we need to modify. + */ + +ul.list li.last-child +{ + border-bottom: 2px groove #fff; +} + +ul.list li.last-child > .before, ul.list li.last-child > .after +{ + position: absolute; + bottom: -2px; + left: -2px; + width: 10px; + height: 10px; + z-index: 1; + background: url(/itablet/images/ie/radius-10px-sprite.png) 0 -10px; +} + +ul.list li.last-child > .after +{ + left: auto; + right: -2px; + background-position: -10px -10px; +} + +/** + * For IE < 9 use solid background colour instead of a gradient - no bigee, it was a subtle gradient anyway. + */ +ul li.active, ul li.radio.checked.active /* Highlight in blue with white text */ +{ + background: #035de7; +} + +ul li.active.arrow +{ + background: #035de7 url(/itablet/images/chevron-active.png) no-repeat right; +} + +ul.list li.arrow.radio.active +{ + background: #035de7 url(/itablet/images/blue-chevron.png) no-repeat right; +} + +/** + * We need to apply the fake border radius to the labels in the horiz-checkbox too as child elements aren't clipped. + * Unfortunately IE8 doesn't seem to distinguish between the selectors ul.list li:first-child:before and + * ul.list li.horiz-checkbox:first-child:before when horiz-checkbox is dynamically added (though it does if it's + * placed in the static HTML) this stops the
  • fake radiused border being correctly repositioned + * for horiz-checkboxes. By adding horiz-checkbox to the
      too we can use a more explicit rule in the CSS. + */ + +/* First we remove the original borders that were previously added for ul.list li:first-child:before and after. */ +ul.list li.horiz-checkbox:first-child:before, ul.list li.horiz-checkbox:first-child:after +{ + content: "."; +} + +/* The we re-add them in the correct position using the more explicit rule on ul.horiz-checkbox */ +/* We need to add the rounded borders to the labels too as they are positioned above the li in the stack. */ +ul.horiz-checkbox li.horiz-checkbox:first-child:before, ul.list li.horiz-checkbox:first-child label.first-child:before, +ul.horiz-checkbox li.horiz-checkbox:first-child:after, ul.list li.horiz-checkbox:first-child label.last-child:after +{ + top: -1px; +} + +canvas /* For IE < 9 the radiused borders for the canvas are actually rendered on the canvas. */ +{ + border: 0; +} + + diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/css/itablet-ie9.css b/qpid/tools/src/java/bin/qpid-web/web/itablet/css/itablet-ie9.css new file mode 100644 index 0000000000..8af2058a70 --- /dev/null +++ b/qpid/tools/src/java/bin/qpid-web/web/itablet/css/itablet-ie9.css @@ -0,0 +1,24 @@ +/** + * Stylesheet to sort out IE9 specific quirks....... + */ + +/** + * For some reason radiused borders cause IE9 to eat CPU when scrolling or animating in the popup window so remove them. + */ + +.popup, .popup-container +{ + border-radius: 0; +} + +.popup .scroll-area +{ + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +input +{ + padding: 12px 0 12px 0; /* top right bottom left */ +} + diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/css/itablet.css b/qpid/tools/src/java/bin/qpid-web/web/itablet/css/itablet.css new file mode 100644 index 0000000000..82498634dd --- /dev/null +++ b/qpid/tools/src/java/bin/qpid-web/web/itablet/css/itablet.css @@ -0,0 +1,973 @@ + +body +{ + font: 13px/1.5 Helvetica, Arial, 'Liberation Sans', FreeSans, sans-serif; + overflow-x: hidden; /* Hide horizontal scrollbar */ + background: #dddddd; +} + +p +{ + margin: 0; + padding: 11px 0 11px 0; /* top right bottom left */ +} + +.sidebar, .main, .popup-window, .popup-container, .popup, .scroll-area +{ + -moz-user-select: -moz-none; /* Disable selection on fields other than input & textarea. */ + -webkit-user-select: none; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + background: #000; +} + +.sidebar +{ + width: 250px; + border-right: 1px solid #000; + z-index: 2; +} + +.main +{ + left: 251px; +} + +.popup-window +{ + overflow: hidden; + background-color: rgba(0, 0, 0, 0.5); + z-index: 5; +} + +.popup, .popup-container +{ + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; +} + +.popup-container +{ + top: 64px; + bottom: 64px; + left: 20%; + right: 20%; + + overflow-x: hidden; + box-shadow: 10px 10px 10px #777; +} + +.scroll-area +{ + top: 44px; + overflow-x: hidden; + overflow-y: auto; + background: #dddddd; +} + +div .mail +{ + background: #f5f5f5; +} + +.popup .scroll-area +{ + -moz-border-bottom-left-radius: 5px; + -webkit-border-bottom-left-radius: 5px; + border-bottom-left-radius: 5px; + -moz-border-bottom-right-radius: 5px; + -webkit-border-bottom-right-radius: 5px; + border-bottom-right-radius: 5px; +} + +.page +{ + padding: 31px 5% 31px 5%; /* top right bottom left */ +} + +.page h1 +{ + color: #666666; + text-shadow: #fff 0 1px 0; + text-indent: 10px; + font-size: 17px; + + margin: 0; + padding: 16px 0 4px 0; /* top right bottom left */ +} + +.page h1.first +{ + padding: 0 0 4px 0; /* top right bottom left */ +} + +.page p.note +{ + color: #717880; + text-shadow: #fff 0 1px 0; + text-align: center; + font-size: 15px; + font-weight: normal; + + margin: 0; + padding: 4px 0 16px 0; /* top right bottom left */ +} + +.page p.note.nopadding +{ + padding-bottom: 0; +} + +/*------------------------------------------- Header ------------------------------------------------*/ + +div.header +{ + left: 0; + right: 0; + height: 43px; + line-height: 43px; + + -moz-border-top-left-radius: 5px; + -webkit-border-top-left-radius: 5px; + border-top-left-radius: 5px; + -moz-border-top-right-radius: 5px; + -webkit-border-top-right-radius: 5px; + border-top-right-radius: 5px; + border-bottom: 1px solid #858b9b; + + background: #bbb url(/itablet/images/ie/header-gradient.png) repeat-x; + background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(1, #999)); + background: -webkit-linear-gradient(top center, #fff 0%, #999 100%); + background: -moz-linear-gradient(top center, #fff 0%, #999 100%); + background: -ms-linear-gradient(top center, #fff 0%, #999 100%); + background: -o-linear-gradient(top center, #fff 0%, #999 100%); + background: linear-gradient(top center, #fff 0%, #999 100%); +} + +div.header h1 +{ + text-align: center; + font-size: 20px; + font-weight: bold; + color: #717880; + text-shadow: #fff 0 1px 0; + + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + + margin: 0 12px 0 12px; /* top right bottom left */ +} + +div.header a.back.button + h1 +{ + margin: 0 88px 0 88px; /* top right bottom left */ +} + +div.header a.cancel.button + h1 +{ + margin: 0 62px 0 62px; /* top right bottom left */ +} + +/*--------------------------------------- Header Buttons --------------------------------------------*/ + +a.button +{ + outline: none; + text-decoration: none; + text-shadow: rgba(0, 0, 0, 0.6) 0 -1px 0; + color: #ddd; + background: #777; + font-size: 12px; + font-weight: bold; + line-height: 28px; + + display: block; + position: absolute; + top: 7px; + left: 12px; + height: 30px; + + background: url(/itablet/images/button-sprite.png) 0px -30px repeat-x; +} + +a.button:before +{ + position: absolute; + content: ""; + top: 0; + left: -5px; + width: 5px; + height: 30px; + background: url(/itablet/images/button-sprite.png) -18px 0 no-repeat; +} + +a.button:after +{ + position: absolute; + content: ""; + top: 0; + right: -5px; + width: 5px; + height: 30px; + background: url(/itablet/images/button-sprite.png) -13px 0 no-repeat; +} + +a.button:active +{ + background-color: #766d69; + background-position: 0 -60px; +} + +a.button:active:before +{ + background-position: -41px 0; +} + +a.button:active:after +{ + background-position: -36px 0; +} + +a.button.back +{ + left: 20px; +} + +a.button.back:before +{ + position: absolute; + left: -13px; + width: 13px; + height: 30px; + background-position: 0 0; +} + +a.button.back:active:before +{ + background-position: -23px 0; +} + +a.button.right +{ + left: auto; + right: 12px; +} + +a.button.blue +{ + color: #fff; + background: url(/itablet/images/blue-button-sprite.png) 0px -30px repeat-x; +} + +a.button.blue:before +{ + background: url(/itablet/images/blue-button-sprite.png) -18px 0 no-repeat; +} + +a.button.blue:after +{ + background: url(/itablet/images/blue-button-sprite.png) -13px 0 no-repeat; +} + +a.button.back.blue:before +{ + background-position: 0 0; +} + +a.button.blue:active +{ + background-color: #6b6f76; + background-position: 0px -60px; +} + +a.button.blue:active:before +{ + background-position: -41px 0; +} + +a.button.blue:active:after +{ + background-position: -36px 0; +} + +a.button.back.blue:active:before +{ + background-position: -23px 0; +} + +/*----------------------------------- Toolbar and Stock Buttons -------------------------------------*/ + +span.toolbar +{ + position: absolute; + overflow: hidden; + top: 7px; + left: auto; + right: 12px; +} + +span.toolbar a +{ + outline: none; + text-decoration: none; + display: block; + float: left; + width: 32px; + height: 32px; +} + +a.delete +{ + background: url(/itablet/images/delete.png) no-repeat left; +} + +a.add +{ + background: url(/itablet/images/add.png) no-repeat left; +} + +a.home +{ + background: url(/itablet/images/home.png) no-repeat left; +} + +a.flag +{ + background: url(/itablet/images/flag.png) no-repeat left; +} + +a.move +{ + background: url(/itablet/images/move.png) no-repeat left; +} + +a.bin +{ + background: url(/itablet/images/bin.png) no-repeat left; +} + +a.action +{ + background: url(/itablet/images/action.png) no-repeat left; +} + +a.write +{ + background: url(/itablet/images/write.png) no-repeat left; +} + +/* Add a "glowing" highlight to toolbar and clickable icons */ +span.toolbar a:active:before, +ul.list li.clickable-icon a:active:before +{ + position: absolute; + content: ""; + top: 0; + left: 0; + width: 32px; + height: 100%; + background: url(/itablet/images/ie/radial-gradient.png) no-repeat left; + background: -webkit-gradient(radial, center center, 0, center center, 16, from(rgba(255,255,255,1)), to(rgba(200,200,200,0))); + background: -webkit-radial-gradient(center center, circle cover, rgba(255,255,255,1), rgba(200,200,200,0) 75%); + background: -moz-radial-gradient(center center, circle cover, rgba(255,255,255,1), rgba(200,200,200,0) 75%); + background: -ms-radial-gradient(center center, circle cover, rgba(255,255,255,1), rgba(200,200,200,0) 75%); + background: -o-radial-gradient(center center, circle cover, rgba(255,255,255,1), rgba(200,200,200,0) 75%); + background: radial-gradient(center center, circle cover, rgba(255,255,255,1), rgba(200,200,200,0) 75%); +} + +span.toolbar a:active:before +{ + position: relative; + float: left; +} + +/*---- this is hidden for desktop browsers it is shown by the styles enabled by the media query -----*/ + +div.header a.menu +{ + display: none; +} + +/*------------------------------- Define the styles for list elements -------------------------------*/ + +ul +{ + list-style: none; + margin: 0; + padding: 0; +} + +ul li +{ + position: relative; + line-height: 42px; + padding: 1px 0 0 0; /* top right bottom left */ + + color: #060606; + font-size: 17px; + font-weight: bold; + border-bottom: 1px solid #ccc; +} + +ul.list li +{ + line-height: 21px; + padding: 11px 0 11px 0; + + background-color: #f7f7f7; + border-left: 2px groove #fff; + border-right: 2px groove #fff; +} + +ul.list li.multiline, ul.list li.icon, ul.list li.clickable-icon +{ + padding: 5px 0 5px 0; +} + +ul.list li:first-child +{ + -moz-border-top-left-radius: 10px; + -webkit-border-top-left-radius: 10px; + border-top-left-radius: 10px; + -moz-border-top-right-radius: 10px; + -webkit-border-top-right-radius: 10px; + border-top-right-radius: 10px; + border-top: 2px groove #fff; +} + +ul.list li:last-child +{ + -moz-border-bottom-left-radius: 10px; + -webkit-border-bottom-left-radius: 10px; + border-bottom-left-radius: 10px; + -moz-border-bottom-right-radius: 10px; + -webkit-border-bottom-right-radius: 10px; + border-bottom-right-radius: 10px; + border-bottom: 2px groove #fff; +} + +ul.mail li +{ + line-height: 24px; + padding-bottom: 3px; +} + +ul li.pop +{ + text-align: center; +} + +ul li.radio.checked /* Adjust text colour on selected radio item */ +{ + color: #385487; + background: #f7f7f7; +} + +ul li.grey /* Grey text generally used to show inactive fields */ +{ + color: #8f8f8f; +} + +ul li.active, ul li.radio.checked.active /* Highlight in blue with white text */ +{ + background: #035de7 url(/itablet/images/ie/active-gradient.png) repeat-x; + background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #058cf7), color-stop(1, #035de7)); + background: -webkit-linear-gradient(top center, #058cf7 0%, #035de7 100%); + background: -moz-linear-gradient(top center, #058cf7 0%, #035de7 100%); + background: -ms-linear-gradient(top center, #058cf7 0%, #035de7 100%); + background: -o-linear-gradient(top center, #058cf7 0%, #035de7 100%); + background: linear-gradient(top center, #058cf7 0%, #035de7 100%); + color: #fff; +} + +/*------------------------------ Define the styles for anchor elements ------------------------------*/ + +input, textarea, a +{ + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); /* Hide the tap highlighting by making it transparent. */ +} + +a +{ + -webkit-touch-callout: none; + cursor: default; /* Disable the "hand" cursor over anchors. */ +} + +ul li a +{ + outline: none; + text-decoration: none; /* Hide the underline */ + color: inherit; /* Get the text colour from the item containing the anchor. */ + display: block; /* Treat anchor as a block element - needed to correctly display image. */ +} + + +ul.list li a, label, ul.list li.arrow a, ul.mail li a, ul.list li.multiline a div +{ + position: relative; + padding: 0 11px 0 11px; /* top right bottom left */ + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +ul.list li.arrow a, ul.mail li.arrow a +{ + padding-right: 30px; /* When a list item has a chevron we need to increase anchor right padding past it. */ +} + +ul li.icon a, ul li.clickable-icon a +{ + margin-left: 5px; + text-indent: 40px; +} + +ul.list li.icon a, ul.list li.clickable-icon a +{ + margin-left: 8px; + text-indent: 30px; + + /* For icon/clickable-icon when not a multiline item we need to increase anchor top and bottom padding so + that we don't end up clipping the top and bottom off the icon. */ + padding-top: 5px; + padding-bottom: 5px; +} + +ul.mail li a +{ + left: 8px; + text-indent: 18px; /* Indents the text to the right of the image. */ +} + +ul.mail li.unread a +{ + background: url(/itablet/images/blueball.png) no-repeat left; +} + + +ul li.arrow +{ + text-align: left; /* This resets alignment in case class="pop arrow" is used because pop centre aligns. */ + background: url(/itablet/images/chevron.png) no-repeat right; +} + +ul.list li.arrow +{ + background: #f7f7f7 url(/itablet/images/chevron.png) no-repeat right; +} + +ul li.active.arrow +{ + background: url(/itablet/images/chevron-active.png) no-repeat right, #035de7 url(/itablet/images/ie/active-gradient.png) repeat-x; + background: url(/itablet/images/chevron-active.png) no-repeat right, -webkit-gradient(linear, left top, left bottom, color-stop(0, #058cf7), color-stop(1, #035de7)); + background: url(/itablet/images/chevron-active.png) no-repeat right, -webkit-linear-gradient(top center, #058cf7 0%, #035de7 100%); + background: url(/itablet/images/chevron-active.png) no-repeat right, -moz-linear-gradient(top center, #058cf7 0%, #035de7 100%); + background: url(/itablet/images/chevron-active.png) no-repeat right, -ms-linear-gradient(top center, #058cf7 0%, #035de7 100%); + background: url(/itablet/images/chevron-active.png) no-repeat right, -o-linear-gradient(top center, #058cf7 0%, #035de7 100%); + background: url(/itablet/images/chevron-active.png) no-repeat right, linear-gradient(top center, #058cf7 0%, #035de7 100%); +} + +/*--------------------------- Define the styles for right justified text ----------------------------*/ + +ul li a p +{ + position: absolute; + top: 0; + right: 11px; + + padding: 0; + width: 50%; + text-align: right; + text-indent: 0; + + color: #464646; + font-weight: normal; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +ul li a p.fullwidth +{ + width: 100%; +} + +ul li a p.date +{ + color: #3078da; + font-size: 13px; +} + +ul li.arrow a p +{ + right: 30px; +} + +/*----------------------------- Define the styles for multiline items -------------------------------*/ + +ul.list li.multiline a +{ + padding-top: 0px; + padding-bottom: 0px; +} + +ul.list li.multiline a div +{ + padding: 0; +} + +ul.list li.multiline a div p +{ + right: 0; +} + +ul li a p.sub, ul li a p.title +{ + position: relative; + top: 0; + left: 0; + + width: auto; + text-align: left; + + color: gray; + font-size: 14px; + line-height: 16px; +} + +ul li a p.title +{ + color: #060606; +} + +ul.list li.icon a p.sub, ul.list li.clickable-icon a p.sub, +ul.list li.icon a p.title, ul.list li.clickable-icon a p.title +{ + margin-left: 30px; +} + +ul.mail li a p.sub, ul.mail li a p.title +{ + margin-left: 18px; +} + +ul.mail li a p.sub +{ + font-size: 12px; + height: 33px; + white-space: normal; +} + +ul li.active a p, ul.mail li.active a p +{ + color: #fff; +} + +/*------------------------------- Define the styles for input fields --------------------------------*/ + +label +{ + display: block; +} + +label.input /* Adding the input class to a label will allow overflow truncation to work */ +{ + width: 115px; +} + +input, .placeholder +{ + position: absolute; + top: 0; + left: 115px; + right: 11px; + padding: 9px 0 9px 0; /* top right bottom left */ + border: 0; + font: 17px Helvetica, Arial, 'Liberation Sans', FreeSans, sans-serif; +} + + +.placeholder.textarea +{ + left: 11px; + font-size: 12px +} + +.placeholder /* Used to fake HTML5 input placeholders in browsers that don't have native support. */ +{ + padding: 12px 0 12px 0; /* top right bottom left */ + color: #9f9f9f; +} + +input.error, textarea.error +{ + -webkit-appearance: none; + moz-box-shadow: 0 0 4px red; + webkit-box-shadow: 0 0 4px red; + box-shadow: 0 0 4px red; +} + +textarea +{ + position: relative; /* Needs to be set for fake placeholders to work properly - the z-index needs to be 1 */ + + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + + resize: vertical; + + width: 100%; + height: 100px; + + border: 0; + padding: 0 11px 0 11px; + + overflow: auto; +} + +/* + For fake placeholders to work we want to ensure the input/textarea is in the foreground and receiving events, + but we also need them to be transparent so we can see the placeholder through them. +*/ +input, textarea +{ + background: rgba(0, 0, 0, 0); + z-index: 1; +} + +/*---------------------------- Define the styles for radio button widget ----------------------------*/ + +ul.list li.radio label +{ + padding: 0 32px 0 11px; /* top right bottom left */ +} + +ul.list li.radio.checked label +{ + background: url(/itablet/images/tick.png) no-repeat right; +} + +ul.list li.radio.active.checked label +{ + background: url(/itablet/images/tick-active.png) no-repeat right; +} + +ul.list li.arrow.radio +{ + background: #f7f7f7 url(/itablet/images/blue-chevron.png) no-repeat right; +} + +ul.list li.arrow.radio.active +{ + background: url(/itablet/images/blue-chevron.png) no-repeat right, #035de7 url(/itablet/images/ie/active-gradient.png) repeat-x; + background: url(/itablet/images/blue-chevron.png) no-repeat right, -webkit-gradient(linear, left top, left bottom, color-stop(0, #058cf7), color-stop(1, #035de7)); + background: url(/itablet/images/blue-chevron.png) no-repeat right, -webkit-linear-gradient(top center, #058cf7 0%, #035de7 100%); + background: url(/itablet/images/blue-chevron.png) no-repeat right, -moz-linear-gradient(top center, #058cf7 0%, #035de7 100%); + background: url(/itablet/images/blue-chevron.png) no-repeat right, -ms-linear-gradient(top center, #058cf7 0%, #035de7 100%); + background: url(/itablet/images/blue-chevron.png) no-repeat right, -o-linear-gradient(top center, #058cf7 0%, #035de7 100%); + background: url(/itablet/images/blue-chevron.png) no-repeat right, linear-gradient(top center, #058cf7 0%, #035de7 100%); +} + +ul.list li.arrow.radio label +{ + padding: 0 38px 0 32px; /* top right bottom left */ +} + +ul.list li.arrow.radio.checked label +{ + background: url(/itablet/images/tick.png) no-repeat 11px; +} + +ul.list li.arrow.radio.active.checked label +{ + background: url(/itablet/images/tick-active.png) no-repeat 11px; +} + +/*------------------------------ Define the styles for checkbox widget ------------------------------*/ + +div.checkbox +{ + position: absolute; + overflow: hidden; /* clip the child div to the size of this one */ + top: 7px; + right: 11px; + width: 77px; + height: 27px; +} + +div.mask +{ + position: absolute; + width: 100%; + height: 100%; + z-index: 1; + background: url(/itablet/images/mask.png) no-repeat; +} + +div.onoff +{ + position: absolute; + top: 0; + left: -50px; + width: 127px; + height: 27px; + background: url(/itablet/images/on_off.png) no-repeat; +} + +/*------------------------- Define the styles for horizontal checkbox widget ------------------------*/ + +ul.list li.horiz-checkbox +{ + display: block; + padding: 0; + line-height: 40px; + background: url(/itablet/images/toggle-off.png) repeat-x; +} + +ul.list li.horiz-checkbox label +{ + color: #717880; + text-shadow: #fff 0 1px 0; + + display: inline-block; + vertical-align: bottom; + text-align: center; + padding: 0; + width: 100%; + background: url(/itablet/images/toggle-off.png) repeat-x; +} + +ul.list li.horiz-checkbox label span +{ + position: absolute; + top: 0; + right: 0; + height: 100%; + border-right: 1px solid #828278; +} + +/* Use toggle-on class not checked to avoid IE6 confusing with a radio button as IE6 doesn't support multiple classes. */ +ul.list li.horiz-checkbox.toggle-on, ul.list li.horiz-checkbox label.checked +{ + color: #fff; + text-shadow: 0 0 0 #000; /* passing all the arguments will reset it to nothing */ + background: url(/itablet/images/toggle-on.png) repeat-x; +} + +ul.list li.horiz-checkbox label.checked span +{ + border-right: 0; + width: 5px; + height: 40px; + background: url(/itablet/images/toggle-on-border.png) no-repeat right; +} + +ul.list li.horiz-checkbox:first-child +{ + border-top: 1px groove #fff; +} + +/* Need to apply border radius to the labels in the horiz-checkbox too as child elements aren't clipped. */ + +ul.list li.horiz-checkbox:first-child label.first-child +{ + -moz-border-top-left-radius: 10px; + -webkit-border-top-left-radius: 10px; + border-top-left-radius: 10px; +} + +ul.list li.horiz-checkbox:first-child label.last-child +{ + -moz-border-top-right-radius: 10px; + -webkit-border-top-right-radius: 10px; + border-top-right-radius: 10px; +} + +ul.list li.horiz-checkbox:last-child label.first-child +{ + -moz-border-bottom-left-radius: 10px; + -webkit-border-bottom-left-radius: 10px; + border-bottom-left-radius: 10px; +} + +ul.list li.horiz-checkbox:last-child label.last-child +{ + -moz-border-bottom-right-radius: 10px; + -webkit-border-bottom-right-radius: 10px; + border-bottom-right-radius: 10px; +} + +/*-------------------------------- Style for the HTML5 drawing canvas -------------------------------*/ +/* N.B. By the standard, CSS does not size the canvas coordinate system, it scales the content. This */ +/* means that we can't style canvas width and height, these must be set via Javascript if we wish to */ +/* use relative sizes. */ +/*---------------------------------------------------------------------------------------------------*/ +canvas +{ + border: 2px groove #fff; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + border-radius: 10px; + background-color: #f6f6f6; + display: block; +} + + + + +/*---------------------------- Detect mobile sized screen via media query ---------------------------*/ +/* +@media only screen and (max-width: 480px) +*/ + +@media only screen and (max-device-width: 480px), + only screen and (min-device-width: 640px) and (max-device-width: 1136px) and (-webkit-min-device-pixel-ratio: 2) +{ + .sidebar + { + width: 100%; + } + + .main /* We check the .main left value in JavaScript if we want to detect mobile or non-mobile */ + { + left: 0; + } + + .popup-container + { /* For some reason the Android VM I'm using isn't respecting top & bottom of zero here iPhone is fine!! */ + top: 0; + bottom: 0; + left: 0; + right: 0; + } + + /* For mobile devices display the menu back buttons */ + div.header a.menu + { + display: block; + } + + .sidebar ul li + { + background: url(/itablet/images/chevron.png) no-repeat right; + } + + .sidebar ul li.active + { + background: url(/itablet/images/chevron-active.png) no-repeat right, #035de7 url(/itablet/images/ie/active-gradient.png) repeat-x; + background: url(/itablet/images/chevron-active.png) no-repeat right, -webkit-gradient(linear, left top, left bottom, color-stop(0, #058cf7), color-stop(1, #035de7)); + background: url(/itablet/images/chevron-active.png) no-repeat right, -webkit-linear-gradient(top center, #058cf7 0%, #035de7 100%); + background: url(/itablet/images/chevron-active.png) no-repeat right, -moz-linear-gradient(top center, #058cf7 0%, #035de7 100%); + background: url(/itablet/images/chevron-active.png) no-repeat right, -ms-linear-gradient(top center, #058cf7 0%, #035de7 100%); + background: url(/itablet/images/chevron-active.png) no-repeat right, -o-linear-gradient(top center, #058cf7 0%, #035de7 100%); + background: url(/itablet/images/chevron-active.png) no-repeat right, linear-gradient(top center, #058cf7 0%, #035de7 100%); + } +} + + diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/action.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/action.png new file mode 100644 index 0000000000..af5e0378b0 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/action.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/add.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/add.png new file mode 100644 index 0000000000..700d9f100e Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/add.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/bin.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/bin.png new file mode 100644 index 0000000000..90923898af Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/bin.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/blue-button-sprite.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/blue-button-sprite.png new file mode 100644 index 0000000000..9fedd12867 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/blue-button-sprite.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/blue-chevron.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/blue-chevron.png new file mode 100644 index 0000000000..41e539fc10 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/blue-chevron.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/blueball.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/blueball.png new file mode 100644 index 0000000000..a7c4c68349 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/blueball.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/button-sprite.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/button-sprite.png new file mode 100644 index 0000000000..c15b4ea217 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/button-sprite.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/chevron-active.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/chevron-active.png new file mode 100644 index 0000000000..86832ebc7b Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/chevron-active.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/chevron.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/chevron.png new file mode 100644 index 0000000000..6421a16762 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/chevron.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/delete.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/delete.png new file mode 100644 index 0000000000..74b1ff3ea1 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/delete.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/flag.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/flag.png new file mode 100644 index 0000000000..0baf2a9986 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/flag.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/home.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/home.png new file mode 100644 index 0000000000..4f359778a2 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/home.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/active-gradient.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/active-gradient.png new file mode 100644 index 0000000000..6cd4404965 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/active-gradient.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/blue-button-sprite.gif b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/blue-button-sprite.gif new file mode 100644 index 0000000000..8edaddedd8 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/blue-button-sprite.gif differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/blue-chevron.gif b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/blue-chevron.gif new file mode 100644 index 0000000000..bb8f3d51d6 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/blue-chevron.gif differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/button-sprite.gif b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/button-sprite.gif new file mode 100644 index 0000000000..5e920511d1 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/button-sprite.gif differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/chevron-active.gif b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/chevron-active.gif new file mode 100644 index 0000000000..f37329bb3b Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/chevron-active.gif differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/chevron.gif b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/chevron.gif new file mode 100644 index 0000000000..dce238269a Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/chevron.gif differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/header-gradient.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/header-gradient.png new file mode 100644 index 0000000000..d4e9a6c9f0 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/header-gradient.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/radial-gradient.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/radial-gradient.png new file mode 100644 index 0000000000..d9ab361add Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/radial-gradient.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/radius-10px-sprite.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/radius-10px-sprite.png new file mode 100644 index 0000000000..ca91770e2f Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/radius-10px-sprite.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/radius-5px-sprite.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/radius-5px-sprite.png new file mode 100644 index 0000000000..c00e2194db Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/radius-5px-sprite.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/red6.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/red6.png new file mode 100644 index 0000000000..c1c0ba1db9 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/red6.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/smoked.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/smoked.png new file mode 100644 index 0000000000..ea6b7c587f Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/smoked.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/tick-active.gif b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/tick-active.gif new file mode 100644 index 0000000000..629f6f1eca Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/tick-active.gif differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/tick.gif b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/tick.gif new file mode 100644 index 0000000000..fdbdc1eec2 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/tick.gif differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/transparent.gif b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/transparent.gif new file mode 100755 index 0000000000..c5b2954ac6 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/transparent.gif differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/transparent.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/transparent.png new file mode 100644 index 0000000000..8ac7f64f1a Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/ie/transparent.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/mask.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/mask.png new file mode 100644 index 0000000000..f8be0e6f36 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/mask.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/move.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/move.png new file mode 100644 index 0000000000..80f77eeb72 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/move.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/on_off.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/on_off.png new file mode 100644 index 0000000000..89243bf27d Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/on_off.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/tick-active.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/tick-active.png new file mode 100644 index 0000000000..16fa8ca71b Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/tick-active.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/tick.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/tick.png new file mode 100644 index 0000000000..783b60fe9a Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/tick.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/toggle-off.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/toggle-off.png new file mode 100644 index 0000000000..474ad3cd63 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/toggle-off.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/toggle-on-border.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/toggle-on-border.png new file mode 100644 index 0000000000..7680cd7d0a Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/toggle-on-border.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/toggle-on.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/toggle-on.png new file mode 100644 index 0000000000..275aa42114 Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/toggle-on.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/images/write.png b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/write.png new file mode 100644 index 0000000000..b7329dbf9f Binary files /dev/null and b/qpid/tools/src/java/bin/qpid-web/web/itablet/images/write.png differ diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/scripts/LICENCE b/qpid/tools/src/java/bin/qpid-web/web/itablet/scripts/LICENCE new file mode 100644 index 0000000000..42cf8a1198 --- /dev/null +++ b/qpid/tools/src/java/bin/qpid-web/web/itablet/scripts/LICENCE @@ -0,0 +1,72 @@ +/* + * itablet.js + * + * Copyright (c) 2013, Fraser Adams + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * 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. + * + */ + + +/* + * jQuery JavaScript Library v1.7.1 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Mon Nov 21 21:11:03 2011 -0500 + */ + + +/* + * iscroll.js + * + * Copyright (c) 2011 Matteo Spinelli, http://cubiq.org/ + * + * 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. + * + */ + + + diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/scripts/iscroll.js b/qpid/tools/src/java/bin/qpid-web/web/itablet/scripts/iscroll.js new file mode 100644 index 0000000000..46330e51f7 --- /dev/null +++ b/qpid/tools/src/java/bin/qpid-web/web/itablet/scripts/iscroll.js @@ -0,0 +1,1117 @@ +/*! + * iScroll v4.2 ~ Copyright (c) 2012 Matteo Spinelli, http://cubiq.org + * Released under MIT license, http://cubiq.org/license + */ +(function(window, doc){ +var m = Math, + dummyStyle = doc.createElement('div').style, + vendor = (function () { + var vendors = 't,webkitT,MozT,msT,OT'.split(','), + t, + i = 0, + l = vendors.length; + + for ( ; i < l; i++ ) { + t = vendors[i] + 'ransform'; + if ( t in dummyStyle ) { + return vendors[i].substr(0, vendors[i].length - 1); + } + } + + return false; + })(), + cssVendor = vendor ? '-' + vendor.toLowerCase() + '-' : '', + + // Style properties + transform = prefixStyle('transform'), + transitionProperty = prefixStyle('transitionProperty'), + transitionDuration = prefixStyle('transitionDuration'), + transformOrigin = prefixStyle('transformOrigin'), + transitionTimingFunction = prefixStyle('transitionTimingFunction'), + transitionDelay = prefixStyle('transitionDelay'), + + // Browser capabilities + isAndroid = (/android/gi).test(navigator.appVersion), + isIDevice = (/iphone|ipad/gi).test(navigator.appVersion), + isTouchPad = (/hp-tablet/gi).test(navigator.appVersion), + + has3d = prefixStyle('perspective') in dummyStyle, + hasTouch = 'ontouchstart' in window && !isTouchPad, + hasTransform = !!vendor, + hasTransitionEnd = prefixStyle('transition') in dummyStyle, + + RESIZE_EV = 'onorientationchange' in window ? 'orientationchange' : 'resize', + START_EV = hasTouch ? 'touchstart' : 'mousedown', + MOVE_EV = hasTouch ? 'touchmove' : 'mousemove', + END_EV = hasTouch ? 'touchend' : 'mouseup', + CANCEL_EV = hasTouch ? 'touchcancel' : 'mouseup', + WHEEL_EV = vendor == 'Moz' ? 'DOMMouseScroll' : 'mousewheel', + TRNEND_EV = (function () { + if ( vendor === false ) return false; + + var transitionEnd = { + '' : 'transitionend', + 'webkit' : 'webkitTransitionEnd', + 'Moz' : 'transitionend', + 'O' : 'oTransitionEnd', + 'ms' : 'MSTransitionEnd' + }; + + return transitionEnd[vendor]; + })(), + + nextFrame = (function() { + return window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function(callback) { return setTimeout(callback, 1); }; + })(), + cancelFrame = (function () { + return window.cancelRequestAnimationFrame || + window.webkitCancelAnimationFrame || + window.webkitCancelRequestAnimationFrame || + window.mozCancelRequestAnimationFrame || + window.oCancelRequestAnimationFrame || + window.msCancelRequestAnimationFrame || + clearTimeout; + })(), + + // Helpers + translateZ = has3d ? ' translateZ(0)' : '', + + // Constructor + iScroll = function (el, options) { + var that = this, + i; + + that.wrapper = typeof el == 'object' ? el : doc.getElementById(el); + that.wrapper.style.overflow = 'hidden'; + that.scroller = that.wrapper.children[0]; + + // Default options + that.options = { + hScroll: true, + vScroll: true, + x: 0, + y: 0, + bounce: true, + bounceLock: false, + momentum: true, + lockDirection: true, + useTransform: true, + useTransition: false, + topOffset: 0, + checkDOMChanges: false, // Experimental + handleClick: true, + + // Scrollbar + hScrollbar: true, + vScrollbar: true, + fixedScrollbar: isAndroid, + hideScrollbar: isIDevice, + fadeScrollbar: isIDevice && has3d, + scrollbarClass: '', + + // Zoom + zoom: false, + zoomMin: 1, + zoomMax: 4, + doubleTapZoom: 2, + wheelAction: 'scroll', + + // Snap + snap: false, + snapThreshold: 1, + + // Events + onRefresh: null, + onBeforeScrollStart: function (e) { e.preventDefault(); }, + onScrollStart: null, + onBeforeScrollMove: null, + onScrollMove: null, + onBeforeScrollEnd: null, + onScrollEnd: null, + onTouchEnd: null, + onDestroy: null, + onZoomStart: null, + onZoom: null, + onZoomEnd: null + }; + + // User defined options + for (i in options) that.options[i] = options[i]; + + // Set starting position + that.x = that.options.x; + that.y = that.options.y; + + // Normalize options + that.options.useTransform = hasTransform && that.options.useTransform; + that.options.hScrollbar = that.options.hScroll && that.options.hScrollbar; + that.options.vScrollbar = that.options.vScroll && that.options.vScrollbar; + that.options.zoom = that.options.useTransform && that.options.zoom; + that.options.useTransition = hasTransitionEnd && that.options.useTransition; + + // Helpers FIX ANDROID BUG! + // translate3d and scale doesn't work together! + // Ignoring 3d ONLY WHEN YOU SET that.options.zoom + if ( that.options.zoom && isAndroid ){ + translateZ = ''; + } + + // Set some default styles + that.scroller.style[transitionProperty] = that.options.useTransform ? cssVendor + 'transform' : 'top left'; + that.scroller.style[transitionDuration] = '0'; + that.scroller.style[transformOrigin] = '0 0'; + if (that.options.useTransition) that.scroller.style[transitionTimingFunction] = 'cubic-bezier(0.33,0.66,0.66,1)'; + + if (that.options.useTransform) that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px)' + translateZ; + else that.scroller.style.cssText += ';position:absolute;top:' + that.y + 'px;left:' + that.x + 'px'; + + if (that.options.useTransition) that.options.fixedScrollbar = true; + + that.refresh(); + + that._bind(RESIZE_EV, window); + that._bind(START_EV); + if (!hasTouch) { + that._bind('mouseout', that.wrapper); + if (that.options.wheelAction != 'none') + that._bind(WHEEL_EV); + } + + if (that.options.checkDOMChanges) that.checkDOMTime = setInterval(function () { + that._checkDOMChanges(); + }, 500); + }; + +// Prototype +iScroll.prototype = { + enabled: true, + x: 0, + y: 0, + steps: [], + scale: 1, + currPageX: 0, currPageY: 0, + pagesX: [], pagesY: [], + aniTime: null, + wheelZoomCount: 0, + + handleEvent: function (e) { + var that = this; + switch(e.type) { + case START_EV: + if (!hasTouch && e.button !== 0) return; + that._start(e); + break; + case MOVE_EV: that._move(e); break; + case END_EV: + case CANCEL_EV: that._end(e); break; + case RESIZE_EV: that._resize(); break; + case WHEEL_EV: that._wheel(e); break; + case 'mouseout': that._mouseout(e); break; + case TRNEND_EV: that._transitionEnd(e); break; + } + }, + + _checkDOMChanges: function () { + if (this.moved || this.zoomed || this.animating || + (this.scrollerW == this.scroller.offsetWidth * this.scale && this.scrollerH == this.scroller.offsetHeight * this.scale)) return; + + this.refresh(); + }, + + _scrollbar: function (dir) { + var that = this, + bar; + + if (!that[dir + 'Scrollbar']) { + if (that[dir + 'ScrollbarWrapper']) { + if (hasTransform) that[dir + 'ScrollbarIndicator'].style[transform] = ''; + that[dir + 'ScrollbarWrapper'].parentNode.removeChild(that[dir + 'ScrollbarWrapper']); + that[dir + 'ScrollbarWrapper'] = null; + that[dir + 'ScrollbarIndicator'] = null; + } + + return; + } + + if (!that[dir + 'ScrollbarWrapper']) { + // Create the scrollbar wrapper + bar = doc.createElement('div'); + + if (that.options.scrollbarClass) bar.className = that.options.scrollbarClass + dir.toUpperCase(); + else bar.style.cssText = 'position:absolute;z-index:100;' + (dir == 'h' ? 'height:7px;bottom:1px;left:2px;right:' + (that.vScrollbar ? '7' : '2') + 'px' : 'width:7px;bottom:' + (that.hScrollbar ? '7' : '2') + 'px;top:2px;right:1px'); + + bar.style.cssText += ';pointer-events:none;' + cssVendor + 'transition-property:opacity;' + cssVendor + 'transition-duration:' + (that.options.fadeScrollbar ? '350ms' : '0') + ';overflow:hidden;opacity:' + (that.options.hideScrollbar ? '0' : '1'); + + that.wrapper.appendChild(bar); + that[dir + 'ScrollbarWrapper'] = bar; + + // Create the scrollbar indicator + bar = doc.createElement('div'); + if (!that.options.scrollbarClass) { + bar.style.cssText = 'position:absolute;z-index:100;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);' + cssVendor + 'background-clip:padding-box;' + cssVendor + 'box-sizing:border-box;' + (dir == 'h' ? 'height:100%' : 'width:100%') + ';' + cssVendor + 'border-radius:3px;border-radius:3px'; + } + bar.style.cssText += ';pointer-events:none;' + cssVendor + 'transition-property:' + cssVendor + 'transform;' + cssVendor + 'transition-timing-function:cubic-bezier(0.33,0.66,0.66,1);' + cssVendor + 'transition-duration:0;' + cssVendor + 'transform: translate(0,0)' + translateZ; + if (that.options.useTransition) bar.style.cssText += ';' + cssVendor + 'transition-timing-function:cubic-bezier(0.33,0.66,0.66,1)'; + + that[dir + 'ScrollbarWrapper'].appendChild(bar); + that[dir + 'ScrollbarIndicator'] = bar; + } + + if (dir == 'h') { + that.hScrollbarSize = that.hScrollbarWrapper.clientWidth; + that.hScrollbarIndicatorSize = m.max(m.round(that.hScrollbarSize * that.hScrollbarSize / that.scrollerW), 8); + that.hScrollbarIndicator.style.width = that.hScrollbarIndicatorSize + 'px'; + that.hScrollbarMaxScroll = that.hScrollbarSize - that.hScrollbarIndicatorSize; + that.hScrollbarProp = that.hScrollbarMaxScroll / that.maxScrollX; + } else { + that.vScrollbarSize = that.vScrollbarWrapper.clientHeight; + that.vScrollbarIndicatorSize = m.max(m.round(that.vScrollbarSize * that.vScrollbarSize / that.scrollerH), 8); + that.vScrollbarIndicator.style.height = that.vScrollbarIndicatorSize + 'px'; + that.vScrollbarMaxScroll = that.vScrollbarSize - that.vScrollbarIndicatorSize; + that.vScrollbarProp = that.vScrollbarMaxScroll / that.maxScrollY; + } + + // Reset position + that._scrollbarPos(dir, true); + }, + + _resize: function () { + var that = this; + setTimeout(function () { that.refresh(); }, isAndroid ? 200 : 0); + }, + + _pos: function (x, y) { + if (this.zoomed) return; + + x = this.hScroll ? x : 0; + y = this.vScroll ? y : 0; + + if (this.options.useTransform) { + this.scroller.style[transform] = 'translate(' + x + 'px,' + y + 'px) scale(' + this.scale + ')' + translateZ; + } else { + x = m.round(x); + y = m.round(y); + this.scroller.style.left = x + 'px'; + this.scroller.style.top = y + 'px'; + } + + this.x = x; + this.y = y; + + this._scrollbarPos('h'); + this._scrollbarPos('v'); + }, + + _scrollbarPos: function (dir, hidden) { + var that = this, + pos = dir == 'h' ? that.x : that.y, + size; + + if (!that[dir + 'Scrollbar']) return; + + pos = that[dir + 'ScrollbarProp'] * pos; + + if (pos < 0) { + if (!that.options.fixedScrollbar) { + size = that[dir + 'ScrollbarIndicatorSize'] + m.round(pos * 3); + if (size < 8) size = 8; + that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px'; + } + pos = 0; + } else if (pos > that[dir + 'ScrollbarMaxScroll']) { + if (!that.options.fixedScrollbar) { + size = that[dir + 'ScrollbarIndicatorSize'] - m.round((pos - that[dir + 'ScrollbarMaxScroll']) * 3); + if (size < 8) size = 8; + that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px'; + pos = that[dir + 'ScrollbarMaxScroll'] + (that[dir + 'ScrollbarIndicatorSize'] - size); + } else { + pos = that[dir + 'ScrollbarMaxScroll']; + } + } + + that[dir + 'ScrollbarWrapper'].style[transitionDelay] = '0'; + that[dir + 'ScrollbarWrapper'].style.opacity = hidden && that.options.hideScrollbar ? '0' : '1'; + that[dir + 'ScrollbarIndicator'].style[transform] = 'translate(' + (dir == 'h' ? pos + 'px,0)' : '0,' + pos + 'px)') + translateZ; + }, + + _start: function (e) { + var that = this, + point = hasTouch ? e.touches[0] : e, + matrix, x, y, + c1, c2; + + if (!that.enabled) return; + + if (that.options.onBeforeScrollStart) that.options.onBeforeScrollStart.call(that, e); + + if (that.options.useTransition || that.options.zoom) that._transitionTime(0); + + that.moved = false; + that.animating = false; + that.zoomed = false; + that.distX = 0; + that.distY = 0; + that.absDistX = 0; + that.absDistY = 0; + that.dirX = 0; + that.dirY = 0; + + // Gesture start + if (that.options.zoom && hasTouch && e.touches.length > 1) { + c1 = m.abs(e.touches[0].pageX-e.touches[1].pageX); + c2 = m.abs(e.touches[0].pageY-e.touches[1].pageY); + that.touchesDistStart = m.sqrt(c1 * c1 + c2 * c2); + + that.originX = m.abs(e.touches[0].pageX + e.touches[1].pageX - that.wrapperOffsetLeft * 2) / 2 - that.x; + that.originY = m.abs(e.touches[0].pageY + e.touches[1].pageY - that.wrapperOffsetTop * 2) / 2 - that.y; + + if (that.options.onZoomStart) that.options.onZoomStart.call(that, e); + } + + if (that.options.momentum) { + if (that.options.useTransform) { + // Very lame general purpose alternative to CSSMatrix + matrix = getComputedStyle(that.scroller, null)[transform].replace(/[^0-9\-.,]/g, '').split(','); + x = matrix[4] * 1; + y = matrix[5] * 1; + } else { + x = getComputedStyle(that.scroller, null).left.replace(/[^0-9-]/g, '') * 1; + y = getComputedStyle(that.scroller, null).top.replace(/[^0-9-]/g, '') * 1; + } + + if (x != that.x || y != that.y) { + if (that.options.useTransition) that._unbind(TRNEND_EV); + else cancelFrame(that.aniTime); + that.steps = []; + that._pos(x, y); + } + } + + that.absStartX = that.x; // Needed by snap threshold + that.absStartY = that.y; + + that.startX = that.x; + that.startY = that.y; + that.pointX = point.pageX; + that.pointY = point.pageY; + + that.startTime = e.timeStamp || Date.now(); + + if (that.options.onScrollStart) that.options.onScrollStart.call(that, e); + + that._bind(MOVE_EV); + that._bind(END_EV); + that._bind(CANCEL_EV); + }, + + _move: function (e) { + var that = this, + point = hasTouch ? e.touches[0] : e, + deltaX = point.pageX - that.pointX, + deltaY = point.pageY - that.pointY, + newX = that.x + deltaX, + newY = that.y + deltaY, + c1, c2, scale, + timestamp = e.timeStamp || Date.now(); + + if (that.options.onBeforeScrollMove) that.options.onBeforeScrollMove.call(that, e); + + // Zoom + if (that.options.zoom && hasTouch && e.touches.length > 1) { + c1 = m.abs(e.touches[0].pageX - e.touches[1].pageX); + c2 = m.abs(e.touches[0].pageY - e.touches[1].pageY); + that.touchesDist = m.sqrt(c1*c1+c2*c2); + + that.zoomed = true; + + scale = 1 / that.touchesDistStart * that.touchesDist * this.scale; + + if (scale < that.options.zoomMin) scale = 0.5 * that.options.zoomMin * Math.pow(2.0, scale / that.options.zoomMin); + else if (scale > that.options.zoomMax) scale = 2.0 * that.options.zoomMax * Math.pow(0.5, that.options.zoomMax / scale); + + that.lastScale = scale / this.scale; + + newX = this.originX - this.originX * that.lastScale + this.x, + newY = this.originY - this.originY * that.lastScale + this.y; + + this.scroller.style[transform] = 'translate(' + newX + 'px,' + newY + 'px) scale(' + scale + ')' + translateZ; + + if (that.options.onZoom) that.options.onZoom.call(that, e); + return; + } + + that.pointX = point.pageX; + that.pointY = point.pageY; + + // Slow down if outside of the boundaries + if (newX > 0 || newX < that.maxScrollX) { + newX = that.options.bounce ? that.x + (deltaX / 2) : newX >= 0 || that.maxScrollX >= 0 ? 0 : that.maxScrollX; + } + if (newY > that.minScrollY || newY < that.maxScrollY) { + newY = that.options.bounce ? that.y + (deltaY / 2) : newY >= that.minScrollY || that.maxScrollY >= 0 ? that.minScrollY : that.maxScrollY; + } + + that.distX += deltaX; + that.distY += deltaY; + that.absDistX = m.abs(that.distX); + that.absDistY = m.abs(that.distY); + + if (that.absDistX < 6 && that.absDistY < 6) { + return; + } + + // Lock direction + if (that.options.lockDirection) { + if (that.absDistX > that.absDistY + 5) { + newY = that.y; + deltaY = 0; + } else if (that.absDistY > that.absDistX + 5) { + newX = that.x; + deltaX = 0; + } + } + + that.moved = true; + that._pos(newX, newY); + that.dirX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0; + that.dirY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0; + + if (timestamp - that.startTime > 300) { + that.startTime = timestamp; + that.startX = that.x; + that.startY = that.y; + } + + if (that.options.onScrollMove) that.options.onScrollMove.call(that, e); + }, + + _end: function (e) { + if (hasTouch && e.touches.length !== 0) return; + + var that = this, + point = hasTouch ? e.changedTouches[0] : e, + target, ev, + momentumX = { dist:0, time:0 }, + momentumY = { dist:0, time:0 }, + duration = (e.timeStamp || Date.now()) - that.startTime, + newPosX = that.x, + newPosY = that.y, + distX, distY, + newDuration, + snap, + scale; + + that._unbind(MOVE_EV); + that._unbind(END_EV); + that._unbind(CANCEL_EV); + + if (that.options.onBeforeScrollEnd) that.options.onBeforeScrollEnd.call(that, e); + + if (that.zoomed) { + scale = that.scale * that.lastScale; + scale = Math.max(that.options.zoomMin, scale); + scale = Math.min(that.options.zoomMax, scale); + that.lastScale = scale / that.scale; + that.scale = scale; + + that.x = that.originX - that.originX * that.lastScale + that.x; + that.y = that.originY - that.originY * that.lastScale + that.y; + + that.scroller.style[transitionDuration] = '200ms'; + that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px) scale(' + that.scale + ')' + translateZ; + + that.zoomed = false; + that.refresh(); + + if (that.options.onZoomEnd) that.options.onZoomEnd.call(that, e); + return; + } + + if (!that.moved) { + if (hasTouch) { + if (that.doubleTapTimer && that.options.zoom) { + // Double tapped + clearTimeout(that.doubleTapTimer); + that.doubleTapTimer = null; + if (that.options.onZoomStart) that.options.onZoomStart.call(that, e); + that.zoom(that.pointX, that.pointY, that.scale == 1 ? that.options.doubleTapZoom : 1); + if (that.options.onZoomEnd) { + setTimeout(function() { + that.options.onZoomEnd.call(that, e); + }, 200); // 200 is default zoom duration + } + } else if (this.options.handleClick) { + that.doubleTapTimer = setTimeout(function () { + that.doubleTapTimer = null; + + // Find the last touched element + target = point.target; + while (target.nodeType != 1) target = target.parentNode; + + if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA') { + ev = doc.createEvent('MouseEvents'); + ev.initMouseEvent('click', true, true, e.view, 1, + point.screenX, point.screenY, point.clientX, point.clientY, + e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, + 0, null); + ev._fake = true; + target.dispatchEvent(ev); + } + }, that.options.zoom ? 250 : 0); + } + } + + that._resetPos(200); + + if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e); + return; + } + + if (duration < 300 && that.options.momentum) { + momentumX = newPosX ? that._momentum(newPosX - that.startX, duration, -that.x, that.scrollerW - that.wrapperW + that.x, that.options.bounce ? that.wrapperW : 0) : momentumX; + momentumY = newPosY ? that._momentum(newPosY - that.startY, duration, -that.y, (that.maxScrollY < 0 ? that.scrollerH - that.wrapperH + that.y - that.minScrollY : 0), that.options.bounce ? that.wrapperH : 0) : momentumY; + + newPosX = that.x + momentumX.dist; + newPosY = that.y + momentumY.dist; + + if ((that.x > 0 && newPosX > 0) || (that.x < that.maxScrollX && newPosX < that.maxScrollX)) momentumX = { dist:0, time:0 }; + if ((that.y > that.minScrollY && newPosY > that.minScrollY) || (that.y < that.maxScrollY && newPosY < that.maxScrollY)) momentumY = { dist:0, time:0 }; + } + + if (momentumX.dist || momentumY.dist) { + newDuration = m.max(m.max(momentumX.time, momentumY.time), 10); + + // Do we need to snap? + if (that.options.snap) { + distX = newPosX - that.absStartX; + distY = newPosY - that.absStartY; + if (m.abs(distX) < that.options.snapThreshold && m.abs(distY) < that.options.snapThreshold) { that.scrollTo(that.absStartX, that.absStartY, 200); } + else { + snap = that._snap(newPosX, newPosY); + newPosX = snap.x; + newPosY = snap.y; + newDuration = m.max(snap.time, newDuration); + } + } + + that.scrollTo(m.round(newPosX), m.round(newPosY), newDuration); + + if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e); + return; + } + + // Do we need to snap? + if (that.options.snap) { + distX = newPosX - that.absStartX; + distY = newPosY - that.absStartY; + if (m.abs(distX) < that.options.snapThreshold && m.abs(distY) < that.options.snapThreshold) that.scrollTo(that.absStartX, that.absStartY, 200); + else { + snap = that._snap(that.x, that.y); + if (snap.x != that.x || snap.y != that.y) that.scrollTo(snap.x, snap.y, snap.time); + } + + if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e); + return; + } + + that._resetPos(200); + if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e); + }, + + _resetPos: function (time) { + var that = this, + resetX = that.x >= 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x, + resetY = that.y >= that.minScrollY || that.maxScrollY > 0 ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y; + + if (resetX == that.x && resetY == that.y) { + if (that.moved) { + that.moved = false; + if (that.options.onScrollEnd) that.options.onScrollEnd.call(that); // Execute custom code on scroll end + } + + if (that.hScrollbar && that.options.hideScrollbar) { + if (vendor == 'webkit') that.hScrollbarWrapper.style[transitionDelay] = '300ms'; + that.hScrollbarWrapper.style.opacity = '0'; + } + if (that.vScrollbar && that.options.hideScrollbar) { + if (vendor == 'webkit') that.vScrollbarWrapper.style[transitionDelay] = '300ms'; + that.vScrollbarWrapper.style.opacity = '0'; + } + + return; + } + + that.scrollTo(resetX, resetY, time || 0); + }, + + _wheel: function (e) { + var that = this, + wheelDeltaX, wheelDeltaY, + deltaX, deltaY, + deltaScale; + + if ('wheelDeltaX' in e) { + wheelDeltaX = e.wheelDeltaX / 12; + wheelDeltaY = e.wheelDeltaY / 12; + } else if('wheelDelta' in e) { + wheelDeltaX = wheelDeltaY = e.wheelDelta / 12; + } else if ('detail' in e) { + wheelDeltaX = wheelDeltaY = -e.detail * 3; + } else { + return; + } + + if (that.options.wheelAction == 'zoom') { + deltaScale = that.scale * Math.pow(2, 1/3 * (wheelDeltaY ? wheelDeltaY / Math.abs(wheelDeltaY) : 0)); + if (deltaScale < that.options.zoomMin) deltaScale = that.options.zoomMin; + if (deltaScale > that.options.zoomMax) deltaScale = that.options.zoomMax; + + if (deltaScale != that.scale) { + if (!that.wheelZoomCount && that.options.onZoomStart) that.options.onZoomStart.call(that, e); + that.wheelZoomCount++; + + that.zoom(e.pageX, e.pageY, deltaScale, 400); + + setTimeout(function() { + that.wheelZoomCount--; + if (!that.wheelZoomCount && that.options.onZoomEnd) that.options.onZoomEnd.call(that, e); + }, 400); + } + + return; + } + + deltaX = that.x + wheelDeltaX; + deltaY = that.y + wheelDeltaY; + + if (deltaX > 0) deltaX = 0; + else if (deltaX < that.maxScrollX) deltaX = that.maxScrollX; + + if (deltaY > that.minScrollY) deltaY = that.minScrollY; + else if (deltaY < that.maxScrollY) deltaY = that.maxScrollY; + + if (that.maxScrollY < 0) { + that.scrollTo(deltaX, deltaY, 0); + } + }, + + _mouseout: function (e) { + var t = e.relatedTarget; + + if (!t) { + this._end(e); + return; + } + + while (t = t.parentNode) if (t == this.wrapper) return; + + this._end(e); + }, + + _transitionEnd: function (e) { + var that = this; + + if (e.target != that.scroller) return; + + that._unbind(TRNEND_EV); + + that._startAni(); + }, + + + /** + * + * Utilities + * + */ + _startAni: function () { + var that = this, + startX = that.x, startY = that.y, + startTime = Date.now(), + step, easeOut, + animate; + + if (that.animating) return; + + if (!that.steps.length) { + that._resetPos(400); + return; + } + + step = that.steps.shift(); + + if (step.x == startX && step.y == startY) step.time = 0; + + that.animating = true; + that.moved = true; + + if (that.options.useTransition) { + that._transitionTime(step.time); + that._pos(step.x, step.y); + that.animating = false; + if (step.time) that._bind(TRNEND_EV); + else that._resetPos(0); + return; + } + + animate = function () { + var now = Date.now(), + newX, newY; + + if (now >= startTime + step.time) { + that._pos(step.x, step.y); + that.animating = false; + if (that.options.onAnimationEnd) that.options.onAnimationEnd.call(that); // Execute custom code on animation end + that._startAni(); + return; + } + + now = (now - startTime) / step.time - 1; + easeOut = m.sqrt(1 - now * now); + newX = (step.x - startX) * easeOut + startX; + newY = (step.y - startY) * easeOut + startY; + that._pos(newX, newY); + if (that.animating) that.aniTime = nextFrame(animate); + }; + + animate(); + }, + + _transitionTime: function (time) { + time += 'ms'; + this.scroller.style[transitionDuration] = time; + if (this.hScrollbar) this.hScrollbarIndicator.style[transitionDuration] = time; + if (this.vScrollbar) this.vScrollbarIndicator.style[transitionDuration] = time; + }, + + _momentum: function (dist, time, maxDistUpper, maxDistLower, size) { + var deceleration = 0.0006, + speed = m.abs(dist) / time, + newDist = (speed * speed) / (2 * deceleration), + newTime = 0, outsideDist = 0; + + // Proportinally reduce speed if we are outside of the boundaries + if (dist > 0 && newDist > maxDistUpper) { + outsideDist = size / (6 / (newDist / speed * deceleration)); + maxDistUpper = maxDistUpper + outsideDist; + speed = speed * maxDistUpper / newDist; + newDist = maxDistUpper; + } else if (dist < 0 && newDist > maxDistLower) { + outsideDist = size / (6 / (newDist / speed * deceleration)); + maxDistLower = maxDistLower + outsideDist; + speed = speed * maxDistLower / newDist; + newDist = maxDistLower; + } + + newDist = newDist * (dist < 0 ? -1 : 1); + newTime = speed / deceleration; + + return { dist: newDist, time: m.round(newTime) }; + }, + + _offset: function (el) { + var left = -el.offsetLeft, + top = -el.offsetTop; + + while (el = el.offsetParent) { + left -= el.offsetLeft; + top -= el.offsetTop; + } + + if (el != this.wrapper) { + left *= this.scale; + top *= this.scale; + } + + return { left: left, top: top }; + }, + + _snap: function (x, y) { + var that = this, + i, l, + page, time, + sizeX, sizeY; + + // Check page X + page = that.pagesX.length - 1; + for (i=0, l=that.pagesX.length; i= that.pagesX[i]) { + page = i; + break; + } + } + if (page == that.currPageX && page > 0 && that.dirX < 0) page--; + x = that.pagesX[page]; + sizeX = m.abs(x - that.pagesX[that.currPageX]); + sizeX = sizeX ? m.abs(that.x - x) / sizeX * 500 : 0; + that.currPageX = page; + + // Check page Y + page = that.pagesY.length-1; + for (i=0; i= that.pagesY[i]) { + page = i; + break; + } + } + if (page == that.currPageY && page > 0 && that.dirY < 0) page--; + y = that.pagesY[page]; + sizeY = m.abs(y - that.pagesY[that.currPageY]); + sizeY = sizeY ? m.abs(that.y - y) / sizeY * 500 : 0; + that.currPageY = page; + + // Snap with constant speed (proportional duration) + time = m.round(m.max(sizeX, sizeY)) || 200; + + return { x: x, y: y, time: time }; + }, + + _bind: function (type, el, bubble) { + (el || this.scroller).addEventListener(type, this, !!bubble); + }, + + _unbind: function (type, el, bubble) { + (el || this.scroller).removeEventListener(type, this, !!bubble); + }, + + + /** + * + * Public methods + * + */ + destroy: function () { + var that = this; + + that.scroller.style[transform] = ''; + + // Remove the scrollbars + that.hScrollbar = false; + that.vScrollbar = false; + that._scrollbar('h'); + that._scrollbar('v'); + + // Remove the event listeners + that._unbind(RESIZE_EV, window); + that._unbind(START_EV); + that._unbind(MOVE_EV); + that._unbind(END_EV); + that._unbind(CANCEL_EV); + + if (!that.options.hasTouch) { + that._unbind('mouseout', that.wrapper); + that._unbind(WHEEL_EV); + } + + if (that.options.useTransition) that._unbind(TRNEND_EV); + + if (that.options.checkDOMChanges) clearInterval(that.checkDOMTime); + + if (that.options.onDestroy) that.options.onDestroy.call(that); + }, + + refresh: function () { + var that = this, + offset, + i, l, + els, + pos = 0, + page = 0; + + if (that.scale < that.options.zoomMin) that.scale = that.options.zoomMin; + that.wrapperW = that.wrapper.clientWidth || 1; + that.wrapperH = that.wrapper.clientHeight || 1; + + that.minScrollY = -that.options.topOffset || 0; + that.scrollerW = m.round(that.scroller.offsetWidth * that.scale); + that.scrollerH = m.round((that.scroller.offsetHeight + that.minScrollY) * that.scale); + that.maxScrollX = that.wrapperW - that.scrollerW; + that.maxScrollY = that.wrapperH - that.scrollerH + that.minScrollY; + that.dirX = 0; + that.dirY = 0; + + if (that.options.onRefresh) that.options.onRefresh.call(that); + + that.hScroll = that.options.hScroll && that.maxScrollX < 0; + that.vScroll = that.options.vScroll && (!that.options.bounceLock && !that.hScroll || that.scrollerH > that.wrapperH); + + that.hScrollbar = that.hScroll && that.options.hScrollbar; + that.vScrollbar = that.vScroll && that.options.vScrollbar && that.scrollerH > that.wrapperH; + + offset = that._offset(that.wrapper); + that.wrapperOffsetLeft = -offset.left; + that.wrapperOffsetTop = -offset.top; + + // Prepare snap + if (typeof that.options.snap == 'string') { + that.pagesX = []; + that.pagesY = []; + els = that.scroller.querySelectorAll(that.options.snap); + for (i=0, l=els.length; i= that.maxScrollX) { + that.pagesX[page] = pos; + pos = pos - that.wrapperW; + page++; + } + if (that.maxScrollX%that.wrapperW) that.pagesX[that.pagesX.length] = that.maxScrollX - that.pagesX[that.pagesX.length-1] + that.pagesX[that.pagesX.length-1]; + + pos = 0; + page = 0; + that.pagesY = []; + while (pos >= that.maxScrollY) { + that.pagesY[page] = pos; + pos = pos - that.wrapperH; + page++; + } + if (that.maxScrollY%that.wrapperH) that.pagesY[that.pagesY.length] = that.maxScrollY - that.pagesY[that.pagesY.length-1] + that.pagesY[that.pagesY.length-1]; + } + + // Prepare the scrollbars + that._scrollbar('h'); + that._scrollbar('v'); + + if (!that.zoomed) { + that.scroller.style[transitionDuration] = '0'; + that._resetPos(200); + } + }, + + scrollTo: function (x, y, time, relative) { + var that = this, + step = x, + i, l; + + that.stop(); + + if (!step.length) step = [{ x: x, y: y, time: time, relative: relative }]; + + for (i=0, l=step.length; i 0 ? 0 : pos.left < that.maxScrollX ? that.maxScrollX : pos.left; + pos.top = pos.top > that.minScrollY ? that.minScrollY : pos.top < that.maxScrollY ? that.maxScrollY : pos.top; + time = time === undefined ? m.max(m.abs(pos.left)*2, m.abs(pos.top)*2) : time; + + that.scrollTo(pos.left, pos.top, time); + }, + + scrollToPage: function (pageX, pageY, time) { + var that = this, x, y; + + time = time === undefined ? 400 : time; + + if (that.options.onScrollStart) that.options.onScrollStart.call(that); + + if (that.options.snap) { + pageX = pageX == 'next' ? that.currPageX+1 : pageX == 'prev' ? that.currPageX-1 : pageX; + pageY = pageY == 'next' ? that.currPageY+1 : pageY == 'prev' ? that.currPageY-1 : pageY; + + pageX = pageX < 0 ? 0 : pageX > that.pagesX.length-1 ? that.pagesX.length-1 : pageX; + pageY = pageY < 0 ? 0 : pageY > that.pagesY.length-1 ? that.pagesY.length-1 : pageY; + + that.currPageX = pageX; + that.currPageY = pageY; + x = that.pagesX[pageX]; + y = that.pagesY[pageY]; + } else { + x = -that.wrapperW * pageX; + y = -that.wrapperH * pageY; + if (x < that.maxScrollX) x = that.maxScrollX; + if (y < that.maxScrollY) y = that.maxScrollY; + } + + that.scrollTo(x, y, time); + }, + + disable: function () { + this.stop(); + this._resetPos(0); + this.enabled = false; + + // If disabled after touchstart we make sure that there are no left over events + this._unbind(MOVE_EV); + this._unbind(END_EV); + this._unbind(CANCEL_EV); + }, + + enable: function () { + this.enabled = true; + }, + + stop: function () { + if (this.options.useTransition) this._unbind(TRNEND_EV); + else cancelFrame(this.aniTime); + this.steps = []; + this.moved = false; + this.animating = false; + }, + + zoom: function (x, y, scale, time) { + var that = this, + relScale = scale / that.scale; + + if (!that.options.useTransform) return; + + that.zoomed = true; + time = time === undefined ? 200 : time; + x = x - that.wrapperOffsetLeft - that.x; + y = y - that.wrapperOffsetTop - that.y; + that.x = x - x * relScale + that.x; + that.y = y - y * relScale + that.y; + + that.scale = scale; + that.refresh(); + + that.x = that.x > 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x; + that.y = that.y > that.minScrollY ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y; + + that.scroller.style[transitionDuration] = time + 'ms'; + that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px) scale(' + scale + ')' + translateZ; + that.zoomed = false; + }, + + isReady: function () { + return !this.moved && !this.zoomed && !this.animating; + } +}; + +function prefixStyle (style) { + if ( vendor === '' ) return style; + + style = style.charAt(0).toUpperCase() + style.substr(1); + return vendor + style; +} + +dummyStyle = null; // for the sake of it + +if (typeof exports !== 'undefined') exports.iScroll = iScroll; +else window.iScroll = iScroll; + +})(this, document); diff --git a/qpid/tools/src/java/bin/qpid-web/web/itablet/scripts/itablet.js b/qpid/tools/src/java/bin/qpid-web/web/itablet/scripts/itablet.js new file mode 100644 index 0000000000..33f01241df --- /dev/null +++ b/qpid/tools/src/java/bin/qpid-web/web/itablet/scripts/itablet.js @@ -0,0 +1,1492 @@ +/** + * http://www.apache.org/licenses/LICENSE-2.0 + * + * This library implements a general user interface look and feel similar to a "well know tablet PC" :-) + * It provides animated page transition eye-candy but is, in essence, really just a fancy tabbed window. + * + * It has dependencies on the following: + * itablet.css + * iscroll.js + * jquery.js (jquery-1.7.1.min.js) + * + * author Fraser Adams + */ + +/** + * Create a Singleton instance of the iTablet user interface generic look and feel. + */ +var iTablet = new function() { + if (!String.prototype.trim) { // Add a String trim method if one doesn't exist (modern browsers should have it.) + String.prototype.trim = function() { + return this.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); + }; + } + + /** + * The Location inner class allows iTablet.location to be used similarly to window.location. + */ + var Location = function(href) { + this.href = href; + var split = href.split("?"); // Split string by query part. + this.hash = split[0]; + this.search = split.length == 2 ? "?" + split[1] : ""; + this.data = null; + + // Populate the data property with key/value pairs extracted from search part of URL. + if (split.length == 2) { + this.data = {}; + var kv = split[1].split("&"); // Split string into key/value pairs using the & is the separator. + var length = kv.length; + for (var i = 0; i < length; i++) { + var s = kv[i].split("="); + if (s.length == 2) { + var key = s[0].trim(); + var value = s[1].trim(); + this.data[key] = value; + } + } + } + + Location.prototype.toString = function() { + return this.href; + }; + + // Location.back() is mapped to the iTablet.goBack() method. + // This allows clients to explicitly return to a previous page, useful for coding submit handlers etc. + Location.prototype.back = goBack; + }; + + /** + * The TextChange inner class adds support for a textchange Event on text input and textarea tags. + * Initialise with: $.event.special.textchange = new TextChange(); + * Uses info derived from from http://benalman.com/news/2010/03/jquery-special-events/ + */ + var TextChange = function() { + /** + * Directly call the triggerIfChanged method on keyup. + */ + var handler = function() { + triggerIfChanged(this); + }; + + /** + * For cut, paste and input handlers we need to call triggerIfChanged from a timeout. + */ + var handlerWithDelay = function() { + var element = this; + setTimeout(function() { + triggerIfChanged(element); + }, 25); + }; + + /** + * Trigger textchange Event handler bound to target element if the text has changed. + */ + var triggerIfChanged = function(domElement) { + var element = $(domElement); + var current = domElement.contentEditable === "true" ? element.html() : element.val(); + if (current !== element.data("lastValue")) { + element.trigger("textchange", [element.data("lastValue")]); + element.data("lastValue", current); + } + }; + + /** + * Called by jQuery when the first event handler is bound to a particular element. + */ + this.setup = function(data) { + var jthis = $(this); + jthis.data("lastValue", this.contentEditable === 'true' ? jthis.html() : jthis.val()); + // Bind keyup, cut, paste and input handlers in the .textchange Event namespace to allow easy unbinding. + jthis.bind("keyup.textchange", handler); + jthis.bind("cut.textchange paste.textchange input.textchange", handlerWithDelay); + }; + + /** + * Called by jQuery when the last event handler is unbound from a particular element. + */ + this.teardown = function (data) { + $(this).unbind('.textchange'); // Unbind the Events linked to the .textchange Event namespace. + } + }; + +//------------------------------------------------------------------------------------------------------------------- + + var TOUCH_ENABLED = 'ontouchstart' in window && !((/hp-tablet/gi).test(navigator.appVersion)); + + // Select start, move and end events based on whether or not the user agent is a touch device. + var START_EV = (TOUCH_ENABLED) ? "touchstart" : "mousedown"; + var MOVE_EV = (TOUCH_ENABLED) ? "touchmove" : "mousemove"; + var END_EV = (TOUCH_ENABLED) ? "touchend" : "mouseup"; + + // Populated in initialiseCSSAnimations() + var ANIMATION_END_EV = "";// = "animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd"; + var TRANSITION_END_EV = "";//"transitionend webkitTransitionEnd MSTransitionEnd oTransitionEnd"; + + /** + * The general perceived wisdom is to use feature detection rather than browser sniffing, which seems a good + * aim, but as it happens *most* of the browser abstraction is happening in jQuery and CSS but there remain + * a few quirks, mostly for IE < 9. IE < 9 and Opera < 12 both appear not to trigger a change when radio or + * checkbox state changes and it's not clear how to "feature detect" this, which is the main reason for + * including the Opera version sniffing. + */ + var IS_IE = (navigator.appName == "Microsoft Internet Explorer"); + var IE_VERSION = IS_IE ? /MSIE (\d+)/.exec(navigator.userAgent)[1] : 1000000; + var IS_OPERA = (navigator.appName == "Opera") && (window.opera.version != null); + var OPERA_VERSION = IS_OPERA ? opera.version() : 1000000; + + var BODY; // jQuery object for body is used in several places so let's cache it (gets set in jQuery.ready()). + var IS_MOBILE = false; // Gets set if we detect a small display (e.g. mobile) device. + + var _mainLeft = 0; // N.B. We need to get the actual value after the DOM has loaded. + var _history = []; // URL history to enable back button behaviour. + var _scrollers = {}; + var _transitions = {}; // Map of transition names to transition functions (populate later after functions defined). + this.location = null; + + /** + * This public helper method renders an HTML list with up to list items using the function. + * If the length of the list is less than the number added by the contents function additional list items are + * appended, conversely if the length of the list is greater than the number added by the contents function then + * the list is truncated. + * + * The contents of the list are populated via the supplied function, which should take an index as a + * parameter and return an
    • with contents or false. If false is returned that item is skipped. + * If an HTML list is supplied without a maxlength and contents function this method will simply carry out + * reskinning of the input widgets for the supplied list (and adding radiused borders for older versions of IE). + * + * For some reason this method seems to run very sluggishly on IE6, is's especially noticable when doing a + * resize. It runs fine on every other browser. I've not noticed any obvious inefficiencies but IE6 is weird.. + * + * @param list jQuery object representing the html list (ul) we wish to populate. + * @param maxlength the maximum number of items that we wish to populate. + * @param contents a function to populate the list contents, this function should take an index as a parameter. + * and return an
    • with the required contents or false to skip (useful if filtering is needed). + */ + this.renderList = function(list, contents, maxlength) { + // For IE 6 get the width. Have to use .main or .popup-container because list.innerWidth() may not be set yet. + var listWidth = 0; + + if (IE_VERSION < 7) { // This seems to be very slow on IE6, no idea why??? + var main = list.closest(".main"); + if (main.length == 0) { // It's a list in a popup + listWidth = Math.round(parseInt($(".popup-container").css('width'), 10) * 0.9); + } else { + listWidth = Math.round($(".main").width() * 0.9); + } + } + + var lengthChanged = false; + var items = list.children("li"); + + if (contents == null) { + maxlength = items.length; + } else if (maxlength == null) { + maxlength = 1; // If no maxlength is supplied default to calling the contents function once. + } + + var actualLength = 0; // Actual number of
    • supplied, this caters for the contents function returning false. + for (var i = 0; i < maxlength; i++) { + var li = false; + if (actualLength < items.length) { + if (contents) { // Modify list item with the new contents at index i. + var newItem = contents(i); + if (newItem) { // If the contents function didn't return false add contents to current li. + li = $(items[actualLength]); + actualLength++; + var active = li.hasClass("active") ? "active" : ""; + var newItem = $(newItem).addClass(active); + li.removeClass().addClass(newItem.attr("class")); // Remove existing classes and add new ones. + li.html(newItem.html()); + } + } else { // If contents function not present we simply reskin the current list item. + li = $(items[actualLength]); + actualLength++; + + if (IE_VERSION < 9) { + // Remove any markup used for faking :first-child, :last-child, :before, :after + li.removeClass("first-child last-child"); + li.children("div.before, div.after, div.fbefore, div.fafter").remove(); + } + } + } else { // If there are fewer items in the list than there are contents then append new list items. + var newItem = contents(i); + if (newItem) { // If the contents function didn't return false append contents as new li. + li = $(newItem); + actualLength++; + list.append(li); + lengthChanged = true; + } + } + + if (li) { + // Reskin input widgets. + Radio.reskin(li.children("input:radio")); + Checkbox.reskin(li.children("input:checkbox")); + + // Fix several quirks in early versions of IE. + if (IE_VERSION < 8) { + var anchor = li.children("a"); + anchor.attr("hideFocus", "hidefocus"); // Fix lack of outline: none; in IE < 8 + + if (IE_VERSION < 7) { // IE6 percentage widths are messed up so need to set absolute width. + // 41 comes from padding: 0 30px 0 11px; 22 comes from padding: 0 11px 0 11px; + // 34 comes from margin-left: 5px; text-indent: 40px; minus 11. + var anchorWidth = listWidth - ((li.hasClass("arrow") ? 41 : 22) + + (anchor.hasClass("icon") ? 34 : 11)); + anchor.css({"width": anchorWidth + "px"}); + + // IE6 can't cope with multiple CSS classes so we need to merge these into a single class. + if (li.is(".arrow.radio")) { + li.addClass("ie6-radio-arrow"); + if (li.hasClass("checked")) { + li.addClass("ie6-checked-arrow"); + } + } + } + } + } + } + + // If list is longer than the contents being added then trim the list so it's the same size. + if (actualLength < items.length) { + items.slice(actualLength).remove(); + lengthChanged = true; + } + + // Add radiused borders for IE8 and below. + // We have to do this after completely populating the list so first() and last() are correct. + if (IE_VERSION < 9) { + items = list.children("li"); + var last = items.last(); + last.addClass("last-child").prepend("
      ").append("
      "); + + if (IE_VERSION < 8) { + var first = items.first(); + if (IE_VERSION == 7) { // For IE7 fake :first-child:before and :first-child:after + first.prepend("
      ").append("
      "); + } else if (IE_VERSION < 7) { // For IE6 fake :first-child + // We're not adding radiused borders to IE6, this class provides the proper top border colour. + first.addClass("first-child"); + } + } + } + + // If the length has changed trigger an iScroll refresh on the top level page that contains the list. + if (lengthChanged) { + list.closest(".main").trigger("refresh"); // refresh is a synthetic event handled by parents of scroll-area + } + }; + +//------------------------------------------------------------------------------------------------------------------- +// UI Widgets +//------------------------------------------------------------------------------------------------------------------- + + /** + * Create a Singleton instance of the Radio class used to reskin and manage HTML input type="radio" widgets. + */ + var Radio = new function() { + /** + * "Reskin" HTML input type="radio" items into a tablet "tick" style radio item. Note that the radio item + * needs to have a label sibling and be wrapped in a parent
    • for this to work correctly. + * e.g.
      + */ + this.reskin = function(radios) { + if (radios == null) { // if no input:radio is specified attempt to reskin every one in the document. + radios = $("input:radio"); + } + + // Add classes to container
    • based on "template" radio buttons. This "re-skins" the radio buttons. + radios.each(function() { // Iterate through each radio button. + var jthis = $(this).hide(); + if (!jthis.hasClass("reskinned")) { // If checkbox has already been reskinned move on. + var parent = jthis.parent(); + parent.addClass("radio"); + if (this.checked) { + parent.addClass("checked"); + } + jthis.addClass("reskinned"); // Mark as reskinned to avoid trying to reskin it again. + } + }); + }; + + /** + * Handle radio button state changes. This method is delegated to by the main handlePointer end() method. + * Note that we are actually passing in the $("ul li.radio") jQuery object that the Event was bound to + * rather than the actual Event object as this has already been extracted by handlePointer and is more + * useful for the implementation of this method. + */ + this.handleClick = function(jthis, type) { + var checked = jthis.parent().children(".checked"); + var radio = jthis.children("input:radio"); // Select the template radio button. + + fade(jthis); // Fade out the highlighting of the selected
    • + + if (type != "click") { // If this handler wasn't triggered by a radio button click we synthesise one. + BODY.unbind("click", handlePointer); // Prevent the synthetic click from triggering handlePointer. + radio.click(); // Trigger radio button's click (on modern browsers this triggers change too if changed). + BODY.click(handlePointer); + } + + // We explicitly manipulate input:radio checked attr in the following block in case a name attr wasn't + // specified in the HTML. With reskinned radio buttons the parent
        is the real container. + if (!jthis.is(checked)) { // If the clicked item is not the previously checked item. + // Clear any check mark on the previously selected
      • and the same on the template radio button. + checked.removeClass("checked"); + checked.children("input:radio").attr("checked", false); + + // Mark the current
      • as checked and do the same on the template radio button. + jthis.addClass("checked").change(); + jthis.children("input:radio").attr("checked", true); + + // For older IE/Opera triggering the click as done earlier won't trigger the change event so do it now. + if (IE_VERSION < 9 || OPERA_VERSION < 12) { + radio.change(); + } + } + }; + }; + + /** + * Create a Singleton instance of the Checkbox class used to reskin and manage HTML input type="checkbox" widgets. + */ + var Checkbox = new function() { + /** + * Return the input element associated with the specified label. This is used because the input element + * may be associated to the label in a number of different was (via the "for" attribute, by containment etc.) + */ + var findInputElement = function(label) { + var input = $("#" + label.attr("for")); // First check if label for points to the input. + if (input.length == 0) { // If not check if the label contains the input. + input = label.children("input"); + } + if (input.length == 0) { // Finally check if the label's next sibling is an input. + input = label.next("input"); + } + + return input; + }; + + /** + * "Reskin" HTML input type="checkbox" items into a tablet "switch" style checkbox. Note that the checkbox + * needs to have a label sibling and be wrapped in a parent
      • for this to work correctly. + * e.g.
        + * If multiple elements are placed in an
      • then they will automatically be + * reskinned as a "horiz-checkbox", this can also be done explicitly by doing
      • + */ + this.reskin = function(checkboxes) { + if (checkboxes == null) { // if no input:checkbox is specified attempt to reskin every one in the document. + checkboxes = $("input:checkbox"); + } + + checkboxes.each(function() { // Iterate through each checkbox. + var jthis = $(this).hide(); + if (!jthis.hasClass("reskinned")) { // If checkbox has already been reskinned move on. + // If there are multiple checkboxes in a container create a horizontal checkbox by adding class + // to parent. Note that
      • may also be explicitly set in the HTML. + jthis.siblings("input:checkbox").parent().addClass("horiz-checkbox"); + + // Mop up where checkbox is contained by label e.g. + jthis.parent().siblings("label").parent().addClass("horiz-checkbox"); + + var li = jthis.closest("li"); // Find containing li. + + if (li.hasClass("horiz-checkbox")) { // Reskin horizontal checkbox. + // IE8 doesn't seem to distinguish between the selectors ul.list li:first-child:before and + // ul.list li.horiz-checkbox:first-child:before when horiz-checkbox is dynamically added + // this stops the
      • fake radiused border being correctly positioned for horiz-checkboxes. + // By adding horiz-checkbox class to the
          too we can use a more explicit rule in the CSS. + li.parent().addClass("horiz-checkbox"); + + // As we use inline-block for horiz-checkbox we need to remove any whitespace text nodes. + li.contents().filter(function() { + return (this.nodeType == 3 && $.trim($(this).text()).length == 0); + }).remove(); + + // For horiz-checkbox we set the width of each item and add a span containing the right border. + // The inner span is needed so the border doesn't impact the element width calculation. + li.each(function() { + var buttons = $(this).children("label"); + var width = 100/buttons.length; + + buttons.css("width", width + "%"); // Using the percentage works for browsers > IE7. + // The child span helps position the border - see css (ul.list li.horiz-checkbox label span) + buttons.filter(":not(:last)").append(""); + buttons.first().addClass("first-child"); + buttons.last().addClass("last-child"); + + // Early IE doesn't respect the width so reduce the width of the last item a little. + if (width < 100 && (IE_VERSION < 8 )) { + buttons.last().css("width", width - 1 + "%") + } + + // Find input associated with each label and if it's checked add "checked" class to label. + buttons.each(function() { + var button = $(this); + var input = findInputElement(button); + input.addClass("reskinned"); // Mark as reskinned to avoid trying to reskin it again. + if (input.attr("checked")) { + button.addClass("checked"); + if (button.is(buttons.last())) { + // Use toggle-on not checked to avoid confusing IE6. + button.parent().addClass("toggle-on"); + } + } + }); + }); + } else { // Reskin normal checkbox. + // Add markup to container
        • based on "template" checkboxes. This "re-skins" the checkboxes. + jthis.parent(). + append("
          "); + + // If the checkbox is checked find onoff switch and change its initial position to "on". + jthis.filter(":checked").siblings(".checkbox").children(".onoff").css("left", "0px"); + jthis.addClass("reskinned"); // Mark as reskinned to avoid trying to reskin it again. + } + } + }); + }; + + /** + * Handle checkbox state changes. This method is delegated to by the main handlePointer method. + */ + this.handlePointer = function(e, type) { + // If triggered by a synthetic click the target is an input:checkbox otherwise it's a div.mask + var jthis = (type == "click") ? $(e.target).siblings("div.checkbox") : $(e.target).parent(); + var onoff = jthis.children(".onoff"); + var checkbox = jthis.parent().children("input:checkbox"); // Select the underlying + var offsetX = onoff.offset().left - jthis.offset().left; + var offset = -parseInt(onoff.css("left"), 10); // If we use translate we adjust by the left CSS position. + var startX = (e.pageX != null) ? e.pageX : e.originalEvent.targetTouches[0].pageX; + var clicked = true; // Set to false if move handler is called; + + var move = function(e) { + var newX = (e.pageX != null) ? e.pageX : e.originalEvent.changedTouches[0].pageX; + var diffX = offsetX + newX - startX; + clicked = false; + + if (diffX >= -50 && diffX <= 0) { + setPosition(onoff, offset, diffX); + } + e.stopPropagation(); // Prevent iScroll from trying to scroll when we drag the switch. + }; + + /** + * The pointer up handler is only bound when the pointer down has been triggered and so behaves like a click. + */ + var end = function(e) { + var pos = onoff.offset().left - jthis.offset().left; + var duration = 300; + + if (clicked) { + pos = (pos == 0) ? -50 : 0; + } else { + // Animation duration is between 150ms and 0ms based on position. + duration = (25 - Math.abs(pos + 25)) * 6; + pos = (pos < -25) ? -50 : 0; + + } + + setPosition(onoff, offset, pos, duration); + + BODY.unbind("click", handlePointer); // Prevent the synthetic click from triggering handlePointer. + var currentlyChecked = checkbox[0].checked; + if ((currentlyChecked && pos == -50) || (!currentlyChecked && pos == 0)) { + if (type == "click") { + checkbox.attr("checked", !currentlyChecked); + } else { + checkbox.click(); + // For older IE/Opera triggering the click won't trigger the change event so do it now. + if (IE_VERSION < 9 || OPERA_VERSION < 12) { + checkbox.change(); + } + } + } + BODY.click(handlePointer); + + if (TOUCH_ENABLED) { + jthis.unbind(MOVE_EV + " " + END_EV); + } else { + BODY.unbind(MOVE_EV + " " + END_EV + " mouseleave"); + } + }; + + if (type == "click") { + end(e); + } else { + // Bind move, end and mouseleave events to our internal handlers. + if (TOUCH_ENABLED) { // Touch events track over the whole page by default. + jthis.bind(MOVE_EV, move).bind(END_EV, end); + } else { // Bind mouse events to body so we can track them over the whole page. + BODY.bind(MOVE_EV, move).bind(END_EV + " mouseleave", end); + } + } + }; + + /** + * Handle horiz-checkbox state changes. This method is delegated to by the main handlePointer end() method. + * Note that we are actually passing in the $("ul li.horiz-checkbox label") jQuery object that the Event was + * bound to rather than the actual Event object as this has already been extracted by handlePointer and is + * more useful for the implementation of this method. + */ + this.handleClick = function(jthis, type) { + var parent = jthis.parent(); + var lastChild = parent.children("label").last(); + + if (jthis.hasClass("checked")) { + jthis.removeClass("checked"); + if (jthis.is(lastChild)) { + parent.removeClass("toggle-on"); // Use toggle-on rather than checked to avoid confusing IE6. + } + } else { + jthis.addClass("checked"); + if (jthis.is(lastChild)) { + parent.addClass("toggle-on"); // Use toggle-on rather than checked to avoid confusing IE6. + } + } + + if (type == "click") { + var input = findInputElement(jthis); + input.attr("checked", !input.attr("checked")); + } else { // If this handler wasn't triggered by a checkbox click we synthesise one. + BODY.unbind("click", handlePointer); // Prevent the synthetic click from triggering handlePointer. + var checkbox = findInputElement(jthis); + checkbox.click(); + // For older IE/Opera triggering the click won't trigger the change event so do it now. + if (IE_VERSION < 9 || OPERA_VERSION < 9) { + checkbox.change(); + } + BODY.click(handlePointer); + } + } + }; + +//------------------------------------------------------------------------------------------------------------------- +// Main Event Handler +//------------------------------------------------------------------------------------------------------------------- + + /** + * This method handles the pointer down, move and up events. + * We handle the discrete events because mobile Safari adds a 300ms delay to the click handler, in addition + * we want to be able to un-highlight rows if we move the mouse/finger. Note that this handler is in the form + * of a delegating event handler - we actually bind the events to the html body, this is so that if we modify + * the DOM externally, e.g. via an AJAX update we will trigger from newly created elements too. + * Note that the start(), removeHighlight(), resetHighlight(), touchMove() and end() methods are private. + * This method does actually handle click events but its main job is to prevent the default navigation action + * on href, however if the click event is a synthetic click caused by a jQuery trigger the method behaves like + * a proper click handler. + */ + var handlePointer = function(e) { + // These are the *actual* selectors that we are interested in handling events for. + var selectors = "ul.contents li, ul.mail li, ul li.radio, ul li div.checkbox, ul li.horiz-checkbox label, " + + "ul li.arrow, ul li.pop, div.header a.back, div.header a.done, div.header a.cancel, " + + "div.header a.menu"; + + var target = e.target; + var jthis = $(target); + var parent; + var prev; + var href = jthis.attr("href"); + var chevronClicked = false; // Set true if we've clicked on a chevron (used for navigable radio buttons). + var scrolled; // Gets set if a page has been (touch) scrolled. + var highlighted; // Gets set if a sidebar or mail item has been selected/highlighted. + var startY; // The vertical position when a touchstart gets triggered. + + var start = function(e) { + // This block checks if the event target is one of the selectors, if not it uses jQuery closest to get the + // first element that matches the selector, start at the current element and progress up through the DOM. + if (!jthis.is(selectors)) { + jthis = jthis.closest(selectors); + } + + // If closest object doesn't match any of the selectors return true if it has an href else return false. + if (jthis.length == 0) { + return (!!href); // The href test allows the browser to add the active pseudoclass. + } + + if (jthis.hasClass("checkbox")) { // If a checkbox then delegate to the Checkbox handlePointer() handler. + Checkbox.handlePointer(e); + return false; + } + + parent = jthis.parent(); + + // prev is the previously highlighted item. We search from parent's parent as we may have multiple lists. + prev = parent.parent().find(".active"); + + href = jthis.attr("href"); // Get the href of the element matching the selector. + + var TOUCHED_SIDEBAR = TOUCH_ENABLED && parent.is(".contents, .mail"); // Is this a touch on a sidebar list? + + // If the href isn't directly present then it's an
        • that contains the anchor, so we have to look further. + if (!href) { + var ICON_WIDTH = 45; // The width of the icon image plus some padding. + var offset = Math.ceil(jthis.offset().left); + + // Get the pointer x value relative to the
        • + var x = (e.pageX != null) ? e.pageX - offset : // Mouse position. + (e.originalEvent != null) ? e.originalEvent.targetTouches[0].pageX - offset : 0; // Touch pos. + + // If target is a clickable-icon we return immediately thus preventing any highlighting or navigation. + if (jthis.hasClass("clickable-icon") && (x < ICON_WIDTH)) { + return false; + } + + // If target is a navigable radio button then check if chevron was clicked/tapped. + if (jthis.hasClass("radio") && jthis.hasClass("arrow") && ((jthis.outerWidth() - x) < ICON_WIDTH)) { + chevronClicked = true; + } + + e.preventDefault(); // Stop the anchor default highlighting, we'll add our own prettier highlight. + + // This block highlights the selected
        • on mousedown or touchstart. For touch enabled devices we wait + // for a short time before highlighting in case the touchstart was the start of a scroll rather than a + // selection. If it was a scroll then the scrolled flag will get set by the touchMove handler and the + // highlight is aborted when the timeout gets triggered. + if (!prev[0] || prev[0] != jthis[0]) { + if (TOUCHED_SIDEBAR && !IS_MOBILE) { + // If TOUCH_ENABLED and a sidebar or mail list wait 50ms before highlighting in case the + // touch start is really the start of a touch scroll event. + scrolled = false; + highlighted = false; + + setTimeout(function() { + if (!scrolled) { // scrolled may be set by touchMove if the list has been scrolled. + prev.removeClass("active"); + jthis.addClass("active"); // Highlight the current
        • + highlighted = true; + } + }, 50); + } else { // If not TOUCH_ENABLED or a sidebar or mail list highlight immediately. + prev.removeClass("active"); + // Navigable radio buttons don't highlight when the chevron is clicked. + if (!chevronClicked) { + jthis.addClass("active"); // Highlight the current
        • + } + } + } + + href = jthis.children("a:first").attr("href"); // Get the href from the first anchor enclosed by the
        • + href = (href == null) ? "#" : href; // Create default href of "#" if none has been specified. + href = href.replace(window.location, ""); // Fix "absolute href" bug found in IE7 and below. + } + + BODY.bind(END_EV, end).unbind(START_EV, handlePointer); + + if (parent.hasClass("list") || (TOUCHED_SIDEBAR && IS_MOBILE)) { + // For a small (e.g. mobile) displays the sidebar becomes the main menu page and touches behave + // like normal list touches and become inactive on any touch move. + BODY.bind(MOVE_EV, removeHighlight); + } else if (TOUCHED_SIDEBAR && !IS_MOBILE) { + // For a real sidebar detect touch scrolling on these items. + startY = (e.originalEvent) ? e.originalEvent.targetTouches[0].pageY : 0; + BODY.bind(MOVE_EV, touchMove); + } + }; + + /** + * If we move the mouse or finger in a list item we un-highlight and deactivate. + */ + var removeHighlight = function(e) { + BODY.unbind(MOVE_EV + " " + END_EV).bind(START_EV, handlePointer); + jthis.removeClass("active"); + }; + + /** + * If we move a finger up or down in a sidebar item we reinstate the previous highlight ontouchend. + */ + var resetHighlight = function(e) { + BODY.unbind(END_EV).bind(START_EV, handlePointer); + prev.addClass("active"); + }; + + /** + * This touch move handler is only bound if the initial event is a touch start event bound to a
        • + * with a
            parent that has a .contents or .mail class. These lists need to be touch scrollable, but + * they also need to have a persistent highlight on selected items. This method checks how many vertical + * pixels have been scrolled and if it exceeds a threshold it triggers a scrolled state. Once scrolled it removes + * any new highlighting and binds resetHighlight to touchend, which reinstates the previous highlight. + */ + var touchMove = function(e) { + var newY = e.originalEvent.changedTouches[0].pageY; + if (Math.abs(newY - startY) > 7) { // Only trigger on an up/down finger movement. + if (highlighted) { // If a new item was highlighted set the highlighting back to the previous item. + BODY.unbind(MOVE_EV + " " + END_EV).bind(END_EV, resetHighlight); + } else { + BODY.unbind(MOVE_EV + " " + END_EV).bind(START_EV, handlePointer); + } + + if (prev[0] != jthis[0]) { + jthis.removeClass("active"); + } + scrolled = true; + } + }; + + /** + * The pointer up handler is only bound when the pointer down has been triggered and so behaves like a click + * handler. If we have been triggered by a back selector or if we re-click an already selected sidebar entry + * that has previously transitioned the we call goBack() to transition backwards otherwise we goTo(href). + */ + var end = function(e) { + BODY.unbind(MOVE_EV + " " + END_EV).bind(START_EV, handlePointer); + + if (!IS_MOBILE && (parent.hasClass("contents") || parent.hasClass("mail"))) { + // Handle sidebar transitions. + if (_history.length == 2 && href == _history[1].href) { + goBack(); + } else { + _history = []; + goTo(href); + } + } else if (parent.is("ul")) { + if (jthis.hasClass("radio") && !chevronClicked) { // Delegate radio button state changes. + Radio.handleClick(jthis, e.type); + } else { // Handle goTo page transition. + var classes = jthis.attr("class").split(" "); + var transition = slide; // Default animation. + // Look up the transition animation based upon the item's class + for (var i in classes) { + var current = classes[i]; + var newTransition = _transitions[current]; + if (newTransition != null) { + transition = newTransition; + break; + } + } + goTo(href, transition); + } + } else if (parent.hasClass("horiz-checkbox")) { + Checkbox.handleClick(jthis); + } else if (jthis.is(".back, .done, .cancel")) { + goBack(); + } else if (jthis.hasClass("menu")) { + // For mobile devices the home button allows immediate navigation back to the main menu, which may + // be useful if several pages have been navigated through. + _history = [_history[0], {href:"#menu?", transition:null}]; + goBack(); + } + }; + + if (e.type == "click") { + e.preventDefault(); // Prevent the browser trying to navigate to the href itself onclick. + if (!e.originalEvent) { // If event is triggered by calling the jQuery click() method. + if (jthis.is("li, input:radio")) { + start(e); + end(e); + } else if (jthis.is("input:checkbox")) { + var li = jthis.closest("li.horiz-checkbox"); + + if (li.length == 0) { // For a normal checkbox add pageX to the event and delegate handlePointer() + e.pageX = 0; + Checkbox.handlePointer(e, e.type); + } else { + // It's a horiz-checkbox. We need to find the label associated with the checkbox. + var label = jthis.parent("label"); // First check if the label contains the checkbox. + if (label.length == 0) { // If not look for a label containing a for matching the checkbox ID. + label = $("label[for='" + jthis.attr("id")+"']"); + } + if (label.length == 0) { // If not assume the label is the preceding sibling (a bit fragile..). + var items = li.children(); + label = $(items[items.index(jthis) - 1]); + } + + Checkbox.handleClick(label, e.type); + } + } + } + } else { // Event type is mousedown or touchstart so call main event start handler. + start(e); + } + }; + + /** + * This method handles keyboard input. Its main purpose is to detect the return key being pressed and if it + * has this method will attempt to trigger the handler bound to the right button, which should be a done/submit. + */ + var handleKeyboard = function(e) { + if (e.which == 13) { // Handle return key; + // When the return key is pressed find any right button present in the header and trigger a click + // on it, this should have the effect of triggering the done/submit handler for the form. + var jthis = $(e.target); + var done = jthis.closest(".main, .popup").find(".header a.right.button"); + done.trigger(START_EV).trigger(END_EV); + } + }; + +//------------------------------------------------------------------------------------------------------------------- +// Page Navigation Methods +//------------------------------------------------------------------------------------------------------------------- + + /** + * This event handler handles the synthetic refresh event that may be triggered on a top level page containing + * a scroll-area. The handler uses the id of the page to index the iScroll object then calls its refresh(). + */ + var handleRefresh = function(e) { + var id = $(this).attr("id"); + if (_scrollers[id] != null) { + _scrollers[id].refresh(); + } + } + + /** + * This method transitions to a selected destination. If the destination is "#" it simply returns, if there + * is no history the destination page is shown otherwise we transition using an animation. + * The ".split("?")[0]" blocks are there to cater for the case where the destination URL contains data to + * be passed between page fragments, where the data is delimited by a "?" and separated by "&". + */ + var goTo = function(destination, transition) { + iTablet.location = new Location(destination); + var previous = (_history.length == 0) ? null : _history[0].href; + + if (destination == "#" || destination == previous) { // The second test guards against multiple clicks + return; + } else if (!IS_MOBILE && _history.length == 0) { + var pages = $(".main"); + $(pages).each(function(index) { + var jthis = $(this); + var id = jthis.attr("id"); + if (("#" + id) == destination.split("?")[0]) { + jthis.show().trigger("show").find(".active").removeClass("active"); + _scrollers[id].refresh(); // Refresh the touch scroller on the new page. + _history.unshift({href:destination, transition:null}); + } else { + jthis.hide().trigger("hide"); + } + }); + } else { + var currentPage = $(_history[0].href.split("?")[0]); + var newPage = $(destination.split("?")[0]); + transition(currentPage, newPage, false); + _scrollers[newPage.attr("id")].refresh(); // Refresh the touch scroller on the new page. + _history.unshift({href:destination, transition:transition}); + } + }; + + /** + * This method transitions back to the previous item in the history using an animation. + * The ".split("?")[0]" blocks are there to cater for the case where the fragment URLs contain data to + * be passed between page fragments, where the data is delimited by a "?" and separated by "&". + */ + var goBack = function() { + if (_history.length > 1) { + iTablet.location = new Location(_history[1].href); + var transition = _history[0].transition; + var currentPage = $(_history[0].href.split("?")[0]); + var newPage = $(_history[1].href.split("?")[0]); + transition(currentPage, newPage, true); + _scrollers[newPage.attr("id")].refresh(); // Refresh the touch scroller on the new page. + _history.shift(); + + // Hide virtual keyboard. + document.activeElement.blur(); + } + }; + +//------------------------------------------------------------------------------------------------------------------- +// Animations +//------------------------------------------------------------------------------------------------------------------- + + /** + * This method detects support for CSS3 animations and transitions and uses them if present. It will attempt + * to use translate3d if present as this is most likely to be GPU accelerated and uses translate as fallback. + * In an ideal world this would be set up in a stylesheet using media queries, but unfortunately using + * prefixes for all of the keyframes is rather verbose and untidy and media query of translate3d only seems + * to be supported in WebKit, so scripting is needed whatever. This method "injects" the relevant styles. + */ + var initialiseCSSAnimations = function() { + // TODO It'd be nicer to use feature detection but that can be hard to get right - how do we *reliably" + // detect support for animationend and transitionend events, which are essential for these animations??? + if ((/android/gi).test(navigator.appVersion) || OPERA_VERSION <= 12.01) { + // Android has poor CSS3 animation support so use jQuery. + // Opera <= 12.01 doesn't have animationend which messes up state management, what's worse is that it + // passes the animationSupported test, so just bomb out early Opera 12.01 at least fails that... + return; + } + + var domPrefixes = ["Webkit", "Moz", "O", "ms", "Khtml"]; + + // For the following lookups ensure that prefix key is forced to lower case!! + var transitionEndLookup = { // Lookup transitionend Event. Note prefixes are different to DOM prefixes + "" : "transitionend", + "webkit" : "webkitTransitionEnd", + "moz" : "transitionend", + "o" : "oTransitionEnd", + "ms" : "transitionend" + }; + + var animationEndLookup = { // Lookup transitionend Event. Note prefixes are different to DOM prefixes + "" : "animationend", + "webkit" : "webkitAnimationEnd", + "moz" : "animationend", + "o" : "oAnimationEnd", + "ms" : "transitionend" + }; + + var has3d = false; + var domPrefix = ""; + var prefix = ""; + + var style = $("