Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

basic status and any search

  • Loading branch information...
commit 5b3519a746f4ce91610a3f0b04780a9c7d7deb82 0 parents
@mobz authored
202 LICENCE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
16 index.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+
+<html>
+ <head>
+ <title>Elastic Search Head</title>
+ <link rel="stylesheet" href="lib/es.css">
+ <script src="lib/jquery.js"></script>
+ <script src="lib/jsacx.js"></script>
+ <script src="lib/jsacx-widgets.js"></script>
+ <script src="lib/es-widgets.js"></script>
+ <script> $(function() { new es.ElasticSearchHead("body", { id: "es" }); }); </script>
+ </head>
+
+ <body></body>
+</html>
+
170 lib/es-widgets.js
@@ -0,0 +1,170 @@
+(function() {
+ var es = window.es = {};
+
+ es.ElasticSearchHead = acx.ui.Widget.extend({
+ defaults: {
+ base_uri: "http://localhost:9200/" // the default ElasticSearch host
+ },
+ init: function(parent) {
+ this._super();
+ this._initElements(parent);
+ },
+
+ open: function(widget, jEv) {
+ var t = $(jEv.target).closest("DIV.es-header-menu-item").addClass("active").siblings().removeClass("active");
+ this.el.find("#"+this.id("body")).empty().append(widget);
+ },
+
+ _openAnyQuery_handler: function(jEv) { this.open(new es.AnyQuery({ base_uri: this.config.base_uri }), jEv); },
+ _openClusterHealth_handler: function(jEv) { this.open(new es.SimpleGetQuery({ base_uri: this.config.base_uri, path: "_cluster/health" }), jEv); },
+ _openClusterState_handler: function(jEv) { this.open(new es.SimpleGetQuery({ base_uri: this.config.base_uri, path: "_cluster/state" }), jEv); },
+ _openClusterNodes_handler: function(jEv) { this.open(new es.SimpleGetQuery({ base_uri: this.config.base_uri, path: "_cluster/nodes" }), jEv); },
+ _openStatus_handler: function(jEv) { this.open(new es.SimpleGetQuery({ base_uri: this.config.base_uri, path: "_status" }), jEv); },
+
+ _initElements: function(parent) {
+ this.el = $(this._main_template());
+ this.appendTo(parent);
+ },
+
+ _main_template: function() {
+ return { tag: "DIV", cls: "es", children: [
+ { tag: "DIV", id: this.id("header"), cls: "es-header", children: [
+ { tag: "DIV", cls: "es-header-top", children: [
+ new es.Cluster({ base_uri: this.config.base_uri }),
+ { tag: "H1", text: "Elastic Search" }
+ ]},
+ { tag: "DIV", cls: "es-header-menu", children: [
+ { tag: "DIV", cls: "es-header-menu-item es-left", text: "Any Query", onclick: this._openAnyQuery_handler },
+ { tag: "DIV", cls: "es-header-menu-item es-right", text: "Cluster Health", onclick: this._openClusterHealth_handler },
+ { tag: "DIV", cls: "es-header-menu-item es-right", text: "Cluster State", onclick: this._openClusterState_handler },
+ { tag: "DIV", cls: "es-header-menu-item es-right", text: "Cluster Nodes", onclick: this._openClusterNodes_handler },
+ { tag: "DIV", cls: "es-header-menu-item es-right", text: "Status", onclick: this._openStatus_handler }
+ ]}
+ ]},
+ { tag: "DIV", id: this.id("body") }
+ ]};
+ }
+ });
+
+ es.AbstractQuery = acx.ui.Widget.extend({
+ defaults: {
+ base_uri: "http://localhost:9200/" // the default ElasticSearch host
+ },
+
+ _request_handler: function(params) {
+ var x = acx.extend({
+ url: this.config.base_uri + params.path,
+ type: "POST",
+ dataType: "json",
+ error: function(xhr) { console.log("XHR error", arguments, xhr_responseText); }
+ }, params);
+ console.log("_request_handler", x);
+ $.ajax(x);
+ }
+ });
+
+ es.Cluster = es.AbstractQuery.extend({
+
+ init: function(parent) {
+ this._super();
+ this.el = $(this._main_template());
+ this.appendTo(parent);
+ this.nameEl = this.el.find(".es-header-clusterName");
+ this.statEl = this.el.find(".es-header-clusterStatus");
+ this.statEl.text("cluster health: not connected").css("background", "red");
+ this._request_handler({ type: "GET", path: "", success: this._node_handler });
+ this._request_handler({ type: "GET", path: "_cluster/health", success: this._health_handler });
+ },
+
+ _node_handler: function(data) {
+ this.nameEl.text(data.name);
+ },
+
+ _health_handler: function(data) {
+ this.statEl.text("cluster health: " + data.status + " (" + data.number_of_nodes + ", " + data.active_primary_shards + ")").css("background", data.status);
+ },
+
+ _reconnect_handler: function() {
+ $("body").empty().append(new es.ElasticSearchHead("body", { id: "es", base_uri: this.el.find(".es-header-uri").val()}));
+ },
+
+ _main_template: function() {
+ return { tag: "SPAN", cls: "es-cluster", children: [
+ { tag: "INPUT", type: "text", cls: "es-header-uri", id: this.id("baseUri"), value: this.config.base_uri },
+ { tag: "BUTTON", type: "button", text: "Connect", onclick: this._reconnect_handler },
+ { tag: "SPAN", cls: "es-header-clusterName" },
+ { tag: "SPAN", cls: "es-header-clusterStatus" }
+ ]};
+ }
+ });
+
+ es.AnyQuery = es.AbstractQuery.extend({
+ defaults: {
+ default_query: "{query:{\"match_all\" : {}}}"
+ },
+ init: function(parent) {
+ this._super();
+ this._initElements();
+ this.appendTo(parent);
+ },
+
+ _request_handler: function() {
+ console.log("_request_handler");
+ this._super({
+ url: this.el.find("#q-url").val(),
+ type: this.el.find("#q-method").val(),
+ data: this.el.find("#q-body").val().trim(),
+ success: this._responseWriter_handler,
+ });
+ },
+
+ _responseWriter_handler: function(data) {
+ console.log("_responseWriter_handler", data);
+ this.el.find("PRE.es-out").text(JSON.stringify(data, null, ' '));
+ },
+
+ _initElements: function() {
+ this.el = $(this._main_template());
+ },
+
+ _main_template: function() {
+ return { tag: "DIV", children: [
+ { tag: "DIV", cls: "es-conf", children: [
+ { tag: "INPUT", type: "text", id: "q-url", value: this.config.base_uri },
+ { tag: "SELECT", id: "q-method", children: ["POST", "GET", "PUT"].map(function(m) { return { tag: "OPTION", value: m, text: m }; }) },
+ { tag: "BUTTON", type: "button", text: "Go", onclick: this._request_handler },
+ { tag: "BR" },
+ { tag: "TEXTAREA", id: "q-body", rows: 10, cols: 80, text: this.config.default_query }
+ ] },
+ { tag: "PRE", cls: "es-out" }
+ ] };
+ }
+ });
+
+ es.SimpleGetQuery = es.AbstractQuery.extend({
+ defaults: {
+ path: "" // required
+ },
+
+ init: function(parent) {
+ this._super();
+ this.el = $(this._main_template());
+ this.appendTo(parent);
+ this.update_handler();
+ },
+
+ update_handler: function() {
+ this._request_handler({
+ path: this.config.path,
+ type: "GET",
+ success: function(data) {
+ this.el.find(".es-out").text(JSON.stringify(data, null, ' '));
+ }.bind(this)
+ });
+ },
+
+ _main_template: function() {
+ return { tag: "DIV", child: { tag: "PRE", cls: "es-out" } };
+ }
+ });
+})();
73 lib/es.css
@@ -0,0 +1,73 @@
+BODY {
+ font-family: Verdana, sans-serif;
+ font-size: 73%;
+ padding: 0;
+ margin: 0;
+ overflow-y: scroll;
+}
+
+.es-left { float: left; }
+.es-right { float: right; }
+
+#es-header {
+ background: #eee;
+ position: fixed;
+ width: 100%;
+}
+
+.es-header-top {
+ padding: 3px 10px;
+}
+
+.es-header H1 {
+ margin: 0;
+ float: left;
+ padding-right: 25px;
+ margin-top: -2px;
+}
+
+.es-header-clusterName, .es-header-clusterStatus {
+ font-size: 1.2em;
+ font-weight: bold;
+ padding: 0 10px;
+}
+
+.es-header-uri {
+ width: 280px;
+}
+
+.es-header-menu {
+ border-bottom: 1px solid #bbb;
+ padding: 0px 3px;
+ height: 22px;
+}
+
+.es-header-menu .active {
+ background: white;
+ border-bottom-color: white;
+}
+
+.es-header-menu-item {
+ border: 1px solid #bbb;
+ padding: 4px 8px 1px ;
+ margin: 2px 1px 0;
+}
+
+#es-body {
+ padding: 5px;
+ padding-top: 60px;
+}
+
+.es-conf INPUT {
+ width: 405px;
+}
+
+.es-conf TEXTAREA {
+ width: 511px;
+}
+
+.es-out {
+ font-size: 1.4em;
+ min-height: 30px;
+ border: 1px solid #dadde6;
+}
7,179 lib/jquery.js
7,179 additions, 0 deletions not shown
207 lib/jsacx-widgets.js
@@ -0,0 +1,207 @@
+/**
+ * acx.ux namespace for interface enhancements
+ * @namespace
+ */
+acx.ux = {};
+
+/**
+ * a class for generating custom events in widgets
+ */
+acx.ux.Observable = acx.Class.extend((function() {
+ function getObs(type) {
+ return ( this.observers[type] || ( this.observers[type] = [] ) );
+ }
+ return {
+ init: function() {
+ this.observers = {};
+ for(var opt in this.config) { // automatically install observers that are defined in the configuration
+ if(opt.indexOf('on') === 0) {
+ this.on(opt.substring(2).replace(/^[A-Z]/, function(a) { return a.toLowerCase(); }), this.config[opt]);
+ }
+ }
+ },
+ on: function(type, fn, params, thisp) { // on: synonymous with addEvent, addObserver, subscribe
+ getObs.call(this, type).push( { cb : fn, args : params || [] , cx : thisp || this } );
+ return this; // make observable functions chainable
+ },
+ fire: function(type) { // fire: synonymous with fireEvent, observe, publish
+ var params = Array.prototype.slice.call(arguments, 1);
+ getObs.call(this, type).slice().forEach(function(ob) {
+ ob.cb.apply(ob.cx, ob.args.concat(params));
+ });
+ return this; // make observable functions chainable
+ },
+ removeObserver: function(type, fn) {
+ var obs = getObs.call(this, type), index = obs.reduce(function(p, t, i) { return (t.cb === fn) ? i : p }, -1 );
+ if(index !== -1) {
+ obs.splice(index, 1);
+ }
+ return this; // make observable functions chainable
+ },
+ hasObserver: function(type) {
+ return !!getObs.call(this, type).length;
+ }
+ };
+})());
+
+/**
+ * Provides drag and drop functionality<br>
+ * a DragDrop instance is created for each usage pattern and then used over and over again<br>
+ * first a dragObj is defined - this is the jquery node that will be dragged around<br>
+ * second, the event callbacks are defined - these allow you control the ui during dragging and run functions when successfully dropping<br>
+ * thirdly drop targets are defined - this is a list of DOM nodes, the constructor works in one of two modes:
+ * <li>without targets - objects can be picked up and dragged around, dragStart and dragStop events fire</li>
+ * <li>with targets - as objects are dragged over targets dragOver, dragOut and DragDrop events fire
+ * to start dragging call the DragDrop.pickup_handler() function, dragging stops when the mouse is released.
+ * @constructor
+ * The following options are supported
+ * <dt>targetSelector</dt>
+ * <dd>an argument passed directly to jquery to create a list of targets, as such it can be a CSS style selector, or an array of DOM nodes<br>if target selector is null the DragDrop does Drag only and will not fire dragOver dragOut and dragDrop events</dd>
+ * <dt>pickupSelector</dt>
+ * <dd>a jquery selector. The pickup_handler is automatically bound to matched elements (eg clicking on these elements starts the drag). if pickupSelector is null, the pickup_handler must be manually bound <code>$(el).bind("mousedown", dragdrop.pickup_handler)</code></dd>
+ * <dt>dragObj</dt>
+ * <dd>the jQuery element to drag around when pickup is called. If not defined, dragObj must be set in onDragStart</dd>
+ * <dt>draggingClass</dt>
+ * <dd>the class(es) added to items when they are being dragged</dd>
+ * The following observables are supported
+ * <dt>dragStart</dt>
+ * <dd>a callback when start to drag<br><code>function(jEv)</code></dd>
+ * <dt>dragOver</dt>
+ * <dd>a callback when we drag into a target<br><code>function(jEl)</code></dd>
+ * <dt>dragOut</dt>
+ * <dd>a callback when we drag out of a target, or when we drop over a target<br><code>function(jEl)</code></dd>
+ * <dt>dragDrop</dt>
+ * <dd>a callback when we drop on a target<br><code>function(jEl)</code></dd>
+ * <dt>dragStop</dt>
+ * <dd>a callback when we stop dragging<br><code>function(jEv)</code></dd>
+ */
+acx.ux.DragDrop = acx.ux.Observable.extend({
+ defaults : {
+ targetsSelector : null,
+ pickupSelector: null,
+ dragObj : null,
+ draggingClass : "dragging"
+ },
+
+ init: function(options) {
+ this._super(); // call the class initialiser
+
+ this.drag_handler = this.drag.bind(this);
+ this.drop_handler = this.drop.bind(this);
+ this.pickup_handler = this.pickup.bind(this);
+ this.targets = [];
+ this.dragObj = null;
+ this.dragObjOffset = null;
+ this.currentTarget = null;
+ if(this.config.pickupSelector) {
+ $(this.config.pickupSelector).bind("mousedown", this.pickup_handler);
+ }
+ },
+
+ drag : function(jEv) {
+ jEv.preventDefault();
+ var mloc = acx.vector(jEv.pageX, jEv.pageY);
+ this.dragObj.css(mloc.add(this.dragObjOffset).asOffset());
+ if(this.targets.length === 0) {
+ return;
+ }
+ if(this.currentTarget !== null && mloc.within(this.currentTarget[1], this.currentTarget[2])) {
+ return;
+ }
+ if(this.currentTarget !== null) {
+ this.fire('dragOut', this.currentTarget[0]);
+ this.currentTarget = null;
+ }
+ for(var i = 0; i < this.targets.length; i++) {
+ if(mloc.within(this.targets[i][1], this.targets[i][2])) {
+ this.currentTarget = this.targets[i];
+ break;
+ }
+ }
+ if(this.currentTarget !== null) {
+ this.fire('dragOver', this.currentTarget[0]);
+ }
+ },
+
+ drop : function(jEv) {
+ $(document).unbind("mousemove", this.drag_handler);
+ $(document).unbind("mouseup", this.drop_handler);
+ this.dragObj.removeClass(this.config.draggingClass);
+ if(this.currentTarget !== null) {
+ this.fire('dragOut', this.currentTarget[0]);
+ this.fire('dragDrop', this.currentTarget[0]);
+ }
+ this.fire('dragStop', jEv);
+ this.dragObj = null;
+ },
+
+ pickup : function(jEv, opts) {
+ acx.extend(this.config, opts);
+ this.fire('dragStart', jEv);
+ this.dragObj = this.dragObj || this.config.dragObj;
+ this.dragObjOffset = this.config.dragObjOffset || acx.vector(this.dragObj.offset()).sub(jEv.pageX, jEv.pageY);
+ this.dragObj.addClass(this.config.draggingClass);
+ if(!this.dragObj.get(0).parentNode || this.dragObj.get(0).parentNode.nodeType === 11) { // 11 = document fragment
+ $(document.body).append(this.dragObj);
+ }
+ if(this.config.targetsSelector) {
+ this.currentTarget = null;
+ var targets = ( this.targets = [] );
+ // create an array of elements optimised for rapid collision detection calculation
+ $(this.config.targetsSelector).each(function(i, el) {
+ var jEl = $(el);
+ var tl = acx.vector(jEl.offset());
+ var br = tl.add(jEl.width(), jEl.height());
+ targets.push([jEl, tl, br]);
+ });
+ }
+ $(document).bind("mousemove", this.drag_handler);
+ $(document).bind("mouseup", this.drop_handler);
+ this.drag_handler(jEv);
+ }
+});
+
+/**
+ * acx.ui namespace for widget components
+ * @namespace
+ */
+acx.ui = {};
+
+/**
+ * base class for all widgets
+ * provides: base element definition, automatic observable creation, bound function handlers
+ * @constructor
+ */
+acx.ui.Widget = acx.ux.Observable.extend({
+ defaults : {
+ id: null // the id of the widget
+ },
+
+ el: null, // this is the jquery wrapped dom element(s) that is the actual widget
+
+ init: function() {
+ this._super();
+ for(var prop in this) { // automatically bind all the event handlers
+ if(prop.contains("_handler")) {
+ this[prop] = this[prop].bind(this);
+ }
+ }
+ },
+
+ id: function(suffix) {
+ return this.config.id ? (this.config.id + (suffix ? "-" + suffix : "")) : undefined;
+ },
+
+ appendTo: function(parent) {
+ if(parent) {
+ this.el.appendTo(parent);
+ }
+ return this;
+ },
+
+ remove: function() {
+ this.el.remove();
+ return this;
+ }
+});
+
604 lib/jsacx.js
@@ -0,0 +1,604 @@
+/**
+ * jsacx.js
+ * @author the regents of aconex ui
+ */
+
+( function() {
+
+var window = this,
+ $ = jQuery,
+ acx = {};
+
+/**
+ * global acx namespace
+ * @namespace
+ * @name acx
+ */
+window.acx = acx;
+
+/**
+ * generic object iterator
+ * @function
+ */
+acx.each = $.each;
+
+/**
+ * extends the first argument with the properties of the second and subsequent arguments
+ * @function
+ */
+acx.extend = $.extend;
+
+/**
+ * augments the first argument with the properties of the second and subsequent arguments
+ * like {@link acx.extend} except that existing properties are not overwritten
+ */
+acx.augment = function() {
+ var args = Array.prototype.slice.call(arguments),
+ src = (args.length === 1) ? this : args.shift(),
+ augf = function(n, v) {
+ if(! (n in src)) {
+ src[n] = v;
+ }
+ };
+ for(var i = 0; i < args.length; i++) {
+ acx.each(args[i], augf);
+ }
+ return src;
+};
+
+/**
+ * tests whether the argument is an array
+ * @function
+ */
+acx.isArray = $.isArray;
+
+/**
+ * tests whether the argument is an object
+ * @function
+ */
+acx.isObject = function (value) {
+ return Object.prototype.toString.call(value) == "[object Object]";
+};
+
+/**
+ * tests whether the argument is a date
+ * @function
+ */
+acx.isDate = function (value) {
+ return Object.prototype.toString.call(value) == "[object Date]";
+};
+
+/**
+ * tests whether the value is blank or empty
+ * @function
+ */
+acx.isEmpty = function (value, allowBlank) {
+ return value === null || value === undefined || ((acx.isArray(value) && !value.length)) || (!allowBlank ? value === '' : false);
+};
+
+/**
+ * creates and parses a string to a date object
+ * @function
+ */
+acx.parseDate = function(str, fmt, forceStrMonth){
+ var fmt = fmt || window.localeDateFormat;
+ var mnlu = ([].concat(JSCal.i18n.mn).concat(JSCal.i18n.smn)).map(function(n) { return n.toLowerCase(); });
+ var flu = [ ["%y%Y", 1900, 2999, _pY ], ["%m%b%B", 0, 11, _pM ], ["%d%e", 1, 31, _pD ], ["%H%I%k%l", 0, 23, _pT ], ["%M", 0, 59, _pT] ];
+ function getFMap(fkey) { return flu.reduce(function(rv, key, i) { return key[0].contains(fkey) ? i : rv; }, null); }
+ function _pY(y) { y = parseInt(y, 10); return y + (y < 100 ? Math.floor(((new Date()).getFullYear() + 50 - y) / 100) * 100 : 0); }
+ function _pM(m) { return ((!forceStrMonth && parseInt(m, 10)) || 1 + (mnlu.indexOf(m.toLowerCase()) % 12)) -1; }
+ function _pD(d) { return parseInt(d, 10); }
+ function _pT(t) { tn = parseInt(t, 10); return tn + ((/pm/i.test(t) && tn < 12) ? 12 : 0) + ((/am/i.test(t) && tn > 12) ? -12 : 0); }
+ var da = new Date(); date = [0, -1, 0, 0, 0], f = fmt.match(/%./g);
+ return ((str.match(/^\d+$/)
+ ? (str.match(new RegExp(f.map(function(t) {
+ return (t.match(/%y/i) && str.length > (f.length * 2)) ? "(....)" : "(..)"; }).join(""))) || [0, "e"]).slice(1)
+ : str.split(/\W/)).reduce(function(good, de, i) {
+ var fkey = getFMap(f[i]); if(fkey === null) { return good; }
+ date[fkey] = flu[fkey][3](de);
+ return good && (date[fkey] >= flu[fkey][1] && date[fkey] <= flu[fkey][2]);
+ }, true) && (da.setTime(Date.UTC.apply(null, date)) && da))
+ || (!forceStrMonth && acx.parseDate(str, "%m%d%y", true)) || (!forceStrMonth && acx.parseDate(str, "%d%m%y", true));
+};
+
+/**
+ * tests whether the argument is a function
+ * @function
+ */
+acx.isFunction = $.isFunction;
+
+/**
+ * data type for performing chainable geometry calculations<br>
+ * can be initialised x,y | {x, y} | {left, top}
+ */
+acx.vector = function(x, y) {
+ return new acx.vector.prototype.Init(x, y);
+};
+
+acx.vector.prototype = {
+ Init : function(x, y) {
+ x = x || 0;
+ this.y = isFinite(x.y) ? x.y : (isFinite(x.top) ? x.top : (isFinite(y) ? y : 0));
+ this.x = isFinite(x.x) ? x.x : (isFinite(x.left) ? x.left : (isFinite(x) ? x : 0));
+ },
+
+ add : function(i, j) {
+ var d = acx.vector(i, j);
+ return new this.Init(this.x + d.x, this.y + d.y);
+ },
+
+ sub : function(i, j) {
+ var d = acx.vector(i, j);
+ return new this.Init(this.x - d.x, this.y - d.y);
+ },
+
+ addX : function(i) {
+ return new this.Init(this.x + i, this.y);
+ },
+
+ addY : function(j) {
+ return new this.Init(this.x, this.y + j);
+ },
+
+ mod : function(fn) { // runs a function against the x and y values
+ return new this.Init({x: fn.call(this, this.x, "x"), y: fn.call(this, this.y, "y")});
+ },
+
+ /** returns true if this is within a rectangle formed by the points p and q */
+ within : function(p, q) {
+ return ( this.x >= ((p.x < q.x) ? p.x : q.x) && this.x <= ((p.x > q.x) ? p.x : q.x) &&
+ this.y >= ((p.y < q.y) ? p.y : q.y) && this.y <= ((p.y > q.y) ? p.y : q.y) );
+ },
+
+ asOffset : function() {
+ return { top: this.y, left: this.x };
+ },
+
+ asSize : function() {
+ return { height: this.y, width: this.x };
+ }
+};
+
+acx.vector.prototype.Init.prototype = acx.vector.prototype;
+
+/**
+ * short cut functions for working with vectors and jquery.
+ * Each function returns the equivalent jquery value in a two dimentional vector
+ */
+$.fn.vSize = function() { return acx.vector(this.width(), this.height()); };
+$.fn.vOuterSize = function(margin) { return acx.vector(this.outerWidth(margin), this.outerHeight(margin)); };
+$.fn.vScroll = function() { return acx.vector(this.scrollLeft(), this.scrollTop()); };
+$.fn.vOffset = function() { return acx.vector(this.offset()); };
+$.fn.vPosition = function() { return acx.vector(this.position()); };
+$.Event.prototype.vMouse = function() { return acx.vector(this.pageX, this.pageY); };
+
+/**
+ * Array prototype extensions
+ */
+acx.augment(Array.prototype, {
+ 'contains' : function(needle) {
+ return this.indexOf(needle) !== -1;
+ },
+
+ 'filter' : function(fn, thisp) {
+ var res = [];
+ for (var i = 0, len = this.length; i < len; i++) {
+ if (i in this) {
+ var val = this[i];
+ if (fn.call(thisp, val, i, this)) {
+ res.push(val);
+ }
+ }
+ }
+ return res;
+ },
+
+ 'forEach' : function(fn, thisp) {
+ for (var i = 0; i < this.length; i++) {
+ if (i in this) {
+ fn.call(thisp, this[i], i, this);
+ }
+ }
+ },
+
+ 'indexOf' : function(needle, from) {
+ from = parseInt(from, 10) || 0;
+ if (from < 0) {
+ from += this.length;
+ }
+ for (; from < this.length; from++) {
+ if (from in this && this[from] === needle) {
+ return from;
+ }
+ }
+ return -1;
+ },
+
+ 'map' : function(fn, thisp) {
+ var ret = [];
+ for ( var i = 0; i < this.length; i++) {
+ if (i in this) {
+ ret[i] = fn.call(thisp, this[i], i, this);
+ }
+ }
+ return ret;
+ },
+
+ 'reduce' : function(fn, value) {
+ var i = 0;
+ rv = value;
+ if (arguments.length === 1) {
+ while (!(i++ in this)) {
+ }
+ rv = this[i - 1];
+ }
+ for (; i < this.length; i++) {
+ if (i in this) {
+ rv = fn.call(null, rv, this[i], i, this);
+ }
+ }
+ return rv;
+ }
+});
+
+/**
+ * Function prototype extensions
+ */
+acx.augment(Function.prototype, {
+ 'bind' : function() {
+ var method = this,
+ args = Array.prototype.slice.call(arguments),
+ obj = args.shift();
+ return function() {
+ return method.apply(obj, args.concat(Array.prototype.slice.call(arguments)));
+ };
+ },
+
+ 'delay' : function() {
+ var method = this,
+ args = Array.prototype.slice.call(arguments),
+ timeout = args.shift();
+ return window.setTimeout( function() {
+ return method.apply(method, args);
+ }, timeout);
+ }
+});
+
+/**
+ * String prototype extensions
+ */
+acx.augment(String.prototype, {
+ 'contains' : function(needle) {
+ return this.indexOf(needle) !== -1;
+ },
+
+ 'trim' : function() {
+ return this.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
+ },
+
+ 'equalsIgnoreCase' : function(match) {
+ return this.toLowerCase() === match.toLowerCase();
+ },
+
+ 'escapeHtml' : function() {
+ return this.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
+ },
+
+ 'escapeJS' : function() {
+ var meta = {'"':'\\"', '\\':'\\\\', '/':'\\/', '\b':'\\b', '\f':'\\f', '\n':'\\n', '\r':'\\r', '\t':'\\t'},
+ xfrm = function(c) { return meta[c] || "\\u" + c.charCodeAt(0).toString(16).zeroPad(4); };
+ return this.replace(new RegExp('(["\\\\\x00-\x1f\x7f-\uffff])', 'g'), xfrm);
+ },
+
+ 'escapeRegExp' : function() {
+ var ret = "", esc = "\\^$*+?.()=|{,}[]-";
+ for ( var i = 0; i < this.length; i++) {
+ ret += (esc.contains(this.charAt(i)) ? "\\" : "") + this.charAt(i);
+ }
+ return ret;
+ },
+
+ 'zeroPad' : function(len) {
+ return ("0000000000" + this).substring(this.length - len + 10);
+ }
+});
+
+/**
+ * contains a series of flags indicating which browser is in use and the presence of different browser features or bugs<br>
+ * Contains the following flags<br>
+ * <ul>
+ * <li> all properties from <a href="http://docs.jquery.com/Utilities/jQuery.support">jQuery.support</a>
+ * <li> safari, opera, msie, mozilla - which rendering engine is in use
+ * <li> version - a string in format A.B.C representing the browser version
+ * <li> ie6, ie7 and ie67 shortcuts to determine exact browser
+ * </ul>
+ * @field
+ */
+acx.browser = $.support;
+acx.extend(acx.browser, $.browser);
+acx.browser.major = parseInt(acx.browser.version, 10);
+acx.browser.ie6 = acx.browser.msie && acx.browser.major === 6;
+acx.browser.ie7 = acx.browser.msie && acx.browser.major === 7;
+acx.browser.ie8 = acx.browser.msie && acx.browser.major === 8;
+acx.browser.ie9 = acx.browser.msie && acx.browser.major === 9;
+acx.browser.ie67 = acx.browser.ie6 || acx.browser.ie7;
+acx.browser.ie678 = acx.browser.ie67 || acx.browser.ie8;
+$(function() { acx.each($.browser, function(n,v, b) { if(v === true && (b = n.match(/ie$|^moz|^saf/))) { document.body.className += b[0] + " " + b[0] + acx.browser.major; } }) });
+
+
+/**
+ * provides text formatting and i18n key storage features<br>
+ * implements most of the Sun Java MessageFormat functionality.
+ * @see <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/text/MessageFormat.html" target="sun">Sun's Documentation</a>
+ * @namespace
+ */
+acx.i18n = (function() {
+ /**
+ * the collections of keys in memory
+ */
+ var keys = {};
+
+ /**
+ * formats a message using the provided arguments
+ */
+ var format = function(message, args) {
+ var substitute = function() {
+ var format = arguments[1].split(',');
+ var substr = escape(args[format.shift()]);
+ if(format.length === 0) {
+ return substr; // simple substitution eg {0}
+ }
+ switch(format.shift()) {
+ case "number" : return (new Number(substr)).toLocaleString();
+ case "date" : return (new Date(+substr)).toLocaleDateString(); // date and time require milliseconds since epoch
+ case "time" : return (new Date(+substr)).toLocaleTimeString(); // eg acx.text("Key", +(new Date())); for current time
+ }
+ var styles = format.join("").split("|").map(function(style) {
+ return style.match(/(-?[\.\d]+)(#|<)([^{}]*)/);
+ });
+ var match = styles[0][3];
+ for(var i=0; i<styles.length; i++) {
+ if((styles[i][2] === "#" && (+styles[i][1]) === (+substr)) ||
+ (styles[i][2] === "<" && ((+styles[i][1]) < (+substr)))) {
+ match = styles[i][3];
+ }
+ }
+ return match;
+ };
+
+ if(message === undefined) {
+ return message;
+ }
+
+ // split message into formatting parts (mostly processed by the regexp)
+ return message.replace(/'(')|'([^']+)'|([^{']+)|([^']+)/g, function(x, sq, qs, ss, sub) {
+
+ // keep replacing substitutions (recursively) until none remain
+ do {} while(sub && (sub !== (sub = (sub.replace(/\{([^{}]+)\}/, substitute)))));
+
+ return sq || qs || ss || unescape(sub);
+ });
+ };
+
+ return {
+
+ /**
+ * set an i18n key for later use<br>
+ * @function
+ * @name acx.i18n.setKey
+ */
+ setKey: function(key, value) {
+ keys[key] = value;
+ },
+
+ /**
+ * sets a group i18n key for later use<br>
+ * @function
+ * @name acx.i18n.setKeys
+ */
+ setKeys: function(strings) {
+ for(key in strings) {
+ keys[key] = strings[key];
+ }
+ },
+
+ /**
+ * convert an i18n key to text and format using the Java MessageFormat standard <br>
+ * use shortcut {@link acx.text}
+ * @name acx.i18n.formatKey
+ * @function
+ */
+ formatKey: function() {
+ var args = Array.prototype.slice.call(arguments),
+ key = keys[args.shift()];
+ if(args.length === 0) {
+ return key;
+ }
+ return format(key, args);
+ },
+
+ /**
+ * format a text string using the Java MessageFormat standard
+ * @name acx.i18n.formatText
+ * @function
+ */
+ formatText: function(text, args) {
+ return format(text, acx.isArray(args) ? args : [args]);
+ },
+
+ /**
+ * format a key substituting non-string values. Returns an array
+ * limited to simple substitution types, useful for passing to $.create
+ */
+ formatComplex: function(key, args) {
+ var args = Array.prototype.slice.call(arguments),
+ key = keys[args.shift()],
+ ret = [];
+ do {} while(key && key !== (key = key.replace(/([^{]+)|\{(\d+)\}/, function(x, pt, sub) {
+ ret.push(pt || args[+sub]);
+ return "";
+ })));
+ return ret;
+ }
+ };
+})();
+
+/**
+ * shortcut to {@link acx.i18n.formatKey}
+ * @function
+ */
+acx.text = acx.i18n.formatKey;
+
+/**
+ * create a node using an object element definition
+ */
+acx.create = (function() {
+ function addAttrs(el, obj, context) {
+ for(var attr in obj){
+ switch(attr) {
+ case 'tag' :
+ break;
+ case 'html' :
+ el.innerHTML = obj[attr];
+ break;
+ case 'css' :
+ for (var style in obj.css) {
+ $.attr(el.style, style, obj.css[style]);
+ }
+ break;
+ case 'text' : case 'child' : case 'children' :
+ createNode(obj[attr], el, context);
+ break;
+ case 'cls' :
+ el.className = obj[attr];
+ break;
+ case 'data' :
+ for(var data in obj.data) {
+ $.data(el, data, obj.data[data]);
+ }
+ break;
+ default :
+ if(attr.indexOf("on") === 0 && acx.isFunction(obj[attr])) {
+ $.event.add(el, attr.substr(2), obj[attr]);
+ } else {
+ $.attr(el, attr, obj[attr]);
+ }
+ }
+ }
+ }
+
+ function createNode(obj, parent, context) {
+ if(obj && (acx.isArray(obj) || obj.jquery)) {
+ for(var ret = [], i = 0; i < obj.length; i++) {
+ var newNode = createNode(obj[i], parent, context);
+ if(newNode) {
+ ret.push(newNode);
+ }
+ }
+ return ret;
+ }
+ var el;
+ if(typeof(obj) === 'string') {
+ el = context.createTextNode(obj);
+ } else if(!obj) {
+ return undefined;
+ } else if(obj.nodeType === 1) {
+ el = obj;
+ } else if(obj instanceof acx.ui.Widget) {
+ el = obj.el[0];
+ } else {
+ if(acx.browser.ie678 && obj.tag && obj.tag.match(/input|button/i)) {
+ el = context.createElement("<"+obj.tag+" type='"+obj.type+"'" + (obj.checked ? " checked" : "") + ">");
+ delete obj.type;
+ } else {
+ el = context.createElement(obj.tag||'DIV');
+ }
+ addAttrs(el, obj, context);
+ }
+ if(parent){ parent.appendChild(el); }
+ return el;
+ };
+
+ return function(elementDef, parentNode) {
+ return createNode(elementDef, parentNode, (parentNode && parentNode.ownerDocument) || document);
+ };
+})();
+
+// inject acx.create into jquery internals so object definitions are treated as first class constructors (uses non-public methods)
+(function() {
+ var clean = jQuery.clean,
+ init = jQuery.fn.init;
+
+ jQuery.clean = function( elems, context, fragment ) {
+ for(var i = 0; i < elems.length; i++) {
+ if(elems[i].tag)
+ elems[i] = acx.create( elems[0], null, context );
+ else if(elems[i] instanceof acx.ui.Widget)
+ elems[i] = elems[i].el
+ }
+ return clean( elems, context, fragment );
+ };
+
+ jQuery.fn.init = function(selector, context) {
+ if ( selector && selector.tag ) {
+ selector = acx.create(selector, null, context);
+ } else if(selector && selector instanceof acx.ui.Widget) {
+ selector = selector.el;
+ }
+ return init.call(this, selector, context);
+ };
+ jQuery.fn.init.prototype = jQuery.fn;
+})();
+
+
+/**
+ * base class for creating inheritable classes
+ * based on resigs 'Simple Javascript Inheritance Class' (based on base2 and prototypejs)
+ * modified with static super and auto config
+ * @name Class
+ * @constructor
+ */
+(function(){
+ var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
+
+ acx.Class = function(){};
+
+ acx.Class.extend = function(prop) {
+ function Class() {
+ if(!initializing) {
+ var args = Array.prototype.slice.call(arguments);
+ this.config = $.extend( function(t) { // automatically construct a config object based on defaults and last item passed into the constructor
+ return $.extend(t._proto && t._proto() && arguments.callee(t._proto()) || {}, t.defaults);
+ } (this) , args.pop() );
+ this.init && this.init.apply(this, args); // automatically run the init function when class created
+ }
+ }
+
+ initializing = true;
+ var prototype = new this();
+ initializing = false;
+
+ var _super = this.prototype;
+ prototype._proto = function() {
+ return _super;
+ };
+
+ for(var name in prop) {
+ prototype[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ?
+ (function(name, fn){
+ return function() { this._super = _super[name]; return fn.apply(this, arguments); };
+ })(name, prop[name]) : prop[name];
+ }
+
+ Class.prototype = prototype;
+ Class.constructor = Class;
+
+ Class.extend = arguments.callee; // make class extendable
+
+ return Class;
+ };
+})();
+
+
+
+})();
Please sign in to comment.
Something went wrong with that request. Please try again.