/* BlobBuilder.js
* A BlobBuilder implementation.
* 2012-04-21
*
* By Eli Grey, http://eligrey.com
* License: X11/MIT
* See LICENSE.md
*/
/*global self, unescape */
/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
plusplus: true */
/*! @source http://purl.eligrey.com/github/BlobBuilder.js/blob/master/BlobBuilder.js */
var BlobBuilder = BlobBuilder || self.WebKitBlobBuilder || self.MozBlobBuilder || self.MSBlobBuilder || (function(view) {
"use strict";
var
get_class = function(object) {
return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
}
, FakeBlobBuilder = function(){
this.data = [];
}
, FakeBlob = function(data, type, encoding) {
this.data = data;
this.size = data.length;
this.type = type;
this.encoding = encoding;
}
, FBB_proto = FakeBlobBuilder.prototype
, FB_proto = FakeBlob.prototype
, FileReaderSync = view.FileReaderSync
, FileException = function(type) {
this.code = this[this.name = type];
}
, file_ex_codes = (
"NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "
+ "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
).split(" ")
, file_ex_code = file_ex_codes.length
, realURL = view.URL || view.webkitURL || view
, real_create_object_URL = realURL.createObjectURL
, real_revoke_object_URL = realURL.revokeObjectURL
, URL = realURL
, btoa = view.btoa
, atob = view.atob
, can_apply_typed_arrays = false
, can_apply_typed_arrays_test = function(pass) {
can_apply_typed_arrays = !pass;
}
, ArrayBuffer = view.ArrayBuffer
, Uint8Array = view.Uint8Array
;
FakeBlobBuilder.fake = FB_proto.fake = true;
while (file_ex_code--) {
FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
}
try {
if (Uint8Array) {
can_apply_typed_arrays_test.apply(0, new Uint8Array(1));
}
} catch (ex) {}
if (!realURL.createObjectURL) {
URL = view.URL = {};
}
URL.createObjectURL = function(blob) {
var
type = blob.type
, data_URI_header
;
if (type === null) {
type = "application/octet-stream";
}
if (blob instanceof FakeBlob) {
data_URI_header = "data:" + type;
if (blob.encoding === "base64") {
return data_URI_header + ";base64," + blob.data;
} else if (blob.encoding === "URI") {
return data_URI_header + "," + decodeURIComponent(blob.data);
} if (btoa) {
return data_URI_header + ";base64," + btoa(blob.data);
} else {
return data_URI_header + "," + encodeURIComponent(blob.data);
}
} else if (real_create_object_url) {
return real_create_object_url.call(realURL, blob);
}
};
URL.revokeObjectURL = function(object_url) {
if (object_url.substring(0, 5) !== "data:" && real_revoke_object_url) {
real_revoke_object_url.call(realURL, object_url);
}
};
FBB_proto.append = function(data/*, endings*/) {
var bb = this.data;
// decode data to a binary string
if (Uint8Array && data instanceof ArrayBuffer) {
if (can_apply_typed_arrays) {
bb.push(String.fromCharCode.apply(String, new Uint8Array(data)));
} else {
var
str = ""
, buf = new Uint8Array(data)
, i = 0
, buf_len = buf.length
;
for (; i < buf_len; i++) {
str += String.fromCharCode(buf[i]);
}
}
} else if (get_class(data) === "Blob" || get_class(data) === "File") {
if (FileReaderSync) {
var fr = new FileReaderSync;
bb.push(fr.readAsBinaryString(data));
} else {
// async FileReader won't work as BlobBuilder is sync
throw new FileException("NOT_READABLE_ERR");
}
} else if (data instanceof FakeBlob) {
if (data.encoding === "base64" && atob) {
bb.push(atob(data.data));
} else if (data.encoding === "URI") {
bb.push(decodeURIComponent(data.data));
} else if (data.encoding === "raw") {
bb.push(data.data);
}
} else {
if (typeof data !== "string") {
data += ""; // convert unsupported types to strings
}
// decode UTF-16 to binary string
bb.push(unescape(encodeURIComponent(data)));
}
};
FBB_proto.getBlob = function(type) {
if (!arguments.length) {
type = null;
}
return new FakeBlob(this.data.join(""), type, "raw");
};
FBB_proto.toString = function() {
return "[object BlobBuilder]";
};
FB_proto.slice = function(start, end, type) {
var args = arguments.length;
if (args < 3) {
type = null;
}
return new FakeBlob(
this.data.slice(start, args > 1 ? end : this.data.length)
, type
, this.encoding
);
};
FB_proto.toString = function() {
return "[object Blob]";
};
return FakeBlobBuilder;
}(self));/* FileSaver.js
* A saveAs() FileSaver implementation.
* 2011-08-02
*
* By Eli Grey, http://eligrey.com
* License: X11/MIT
* See LICENSE.md
*/
/*global self */
/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
plusplus: true */
/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
var saveAs = saveAs || (function(view) {
"use strict";
var
doc = view.document
// only get URL when necessary in case BlobBuilder.js hasn't overridden it yet
, get_URL = function() {
return view.URL || view.webkitURL || view;
}
, URL = view.URL || view.webkitURL || view
, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
, can_use_save_link = "download" in save_link
, click = function(node) {
var event = doc.createEvent("MouseEvents");
event.initMouseEvent(
"click", true, false, view, 0, 0, 0, 0, 0
, false, false, false, false, 0, null
);
return node.dispatchEvent(event); // false if event was cancelled
}
, webkit_req_fs = view.webkitRequestFileSystem
, req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
, throw_outside = function (ex) {
(view.setImmediate || view.setTimeout)(function() {
throw ex;
}, 0);
}
, force_saveable_type = "application/octet-stream"
, fs_min_size = 0
, deletion_queue = []
, process_deletion_queue = function() {
var i = deletion_queue.length;
while (i--) {
var file = deletion_queue[i];
if (typeof file === "string") { // file is an object URL
URL.revokeObjectURL(file);
} else { // file is a File
file.remove();
}
}
deletion_queue.length = 0; // clear queue
}
, dispatch = function(filesaver, event_types, event) {
event_types = [].concat(event_types);
var i = event_types.length;
while (i--) {
var listener = filesaver["on" + event_types[i]];
if (typeof listener === "function") {
try {
listener.call(filesaver, event || filesaver);
} catch (ex) {
throw_outside(ex);
}
}
}
}
, FileSaver = function(blob, name) {
// First try a.download, then web filesystem, then object URLs
var
filesaver = this
, type = blob.type
, blob_changed = false
, object_url
, target_view
, get_object_url = function() {
var object_url = get_URL().createObjectURL(blob);
deletion_queue.push(object_url);
return object_url;
}
, dispatch_all = function() {
dispatch(filesaver, "writestart progress write writeend".split(" "));
}
// on any filesys errors revert to saving with object URLs
, fs_error = function() {
// don't create more object URLs than needed
if (blob_changed || !object_url) {
object_url = get_object_url(blob);
}
target_view.location.href = object_url;
filesaver.readyState = filesaver.DONE;
dispatch_all();
}
, abortable = function(func) {
return function() {
if (filesaver.readyState !== filesaver.DONE) {
return func.apply(this, arguments);
}
};
}
, create_if_not_found = {create: true, exclusive: false}
, slice
;
filesaver.readyState = filesaver.INIT;
if (!name) {
name = "download";
}
if (can_use_save_link) {
object_url = get_object_url(blob);
save_link.href = object_url;
save_link.download = name;
if (click(save_link)) {
filesaver.readyState = filesaver.DONE;
dispatch_all();
return;
}
}
// Object and web filesystem URLs have a problem saving in Google Chrome when
// viewed in a tab, so I force save with application/octet-stream
// http://code.google.com/p/chromium/issues/detail?id=91158
if (view.chrome && type && type !== force_saveable_type) {
slice = blob.slice || blob.webkitSlice;
blob = slice.call(blob, 0, blob.size, force_saveable_type);
blob_changed = true;
}
// Since I can't be sure that the guessed media type will trigger a download
// in WebKit, I append .download to the filename.
// https://bugs.webkit.org/show_bug.cgi?id=65440
if (webkit_req_fs && name !== "download") {
name += ".download";
}
if (type === force_saveable_type || webkit_req_fs) {
target_view = view;
} else {
target_view = view.open();
}
if (!req_fs) {
fs_error();
return;
}
fs_min_size += blob.size;
req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
var save = function() {
dir.getFile(name, create_if_not_found, abortable(function(file) {
file.createWriter(abortable(function(writer) {
writer.onwriteend = function(event) {
target_view.location.href = file.toURL();
deletion_queue.push(file);
filesaver.readyState = filesaver.DONE;
dispatch(filesaver, "writeend", event);
};
writer.onerror = function() {
var error = writer.error;
if (error.code !== error.ABORT_ERR) {
fs_error();
}
};
"writestart progress write abort".split(" ").forEach(function(event) {
writer["on" + event] = filesaver["on" + event];
});
writer.write(blob);
filesaver.abort = function() {
writer.abort();
filesaver.readyState = filesaver.DONE;
};
filesaver.readyState = filesaver.WRITING;
}), fs_error);
}), fs_error);
};
dir.getFile(name, {create: false}, abortable(function(file) {
// delete file if it already exists
file.remove();
save();
}), abortable(function(ex) {
if (ex.code === ex.NOT_FOUND_ERR) {
save();
} else {
fs_error();
}
}));
}), fs_error);
}), fs_error);
}
, FS_proto = FileSaver.prototype
, saveAs = function(blob, name) {
return new FileSaver(blob, name);
}
;
FS_proto.abort = function() {
var filesaver = this;
filesaver.readyState = filesaver.DONE;
dispatch(filesaver, "abort");
};
FS_proto.readyState = FS_proto.INIT = 0;
FS_proto.WRITING = 1;
FS_proto.DONE = 2;
FS_proto.error =
FS_proto.onwritestart =
FS_proto.onprogress =
FS_proto.onwrite =
FS_proto.onabort =
FS_proto.onerror =
FS_proto.onwriteend =
null;
view.addEventListener("unload", process_deletion_queue, false);
return saveAs;
}(self));/* canvas-toBlob.js
* A canvas.toBlob() implementation.
* 2011-07-13
*
* By Eli Grey, http://eligrey.com and Devin Samarin, https://github.com/eboyjr
* License: X11/MIT
* See LICENSE.md
*/
/*global self */
/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
plusplus: true */
/*! @source http://purl.eligrey.com/github/canvas-toBlob.js/blob/master/canvas-toBlob.js */
(function(view) {
"use strict";
var
Uint8Array = view.Uint8Array
, HTMLCanvasElement = view.HTMLCanvasElement
, is_base64_regex = /\s*;\s*base64\s*(?:;|$)/i
, base64_ranks
, decode_base64 = function(base64) {
var
len = base64.length
, buffer = new Uint8Array(len / 4 * 3 | 0)
, i = 0
, outptr = 0
, last = [0, 0]
, state = 0
, save = 0
, rank
, code
, undef
;
while (len--) {
code = base64.charCodeAt(i++);
rank = base64_ranks[code-43];
if (rank !== 255 && rank !== undef) {
last[1] = last[0];
last[0] = code;
save = (save << 6) | rank;
state++;
if (state === 4) {
buffer[outptr++] = save >>> 16;
if (last[1] !== 61 /* padding character */) {
buffer[outptr++] = save >>> 8;
}
if (last[0] !== 61 /* padding character */) {
buffer[outptr++] = save;
}
state = 0;
}
}
}
// 2/3 chance there's going to be some null bytes at the end, but that
// doesn't really matter with most image formats.
// If it somehow matters for you, truncate the buffer up outptr.
return buffer.buffer;
}
;
if (Uint8Array) {
base64_ranks = new Uint8Array([
62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1
, -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35
, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
]);
}
if (HTMLCanvasElement && !HTMLCanvasElement.prototype.toBlob) {
HTMLCanvasElement.prototype.toBlob = function(callback, type /*, ...args*/) {
if (!type) {
type = "image/png";
} if (this.mozGetAsFile) {
callback(this.mozGetAsFile("canvas", type));
return;
}
var
args = Array.prototype.slice.call(arguments, 1)
, dataURI = this.toDataURL.apply(this, args)
, header_end = dataURI.indexOf(",")
, data = dataURI.substring(header_end + 1)
, is_base64 = is_base64_regex.test(dataURI.substring(0, header_end))
, BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder
, bb = new BlobBuilder
, blob
;
if (BlobBuilder.fake) {
// no reason to decode a data: URI that's just going to become a data URI again
blob = bb.getBlob(type);
if (is_base64) {
blob.encoding = "base64";
} else {
blob.encoding = "URI";
}
blob.data = data;
blob.size = data.length;
} else if (Uint8Array) {
if (is_base64) {
bb.append(decode_base64(data));
} else {
bb.append(decodeURIComponent(data));
}
blob = bb.getBlob(type);
}
callback(blob);
};
}
}(self));/**
* @author Shea Frederick - http://www.vinylfox.com
* @class Ext.ux.form.HtmlEditor.MidasCommand
* @extends Ext.util.Observable
* <p>A base plugin for extending to create standard Midas command buttons.</p>
* http://msdn.microsoft.com/en-us/library/ms533049%28v=VS.85%29.aspx
* http://www.mozilla.org/editor/midas-spec.html
*/
Ext.ns('Ext.ux.form.HtmlEditor');
if (!Ext.isObject) {
Ext.isObject = function(v){
return v && typeof v == "object";
};
}
Ext.override(Ext.form.HtmlEditor, {
getSelectedText: function(clip){
var doc = this.getDoc(), selDocFrag;
var txt = '', hasHTML = false, selNodes = [], ret, html = '';
if (this.win.getSelection || doc.getSelection) {
// FF, Chrome, Safari
var sel = this.win.getSelection();
if (!sel) {
sel = doc.getSelection();
}
if (clip) {
selDocFrag = sel.getRangeAt(0).extractContents();
} else {
selDocFrag = this.win.getSelection().getRangeAt(0).cloneContents();
}
Ext.each(selDocFrag.childNodes, function(n){
if (n.nodeType !== 3) {
hasHTML = true;
}
});
if (hasHTML) {
var div = document.createElement('div');
div.appendChild(selDocFrag);
html = div.innerHTML;
txt = this.win.getSelection() + '';
} else {
html = txt = selDocFrag.textContent;
}
ret = {
textContent: txt,
hasHTML: hasHTML,
html: html
};
} else if (doc.selection) {
// IE
this.win.focus();
txt = doc.selection.createRange();
if (txt.text !== txt.htmlText) {
hasHTML = true;
}
ret = {
textContent: txt.text,
hasHTML: hasHTML,
html: txt.htmlText
};
} else {
return {
textContent: ''
};
}
return ret;
}
});
Ext.ux.form.HtmlEditor.MidasCommand = Ext.extend(Ext.util.Observable, {
// private
init: function(cmp){
this.cmp = cmp;
this.btns = [];
this.cmp.on('render', this.onRender, this);
this.cmp.on('initialize', this.onInit, this, {
delay: 100,
single: true
});
},
// private
onInit: function(){
Ext.EventManager.on(this.cmp.getDoc(), {
'mousedown': this.onEditorEvent,
'dblclick': this.onEditorEvent,
'click': this.onEditorEvent,
'keyup': this.onEditorEvent,
buffer: 100,
scope: this
});
},
// private
onRender: function(){
var midasCmdButton, tb = this.cmp.getToolbar(), btn, iconCls;
Ext.each(this.midasBtns, function(b){
if (Ext.isObject(b)) {
iconCls = (b.iconCls) ? b.iconCls : 'x-edit-' + b.cmd;
if (b.value) { iconCls = iconCls+'-'+b.value.replace(/[<>\/]/g,''); }
midasCmdButton = {
iconCls: iconCls,
handler: function(){
this.cmp.relayCmd(b.cmd, b.value);
},
scope: this,
tooltip: b.tooltip ||
{
title: b.title
},
overflowText: b.overflowText || b.title
};
} else {
midasCmdButton = new Ext.Toolbar.Separator();
}
btn = tb.addButton(midasCmdButton);
if (b.enableOnSelection) {
btn.disable();
}
this.btns.push(btn);
}, this);
},
// private
onEditorEvent: function(){
var doc = this.cmp.getDoc();
Ext.each(this.btns, function(b, i){
if (this.midasBtns[i].enableOnSelection || this.midasBtns[i].disableOnSelection) {
if (doc.getSelection) {
if ((this.midasBtns[i].enableOnSelection && doc.getSelection() !== '') || (this.midasBtns[i].disableOnSelection && doc.getSelection() === '')) {
b.enable();
} else {
b.disable();
}
} else if (doc.selection) {
if ((this.midasBtns[i].enableOnSelection && doc.selection.createRange().text !== '') || (this.midasBtns[i].disableOnSelection && doc.selection.createRange().text === '')) {
b.enable();
} else {
b.disable();
}
}
}
if (this.midasBtns[i].monitorCmdState) {
b.toggle(doc.queryCommandState(this.midasBtns[i].cmd));
}
}, this);
}
});
/**
* @author Shea Frederick - http://www.vinylfox.com
* @class Ext.ux.form.HtmlEditor.Divider
* @extends Ext.util.Observable
* <p>A plugin that creates a divider on the HtmlEditor. Used for separating additional buttons.</p>
*/
Ext.ux.form.HtmlEditor.Divider = Ext.extend(Ext.util.Observable, {
// private
init: function(cmp){
this.cmp = cmp;
this.cmp.on('render', this.onRender, this);
},
// private
onRender: function(){
this.cmp.getToolbar().addButton([new Ext.Toolbar.Separator()]);
}
});
/**
* @author Shea Frederick - http://www.vinylfox.com
* @class Ext.ux.form.HtmlEditor.HR
* @extends Ext.util.Observable
* <p>A plugin that creates a button on the HtmlEditor for inserting a horizontal rule.</p>
*/
Ext.ux.form.HtmlEditor.HR = Ext.extend(Ext.util.Observable, {
// HR language text
langTitle : 'Horizontal Rule',
langHelp : 'Enter the width of the Rule in percentage<br/> followed by the % sign at the end, or to<br/> set a fixed width ommit the % symbol.',
langInsert : 'Insert',
langCancel : 'Cancel',
langWidth : 'Width',
// defaults
defaultHRWidth: '100%',
// private
cmd: 'hr',
// private
init: function(cmp){
this.cmp = cmp;
this.cmp.on('render', this.onRender, this);
},
// private
onRender: function(){
var cmp = this.cmp;
var btn = this.cmp.getToolbar().addButton({
iconCls: 'x-edit-hr',
handler: function(){
if (!this.hrWindow) {
this.hrWindow = new Ext.Window({
title: this.langTitle,
width: 240,
closeAction: 'hide',
items: [{
itemId: 'insert-hr',
xtype: 'form',
border: false,
plain: true,
bodyStyle: 'padding: 10px;',
labelWidth: 60,
labelAlign: 'right',
items: [{
xtype: 'label',
html: this.langHelp + '<br/> '
}, {
xtype: 'textfield',
maskRe: /[0-9]|%/,
regex: /^[1-9][0-9%]{1,3}/,
fieldLabel: this.langWidth,
name: 'hrwidth',
width: 60,
value: this.defaultHRWidth,
listeners: {
specialkey: function(f, e){
if ((e.getKey() == e.ENTER || e.getKey() == e.RETURN) && f.isValid()) {
this.doInsertHR();
}
},
scope: this
}
}]
}],
buttons: [{
text: this.langInsert,
handler: function(){
var frm = this.hrWindow.getComponent('insert-hr').getForm();
if (frm.isValid()) {
this.doInsertHR();
} else {
frm.findField('hrwidth').getEl().frame();
}
},
scope: this
}, {
text: this.langCancel,
handler: function(){
this.hrWindow.hide();
},
scope: this
}],
listeners: {
render: (Ext.isGecko) ? this.focusHRLong : this.focusHR,
show: this.focusHR,
move: this.focusHR,
scope: this
}
});
} else {
this.hrWindow.getEl().frame();
}
this.hrWindow.show();
},
scope: this,
tooltip: {
title: this.langInsert + ' ' + this.langTitle
},
overflowText: this.langTitle
});
},
// private
focusHRLong: function(w){
this.focus(w, 600);
},
// private
focusHR: function(w){
this.focus(w, 100);
},
/**
* This method is just for focusing the text field use for entering the width of the HR.
* It's extra messy because Firefox seems to take a while longer to render the window than other browsers,
* particularly when Firbug is enabled, which is all the time if your like me.
* Had to crank up the delay for focusing on render to 600ms for Firefox, and 100ms for all other focusing.
* Other browsers seem to work fine in all cases with as little as 50ms delay. Compromise bleh!
* @param {Object} win the window to focus
* @param {Integer} delay the delay in milliseconds before focusing
*/
focus: function(win, delay){
win.getComponent('insert-hr').getForm().findField('hrwidth').focus(true, delay);
},
// private
doInsertHR: function(){
var frm = this.hrWindow.getComponent('insert-hr').getForm();
if (frm.isValid()) {
var hrwidth = frm.findField('hrwidth').getValue();
if (hrwidth) {
this.insertHR(hrwidth);
} else {
this.insertHR(this.defaultHRWidth);
}
frm.reset();
this.hrWindow.hide();
}
},
/**
* Insert a horizontal rule into the document.
* @param w String The width of the horizontal rule as the <tt>width</tt> attribute of the HR tag expects. ie: '100%' or '400' (pixels).
*/
insertHR: function(w){
this.cmp.insertAtCursor('<hr width="' + w + '">');
}
});
/**
* @author Shea Frederick - http://www.vinylfox.com
* @class Ext.ux.form.HtmlEditor.Image
* @extends Ext.util.Observable
* <p>A plugin that creates an image button in the HtmlEditor toolbar for inserting an image. The method to select an image must be defined by overriding the selectImage method. Supports resizing of the image after insertion.</p>
* <p>The selectImage implementation must call insertImage after the user has selected an image, passing it a simple image object like the one below.</p>
* <pre>
* var img = {
* Width: 100,
* Height: 100,
* ID: 123,
* Title: 'My Image'
* };
* </pre>
*/
Ext.ux.form.HtmlEditor.Image = Ext.extend(Ext.util.Observable, {
// Image language text
langTitle: 'Insert Image',
urlSizeVars: ['width','height'],
basePath: 'image.php',
init: function(cmp){
this.cmp = cmp;
this.cmp.on('render', this.onRender, this);
this.cmp.on('initialize', this.onInit, this, {single: true});
},
onEditorMouseUp : function(e){
Ext.get(e.getTarget()).select('img').each(function(el){
var w = el.getAttribute('width'), h = el.getAttribute('height'), src = el.getAttribute('src')+' ';
src = src.replace(new RegExp(this.urlSizeVars[0]+'=[0-9]{1,5}([&| ])'), this.urlSizeVars[0]+'='+w+'$1');
src = src.replace(new RegExp(this.urlSizeVars[1]+'=[0-9]{1,5}([&| ])'), this.urlSizeVars[1]+'='+h+'$1');
el.set({src:src.replace(/\s+$/,"")});
}, this);
},
onInit: function(){
Ext.EventManager.on(this.cmp.getDoc(), {
'abort': this.onEditorMouseUp,
scope: this
});
},
onRender: function() {
var btn = this.cmp.getToolbar().addButton({
iconCls: 'x-edit-image',
scope: this,
handler: this.selectImage,
tooltip: {
title: this.langTitle
},
overflowText: this.langTitle
});
},
selectImage: function (){
function validate(data, config) {
config.fieldUrl.setValue(data.url);
}
var chooser = new ImageExplorer({
directoryImageUrl : this.cmp.directoryImageUrl,
width : 500,
height : 350,
htmlEditor : this.cmp
});
chooser.show(document);
},
insertImage: function(img) {
this.cmp.insertAtCursor('<img src="'+this.basePath+'?'+this.urlSizeVars[0]+'='+img.Width+'&'+this.urlSizeVars[1]+'='+img.Height+'&id='+img.ID+'" title="'+img.Name+'" alt="'+img.Name+'">');
}
});
Image.insertImage = function(data, config) {
var htmlEditor = config.htmlEditor;
var url = data.url;
var indexDatastorageUrl = url.indexOf(config.directoryImageUrl);
if (indexDatastorageUrl !== -1) {
url = "./images" + url.substr(indexDatastorageUrl + config.directoryImageUrl.length, url.length);
}
if (data.width && data.height){
htmlEditor.insertAtCursor('<img src="'+ url +'" title="'+ data.text +'" width="'+ data.width +'" height="'+ data.height +'" alt="'+ data.text +'">');
}
else {
htmlEditor.insertAtCursor('<img src="'+ url +'" title="'+ data.text +'" alt="'+ data.text +'">');
}
};
/**
* @author Shea Frederick - http://www.vinylfox.com
* @class Ext.ux.form.HtmlEditor.RemoveFormat
* @extends Ext.ux.form.HtmlEditor.MidasCommand
* <p>A plugin that creates a button on the HtmlEditor that will remove all formatting on selected text.</p>
*/
Ext.ux.form.HtmlEditor.RemoveFormat = Ext.extend(Ext.ux.form.HtmlEditor.MidasCommand, {
midasBtns: ['|', {
enableOnSelection: true,
cmd: 'removeFormat',
tooltip: {
title: 'Remove Formatting'
},
overflowText: 'Remove Formatting'
}]
});
/**
* @author Shea Frederick - http://www.vinylfox.com
* @class Ext.ux.form.HtmlEditor.IndentOutdent
* @extends Ext.ux.form.HtmlEditor.MidasCommand
* <p>A plugin that creates two buttons on the HtmlEditor for indenting and outdenting of selected text.</p>
*/
Ext.ux.form.HtmlEditor.IndentOutdent = Ext.extend(Ext.ux.form.HtmlEditor.MidasCommand, {
// private
midasBtns: ['|', {
cmd: 'indent',
tooltip: {
title: 'Indent Text'
},
overflowText: 'Indent Text'
}, {
cmd: 'outdent',
tooltip: {
title: 'Outdent Text'
},
overflowText: 'Outdent Text'
}]
});
/**
* @author Shea Frederick - http://www.vinylfox.com
* @class Ext.ux.form.HtmlEditor.SubSuperScript
* @extends Ext.ux.form.HtmlEditor.MidasCommand
* <p>A plugin that creates two buttons on the HtmlEditor for superscript and subscripting of selected text.</p>
*/
Ext.ux.form.HtmlEditor.SubSuperScript = Ext.extend(Ext.ux.form.HtmlEditor.MidasCommand, {
// private
midasBtns: ['|', {
enableOnSelection: true,
cmd: 'subscript',
tooltip: {
title: 'Subscript'
},
overflowText: 'Subscript'
}, {
enableOnSelection: true,
cmd: 'superscript',
tooltip: {
title: 'Superscript'
},
overflowText: 'Superscript'
}]
});
/**
* @author Shea Frederick - http://www.vinylfox.com
* @class Ext.ux.form.HtmlEditor.RemoveFormat
* @extends Ext.ux.form.HtmlEditor.MidasCommand
* <p>A plugin that creates a button on the HtmlEditor that will remove all formatting on selected text.</p>
*/
Ext.ux.form.HtmlEditor.RemoveFormat = Ext.extend(Ext.ux.form.HtmlEditor.MidasCommand, {
midasBtns: ['|', {
enableOnSelection: true,
cmd: 'removeFormat',
tooltip: {
title: 'Remove Formatting'
},
overflowText: 'Remove Formatting'
}]
});
/**
* @author Shea Frederick - http://www.vinylfox.com
* @contributor Ronald van Raaphorst - Twensoc
* @class Ext.ux.form.HtmlEditor.FindReplace
* @extends Ext.util.Observable
* <p>A plugin that provides search and replace functionality in source edit mode. Incomplete.</p>
*/
Ext.ux.form.HtmlEditor.FindAndReplace = Ext.extend(Ext.util.Observable, {
// Find and Replace language text
langTitle: 'Find/Replace',
langFind: 'Find',
langReplace: 'Replace',
langReplaceWith: 'Replace with',
langClose: 'Close',
// private
cmd: 'findandreplace',
// private
init: function(cmp){
this.cmp = cmp;
this.cmp.on({
'render': this.onRender,
'editmodechange': this.editModeChange,
scope: this
});
this.lastSelectionStart=-1;
},
editModeChange: function(t, m){
if (this.btn && m){
this.btn.setDisabled(false);
}
},
// private
onRender: function(){
this.btn = this.cmp.getToolbar().addButton({
iconCls: 'x-edit-findandreplace',
sourceEditEnabled:true,
handler: function(){
if (!this.farWindow){
this.farWindow = new Ext.Window({
title: this.langTitle,
closeAction: 'hide',
width: 270,
items: [{
itemId: 'findandreplace',
xtype: 'form',
border: false,
plain: true,
bodyStyle: 'padding: 10px;',
labelWidth: 80,
labelAlign: 'right',
items: [{
xtype: 'textfield',
allowBlank: false,
fieldLabel: this.langFind,
name: 'find',
width: 145
}, {
xtype: 'textfield',
allowBlank: true,
fieldLabel: this.langReplaceWith,
name: 'replace',
width: 145
}]
}],
buttons: [{
text: this.langFind,
handler: this.doFind,
scope: this
}, {
text: this.langReplace,
handler: this.doReplace,
scope: this
}, {
text: this.langClose,
handler: function(){
this.farWindow.hide();
},
scope: this
}]
});
}else{
this.farWindow.getEl().frame();
}
this.farWindow.show();
},
scope: this,
tooltip: {
title: this.langTitle
},
overflowText: this.langTitle
});
},
doFind: function(){
var frm = this.farWindow.getComponent('findandreplace').getForm();
if (!frm.isValid()) {
return '';
}
var findValue = frm.findField('find').getValue();
var replaceValue = frm.findField('replace').getValue();
if(this.cmp.sourceEditMode) {
// source edit mode
var textarea = this.cmp.el.dom;
var startPos = textarea.selectionStart===this.lastSelectionStart ? textarea.selectionStart+1 : textarea.selectionStart;
var txt = textarea.value.substring(startPos);
var regexp = new RegExp(findValue);
var r = txt.search(regexp);
if(r==-1) {
return;
}
this.lastSelectionStart = startPos + r;
if(Ext.isGecko) {
textarea.setSelectionRange(this.lastSelectionStart , this.lastSelectionStart + findValue.length);
this.cmp.scrollIntoView(startPos);
this.cmp.focus(false, true);
}
return;
}
// design mode
//var doc = this.cmp.getEditorBody();
//var txt = doc.innerHTML;
// Should we search/replace in the source, and push the result back to the design?
},
doReplace: function(){
var frm = this.farWindow.getComponent('findandreplace').getForm();
if (!frm.isValid()) {
return '';
}
var findValue = frm.findField('find').getValue();
var replaceValue = frm.findField('replace').getValue();
if(this.cmp.sourceEditMode) {
var textarea = this.cmp.el.dom;
var startPos = textarea.selectionStart;
var endPos = textarea.selectionEnd;
if (startPos == 0 && endPos == 0){
Ext.Msg.alert("Warning", "No text selection, please select some text");
return;
}
var txt = textarea.value;
//cmp.execCmd('delete', null);
//cmp.focus(false, false);
//cmp.insertAtCursor(replaceValue);
//if(Ext.isGecko) {
// TODO: Scroll into view
var scrollPosition = textarea.scrollTop;
textarea.value = txt.substring(0,startPos) + replaceValue + txt.substring(endPos);
textarea.setSelectionRange(startPos,startPos + replaceValue.length);
textarea.scrollTop = scrollPosition;
this.cmp.focus(false, true);
//}
return;
}
else{
Ext.Msg.alert("Warning", "Not in Source Edit mode");
}
return;
}
});/**
* @author Shea Frederick - http://www.vinylfox.com
* @class Ext.ux.form.HtmlEditor.Table
* @extends Ext.util.Observable
* <p>A plugin that creates a button on the HtmlEditor for making simple tables.</p>
*/
Ext.ux.form.HtmlEditor.Table = Ext.extend(Ext.util.Observable, {
// Table language text
langTitle : 'Insert Table',
langInsert : 'Insert',
langCancel : 'Cancel',
langRows : 'Rows',
langColumns : 'Columns',
langBorder : 'Border',
langCellLabel : 'Label Cells',
// private
cmd: 'table',
/**
* @cfg {Boolean} showCellLocationText
* Set true to display row and column informational text inside of newly created table cells.
*/
showCellLocationText: true,
/**
* @cfg {String} cellLocationText
* The string to display inside of newly created table cells.
*/
cellLocationText: '{0} - {1}',
/**
* @cfg {Array} tableBorderOptions
* A nested array of value/display options to present to the user for table border style. Defaults to a simple list of 5 varrying border types.
*/
tableBorderOptions: [['none', 'None'], ['1px solid #000', 'Sold Thin'], ['2px solid #000', 'Solid Thick'], ['1px dashed #000', 'Dashed'], ['1px dotted #000', 'Dotted']],
// private
init: function(cmp){
this.cmp = cmp;
this.cmp.on('render', this.onRender, this);
},
// private
onRender: function(){
var btn = this.cmp.getToolbar().addButton({
iconCls: 'x-edit-table',
handler: function(){
if (!this.tableWindow){
this.tableWindow = new Ext.Window({
title: this.langTitle,
closeAction: 'hide',
width: 235,
items: [{
itemId: 'insert-table',
xtype: 'form',
border: false,
plain: true,
bodyStyle: 'padding: 10px;',
labelWidth: 65,
labelAlign: 'right',
items: [{
xtype: 'numberfield',
allowBlank: false,
allowDecimals: false,
fieldLabel: this.langRows,
name: 'row',
width: 60
}, {
xtype: 'numberfield',
allowBlank: false,
allowDecimals: false,
fieldLabel: this.langColumns,
name: 'col',
width: 60
}, {
xtype: 'combo',
fieldLabel: this.langBorder,
name: 'border',
forceSelection: true,
mode: 'local',
store: new Ext.data.ArrayStore({
autoDestroy: true,
fields: ['spec', 'val'],
data: this.tableBorderOptions
}),
triggerAction: 'all',
value: 'none',
displayField: 'val',
valueField: 'spec',
anchor: '-15'
}, {
xtype: 'checkbox',
fieldLabel: this.langCellLabel,
checked: this.showCellLocationText,
listeners: {
check: function(){
this.showCellLocationText = !this.showCellLocationText;
},
scope: this
}
}]
}],
buttons: [{
text: this.langInsert,
handler: function(){
var frm = this.tableWindow.getComponent('insert-table').getForm();
if (frm.isValid()) {
var border = frm.findField('border').getValue();
var rowcol = [frm.findField('row').getValue(), frm.findField('col').getValue()];
if (rowcol.length == 2 && rowcol[0] > 0 && rowcol[1] > 0) {
var colwidth = Math.floor(100/rowcol[0]);
var html = "<table style='border-collapse: collapse'>";
var cellText = ' ';
if (this.showCellLocationText){ cellText = this.cellLocationText; }
for (var row = 0; row < rowcol[0]; row++) {
html += "<tr>";
for (var col = 0; col < rowcol[1]; col++) {
html += "<td width='" + colwidth + "%' style='border: " + border + ";'>" + String.format(cellText, (row+1), String.fromCharCode(col+65)) + "</td>";
}
html += "</tr>";
}
html += "</table>";
this.cmp.insertAtCursor(html);
}
this.tableWindow.hide();
}else{
if (!frm.findField('row').isValid()){
frm.findField('row').getEl().frame();
}else if (!frm.findField('col').isValid()){
frm.findField('col').getEl().frame();
}
}
},
scope: this
}, {
text: this.langCancel,
handler: function(){
this.tableWindow.hide();
},
scope: this
}]
});
}else{
this.tableWindow.getEl().frame();
}
this.tableWindow.show();
},
scope: this,
tooltip: {
title: this.langTitle
},
overflowText: this.langTitle
});
}
});
/**
* @author Shea Frederick - http://www.vinylfox.com
* @class Ext.ux.form.HtmlEditor.Word
* @extends Ext.util.Observable
* <p>A plugin that creates a button on the HtmlEditor for pasting text from Word without all the jibberish html.</p>
*/
Ext.ux.form.HtmlEditor.Word = Ext.extend(Ext.util.Observable, {
// Word language text
langTitle: 'Word Paste',
langToolTip: 'Cleanse text pasted from Word or other Rich Text applications',
wordPasteEnabled: true,
// private
curLength: 0,
lastLength: 0,
lastValue: '',
// private
init: function(cmp){
this.cmp = cmp;
this.cmp.on('render', this.onRender, this);
this.cmp.on('initialize', this.onInit, this, {delay:100, single: true});
},
// private
onInit: function(){
Ext.EventManager.on(this.cmp.getDoc(), {
'keyup': this.checkIfPaste,
scope: this
});
this.lastValue = this.cmp.getValue();
this.curLength = this.lastValue.length;
this.lastLength = this.lastValue.length;
},
// private
checkIfPaste: function(e){
var diffAt = 0;
this.curLength = this.cmp.getValue().length;
if (e.V == e.getKey() && e.ctrlKey && this.wordPasteEnabled){
this.cmp.suspendEvents();
diffAt = this.findValueDiffAt(this.cmp.getValue());
var parts = [
this.cmp.getValue().substr(0, diffAt),
this.fixWordPaste(this.cmp.getValue().substr(diffAt, (this.curLength - this.lastLength))),
this.cmp.getValue().substr((this.curLength - this.lastLength)+diffAt, this.curLength)
];
this.cmp.setValue(parts.join(''));
this.cmp.resumeEvents();
}
this.lastLength = this.cmp.getValue().length;
this.lastValue = this.cmp.getValue();
},
// private
findValueDiffAt: function(val){
for (i=0;i<this.curLength;i++){
if (this.lastValue[i] != val[i]){
return i;
}
}
},
/**
* Cleans up the jubberish html from Word pasted text.
* @param wordPaste String The text that needs to be cleansed of Word jibberish html.
* @return {String} The passed in text with all Word jibberish html removed.
*/
fixWordPaste: function(wordPaste) {
var removals = [/ /ig, /[\r\n]/g, /<(xml|style)[^>]*>.*?<\/\1>/ig, /<\/?(meta|object|span)[^>]*>/ig,
/<\/?[A-Z0-9]*:[A-Z]*[^>]*>/ig, /(lang|class|type|href|name|title|id|clear)=\"[^\"]*\"/ig, /style=(\'\'|\"\")/ig, /<![\[-].*?-*>/g,
/MsoNormal/g, /<\\?\?xml[^>]*>/g, /<\/?o:p[^>]*>/g, /<\/?v:[^>]*>/g, /<\/?o:[^>]*>/g, /<\/?st1:[^>]*>/g, / /g,
/<\/?SPAN[^>]*>/g, /<\/?FONT[^>]*>/g, /<\/?STRONG[^>]*>/g, /<\/?H1[^>]*>/g, /<\/?H2[^>]*>/g, /<\/?H3[^>]*>/g, /<\/?H4[^>]*>/g,
/<\/?H5[^>]*>/g, /<\/?H6[^>]*>/g, /<\/?P[^>]*><\/P>/g, /<!--(.*)-->/g, /<!--(.*)>/g, /<!(.*)-->/g, /<\\?\?xml[^>]*>/g,
/<\/?o:p[^>]*>/g, /<\/?v:[^>]*>/g, /<\/?o:[^>]*>/g, /<\/?st1:[^>]*>/g, /style=\"[^\"]*\"/g, /style=\'[^\"]*\'/g, /lang=\"[^\"]*\"/g,
/lang=\'[^\"]*\'/g, /class=\"[^\"]*\"/g, /class=\'[^\"]*\'/g, /type=\"[^\"]*\"/g, /type=\'[^\"]*\'/g, /href=\'#[^\"]*\'/g,
/href=\"#[^\"]*\"/g, /name=\"[^\"]*\"/g, /name=\'[^\"]*\'/g, / clear=\"all\"/g, /id=\"[^\"]*\"/g, /title=\"[^\"]*\"/g,
/<span[^>]*>/g, /<\/?span[^>]*>/g, /<title>(.*)<\/title>/g, /class=/g, /<meta[^>]*>/g, /<link[^>]*>/g, /<style>(.*)<\/style>/g,
/<w:[^>]*>(.*)<\/w:[^>]*>/g];
Ext.each(removals, function(s){
wordPaste = wordPaste.replace(s, "");
});
// keep the divs in paragraphs
wordPaste = wordPaste.replace(/<div[^>]*>/g, "<p>");
wordPaste = wordPaste.replace(/<\/?div[^>]*>/g, "</p>");
return wordPaste;
},
// private
onRender: function() {
this.cmp.getToolbar().add({
iconCls: 'x-edit-wordpaste',
pressed: true,
handler: function(t){
t.toggle(!t.pressed);
this.wordPasteEnabled = !this.wordPasteEnabled;
},
scope: this,
tooltip: {
text: this.langToolTip
},
overflowText: this.langTitle
});
}
});/**
* @author Shea Frederick - http://www.vinylfox.com
* @class Ext.ux.form.HtmlEditor.Link
* @extends Ext.util.Observable
* <p>A plugin that creates a button on the HtmlEditor for inserting a link.</p>
*/
Ext.ux.form.HtmlEditor.Link = Ext.extend(Ext.util.Observable, {
// Link language text
langTitle : 'Insert Link',
langInsert : 'Insert',
langCancel : 'Cancel',
langTarget : 'Target',
langURL : 'URL',
langText : 'Text',
// private
linkTargetOptions: [['_self', 'Default'], ['_blank', 'New Window'], ['_parent', 'Parent Window'], ['_top', 'Entire Window']],
init: function(cmp){
cmp.enableLinks = false;
this.cmp = cmp;
this.cmp.on('render', this.onRender, this);
},
onRender: function(){
var cmp = this.cmp;
var btn = this.cmp.getToolbar().addButton({
iconCls: 'x-edit-createlink',
handler: function(){
var sel = this.cmp.getSelectedText();
if (!this.linkWindow) {
this.linkWindow = new Ext.Window({
title: this.langTitle,
closeAction: 'hide',
width: 250,
height: 160,
items: [{
xtype: 'form',
itemId: 'insert-link',
border: false,
plain: true,
bodyStyle: 'padding: 10px;',
labelWidth: 40,
labelAlign: 'right',
items: [{
xtype: 'textfield',
fieldLabel: this.langText,
name: 'text',
anchor: '100%',
value: ''
}, {
xtype: 'textfield',
fieldLabel: this.langURL,
vtype: 'url',
name: 'url',
anchor: '100%',
value: 'http://'
}, {
xtype: 'combo',
fieldLabel: this.langTarget,
name: 'target',
forceSelection: true,
mode: 'local',
store: new Ext.data.ArrayStore({
autoDestroy: true,
fields: ['spec', 'val'],
data: this.linkTargetOptions
}),
triggerAction: 'all',
value: '_self',
displayField: 'val',
valueField: 'spec',
anchor: '100%'
}]
}],
buttons: [{
text: this.langInsert,
handler: function(){
var frm = this.linkWindow.getComponent('insert-link').getForm();
if (frm.isValid()) {
var afterSpace = '', sel = this.cmp.getSelectedText(true), text = frm.findField('text').getValue(), url = frm.findField('url').getValue(), target = frm.findField('target').getValue();
if (text.length && text[text.length - 1] == ' ') {
text = text.substr(0, text.length - 1);
afterSpace = ' ';
}
if (sel.hasHTML) {
text = sel.html;
}
var html = '<a href="' + url + '" target="' + target + '">' + text + '</a>' + afterSpace;
this.cmp.insertAtCursor(html);
this.linkWindow.hide();
} else {
if (!frm.findField('url').isValid()) {
frm.findField('url').getEl().frame();
} else if (!frm.findField('target').isValid()) {
frm.findField('target').getEl().frame();
}
}
},
scope: this
}, {
text: this.langCancel,
handler: function(){
this.linkWindow.close();
},
scope: this
}],
listeners: {
show: {
fn: function(){
var frm = this.linkWindow.getComponent('insert-link').getForm();
frm.findField('text').setValue(sel.textContent).setDisabled(sel.hasHTML);
frm.findField('url').reset().focus(true, 50);
},
scope: this,
defer: 350
}
}
});
this.linkWindow.show();
} else {
this.linkWindow.show();
this.linkWindow.getEl().frame();
}
},
scope: this,
tooltip: this.langTitle
});
}
});
/**
* @author Shea Frederick - http://www.vinylfox.com
* @class Ext.ux.form.HtmlEditor.SpecialCharacters
* @extends Ext.util.Observable
* <p>A plugin that creates a button on the HtmlEditor for inserting special characters.</p>
*/
Ext.ux.form.HtmlEditor.SpecialCharacters = Ext.extend(Ext.util.Observable, {
// SpecialCharacters language text
langTitle : 'Insert Special Character',
langInsert : 'Insert',
langCancel : 'Cancel',
/**
* @cfg {Array} specialChars
* An array of additional characters to display for user selection. Uses numeric portion of the ASCII HTML Character Code only. For example, to use the Copyright symbol, which is © we would just specify <tt>169</tt> (ie: <tt>specialChars:[169]</tt>).
*/
specialChars: [153],
/**
* @cfg {Array} charRange
* Two numbers specifying a range of ASCII HTML Characters to display for user selection. Defaults to <tt>[160, 256]</tt>.
*/
charRange: [160, 256],
// private
chars: [],
// private
init: function(cmp){
this.cmp = cmp;
this.cmp.on('render', this.onRender, this);
},
// private
onRender: function(){
var cmp = this.cmp;
var btn = this.cmp.getToolbar().addButton({
iconCls: 'x-edit-char',
handler: function(){
if (!this.chars.length) {
if (this.specialChars.length) {
Ext.each(this.specialChars, function(c, i){
this.chars[i] = ['&#' + c + ';'];
}, this);
}
for (i = this.charRange[0]; i < this.charRange[1]; i++) {
this.chars.push(['&#' + i + ';']);
}
}
var charStore = new Ext.data.ArrayStore({
fields: ['char'],
data: this.chars
});
this.charWindow = new Ext.Window({
title: this.langTitle,
width: 436,
autoHeight: true,
layout: 'fit',
items: [{
xtype: 'dataview',
store: charStore,
ref: 'charView',
autoHeight: true,
multiSelect: true,
tpl: new Ext.XTemplate('<tpl for="."><div class="char-item">{char}</div></tpl><div class="x-clear"></div>'),
overClass: 'char-over',
itemSelector: 'div.char-item',
listeners: {
dblclick: function(t, i, n, e){
this.insertChar(t.getStore().getAt(i).get('char'));
this.charWindow.close();
},
scope: this
}
}],
buttons: [{
text: this.langInsert,
handler: function(){
Ext.each(this.charWindow.charView.getSelectedRecords(), function(rec){
var c = rec.get('char');
this.insertChar(c);
}, this);
this.charWindow.close();
},
scope: this
}, {
text: this.langCancel,
handler: function(){
this.charWindow.close();
},
scope: this
}]
});
this.charWindow.show();
},
scope: this,
tooltip: {
title: this.langTitle
},
overflowText: this.langTitle
});
},
/**
* Insert a single special character into the document.
* @param c String The special character to insert (not just the numeric code, but the entire ASCII HTML entity).
*/
insertChar: function(c){
if (c) {
this.cmp.insertAtCursor(c);
}
}
});
/**
* @author Shea Frederick - http://www.vinylfox.com
* @contributor vizcano - http://www.extjs.com/forum/member.php?u=23512
* @class Ext.ux.form.HtmlEditor.UndoRedo
* @extends Ext.ux.form.HtmlEditor.MidasCommand
* <p>A plugin that creates undo and redo buttons on the HtmlEditor. Incomplete.</p>
*/
Ext.ux.form.HtmlEditor.UndoRedo = Ext.extend(Ext.ux.form.HtmlEditor.MidasCommand, {
// private
midasBtns: ['|', {
cmd: 'undo',
tooltip: {
title: 'Undo'
},
overflowText: 'Undo'
}, {
cmd: 'redo',
tooltip: {
title: 'Redo'
},
overflowText: 'Redo'
}]
});
/**
* @author Shea Frederick - http://www.vinylfox.com
* @contributor Somani - http://www.sencha.com/forum/member.php?51567-Somani
* @class Ext.ux.form.HtmlEditor.HeadingButtons
* @extends Ext.ux.form.HtmlEditor.MidasCommand
* <p>A plugin that creates a button on the HtmlEditor that will have H1 and H2 options. This is used when you want to restrict users to just a few heading types.</p>
* NOTE: while 'heading' should be the command used, it is not supported in IE, so 'formatblock' is used instead. Thank you IE.
*/
Ext.ux.form.HtmlEditor.HeadingButtons = Ext.extend(Ext.ux.form.HtmlEditor.MidasCommand, {
// private
midasBtns: ['|', {
enableOnSelection: true,
cmd: 'formatblock',
value: '<h1>',
tooltip: {
title: '1st Heading'
},
overflowText: '1st Heading'
}, {
enableOnSelection: true,
cmd: 'formatblock',
value: '<h2>',
tooltip: {
title: '2nd Heading'
},
overflowText: '2nd Heading'
}]
});
* @author Shea Frederick - http://www.vinylfox.com
* @class Ext.ux.form.HtmlEditor.HeadingMenu
* @extends Ext.util.Observable
* <p>A plugin that creates a menu on the HtmlEditor for selecting a heading size. Takes up less room than the heading buttons if your going to have all six heading sizes available.</p>
*/
Ext.ux.form.HtmlEditor.HeadingMenu = Ext.extend(Ext.util.Observable, {
init: function(cmp){
this.cmp = cmp;
this.cmp.on('render', this.onRender, this);
},
// private
onRender: function(){
var cmp = this.cmp;
var btn = this.cmp.getToolbar().addItem({
xtype: 'combo',
displayField: 'display',
valueField: 'value',
name: 'headingsize',
forceSelection: true,
mode: 'local',
triggerAction: 'all',
width: 65,
emptyText: 'Heading',
store: {
xtype: 'arraystore',
autoDestroy: true,
fields: ['value','display'],
data: [['H1','1st Heading'],['H2','2nd Heading'],['H3','3rd Heading'],['H4','4th Heading'],['H5','5th Heading'],['H6','6th Heading']]
},
listeners: {
'select': function(combo,rec){
this.relayCmd('formatblock', '<'+rec.get('value')+'>');
combo.reset();
},
scope: cmp
}
});
}
});
/**
* @author Shea Frederick - http://www.vinylfox.com
* @class Ext.ux.form.HtmlEditor.plugins
* <p>A convenience function that returns a standard set of HtmlEditor buttons.</p>
* <p>Sample usage:</p>
* <pre><code>
new Ext.FormPanel({
...
items : [{
...
xtype : "htmleditor",
plugins : Ext.ux.form.HtmlEditor.plugins()
}]
});
* </code></pre>
*/
Ext.ux.form.HtmlEditor.plugins = function(){
return [
// new Ext.ux.form.HtmlEditor.Link(),
// new Ext.ux.form.HtmlEditor.Divider(),
// new Ext.ux.form.HtmlEditor.Word(),
// new Ext.ux.form.HtmlEditor.FindAndReplace(),
new sitools.widget.HtmlEditor.datasetLink(),
new Ext.ux.form.HtmlEditor.UndoRedo(),
new Ext.ux.form.HtmlEditor.Divider(),
new Ext.ux.form.HtmlEditor.Image(),
// new Ext.ux.form.HtmlEditor.Table(),
new Ext.ux.form.HtmlEditor.HR(),
new Ext.ux.form.HtmlEditor.SpecialCharacters(),
new Ext.ux.form.HtmlEditor.HeadingMenu(),
new Ext.ux.form.HtmlEditor.IndentOutdent(),
new Ext.ux.form.HtmlEditor.SubSuperScript(),
new Ext.ux.form.HtmlEditor.RemoveFormat()
];
};/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*
* Ext JS Library 3.3.1
* Copyright(c) 2006-2010 Sencha Inc.
* licensing@sencha.com
* http://www.sencha.com/license
*/
var ImageExplorer = function(config){
this.config = config;
}
ImageExplorer.prototype = {
// cache data by image name for easy lookup
lookup : {},
show : function(el, callback){
if(!this.win){
this.initTemplates();
this.store = new Ext.data.JsonStore({
proxy : new Ext.data.HttpProxy({
method : 'GET',
url: this.config.directoryImageUrl,
headers : {
'Accept' : 'application/json+sitools-directory'
}
}),
idProperty: 'text',
fields: [
{name : 'text', mapping: 'text'},
{name : 'lastmod', mapping : 'lastmod', type:'date', dateFormat:'timestamp'},
{name : 'leaf', mapping : 'leaf'},
{name : 'url', mapping : 'url'},
{name : 'size', mapping : 'size', type: 'float'},
{name : 'cls', mapping : 'cls'}
],
listeners: {
'load': {fn:function(){
this.view.select(0);
}, scope: this, single:true}
}
});
this.store.load();
var formatSize = function(data){
if(data.size < 1024) {
return data.size + " bytes";
} else {
return (Math.round(((data.size*10) / 1024))/10) + " KB";
}
};
var formatData = function(data){
data.shortName = data.text.ellipse(15);
data.sizeString = formatSize(data);
data.dateString = new Date(data.lastmod).format("d/m/Y g:i a");
this.lookup[data.text] = data;
return data;
};
this.view = new Ext.DataView({
tpl: this.thumbTemplate,
id : 'imageChooserDataViewId',
singleSelect: true,
overClass:'x-view-over',
itemSelector: 'div.thumb-wrap',
emptyText : '<div style="padding:10px;">No images match the specified filter</div>',
store: this.store,
listeners: {
'dblclick' : {fn: function (dv, ind, node, e){
this.doCallback(dv, ind, node, e);
}, scope:this},
'loadexception' : {fn:this.onLoadException, scope:this},
'beforeselect' : {fn:function(view){
return view.store.getRange().length > 0;
}}
},
prepareData: formatData.createDelegate(this)
});
this.menu = new Ext.menu.Menu({
id : 'paramMenu',
items : [{
text: 'Initial Size',
id : 'initialId',
checked: true,
checkHandler: function (){
if (this.checked){
this.parentMenu.find('id', 'customId')[0].setChecked(false);
}
}
}, '-',
{
text: 'Customisable Size',
id : 'customId',
checked: false,
menu : {
items : [{
xtype: 'spinnerfield',
emptyText: 'Custom width...',
name: 'width',
listeners : {
scope : this,
mousedown : function (field, e){
var ed = ed;
}
}
},
{
xtype: 'spinnerfield',
emptyText: 'Custom height...',
name: 'height',
listeners : {
scope : this,
mousedown : function (field, e){
var ed = ed;
}
}
}]
},
checkHandler: function (){
if (this.checked){
this.parentMenu.find('id', 'initialId')[0].setChecked(false);
}
}
}]
});
this.splitButton = new Ext.Toolbar.SplitButton({
id: 'ok-btn',
text: 'OK',
scope : this,
handler: function (){
var node = this.view.getSelectedNodes()[0];
var rec = this.view.getStore().getById(node.id);
if(this.menu.find('id', 'initialId')[0].checked){
this.doCallback2(this.view, rec);
}
else {
var subMenu = this.menu.find('id', 'customId')[0];
var width = subMenu.menu.find('name', 'width')[0].getValue();
var height = subMenu.menu.find('name', 'height')[0].getValue();
this.doCallback2(this.view, rec, width, height);
}
},
menu : this.menu
});
var cfg = {
title: i18n.get('label.chooseImage'),
id: 'img-chooser-dlg',
layout: 'border',
minWidth: 500,
minHeight: 450,
modal: true,
// closeAction: 'hide',
border: false,
tbar : [ '->', {
xtype : 'label',
text : i18n.get('label.uploadFile') + ' :'
},
{
xtype : 'button',
iconAlign : 'right',
iconCls : 'upload-icon',
tooltip : i18n.get('label.uploadFile'),
scope : this,
handler : function () {
var callbackUpload = function (createdNode) {
var rec = new Ext.data.Record(createdNode);
this.add(rec);
this.reload();
}
var uploadWin = new sitools.user.modules.datastorageUploadFile({
urlUpload : this.config.directoryImageUrl + "/",
callback : callbackUpload,
scope : this.store
}).show();
}
}
],
items:[{
id: 'img-chooser-view',
region: 'center',
autoScroll: true,
items: this.view,
tbar:[{
text: i18n.get ('label.filter')
},{
xtype: 'textfield',
id: 'filter',
selectOnFocus: true,
width: 100,
listeners: {
'render': {fn:function(){
Ext.getCmp('filter').getEl().on('keyup', function(){
this.filter();
}, this, {buffer:500});
}, scope:this}
}
}, ' ', '-', {
text: i18n.get ('label.sortBy')
}, {
id: 'sortSelect',
xtype: 'combo',
typeAhead: true,
triggerAction: 'all',
width: 100,
editable: false,
mode: 'local',
displayField: 'desc',
valueField: 'text',
lazyInit: false,
value: 'text',
store: new Ext.data.ArrayStore({
fields: ['text', 'desc'],
data : [['text', 'Name'],['size', 'File Size'],['lastmod', 'Last Modified']]
}),
listeners: {
'select': {fn:this.sortImages, scope:this}
}
}]
}],
buttons: [this.splitButton
,{
text: 'Cancel',
handler: function(){ this.win.close(); },
scope: this
}],
keys: {
key: 27, // Esc key
handler: function(){ this.win.close(); },
scope: this
}
};
Ext.apply(cfg, this.config);
this.win = new Ext.Window(cfg);
}
this.reset();
this.win.show(el);
this.callback = callback;
this.animateTarget = el;
},
initTemplates : function(){
this.thumbTemplate = new Ext.XTemplate(
'<tpl for=".">',
'<tpl if="this.isImage(url)">',
'<div class="thumb-wrap" id="{name}">',
'<div class="thumb"><img src="{url}" height="96" width="96" title="{name}"></div>',
'<span>{shortName}</span></div>',
'</tpl>',
'</tpl>',
{
compiled : true,
isLeaf : function (leaf){
return leaf;
},
isImage : function (text){
var imageRegex = /\.(png|jpg|jpeg|gif|bmp)$/;
if (text.match(imageRegex))
return true;
else{
return false;
}
}
}
);
this.thumbTemplate.compile();
},
filter : function(){
var filter = Ext.getCmp('filter');
this.view.store.filter('text', filter.getValue());
this.view.select(0);
},
sortImages : function(){
var v = Ext.getCmp('sortSelect').getValue();
this.view.store.sort(v, v == 'text' ? 'asc' : 'desc');
this.view.select(0);
},
reset : function(){
if(this.win.rendered){
Ext.getCmp('filter').reset();
this.view.getEl().dom.scrollTop = 0;
}
this.view.store.clearFilter();
this.view.select(0);
},
doCallback : function(dv, ind, node, e){
var rec = dv.getStore().getById(node.id);
//Insert Selected Image in HtmlEditor
Image.insertImage(rec.data, this.config);
this.win.close();
},
doCallback2 : function (dv, rec, width, height){
//Insert Selected Image in HtmlEditor
if (width && height){
rec.data.width = width;
rec.data.height = height;
}
Image.insertImage(rec.data, this.config);
this.win.close();
},
onLoadException : function(v,o){
this.view.getEl().update('<div style="padding:10px;">Error loading images.</div>');
},
isImage : function (text){
var imageRegex = /\.(png|jpg|jpeg|gif|bmp)$/;
if (text.match(imageRegex))
return true;
else{
var ind = this.store.find('text', text);
this.store.remove(this.store.getAt(ind));
return false;
}
}
};
String.prototype.ellipse = function(maxLength){
if(this.length > maxLength){
return this.substr(0, maxLength-3) + '...';
}
return this;
};
/*******************************************************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* SITools2 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* SITools2. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/* global Ext, sitools, i18n, loadUrl */
Ext.namespace('sitools.widget.HtmlEditor');
/**
* datasetLink widget
*
* @class sitools.widget.HtmlEditor.datasetLink
* @extends Ext.util.Observable
*/
sitools.widget.HtmlEditor.datasetLink = Ext.extend(Ext.util.Observable, {
init : function(cmp) {
this.cmp = cmp;
this.cmp.on('render', this.onRender, this);
this.browseField = new Ext.form.TriggerField({
name : 'datasetLink',
fieldLabel : i18n.get('label.selectDatasetLink'),
allowBlank : false,
labelWidth : 100,
editable : false,
emptyText : i18n.get('label.openDatasetBrowser'),
anchor : '100%',
forceSelection: true,
onTriggerClick : function () {
if (!this.disabled) {
var browser = new sitools.widget.HtmlEditor.datasetBrowser({
field : this
});
new Ext.Window({
title : i18n.get('label.selectDatasetLink'),
iconCls : 'x-edit-datasetLink',
layout : 'fit',
height : 300,
width : 300,
autoScroll : true,
items : [browser]
}).show();
}
}
});
var sel;
this.datasetLinkWindow = new Ext.Window({
title : i18n.get('label.insertDatasetLink'),
closeAction : 'hide',
resizable : false,
width : 400,
height : 175,
items : [{
xtype : 'form',
itemId : 'insert-datasetLink',
border : false,
plain : true,
bodyStyle : 'padding: 10px;',
labelWidth : 100,
labelAlign : 'right',
bbar : new Ext.ux.StatusBar({
text : i18n.get('label.ready'),
id : 'sbWinEditProfile',
iconCls : 'x-status-valid',
hidden : true
}),
items : [{
xtype : 'textfield',
allowBlank : false,
fieldLabel : i18n.get('label.text'),
name : 'text',
anchor : '100%',
value : ''
}, this.browseField ]
}],
buttons : [{
text : i18n.get('label.insertDatasetLink'),
handler : function() {
var frm = this.datasetLinkWindow
.getComponent('insert-datasetLink').getForm();
if (frm.isValid()) {
text = frm.findField('text').getValue();
browseField = frm.findField('datasetLink');
var html = String.format(browseField.dataLinkComponent + "{0}</a>", text);
this.cmp.insertAtCursor(html);
this.datasetLinkWindow.close();
} else {
var sb = Ext.getCmp('sbWinEditProfile');
sb.setStatus({
text : i18n.get('warning.checkForm'),
iconCls : 'x-status-error',
hidden : false
});
sb.setVisible(true);
return;
}
},
scope : this
}, {
text : i18n.get('label.cancel'),
handler : function() {
this.datasetLinkWindow.close();
},
scope : this
}]
});
},
onRender : function() {
this.btnToolbar = this.cmp.getToolbar().addButton({
iconCls : 'x-edit-datasetLink',
scope : this,
handler : this.showDatasetLinkWindow,
tooltip : i18n.get('label.insertDatasetLink')
});
},
showDatasetLinkWindow : function () {
if (!this.datasetLinkWindow.isDestroyed) {
this.datasetLinkWindow.show();
}
else {
this.datasetLinkWindow.destroy();
this.init(this.cmp);
this.datasetLinkWindow.show();
}
}
});
Ext.reg('sitools.widget.HtmlEditor.datasetLink',
sitools.widget.HtmlEditor.datasetLink);
/*******************************************************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* SITools2 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* SITools2. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/* global Ext, sitools, i18n, loadUrl */
Ext.namespace('sitools.widget.HtmlEditor');
/**
* datasetLink widget
*
* @class sitools.widget.HtmlEditor.datasetBrowser
* @extends Ext.util.Observable
*/
sitools.widget.HtmlEditor.datasetBrowser = function(config) {
this.datasets = [];
this.browseField = config.field;
/**
* INDEX JPB var projectId = Ext.util.Cookies.get('projectId'); if
* (Ext.isEmpty(projectId)){ Ext.Msg.alert(i18n.get ('warning.noProject'));
* return; }
*/
// var projectId = projectGlobal.getProjectId();
var projectAttachment = projectGlobal.sitoolsAttachementForUsers;
var treeUtils = commonTreeUtils;
var conn = Ext.Ajax;
conn.request({
url : projectAttachment + '/datasets?media=json',
method : 'GET',
scriptTag : true,
scope : this,
success : function(response) {
if (!showResponse(response, false)) {
return;
}
var config = Ext.decode(response.responseText);
var i = 0;
Ext.each(config.data, function(dataset) {
if (dataset.authorized !== "false") {
this.datasets.push({
text : dataset.name,
listeners : {
scope : this,
beforeexpand : function(node) {
node.removeAll(true);
if (dataset.status != "ACTIVE") {
var notify = new Ext.ux.Notification({
iconCls : 'x-icon-information',
title : i18n
.get('label.information'),
html : i18n
.get('warning.wrongStatus'),
autoDestroy : true,
hideDelay : 1000
});
notify.show(document);
return true;
}
conn.request({
// url : '/sitools/datasets/' + dataset.id +
// '?media=json',
url : dataset.url + '?media=json',
scope : this,
success : function(response) {
var dataset = Ext.decode(response.responseText).dataset;
commonTreeUtils.addShowData(node,dataset);
SitoolsDesk.navProfile.manageDatasetExplorerShowDefinitionAndForms(commonTreeUtils, node, dataset);
conn.request({
url : dataset.sitoolsAttachementForUsers
+ "/opensearch.xml",
scope : this,
success : function(response) {
var xml = response.responseXML;
var dq = Ext.DomQuery;
// check if there is a success
// node
// in the xml
var success = dq
.selectNode(
'OpenSearchDescription ',
xml);
if (success !== undefined) {
// commonTreeUtils.addOpensearch(node, dataset);
}
return true;
}
});
// commonTreeUtils.addFeeds(node, dataset);
}
});
return true;
}
},
children : [{
text : ""
}]
});
} else {
this.datasets.push({
text : dataset.name,
leaf : false,
icon : loadUrl.get('APP_URL')
+ "/common/res/images/icons/cadenas.png",
authorized : false
});
}
i++;
}, this);
this.fireEvent('datasetLoaded');
},
failure : function() {
Ext.Msg.alert(i18n.get('label.warning'), i18n.get('warning.noProject'));
}
});
this.rootNode = new Ext.tree.AsyncTreeNode({
nodeType : 'async',
text : 'dataSets',
leaf : false,
draggable : false,
children : this.datasets,
expanded : false,
listeners : {
scope : this,
beforeexpand : function() {
this.rootNode.removeAll(true);
this.rootNode.appendChild(this.datasets);
return true;
}
}
});
sitools.widget.HtmlEditor.datasetBrowser.superclass.constructor.call(this,
Ext.apply({
expanded : true,
useArrows : true,
autoScroll : true,
animate : true,
loader : new Ext.tree.TreeLoader(),
root : this.rootNode,
rootVisible : true,
layout : 'fit',
listeners : {
beforeload : function(node) {
return node.isRoot || Ext.isDefined(node.attributes.children);
},
datasetLoaded : function() {
this.getRootNode().expand();
}
},
bbar : [{
xtype : 'button',
text : i18n.get('label.select'),
scope : this,
handler : this.onValidate
}]
}));
};
Ext.extend(sitools.widget.HtmlEditor.datasetBrowser, Ext.tree.TreePanel, {
/**
* method called when trying to save preference
*
* @returns
*/
_getSettings : function() {
return {
preferencesPath : "/modules",
preferencesFileName : this.id
};
},
onValidate : function() {
var selNode = this.selModel.getSelectedNode();
if (selNode.isLeaf() && selNode.attributes.type != "defi"){
var urlLink, displayValue;
urlLink = selNode.attributes.dataUrl;
displayValue = selNode.attributes.winTitle;
this.browseField.setValue(displayValue);
if (selNode.attributes.type == "data"){
this.browseField.dataLinkComponent = String.format("<a href='#' onclick='parent.sitools.user.component.dataviews.dataviewUtils.showDetailsData(\"\",\"\",\"{0}\"); return false;'>", urlLink);
}
else if (selNode.attributes.type == "form"){
this.browseField.dataLinkComponent = String.format("<a href='#' onclick='parent.SitoolsDesk.showFormFromEditor(\"{0}\\/forms\"); return false;'>", urlLink);
}
this.ownerCt.close();
}
else {
Ext.Msg.alert(i18n.get('label.info'), i18n.get('label.selectNode'));
}
}
});
Ext.reg('sitools.widget.HtmlEditor.datasetBrowser',
sitools.widget.HtmlEditor.datasetBrowser);
Ext.override (GeoExt.data.FeatureStore, {
/**
* Sort by multiple fields in the specified order.
*
* @param {Array}
* An Array of field sort specifications, or, if ascending sort
* is required on all columns, an Array of field names. A field
* specification looks like:
*
* <pre><code>
* {
* ordersList : [ {
* field : firstname,
* direction : ASC
* }, {
* field : name
* direction : DESC
* } ]
* }
*
* </code>
*
*/
multiSort : function (sorters, direction) {
this.hasMultiSort = true;
direction = direction || "ASC";
if (this.multiSortInfo && direction == this.multiSortInfo.direction) {
direction = direction.toggle("ASC", "DESC");
}
this.multiSortInfo = {
sorters : sorters,
direction : direction
};
if (this.remoteSort) {
// this.singleSort(sorters[0].field, sorters[0].direction);
this.load(this.lastOptions);
} else {
this.applySort();
this.fireEvent('datachanged', this);
}
},
getSortState : function () {
return this.hasMultiSort ? this.multiSortInfo : this.sortInfo;
},
// application du tri multiple sur le store
load : function (options) {
options = Ext.apply({}, options);
this.storeOptions(options);
if ((this.sortInfo || this.multiSortInfo) && this.remoteSort) {
var pn = this.paramNames;
options.params = Ext.apply({}, options.params);
this.isInSort = true;
var root = pn.sort;
if (this.hasMultiSort) {
options.params[pn.sort] = Ext.encode({
"ordersList" : this.multiSortInfo.sorters
});
} else {
options.params[pn.sort] = Ext.encode({
"ordersList" : [ this.sortInfo ]
});
}
}
try {
return this.execute('read', null, options);
} catch (e) {
this.handleException(e);
return false;
}
}
});/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, ann, alert, document, alertFailure, getDesktop, SitoolsDesk, locale */
/*global DEFAULT_WIN_HEIGHT, DEFAULT_WIN_WIDTH, sitools, loadUrl, includeJs, DEFAULT_PREFERENCES_FOLDER */
/*
* @include "desktop/desktop.js"
* @include "components/columnsDefinition/dependencies/columnsDefinition.js"
* @include "components/forms/forms.js"
*/
Ext.namespace('sitools.env');
var userPreferences = null;
var userLogin = null;
var sql2ext = {
map : [],
load : function (url) {
var i18nRef = this;
Ext.Ajax.request({
method : 'GET',
url : url,
// params:'formLogin', using autorization instead
success : function (response, opts) {
ann(response.responseText, "no response is sent");
i18nRef.map = i18nRef.transformsPropertiesToMap(response.responseText);
},
failure : function (response, opts) {
alert("Error! Can't read i18n file with url :" + url);
}
});
},
/**
* Transforms a properties Text to a map
*
* @param text
* raw properties file
* @returns a map (associative array) TODO check when the raw properties
*/
transformsPropertiesToMap : function (text) {
var array = text.split('\n');
var localMap = [];
var i;
for (i = 0; i < array.length; i++) {
var string = array[i];
var indexOfEqualsSign = string.indexOf('=');
if (indexOfEqualsSign >= 1) {
var key = string.substring(0, indexOfEqualsSign).replace('\r', '');
var value = string.substring(indexOfEqualsSign + 1).replace('\r', '');
localMap[key] = value;
}
}
return localMap;
},
/**
* return the i18n value
*
* @param name
* @returns
*/
get : function (entry) {
return !Ext.isEmpty(this.map[entry]) ? this.map[entry] : 'auto';
}
};
var i18n = {
map : [],
/**
* Load a properties file and and the name/values in a associative array ;
* Executing this function on multiple properties file increase the size of
* the array Results can be displayed in the help panel with the display()
* function
*
* @param url
* URL of the i18n file
* @param callback
* No args function that will be executed
* @returns void
*/
load : function (url, callback, loopOnFailure) {
var i18nRef = this;
Ext.Ajax.request({
method : 'GET',
url : url,
loopOnFailure : (Ext.isEmpty(loopOnFailure)) ? true : loopOnFailure,
// params:'formLogin', using autorization instead
success : function (response, opts) {
ann(response.responseText, "no response is sent");
i18nRef.map = i18nRef.transformsPropertiesToMap(response.responseText);
if (Ext.isFunction(callback)) {
callback();
}
},
failure : function (response, opts) {
if (!opts.loopOnFailure) {
Ext.Msg.alert("Error! Can't read i18n file with url :" + url);
} else {
locale.restoreDefault();
url = '/sitools/res/i18n/' + locale.getLocale() + '/gui.properties';
i18n.load(url, callback, false);
}
}
});
},
/**
* Transforms a properties Text to a map
*
* @param text
* raw properties file
* @returns a map (associative array) TODO check when the raw properties
* file is rotten
*/
transformsPropertiesToMap : function (text) {
var array = text.split('\n');
var localMap = [];
var i;
for (i = 0; i < array.length; i++) {
var string = array[i];
var indexOfEqualsSign = string.indexOf('=');
if (indexOfEqualsSign >= 1) {
var key = string.substring(0, indexOfEqualsSign).replace('\r', '');
var value = string.substring(indexOfEqualsSign + 1).replace('\r', '');
localMap[key] = value;
}
}
return localMap;
},
/**
* return the i18n value
*
* @param name
* @returns
*/
get : function (entry) {
return !Ext.isEmpty(this.map[entry]) ? this.map[entry] : entry;
}
};
/**
* To be defined
*/
var componentManager = {
loadedComponents : [],
load : function (name) {
}
};
var data = {
ret : null,
/**
* Fetch a html file in the url, and display its content into the helpPanel. *
*
* @param url
* @returns
*/
get : function (url, cbk) {
Ext.Ajax.request({
method : 'GET',
url : url,
success : function (response, opts) {
cbk(Ext.decode(response.responseText));
},
failure : function (response, opts) {
Ext.Msg.alert("Warning", "Error! Can't get data with url :" + url);
}
});
return this.ret;
}
};
userLogin = Ext.util.Cookies.get('userLogin');
var userStorage = {
set : function (filename, filepath, content, callback) {
Ext.Ajax.request({
url : loadUrl.get('APP_URL') + loadUrl.get('APP_USERSTORAGE_USER_URL').replace('{identifier}', userLogin) + "/files",
method : 'POST',
scope : this,
params : {
filepath : filepath,
filename : filename
},
jsonData : content,
success : function (ret) {
var Json = Ext.decode(ret.responseText);
if (!Json.success) {
Ext.Msg.alert(i18n.get('label.warning'), Json.message);
return;
} else {
var notify = new Ext.ux.Notification({
iconCls : 'x-icon-information',
title : i18n.get('label.information'),
html : Json.message,
autoDestroy : true,
hideDelay : 1000
});
notify.show(document);
}
},
failure : function () {
Ext.Msg.alert(i18n.get('label.warning'), i18n.get('label.warning.savepreference.error'));
return;
},
callback : function () {
if (!Ext.isEmpty(callback)) {
callback.call();
}
}
});
},
get : function (fileName, filePath, scope, success, failure, callback) {
Ext.Ajax.request({
url : loadUrl.get('APP_URL') + loadUrl.get('APP_USERSTORAGE_USER_URL').replace('{identifier}', userLogin) + "/files" + filePath + "/" + fileName,
method : 'GET',
scope : scope,
success : success,
failure : failure,
callback : callback
});
}
};
/**
* Global project variable Used to get the projectId from the url
*/
var projectGlobal = {
/**
* Get the current projectId from the url url is like :
* /sitools/client-user/{projectName}/indexproject.html /sitools/client-user/
* can be changed
*
* @return the projectId
*/
projectId : null,
projectName : null,
preferences : null,
userRoles : null,
isAdmin : false,
sitoolsAttachementForUsers : null,
modules : null,
links : null,
callback : Ext.emptyFn,
initProject : function (callback) {
this.callback = callback;
this.projectName = this.getProjectName();
this.getProjectInfo();
},
// only load datasetView used by datasets in the current project
getDataViewsDependencies : function () {
Ext.Ajax.request({
url : this.sitoolsAttachementForUsers + "/datasetViews",
method : "GET",
scope : this,
success : function (ret) {
var json = Ext.decode(ret.responseText);
if (!json.success) {
Ext.Msg.alert(i18n.get('label.warning'), i18n.get('warning.noProjectName'));
return false;
} else {
var data = json.data;
Ext.each(data, function (datasetViewComponent) {
if (!Ext.isEmpty(datasetViewComponent.dependencies) && !Ext.isEmpty(datasetViewComponent.dependencies.js)) {
Ext.each(datasetViewComponent.dependencies.js, function (dependencies) {
includeJs(dependencies.url);
}, this);
}
if (!Ext.isEmpty(datasetViewComponent.dependencies) && !Ext.isEmpty(datasetViewComponent.dependencies.css)) {
Ext.each(datasetViewComponent.dependencies.css, function (dependencies) {
includeCss(dependencies.url);
}, this);
}
});
}
},
callback : function () {
this.getFormDependencies();
}
});
},
getFormDependencies : function () {
Ext.Ajax.request({
url : loadUrl.get('APP_URL') + loadUrl.get('APP_FORMCOMPONENTS_URL'),
method : "GET",
scope : this,
success : function (ret) {
var json = Ext.decode(ret.responseText);
if (!json.success) {
Ext.Msg.alert(i18n.get('label.warning'), i18n.get('warning.noProjectName'));
return false;
} else {
var data = json.data;
Ext.each(data, function (formComponent) {
includeJs(formComponent.fileUrlUser);
});
}
},
callback : function () {
this.initLanguages();
}
});
},
initLanguages : function () {
Ext.Ajax.request({
scope : this,
method : "GET",
/* /sitools/client-user */
// url : loadUrl.get('APP_URL') + loadUrl.get('APP_CLIENT_USER_URL') + '/tmp/langues.json',
url : loadUrl.get('APP_URL') + '/client-user/tmp/langues.json',
success : function (response) {
var json = Ext.decode(response.responseText);
this.languages = json.data;
},
failure : function (response) {
Ext.Msg.alert('Status', i18n.get('warning.serverError'));
},
callback : function () {
this.getPreferences(this.callback);
}
});
},
getUserRoles : function (cb) {
if (Ext.isEmpty(userLogin)) {
cb.call();
}
else {
Ext.Ajax.request({
url : loadUrl.get('APP_URL') + loadUrl.get("APP_USER_ROLE_URL"),
method : "GET",
scope : this,
success : function (ret) {
var json = Ext.decode(ret.responseText);
if (!json.success) {
Ext.Msg.alert(i18n.get('label.warning'), i18n.get('warning.noProjectName'));
return false;
} else {
this.user = json.user;
if (Ext.isEmpty(this.user.roles)) {
return;
}
for (var index = 0; index < this.user.roles.length; index++) {
var role = this.user.roles[index];
if (role.name === "Administrator") {
this.isAdmin = true;
}
}
}
},
callback : cb
});
}
},
getProjectName : function () {
if (this.projectName === null) {
// get the relative url
var url = document.location.pathname;
// split the url to get each part of the url in a tab cell
var tabUrl = url.split("/");
var i = 0, index;
var found = false;
// search for index.html, the projectName is right before
// '/index.html'
while (i < tabUrl.length && !found) {
if (tabUrl[i] === "project-index.html") {
found = true;
index = i;
}
i++;
}
// get the projectName from the tabUrl
this.projectName = tabUrl[index - 1];
if (this.projectName === undefined || this.projectName === "") {
Ext.Msg.alert(i18n.get('label.warning'), i18n.get('warning.noProject'));
}
}
return this.projectName;
},
/**
* Get the name of a project from the server
*/
getProjectInfo : function () {
Ext.Ajax.request({
url : loadUrl.get('APP_URL') + loadUrl.get('APP_PORTAL_URL') + '/projects/' + this.projectName,
method : "GET",
scope : this,
success : function (ret) {
var data = Ext.decode(ret.responseText);
if (!data.success) {
Ext.Msg.alert(i18n.get('label.warning'), i18n.get('warning.noProjectName'));
return false;
} else {
this.sitoolsAttachementForUsers = data.project.sitoolsAttachementForUsers;
this.projectId = data.project.id;
this.projectName = data.project.name;
this.htmlHeader = data.project.htmlHeader;
this.links = data.project.links;
this.navigationMode = data.project.navigationMode;
}
// var topEl = Ext.get('toppanel');
// topEl.update(Ext.util.Format.htmlDecode(data.project.htmlHeader));
},
callback : function (){
this.getDataViewsDependencies();
},
failure : function () {
Ext.Msg.alert(i18n.get('label.warning'), i18n.get('warning.noProject'));
}
});
},
getPreferences : function (callback) {
if (!Ext.isEmpty(userLogin)) {
var filePath = "/" + DEFAULT_PREFERENCES_FOLDER + "/" + projectGlobal.projectName;
var fileName = "desktop";
var success = function (ret) {
try {
this.preferences = Ext.decode(ret.responseText);
callback.call();
} catch (err) {
callback.call();
}
};
var failure = function (ret) {
this.getPublicPreferences(callback);
};
userStorage.get(fileName, filePath, this, success, failure);
} else {
this.getPublicPreferences(callback);
}
},
getPublicPreferences : function (callback) {
var AppPublicStorage = loadUrl.get('APP_PUBLIC_STORAGE_URL') + "/files";
Ext.Ajax.request({
// url : "/sitools/userstorage/" + userLogin + "/" + DEFAULT_PREFERENCES_FOLDER + "/" + this.projectName + "/desktop?media=json",
url : loadUrl.get('APP_URL') + AppPublicStorage + "/" + DEFAULT_PREFERENCES_FOLDER + "/" + this.projectName + "/desktop?media=json",
method : 'GET',
scope : this,
success : function (ret) {
try {
this.preferences = Ext.decode(ret.responseText);
} catch (err) {
this.preferences = null;
}
},
callback : callback
});
}
};
var publicStorage = {
set : function (filename, filepath, content, callback) {
this.url = loadUrl.get('APP_URL') + loadUrl.get('APP_PUBLIC_STORAGE_URL') + "/files";
Ext.Ajax.request({
url : this.url,
method : 'POST',
scope : this,
params : {
filepath : filepath,
filename : filename
},
jsonData : content,
success : function (ret) {
var Json = Ext.decode(ret.responseText);
if (!Json.success) {
Ext.Msg.alert(i18n.get('label.warning'), Json.message);
return;
} else {
var notify = new Ext.ux.Notification({
iconCls : 'x-icon-information',
title : i18n.get('label.information'),
html : Json.message,
autoDestroy : true,
hideDelay : 1000
});
notify.show(document);
}
},
failure : function () {
Ext.Msg.alert(i18n.get('label.warning'), i18n.get('label.warning.savepreference.error'));
return;
},
callback : function () {
if (!Ext.isEmpty(callback)) {
callback.call();
}
}
});
},
get : function (fileName, filePath, scope, success, failure) {
Ext.Ajax.request({
url : loadUrl.get('APP_URL') + loadUrl.get('APP_PUBLIC_STORAGE_URL') + "/files" + filePath + "/" + fileName,
method : 'GET',
scope : scope,
success : success,
failure : failure
});
},
remove : function () {
this.url = loadUrl.get('APP_URL') + loadUrl.get('APP_PUBLIC_STORAGE_URL') + "/files" + "?recursive=true";
Ext.Ajax.request({
url : this.url,
method : 'DELETE',
scope : this,
success : function (ret) {
var notify = new Ext.ux.Notification({
iconCls : 'x-icon-information',
title : i18n.get('label.information'),
html : i18n.get("label.publicUserPrefDeleted"),
autoDestroy : true,
hideDelay : 1000
});
notify.show(document);
},
failure : function (ret) {
//cas normal...
if (ret.status === 404) {
var notify = new Ext.ux.Notification({
iconCls : 'x-icon-information',
title : i18n.get('label.information'),
html : i18n.get("label.publicUserPrefDeleted"),
autoDestroy : true,
hideDelay : 1000
});
notify.show(document);
}
else {
var notifye = new Ext.ux.Notification({
iconCls : 'x-icon-error',
title : i18n.get('label.error'),
html : ret.responseText,
autoDestroy : true,
hideDelay : 1000
});
notifye.show(document);
}
}
});
}
};
function showResponse(ret, notification) {
try {
var Json = Ext.decode(ret.responseText);
if (!Json.success) {
Ext.Msg.alert(i18n.get('label.warning'), Json.message);
return false;
}
if (notification) {
var notify = new Ext.ux.Notification({
iconCls : 'x-icon-information',
title : i18n.get('label.information'),
html : Json.message,
autoDestroy : true,
hideDelay : 1000
});
notify.show(document);
}
return true;
} catch (err) {
Ext.Msg.alert(i18n.get('label.warning'), i18n.get('warning.javascriptError') + " : " + err);
return false;
}
};
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*!
* Ext JS Library 3.0+
* Copyright(c) 2006-2009 Ext JS, LLC
* licensing@extjs.com
* http://www.extjs.com/license
*/
/*global Ext, i18n, date, Digest, sql2ext, SitoolsDesk, loadUrl, sitools, showResponse, ColumnRendererEnum*/
// GLOBAL BEHAVIOUR
var DEFAULT_NATIVEJSON = false; //must be set to false to constrain Ext.doEncode (if true, doesn't work with prototype library)
var DEFAULT_TIMEOUT = 30000; // server request timeout (msec)
var DEFAULT_TIMEBUF = 10; // time to wait before sending request (msec)
var DEFAULT_NBRETRY = 0;// 3; // nb of request retries (if failure)
var SERVER_OK = 200;
var DEFAULT_WIN_HEIGHT = 400;
var DEFAULT_WIN_WIDTH = 600;
var DEFAULT_WINORDER_WIDTH = 400;
var DEFAULT_ORDER_FOLDER = "dataSelection";
var DEFAULT_PREFERENCES_FOLDER = "preferences";
var DEFAULT_LIVEGRID_BUFFER_SIZE = 300;
var WARNING_NB_RECORDS_PLOT = 10000;
var URL_CGU = "/sitools/res/licences/cgu.html";
var COOKIE_DURATION = 20;
var MULTIDS_TIME_DELAY = 2000;
var SITOOLS_DEFAULT_PROJECT_IMAGE_URL = "/sitools/res/images/sitools2_logo.png";
/**
* The nearLimit is a
* parameter for the predictive fetch algorithm within the view. If your
* bufferSize is small, set this to a value around a third or a quarter of
* the store's bufferSize (e.g. a value of 25 for a bufferSize of 100;
*/
var DEFAULT_NEAR_LIMIT_SIZE = 100;
Ext.BLANK_IMAGE_URL = '/sitools/cots/extjs/resources/images/default/s.gif';
Ext.USE_NATIVE_JSON = DEFAULT_NATIVEJSON;
Ext.Ajax.timeout = DEFAULT_TIMEOUT;
var onBeforeRequest = function (conn, options) {
var date = new Date();
if (!Ext.isEmpty(Ext.util.Cookies.get('scheme'))) {
if (Ext.util.Cookies.get('scheme') == "HTTP_Digest") {
var tmp = null;
var method = "GET";
if (!Ext.isEmpty(options.method)) {
method = options.method;
}
var url = options.url;
if (Ext.isEmpty(options.url) && !Ext.isEmpty(options.scope)) {
if (!Ext.isEmpty(options.scope.url)) {
url = options.scope.url;
}
}
var A1 = Ext.util.Cookies.get("A1");
var auth = new Digest({
usr : Ext.util.Cookies.get("userLogin"),
algorithm : Ext.util.Cookies.get("algorithm"),
realm : Ext.util.Cookies.get("realm"),
url : url,
nonce : Ext.util.Cookies.get('nonce'),
method : method,
mode : "digest",
A1 : A1
});
Ext.apply(Ext.Ajax.defaultHeaders, {
Authorization : auth.getDigestAuth()
});
}
else {
if (!Ext.isEmpty(Ext.util.Cookies.get('hashCode'))) {
Ext.util.Cookies.set('hashCode', Ext.util.Cookies.get('hashCode'), date.add(Date.MINUTE, COOKIE_DURATION));
Ext.apply(Ext.Ajax.defaultHeaders, {
Authorization : Ext.util.Cookies.get('hashCode')
});
}
}
}
if (!Ext.isEmpty(Ext.util.Cookies.get('userLogin'))) {
Ext.util.Cookies.set('userLogin', Ext.util.Cookies.get('userLogin'), date.add(Date.MINUTE, 20));
}
};
Ext.Ajax.on('beforerequest', onBeforeRequest, this);
var DEFAULT_LOCALE = "en";
var SITOOLS_DATE_FORMAT = 'Y-m-d\\TH:i:s.u';
var SITOOLS_DEFAULT_IHM_DATE_FORMAT = 'Y-m-d H:i:s.u';
var locale = {
locale : DEFAULT_LOCALE,
isInit : false,
getLocale : function () {
if (!this.isInit) {
if (Ext.isEmpty(Ext.util.Cookies.get('language'))) {
var navigator = window.navigator;
this.locale = navigator.language || navigator.browserLanguage || navigator.userLanguage;
}
else {
this.locale = Ext.util.Cookies.get('language');
}
this.isInit = true;
}
return this.locale;
},
setLocale : function (locale) {
this.locale = locale;
},
restoreDefault : function () {
this.setLocale(DEFAULT_LOCALE);
}
};
var onRequestFeedException = function (proxy, type, action, options, response, args) {
// si on a un cookie de session et une erreur 403
if ((response.status == 403) && !Ext.isEmpty(Ext.util.Cookies.get('hashCode'))) {
Ext.MessageBox.minWidth = 360;
Ext.MessageBox.alert(i18n.get('label.session.expired'), response.responseText);
} else {
Ext.MessageBox.minWidth = 360;
Ext.MessageBox.alert(i18n.get('label.error'), response.responseText);
}
return false;
};
// GLOBAL VARIABLES
var desktop;
var projectGlobal;
var projectId;
// Application d'exception sur tous les JsonStores :
// Ext.override (Ext.data.JsonStore, {
// listeners : {
// exception : function (dataProxy, type, action, options, response){
// Ext.Msg.alert (i18n.get('label.warning'), response.responseText);
// }
// }
// });
// GLOBAL FUNCTIONS
function alertFailure(response, opts) {
var txt;
if (response.status == SERVER_OK) {
var ret = Ext.decode(response.responseText).message;
txt = i18n.get('msg.error') + ': ' + ret;
} else {
txt = i18n.get('warning.serverError') + ': ' + response.statusText;
}
Ext.Msg.alert(i18n.get('label.warning'), txt);
// Ext.WindowMgr.bringToFront(alert);
}
function extColModelToJsonColModel(ExtColModel) {
var colModel = [];
var columns;
if (!Ext.isEmpty(ExtColModel.columns)) {
columns = ExtColModel.columns;
}
else {
columns = ExtColModel;
}
Ext.each(columns, function (column) {
colModel.push({
columnAlias : column.columnAlias,
dataIndex : column.dataIndexSitools,
dataIndexSitools : column.dataIndexSitools,
header : column.header,
filter : column.filter,
hidden : column.hidden,
id : column.id,
previewColumn : column.previewColumn,
primaryKey : column.primaryKey,
schema : column.schema,
sortable : column.sortable,
sqlColumnType : column.sqlColumnType,
tableAlias : column.tableAlias,
tableName : column.tableName,
toolTip : column.tooltip,
urlColumn : column.urlColumn,
width : column.width,
// columnAliasDetail : column.columnAliasDetail,
columnRenderer : column.columnRenderer,
// datasetDetailId : column.datasetDetailId,
specificColumnType : column.specificColumnType,
javaSqlColumnType : column.javaSqlColumnType,
format : column.format
// image : column.image,
// datasetDetailUrl : column.datasetDetailUrl
});
});
return colModel;
}
function extColModelToSrv(ExtColModel) {
var colModel = [];
var columns;
if (!Ext.isEmpty(ExtColModel.columns)) {
columns = ExtColModel.columns;
}
else {
columns = ExtColModel;
}
Ext.each(columns, function (column) {
if (!column.hidden) {
colModel.push(column.columnAlias);
}
});
return colModel.join(", ");
}
function extColModelToStorage(ExtColModel) {
var colModel = [];
var columns;
if (!Ext.isEmpty(ExtColModel.columns)) {
columns = ExtColModel.columns;
}
else {
columns = ExtColModel;
}
Ext.each(columns, function (column) {
if (!column.hidden) {
colModel.push({
columnAlias : column.columnAlias,
dataIndex : column.dataIndex,
dataIndexSitools : column.dataIndexSitools,
editor : column.editor,
filter : column.filter,
header : column.header,
hidden : column.hidden,
id : column.id,
isColumn : column.isColumn,
previewColumn : column.previewColumn,
primaryKey : column.primaryKey,
schema : column.schema,
sortable : column.sortable,
sqlColumnType : column.sqlColumnType,
tableAlias : column.tableAlias,
tableName : column.tableName,
toolTip : column.tooltip,
urlColumn : column.urlColumn,
width : column.width,
// columnAliasDetail : column.columnAliasDetail,
columnRenderer : column.columnRenderer,
// datasetDetailId : column.datasetDetailId,
specificColumnType : column.specificColumnType,
javaSqlColumnType : column.javaSqlColumnType,
unit : column.unit,
format : column.format
// image : column.image,
// datasetDetailUrl : column.datasetDetailUrl
});
}
});
return colModel;
}
/**
* Get the Sitools Desktop
* @returns the sitools Desktop
*/
function getDesktop() {
if (Ext.isEmpty(this.SitoolsDesk)) {
return null;
}
else {
return this.SitoolsDesk.app.desktop;
}
}
/**
* Get the Sitools Application
* @returns the sitools Desktop
*/
function getApp() {
if (Ext.isEmpty(SitoolsDesk)) {
return null;
}
else {
return SitoolsDesk.app;
}
}
// Ext.WindowMgr = getDesktop().getManager();
// Override de la méthode initEvents pour que le windowManager utilisé soit
// toujours le même
Ext.override(Ext.Window, {
initEvents : function () {
Ext.Window.superclass.initEvents.call(this);
if (this.animateTarget) {
this.setAnimateTarget(this.animateTarget);
}
if (this.resizable) {
this.resizer = new Ext.Resizable(this.el, {
minWidth: this.minWidth,
minHeight: this.minHeight,
handles: this.resizeHandles || 'all',
pinned: true,
resizeElement : this.resizerAction,
handleCls: 'x-window-handle'
});
this.resizer.window = this;
this.mon(this.resizer, 'beforeresize', this.beforeResize, this);
}
if (this.draggable) {
this.header.addClass('x-window-draggable');
}
this.mon(this.el, 'mousedown', this.toFront, this);
// this.manager = this.manager || Ext.WindowMgr;
var tmp = getDesktop();
if (Ext.isEmpty(tmp)) {
this.manager = Ext.WindowMgr;
}
else {
this.manager = getDesktop().getManager() || Ext.WindowMgr;
}
this.manager.register(this);
if (this.maximized) {
this.maximized = false;
this.maximize();
}
if (this.closable) {
var km = this.getKeyMap();
km.on(27, this.onEsc, this);
km.disable();
}
}
});
Ext.override(Ext.grid.GridPanel, {
stripeRows : true
});
Ext.data.Types.DATEASSTRING = {
convert : function (v, data) {
return v;
},
sortType : function (v) {
return v;
},
type : "dateAsString"
};
function includeJs(url) {
if (Ext.isEmpty(url)) {
return;
}
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.setAttribute('src', url);
script.setAttribute('type', 'text/javascript');
head.appendChild(script);
}
function includeCss(url) {
var headID = document.getElementsByTagName("head")[0];
var newCss = document.createElement('link');
newCss.type = 'text/css';
newCss.rel = 'stylesheet';
newCss.href = url;
newCss.media = 'screen';
// pas possible de monitorer l'evenement onload sur une balise link
headID.appendChild(newCss);
}
Ext.override(Ext.PagingToolbar, {
initComponent : function () {
var T = Ext.Toolbar;
var pagingItems = [this.first = new T.Button({
tooltip: this.firstText,
overflowText: this.firstText,
iconCls: 'x-tbar-page-first',
disabled: true,
handler: this.moveFirst,
scope: this
}), this.prev = new T.Button({
tooltip: this.prevText,
overflowText: this.prevText,
iconCls: 'x-tbar-page-prev',
disabled: true,
handler: this.movePrevious,
scope: this
}), '-', this.beforePageText,
this.inputItem = new Ext.form.NumberField({
cls: 'x-tbar-page-number',
allowDecimals: false,
allowNegative: false,
enableKeyEvents: true,
selectOnFocus: true,
submitValue: false,
listeners: {
scope: this,
keydown: this.onPagingKeyDown,
blur: this.onPagingBlur
}
}), this.afterTextItem = new T.TextItem({
text: String.format(this.afterPageText, 1)
}), '-', this.next = new T.Button({
tooltip: this.nextText,
overflowText: this.nextText,
iconCls: 'x-tbar-page-next',
disabled: true,
handler: this.moveNext,
scope: this
}), this.last = new T.Button({
tooltip: this.lastText,
overflowText: this.lastText,
iconCls: 'x-tbar-page-last',
disabled: true,
handler: this.moveLast,
scope: this
}), '-'];
var userItems = this.items || this.buttons || [];
if (this.prependButtons) {
this.items = userItems.concat(pagingItems);
} else {
this.items = pagingItems.concat(userItems);
}
delete this.buttons;
if (this.displayInfo) {
this.items.push('->');
this.items.push(this.displayItem = new T.TextItem({}));
}
Ext.PagingToolbar.superclass.initComponent.call(this);
this.addEvents(
/**
* @event change
* Fires after the active page has been changed.
* @param {Ext.PagingToolbar} this
* @param {Object} pageData An object that has these properties:<ul>
* <li><code>total</code> : Number <div class="sub-desc">The total number of records in the dataset as
* returned by the server</div></li>
* <li><code>activePage</code> : Number <div class="sub-desc">The current page number</div></li>
* <li><code>pages</code> : Number <div class="sub-desc">The total number of pages (calculated from
* the total number of records in the dataset as returned by the server and the current {@link #pageSize})</div></li>
* </ul>
*/
'change',
/**
* @event beforechange
* Fires just before the active page is changed.
* Return false to prevent the active page from being changed.
* @param {Ext.PagingToolbar} this
* @param {Object} params An object hash of the parameters which the PagingToolbar will send when
* loading the required page. This will contain:<ul>
* <li><code>start</code> : Number <div class="sub-desc">The starting row number for the next page of records to
* be retrieved from the server</div></li>
* <li><code>limit</code> : Number <div class="sub-desc">The number of records to be retrieved from the server</div></li>
* </ul>
* <p>(note: the names of the <b>start</b> and <b>limit</b> properties are determined
* by the store's {@link Ext.data.Store#paramNames paramNames} property.)</p>
* <p>Parameters may be added as required in the event handler.</p>
*/
'beforechange'
);
this.on('afterlayout', this.onFirstLayout, this, {single: true});
this.cursor = 0;
this.bindStore(this.store, true);
},
onFirstLayout : function () {
this.refresh = new Ext.Toolbar.Button({
tooltip: i18n.get('label.refreshText'),
overflowText: i18n.get('label.refreshText'),
iconCls: 'x-tbar-loading',
handler: this.doRefresh,
scope: this
});
this.insert(10, this.refresh);
if (this.dsLoaded) {
this.onLoad.apply(this, this.dsLoaded);
}
}
});
/**
* Build a {Ext.grid.ColumnModel} columnModel with a dataset informations
* @param {Array} listeColonnes Array of dataset Columns
* @param {Array} dictionnaryMappings Array of Dataset dictionnary mappings
* @param {Object} dataviewConfig the specific dataview Configuration.
* @return {Ext.grid.ColumnModel} the builded columnModel
*/
function getColumnModel(listeColonnes, dictionnaryMappings, dataviewConfig) {
var columns = [];
if (!Ext.isEmpty(listeColonnes)) {
Ext.each(listeColonnes, function (item, index, totalItems) {
var tooltip = "";
if (item.toolTip) {
tooltip = item.toolTip;
}
else {
if (Ext.isArray(dictionnaryMappings) && !Ext.isEmpty(dictionnaryMappings)) {
var dico = dictionnaryMappings[0];
var dicoMapping = dico.mapping || [];
dicoMapping.each(function (mapping) {
if (item.columnAlias == mapping.columnAlias) {
var concept = mapping.concept || {};
if (!Ext.isEmpty(concept.description)) {
tooltip += concept.description.replace('"', "''") + "<br>";
}
}
});
}
}
var renderer = sitools.user.component.dataviews.dataviewUtils.getRendererLiveGrid(item, dataviewConfig);
var hidden;
if (Ext.isEmpty(item.visible)) {
hidden = item.hidden;
} else {
hidden = !item.visible;
}
if (Ext.isEmpty(item.columnRenderer) || ColumnRendererEnum.NO_CLIENT_ACCESS != item.columnRenderer.behavior) {
columns.push(new Ext.grid.Column({
columnAlias : item.columnAlias,
dataIndexSitools : item.dataIndex,
dataIndex : item.columnAlias,
header : item.header,
width : item.width,
sortable : item.sortable,
hidden : hidden,
tooltip : tooltip,
renderer : renderer,
schema : item.schema,
tableName : item.tableName,
tableAlias : item.tableAlias,
id : item.id,
// urlColumn : item.urlColumn,
primaryKey : item.primaryKey,
previewColumn : item.previewColumn,
filter : item.filter,
sqlColumnType : item.sqlColumnType,
// columnAliasDetail : item.columnAliasDetail,
columnRenderer : item.columnRenderer,
// datasetDetailId : item.datasetDetailId,
specificColumnType : item.specificColumnType,
// image : item.image,
// datasetDetailUrl : item.datasetDetailUrl,
format : item.format
}));
}
}, this);
}
var cm = new Ext.grid.ColumnModel({
columns : columns
});
return cm;
}
//Date.formatFunctions['sitoolsGrid Y-m-d H:i:s'] = function () {
// if (this.getHours() === 0 && this.getMinutes() === 0 && this.getSeconds() === 0) {
// return this.format(BDD_DATE_FORMAT);
// }
// else {
// return this.format(BDD_DATE_FORMAT_WITH_TIME);
// }
//};
Ext.override(Ext.menu.DateMenu, {
initComponent : function () {
this.on('beforeshow', this.onBeforeShow, this);
if (this.strict == (Ext.isIE7 && Ext.isStrict)) {
this.on('show', this.onShow, this, {single: true, delay: 20});
}
Ext.apply(this, {
plain: true,
showSeparator: false,
items: this.picker = new Ext.SitoolsDatePicker(Ext.applyIf({
internalRender: this.strict || !Ext.isIE,
ctCls: 'x-menu-date-item',
id: this.pickerId
}, this.initialConfig))
});
this.picker.purgeListeners();
Ext.menu.DateMenu.superclass.initComponent.call(this);
this.relayEvents(this.picker, ['select']);
this.on('show', this.picker.focus, this.picker);
this.on('select', this.menuHide, this);
if (this.handler) {
this.on('select', this.handler, this.scope || this);
}
}
});
Ext.override(Ext.form.DateField, {
showTime : false,
onTriggerClick : function () {
if (this.disabled) {
return;
}
if (Ext.isEmpty(this.menu)) {
this.menu = new Ext.menu.DateMenu({
hideOnClick: false,
showTime : this.showTime,
focusOnSelect: false
});
}
this.onFocus();
Ext.apply(this.menu.picker, {
minDate : this.minValue,
maxDate : this.maxValue,
disabledDatesRE : this.disabledDatesRE,
disabledDatesText : this.disabledDatesText,
disabledDays : this.disabledDays,
disabledDaysText : this.disabledDaysText,
format : this.format,
showToday : this.showToday,
minText : String.format(this.minText, this.formatDate(this.minValue)),
maxText : String.format(this.maxText, this.formatDate(this.maxValue))
});
this.menu.picker.setValue(this.getValue() || new Date());
this.menu.show(this.el, "tl-bl?");
this.menuEvents('on');
}
});
/**
* Display the content of the file located at the given Url depending on its
* content type
*
* @param url
* the url of the file
* @param title
* the title of the window to open
*/
function viewFileContent(url, title) {
// build first request to get the headers
Ext.Ajax.request({
url : url,
method : 'HEAD',
scope : this,
success : function (ret) {
try {
var headerFile = ret.getResponseHeader("Content-Type").split(";")[0].split("/")[0];
if (headerFile == "text" || ret.getResponseHeader("Content-Type").indexOf("application/json") >= 0) {
Ext.Ajax.request({
url : url,
method : 'GET',
scope : this,
success : function (ret) {
var windowConfig = {
id : "winPreferenceDetailId",
title : title,
iconCls : "version"
};
var jsObj = sitools.user.component.entete.userProfile.viewTextPanel;
var componentCfg = {
text : ret.responseText,
formatJson : (ret.getResponseHeader("Content-Type").indexOf("application/json") >= 0)
};
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, jsObj);
}
});
}
else if (headerFile == "image") {
sitools.user.component.dataviews.dataviewUtils.showPreview(url, title);
}
else {
sitools.user.component.dataviews.dataviewUtils.downloadFile(url);
}
} catch (err) {
Ext.Msg.alert(i18n.get('label.error'), err);
}
},
failure : function (ret) {
return null;
}
});
}
Ext.override(Ext.data.XmlReader, {
buildExtractors : function () {
if (this.ef) {
return;
}
var s = this.meta,
Record = this.recordType,
f = Record.prototype.fields,
fi = f.items,
fl = f.length;
if (s.totalProperty) {
this.getTotal = this.createAccessor(s.totalProperty);
}
if (s.successProperty) {
this.getSuccess = this.createAccessor(s.successProperty);
}
if (s.messageProperty) {
this.getMessage = this.createAccessor(s.messageProperty);
}
this.getRoot = function (res) {
return (!Ext.isEmpty(res[this.meta.record])) ? res[this.meta.record] : res[this.meta.root];
};
if (s.idPath || s.idProperty) {
var g = this.createAccessor(s.idPath || s.idProperty);
this.getId = function (rec) {
var id = g(rec) || rec.id;
return (id === undefined || id === '') ? null : id;
};
} else {
this.getId = function () {
return null;
};
}
var ef = [];
for (var i = 0; i < fl; i++) {
f = fi[i];
var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
if (f.createAccessor !== undefined && f.createAccessor !== null) {
ef.push(f.createAccessor);
}
else {
ef.push(this.createAccessor(map));
}
}
this.ef = ef;
}
});
Ext.override(Ext.layout.BorderLayout.Region, {
getCollapsedEl : function () {
if (!this.collapsedEl) {
if (!this.toolTemplate) {
var tt = new Ext.Template(
'<span class="x-panel-collapsed-text">{title}</span>',
'<div class="x-tool x-tool-{id}"> </div>'
);
tt.disableFormats = true;
tt.compile();
Ext.layout.BorderLayout.Region.prototype.toolTemplate = tt;
}
this.collapsedEl = this.targetEl.createChild({
cls: "x-layout-collapsed x-layout-collapsed-" + this.position,
id: this.panel.id + '-xcollapsed'
});
this.collapsedEl.enableDisplayMode('block');
if (this.collapseMode == 'mini') {
this.collapsedEl.addClass('x-layout-cmini-' + this.position);
this.miniCollapsedEl = this.collapsedEl.createChild({
cls : "x-layout-mini x-layout-mini-" + this.position,
html : " "
});
this.miniCollapsedEl.addClassOnOver('x-layout-mini-over');
this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
this.collapsedEl.on('click', this.onExpandClick, this, {stopEvent : true});
}
else {
if (this.collapsible !== false && !this.hideCollapseTool) {
var t = this.expandToolEl = this.toolTemplate.append(
this.collapsedEl.dom,
{
id: 'expand-' + this.position,
title : this.panel.collapsedTitle
}, true);
t.addClassOnOver('x-tool-expand-' + this.position + '-over');
t.on('click', this.onExpandClick, this, {
stopEvent: true
});
}
if (this.floatable !== false || this.titleCollapse) {
this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
this.collapsedEl.on("click", this[this.floatable ? 'collapseClick' : 'onExpandClick'], this);
}
}
}
return this.collapsedEl;
}
});
Ext.ns("sitools.user");
/**
* A méthod call when click on dataset Icon. Request the dataset, and open a window depending on type
*
* @static
* @param {string} url the url to request the dataset
* @param {string} type the type of the component.
* @param {} extraCmpConfig an extra config to apply to the component.
*/
sitools.user.clickDatasetIcone = function (url, type, extraCmpConfig) {
Ext.Ajax.request({
method : "GET",
url : url,
success : function (ret) {
var Json = Ext.decode(ret.responseText);
if (showResponse(ret)) {
var dataset = Json.dataset;
var componentCfg, javascriptObject;
var windowConfig = {
datasetName : dataset.name,
type : type,
saveToolbar : true,
toolbarItems : []
};
switch (type) {
case "desc" :
Ext.apply(windowConfig, {
title : i18n.get('label.description') + " : " + dataset.name,
id : "desc" + dataset.id,
saveToolbar : false,
iconCls : "version"
});
componentCfg = {
autoScroll : true,
html : dataset.descriptionHTML
};
Ext.applyIf(componentCfg, extraCmpConfig);
javascriptObject = Ext.Panel;
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, javascriptObject);
break;
case "data" :
javascriptObject = eval(SitoolsDesk.navProfile.getDatasetOpenMode(dataset));
Ext.apply(windowConfig, {
winWidth : 900,
winHeight : 400,
title : i18n.get('label.dataTitle') + " : " + dataset.name,
id : type + dataset.id,
iconCls : "dataviews"
});
componentCfg = {
dataUrl : dataset.sitoolsAttachementForUsers,
datasetId : dataset.Id,
datasetCm : dataset.columnModel,
datasetName : dataset.name,
dictionaryMappings : dataset.dictionaryMappings,
datasetViewConfig : dataset.datasetViewConfig,
preferencesPath : "/" + dataset.datasetName,
preferencesFileName : "datasetOverview",
sitoolsAttachementForUsers : dataset.sitoolsAttachementForUsers
};
Ext.applyIf(componentCfg, extraCmpConfig);
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, javascriptObject);
break;
case "forms" :
var menuForms = new Ext.menu.Menu();
Ext.Ajax.request({
method : "GET",
url : dataset.sitoolsAttachementForUsers + "/forms",
success : function (ret) {
try {
var Json = Ext.decode(ret.responseText);
if (! Json.success) {
throw Json.message;
}
if (Json.total === 0) {
throw i18n.get('label.noForms');
}
javascriptObject = sitools.user.component.forms.mainContainer;
if (Json.total == 1) {
var form = Json.data[0];
Ext.apply(windowConfig, {
title : i18n.get('label.forms') + " : " + dataset.name + "." + form.name,
iconCls : "forms"
});
Ext.apply(windowConfig, {
id : type + dataset.id + form.id
});
componentCfg = {
dataUrl : dataset.sitoolsAttachementForUsers,
dataset : dataset,
formId : form.id,
formName : form.name,
formParameters : form.parameters,
formWidth : form.width,
formHeight : form.height,
formCss : form.css,
preferencesPath : "/" + dataset.name + "/forms",
preferencesFileName : form.name
};
Ext.applyIf(componentCfg, extraCmpConfig);
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, javascriptObject);
}
else {
var handler = null;
Ext.each(Json.data, function (form) {
handler = function (form, dataset) {
Ext.apply(windowConfig, {
title : i18n.get('label.forms') + " : " + dataset.name + "." + form.name,
iconCls : "forms"
});
Ext.apply(windowConfig, {
id : type + dataset.id + form.id
});
componentCfg = {
dataUrl : dataset.sitoolsAttachementForUsers,
formId : form.id,
formName : form.name,
formParameters : form.parameters,
formWidth : form.width,
formHeight : form.height,
formCss : form.css,
dataset : dataset
};
Ext.applyIf(componentCfg, extraCmpConfig);
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, javascriptObject);
};
menuForms.addItem({
text : form.name,
handler : function () {
handler(form, dataset);
},
icon : loadUrl.get('APP_URL') + "/common/res/images/icons/tree_forms.png"
});
}, this);
menuForms.showAt(Ext.EventObject.xy);
}
}
catch (err) {
var tmp = new Ext.ux.Notification({
iconCls : 'x-icon-information',
title : i18n.get('label.information'),
html : i18n.get(err),
autoDestroy : true,
hideDelay : 1000
}).show(document);
}
}
});
break;
case "feeds" :
var menuFeeds = new Ext.menu.Menu();
Ext.Ajax.request({
method : "GET",
url : dataset.sitoolsAttachementForUsers + "/feeds",
success : function (ret) {
try {
var Json = Ext.decode(ret.responseText);
if (! Json.success) {
throw Json.message;
}
if (Json.total === 0) {
throw i18n.get('label.noFeeds');
}
javascriptObject = sitools.widget.FeedGridFlux;
if (Json.total == 1) {
var feed = Json.data[0];
Ext.apply(windowConfig, {
title : i18n.get('label.feeds') + " : " + dataset.name + "." + feed.title,
id : type + dataset.id + feed.id,
iconCls : "feedsModule"
});
componentCfg = {
datasetId : dataset.id,
urlFeed : dataset.sitoolsAttachementForUsers + "/clientFeeds/" + feed.name,
feedType : feed.feedType,
datasetName : dataset.name,
feedSource : feed.feedSource,
autoLoad : true
};
Ext.applyIf(componentCfg, extraCmpConfig);
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, javascriptObject);
}
else {
var handler = null;
Ext.each(Json.data, function (feed) {
handler = function (feed, dataset) {
Ext.apply(windowConfig, {
title : i18n.get('label.feeds') + " : " + dataset.name + "." + feed.title,
id : type + dataset.id + feed.id,
iconCls : "feedsModule"
});
componentCfg = {
datasetId : dataset.id,
urlFeed : dataset.sitoolsAttachementForUsers + "/clientFeeds/" + feed.name,
feedType : feed.feedType,
datasetName : dataset.name,
feedSource : feed.feedSource,
autoLoad : true
};
Ext.applyIf(componentCfg, extraCmpConfig);
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, javascriptObject);
};
menuFeeds.addItem({
text : feed.name,
handler : function () {
handler(feed, dataset);
},
icon : loadUrl.get('APP_URL') + "/common/res/images/icons/rss.png"
});
}, this);
menuFeeds.showAt(Ext.EventObject.xy);
}
}
catch (err) {
var tmp = new Ext.ux.Notification({
iconCls : 'x-icon-information',
title : i18n.get('label.information'),
html : i18n.get(err),
autoDestroy : true,
hideDelay : 1000
}).show(document);
}
}
});
break;
case "defi" :
Ext.apply(windowConfig, {
title : i18n.get('label.definitionTitle') + " : " + dataset.name,
id : type + dataset.id,
iconCls : "semantic"
});
javascriptObject = sitools.user.component.columnsDefinition;
componentCfg = {
datasetId : dataset.id,
datasetCm : dataset.columnModel,
datasetName : dataset.name,
dictionaryMappings : dataset.dictionaryMappings,
preferencesPath : "/" + dataset.name,
preferencesFileName : "semantic"
};
Ext.applyIf(componentCfg, extraCmpConfig);
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, javascriptObject);
break;
case "openSearch" :
Ext.Ajax.request({
method : "GET",
url : dataset.sitoolsAttachementForUsers + "/opensearch.xml",
success : function (ret) {
var xml = ret.responseXML;
var dq = Ext.DomQuery;
// check if there is a success node
// in the xml
var success = dq.selectNode('OpenSearchDescription ', xml);
if (!success) {
var tmp = new Ext.ux.Notification({
iconCls : 'x-icon-information',
title : i18n.get('label.information'),
html : i18n.get("label.noOpenSearch"),
autoDestroy : true,
hideDelay : 1000
}).show(document);
return;
}
Ext.apply(windowConfig, {
title : i18n.get('label.opensearch') + " : " + dataset.name,
id : type + dataset.id,
iconCls : "openSearch"
});
javascriptObject = sitools.user.component.datasetOpensearch;
componentCfg = {
datasetId : dataset.id,
dataUrl : dataset.sitoolsAttachementForUsers,
datasetName : dataset.name,
preferencesPath : "/" + dataset.name,
preferencesFileName : "openSearch"
};
Ext.applyIf(componentCfg, extraCmpConfig);
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, javascriptObject);
}
});
break;
}
}
},
failure : alertFailure
});
};
/**
* Add a tooltip on every form field: tooltip could be an object like tooltip : {
* text : string width : number }, or a simple string
*/
Ext.override(Ext.form.Field, {
tooltip : null,
listeners : {
render: function () {
Ext.form.Field.superclass.render.apply(this, arguments);
if (!Ext.isEmpty(this.tooltip)) {
var ttConfig = {};
if (Ext.isString(this.tooltip)) {
ttConfig = {
html : this.tooltip,
width : 200,
dismissDelay : 5000
};
}
else if (Ext.isObject(this.tooltip)) {
ttConfig = this.tooltip;
} else {
return;
}
Ext.apply(ttConfig, {
target : this.el
});
this.tTip = new Ext.ToolTip(ttConfig);
}
}
}
});
/**
* Add a tooltip on every boxcomponent : tooltip could be an object like tooltip : {
* text : string width : number }, or a simple string
*/
Ext.override(Ext.BoxComponent, {
tooltip : null,
listeners : {
render: function () {
Ext.BoxComponent.superclass.render.apply(this, arguments);
if (!Ext.isEmpty(this.tooltip)) {
var ttConfig = {};
if (Ext.isString(this.tooltip)) {
ttConfig = {
html : this.tooltip,
width : 200,
dismissDelay : 5000
};
}
else if (Ext.isObject(this.tooltip)) {
ttConfig = this.tooltip;
} else {
return;
}
Ext.apply(ttConfig, {
target : this.el
});
this.tTip = new Ext.ToolTip(ttConfig);
}
}
}
});
/**
* Add a tooltip on every boxcomponent : tooltip could be an object like tooltip : {
* text : string width : number }, or a simple string
*/
Ext.override(Ext.Button, {
setTooltip : function() {
return;
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*!
* Ext JS Library 3.2.1
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
/*global Ext, i18n, locale:true, sitools, loadUrl, userLogin, DEFAULT_PREFERENCES_FOLDER*/
/*
* @include "../../client-public/js/siteMap.js"
* @include "portal/portal.js"
*/
// Sample desktop configuration
function initAppliDesktop() {
return;
}
var portal;
var portalApp = {
projects : null,
languages : null,
preferences : null,
//callbacks : [this.callSiteMapResource, this.initProjects, this.initLanguages, this.initPreferences]
autoChainAjaxRequest : true,
initProjects : function (callback) {
Ext.Ajax.request({
scope : this,
/* sitools/portal/projects...*/
url : loadUrl.get('APP_URL') + loadUrl.get('APP_PORTAL_URL') + '/projects?media=json',
// url : '/sitools/portal/projects?media=json',
method : 'GET',
success : function (response) {
try {
this.projects = Ext.decode(response.responseText).data;
if (this.autoChainAjaxRequest) {
this.initLanguages();
}
} catch (err) {
Ext.Msg.alert(i18n.get('label.error'), err);
}
// portal = new sitools.Portal(response.responseJSON.data);
},
failure : function (response) {
Ext.Msg.alert('Status', i18n.get('warning.serverError'));
}
});
},
initLanguages : function () {
Ext.Ajax.request({
scope : this,
method : "GET",
/* /sitools/client-user */
// url : loadUrl.get('APP_URL') + loadUrl.get('APP_CLIENT_USER_URL') + '/tmp/langues.json',
url : loadUrl.get('APP_URL') + '/client-user/tmp/langues.json',
success : function (response) {
this.languages = Ext.decode(response.responseText).data;
if (this.autoChainAjaxRequest) {
this.initPreferences();
}
},
failure : function (response) {
Ext.Msg.alert('Status', i18n.get('warning.serverError'));
}
});
},
initPreferences : function (cb) {
if (Ext.isEmpty(userLogin)) {
var projects = this.projects;
var languages = this.languages;
var preferences = this.preferences;
var callback;
if (this.autoChainAjaxRequest) {
callback = function () {
// loadUrl.load('/sitools/client-user/siteMap', function (){
portal = new sitools.Portal(projects, languages, preferences);
// });
};
}
else {
callback = cb;
}
i18n.load(loadUrl.get('APP_URL') + '/res/i18n/' + locale.getLocale() + '/gui.properties', callback);
return;
}
var filePath = "/" + DEFAULT_PREFERENCES_FOLDER + '/portal';
var success = function (response) {
this.preferences = Ext.decode(response.responseText);
if (!Ext.isEmpty(this.preferences.language)) {
locale.setLocale(this.preferences.language);
}
};
var failure = function () {
return;
};
var callback = function () {
var projects = this.projects;
var languages = this.languages;
var preferences = this.preferences;
i18n.load(loadUrl.get('APP_URL') + '/res/i18n/' + locale.getLocale() + '/gui.properties', function () {
// loadUrl.load('/sitools/client-user/siteMap', function (){
portal = new sitools.Portal(projects, languages, preferences);
// });
});
};
userStorage.get("portal", filePath, this, success, failure, callback);
},
initAppliPortal : function (opts, callback) {
if (!Ext.isEmpty(Ext.util.Cookies.get('userLogin'))) {
var auth = Ext.util.Cookies.get('hashCode');
Ext.Ajax.defaultHeaders = {
"Authorization" : auth,
"Accept" : "application/json",
"X-User-Agent" : "Sitools"
};
} else {
Ext.Ajax.defaultHeaders = {
"Accept" : "application/json",
"X-User-Agent" : "Sitools"
};
}
Ext.QuickTips.init();
// this.callbacks[0](opts.siteMapRes, callback);
this.callSiteMapResource(opts.siteMapRes, callback);
//this.initProjects();
},
callSiteMapResource : function (res, cb) {
var callback;
if (this.autoChainAjaxRequest) {
callback = this.initProjects;
} else {
callback = cb;
}
loadUrl.load(res + '/siteMap', callback, this);
}
};
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
var ID = {
PANEL : {
MENU : 'menuPanelId',
TREE : 'treePanelId',
MAIN : 'mainPanelId',
HELP : 'helpPanelId'
},
CMP : {
TOOLBAR : 'toolbarId',
MENU : 'menuId'
},
WIN : {
LOGIN : 'loginWinId',
ORDER : 'orderWinId'
},
BOX : {
REG : 'regBoxId',
USER : 'userBoxId',
GROUP : 'groupBoxId',
FIREWALL : 'firewallBoxId'
},
PORTLET : {
PROJET : 'portletProjectId',
RECHERCHE : 'portletRecherceID',
FEEDS : 'portletFeedsId'
},
PORTALTREENAV : {
PROJET : 'navProjectId',
RECHERCHE : 'navRechercheId',
FEEDS : 'navFeedsId'
}
};
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/**
* Object to expose common tree Utils Methods
* @requires sitools.user.component.datasetOpensearch
* @requires sitools.user.component.forms.mainContainer
*/
/*global Ext, i18n, loadUrl, getDesktop, sitools, SitoolsDesk */
var commonTreeUtils = {
addShowData : function (node, dataset) {
node.appendChild({
id : "nodedata" + dataset.id,
text : i18n.get('label.dataTitle'),
winTitle : i18n.get('label.dataTitle') + " : " + dataset.name,
leaf : true,
type : "data",
datasetId : dataset.id,
columnModel : dataset.columnModel,
datasetName : dataset.name,
datasetDescription : dataset.description,
dataUrl : dataset.sitoolsAttachementForUsers,
dictionaryMappings : dataset.dictionaryMappings,
icon : loadUrl.get('APP_URL') + "/common/res/images/icons/tree_datasets.png",
datasetView : dataset.datasetView,
datasetViewConfig : dataset.datasetViewConfig,
sitoolsAttachementForUsers : dataset.sitoolsAttachementForUsers
});
},
addShowDefinition : function (node, dataset) {
node.appendChild({
text : i18n.get('label.definitionTitle'),
winTitle : i18n.get('label.definitionTitle') + " : " + dataset.name,
leaf : true,
type : "defi",
datasetId : dataset.id,
columnModel : dataset.columnModel,
datasetName : dataset.name,
dictionaryMappings : dataset.dictionaryMappings,
icon : loadUrl.get('APP_URL') + "/common/res/images/icons/tree_dictionary.png"
});
},
addOpensearch : function (node, dataset) {
node.appendChild({
text : i18n.get('label.opensearch'),
winTitle : i18n.get('label.opensearch') + " : " + dataset.name,
leaf : true,
type : "openSearch",
datasetId : dataset.id,
columnModel : dataset.columnModel,
datasetName : dataset.name,
dataUrl : dataset.sitoolsAttachementForUsers,
icon : loadUrl.get('APP_URL') + "/common/res/images/icons/toolbar_open_search.png"
});
},
addForm : function (node, dataset) {
node.appendChild({
text : i18n.get('label.forms'),
leaf : false,
children : [ {
leaf : true
} ],
datasetId : dataset.id,
columnModel : dataset.columnModel,
datasetName : dataset.name,
listeners : {
scope : this,
beforeexpand : function (node) {
var conn = new Ext.data.Connection();
conn.request({
url : dataset.sitoolsAttachementForUsers + '/forms?media=json',
success : function (response) {
node.removeAll(true);
var forms = Ext.decode(response.responseText);
if (!forms.success) {
Ext.msg.alert(i18n.get('label.warning'), forms.message);
return;
}
Ext.each(forms.data, function (form) {
node.appendChild({
leaf : true,
winTitle : i18n.get('label.forms') + " : " + dataset.name + "." + form.name,
dataset : dataset,
datasetId : dataset.id,
columnModel : dataset.columnModel,
datasetName : dataset.name,
dataUrl : dataset.sitoolsAttachementForUsers,
type : "form",
text : form.name,
formId : form.id,
formName : form.name,
formParameters : form.parameters,
formWidth : form.width,
formHeight : form.height,
formCss : form.css,
node : this,
icon : loadUrl.get('APP_URL') + "/common/res/images/icons/tree_forms.png",
datasetView : dataset.datasetView
});
});
}
});
}
}
});
},
addFeeds : function (node, dataset) {
node.appendChild({
text : i18n.get('label.feeds'),
leaf : false,
children : [ {
leaf : true
} ],
datasetId : dataset.id,
datasetName : dataset.name,
listeners : {
scope : this,
beforeexpand : function (node) {
var conn = new Ext.data.Connection();
conn.request({
url : dataset.sitoolsAttachementForUsers + '/feeds?media=json',
success : function (response) {
node.removeAll(true);
var feeds = Ext.decode(response.responseText);
if (!feeds.success) {
Ext.msg.alert(i18n.get('label.warning'), feeds.message);
return;
}
Ext.each(feeds.data, function (feed) {
node.appendChild({
leaf : true,
winTitle : i18n.get('label.feeds') + " : " + dataset.name + "." + feed.title,
type : "feeds",
text : feed.name,
datasetId : dataset.id,
feedId : feed.name,
dataUrl : dataset.sitoolsAttachementForUsers,
feedType : feed.feedType,
feedSource : feed.feedSource,
datasetName : dataset.name,
icon : loadUrl.get('APP_URL') + "/common/res/images/icons/rss.png"
});
});
}
});
}
}
});
},
/**
* Build the component regarding to the node,
* Load a window with this component into the SitoolsDesk
* @param node
*/
treeAction : function (node) {
var desktop = getDesktop();
var win = desktop.getWindow("wind" + node.id);
if (!win) {
var componentCfg, javascriptObject;
var windowConfig = {
datasetId : node.attributes.datasetId,
title : node.attributes.winTitle,
datasetName : node.attributes.datasetName,
datasetDescription : node.attributes.datasetDescription,
type : node.attributes.type,
saveToolbar : true,
toolbarItems : []
};
if (node.attributes.type === "data") {
//open the dataView according to the dataset Configuration.
// javascriptObject = eval(node.attributes.datasetView.jsObject);
javascriptObject = eval(SitoolsDesk.navProfile.getDatasetOpenMode(node.attributes));
Ext.apply(windowConfig, {
winWidth : 900,
winHeight : 400,
iconCls : "dataviews"
});
componentCfg = {
dataUrl : node.attributes.dataUrl,
datasetId : node.attributes.datasetId,
datasetCm : node.attributes.columnModel,
datasetName : node.attributes.datasetName,
dictionaryMappings : node.attributes.dictionaryMappings,
datasetViewConfig : node.attributes.datasetViewConfig,
preferencesPath : "/" + node.attributes.datasetName,
preferencesFileName : "datasetOverview",
sitoolsAttachementForUsers : node.attributes.sitoolsAttachementForUsers
};
}
if (node.attributes.type === "defi") {
javascriptObject = sitools.user.component.columnsDefinition;
Ext.apply(windowConfig, {
id : node.attributes.type + node.attributes.datasetId,
iconCls : "semantic"
});
componentCfg = {
datasetId : node.attributes.datasetId,
datasetCm : node.attributes.columnModel,
datasetName : node.attributes.datasetName,
dictionaryMappings : node.attributes.dictionaryMappings,
preferencesPath : "/" + node.attributes.datasetName,
preferencesFileName : "semantic"
};
}
if (node.attributes.type === "openSearch") {
javascriptObject = sitools.user.component.datasetOpensearch;
Ext.apply(windowConfig, {
id : node.attributes.type + node.attributes.datasetId,
iconCls : "openSearch"
});
componentCfg = {
datasetId : node.attributes.datasetId,
dataUrl : node.attributes.dataUrl,
datasetName : node.attributes.datasetName,
preferencesPath : "/" + node.attributes.datasetName,
preferencesFileName : "openSearch"
};
}
if (node.attributes.type === "form") {
javascriptObject = sitools.user.component.forms.mainContainer;
Ext.apply(windowConfig, {
id : node.attributes.type + node.attributes.datasetId + node.attributes.formId,
iconCls : "forms"
});
componentCfg = {
dataUrl : node.attributes.dataUrl,
dataset : node.attributes.dataset,
formId : node.attributes.formId,
formName : node.attributes.formName,
formParameters : node.attributes.formParameters,
formWidth : node.attributes.formWidth,
formHeight : node.attributes.formHeight,
formCss : node.attributes.formCss,
preferencesPath : "/" + node.attributes.datasetName + "/forms",
preferencesFileName : node.attributes.formName
};
}
if (node.attributes.type === "feeds") {
javascriptObject = sitools.widget.FeedGridFlux;
var url = node.attributes.dataUrl + "/clientFeeds/" + node.attributes.feedId;
Ext.apply(windowConfig, {
id : node.attributes.type + node.attributes.datasetId + node.attributes.feedId,
iconCls : "feedsModule"
});
componentCfg = {
datasetId : node.attributes.datasetId,
urlFeed : url,
feedType : node.attributes.feedType,
datasetName : node.attributes.datasetName,
feedSource : node.attributes.feedSource,
autoLoad : true
};
}
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, javascriptObject);
} else {
win.toFront();
}
}
};/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*
The MIT License
Copyright (c) 2009-2010 Niko Ni (bluepspower@163.com)
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.
*/
// namespace
Ext.ns('Ext.ux');
* @class Ext.ux.FisheyeMenu
* @extends-ext Ext.util.Observable
* @author Niko Ni (bluepspower@163.com)
* @demo http://cz9908.com/showcase/?item=fisheye-menu&p=1
* @demo-extra http://cz9908.com/showcase/?item=desktop-fisheye&p=1
* @version v0.3
* @create 2009-06-26
* @update 2010-02-14
*
* Evolution : 2010-06
*
* @author a.labeau
*
* // Example object item:
* {
* text: 'some text',
* imagePath: 'some image path',
* url: 'some url (optional)',
* tip: 'some tip (optional)',
* target: 'target element (optional)'
* }
*
*/
Ext.ux.FisheyeMenu = Ext.extend(Ext.util.Observable, {
//------------------------------------------------------------
// config options
//------------------------------------------------------------
* @cfg {Array} items Array of fisheye menu config object items.
*/
items : [],
* @cfg {Mixed} renderTo The container element.
*/
renderTo : document.body,
* @cfg {Number} itemWidth The minimum width for each menu item.
*/
itemWidth : 50,
* @cfg {Number} vicinity The distance from element that make item interaction.
*/
vicinity : 35,
* @cfg {String} hAlign Horizontal alignment (left|center|right).
*/
hAlign : 'center',
* @cfg {String} vAlign Vertical alignment (top|bottom).
*/
vAlign : 'bottom',
* @cfg {Boolean} showTitle To show menu item title or not.
*/
showTitle : true,
//------------------------------------------------------------
// class constructor
//------------------------------------------------------------
* @constructor
* @param config
* @private
*/
constructor : function(config) {
Ext.apply(this, config);
Ext.ux.FisheyeMenu.superclass.constructor.call(this);
// add custom event
this.addEvents(
* @event change
* Fires when fisheye menu container is clicked
* @param {Ext.ux.FisheyeMenu} this
* @param {Object} targetItem
* @param {Number} index
*/
'change'
);
// initialize
this.init();
},
//------------------------------------------------------------
// public/private methods
//------------------------------------------------------------
* @private
*/
init : function() {
// properties
this.el = Ext.get(this.renderTo);
// init markup
this.initMarkup();
// init events
this.initEvents();
},
* @private
*/
initMarkup : function() {
// set necessary css class
this.setClass();
// for wrap class
this.el.addClass(this.wrapCls);
// fisheye menu container
this.containerEl = this.el.createChild({
tag : 'div',
cls : 'ux-fisheye-menu-container ' + this.vAlignCls
});
var sId = this.el.getAttribute('id') || Ext.id();
// build fisheye menu items
Ext.each(this.items, function(item) {
var sTitle = this.showTitle === true ? (item.tip || item.text) : '';
var arr = [{
tag : 'span',
html : item.text
}, {
tag : 'img',
src : item.imagePath,
alt : sTitle
}];
if(this.vOrient == 'top') {
arr = arr.reverse();
}
this.containerEl.createChild({
tag : 'a',
//id fisheyeMenuItem = fisheye... + module ID
id : sId + '-' + item.id,
cls : 'ux-fisheye-menu-item ' + this.vAlignCls,
//href : item.url || '#',
href : '#',
onClick : "javascript : " + item.fct || "void(0);",
title : sTitle,
//target : item.target || '_blank',
children : arr
});
}, this);
this.menuItems = this.containerEl.select('a.ux-fisheye-menu-item');
this.itemCount = this.menuItems.getCount();
// render UI
this.onRender();
},
* @private
*/
initEvents : function() {
// hover or not
this.menuItems.on('mouseover', this.onItemHover, this);
this.menuItems.on('mouseout', this.onItemOut, this);
// for viewport mousemove event
Ext.getBody().on('mousemove', this.onItemMove, this);
// for viewport resize event
Ext.EventManager.on(window, 'resize', this.onRender, this);
// for custom event
this.containerEl.on('click', function(ev, t) {
if(t.href.slice(-1) == '#') {
ev.preventDefault();
}
var index = parseInt(t.id.split('-').pop(), 10);
this.fireEvent('change', t, index);
}, this, {
delegate : 'a'
});
},
* @private
*/
setClass : function() {
this.vOrient = this.vAlign.toLowerCase();
this.wrapCls = 'menu-wrap-' + this.vOrient;
this.vAlignCls = 'menu-align-' + this.vOrient;
},
* @private
*/
onItemMove : function(ev, t) {
// pointer
var p = ev.getXY(),
posX,
posY,
increment = 0;
switch(this.hAlign.toLowerCase()) {
case 'left':
posX = p[0] - this.pos[0];
break;
case 'right':
posX = p[0] - this.pos[0] - this.el.getWidth() + this.itemWidth * this.itemCount;
break;
default:
posX = p[0] - this.pos[0] - (this.el.getWidth() - this.itemWidth * this.itemCount)/2 - this.itemWidth/2;
break;
}
posY = Math.pow(p[1] - this.pos[1] - this.el.getHeight()/2, 2);
this.menuItems.each(function(item, all, index) {
// distance mathematical calculation reference from http://interface.eyecon.ro
var d = Math.sqrt(Math.pow(posX - index * this.itemWidth, 2) + posY);
d -= this.itemWidth/2;
d = d < 0 ? 0 : d;
d = d > this.vicinity ? this.vicinity : d;
d = this.vicinity - d;
var extraWidth = this.itemWidth * d / this.vicinity;
item.setStyle({
left : (this.itemWidth + 3) * index + increment + 'px',
width : this.itemWidth + extraWidth + 'px'
});
increment += extraWidth;
}, this);
this.setPosContainer(increment);
},
* @private
*/
onItemHover : function(ev, t) {
var target = Ext.get(t);
target = target.is('img') ? target.up('a') : target;
var itemText = target.child('span');
if(itemText) {
itemText.show();
}
},
* @private
*/
onItemOut : function(ev, t) {
var target = Ext.get(t);
target = target.is('img') ? target.up('a') : target;
var itemText = target.child('span');
if(itemText) {
itemText.hide();
}
},
* @private
*/
onRender : function() {
this.pos = this.el.getXY();
this.setPosContainer(0);
this.setPosMenuItems();
},
* @private
*/
doAlignment : function() {
var aWrapCls = ['menu-wrap-top', 'menu-wrap-bottom'],
aAlignCls = ['menu-align-top', 'menu-align-bottom'];
this.setClass();
this.el.removeClass(aWrapCls).addClass(this.wrapCls);
this.containerEl.removeClass(aAlignCls).addClass(this.vAlignCls);
this.menuItems.each(function(item, all, index) {
var itemText = item.child('span');
var itemTextCfg = {
tag : 'span',
html : itemText.dom.innerHTML
};
item.removeClass(aAlignCls).addClass(this.vAlignCls);
if(this.vAlign.toLowerCase() == 'top') {
if(!item.last().is('span')) {
item.createChild(itemTextCfg);
itemText.remove();
}
} else {
if(!item.first().is('span')) {
item.insertFirst(itemTextCfg);
itemText.remove();
}
}
}, this);
},
* Set alignment
* @param {Object} cfg Config options
*/
setAlign : function(cfg) {
var isChange = false;
// for horizontal alignment
if(cfg.hAlign) {
var sHAlign = cfg.hAlign.toLowerCase();
if(sHAlign != this.hAlign.toLowerCase()) {
this.hAlign = sHAlign;
isChange = true;
}
}
// for vertical alignment
if(cfg.vAlign) {
var sVAlign = cfg.vAlign.toLowerCase();
if(sVAlign != this.vAlign.toLowerCase()) {
this.vAlign = sVAlign;
isChange = true;
}
}
if(isChange) {
this.doAlignment();
this.onRender();
}
},
* @private
*/
setPosContainer : function(increment) {
var iLeft;
switch(this.hAlign.toLowerCase()) {
case 'left':
iLeft = - increment/this.itemCount;
break;
case 'right':
iLeft = (this.el.getWidth() - this.itemWidth * this.itemCount) - increment/2;
break;
default:
iLeft = (this.el.getWidth() - this.itemWidth * this.itemCount)/2 - increment/2;
break;
}
this.containerEl.setStyle({
left : iLeft + 'px',
width : this.itemWidth * this.itemCount + increment + 'px'
});
},
* @private
*/
setPosMenuItems : function() {
this.menuItems.each(function(item, all, index) {
item.setStyle({
left : (this.itemWidth + 3) * index + 'px',
width : this.itemWidth + 'px'
});
}, this);
}
}); // end of Ext.ux.FisheyeMenu
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
// namespace
//Ext.ns('Ext.ux');
* @class Ext.ux.FisheyeMenuExtention
* @extend Ext.ux.FisheyeMenu
* @author hello2008
* @version v0.2
* @create 2010-04-22
* @update 2010-04-26
*
* Evolution
* @author a.labeau
* @update 2010-06
*/
Ext.ux.FisheyeMenuExtention = Ext.extend(Ext.ux.FisheyeMenu, {
//------------------------------------------------------------
// class constructor
//------------------------------------------------------------
* @constructor
* @param config
* @private
*/
constructor : function(config) {
Ext.apply(this, config);
Ext.ux.FisheyeMenuExtention.superclass.constructor.call(this);
},
//------------------------------------------------------------
// public/private methods
//------------------------------------------------------------
* Add menu item
* @param {Object} item Config option
*/
addItem : function(item) {
var sId = this.el.getAttribute('id') || Ext.id();
// build fisheye menu item
var sTitle = this.showTitle === true ? (item.tip || item.text) : '';
var arr = [{
tag : 'span',
html : item.text
}, {
tag : 'img',
src : item.imagePath,
alt : sTitle
}];
if(this.vOrient == 'top') {
arr = arr.reverse();
}
this.containerEl.createChild({
tag : 'a',
id : sId + '-' + item.id,
cls : 'ux-fisheye-menu-item ' + this.vAlignCls,
href : item.url || '#',
title : sTitle,
target : item.target || '_blank',
onClick : "javascript : "+item.fct,
children : arr
});
this.menuItems = this.containerEl.select('a.ux-fisheye-menu-item');
this.itemCount = this.menuItems.getCount();
// render UI
this.onRender();
// reset events, hover or not
this.menuItems.on('mouseover', this.onItemHover, this);
this.menuItems.on('mouseout', this.onItemOut, this);
},
* Remove specific menu item
* @param {Number} index The specific item index
*/
removeItem : function(idModule) {
var sId = 'fisheye-menu-bottom-' + idModule;
menuItem = Ext.get(sId);
if(!menuItem) {
alert('cannot find the menu item!');
} else {
menuItem.remove();
this.menuItems = this.containerEl.select('a.ux-fisheye-menu-item');
this.itemCount = this.menuItems.getCount();
// render UI
this.onRender();
}
}
}); // end of Ext.ux.FisheyeMenuExtention
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n,document*/
/*!
* Ext JS Library 3.2.1
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
* <p>SAMPLE USAGE:</p>
*
* <pre><code>
this.startMenu = new Ext.ux.StartMenu({ iconCls: 'user', height: 300, shadow: true, title: get_cookie('memberName'), width: 300 });
this.startMenu.add({ text: 'Grid Window', iconCls:'icon-grid', handler :
this.createWindow, scope: this });
this.startMenu.addTool({
text:'Logout',
iconCls:'logout',
handler:function(){
window.location = "logout.php";
},
scope:this
});
* </code></pre>
* @class Ext.ux.StartMenu
* @extends Ext.menu.Menu A start menu object.
* @constructor Creates a new StartMenu
* @cfg {Object}
* config Configuration options
*
*
*/
Ext.namespace("Ext.ux");
Ext.ux.StartMenu = Ext.extend(Ext.menu.Menu, {
initComponent : function (config) {
Ext.ux.StartMenu.superclass.initComponent.call(this, config);
var tools = this.toolItems;
this.toolItems = new Ext.util.MixedCollection();
if (tools) {
this.addTool.apply(this, tools);
}
},
// private
onRender : function (ct, position) {
Ext.ux.StartMenu.superclass.onRender.call(this, ct, position);
var el = this.el.addClass('ux-start-menu');
var header = el.createChild({
tag : "div",
cls : "x-window-header x-unselectable x-panel-icon " + this.iconCls
});
this.header = header;
var headerText = header.createChild({
tag : "span",
cls : "x-window-header-text"
});
var tl = header.wrap({
cls : "ux-start-menu-tl"
});
var tr = header.wrap({
cls : "ux-start-menu-tr"
});
var tc = header.wrap({
cls : "ux-start-menu-tc"
});
this.menuBWrap = el.createChild({
tag : "div",
cls : "x-window-body x-border-layout-ct ux-start-menu-body"
});
var ml = this.menuBWrap.wrap({
cls : "ux-start-menu-ml"
});
var mc = this.menuBWrap.wrap({
cls : "x-window-mc ux-start-menu-bwrap"
});
this.menuPanel = this.menuBWrap.createChild({
tag : "div",
cls : "x-panel x-border-panel ux-start-menu-apps-panel"
});
this.toolsPanel = this.menuBWrap.createChild({
tag : "div",
cls : "x-panel x-border-panel ux-start-menu-tools-panel"
});
var bwrap = ml.wrap({
cls : "x-window-bwrap"
});
var bc = bwrap.createChild({
tag : "div",
cls : "ux-start-menu-bc"
});
var bl = bc.wrap({
cls : "ux-start-menu-bl x-panel-nofooter"
});
var br = bc.wrap({
cls : "ux-start-menu-br"
});
this.ul.appendTo(this.menuPanel);
var toolsUl = this.toolsPanel.createChild({
tag : "ul",
cls : "x-menu-list"
});
this.mon(toolsUl, 'click', this.onClick, this);
this.mon(toolsUl, 'mouseover', this.onMouseOver, this);
this.mon(toolsUl, 'mouseout', this.onMouseOut, this);
if (this.item) {
this.items.each(function (item) {
item.parentMenu = this;
}, this);
}
this.toolItems.each(function (item) {
if (!Ext.isEmpty(item.text)) {
item.text = i18n.get(item.text);
}
var li = document.createElement("li");
li.className = "x-menu-list-item";
toolsUl.dom.appendChild(li);
item.render(li);
item.parentMenu = this;
}, this);
this.toolsUl = toolsUl;
this.menuBWrap.setStyle('position', 'relative');
this.menuBWrap.setHeight(this.height - 28);
this.menuPanel.setStyle({
padding : '2px',
position : 'absolute',
overflow : 'auto'
});
this.toolsPanel.setStyle({
padding : '2px 4px 2px 2px',
position : 'absolute',
overflow : 'auto'
});
this.setTitle(this.title);
},
// private
findTargetItem : function (e) {
var t = e.getTarget(".x-menu-list-item", this.ul, true);
if (t && t.menuItemId) {
if (this.items.get(t.menuItemId)) {
return this.items.get(t.menuItemId);
} else {
return this.toolItems.get(t.menuItemId);
}
}
},
* Displays this menu relative to another element
*
* @param {Mixed}
* element The element to align to
* @param {String}
* position (optional) The {@link Ext.Element#alignTo} anchor
* position to use in aligning to the element (defaults to
* this.defaultAlign)
* @param {Ext.ux.StartMenu}
* parentMenu (optional) This menu's parent menu, if applicable
* (defaults to undefined)
*/
show : function (el, pos, parentMenu) {
this.parentMenu = parentMenu;
if (!this.el) {
this.render();
}
this.fireEvent("beforeshow", this);
this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
var tPanelWidth = 100;
var box = this.menuBWrap.getBox();
this.menuPanel.setWidth(box.width - tPanelWidth);
this.menuPanel.setHeight(box.height);
this.toolsPanel.setWidth(tPanelWidth);
this.toolsPanel.setX(box.x + box.width - tPanelWidth);
this.toolsPanel.setHeight(box.height);
},
addTool : function () {
var a = arguments, l = a.length, item;
for (var i = 0; i < l; i++) {
var el = a[i];
if (el.render) { // some kind of Item
item = this.addToolItem(el);
} else if (typeof el == "string") { // string
if (el == "separator" || el == "-") {
item = this.addToolSeparator();
} else {
item = this.addText(el);
}
} else if (el.tagName || el.el) { // element
item = this.addElement(el);
} else if (typeof el == "object") { // must be menu item config?
item = this.addToolMenuItem(el);
}
}
return item;
},
* Adds a separator bar to the Tools
*
* @return {Ext.menu.Item} The menu item that was added
*/
addToolSeparator : function () {
return this.addToolItem(new Ext.menu.Separator({
itemCls : 'ux-toolmenu-sep'
}));
},
addToolItem : function (item) {
item.text = i18n.get(item.text);
this.toolItems.add(item);
if (this.ul) {
var li = document.createElement("li");
li.className = "x-menu-list-item";
this.ul.dom.appendChild(li);
item.render(li, this);
this.delayAutoWidth();
}
return item;
},
addToolMenuItem : function (config) {
if (!(config instanceof Ext.menu.Item)) {
if (typeof config.checked == "boolean") { // must be check menu
// item config?
config = new Ext.menu.CheckItem(config);
} else {
config = new Ext.menu.Item(config);
}
}
return this.addToolItem(config);
},
setTitle : function (title, iconCls) {
this.title = title;
this.header.child('span').update(title);
return this;
}
});
Ext.ns("sitools.common");
sitools.common._PreviewBox = Ext.extend(Ext.BoxComponent, {
inited : false,
defaultZIndex : 13000,
defaultLeft : 0,
defaultTop : 35,
hideTop : 25,
boxWidth : 250,
cloneWinMaxWidth : 220,
cloneWinMaxHeight : 116,
hideDelay : 500,
showDelay : 500,
constructor : function() {
sitools.common._PreviewBox.superclass.constructor.call(this, {
renderTo : document.body,
cls : "taskbar-previewbox",
hidden : true
});
this.inited = false;
this.hoverCount = 0
},
createBoxElements : function() {
var el = this.getEl(), box;
this.boxMl = el.createChild( {
tag : "div",
cls : "taskbar-previewbox-ml"
});
this.boxMr = this.boxMl.createChild( {
tag : "div",
cls : "taskbar-previewbox-mr"
});
this.boxMc = this.boxMr.createChild( {
tag : "div",
cls : "taskbar-previewbox-mc"
});
this.arrow = el.createChild( {
tag : "div",
cls : "taskbar-previewbox-arrow"
});
box = this.boxMc;
this.desc = box.createChild( {
tag : "div",
cls : "taskbar-previewbox-desc"
});
box.createChild( {
tag : "hr"
});
this.win = box.createChild( {
tag : "div",
cls : "taskbar-previewbox-win"
});
this.inited = true;
},
// onTaskbarClick : function() {
// this.hideBox(true)
// },
showBox : function(boxConfig) {
if (!this.isEnabled()) {
return
}
this.needShowBox = true;
this.hoverCount += 1;
this.doShowBox.defer(300, this, [ boxConfig, this.hoverCount ]);
},
doShowBox : function(boxConfig, hoverCount) {
var win, winEl, previewBox, center;
if (!boxConfig || !boxConfig.win || !boxConfig.centerX) {
return;
}
if (this.hoverCount !== hoverCount) {
return;
}
if (!this.needShowBox) {
return;
}
if (!this.inited) {
this.createBoxElements()
}
center = Ext.isNumber(boxConfig.centerX) ? boxConfig.centerX : this.defaultLeft;
win = boxConfig.win;
winEl = win.getEl();
this.desc.update(boxConfig.win.title);
if (this.clonedEl) {
this.clonedEl.remove()
}
this.clonedEl = this.getClonedEl(win);
this.clonedEl.show();
this.win.appendChild(this.clonedEl);
previewBox = this.getEl();
var top = Ext.get("ux-taskbar").getTop() - previewBox.getHeight() - 10;
if (this.isVisible()) {
previewBox.setTop(top);
this.show();
previewBox.shift( {
left : center - (this.boxWidth / 2),
opacity : 1,
duration : 0.3
})
} else {
previewBox.setLeftTop(center - (this.boxWidth / 2), top - 200);
previewBox.setOpacity(0);
this.show();
top = Ext.get("ux-taskbar").getTop() - previewBox.getHeight() - 10;
previewBox.shift( {
top : top,
opacity : 1,
duration : 0.8
});
}
this.hoverCount = 0;
},
hideBox : function(a) {
if (!this.isEnabled()) {
return
}
this.needShowBox = false;
(function() {
if (this.needShowBox) {
return
}
this.doHideBox(a)
}).defer((a === true) ? 0 : 300, this);
},
doHideBox : function(b) {
var c;
var a = function() {
if (this.needShowBox) {
return
}
this.hide();
};
if (this.clonedEl) {
this.clonedEl.remove()
}
this.hoverCount = 0;
if (b === true) {
a.call(this);
return
}
c = this.getEl();
var top = Ext.get("ux-taskbar").getTop() - c.getHeight() - 20;
c.shift( {
top : top,
opacity : 0,
duration : 0.2,
scope : this,
callback : a
});
},
getClonedEl : function(win) {
var c = 0;
var h = 0;
var el = win.getEl();
var newHtmlEl = el.dom.cloneNode(true);
newHtmlEl.removeAttribute("id");
var newEl = Ext.get(newHtmlEl);
newEl.visibilityCls = "x-hide-display";
newEl._previewMask = newEl.createChild( {
tag : "div",
cls : "taskbar-previewbox-win-mask"
});
var size = el.getSize();
if (size.height === 0 && size.width === 0) {
size = SitoolsDesk.getDesktop().getDesktopEl().getSize();
}
var d = this.cloneWinMaxWidth / size.width;
c = (this.cloneWinMaxHeight - size.height * d) / 2;
if ((size.height * d) > this.cloneWinMaxHeight) {
d = this.cloneWinMaxHeight / size.height;
c = 0;
h = (this.cloneWinMaxWidth - size.width * d) / 2
}
d = Math.min(d, 1);
newEl.addClass("taskbar-previewbox-win-transform");
newEl.setStyle("-webkit-transform", String.format("scale({0})", d));
newEl.setStyle("-moz-transform", String.format("scale({0})", d));
newEl.setStyle("-o-transform", String.format("scale({0})", d));
newEl.setStyle("transform", String.format("scale({0})", d));
newEl.setLeftTop(h, c);
return newEl;
},
isEnabled : function() {
return true;
}
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n,document*/
/*!
* Ext JS Library 3.2.1
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
/**
* @class Ext.ux.TaskBar
* @extends Ext.util.Observable
*/
Ext.ux.TaskBar = function (app, enableWarning) {
this.app = app;
this.init(enableWarning);
};
Ext.extend(Ext.ux.TaskBar, Ext.util.Observable, {
init : function (enableWarning) {
// this.startMenu = new Ext.ux.StartMenu(Ext.apply({
// iconCls : 'user',
// height : 300,
// shadow : true,
// title : 'Jack Slocum',
// width : 300
// }, this.app.startConfig));
// this.startBtn = new Ext.Button({
// text : i18n.get('label.start'),
// id : 'ux-startbutton',
// iconCls : 'start',
// menu : this.startMenu,
// menuAlign : 'bl-tl',
// renderTo : 'ux-taskbar-start',
// clickEvent : 'mousedown',
// template : new Ext.Template('<table cellspacing="0" class="x-btn"><tbody class="{1}"><tr>',
// '<td class="ux-startbutton-left"><i> </i></td>',
// '<td class="ux-startbutton-center"><em class="{2} unselectable="on">',
// '<button class="x-btn-text" type="{0}" style="height:30px;"></button>', '</em></td>',
// '<td class="ux-startbutton-right"><i> </i></td>', '</tr></tbody></table>')
// });
// var width = this.startBtn.getEl().getWidth() + 10;
// var sbBox = new Ext.BoxComponent({
// el : 'ux-taskbar-start',
// id : 'TaskBarStart',
// minWidth : width,
// region : 'west',
// split : true,
// width : width
// });
this.staticButtonPanel = new Ext.ux.TaskButtonsPanel({
el : 'ux-staticbuttons-panel',
id : 'TaskBarStaticButtons',
region : 'center',
style : 'overflow:hidden !important; height: 30px; width: 100% !important;',
listeners : {
addNewWindow : function () {
this.items[0].action = "minimize";
}
}
});
this.tbPanel = new Ext.ux.TaskButtonsPanel({
el : 'ux-taskbuttons-panel',
id : 'TaskBarButtons',
region : 'center',
style : 'overflow:hidden !important',
enableWarning : enableWarning
});
var container = new Ext.ux.TaskBarContainer({
el : 'ux-taskbar',
layout : 'border',
items : [ this.staticButtonPanel, this.tbPanel ]
});
return this;
},
addTaskButton : function (win) {
var btn = this.tbPanel.addButton(win, 'ux-taskbuttons-panel');
this.setActiveButton(btn);
return btn;
this.staticButtonPanel.fireEvent("addNewWindow");
},
removeTaskButton : function (btn) {
this.tbPanel.removeButton(btn);
},
setActiveButton : function (btn) {
this.tbPanel.setActiveButton(btn);
},
getActiveButton : function () {
return this.tbPanel.getActiveButton();
},
getPreviousBtn : function (btn) {
return this.tbPanel.getPreviousBtn(btn);
},
getNextBtn : function (btn) {
return this.tbPanel.getNextBtn(btn);
},
getAllTaskButtons : function () {
return this.tbPanel.items;
},
setEnableWarning : function (enableWarning) {
this.tbPanel.enableWarning = enableWarning;
}
});
/**
* @class Ext.ux.TaskBarContainer
* @extends Ext.Container
*/
Ext.ux.TaskBarContainer = Ext.extend(Ext.Container, {
initComponent : function () {
Ext.ux.TaskBarContainer.superclass.initComponent.call(this);
this.el = Ext.get(this.el) || Ext.getBody();
this.el.setHeight = Ext.emptyFn;
this.el.setWidth = Ext.emptyFn;
this.el.setSize = Ext.emptyFn;
this.el.setStyle({
overflow : 'hidden',
margin : '0',
border : '0 none'
});
this.el.dom.scroll = 'no';
this.allowDomMove = false;
this.autoWidth = true;
this.autoHeight = true;
Ext.EventManager.onWindowResize(this.fireResize, this);
this.renderTo = this.el;
this.listeners = {
maximizeDesktop : this.onMaximizeDesktop
}
},
fireResize : function (w, h) {
this.onResize(w, h, w, h);
this.fireEvent('resize', this, w, h, w, h);
},
onMaximizeDesktop : function () {
console.log('max');
}
});
/**
* @class Ext.ux.TaskButtonsPanel
* @extends Ext.BoxComponent
*/
Ext.ux.TaskButtonsPanel = Ext.extend(Ext.BoxComponent, {
activeButton : null,
enableScroll : true,
scrollIncrement : 0,
scrollRepeatInterval : 400,
scrollDuration : .35,
animScroll : true,
resizeButtons : false,
buttonWidth : 168,
minButtonWidth : 118,
buttonMargin : 2,
buttonWidthSet : false,
initComponent : function () {
Ext.ux.TaskButtonsPanel.superclass.initComponent.call(this);
this.on('resize', this.delegateUpdates);
this.items = [];
this.stripWrap = Ext.get(this.el).createChild({
cls : 'ux-taskbuttons-strip-wrap',
cn : {
tag : 'ul',
cls : 'ux-taskbuttons-strip'
}
});
this.stripSpacer = Ext.get(this.el).createChild({
cls : 'ux-taskbuttons-strip-spacer'
});
this.strip = new Ext.Element(this.stripWrap.dom.firstChild);
this.edge = this.strip.createChild({
tag : 'li',
cls : 'ux-taskbuttons-edge'
});
this.strip.createChild({
cls : 'x-clear'
});
if (this.enableWarning) {
this.warningCt = this.edge.createChild({
tag : 'div',
cls : "ux-taskbar-warningCt"
});
}
},
addButton : function (win) {
var li = this.strip.createChild({
tag : 'li'
}, this.edge); // insert before the edge
var btn = new Ext.ux.TaskBar.TaskButton(win, li);
this.items.push(btn);
if (!this.buttonWidthSet) {
this.lastButtonWidth = btn.container.getWidth();
}
this.setActiveButton(btn);
return btn;
},
addStaticButton : function (button) {
var li = this.strip.createChild({
tag : 'li'
}, this.edge); // insert before the edge
button.render(li);
this.items.push(button);
},
removeButton : function (btn) {
var li = document.getElementById(btn.container.id);
Ext.fly(li).ghost('b', {
duration : .5,
remove : true,
callback : function () {
btn.destroy();
}
});
var s = [];
for (var i = 0, len = this.items.length; i < len; i++) {
if (this.items[i] != btn) {
s.push(this.items[i]);
}
}
this.items = s;
this.delegateUpdates();
},
setActiveButton : function (btn) {
if (this.activeButton) {
Ext.fly(this.activeButton.el).removeClass('active-win');
}
Ext.fly(btn.el).addClass('active-win');
this.activeButton = btn;
this.delegateUpdates();
},
getActiveButton : function() {
return this.activeButton;
},
getNextBtn : function (btn) {
var result;
try {
for (var i = 0, len = this.items.length; i < len; i++) {
if (this.items[i] == btn) {
result = this.items[i+1];
}
}
return result;
}
catch (err) {
return null;
}
},
getPreviousBtn : function (btn) {
var result;
try {
for (var i = 0, len = this.items.length; i < len; i++) {
if (this.items[i] == btn) {
result = this.items[i-1];
}
}
return result;
}
catch (err) {
return null;
}
},
delegateUpdates : function () {
/*
* if(this.suspendUpdates){ return; }
*/
if (this.resizeButtons && this.rendered) {
this.autoSize();
}
if (this.enableScroll && this.rendered) {
this.autoScroll();
}
if (this.enableWarning) {
if (this.items.length > 10) {
this.removeButton(this.items[0]);
}
if (this.items.length == 10) {
this.warningCt.addClass('x-warning');
this.warningTT = new Ext.ToolTip({
target: this.warningCt,
width: 200,
anchor : "bottom",
cls : "x-form-invalid-tip",
html : i18n.get('label.tooManyPanelsOpened'),
dismissDelay: 5000 // auto hide after 15 seconds
});
}
else {
if (this.warningTT) {
this.warningTT.destroy();
}
this.warningCt.removeClass("x-warning");
}
}
},
autoSize : function () {
var count = this.items.length;
var ow = this.el.dom.offsetWidth;
var aw = this.el.dom.clientWidth;
if (!this.resizeButtons || count < 1 || !aw) { // !aw for display:none
return;
}
var each = Math.max(Math.min(Math.floor((aw - 4) / count) - this.buttonMargin, this.buttonWidth),
this.minButtonWidth); // -4 for float errors in IE
var btns = this.stripWrap.dom.getElementsByTagName('button');
this.lastButtonWidth = Ext.get(btns[0].id).findParent('li').offsetWidth;
for (var i = 0, len = btns.length; i < len; i++) {
var btn = btns[i];
var tw = Ext.get(btns[i].id).findParent('li').offsetWidth;
var iw = btn.offsetWidth;
btn.style.width = (each - (tw - iw)) + 'px';
}
},
autoScroll : function () {
var count = this.items.length;
var ow = this.el.dom.offsetWidth;
var tw = this.el.dom.clientWidth;
var wrap = this.stripWrap;
var cw = wrap.dom.offsetWidth;
var pos = this.getScrollPos();
var l = this.edge.getOffsetsTo(this.stripWrap)[0] + pos;
if (!this.enableScroll || count < 1 || cw < 20) { // 20 to prevent
// display:none
// issues
return;
}
wrap.setWidth(tw); // moved to here because of problem in Safari
if (l <= tw) {
wrap.dom.scrollLeft = 0;
// wrap.setWidth(tw); moved from here because of problem in Safari
if (this.scrolling) {
this.scrolling = false;
this.el.removeClass('x-taskbuttons-scrolling');
this.scrollLeft.hide();
this.scrollRight.hide();
}
} else {
if (!this.scrolling) {
this.el.addClass('x-taskbuttons-scrolling');
}
tw -= wrap.getMargins('lr');
wrap.setWidth(tw > 20 ? tw : 20);
if (!this.scrolling) {
if (!this.scrollLeft) {
this.createScrollers();
} else {
this.scrollLeft.show();
this.scrollRight.show();
}
}
this.scrolling = true;
if (pos > (l - tw)) { // ensure it stays within bounds
wrap.dom.scrollLeft = l - tw;
} else { // otherwise, make sure the active button is still
// visible
this.scrollToButton(this.activeButton, true); // true to
// animate
}
this.updateScrollButtons();
}
},
createScrollers : function () {
var h = this.el.dom.offsetHeight; // var h =
// this.stripWrap.dom.offsetHeight;
// left
var sl = this.el.insertFirst({
cls : 'ux-taskbuttons-scroller-left'
});
sl.setHeight(h);
sl.addClassOnOver('ux-taskbuttons-scroller-left-over');
this.leftRepeater = new Ext.util.ClickRepeater(sl, {
interval : this.scrollRepeatInterval,
handler : this.onScrollLeft,
scope : this
});
this.scrollLeft = sl;
// right
var sr = this.el.insertFirst({
cls : 'ux-taskbuttons-scroller-right'
});
sr.setHeight(h);
sr.addClassOnOver('ux-taskbuttons-scroller-right-over');
this.rightRepeater = new Ext.util.ClickRepeater(sr, {
interval : this.scrollRepeatInterval,
handler : this.onScrollRight,
scope : this
});
this.scrollRight = sr;
},
getScrollWidth : function () {
return this.edge.getOffsetsTo(this.stripWrap)[0] + this.getScrollPos();
},
getScrollPos : function () {
return parseInt(this.stripWrap.dom.scrollLeft, 10) || 0;
},
getScrollArea : function () {
return parseInt(this.stripWrap.dom.clientWidth, 10) || 0;
},
getScrollAnim : function () {
return {
duration : this.scrollDuration,
callback : this.updateScrollButtons,
scope : this
};
},
getScrollIncrement : function () {
return (this.scrollIncrement || this.lastButtonWidth + 2);
},
/*
* getBtnEl : function(item){ return document.getElementById(item.id); },
*/
scrollToButton : function (item, animate) {
item = item.el.dom.parentNode; // li
if (!item) {
return;
}
var el = item; // this.getBtnEl(item);
var pos = this.getScrollPos(), area = this.getScrollArea();
var left = Ext.fly(el).getOffsetsTo(this.stripWrap)[0] + pos;
var right = left + el.offsetWidth;
if (left < pos) {
this.scrollTo(left, animate);
} else if (right > (pos + area)) {
this.scrollTo(right - area, animate);
}
},
scrollTo : function (pos, animate) {
this.stripWrap.scrollTo('left', pos, animate ? this.getScrollAnim() : false);
if (!animate) {
this.updateScrollButtons();
}
},
onScrollRight : function () {
var sw = this.getScrollWidth() - this.getScrollArea();
var pos = this.getScrollPos();
var s = Math.min(sw, pos + this.getScrollIncrement());
if (s != pos) {
this.scrollTo(s, this.animScroll);
}
},
onScrollLeft : function () {
var pos = this.getScrollPos();
var s = Math.max(0, pos - this.getScrollIncrement());
if (s != pos) {
this.scrollTo(s, this.animScroll);
}
},
updateScrollButtons : function () {
var pos = this.getScrollPos();
this.scrollLeft[pos === 0 ? 'addClass' : 'removeClass']('ux-taskbuttons-scroller-left-disabled');
this.scrollRight[pos >= (this.getScrollWidth() - this.getScrollArea()) ? 'addClass' : 'removeClass']
('ux-taskbuttons-scroller-right-disabled');
}
});
/**
* @class Ext.ux.TaskBar.TaskButton
* @extends Ext.Button
*/
Ext.ux.TaskBar.TaskButton = function (win, el) {
this.win = win;
Ext.ux.TaskBar.TaskButton.superclass.constructor.call(this, {
iconCls : win.iconCls,
// text : Ext.util.Format.ellipsis(win.title, 12),
renderTo : el,
handler : function (btn) {
SitoolsDesk.navProfile.taskbar.handleTaskButton.call(this, btn);
},
// clickEvent : 'mousedown',
template : new Ext.Template('<table cellspacing="0" class="x-btn {3}"><tbody><tr>',
'<td class="ux-taskbutton-center"><em class="{5} unselectable="on">',
'<button class="x-btn-text {2}" type="{1}" style="height:28px;">{0}</button>', '</em></td>',
"</tr></tbody></table>")
});
};
Ext.extend(Ext.ux.TaskBar.TaskButton, Ext.Button, {
scale : "medium",
width : 50,
initButtonEl : function() {
Ext.ux.TaskBar.TaskButton.superclass.initButtonEl.apply(this, arguments);
// this.mon(this.el, "contextmenu", this.onContextMenu, this);
this.mon(this.el, "mouseover", this.onMouseOverHandler, this);
this.mon(this.el, "mouseout", this.onMouseOutHandler, this);
},
onRender : function () {
Ext.ux.TaskBar.TaskButton.superclass.onRender.apply(this, arguments);
this.cmenu = new Ext.menu.Menu({
items : SitoolsDesk.navProfile.taskbar.getContextMenuItems.call(this)
});
this.cmenu.on('beforeshow', function () {
SitoolsDesk.navProfile.taskbar.beforeShowCtxMenu.call(this);
}, this);
this.el.on('contextmenu', function (e) {
e.stopEvent();
if (!this.cmenu.el) {
this.cmenu.render();
}
var xy = e.getXY();
xy[1] -= this.cmenu.el.getHeight();
this.cmenu.showAt(xy);
}, this);
},
onMouseOverHandler : function(d) {
if (this.state === "normal") {
return;
}
var ca = this.container.getAlignToXY(this.container, "?");
var cw = this.container.getWidth();
var boxConfig = {
win : this.win,
centerX : ca[0] + (cw / 2)
};
sitools.PreviewBox.showBox(boxConfig);
},
onMouseOutHandler : function(a) {
sitools.PreviewBox.hideBox();
},
closeWin : function (cMenu, e, win) {
SitoolsDesk.navProfile.taskbar.closeWin.call(this, cMenu, e, win);
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*!
* Ext JS Library 3.2.1
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
/*global Ext, sitools*/
/**
* The object that builds main desktop off the application.
* @param {Ext.app.App} app
*/
Ext.Desktop = function (app) {
/**
* The taskBar object
* @type Ext.ux.TaskBar
*/
this.taskbar = new Ext.ux.TaskBar(app, true);
this.xTickSize = this.yTickSize = 1;
var taskbar = this.taskbar;
var desktopEl = Ext.get('x-desktop');
var bureauEl = Ext.get('bureau');
var topEl = Ext.get('toppanel');
var taskbarEl = Ext.get('ux-taskbar');
var shortcuts = Ext.get('x-shortcuts');
var windowsGroup = new Ext.WindowGroup({
nbWin : function () {
return this.accessList.length;
}
});
var activeWindow;
/**
* Minimize a window in the desktop.
* @private
* @param {Ext.Window} win the window to minimize
*/
function minimizeWin(win) {
win.minimized = true;
win.hide(win.taskButton.getEl());
}
/**
* Render the window at the top of the desktop.
* @private
* @param {Ext.Window} win the window to minimize
*/
function markActive(win) {
if (activeWindow && activeWindow != win) {
markInactive(activeWindow);
}
taskbar.setActiveButton(win.taskButton);
activeWindow = win;
Ext.fly(win.taskButton.el).addClass('active-win');
win.minimized = false;
}
/**
* @private
* @param {Ext.Window} win the window to minimize
*/
function markInactive(win) {
if (win == activeWindow) {
activeWindow = null;
Ext.fly(win.taskButton.el).removeClass('active-win');
}
}
/**
* Set the height of the different elements of the desktop, according to the screen height.
* @private
*/
function layout() {
var el = Ext.get("x-main");
var enteteEl = SitoolsDesk.getEnteteEl();
var bottom = SitoolsDesk.getBottomEl();
try {
el.setHeight(Ext.getBody().getHeight() - enteteEl.getHeight() - bottom.getHeight())
desktopEl.setHeight(Ext.get("x-desktop-taskbar").getHeight()- taskbarEl.getHeight());
}
catch (err) {
return;
}
// bureauEl.setHeight(Ext.lib.Dom.getViewHeight() - taskbarEl.getHeight() - topEl.getHeight())
}
/**
* Remove a window from the desktop.
* @private
* @param {Ext.Window} win the window to minimize
*/
function removeWin(win) {
taskbar.removeTaskButton(win.taskButton);
layout();
}
Ext.EventManager.onWindowResize(layout);
this.layout = layout;
/**
* Creates a window.
* @method
* @returns {Ext.ux.stateFullWindow} the builded window.
*/
this.createWindow = function (config, cls) {
var win = new (cls || Ext.ux.stateFullWindow)(Ext.applyIf(config || {}, {
renderTo : desktopEl,
constrain : true,
constrainHeader : true,
draggable : true,
manager : windowsGroup,
minimizable : true,
maximizable : true,
//DA : forcer le doLayout apres l'affichage
listeners : {
show : function (win) {
var size = win.getSize();
size.width = size.width - 1;
win.setSize(size);
win.doLayout();
}
},
cfgWindow : config.cfgWindow
}));
win.dd.xTickSize = this.xTickSize;
win.dd.yTickSize = this.yTickSize;
win.resizer.widthIncrement = this.xTickSize;
win.resizer.heightIncrement = this.yTickSize;
win.resizer.constrainTo = desktopEl;
win.show();
win.setPagePosition(config.xPos, config.yPos);
win.taskButton = taskbar.addTaskButton(win);
win.cmenu = new Ext.menu.Menu({
items : [
]
});
win.on({
'activate' : {
fn : markActive
},
'beforeshow' : {
fn : markActive
},
'deactivate' : {
fn : markInactive
},
'minimize' : {
fn : minimizeWin
},
'close' : {
fn : removeWin
}
});
layout();
return win;
};
/**
* Creates a window.
* @method
* @returns {Ext.ux.stateFullWindow} the builded window.
*/
this.createPanel = function (config, cls) {
var panel = new (cls || Ext.Panel)(Ext.applyIf(config || {}, {
renderTo : desktopEl
}));
panel.taskButton = taskbar.addTaskButton(panel);
panel.on({
'activate' : {
fn : markActive
},
'beforeshow' : {
fn : markActive
},
'deactivate' : {
fn : markInactive
}
});
layout();
return panel;
};
/**
* @method
* @returns {Ext.WindowGroup} the windowGroup object of this desktop.
*/
this.getManager = function () {
return windowsGroup;
};
/**
* Returns the window with the id .
* @param {string} id the id to look for
* @returns {Ext.Window} win the window
*/
this.getWindow = function (id) {
return windowsGroup.get(id);
};
this.getWinWidth = function () {
var width = Ext.lib.Dom.getViewWidth();
return width < 200 ? 200 : width;
};
this.getWinHeight = function () {
var height = (Ext.lib.Dom.getViewHeight() - taskbarEl.getHeight());
return height < 100 ? 100 : height;
};
this.getWinX = function (width) {
return (Ext.lib.Dom.getViewWidth() - width) / 2;
};
this.getWinY = function (height) {
return (Ext.lib.Dom.getViewHeight() - taskbarEl.getHeight() - height) / 2;
};
this.setTickSize = function (xTickSize, yTickSize) {
this.xTickSize = xTickSize;
if (arguments.length == 1) {
this.yTickSize = xTickSize;
} else {
this.yTickSize = yTickSize;
}
windowsGroup.each(function (win) {
win.dd.xTickSize = this.xTickSize;
win.dd.yTickSize = this.yTickSize;
win.resizer.widthIncrement = this.xTickSize;
win.resizer.heightIncrement = this.yTickSize;
}, this);
};
this.maximize = function () {
SitoolsDesk.getEnteteComp().fireEvent("maximizeDesktop");
SitoolsDesk.getBottomComp().fireEvent("maximizeDesktop");
Ext.DomQuery.select("div[stype=freeDiv]").each(function (freeDiv) {
freeDiv.style.height = "0px";
freeDiv.style.width = "0px";
});
SitoolsDesk.app.getModulesInDiv().each(function (moduleInDiv) {
moduleInDiv.fireEvent("maximizeDesktop", moduleInDiv);
});
//Agrandir la zone desktopAndTaskbar
this.getDesktopAndTaskBarEl().setHeight(Ext.getBody().getHeight() - SitoolsDesk.getEnteteEl().getHeight());
this.getDesktopAndTaskBarEl().setWidth(Ext.getBody().getWidth());
this.getDesktopEl().setHeight(Ext.getBody().getHeight() - SitoolsDesk.getEnteteEl().getHeight() - taskbarEl.getHeight());
this.getDesktopEl().setWidth(Ext.getBody().getWidth());
if (SitoolsDesk.getDesktop().activePanel) {
SitoolsDesk.getDesktop().activePanel.fireEvent("resizeDesktop", SitoolsDesk.getDesktop().activePanel);
}
this.getManager().each(function (win) {
if (win.maximized) {
win.fitContainer();
}
});
SitoolsDesk.getDesktop().taskbar.tbPanel.ownerCt.doLayout()
}
this.minimize = function () {
SitoolsDesk.getEnteteComp().fireEvent("minimizeDesktop");
SitoolsDesk.getBottomComp().fireEvent("minimizeDesktop");
SitoolsDesk.app.getModulesInDiv().each(function (moduleInDiv) {
moduleInDiv.fireEvent("minimizeDesktop", moduleInDiv);
});
Ext.DomQuery.select("div[stype=freeDiv]").each(function (freeDiv) {
freeDiv.style.height = "";
freeDiv.style.width = "";
});
//Revenir à la taille initiale de la zone desktopAndTaskbar
this.getDesktopAndTaskBarEl().dom.style.height="";
this.getDesktopAndTaskBarEl().dom.style.width="";
this.getDesktopEl().setWidth("");
layout();
if (SitoolsDesk.getDesktop().activePanel) {
SitoolsDesk.getDesktop().activePanel.fireEvent("resizeDesktop", SitoolsDesk.getDesktop().activePanel);
}
this.getManager().each(function (win) {
if (win.maximized) {
win.fitContainer();
}
});
SitoolsDesk.getDesktop().taskbar.tbPanel.ownerCt.doLayout()
}
/**
* called when contextMenu cascade option is pressed.
* @method
*/
this.cascade = function () {
var x = 0, y = 0;
windowsGroup.each(function (win) {
if (win.isVisible() && !win.maximized) {
win.setPosition(x, y);
x += 20;
y += 20;
}
}, this);
};
/**
* called when contextMenu tile option is pressed.
* @method
*/
this.tile = function () {
var availWidth = desktopEl.getWidth(true);
var x = this.xTickSize;
var y = this.yTickSize;
var nextY = y;
windowsGroup.each(function (win) {
if (win.isVisible() && !win.maximized) {
var w = win.el.getWidth();
// Wrap to next row if we are not at the line start and this
// Window will go off the end
if ((x > this.xTickSize) && (x + w > availWidth)) {
x = this.xTickSize;
y = nextY;
}
win.setPosition(x, y);
x += w + this.xTickSize;
nextY = Math.max(nextY, y + win.el.getHeight() + this.yTickSize);
}
}, this);
};
this.contextMenu = new Ext.menu.Menu({
items : [ {
text : 'Tile',
handler : this.tile,
scope : this,
icon : loadUrl.get('APP_URL') + "/res/images/icons/presentation2.png"
}, {
text : 'Cascade',
handler : this.cascade,
scope : this,
icon : loadUrl.get('APP_URL') + "/res/images/icons/presentation1.png"
} ]
});
desktopEl.on('contextmenu', function (e) {
if (e.target.id == "x-desktop"){
e.stopEvent();
this.contextMenu.showAt(e.getXY());
}
}, this);
layout();
if (shortcuts) {
shortcuts.on('click', function (e, t) {
if (t = e.getTarget('dt', shortcuts)) {
e.stopEvent();
var module = app.getModule(t.id.replace('-shortcut', ''));
if (module) {
module.openModule();
}
}
});
}
this.getDesktopEl = function () {
return Ext.get('x-desktop');
}
this.getDesktopAndTaskBarEl = function () {
return Ext.get('x-desktop-taskbar');
}
};
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*!
* Ext JS Library 3.2.1
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
/*global Ext, sitools, ID, i18n, showResponse,locale,window*/
/*
* @include "Desktop.js"
*/
/**
* The Main Application
* @cfg {} cfg The initial config
* @class Ext.app.App
* @extends Ext.util.Observable
*/
Ext.app.App = function (cfg) {
Ext.apply(this, cfg);
this.addEvents({
'ready' : true,
'beforeunload' : true
});
};
Ext.extend(Ext.app.App, Ext.util.Observable, {
/**
* True when application is ready
* @type Boolean
*/
isReady : false,
/**
* The list of modules
* @type [Ext.app.Module]
*/
modules : [],
/**
* The list of modules to be displayed in a Div
* @type [Ext.Panel]
*/
modulesInDiv : [],
/**
* The fishEyeMenu
* @type Ext.ux.FisheyeMenuExtention
*/
fisheye : null,
/**
* BasicMethod to override.
*/
getStartConfig : function () {
},
/**
* Initialize application.
* Call the method init wich must have been override on instanciation.
*/
initApp : function () {
// this.startConfig = this.startConfig || this.getStartConfig();
this.desktop = new Ext.Desktop(this);
sitools.PreviewBox = new sitools.common._PreviewBox();
// this.tabMenu = [];
//
// this.launcher = this.desktop.taskbar.startMenu;
//
// this.modules = this.getModules();
// if (this.modules) {
// this.initModules(this.modules);
// }
this.init();
Ext.EventManager.on(window, 'beforeunload', this.onUnload, this);
this.isReady = true;
},
/**
* @method
* BasicMethod to override.
*/
getModules : Ext.emptyFn,
/**
* @method
* BasicMethod to override.
*/
getModulesInDiv : Ext.emptyFn,
/**
* @method
* BasicMethod to override.
*/
init : Ext.emptyFn,
/**
* Add all modules to fisheye menu and launcher.
*/
initModules : function (ms) {
this.modules = ms;
for (var i = 0, len = ms.length; i < len; i++) {
var m = ms[i];
this.launcher.add(m.launcher);
// this.tabMenu.push(m.fisheye);
m.app = this;
}
// this.fisheye = new Ext.ux.FisheyeMenuExtention({
// renderTo : 'fisheye-menu-bottom',
// hAlign : 'center', // left|center|right
// vAlign : 'bottom', // top|bottom
// itemWidth : 60,
// items : this.tabMenu
// });
// quand tous les modules sont prets,
// l'application est prete a etre utilisee
this.isReady = true;
},
/**
* Add a single Module
* @param {Ext.app.Module} module
*/
addModule : function (module) {
this.launcher.add(module.launcher);
this.fisheye.addItem(module.fisheye);
module.app = this;
},
/**
* Remove a single Module
* @param {Ext.app.Module} moduleToRemove
*/
removeModule : function (moduleToRemove) {
this.launcher.remove(moduleToRemove.id);
this.fisheye.removeItem(moduleToRemove.fisheye.id);
this.modules.remove(moduleToRemove);
},
/**
* Return a {Ext.app.Module} module from his name
* @param {string} name
* @return {Ext.app.Module} if founded, "" else
*/
getModule : function (name) {
var ms = this.modules;
if (!Ext.isEmpty(ms)) {
for (var i = 0, len = ms.length; i < len; i++) {
if (ms[i].id == name || ms[i].appType == name) {
return ms[i];
}
}
}
return '';
},
/**
*
* @return {Ext.Desktop} the Desktop object
*/
getDesktop : function () {
return this.desktop;
},
* @return {Ext.ux.FisheyeMenuExtention} return the Fisheye menu object
*/
getFisheyeMenu : function () {
return this.fisheye;
},
/**
* Called by the event beforeunload on the window object
* @param {} e
*/
onUnload : function (e) {
if (this.fireEvent('beforeunload', this) === false) {
e.stopEvent();
}
},
/**
* @deprecated (it is not masking taskBar)
*/
showSpinner : function () {
Ext.getBody().mask("loading...", "x-mask-loading");
},
/**
* @deprecated (it is not masking taskBar)
*/
hideSpinner : function () {
if (Ext.getBody().isMasked()){
Ext.getBody().unmask();
}
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*!
* Ext JS Library 3.2.1
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
/*global Ext, sitools*/
/**
* A simple Observable class to instanciate module App
* @class Ext.app.Module
* @extends Ext.util.Observable
*/
Ext.app.Module = function (config) {
Ext.apply(this, config);
Ext.app.Module.superclass.constructor.call(this);
this.init();
};
Ext.extend(Ext.app.Module, Ext.util.Observable, {
init : Ext.emptyFn
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*
* Ext JS Library 3.2.1
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
/*global Ext, sitools, ID, i18n, showResponse, alertFailure,clog*/
Ext.ns('Ext.ux.grid');
/**
* @class Ext.ux.grid.CheckColumn
* @extends Object GridPanel plugin to add a column with check boxes to a grid.
* <p>
* Example usage:
* </p>
*
* <pre><code>
* // create the column
* var checkColumn = new Ext.grid.CheckColumn({
* header: 'Indoor?',
* dataIndex: 'indoor',
* id: 'check',
* width: 55
* });
*
* // add the column to the column model
* var cm = new Ext.grid.ColumnModel([{
* header: 'Foo',
* ...
* },
* checkColumn
* ]);
*
* // create the grid
* var grid = new Ext.grid.EditorGridPanel({
* ...
* cm: cm,
* plugins: [checkColumn], // include plugin
* ...
* });
* </code></pre>
*
* In addition to storing a Boolean value within the record data, this class
* toggles a css class between <tt>'x-grid3-check-col'</tt> and
* <tt>'x-grid3-check-col-on'</tt> to alter the background image used for a
* column.
*/
Ext.ux.grid.CheckColumn = function(config){
Ext.apply(this, config);
if(!this.id){
this.id = Ext.id();
}
this.renderer = this.renderer.createDelegate(this);
};
Ext.ux.grid.CheckColumn = Ext.extend(Ext.Component, {
enabled : true,
init : function(grid){
this.grid = grid;
this.grid.on('render', function(){
var view = this.grid.getView();
view.mainBody.on('mousedown', this.onMouseDown, this);
}, this);
},
onMouseDown : function(e, t){
if(Ext.fly(t).hasClass(this.createId()) && Ext.fly(t).hasClass("x-grid3-check-col-enabled")){
e.stopEvent();
var index = this.grid.getView().findRowIndex(t);
var record = this.grid.store.getAt(index);
record.set(this.dataIndex, !record.data[this.dataIndex]);
}
},
renderer : function(v, p, record){
p.css += ' x-grid3-check-col-td';
var cmp = Ext.getCmp(this.id);
if (cmp.enabled) {
return String.format('<div id="{2}" class="x-grid3-check-col{0} x-grid3-check-col-enabled {1}"> </div>', v ? '-on' : '', cmp.createId(), this.id);
}
else {
return String.format('<div id="{2}" class="x-grid3-check-disabled-col{0} {1}"> </div>', v ? '-on' : '', cmp.createId(), this.id);
}
},
createId : function(){
return 'x-grid3-cc-' + this.id;
} ,
getEnabled : function () {
return this.enabled;
},
setEnabled : function (value) {
this.enabled = value;
}
});
// register ptype
Ext.preg('checkcolumn', Ext.ux.grid.CheckColumn);
// backwards compat
Ext.grid.CheckColumn = Ext.ux.grid.CheckColumn;
/*******************************************************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* SITools2 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* SITools2. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/* global Ext, ann */
Ext.namespace('sitools.siteMap');
var loadUrl = {
map : [],
/**
* Load a properties file and and the name/values in a associative array ;
* Executing this function on multiple properties file increase the size of
* the array Results can be displayed in the help panel with the display()
* function
*
* @param url
* URL of the i18n file
* @param callback
* No args function that will be executed
* @returns void
*/
load : function (url, callback, scope) {
var siteMapRef = this;
siteMapRef.transformsPropertiesToMap(url, callback, scope);
},
/**
* Transforms a xml Text to a map
*
* @param text
* raw properties file
* @returns a map (associative array) TODO check when the raw properties
* file is rotten
*/
transformsPropertiesToMap : function (url, callback, scope) {
var store = new Ext.data.Store({
proxy : new Ext.data.HttpProxy({
url : url,
restful : true
}),
reader : new Ext.data.XmlReader({
record : 'url'
}, [ {
name : 'name',
mapping : 'name'
}, {
name : 'loc',
mapping : 'loc'
} ])
});
var localMap = this.map;
store.load({
scope : scope,
callback : function (r, options, success) {
var i = 0;
while (i != undefined) {
var rec = r[i];
if (rec != undefined) {
var url = rec.data.loc;
var name = rec.data.name;
localMap[name] = url;
i++;
} else {
i = undefined;
}
}
callback.call(this);
}
});
},
/**
* return the url value
*
* @param name
* @returns
*/
get : function (entry) {
return !Ext.isEmpty(this.map[entry]) ? this.map[entry] : entry;
}
};
/**
* To be defined
*/
var componentManager = {
loadedComponents : [],
load : function (name) {
}
};
var data = {
ret : null,
/**
* Fetch a html file in the url, and display its content into the helpPanel. *
*
* @param url
* @returns
*/
get : function (url, cbk) {
Ext.Ajax.request({
method : 'GET',
url : url,
success : function (response, opts) {
cbk(Ext.decode(response.responseText));
},
failure : function (response, opts) {
Ext.Msg.alert("Warning", "Error! Can't get data with url :" + url);
}
});
return this.ret;
}
};
Ext.applyIf(Array.prototype, {
clone : function () {
return [].concat(this);
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, ID, i18n, showResponse, alertFailure, extColModelToSrv*/
/**
* Redefine the method beforeColMenuShow to request the store when adding a column
* @class Ext.ux.sitoolsGridView
* @extends Ext.grid.GridView
*/
Ext.ux.sitoolsGridView = Ext.extend(Ext.grid.GridView, {
// surcharge de la m�thode pour que l'ajout d'une colonne relance une
// interrogation du store
// avec comme parametre le nouveau columnModel
beforeColMenuShow : function () {
var cm = this.cm, colCount = cm.getColumnCount();
this.colMenu.removeAll();
for (var i = 0; i < colCount; i++) {
if (cm.config[i].hideable !== false) {
this.colMenu.add(new Ext.menu.CheckItem({
itemId : 'col-' + cm.getColumnId(i),
text : cm.getColumnHeader(i),
checked : !cm.isHidden(i),
hideOnClick : false,
disabled : cm.config[i].hideable === false,
listeners : {
scope : this,
checkchange : function (ci, checked) {
if (checked) {
var colModel = extColModelToSrv(this.cm);
this.grid.getStore().load({
params : {
colModel : Ext.util.JSON.encode(colModel)
}
});
}
}
}
}));
}
}
},
doRender : function(columns, records, store, startRow, colCount, stripe) {
var templates = this.templates,
cellTemplate = templates.cell,
rowTemplate = templates.row,
last = colCount - 1;
var tstyle = 'width:' + this.getTotalWidth() + ';';
var rowBuffer = [],
colBuffer = [],
rowParams = {tstyle: tstyle},
meta = {},
column,
record;
for (var j = 0, len = records.length; j < len; j++) {
record = records[j];
colBuffer = [];
var rowIndex = j + startRow;
for (var i = 0; i < colCount; i++) {
column = columns[i];
meta.id = column.id;
meta.css = i === 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : '');
meta.attr = meta.cellAttr = '';
meta.style = column.style;
meta.value = column.renderer.call(column.scope, record.data[column.name], meta, record, rowIndex, i, store);
if (Ext.isEmpty(meta.value)) {
meta.value = ' ';
}
if (this.markDirty && record.dirty && Ext.isDefined(record.modified[column.name])) {
meta.css += ' x-grid3-dirty-cell';
}
colBuffer[colBuffer.length] = cellTemplate.apply(meta);
}
var alt = [];
if (stripe && ((rowIndex + 1) % 2 === 0)) {
alt[0] = 'x-grid3-row-alt';
}
if (record.dirty) {
alt[1] = ' x-grid3-dirty-row';
}
rowParams.cols = colCount;
if (this.getRowClass) {
alt[2] = this.getRowClass(record, rowIndex, rowParams, store);
}
rowParams.alt = alt.join(' ');
rowParams.cells = colBuffer.join('');
rowBuffer[rowBuffer.length] = rowTemplate.apply(rowParams);
}
//Ajout du cas où il n'y a pas de records.
if (records.length == 0) {
var alt = [];
rowParams.cols = colCount;
rowParams.cells = " ";
rowBuffer[0] = rowTemplate.apply(rowParams);
}
return rowBuffer.join('');
},
renderRows : function(startRow, endRow){
var g = this.grid, cm = g.colModel, ds = g.store, stripe = g.stripeRows;
var colCount = cm.getColumnCount();
//if(ds.getCount() < 1){
// return '';
//}
var cs = this.getColumnData();
startRow = startRow || 0;
endRow = !Ext.isDefined(endRow) ? ds.getCount()-1 : endRow;
var rs = ds.getRange(startRow, endRow);
return this.doRender(cs, rs, ds, startRow, colCount, stripe);
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/**
*
* Base64 encode / decode
* http://www.webtoolkit.info/
*
**/
var Base64 = {
// private property
_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
// public method for encoding
encode : function (input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = Base64._utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
}
return output;
},
// public method for decoding
decode : function (input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = this._keyStr.indexOf(input.charAt(i++));
enc2 = this._keyStr.indexOf(input.charAt(i++));
enc3 = this._keyStr.indexOf(input.charAt(i++));
enc4 = this._keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
output = Base64._utf8_decode(output);
return output;
},
// private method for UTF-8 encoding
_utf8_encode : function (string) {
string = string.replace(/\r\n/g,"\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
}
else if((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
}
else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
},
// private method for UTF-8 decoding
_utf8_decode : function (utftext) {
var string = "";
var i = 0;
var c = c1 = c2 = 0;
while ( i < utftext.length ) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
}
else if((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i+1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
}
else {
c2 = utftext.charCodeAt(i+1);
c3 = utftext.charCodeAt(i+2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
};
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*
* md5.js 1.0b 27/06/96
*
* Javascript implementation of the RSA Data Security, Inc. MD5
* Message-Digest Algorithm.
*
* Copyright (c) 1996 Henri Torgemane. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for any purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies.
*
* Of course, this soft is provided "as is" without express or implied
* warranty of any kind.
*
*
* Modified with german comments and some information about collisions.
* (Ralf Mieke, ralf@miekenet.de, http://mieke.home.pages.de)
* French translation: Serge François, serge@selfhtml.org, http://fr.selfhtml.org
*/
function array(n) {
for(i=0;i<n;i++) this[i]=0;
this.length=n;
}
/* Quelques fonctions fondamentales doivent être transformées à cause
* d'erreurs Javascript.
* Essayez par exemple de calculer 0xffffffff >> 4 ...
* Les fonctions utilisées maintenant sont il est vrai plus lentes que les
* fonctions originales mais elles fonctionnent.
*/
function integer(n) { return n%(0xffffffff+1); }
function shr(a,b) {
a=integer(a);
b=integer(b);
if (a-0x80000000>=0) {
a=a%0x80000000;
a>>=b;
a+=0x40000000>>(b-1);
} else
a>>=b;
return a;
}
function shl1(a) {
a=a%0x80000000;
if (a&0x40000000==0x40000000)
{
a-=0x40000000;
a*=2;
a+=0x80000000;
} else
a*=2;
return a;
}
function shl(a,b) {
a=integer(a);
b=integer(b);
for (var i=0;i<b;i++) a=shl1(a);
return a;
}
function and(a,b) {
a=integer(a);
b=integer(b);
var t1=(a-0x80000000);
var t2=(b-0x80000000);
if (t1>=0)
if (t2>=0)
return ((t1&t2)+0x80000000);
else
return (t1&b);
else
if (t2>=0)
return (a&t2);
else
return (a&b);
}
function or(a,b) {
a=integer(a);
b=integer(b);
var t1=(a-0x80000000);
var t2=(b-0x80000000);
if (t1>=0)
if (t2>=0)
return ((t1|t2)+0x80000000);
else
return ((t1|b)+0x80000000);
else
if (t2>=0)
return ((a|t2)+0x80000000);
else
return (a|b);
}
function xor(a,b) {
a=integer(a);
b=integer(b);
var t1=(a-0x80000000);
var t2=(b-0x80000000);
if (t1>=0)
if (t2>=0)
return (t1^t2);
else
return ((t1^b)+0x80000000);
else
if (t2>=0)
return ((a^t2)+0x80000000);
else
return (a^b);
}
function not(a) {
a=integer(a);
return (0xffffffff-a);
}
/* Début de l'algorithme */
var state = new array(4);
var count = new array(2);
count[0] = 0;
count[1] = 0;
var buffer = new array(64);
var transformBuffer = new array(16);
var digestBits = new array(16);
var S11 = 7;
var S12 = 12;
var S13 = 17;
var S14 = 22;
var S21 = 5;
var S22 = 9;
var S23 = 14;
var S24 = 20;
var S31 = 4;
var S32 = 11;
var S33 = 16;
var S34 = 23;
var S41 = 6;
var S42 = 10;
var S43 = 15;
var S44 = 21;
function F(x,y,z) {
return or(and(x,y),and(not(x),z));
}
function G(x,y,z) {
return or(and(x,z),and(y,not(z)));
}
function H(x,y,z) {
return xor(xor(x,y),z);
}
function I(x,y,z) {
return xor(y ,or(x , not(z)));
}
function rotateLeft(a,n) {
return or(shl(a, n),(shr(a,(32 - n))));
}
function FF(a,b,c,d,x,s,ac) {
a = a+F(b, c, d) + x + ac;
a = rotateLeft(a, s);
a = a+b;
return a;
}
function GG(a,b,c,d,x,s,ac) {
a = a+G(b, c, d) +x + ac;
a = rotateLeft(a, s);
a = a+b;
return a;
}
function HH(a,b,c,d,x,s,ac) {
a = a+H(b, c, d) + x + ac;
a = rotateLeft(a, s);
a = a+b;
return a;
}
function II(a,b,c,d,x,s,ac) {
a = a+I(b, c, d) + x + ac;
a = rotateLeft(a, s);
a = a+b;
return a;
}
function transform(buf,offset) {
var a=0, b=0, c=0, d=0;
var x = transformBuffer;
a = state[0];
b = state[1];
c = state[2];
d = state[3];
for (i = 0; i < 16; i++) {
x[i] = and(buf[i*4+offset],0xff);
for (j = 1; j < 4; j++) {
x[i]+=shl(and(buf[i*4+j+offset] ,0xff), j * 8);
}
}
/* tour 1 */
a = FF ( a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
d = FF ( d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
c = FF ( c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
b = FF ( b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
a = FF ( a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
d = FF ( d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
c = FF ( c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
b = FF ( b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
a = FF ( a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
d = FF ( d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
c = FF ( c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
b = FF ( b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
a = FF ( a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
d = FF ( d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
c = FF ( c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
b = FF ( b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* tour 2 */
a = GG ( a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
d = GG ( d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
c = GG ( c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
b = GG ( b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
a = GG ( a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
d = GG ( d, a, b, c, x[10], S22, 0x2441453); /* 22 */
c = GG ( c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
b = GG ( b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
a = GG ( a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
d = GG ( d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
c = GG ( c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
b = GG ( b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
a = GG ( a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
d = GG ( d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
c = GG ( c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
b = GG ( b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* tour 3 */
a = HH ( a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
d = HH ( d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
c = HH ( c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
b = HH ( b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
a = HH ( a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
d = HH ( d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
c = HH ( c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
b = HH ( b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
a = HH ( a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
d = HH ( d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
c = HH ( c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
b = HH ( b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
a = HH ( a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
d = HH ( d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
c = HH ( c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
b = HH ( b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* tour 4 */
a = II ( a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
d = II ( d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
c = II ( c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
b = II ( b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
a = II ( a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
d = II ( d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
c = II ( c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
b = II ( b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
a = II ( a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
d = II ( d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
c = II ( c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
b = II ( b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
a = II ( a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
d = II ( d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
c = II ( c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
b = II ( b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state[0] +=a;
state[1] +=b;
state[2] +=c;
state[3] +=d;
}
/* Avec l'initialisation de Dobbertin:
state[0] = 0x12ac2375;
state[1] = 0x3b341042;
state[2] = 0x5f62b97c;
state[3] = 0x4ba763ed;
s'il y a une collision:
begin 644 Message1
M7MH=JO6_>MG!X?!51$)W,CXV!A"=(!AR71,<X`Y-IIT9^Z&8L$2N'Y*Y:R.;
39GIK9>TF$W()/MEHR%C4:G1R:Q"=
`
end
begin 644 Message2
M7MH=JO6_>MG!X?!51$)W,CXV!A"=(!AR71,<X`Y-IIT9^Z&8L$2N'Y*Y:R.;
39GIK9>TF$W()/MEHREC4:G1R:Q"=
`
end
*/
function init() {
count[0]=count[1] = 0;
state[0] = 0x67452301;
state[1] = 0xefcdab89;
state[2] = 0x98badcfe;
state[3] = 0x10325476;
for (i = 0; i < digestBits.length; i++)
digestBits[i] = 0;
}
function update(b) {
var index,i;
index = and(shr(count[0],3) , 0x3f);
if (count[0]<0xffffffff-7)
count[0] += 8;
else {
count[1]++;
count[0]-=0xffffffff+1;
count[0]+=8;
}
buffer[index] = and(b,0xff);
if (index >= 63) {
transform(buffer, 0);
}
}
function finish() {
var bits = new array(8);
var padding;
var i=0, index=0, padLen=0;
for (i = 0; i < 4; i++) {
bits[i] = and(shr(count[0],(i * 8)), 0xff);
}
for (i = 0; i < 4; i++) {
bits[i+4]=and(shr(count[1],(i * 8)), 0xff);
}
index = and(shr(count[0], 3) ,0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
padding = new array(64);
padding[0] = 0x80;
for (i=0;i<padLen;i++)
update(padding[i]);
for (i=0;i<8;i++)
update(bits[i]);
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
digestBits[i*4+j] = and(shr(state[i], (j * 8)) , 0xff);
}
}
}
/* Fin de l'algorithme MD5 */
function hexa(n) {
var hexa_h = "0123456789abcdef";
var hexa_c="";
var hexa_m=n;
for (hexa_i=0;hexa_i<8;hexa_i++) {
hexa_c=hexa_h.charAt(Math.abs(hexa_m)%16)+hexa_c;
hexa_m=Math.floor(hexa_m/16);
}
return hexa_c;
}
var ascii="01234567890123456789012345678901" +
" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"+
"[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
function MD5(message)
{
var l,s,k,ka,kb,kc,kd;
init();
for (k=0;k<message.length;k++) {
l=message.charAt(k);
update(ascii.lastIndexOf(l));
}
finish();
ka=kb=kc=kd=0;
for (i=0;i<4;i++) ka+=shl(digestBits[15-i], (i*8));
for (i=4;i<8;i++) kb+=shl(digestBits[15-i], ((i-4)*8));
for (i=8;i<12;i++) kc+=shl(digestBits[15-i], ((i-8)*8));
for (i=12;i<16;i++) kd+=shl(digestBits[15-i], ((i-12)*8));
s=hexa(kd)+hexa(kc)+hexa(kb)+hexa(ka);
return s;
}
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
function Digest (config) {
this.url = config.url;
this.usr = config.usr;
this.pwd = config.pwd;
this.realm = config.realm;
this.algorithm = config.algorithm;
this.nonce = config.nonce;
this.method = config.method;
this.mode = config.mode;
this.A1 = config.A1;
this.getDigestAuth = function () {
this.resetHeaders();
return this.buildAuthenticationRequest();
};
this.getA1 = function () {
this.resetHeaders();
return this.digest(this.usr + ':' + this.realm + ':' + this.pwd);
};
this.resetHeaders = function () {
if ( typeof( this.headers) != "undefined" ) {
delete this.headers;
}
this.headers = {
'uri' : this.url,
'username' : this.usr,
'algorithm' : this.algorithm,
'realm' : this.realm,
'nonce' : this.nonce
};
};
this.digest = function (s) {
// Fallback to MD5 if requested algorithm is unavilable.
if (typeof ( window[this.headers.algorithm] ) != 'function') {
if (typeof ( window['MD5'] ) != 'function') {
alert('Votre navigateur ne supporte pas l\'authentification HTTP Digest !');
return false;
} else {
return MD5(s);
}
}
return window[this.headers.algorithm](s);
};
this.buildResponseHash = function () {
if (this.headers.salt) {
auth.secret = auth.secret + ':' + auth.headers.salt;
delete auth.headers.salt;
}
if (this.headers.migrate) {
auth.secret = this.digest(auth.secret);
}
var A1;
if (Ext.isEmpty(this.A1)){
A1 = this.getA1();
}
else {
A1 = this.A1;
}
//delete this.secret;
var A2 = this.digest(this.method + ':' + this.headers.uri);
if (this.mode == 'digest') {
return this.digest(A1 + ":" + this.headers.nonce + ":" + A2);
}
//TODO : voir s'il y a d'autres encodages possibles
return null;
};
this.buildAuthenticationRequest = function () {
var request = "Digest";
var comma = ' ';
for (name in this.headers) {
request += comma + name + '="' + this.headers[name] + '"';
comma = ',';
}
// request += ' username="'+ auth.headers.username+ '"';
// don't continue further if there is no algorithm yet.
if (typeof( this.headers.algorithm ) == 'undefined') {
return request;
}
var r = this.buildResponseHash();
if (r) {
request += ", response=\"" + r + "\"";
return request;
}
return false;
};
};
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/**
* shortcut for console.assert(object is not null neither undefined neither
* empty string)
*/
/*global cerr,ctrace,isFirebugConsoleIsActive,console */
function ann(obj, message) {
if (obj === true || obj === false) {
return;
}
if (obj === undefined) {
cerr('Object is undefined - ' + message);
ctrace();
return;
}
if (obj === null) {
cerr('Object is null - ' + message);
ctrace();
return;
}
if (obj === "") {
cerr('String seems empty - ' + message);
ctrace();
return;
}
if (obj == NaN) {
cerr('Object equals NaN - ' + message);
ctrace();
return;
}
}
/**
* shortcut for console.assert(object is not null neither undefined neither
* empty string)
*/
function assert(condition, message) {
if (!condition) {
cerr('Condition is not valid : ' + message);
ctrace();
return;
}
}
/**
* Log on the console
*/
function clog(message) {
if (isFirebugConsoleIsActive()) {
console.log(message);
}
}
/**
* Display an error on the console
*/
function cerr(message) {
if (isFirebugConsoleIsActive()) {
console.trace();
}
}
/**
* Trace the Javascript stack to this point
*/
function ctrace() {
if (isFirebugConsoleIsActive()) {
console.trace();
}
}
/**
* Trace the Javascript stack to this point
*/
function cdir(obj) {
if (isFirebugConsoleIsActive()) {
console.dir(obj);
}
}
/**
* Return true if the firebug console is active, false elsewhere
*/
function isFirebugConsoleIsActive() {
try {
if (console !== null && console !== undefined)
{
return true;
} else {
return false;
}
}
catch (e) {
return false;
}
}
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
Ext.ns("sitools.common.utils");
/**
* An utility class to use for specific sitools dates.
*/
sitools.common.utils.Date = {
/**
* The regExp to test if a string can be transformed to a date
*/
regToday : new RegExp("^\{\\$TODAY\} *(\\+ *[0-9]*|\\- *[0-9]*)?$"),
/**
* in the template {$TODAY} + x, determine the x unit (currently it is a Day)
* @type
*/
timeInterval : Date.DAY,
/**
* Transform a String value containing {$TODAY} into a valid date.
* @param {String} val the string value
* @return {Date} the date Value.
*/
stringWithTodayToDate : function(val) {
if (Ext.isDate(val)) {
return val;
}
if (!this.regToday.test(val)) {
return null;
}
var regNbJour = new RegExp("[0-9]+", "g");
var regOp = new RegExp("[+]|[-]");
var nbJour = parseFloat(regNbJour.exec(val));
var op = regOp.exec(val);
var result = new Date();
if (Ext.isEmpty(nbJour) && !Ext.isEmpty(op)) {
return null;
}
if (!Ext.isEmpty(nbJour) && !Ext.isEmpty(op)) {
if (op == "-") {
nbJour = nbJour * -1;
}
result = result.add(this.timeInterval, nbJour);
}
return result;
},
/**
* Test if a date object is valid or not.
* @param {Date} d date value
* @return {Boolean} valid or not valid
*/
isValidDate : function (d) {
if ( Object.prototype.toString.call(d) !== "[object Date]" )
return false;
return !isNaN(d.getTime());
}
}/* URL class for JavaScript
* Copyright (C) 2003 Johan Känngård, <johan AT kanngard DOT net>
* http://dev.kanngard.net/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* The GPL is located at: http://www.gnu.org/licenses/gpl.txt
*/
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/* Creates a new URL object with the specified url String. */
function URL(url){
if(url.length==0) eval('throw "Invalid URL ['+url+'];');
this.url=url;
this.port=-1;
this.query=(this.url.indexOf('?')>=0)?this.url.substring(this.url.indexOf('?')+1):'';
if(this.query.indexOf('#')>=0) this.query=this.query.substring(0,this.query.indexOf('#'));
this.protocol='';
this.host='';
var protocolSepIndex=this.url.indexOf('://');
if(protocolSepIndex>=0){
this.protocol=this.url.substring(0,protocolSepIndex).toLowerCase();
this.host=this.url.substring(protocolSepIndex+3);
if(this.host.indexOf('/')>=0) this.host=this.host.substring(0,this.host.indexOf('/'));
var atIndex=this.host.indexOf('@');
if(atIndex>=0){
var credentials=this.host.substring(0,atIndex);
var colonIndex=credentials.indexOf(':');
if(colonIndex>=0){
this.username=credentials.substring(0,colonIndex);
this.password=credentials.substring(colonIndex);
}else{
this.username=credentials;
}
this.host=this.host.substring(atIndex+1);
}
var portColonIndex=this.host.indexOf(':');
if(portColonIndex>=0){
this.port=this.host.substring(portColonIndex);
this.host=this.host.substring(0,portColonIndex);
}
this.file=this.url.substring(protocolSepIndex+3);
this.file=this.file.substring(this.file.indexOf('/'));
}else{
this.file=this.url;
}
if(this.file.indexOf('?')>=0) this.file=this.file.substring(0, this.file.indexOf('?'));
var refSepIndex=url.indexOf('#');
if(refSepIndex>=0){
this.file=this.file.substring(0,refSepIndex);
this.reference=this.url.substring(this.url.indexOf('#'));
}else{
this.reference='';
}
this.path=this.file;
if(this.query.length>0) this.file+='?'+this.query;
if(this.reference.length>0) this.file+='#'+this.reference;
this.getPort=getPort;
this.getQuery=getQuery;
this.getProtocol=getProtocol;
this.getHost=getHost;
this.getUserName=getUserName;
this.getPassword=getPassword;
this.getFile=getFile;
this.getReference=getReference;
this.getPath=getPath;
this.getArgumentValue=getArgumentValue;
this.getArgumentValues=getArgumentValues;
this.toString=toString;
/* Returns the port part of this URL, i.e. '8080' in the url 'http://server:8080/' */
function getPort(){
return this.port;
}
/* Returns the query part of this URL, i.e. 'Open' in the url 'http://server/?Open' */
function getQuery(){
return this.query;
}
/* Returns the protocol of this URL, i.e. 'http' in the url 'http://server/' */
function getProtocol(){
return this.protocol;
}
/* Returns the host name of this URL, i.e. 'server.com' in the url 'http://server.com/' */
function getHost(){
return this.host;
}
/* Returns the user name part of this URL, i.e. 'joe' in the url 'http://joe@server.com/' */
function getUserName(){
return this.username;
}
/* Returns the password part of this url, i.e. 'secret' in the url 'http://joe:secret@server.com/' */
function getPassword(){
return this.password;
}
/* Returns the file part of this url, i.e. everything after the host name. */
function getFile(){
return this.file;
}
/* Returns the reference of this url, i.e. 'bookmark' in the url 'http://server/file.html#bookmark' */
function getReference(){
return this.reference;
}
/* Returns the file path of this url, i.e. '/dir/file.html' in the url 'http://server/dir/file.html' */
function getPath(){
return this.path;
}
/* Returns the FIRST matching value to the specified key in the query.
If the url has a non-value argument, like 'Open' in '?Open&bla=12', this method
returns the same as the key: 'Open'...
The url must be correctly encoded, ampersands must encoded as &
I.e. returns 'value' if the key is 'key' in the url 'http://server/?Open&key=value' */
function getArgumentValue(key){
var a=this.getArgumentValues();
if(a.length<1) return '';
for(var i=0;i<a.length;i++){
if(a[i][0]==key) return a[i][1];
}
return '';
}
/* Returns all key / value pairs in the query as a two dimensional array */
function getArgumentValues(){
var a=new Array();
var b=this.query.split('&');
var c='';
if(b.length<1) return a;
for(var i=0;i<b.length;i++){
c=b[i].split('=');
a[i]=new Array(c[0],((c.length==1)?c[0]:c[1]));
}
return a;
}
/* Returns a String representation of this url */
function toString(){
return this.url;
}
}/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
Ext.ns("sitools.common.utils");
/**
* An utility class to use in sitools.
*/
sitools.common.utils.Utils = {
/**
* Transform an Array of Sitools properties (with field name, value) into an object.
* @param {Array} array the array to transform
* @return {Object} An object containing all properties as attributes.
*/
arrayProperties2Object : function (array) {
var result = {};
Ext.each(array, function(item){
if (!Ext.isEmpty(item.name) && !Ext.isEmpty(item.value)) {
result[item.name] = item.value;
}
});
return result;
},
/**
* Highlight a json string inside a <pre> html tag
*/
syntaxHighlight : function (json) {
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
var cls = 'number';
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = 'key';
} else {
cls = 'string';
}
} else if (/true|false/.test(match)) {
cls = 'boolean';
} else if (/null/.test(match)) {
cls = 'null';
}
return '<span class="' + cls + '">' + match + '</span>';
});
}
}
sitoolsUtils = sitools.common.utils.Utils;
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*
* Ext JS Library 3.2.1
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
/**
* @class Ext.ux.StatusBar
* <p>Basic status bar component that can be used as the bottom toolbar of any {@link Ext.Panel}. In addition to
* supporting the standard {@link Ext.Toolbar} interface for adding buttons, menus and other items, the StatusBar
* provides a greedy status element that can be aligned to either side and has convenient methods for setting the
* status text and icon. You can also indicate that something is processing using the {@link #showBusy} method.</p>
* <pre><code>
new Ext.Panel({
title: 'StatusBar',
// etc.
bbar: new Ext.ux.StatusBar({
id: 'my-status',
// defaults to use when the status is cleared:
defaultText: 'Default status text',
defaultIconCls: 'default-icon',
// values to set initially:
text: 'Ready',
iconCls: 'ready-icon',
// any standard Toolbar items:
items: [{
text: 'A Button'
}, '-', 'Plain Text']
})
});
// Update the status bar later in code:
var sb = Ext.getCmp('my-status');
sb.setStatus({
text: 'OK',
iconCls: 'ok-icon',
clear: true // auto-clear after a set interval
});
// Set the status bar to show that something is processing:
sb.showBusy();
// processing....
sb.clearStatus(); // once completeed
</code></pre>
* @extends Ext.Toolbar
* @constructor
* Creates a new StatusBar
* @param {Object/Array} config A config object
*/
Ext.ux.StatusBar = Ext.extend(Ext.Toolbar, {
/**
* @cfg {String} statusAlign
* The alignment of the status element within the overall StatusBar layout. When the StatusBar is rendered,
* it creates an internal div containing the status text and icon. Any additional Toolbar items added in the
* StatusBar's {@link #items} config, or added via {@link #add} or any of the supported add* methods, will be
* rendered, in added order, to the opposite side. The status element is greedy, so it will automatically
* expand to take up all sapce left over by any other items. Example usage:
* <pre><code>
// Create a left-aligned status bar containing a button,
// separator and text item that will be right-aligned (default):
new Ext.Panel({
title: 'StatusBar',
// etc.
bbar: new Ext.ux.StatusBar({
defaultText: 'Default status text',
id: 'status-id',
items: [{
text: 'A Button'
}, '-', 'Plain Text']
})
});
// By adding the statusAlign config, this will create the
// exact same toolbar, except the status and toolbar item
// layout will be reversed from the previous example:
new Ext.Panel({
title: 'StatusBar',
// etc.
bbar: new Ext.ux.StatusBar({
defaultText: 'Default status text',
id: 'status-id',
statusAlign: 'right',
items: [{
text: 'A Button'
}, '-', 'Plain Text']
})
});
</code></pre>
*/
/**
* @cfg {String} defaultText
* The default {@link #text} value. This will be used anytime the status bar is cleared with the
* <tt>useDefaults:true</tt> option (defaults to '').
*/
/**
* @cfg {String} defaultIconCls
* The default {@link #iconCls} value (see the iconCls docs for additional details about customizing the icon).
* This will be used anytime the status bar is cleared with the <tt>useDefaults:true</tt> option (defaults to '').
*/
/**
* @cfg {String} text
* A string that will be <b>initially</b> set as the status message. This string
* will be set as innerHTML (html tags are accepted) for the toolbar item.
* If not specified, the value set for <code>{@link #defaultText}</code>
* will be used.
*/
/**
* @cfg {String} iconCls
* A CSS class that will be <b>initially</b> set as the status bar icon and is
* expected to provide a background image (defaults to '').
* Example usage:<pre><code>
// Example CSS rule:
.x-statusbar .x-status-custom {
padding-left: 25px;
background: transparent url(images/custom-icon.gif) no-repeat 3px 2px;
}
// Setting a default icon:
var sb = new Ext.ux.StatusBar({
defaultIconCls: 'x-status-custom'
});
// Changing the icon:
sb.setStatus({
text: 'New status',
iconCls: 'x-status-custom'
});
</code></pre>
*/
/**
* @cfg {String} cls
* The base class applied to the containing element for this component on render (defaults to 'x-statusbar')
*/
cls : 'x-statusbar',
/**
* @cfg {String} busyIconCls
* The default <code>{@link #iconCls}</code> applied when calling
* <code>{@link #showBusy}</code> (defaults to <tt>'x-status-busy'</tt>).
* It can be overridden at any time by passing the <code>iconCls</code>
* argument into <code>{@link #showBusy}</code>.
*/
busyIconCls : 'x-status-busy',
/**
* @cfg {String} busyText
* The default <code>{@link #text}</code> applied when calling
* <code>{@link #showBusy}</code> (defaults to <tt>'Loading...'</tt>).
* It can be overridden at any time by passing the <code>text</code>
* argument into <code>{@link #showBusy}</code>.
*/
busyText : 'Loading...',
/**
* @cfg {Number} autoClear
* The number of milliseconds to wait after setting the status via
* <code>{@link #setStatus}</code> before automatically clearing the status
* text and icon (defaults to <tt>5000</tt>). Note that this only applies
* when passing the <tt>clear</tt> argument to <code>{@link #setStatus}</code>
* since that is the only way to defer clearing the status. This can
* be overridden by specifying a different <tt>wait</tt> value in
* <code>{@link #setStatus}</code>. Calls to <code>{@link #clearStatus}</code>
* always clear the status bar immediately and ignore this value.
*/
autoClear : 5000,
/**
* @cfg {String} emptyText
* The text string to use if no text has been set. Defaults to
* <tt>' '</tt>). If there are no other items in the toolbar using
* an empty string (<tt>''</tt>) for this value would end up in the toolbar
* height collapsing since the empty string will not maintain the toolbar
* height. Use <tt>''</tt> if the toolbar should collapse in height
* vertically when no text is specified and there are no other items in
* the toolbar.
*/
emptyText : ' ',
// private
activeThreadId : 0,
// private
initComponent : function(){
if(this.statusAlign=='right'){
this.cls += ' x-status-right';
}
Ext.ux.StatusBar.superclass.initComponent.call(this);
},
// private
afterRender : function(){
Ext.ux.StatusBar.superclass.afterRender.call(this);
var right = this.statusAlign == 'right';
this.currIconCls = this.iconCls || this.defaultIconCls;
this.statusEl = new Ext.Toolbar.TextItem({
cls: 'x-status-text ' + (this.currIconCls || ''),
text: this.text || this.defaultText || ''
});
if(right){
this.add('->');
this.add(this.statusEl);
}else{
this.insert(0, this.statusEl);
this.insert(1, '->');
}
this.doLayout();
},
/**
* Sets the status {@link #text} and/or {@link #iconCls}. Also supports automatically clearing the
* status that was set after a specified interval.
* @param {Object/String} config A config object specifying what status to set, or a string assumed
* to be the status text (and all other options are defaulted as explained below). A config
* object containing any or all of the following properties can be passed:<ul>
* <li><tt>text</tt> {String} : (optional) The status text to display. If not specified, any current
* status text will remain unchanged.</li>
* <li><tt>iconCls</tt> {String} : (optional) The CSS class used to customize the status icon (see
* {@link #iconCls} for details). If not specified, any current iconCls will remain unchanged.</li>
* <li><tt>clear</tt> {Boolean/Number/Object} : (optional) Allows you to set an internal callback that will
* automatically clear the status text and iconCls after a specified amount of time has passed. If clear is not
* specified, the new status will not be auto-cleared and will stay until updated again or cleared using
* {@link #clearStatus}. If <tt>true</tt> is passed, the status will be cleared using {@link #autoClear},
* {@link #defaultText} and {@link #defaultIconCls} via a fade out animation. If a numeric value is passed,
* it will be used as the callback interval (in milliseconds), overriding the {@link #autoClear} value.
* All other options will be defaulted as with the boolean option. To customize any other options,
* you can pass an object in the format:<ul>
* <li><tt>wait</tt> {Number} : (optional) The number of milliseconds to wait before clearing
* (defaults to {@link #autoClear}).</li>
* <li><tt>anim</tt> {Number} : (optional) False to clear the status immediately once the callback
* executes (defaults to true which fades the status out).</li>
* <li><tt>useDefaults</tt> {Number} : (optional) False to completely clear the status text and iconCls
* (defaults to true which uses {@link #defaultText} and {@link #defaultIconCls}).</li>
* </ul></li></ul>
* Example usage:<pre><code>
// Simple call to update the text
statusBar.setStatus('New status');
// Set the status and icon, auto-clearing with default options:
statusBar.setStatus({
text: 'New status',
iconCls: 'x-status-custom',
clear: true
});
// Auto-clear with custom options:
statusBar.setStatus({
text: 'New status',
iconCls: 'x-status-custom',
clear: {
wait: 8000,
anim: false,
useDefaults: false
}
});
</code></pre>
* @return {Ext.ux.StatusBar} this
*/
setStatus : function(o){
o = o || {};
if(typeof o == 'string'){
o = {text:o};
}
if(o.text !== undefined){
this.setText(o.text);
}
if(o.iconCls !== undefined){
this.setIcon(o.iconCls);
}
if(o.clear){
var c = o.clear,
wait = this.autoClear,
defaults = {useDefaults: true, anim: true};
if(typeof c == 'object'){
c = Ext.applyIf(c, defaults);
if(c.wait){
wait = c.wait;
}
}else if(typeof c == 'number'){
wait = c;
c = defaults;
}else if(typeof c == 'boolean'){
c = defaults;
}
c.threadId = this.activeThreadId;
this.clearStatus.defer(wait, this, [c]);
}
return this;
},
/**
* Clears the status {@link #text} and {@link #iconCls}. Also supports clearing via an optional fade out animation.
* @param {Object} config (optional) A config object containing any or all of the following properties. If this
* object is not specified the status will be cleared using the defaults below:<ul>
* <li><tt>anim</tt> {Boolean} : (optional) True to clear the status by fading out the status element (defaults
* to false which clears immediately).</li>
* <li><tt>useDefaults</tt> {Boolean} : (optional) True to reset the text and icon using {@link #defaultText} and
* {@link #defaultIconCls} (defaults to false which sets the text to '' and removes any existing icon class).</li>
* </ul>
* @return {Ext.ux.StatusBar} this
*/
clearStatus : function(o){
o = o || {};
if(o.threadId && o.threadId !== this.activeThreadId){
// this means the current call was made internally, but a newer
// thread has set a message since this call was deferred. Since
// we don't want to overwrite a newer message just ignore.
return this;
}
var text = o.useDefaults ? this.defaultText : this.emptyText,
iconCls = o.useDefaults ? (this.defaultIconCls ? this.defaultIconCls : '') : '';
if(o.anim){
// animate the statusEl Ext.Element
this.statusEl.el.fadeOut({
remove: false,
useDisplay: true,
scope: this,
callback: function(){
this.setStatus({
text: text,
iconCls: iconCls
});
this.statusEl.el.show();
}
});
}else{
// hide/show the el to avoid jumpy text or icon
this.statusEl.hide();
this.setStatus({
text: text,
iconCls: iconCls
});
this.statusEl.show();
}
return this;
},
/**
* Convenience method for setting the status text directly. For more flexible options see {@link #setStatus}.
* @param {String} text (optional) The text to set (defaults to '')
* @return {Ext.ux.StatusBar} this
*/
setText : function(text){
this.activeThreadId++;
this.text = text || '';
if(this.rendered){
this.statusEl.setText(this.text);
}
return this;
},
/**
* Returns the current status text.
* @return {String} The status text
*/
getText : function(){
return this.text;
},
/**
* Convenience method for setting the status icon directly. For more flexible options see {@link #setStatus}.
* See {@link #iconCls} for complete details about customizing the icon.
* @param {String} iconCls (optional) The icon class to set (defaults to '', and any current icon class is removed)
* @return {Ext.ux.StatusBar} this
*/
setIcon : function(cls){
this.activeThreadId++;
cls = cls || '';
if(this.rendered){
if(this.currIconCls){
this.statusEl.removeClass(this.currIconCls);
this.currIconCls = null;
}
if(cls.length > 0){
this.statusEl.addClass(cls);
this.currIconCls = cls;
}
}else{
this.currIconCls = cls;
}
return this;
},
/**
* Convenience method for setting the status text and icon to special values that are pre-configured to indicate
* a "busy" state, usually for loading or processing activities.
* @param {Object/String} config (optional) A config object in the same format supported by {@link #setStatus}, or a
* string to use as the status text (in which case all other options for setStatus will be defaulted). Use the
* <tt>text</tt> and/or <tt>iconCls</tt> properties on the config to override the default {@link #busyText}
* and {@link #busyIconCls} settings. If the config argument is not specified, {@link #busyText} and
* {@link #busyIconCls} will be used in conjunction with all of the default options for {@link #setStatus}.
* @return {Ext.ux.StatusBar} this
*/
showBusy : function(o){
if(typeof o == 'string'){
o = {text:o};
}
o = Ext.applyIf(o || {}, {
text: this.busyText,
iconCls: this.busyIconCls
});
return this.setStatus(o);
}
});
Ext.reg('statusbar', Ext.ux.StatusBar);
/*******************************************************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* SITools2 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* SITools2. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/* global Ext, sitools, ID, i18n, showResponse, alertFailure,clog,window,Base64 */
Ext.namespace('sitools.userProfile');
/*
* defurl: default page url to load if click on Cancel button url: url to
* request if click on Login button handler: if request is OK then is called
* register: url to set to Register button reset: url to set to Reset Password
* button
*/
sitools.userProfile.Login = Ext.extend(Ext.Window, {
id : 'winLogin',
layout : 'hbox',
width : 392,
height : 200,
resizable : false,
closable : false,
modal : true,
initComponent : function () {
this.title = i18n.get('label.login');
this.bbar = new Ext.ux.StatusBar({
text : i18n.get('label.ready'),
id : 'sbWinLogin',
iconCls : 'x-status-valid',
items : [ {
text : i18n.get('label.passwordLost'),
hidden : !this.reset,
scope : this,
icon : loadUrl.get('APP_URL') + '/common/res/images/icons/wadl.gif',
iconAlign : 'right',
handler : function () {
Ext.getCmp('winLogin').close();
var reset = new sitools.userProfile.resetPassword({
closable : this.closable,
url : this.reset,
handler : this.handler
});
reset.show();
}
} ]
});
this.combo = new Ext.form.ComboBox({
typeAhead : true,
triggerAction : 'all',
forceSelection : true,
allowBlank : false,
lazyRender : true,
mode : 'local',
store : new Ext.data.ArrayStore({
id : 0,
fields : [ 'myId', 'displayText' ],
data : [ [ 1, i18n.get('label.userPortal') ], [ 2, i18n.get('label.administration') ] ]
}),
valueField : 'myId',
displayField : 'displayText',
anchor : '80%',
value : 1,
fieldLabel : i18n.get('label.target'),
hideLabel : true
});
if (this.chooseLocation) {
this.combo.setVisible(true);
this.combo.hideLabel = false;
} else {
this.combo.setVisible(false);
this.setSize(392, 160);
}
this.items = [ {
xtype : 'form',
frame : true,
border : false,
buttonAlign : 'center',
id : 'frmLogin',
width : 392,
labelWidth : 100,
padding : "10px 10px 0px 60px",
bodyStyle : "background-image: url("+loadUrl.get('APP_URL')+"/common/res/images/ux/login-big.gif);" +
"background-position: top left;" +
"background-repeat: no-repeat;",
items : [ {
xtype : 'textfield',
fieldLabel : i18n.get('label.login'),
name : 'login',
id : 'logId',
allowBlank : false,
anchor : '80%'
}, {
xtype : 'textfield',
fieldLabel : i18n.get('label.password'),
name : 'password',
id : 'pwdId',
allowBlank : false,
inputType : 'password',
anchor : '80%',
listeners : {
scope : this,
specialkey : function (field, e) {
if (e.getKey() == e.ENTER) {
this.getAuth();
}
}
}
}, this.combo ],
buttons : [ {
text : i18n.get('label.login'),
handler : this.getAuth,
scope : this
}, {
text : i18n.get('label.reset'),
handler : function () {
Ext.getCmp('frmLogin').getForm().reset();
Ext.getCmp('sbWinLogin').setStatus({
text : i18n.get('label.ready'),
iconCls : 'x-status-valid'
});
}
}, {
text : i18n.get('label.cancel'),
hidden : !this.defurl,
scope : this,
handler : function () {
window.location.href = this.defurl;
}
}, {
text : i18n.get('label.register'),
hidden : !this.register,
scope : this,
icon : loadUrl.get('APP_URL') + '/common/res/images/icons/refresh.png',
handler : function () {
Ext.getCmp('winLogin').close();
var register = new sitools.userProfile.Register({
closable : this.closable,
url : this.register,
login : this.url,
handler : this.handler
});
register.show();
}
} ]
} ];
sitools.userProfile.Login.superclass.initComponent.call(this);
},
getAuth : function () {
/*
* var usr = Ext.getCmp('logId').getValue(); var pwd =
* Ext.getCmp('pwdId').getValue(); var tok = usr + ':' + pwd; var hash =
* Base64.encode(tok); var auth = 'Basic ' + hash;
* Ext.util.Cookies.set('hashCode', auth);
* Ext.apply(Ext.Ajax.defaultHeaders, { "Authorization" : auth });
* this.login();
*/
Ext.util.Cookies.set('A1', "");
Ext.util.Cookies.set('userLogin', "");
Ext.util.Cookies.set('scheme', "");
Ext.util.Cookies.set('algorithm', "");
Ext.util.Cookies.set('realm', "");
Ext.util.Cookies.set('nonce', "");
Ext.util.Cookies.set('hashCode', "");
Ext.apply(Ext.Ajax.defaultHeaders, {
"Authorization" : ""
});
Ext.Ajax.request({
url : this.url,
method : 'GET',
scope : this,
success : function (response, opts) {
var Json = Ext.decode(response.responseText);
var date = new Date();
if (!Ext.isEmpty(Json.data)) {
if (Json.data.scheme == 'HTTP_Digest') {
var auth = new Digest({
usr : Ext.getCmp('logId').getValue(),
pwd : Ext.getCmp('pwdId').getValue(),
realm : Json.data.realm
});
var A1 = auth.getA1();
// stockage en cookie du mode d'authorization
Ext.util.Cookies.set('A1', A1);
Ext.util.Cookies.set('userLogin', auth.usr, date.add(Date.MINUTE, 1));
Ext.util.Cookies.set('scheme', Json.data.scheme);
Ext.util.Cookies.set('algorithm', Json.data.algorithm);
Ext.util.Cookies.set('realm', auth.realm);
Ext.util.Cookies.set('nonce', Json.data.nonce);
} else if (Json.data.scheme == "HTTP_Basic") {
var usr = Ext.getCmp('logId').getValue();
var pwd = Ext.getCmp('pwdId').getValue();
var tok = usr + ':' + pwd;
var hash = Base64.encode(tok);
var auth = 'Basic ' + hash;
// stockage en cookie du mode d'authorization
Ext.util.Cookies.set('userLogin', usr, date.add(Date.MINUTE, 1));
Ext.util.Cookies.set('scheme', Json.data.scheme);
Ext.util.Cookies.set('hashCode', auth, date.add(Date.MINUTE, 1));
}
}
this.login();
},
failure : alertFailure
});
},
login : function () {
if (!Ext.getCmp('frmLogin').getForm().isValid()) {
Ext.getCmp('sbWinLogin').setStatus({
text : i18n.get('warning.checkForm'),
iconCls : 'x-status-error'
});
return;
}
Ext.getCmp('winLogin').body.mask();
Ext.getCmp('sbWinLogin').showBusy();
Ext.Ajax.request({
url : this.url,
method : 'GET',
scope : this,
success : function (response, opts) {
try {
var Json = Ext.decode(response.responseText);
if (Json.success) {
// var date = new Date();
Ext.apply(Ext.Ajax.defaultHeaders, {
"Authorization" : Ext.util.Cookies.get('hashCode')
});
Ext.getCmp('winLogin').close();
// this.handler.call(this.scope || this);
if (this.chooseLocation) {
if (this.combo.getValue() == 1) {
window.location.href = loadUrl.get('APP_URL') + '/login-redirect?kwd=/client-user/index.html';
// window.location.href =
// "/sitools/client-user/index.html?authorization="
// + hash;
} else {
Ext.Ajax.request({
url : loadUrl.get('APP_URL') + '/login-redirect?kwd=/client-admin',
method : "GET",
success : function (response) {
Ext.Msg.alert('error login.js redirect with authorization');
}
});
// window.location.href =
// "/sitools/client-admin";
}
} else {
window.location.reload();
}
} else {
Ext.util.Cookies.set('userLogin', "", new Date().add(Date.MINUTE, COOKIE_DURATION * -1));
Ext.util.Cookies.set('scheme', "", new Date().add(Date.MINUTE, COOKIE_DURATION * -1));
Ext.util.Cookies.set('hashCode', "", new Date().add(Date.MINUTE, COOKIE_DURATION * -1));
var txt = i18n.get('warning.serverError') + ': ' + Json.message;
Ext.getCmp('winLogin').body.unmask();
Ext.getCmp('sbWinLogin').setStatus({
// text: ret.error ? ret.error :
// i18n.get('warning.serverUnreachable'),
text : txt,
iconCls : 'x-status-error'
});
}
} catch (err) {
Ext.Msg.alert(i18n.get('label.error'), err);
}
},
failure : function (response, opts) {
Ext.util.Cookies.set('userLogin', "", new Date().add(Date.MINUTE, COOKIE_DURATION * -1));
Ext.util.Cookies.set('scheme', "", new Date().add(Date.MINUTE, COOKIE_DURATION * -1));
Ext.util.Cookies.set('hashCode', "", new Date().add(Date.MINUTE, COOKIE_DURATION * -1));
var txt;
if (response.status == 200) {
var ret = Ext.decode(response.responseText).error;
txt = i18n.get('msg.error') + ': ' + ret;
} else {
txt = i18n.get('warning.serverError') + ': ' + response.statusText;
}
Ext.getCmp('winLogin').body.unmask();
Ext.getCmp('sbWinLogin').setStatus({
// text: ret.error ? ret.error :
// i18n.get('warning.serverUnreachable'),
text : txt,
iconCls : 'x-status-error'
});
}
});
}
});
Ext.reg('s-login', sitools.userProfile.Login);
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n,document*/
Ext.namespace('sitools.userProfile');
/*
* config { url + handler }
*/
/**
* @cfg {string} url the url to request when register
* @cfg {string} login the url to login
* @class sitools.userProfile.Register
* @extends Ext.Window
*/
sitools.userProfile.Register = Ext.extend(Ext.Window, {
id: 'winRegister',
layout: 'hbox',
width: 420,
height: 490,
resizable: false,
closable: false,
modal: true,
initComponent: function () {
this.title = i18n.get('label.register');
this.captchaUrl = loadUrl.get('APP_URL') + loadUrl.get('APP_INSCRIPTIONS_USER_URL') + '/captcha?width=300&height=50';
this.bbar = new Ext.ux.StatusBar({
text: i18n.get('label.ready'),
id: 'sbWinRegister',
iconCls: 'x-status-valid'
});
this.captcha = new Ext.BoxComponent({
id : 'captchaBox',
autoEl: {
tag: 'img',
src: this.captchaUrl + '&_dc=' + new Date().getTime()
},
fieldLabel : i18n.get('label.captcha'),
height : 50,
width : 300,
anchor: '100%'
});
this.items = [{
xtype: 'form',
// frame: false,
border: false,
buttonAlign: 'center',
id: 'frmRegister',
bodyStyle: 'padding:10px 10px 0px 60px; background:url("'+loadUrl.get('APP_URL')+'/common/res/images/ux/register-big.gif") no-repeat;',
width: 400,
height : 420,
labelWidth: 120,
items: [{
xtype: 'textfield',
fieldLabel: i18n.get('label.login'),
name: 'identifier',
id: 'regLogin',
allowBlank: false,
vtype: 'uniquelogin',
anchor: '100%'
}, {
xtype: 'textfield',
fieldLabel: i18n.get('label.firstName'),
name: 'firstName',
id: 'regFirstName',
allowBlank: false,
anchor: '100%'
}, {
xtype: 'textfield',
fieldLabel: i18n.get('label.lastName'),
name: 'lastName',
id: 'regLastName',
allowBlank: false,
anchor: '100%'
}, {
xtype: 'textfield',
fieldLabel: i18n.get('label.password'),
name: 'password',
allowBlank: false,
inputType: 'password',
vtype: 'passwordlength',
id: 'pass1',
anchor: '100%'
}, {
xtype: 'textfield',
fieldLabel: i18n.get('label.confirmPassword'),
name: 'cpassword',
submitValue: false,
allowBlank: false,
inputType: 'password',
id: 'pass2',
initialPassField: 'pass1',
vtype: 'password',
anchor: '100%'
}, {
xtype: 'textfield',
fieldLabel: i18n.get('label.email'),
id: 'regEmail',
name: 'email',
vtype: 'uniqueemail',
allowBlank: false,
validationEvent: '',
anchor: '100%'
}, {
xtype : 'textfield',
name : 'organisation',
fieldLabel : i18n.get('label.organisation'),
anchor : '100%'
}, {
xtype: 'textarea',
fieldLabel: i18n.get('label.comment'),
id: 'regComment',
name: 'comment',
validationEvent: '',
height: 40,
anchor: '100%'
},
this.captcha,
{
xtype: 'button',
text: i18n.get('label.captchaReload'),
icon : loadUrl.get('APP_URL') + '/common/res/images/icons/refresh.png',
x : 150,
arrowAlign : 'right',
reloadUrl : this.captchaUrl,
handler : function () {
Ext.util.Cookies.clear('captcha');
var box = Ext.get('captchaBox');
box.dom.src = this.reloadUrl + '&_dc=' + new Date().getTime();
box.slideIn('l');
}
},
{
xtype: 'textfield',
fieldLabel: i18n.get('label.fieldCaptcha'),
name: 'captcha',
id: 'captcha',
allowBlank: false,
anchor: '100%'
},
{
xtype: 'checkbox',
fieldLabel: String.format(i18n.get('label.acceptCGU'), URL_CGU),
id: 'acceptCGU',
name: 'acceptCGU',
height: 40,
anchor: '100%',
submitValue : false
}],
buttons: [
{ text: i18n.get('label.register'), handler: this.register, scope: this },
{ text: i18n.get('label.reset'), reloadUrl : this.captchaUrl, handler: function () {
Ext.getCmp('frmRegister').getForm().reset();
Ext.getCmp('sbWinRegister').setStatus({
text: i18n.get('label.ready'),
iconCls: 'x-status-valid'
});
Ext.util.Cookies.clear('captcha');
var box = Ext.get('captchaBox');
box.dom.src = this.reloadUrl + '&_dc=' + new Date().getTime();
box.slideIn('l');
}
},
{ text: i18n.get('label.login'), hidden: !this.register, scope: this,
icon: loadUrl.get('APP_URL') + '/common/res/images/icons/refresh.png',
handler: function () {
Ext.getCmp('winRegister').close();
var login = new sitools.userProfile.Login({
closable: this.closable,
url: this.login,
register: this.url,
handler: this.handler
});
login.show();
}
}
]
}];
sitools.userProfile.Register.superclass.initComponent.call(this);
},
register : function () {
var f = Ext.getCmp('frmRegister').getForm();
if (!f.findField('acceptCGU').getValue()) {
Ext.getCmp('sbWinRegister').setStatus({
text: i18n.get('label.mustAcceptCGU'),
iconCls: 'x-status-error'
});;
return;
}
if (! f.isValid()) {
Ext.getCmp('sbWinRegister').setStatus({
text: i18n.get('warning.checkForm'),
iconCls: 'x-status-error'
});
this.reloadCaptcha();
return;
}
var putObject = new Object();
putObject.properties = [];
Ext.iterate(f.getValues(), function (key, value) {
if (key == 'organisation') {
putObject.properties.push({
name : "organisation",
value : value,
scope : "Editable"
});
} else {
if (key != 'captcha') {
putObject[key] = value;
}
}
}, this);
var cook = Ext.util.Cookies.get('captcha');
var capt = f.findField('captcha').getValue();
Ext.getCmp('winRegister').body.mask();
Ext.getCmp('sbWinRegister').showBusy();
Ext.Ajax.request({
url: this.url,
method: 'POST',
jsonData: putObject,
params : {
"captcha.id" : cook,
"captcha.key" : capt
},
scope: this,
success: function (response, opts) {
var json = Ext.decode(response.responseText);
if (json.success){
new Ext.ux.Notification({
iconCls : 'x-icon-information',
title : i18n.get('label.information'),
html : i18n.get('label.registerSent'),
autoDestroy : true,
hideDelay : 1000
}).show(document);
Ext.getCmp('winRegister').close();
}
else {
Ext.getCmp('winRegister').body.unmask();
Ext.getCmp('sbWinRegister').setStatus({
text : json.message,
iconCls: 'x-status-error'
});
}
if (this.handler !== null && this.handler !== undefined) {
this.handler.call(this.scope || this);
}
},
failure: function (response, opts) {
var txt;
if (response.status == 200) {
var ret = Ext.decode(response.responseText).message;
txt = i18n.get('msg.error') + ': ' + ret;
} else if (response.status == 403){
txt = i18n.get('msg.wrongCaptcha');
} else {
txt = i18n.get('warning.serverError') + ': ' + response.statusText;
}
Ext.getCmp('winRegister').body.unmask();
Ext.getCmp('sbWinRegister').setStatus({
text : txt,
iconCls: 'x-status-error'
});
this.reloadCaptcha();
}
});
},
reloadCaptcha : function () {
Ext.util.Cookies.clear('captcha');
var box = Ext.get('captchaBox');
box.dom.src = this.captchaUrl + '&_dc=' + new Date().getTime();
box.slideIn('l');
var f = Ext.getCmp('frmRegister').getForm();
var capt = f.findField('captcha').setValue("");
}
});
Ext.reg('s-register', sitools.userProfile.Register);
/*******************************************************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* SITools2 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* SITools2. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
Ext.namespace('sitools.userProfile');
/**
* A specific window to reset user password
* @cfg {boolean} closable Window config
* @cfg {string} url The url to send reset request
* @cfg {} handler A method to call after success
* @class sitools.userProfile.resetPassword
* @extends Ext.Window
*/
sitools.userProfile.resetPassword = Ext.extend(Ext.Window, {
id : 'winPassword',
layout : 'hbox',
width : 420,
height : 183,
resizable : false,
// closable: true,
modal : true,
initComponent : function () {
this.title = i18n.get('label.resetPassword');
this.bbar = new Ext.ux.StatusBar({
text : i18n.get('label.ready'),
id : 'sbWinPassword',
iconCls : 'x-status-valid'
});
this.items = [ {
xtype : 'form',
// frame : false,
border : false,
buttonAlign : 'center',
id : 'frmResetPassword',
bodyStyle : 'padding:10px 10px 0px 60px; background:url("'+loadUrl.get('APP_URL')+'/common/res/images/ux/login-big.gif") no-repeat;',
width : 400,
labelWidth : 120,
items : [ {
xtype : 'textfield',
fieldLabel : i18n.get('label.login'),
name : 'identifier',
id : 'regLogin',
allowBlank : false,
anchor : '100%'
}, {
xtype : 'textfield',
fieldLabel : i18n.get('label.email'),
id : 'regEmail',
name : 'email',
vtype : 'uniqueemail',
allowBlank : false,
validationEvent : '',
anchor : '100%'
}, {
xtype : 'textfield',
fieldLabel : i18n.get('label.emailConfirm'),
id : 'regEmailConfirm',
name : 'emailConfirm',
vtype : 'uniqueemail',
allowBlank : false,
validationEvent : '',
anchor : '100%'
} ],
buttons : [ {
text : i18n.get('label.resetPassword'),
handler : this.reset,
scope : this
}, {
text : i18n.get('label.reset'),
handler : function () {
Ext.getCmp('frmResetPassword').getForm().reset();
Ext.getCmp('sbWinPassword').setStatus({
text : i18n.get('label.ready'),
iconCls : 'x-status-valid'
});
}
} ]
} ];
sitools.userProfile.resetPassword.superclass.initComponent.call(this);
},
reset : function () {
var f = Ext.getCmp('frmResetPassword').getForm();
if (f.findField('email').getValue() != f.findField('emailConfirm').getValue()) {
Ext.getCmp('sbWinPassword').setStatus({
text : i18n.get('warning.checkForm'),
iconCls : 'x-status-error'
});
return;
}
if (!f.isValid()) {
Ext.getCmp('sbWinPassword').setStatus({
text : i18n.get('warning.checkForm'),
iconCls : 'x-status-error'
});
return;
}
var putObject = new Object();
Ext.iterate(f.getValues(), function (key, value) {
if (key != 'emailConfirm') {
putObject[key] = value;
}
}, this);
Ext.getCmp('winPassword').body.mask();
Ext.getCmp('sbWinPassword').showBusy();
Ext.Ajax.request({
url : this.url,
method : 'PUT',
jsonData : putObject,
scope : this,
success : function (response, opts) {
var json = Ext.decode(response.responseText);
if (json.success) {
Ext.getCmp('winPassword').body.unmask();
Ext.getCmp('sbWinPassword').setStatus({
text : json.message,
iconCls : 'x-status-valid'
});
Ext.getCmp('winPassword').close();
var notify = new Ext.ux.Notification({
iconCls : 'x-icon-information',
title : i18n.get('label.information'),
html : i18n.get('label.passwordSent') + json.message,
autoDestroy : true,
hideDelay : 1300
});
notify.show(document);
} else {
Ext.getCmp('winPassword').body.unmask();
Ext.getCmp('sbWinPassword').setStatus({
text : json.message,
iconCls : 'x-status-error'
});
}
if (this.handler !== null && this.handler !== undefined) {
this.handler.call(this.scope || this);
}
},
failure : function (response, opts) {
var txt;
if (response.status == 200) {
var ret = Ext.decode(response.responseText).message;
txt = i18n.get('msg.error') + ': ' + ret;
} else {
txt = i18n.get('warning.serverError') + ': ' + response.statusText;
}
Ext.getCmp('winPassword').body.unmask();
Ext.getCmp('sbWinPassword').setStatus({
text : txt,
iconCls : 'x-status-error'
});
}
});
}
});
/*******************************************************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* SITools2 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* SITools2. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/* global Ext, sitools, i18n,document */
Ext.namespace('sitools.userProfile');
/*
* config { url + handler }
*/
sitools.userProfile.editProfile = Ext.extend(Ext.Panel, {
// id : 'winEditProfile',
// layout : 'hbox',
// width : 420,
// height : 410,
// resizable : false,
// closable : true,
// modal : true,
padding : "10px 10px 0px 60px",
frame : true,
layout : "fit",
initComponent : function () {
this.bodyStyle = "background-image: url("+loadUrl.get('APP_URL')+"/common/res/images/ux/login-big.gif);" +
"background-position: top left;" +
"background-repeat: no-repeat;";
// this.title = i18n.get('label.editProfile');
this.bbar = new Ext.ux.StatusBar({
text : i18n.get('label.ready'),
id : 'sbWinEditProfile',
iconCls : 'x-status-valid'
});
var storeProperties = new Ext.data.JsonStore({
fields : [ {
name : 'name',
type : 'string'
}, {
name : 'value',
type : 'string'
}, {
name : 'scope',
type : 'string'
} ],
autoLoad : false
});
var smProperties = new Ext.grid.RowSelectionModel({
singleSelect : true
});
var cmProperties = new Ext.grid.ColumnModel({
columns : [ {
header : i18n.get('headers.name'),
dataIndex : 'name',
editor : new Ext.form.TextField({
readOnly : true
})
}, {
header : i18n.get('headers.value'),
dataIndex : 'value',
editor : new Ext.form.TextField({
allowBlank : false
})
}],
defaults : {
sortable : false,
width : 100
}
});
this.gridProperties = new Ext.grid.EditorGridPanel({
title : i18n.get('title.properties'),
id : 'userGridProperties',
height : 130,
autoScroll : true,
clicksToEdit : 1,
store : storeProperties,
cm : cmProperties,
sm : smProperties,
viewConfig : {
forceFit : true,
getRowClass : function (row, col) {
var data = row.data;
if (data.scope == 'ReadOnly') {
return "row-grid-readOnly";
}
}
},
listeners : {
beforeedit : function (e) {
var scope = e.record.data.scope;
var name = e.field;
if (scope == 'ReadOnly' || name == 'name') {
return false;
}
}
}
});
this.items = [ {
xtype : 'form',
flex : 1,
border : false,
buttonAlign : 'center',
id : 'frmEditProfile',
labelWidth : 120,
items : [ {
xtype : 'textfield',
name : 'identifier',
fieldLabel : i18n.get('label.login'),
anchor : '100%',
allowBlank : false,
readOnly : true,
style : {
color : '#C0C0C0'
},
id : "nameField"
}, {
xtype : 'textfield',
fieldLabel : i18n.get('label.firstName'),
name : 'firstName',
id : 'regFirstName',
allowBlank : false,
anchor : '100%'
}, {
xtype : 'textfield',
fieldLabel : i18n.get('label.lastName'),
name : 'lastName',
id : 'regLastName',
allowBlank : false,
anchor : '100%'
}, {
xtype : 'textfield',
fieldLabel : i18n.get('label.password'),
anchor : '100%',
inputType : 'password',
name : 'secret',
value : '',
id : "passwordField",
vtype : 'passwordlength'
}, {
id : "confirmSecret",
xtype : 'textfield',
fieldLabel : i18n.get('label.confirmPassword'),
anchor : '100%',
inputType : 'password',
initialPassField : 'passwordField',
vtype : 'password',
name : 'confirmSecret',
submitValue : false,
value : ''
}, {
xtype : 'textfield',
fieldLabel : i18n.get('label.email'),
id : 'regEmail',
name : 'email',
vtype : 'uniqueemail',
allowBlank : false,
validationEvent : '',
anchor : '100%'
}, this.gridProperties ],
buttons : [ {
text : i18n.get('label.saveEdit'),
x : 30,
handler : this.saveEdit,
scope : this
}]
} ];
sitools.userProfile.editProfile.superclass.initComponent.call(this);
},
saveEdit : function () {
var f = Ext.getCmp('frmEditProfile').getForm();
if (!f.isValid()) {
Ext.getCmp('sbWinEditProfile').setStatus({
text : i18n.get('warning.checkForm'),
iconCls : 'x-status-error'
});
return;
}
var putObject = f.getValues();
putObject.properties = [];
this.gridProperties.getStore().each(function (item) {
putObject.properties.push({
name : item.data.name,
value : item.data.value,
scope : item.data.scope
});
});
this.body.mask();
Ext.getCmp('sbWinEditProfile').showBusy();
Ext.Ajax.request({
url : this.url,
method : 'PUT',
jsonData : putObject,
scope : this,
success : function (response, opts) {
var json = Ext.decode(response.responseText);
if (json.success) {
this.ownerCt.close();
var notify = new Ext.ux.Notification({
iconCls : 'x-icon-information',
title : i18n.get('label.information'),
html : json.message,
autoDestroy : true,
hideDelay : 1000
});
notify.show(document);
} else {
Ext.getCmp('winEditProfile').body.unmask();
Ext.getCmp('sbWinEditProfile').setStatus({
text : json.message,
iconCls : 'x-status-error'
});
}
if (this.handler !== null && this.handler !== undefined) {
this.handler.call(this.scope || this, putObject);
}
},
failure : function (response, opts) {
var txt;
if (response.status == 200) {
var ret = Ext.decode(response.responseText).message;
txt = i18n.get('msg.error') + ': ' + ret;
} else {
txt = i18n.get('warning.serverError') + ': ' + response.statusText;
}
Ext.getCmp('winEditProfile').body.unmask();
Ext.getCmp('sbWinEditProfile').setStatus({
text : txt,
iconCls : 'x-status-error'
});
}
});
},
onRender : function () {
sitools.userProfile.editProfile.superclass.onRender.apply(this, arguments);
if (this.url) {
Ext.Ajax.request({
url : this.url,
method : 'GET',
scope : this,
success : function (ret) {
var f = this.findByType('form')[0].getForm();
var data = Ext.decode(ret.responseText);
if (data.user !== undefined) {
f.setValues(data.user);
f.findField('secret').setValue('');
if (!Ext.isEmpty(data.user.properties)) {
Ext.each(data.user.properties, function (property) {
var rec = new Ext.data.Record({
name : property.name,
value : property.value,
scope : property.scope
});
this.gridProperties.getStore().add(rec);
}, this);
}
}
},
failure : alertFailure
});
}
},
/**
* Method called when trying to show this component with fixed navigation
*
* @param {sitools.user.component.viewDataDetail} me the dataDetail view
* @param {} config config options
* @returns
*/
showMeInFixedNav : function (me, config) {
Ext.apply(config.windowSettings, {
width : config.windowSettings.winWidth || DEFAULT_WIN_WIDTH,
height : config.windowSettings.winHeight || DEFAULT_WIN_HEIGHT
});
SitoolsDesk.openModalWindow(me, config);
},
/**
* Method called when trying to show this component with Desktop navigation
*
* @param {sitools.user.component.viewDataDetail} me the dataDetail view
* @param {} config config options
* @returns
*/
showMeInDesktopNav : function (me, config) {
Ext.apply(config.windowSettings, {
width : config.windowSettings.winWidth || DEFAULT_WIN_WIDTH,
height : config.windowSettings.winHeight || DEFAULT_WIN_HEIGHT
});
SitoolsDesk.openModalWindow(me, config);
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
var loginErrLength = 'Login minimum 4 character !';
var loginErrUnique = 'Login already in use !';
var loginSuccess = 'Login avaliable';
var emailErrFormat = 'Email not valid !';
var emailErrUnique = 'Email already in use !';
var emailSuccess = 'Email valid & avaliable';
Ext.apply(Ext.form.VTypes, {
uniqueloginMask : /[a-z0-9_\.\-@\+]/i,
uniquelogin : function(val) {
if (val.length < 4) {
Ext.apply(Ext.form.VTypes, {
uniqueloginText: loginErrLength
});
return false;
} else {
/*Ext.Ajax.request({
url: 'user/ext_is_unique_login',
method: 'POST',
params: 'login=' + val,
success: function(o) {
if (o.responseText == 0) {
resetLoginValidator(false);
Ext.apply(Ext.form.VTypes, {
uniqueloginText: loginErrUnique
});
return false;
} else {
resetLoginValidator(true);
}
}
});*/
return true;
}
},
uniqueloginText : loginErrUnique,
uniqueemailMask : /[a-z0-9_\.\-@\+]/i,
uniqueemail : function(val) {
var uniqueemail = /^(\w+)([\-+.][\w]+)*@(\w[\-\w]*\.){1,5}([A-Za-z]){2,6}$/;
if (uniqueemail.test(val)) {
/*
Ext.Ajax.request({
url: BASE_URL + 'user/ext_is_unique_email',
method: 'POST',
params: 'email=' + val,
success: function(o) {
if (o.responseText == 0) {
resetEmailValidator(false);
Ext.apply(Ext.form.VTypes, {
uniqueemailText: emailErrUnique
});
} else {
resetEmailValidator(true);
}
}
});*/
return true;
} else {
return false;
}
},
uniqueemailText : emailErrFormat,
password : function(val, field) {
if (field.initialPassField) {
var pwd = Ext.getCmp(field.initialPassField);
return (val == pwd.getValue());
}
return true;
},
passwordText : 'Passwords do not match',
passwordlength : function(val) {
if (val.length < 6 || val.length > 40) {
return false;
} else {
return true;
}
},
passwordlengthText : 'Invalid Password Length. It must be between 6 and 40'
});
function resetLoginValidator(is_error) {
Ext.apply(Ext.form.VTypes, {
uniquelogin : function(val) {
if (val.length < 4) {
Ext.apply(Ext.form.VTypes, {
uniqueloginText: loginErrLength
});
return false;
} else {
/*
Ext.Ajax.request({
url: 'user/ext_is_unique_login',
method: 'POST',
params: 'login=' + val,
success: function(o) {
if (o.responseText == 0) {
resetLoginValidator(false);
} else {
resetLoginValidator(true);
}
}
});
return is_error;
*/return true;
}
}
});
}
function resetEmailValidator(value) {
Ext.apply(Ext.form.VTypes, {
uniqueemail : function(val) {
var uniqueemail = /^(\w+)([\-+.][\w]+)*@(\w[\-\w]*\.){1,5}([A-Za-z]){2,6}$/;
if (uniqueemail.test(val)) {
/*Ext.Ajax.request({
url: BASE_URL + 'user/ext_is_unique_email',
method: 'POST',
params: 'email=' + val,
success: function(o) {
if (o.responseText == 0) {
resetEmailValidator(false);
Ext.apply(Ext.form.VTypes, {
uniqueemailText: emailErrUnique
});
} else {
resetEmailValidator(true);
}
}
});*/return true;
} else {
return false;
}
return (value);
}
});
}
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/** (c) 2007-2008 Timo Michna / www.matikom.de
* All rights reserved
*
* This script is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
/***************************************************************
* For commercial use, ask the author for permission and different license
***************************************************************/
Ext.namespace('Ext.ux');
Ext.namespace('Ext.ux.Plugin');
Ext.ux.Plugin.LiteRemoteComponent = function (config){
var defaultType = config.xtype || 'panel';
var callback = function(res){
this.container.add(Ext.ComponentMgr.create(Ext.decode(res.responseText), defaultType)).show();
this.container.doLayout() ;
};
return{
init : function (container){
this.container = container;
Ext.Ajax.request(Ext.apply(config, {success: callback, scope: this}));
}
}
};
/**
* @author Timo Michna / matikom
* @class Ext.ux.Plugin.RemoteComponent
* @extends Ext.util.Observable
* @constructor
* @param {Object} config
* @version 0.3.0
* Plugin for Ext.Container/Ext.Toolbar Elements to dynamically
* add Components from a remote source to the Element�s body.
* Loads configuration as JSON-String from a remote source.
* Creates the Components from configuration.
* Adds the Components to the Container body.
* Additionally to its own config options the class accepts all the
* configuration options required to configure its internal Ext.Ajax.request().
*/
Ext.ux.Plugin.RemoteComponent = function (config){
/**
* @cfg {String} breakOn
* set to one of the plugins events, to stop any
* further processing of the plugin, when the event fires.
*/
/**
* @cfg {mixed} loadOn
* Set to one of the Containers events {String}, to defer
* further processing of the plugin to when the event fires.
* Set as an object literal {event: 'event', scope: 'scope'}
* to listen for a different components (not the container) event.
* Set to an numeric Array to listen to different events or components.
* Use String or Literal style in numeric Array. Plugin will load by
* the first occurence of any of the events.
*/
/**
* @cfg {String} xtype
* Default xtype for loaded toplevel component.
* Overwritten by config.xtype or xtype declaration
* Defaults to 'panel'
* in loaded toplevel component.
*/
/**
* @cfg {Boolean} purgeSubscribers
* set to 'true' to avoid unsubstribing all listeners after successfull process chain
* Defaults to false
*/
/**
* @cfg {Mixed el} mask
* The element or DOM node, or its id to mask with loading indicator
*/
/**
* @cfg {Object} maskConfig
* Configuration for LoadMask.
* only effective if config option 'mask' is set.
*/
var defaultType = config.xtype || 'panel';
Ext.applyIf(config, {
purgeSubscribers:true
});
this.initialConfig = config;
Ext.apply(this, config);
//this.purgeSubscribers = config.purgeSubscribers || true;
this.addEvents({
/**
* @event beforeload
* Fires before AJAX request. Return false to stop further processing.
* @param {Object} config
* @param {Ext.ux.Plugin.RemoteComponent} this
*/
'beforeload' : true,
/**
* @event beforecreate
* Fires before creation of new Components from AJAX response.
* Return false to stop further processing.
* @param {Object} JSON-Object decoded from AJAX response
* @param {Ext.ux.Plugin.RemoteComponent} this
*/
'beforecreate' : true,
/**
* @event beforeadd
* Fires before adding the new Components to the Container.
* Return false to stop further processing.
* @param {Object} new Components created from AJAX response.
* @param {Ext.ux.Plugin.RemoteComponent} this
*/
'beforeadd' : true,
/**
* @event beforecomponshow
* Fires before show() is called on the new Components.
* Return false to stop further processing.
* @param {Object} new Components created from AJAX response.
* @param {Ext.ux.Plugin.RemoteComponent} this
*/
'beforecomponshow': true,
/**
* @event beforecontainshow
* Fires before show() is called on the Container.
* Return false to stop further processing.
* @param {Object} new Components created from AJAX response.
* @param {Ext.ux.Plugin.RemoteComponent} this
*/
'beforecontainshow': true,
/**
* @event success
* Fires after full process chain.
* Return false to stop further processing.
* @param {Object} new Components created from AJAX response.
* @param {Ext.ux.Plugin.RemoteComponent} this
*/
'success': true
});
Ext.ux.Plugin.RemoteComponent.superclass.constructor.call(this, config);
// set breakpoint
if(config.breakOn){
this.on(config.breakOn, function(){return false;});
}
/**
* private
* method adds component to container.
* Creates Components from responseText and
* and populates Components in Container.
* @param {Object} JSON Config for new component.
*/
var renderComponent = function(JSON){
if(this.fireEvent('beforeadd', JSON, this)){
//this.container.initComponent();
var component = this.container.add(JSON);
component.fireEvent ('bodyResize', this);
//alert (this.container.ownerCt.height());
if(this.fireEvent('beforecomponshow', component, this)){
return component;
}
}
}.createDelegate(this);
/**
* private
* Callback method for successful Ajax request.
* Creates Components from responseText and
* and populates Components in Container.
* @param {Object} response object from successful AJAX request.
*/
var callback = function(res){
var JSON = Ext.decode(res.responseText);
if(this.fireEvent('beforecreate', JSON, this)){
var component = null;
//JSON = JSON instanceof Array ? JSON[0] : JSON;
if(JSON instanceof Array){
Ext.each(JSON, function(j, i){
component = renderComponent(j).show();;
});
}else{
component = renderComponent(JSON).show();
}
if(this.fireEvent('beforecontainshow', component, this)){
this.container.ownerCt.doLayout();
this.fireEvent('success', component, this);
}
}
if(this.purgeSubscribers){
this.purgeListeners();
}
}.createDelegate(this);
/**
* public
* Processes the AJAX request.
* Generally only called internal. Can be called external,
* when processing has been stopped or defered by config
* options breakOn or loadOn.
*/
this.load = function(){
if(this.fireEvent('beforeload', config, this)){
if(config.mask){
var mask = new Ext.LoadMask(Ext.getDom(config.mask), Ext.apply({msg:'loading components...'}, config.maskConfig || {}));
mask.show();
this.on('success', mask.hide, mask);
}
Ext.Ajax.request(Ext.apply(config, {success: callback, scope: this}));
}
};
/**
* public
* Initialization method called by the Container.
*/
this.init = function (container){
container.on('beforedestroy', function(){this.purgeListeners();}, this);
this.container = container;
if(config.loadOn){
if(config.loadOn instanceof Array){
Ext.each(config.loadOn, function(l, i, a){
var evt = l.event || l.loadOn;
var defer = function (){
this.load();
Ext.each(a, function(lo){
(lo.scope || container).un(evt, defer, this);
}.createDelegate(this));
}.createDelegate(this);
(l.scope || container).on(evt, defer, this);
}.createDelegate(this));
}else{
(config.loadOn.scope || container).on((config.loadOn.event || config.loadOn), this.load, this, {single:true});
}
}else{
this.load();
}
};
};
Ext.extend(Ext.ux.Plugin.RemoteComponent, Ext.util.Observable);
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*
* Ext JS Library 3.3.0
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
Ext.ns('Ext.ux.form');
/**
* @class Ext.ux.form.MultiSelect
* @extends Ext.form.Field
* A control that allows selection and form submission of multiple list items.
*
* @history
* 2008-06-19 bpm Original code contributed by Toby Stuart (with contributions from Robert Williams)
* 2008-06-19 bpm Docs and demo code clean up
*
* @constructor
* Create a new MultiSelect
* @param {Object} config Configuration options
* @xtype multiselect
*/
Ext.ux.form.MultiSelect = Ext.extend(Ext.form.Field, {
/**
* @cfg {String} legend Wraps the object with a fieldset and specified legend.
*/
/**
* @cfg {Ext.ListView} view The {@link Ext.ListView} used to render the multiselect list.
*/
/**
* @cfg {String/Array} dragGroup The ddgroup name(s) for the MultiSelect DragZone (defaults to undefined).
*/
/**
* @cfg {String/Array} dropGroup The ddgroup name(s) for the MultiSelect DropZone (defaults to undefined).
*/
/**
* @cfg {Boolean} ddReorder Whether the items in the MultiSelect list are drag/drop reorderable (defaults to false).
*/
ddReorder:false,
/**
* @cfg {Object/Array} tbar The top toolbar of the control. This can be a {@link Ext.Toolbar} object, a
* toolbar config, or an array of buttons/button configs to be added to the toolbar.
*/
/**
* @cfg {String} appendOnly True if the list should only allow append drops when drag/drop is enabled
* (use for lists which are sorted, defaults to false).
*/
appendOnly:false,
/**
* @cfg {Number} width Width in pixels of the control (defaults to 100).
*/
width:100,
/**
* @cfg {Number} height Height in pixels of the control (defaults to 100).
*/
height:100,
/**
* @cfg {String/Number} displayField Name/Index of the desired display field in the dataset (defaults to 0).
*/
displayField:0,
/**
* @cfg {String/Number} valueField Name/Index of the desired value field in the dataset (defaults to 1).
*/
valueField:1,
/**
* @cfg {Boolean} allowBlank False to require at least one item in the list to be selected, true to allow no
* selection (defaults to true).
*/
allowBlank:true,
/**
* @cfg {Number} minSelections Minimum number of selections allowed (defaults to 0).
*/
minSelections:0,
/**
* @cfg {Number} maxSelections Maximum number of selections allowed (defaults to Number.MAX_VALUE).
*/
maxSelections:Number.MAX_VALUE,
/**
* @cfg {String} blankText Default text displayed when the control contains no items (defaults to the same value as
* {@link Ext.form.TextField#blankText}.
*/
blankText:Ext.form.TextField.prototype.blankText,
/**
* @cfg {String} minSelectionsText Validation message displayed when {@link #minSelections} is not met (defaults to 'Minimum {0}
* item(s) required'). The {0} token will be replaced by the value of {@link #minSelections}.
*/
minSelectionsText:'Minimum {0} item(s) required',
/**
* @cfg {String} maxSelectionsText Validation message displayed when {@link #maxSelections} is not met (defaults to 'Maximum {0}
* item(s) allowed'). The {0} token will be replaced by the value of {@link #maxSelections}.
*/
maxSelectionsText:'Maximum {0} item(s) allowed',
/**
* @cfg {String} delimiter The string used to delimit between items when set or returned as a string of values
* (defaults to ',').
*/
delimiter:',',
/**
* @cfg {Ext.data.Store/Array} store The data source to which this MultiSelect is bound (defaults to <tt>undefined</tt>).
* Acceptable values for this property are:
* <div class="mdetail-params"><ul>
* <li><b>any {@link Ext.data.Store Store} subclass</b></li>
* <li><b>an Array</b> : Arrays will be converted to a {@link Ext.data.ArrayStore} internally.
* <div class="mdetail-params"><ul>
* <li><b>1-dimensional array</b> : (e.g., <tt>['Foo','Bar']</tt>)<div class="sub-desc">
* A 1-dimensional array will automatically be expanded (each array item will be the combo
* {@link #valueField value} and {@link #displayField text})</div></li>
* <li><b>2-dimensional array</b> : (e.g., <tt>[['f','Foo'],['b','Bar']]</tt>)<div class="sub-desc">
* For a multi-dimensional array, the value in index 0 of each item will be assumed to be the combo
* {@link #valueField value}, while the value at index 1 is assumed to be the combo {@link #displayField text}.
* </div></li></ul></div></li></ul></div>
*/
// private
defaultAutoCreate : {tag: "div"},
// private
initComponent: function(){
Ext.ux.form.MultiSelect.superclass.initComponent.call(this);
if(Ext.isArray(this.store)){
if (Ext.isArray(this.store[0])){
this.store = new Ext.data.ArrayStore({
fields: ['value','text'],
data: this.store
});
this.valueField = 'value';
}else{
this.store = new Ext.data.ArrayStore({
fields: ['text'],
data: this.store,
expandData: true
});
this.valueField = 'text';
}
this.displayField = 'text';
} else {
this.store = Ext.StoreMgr.lookup(this.store);
this.displayField = this.store.displayField;
this.valueField = this.store.valueField;
}
this.addEvents({
'dblclick' : true,
'click' : true,
'change' : true,
'drop' : true
});
},
// private
onRender: function(ct, position){
Ext.ux.form.MultiSelect.superclass.onRender.call(this, ct, position);
var fs = this.fs = new Ext.form.FieldSet({
renderTo: this.el,
title: this.legend,
height: this.height - 20,
width: this.width,
style: "padding:0;",
tbar: this.tbar
});
fs.body.addClass('ux-mselect');
this.view = new Ext.ListView({
multiSelect: true,
store: this.store,
columns: [{ header: 'Value', width: 1, dataIndex: this.displayField }],
hideHeaders: true
});
fs.add(this.view);
this.view.on('click', this.onViewClick, this);
this.view.on('beforeclick', this.onViewBeforeClick, this);
this.view.on('dblclick', this.onViewDblClick, this);
this.hiddenName = this.name || Ext.id();
var hiddenTag = { tag: "input", type: "hidden", value: "", name: this.hiddenName };
this.hiddenField = this.el.createChild(hiddenTag);
this.hiddenField.dom.disabled = this.hiddenName != this.name;
fs.doLayout();
},
// private
afterRender: function(){
Ext.ux.form.MultiSelect.superclass.afterRender.call(this);
if (this.ddReorder && !this.dragGroup && !this.dropGroup){
this.dragGroup = this.dropGroup = 'MultiselectDD-' + Ext.id();
}
if (this.draggable || this.dragGroup){
this.dragZone = new Ext.ux.form.MultiSelect.DragZone(this, {
ddGroup: this.dragGroup
});
}
if (this.droppable || this.dropGroup){
this.dropZone = new Ext.ux.form.MultiSelect.DropZone(this, {
ddGroup: this.dropGroup
});
}
if (this.values) {
this.setValue(this.values);
}
},
// private
onViewClick: function(vw, index, node, e) {
this.fireEvent('change', this, this.getValue(), this.hiddenField.dom.value);
this.hiddenField.dom.value = this.getValue();
this.fireEvent('click', this, e);
this.validate();
},
// private
onViewBeforeClick: function(vw, index, node, e) {
if (this.disabled || this.readOnly) {
return false;
}
},
// private
onViewDblClick : function(vw, index, node, e) {
return this.fireEvent('dblclick', vw, index, node, e);
},
/**
* Returns an array of data values for the selected items in the list. The values will be separated
* by {@link #delimiter}.
* @return {Array} value An array of string data values
*/
getValue: function(valueField){
var returnArray = [];
var selectionsArray = this.view.getSelectedIndexes();
if (selectionsArray.length == 0) {return '';}
for (var i=0; i<selectionsArray.length; i++) {
var returnValue = this.store.getAt(selectionsArray[i]).get((valueField != null) ? valueField : this.valueField);
if (Ext.isString(returnValue)){
returnValue = returnValue;
}
returnArray.push(returnValue);
} return returnArray.join(this.delimiter);
},
/**
* Sets a delimited string (using {@link #delimiter}) or array of data values into the list.
* @param {String/Array} values The values to set
*/
setValue: function(values) {
var index;
var selections = [];
this.view.clearSelections();
this.hiddenField.dom.value = '';
if (!values || (values == '')) { return; }
if (!Ext.isArray(values)) { values = values.split(this.delimiter); }
for (var i=0; i<values.length; i++) {
index = this.view.store.indexOf(this.view.store.query(this.valueField,
new RegExp('^' + values[i] + '$', "i")).itemAt(0));
selections.push(index);
}
this.view.select(selections);
this.hiddenField.dom.value = this.getValue();
this.validate();
},
// inherit docs
reset : function() {
this.setValue('');
},
// inherit docs
getRawValue: function(valueField) {
var tmp = this.getValue(valueField);
if (tmp.length) {
tmp = tmp.split(this.delimiter);
}
else {
tmp = [];
}
return tmp;
},
// inherit docs
setRawValue: function(values){
setValue(values);
},
// inherit docs
validateValue : function(value){
if (value.length < 1) { // if it has no value
if (this.allowBlank) {
this.clearInvalid();
return true;
} else {
this.markInvalid(this.blankText);
return false;
}
}
if (value.length < this.minSelections) {
this.markInvalid(String.format(this.minSelectionsText, this.minSelections));
return false;
}
if (value.length > this.maxSelections) {
this.markInvalid(String.format(this.maxSelectionsText, this.maxSelections));
return false;
}
return true;
},
// inherit docs
disable: function(){
this.disabled = true;
if (!Ext.isEmpty(this.hiddenField)){
this.hiddenField.dom.disabled = true;
}
if (!Ext.isEmpty(this.fs)){
this.fs.disable();
}
},
// inherit docs
enable: function(){
this.disabled = false;
this.hiddenField.dom.disabled = false;
this.fs.enable();
},
// inherit docs
destroy: function(){
Ext.destroy(this.fs, this.dragZone, this.dropZone);
Ext.ux.form.MultiSelect.superclass.destroy.call(this);
}
});
Ext.reg('multiselect', Ext.ux.form.MultiSelect);
//backwards compat
Ext.ux.Multiselect = Ext.ux.form.MultiSelect;
Ext.ux.form.MultiSelect.DragZone = function(ms, config){
this.ms = ms;
this.view = ms.view;
var ddGroup = config.ddGroup || 'MultiselectDD';
var dd;
if (Ext.isArray(ddGroup)){
dd = ddGroup.shift();
} else {
dd = ddGroup;
ddGroup = null;
}
Ext.ux.form.MultiSelect.DragZone.superclass.constructor.call(this, this.ms.fs.body, { containerScroll: true, ddGroup: dd });
this.setDraggable(ddGroup);
};
Ext.extend(Ext.ux.form.MultiSelect.DragZone, Ext.dd.DragZone, {
onInitDrag : function(x, y){
var el = Ext.get(this.dragData.ddel.cloneNode(true));
this.proxy.update(el.dom);
el.setWidth(el.child('em').getWidth());
this.onStartDrag(x, y);
return true;
},
// private
collectSelection: function(data) {
data.repairXY = Ext.fly(this.view.getSelectedNodes()[0]).getXY();
var i = 0;
this.view.store.each(function(rec){
if (this.view.isSelected(i)) {
var n = this.view.getNode(i);
var dragNode = n.cloneNode(true);
dragNode.id = Ext.id();
data.ddel.appendChild(dragNode);
data.records.push(this.view.store.getAt(i));
data.viewNodes.push(n);
}
i++;
}, this);
},
// override
onEndDrag: function(data, e) {
var d = Ext.get(this.dragData.ddel);
if (d && d.hasClass("multi-proxy")) {
d.remove();
}
},
// override
getDragData: function(e){
var target = this.view.findItemFromChild(e.getTarget());
if(target) {
if (!this.view.isSelected(target) && !e.ctrlKey && !e.shiftKey) {
this.view.select(target);
this.ms.setValue(this.ms.getValue());
}
if (this.view.getSelectionCount() == 0 || e.ctrlKey || e.shiftKey) return false;
var dragData = {
sourceView: this.view,
viewNodes: [],
records: []
};
if (this.view.getSelectionCount() == 1) {
var i = this.view.getSelectedIndexes()[0];
var n = this.view.getNode(i);
dragData.viewNodes.push(dragData.ddel = n);
dragData.records.push(this.view.store.getAt(i));
dragData.repairXY = Ext.fly(n).getXY();
} else {
dragData.ddel = document.createElement('div');
dragData.ddel.className = 'multi-proxy';
this.collectSelection(dragData);
}
return dragData;
}
return false;
},
// override the default repairXY.
getRepairXY : function(e){
return this.dragData.repairXY;
},
// private
setDraggable: function(ddGroup){
if (!ddGroup) return;
if (Ext.isArray(ddGroup)) {
Ext.each(ddGroup, this.setDraggable, this);
return;
}
this.addToGroup(ddGroup);
}
});
Ext.ux.form.MultiSelect.DropZone = function(ms, config){
this.ms = ms;
this.view = ms.view;
var ddGroup = config.ddGroup || 'MultiselectDD';
var dd;
if (Ext.isArray(ddGroup)){
dd = ddGroup.shift();
} else {
dd = ddGroup;
ddGroup = null;
}
Ext.ux.form.MultiSelect.DropZone.superclass.constructor.call(this, this.ms.fs.body, { containerScroll: true, ddGroup: dd });
this.setDroppable(ddGroup);
};
Ext.extend(Ext.ux.form.MultiSelect.DropZone, Ext.dd.DropZone, {
/**
* Part of the Ext.dd.DropZone interface. If no target node is found, the
* whole Element becomes the target, and this causes the drop gesture to append.
*/
getTargetFromEvent : function(e) {
var target = e.getTarget();
return target;
},
// private
getDropPoint : function(e, n, dd){
if (n == this.ms.fs.body.dom) { return "below"; }
var t = Ext.lib.Dom.getY(n), b = t + n.offsetHeight;
var c = t + (b - t) / 2;
var y = Ext.lib.Event.getPageY(e);
if(y <= c) {
return "above";
}else{
return "below";
}
},
// private
isValidDropPoint: function(pt, n, data) {
if (!data.viewNodes || (data.viewNodes.length != 1)) {
return true;
}
var d = data.viewNodes[0];
if (d == n) {
return false;
}
if ((pt == "below") && (n.nextSibling == d)) {
return false;
}
if ((pt == "above") && (n.previousSibling == d)) {
return false;
}
return true;
},
// override
onNodeEnter : function(n, dd, e, data){
return false;
},
// override
onNodeOver : function(n, dd, e, data){
var dragElClass = this.dropNotAllowed;
var pt = this.getDropPoint(e, n, dd);
if (this.isValidDropPoint(pt, n, data)) {
if (this.ms.appendOnly) {
return "x-tree-drop-ok-below";
}
// set the insert point style on the target node
if (pt) {
var targetElClass;
if (pt == "above"){
dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
targetElClass = "x-view-drag-insert-above";
} else {
dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
targetElClass = "x-view-drag-insert-below";
}
if (this.lastInsertClass != targetElClass){
Ext.fly(n).replaceClass(this.lastInsertClass, targetElClass);
this.lastInsertClass = targetElClass;
}
}
}
return dragElClass;
},
// private
onNodeOut : function(n, dd, e, data){
this.removeDropIndicators(n);
},
// private
onNodeDrop : function(n, dd, e, data){
if (this.ms.fireEvent("drop", this, n, dd, e, data) === false) {
return false;
}
var pt = this.getDropPoint(e, n, dd);
if (n != this.ms.fs.body.dom)
n = this.view.findItemFromChild(n);
if(this.ms.appendOnly) {
insertAt = this.view.store.getCount();
} else {
insertAt = n == this.ms.fs.body.dom ? this.view.store.getCount() - 1 : this.view.indexOf(n);
if (pt == "below") {
insertAt++;
}
}
var dir = false;
// Validate if dragging within the same MultiSelect
if (data.sourceView == this.view) {
// If the first element to be inserted below is the target node, remove it
if (pt == "below") {
if (data.viewNodes[0] == n) {
data.viewNodes.shift();
}
} else { // If the last element to be inserted above is the target node, remove it
if (data.viewNodes[data.viewNodes.length - 1] == n) {
data.viewNodes.pop();
}
}
// Nothing to drop...
if (!data.viewNodes.length) {
return false;
}
// If we are moving DOWN, then because a store.remove() takes place first,
// the insertAt must be decremented.
if (insertAt > this.view.store.indexOf(data.records[0])) {
dir = 'down';
insertAt--;
}
}
for (var i = 0; i < data.records.length; i++) {
var r = data.records[i];
if (data.sourceView) {
data.sourceView.store.remove(r);
}
this.view.store.insert(dir == 'down' ? insertAt : insertAt++, r);
var si = this.view.store.sortInfo;
if(si){
this.view.store.sort(si.field, si.direction);
}
}
return true;
},
// private
removeDropIndicators : function(n){
if(n){
Ext.fly(n).removeClass([
"x-view-drag-insert-above",
"x-view-drag-insert-left",
"x-view-drag-insert-right",
"x-view-drag-insert-below"]);
this.lastInsertClass = "_noclass";
}
},
// private
setDroppable: function(ddGroup){
if (!ddGroup) return;
if (Ext.isArray(ddGroup)) {
Ext.each(ddGroup, this.setDroppable, this);
return;
}
this.addToGroup(ddGroup);
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n,document,projectGlobal,userStorage*/
Ext.ns('Ext.ux');
Ext.ux.stateFullWindow = Ext.extend(Ext.Window, {
saveSettings : function (componentSettings, forPublicUser) {
if (Ext.isEmpty(userLogin)) {
Ext.Msg.alert(i18n.get('label.warning', 'label.needLogin'));
return;
}
var position = Ext.encode(this.getPosition(true));
var size = Ext.encode(this.getSize());
var putObject = {};
// putObject['datasetId'] = datasetId;
// putObject['componentType'] = componentType;
putObject.componentSettings = componentSettings;
putObject.windowSettings = {};
putObject.windowSettings.size = size;
putObject.windowSettings.position = position;
putObject.windowSettings.specificType = this.specificType;
putObject.windowSettings.moduleId = this.getId();
putObject.windowSettings.typeWindow = this.typeWindow;
putObject.windowSettings.maximized = this.maximized;
var baseFilePath = "/" + DEFAULT_PREFERENCES_FOLDER + "/" + projectGlobal.projectName;
var filePath = componentSettings.preferencesPath;
var fileName = componentSettings.preferencesFileName;
if (Ext.isEmpty(filePath) || Ext.isEmpty(fileName)) {
return;
}
filePath = baseFilePath + filePath;
if (forPublicUser) {
publicStorage.set(fileName, filePath, putObject);
}
else {
userStorage.set(fileName, filePath, putObject);
}
return putObject;
},
//Change the posistion when maximizing the window (according to the desktop position
maximize : function(){
if(!this.maximized){
this.expand(false);
this.restoreSize = this.getSize();
this.restorePos = this.getPosition(true);
if (this.maximizable){
this.tools.maximize.hide();
this.tools.restore.show();
}
this.maximized = true;
this.el.disableShadow();
if(this.dd){
this.dd.lock();
}
if(this.collapsible){
this.tools.toggle.hide();
}
this.el.addClass('x-window-maximized');
this.container.addClass('x-window-maximized-ct');
this.setPosition(0,0);
this.fitContainer();
this.fireEvent('maximize', this);
}
return this;
}
});
Ext.reg('statewindow', Ext.ux.stateFullWindow);
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
Ext.namespace("Ext.ux");
Ext.ux.NotificationMgr = {
positions: []
};
Ext.ux.Notification = Ext.extend(Ext.Window, {
initComponent: function(){
Ext.apply(this, {
iconCls: this.iconCls || 'x-icon-information',
cls: 'x-notification',
width: 200,
autoHeight: true,
plain: false,
draggable: false,
shadow:false,
bodyStyle: 'text-align:center'
});
if(this.autoDestroy) {
this.task = new Ext.util.DelayedTask(this.hide, this);
} else {
this.closable = true;
}
Ext.ux.Notification.superclass.initComponent.apply(this);
},
setMessage: function(msg){
this.body.update(msg);
},
setTitle: function(title, iconCls){
Ext.ux.Notification.superclass.setTitle.call(this, title, iconCls||this.iconCls);
},
onDestroy: function(){
Ext.ux.NotificationMgr.positions.remove(this.pos);
Ext.ux.Notification.superclass.onDestroy.call(this);
},
cancelHiding: function(){
this.addClass('fixed');
if(this.autoDestroy) {
this.task.cancel();
}
},
afterShow: function(){
Ext.ux.Notification.superclass.afterShow.call(this);
Ext.fly(this.body.dom).on('click', this.cancelHiding, this);
if(this.autoDestroy) {
this.task.delay(this.hideDelay || 5000);
}
},
animShow: function(){
this.pos = 0;
while(Ext.ux.NotificationMgr.positions.indexOf(this.pos)>-1)
this.pos++;
Ext.ux.NotificationMgr.positions.push(this.pos);
this.setSize(200,100);
this.el.alignTo(document, "br-br", [ -20, -140-((this.getSize().height+10)*this.pos) ]);
this.el.slideIn('b', {
duration: 1,
callback: this.afterShow,
scope: this
});
},
animHide: function(){
this.el.ghost("b", {
duration: 1,
remove: false,
callback : function () {
Ext.ux.NotificationMgr.positions.remove(this.pos);
this.destroy();
}.createDelegate(this)
});
},
focus: Ext.emptyFn
});
/**
* @class Ext.ux.grid.filter.Filter
* @extends Ext.util.Observable
* Abstract base class for filter implementations.
*/
Ext.ns("sitools.widget");
sitools.widget.Filter = Ext.extend(Ext.Container, {
/**
* @cfg {String} columnAlias
* The {@link Ext.data.Store} columnAlias of the field this filter represents.
*/
columnAlias : null,
layout : "vbox",
layoutConfig : {
align : "left",
pack : "center"
},
specificType : "filter",
constructor : function (config) {
Ext.apply(this, config);
this.layout = 'hbox';
this.columnAlias = config.columnAlias;
this.specificType = "filter";
sitools.widget.Filter.superclass.constructor.call(this);
this.init(config);
if(config && config.value){
this.setValue(config.value);
delete config.value;
}
},
/**
* Template method to be implemented by all subclasses that is to
* initialize the filter and install required menu items.
* Defaults to Ext.emptyFn.
*/
init : Ext.emptyFn,
/**
* Template method to be implemented by all subclasses that is to
* get and return the value of the filter.
* Defaults to Ext.emptyFn.
* @return {Object} The 'serialized' form of this filter
* @methodOf Ext.ux.grid.filter.Filter
*/
getValue : Ext.emptyFn,
/**
* Template method to be implemented by all subclasses that is to
* set the value of the filter and fire the 'update' event.
* Defaults to Ext.emptyFn.
* @param {Object} data The value to set the filter
* @methodOf Ext.ux.grid.filter.Filter
*/
setValue : Ext.emptyFn,
/**
* Template method to be implemented by all subclasses that is to
* validates the provided Ext.data.Record against the filters configuration.
* Defaults to <tt>return true</tt>.
* @param {Ext.data.Record} record The record to validate
* @return {Boolean} true if the record is valid within the bounds
* of the filter, false otherwise.
*/
validateRecord : function(){
return true;
},
_getHeight : Ext.emptyFn,
getFilterData : function (){
return this.getValue();
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
Ext.ns("sitools.widget");
sitools.widget.DateFilter = Ext.extend(sitools.widget.Filter, {
/**
* @cfg {String} iconCls
* The iconCls to be applied to the menu item.
* Defaults to <tt>'ux-gridfilter-text-icon'</tt>.
*/
iconCls : 'ux-gridfilter-text-icon',
emptyText: 'Enter Filter Text...',
selectOnFocus: true,
flex : 0.9,
style: {
"padding-left" : '10px'
},
height : 60,
/**
* @private
* Template method that is to initialize the filter and install required menu items.
*/
init : function (config) {
config = config || {};
this.inputFrom = new Ext.form.DateField({
anchor : "100%",
fieldLabel : "ux-rangemenu-gte",
format : SITOOLS_DEFAULT_IHM_DATE_FORMAT,
labelStyle : "height: 10px",
width : 150
});
this.inputTo = new Ext.form.DateField({
anchor : "100%",
fieldLabel : "ux-rangemenu-lte",
format : SITOOLS_DEFAULT_IHM_DATE_FORMAT,
labelStyle : "height: 10px",
width : 150
});
var formPanel = new Ext.form.FormPanel({
items : [this.inputFrom, this.inputTo],
labelWidth : 21,
bodyBorder : false,
border : false,
layout : 'form',
layoutConfig : {
fieldTpl : new Ext.Template(
'<div class="x-form-item {itemCls}" tabIndex="-1">',
'<label for="{id}" style="{labelStyle}" class="x-form-item-label {label}"></label>',
'<div class="x-form-element" id="x-form-el-{id}" style="{elementStyle}">',
'</div><div class="{clearCls}"></div>',
'</div>'
)
}
})
this.add(formPanel);
},
/**
* @private
* Template method that is to get and return the value of the filter.
* @return {String} The value of this filter
*/
getValue : function () {
var result = [];
if (!Ext.isEmpty(this.inputFrom.getValue())) {
result.push({
"columnAlias" : this.columnAlias,
"data" : {
"comparison" : "gte",
"value" : this.inputFrom.getValue().format(SITOOLS_DATE_FORMAT),
"type" : "date"
}
});
}
if (!Ext.isEmpty(this.inputTo.getValue())) {
result.push({
"columnAlias" : this.columnAlias,
"data" : {
"comparison" : "lte",
"value" : this.inputTo.getValue().format(SITOOLS_DATE_FORMAT),
"type" : "date"
}
});
}
return result;
},
getConfig : function () {
if (!Ext.isEmpty(this.inputFrom.getValue()) || !Ext.isEmpty(this.inputTo.getValue())) {
return {
"columnAlias" : this.columnAlias,
"value" : {
"from" : this.inputFrom.getValue(),
"to" : this.inputTo.getValue()
},
"type" : "date"
};
}
else {
return null;
}
},
/**
* @private
* Template method that is to set the value of the filter.
* @param {Object} value The value to set the filter
*/
setValue : function (value) {
this.inputFrom.setValue(value.from);
this.inputTo.setValue(value.to);
} ,
_getHeight : function () {
return this.height;
}
});
Ext.ns("sitools.widget");
sitools.widget.StringFilter = Ext.extend(sitools.widget.Filter, {
/**
* @cfg {String} iconCls
* The iconCls to be applied to the menu item.
* Defaults to <tt>'ux-gridfilter-text-icon'</tt>.
*/
iconCls : 'ux-gridfilter-text-icon',
emptyText: 'Enter Filter Text...',
selectOnFocus: true,
flex : 0.9,
style: {
"padding-left" : '10px'
},
height : 30,
/**
* @private
* Template method that is to initialize the filter and install required menu items.
*/
init : function (config) {
config = config || {};
this.inputItem = new Ext.form.TextField({
anchor : "100%",
fieldLabel : "ux-gridfilter-text-icon",
labelStyle : "height: 10px",
width : 150
});
var formPanel = new Ext.form.FormPanel({
items : [this.inputItem],
labelWidth : 21,
bodyBorder : false,
border : false,
layout : 'form',
layoutConfig : {
fieldTpl : new Ext.Template(
'<div class="x-form-item {itemCls}" tabIndex="-1">',
'<label for="{id}" style="{labelStyle}" class="x-form-item-label {label}"></label>',
'<div class="x-form-element" id="x-form-el-{id}" style="{elementStyle}">',
'</div><div class="{clearCls}"></div>',
'</div>'
)
}
});
this.add(formPanel);
},
/**
* @private
* Template method that is to get and return the value of the filter.
* @return {String} The value of this filter
*/
getValue : function () {
if (!Ext.isEmpty(this.inputItem.getValue())) {
return [{
"columnAlias" : this.columnAlias,
"data" : {
"comparison" : "LIKE",
"value" : this.inputItem.getValue(),
"type" : "string"
}
}];
}
else {
return [];
}
},
/**
* @private
* Template method that is to get and return the value of the filter.
* @return {String} The value of this filter
*/
getConfig : function () {
if (!Ext.isEmpty(this.inputItem.getValue())) {
return {
"columnAlias" : this.columnAlias,
"value" : this.inputItem.getValue(),
"type" : "string"
};
}
else {
return null;
}
},
/**
* @private
* Template method that is to set the value of the filter.
* @param {Object} value The value to set the filter
*/
setValue : function (value) {
this.inputItem.setValue(value);
},
/**
* Template method that is to validate the provided Ext.data.Record
* against the filters configuration.
* @param {Ext.data.Record} record The record to validate
* @return {Boolean} true if the record is valid within the bounds
* of the filter, false otherwise.
*/
validateRecord : function (record) {
var val = record.get(this.dataIndex);
if(typeof val != 'string') {
return (this.getValue().length === 0);
}
return val.toLowerCase().indexOf(this.getValue().toLowerCase()) > -1;
},
_getHeight : function () {
return this.height;
}
});
Ext.ns("sitools.widget");
sitools.widget.NumericFilter = Ext.extend(sitools.widget.Filter, {
/**
* @cfg {String} iconCls
* The iconCls to be applied to the menu item.
* Defaults to <tt>'ux-gridfilter-text-icon'</tt>.
*/
iconCls : 'ux-gridfilter-text-icon',
emptyText: 'Enter Filter Text...',
selectOnFocus: true,
flex : 0.9,
style: {
"padding-left" : '10px'
},
height : 60,
/**
* @private
* Template method that is to initialize the filter and install required menu items.
*/
init : function (config) {
config = config || {};
this.inputFrom = new Ext.form.NumberField({
anchor : "100%",
fieldLabel : "ux-rangemenu-gte",
labelStyle : "height: 10px",
width : 150
});
this.inputTo = new Ext.form.NumberField({
anchor : "100%",
fieldLabel : "ux-rangemenu-lte",
labelStyle : "height: 10px",
width : 150
});
var formPanel = new Ext.form.FormPanel({
items : [this.inputTo, this.inputFrom],
labelWidth : 21,
bodyBorder : false,
border : false,
layoutConfig : {
fieldTpl : new Ext.Template(
'<div class="x-form-item {itemCls}" tabIndex="-1">',
'<label for="{id}" style="{labelStyle}" class="x-form-item-label {label}"></label>',
'<div class="x-form-element" id="x-form-el-{id}" style="{elementStyle}">',
'</div><div class="{clearCls}"></div>',
'</div>'
)
}
})
this.add(formPanel);
},
/**
* @private
* Template method that is to get and return the value of the filter.
* @return {String} The value of this filter
*/
getValue : function () {
var result = [];
if (!Ext.isEmpty(this.inputFrom.getValue())) {
result.push({
"columnAlias" : this.columnAlias,
"data" : {
"comparison" : "gte",
"value" : this.inputFrom.getValue(),
"type" : "numeric"
}
});
}
if (!Ext.isEmpty(this.inputTo.getValue())) {
result.push({
"columnAlias" : this.columnAlias,
"data" : {
"comparison" : "lte",
"value" : this.inputTo.getValue(),
"type" : "numeric"
}
});
}
return result;
},
getConfig : function () {
if (!Ext.isEmpty(this.inputFrom.getValue()) || !Ext.isEmpty(this.inputTo.getValue())) {
return {
"columnAlias" : this.columnAlias,
"value" : {
"from" : this.inputFrom.getValue(),
"to" : this.inputTo.getValue()
},
"type" : "numeric"
};
}
else {
return null;
}
},
/**
* @private
* Template method that is to set the value of the filter.
* @param {Object} value The value to set the filter
*/
setValue : function (value) {
this.inputFrom.setValue(value.from);
this.inputTo.setValue(value.to);
} ,
_getHeight : function () {
return this.height;
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/**
* @class sitools.widget.FiltersCollection
* @extends Ext.util.MixedCollection
* Class for sitoolsFilter.getValue() collections.
*/
Ext.ns("sitools.widget");
sitools.widget.FiltersCollection = Ext.extend(Ext.util.MixedCollection, {
constructor : function (config) {
sitools.widget.FiltersCollection.superclass.constructor.call(this);
this.addAll(config.filters);
},
getFilterData : function(){
var filters = [];
this.each(function (filter, index, length) {
filters.push(filter);
});
return filters;
}
});/*
* Ext JS Library 3.3.1
* Copyright(c) 2006-2010 Sencha Inc.
* licensing@sencha.com
* http://www.sencha.com/license
*/
Ext.ns('Ext.ux.grid');
/**
* @class Ext.ux.grid.RowExpander
* @extends Ext.util.Observable
* Plugin (ptype = 'rowexpander') that adds the ability to have a Column in a grid which enables
* a second row body which expands/contracts. The expand/contract behavior is configurable to react
* on clicking of the column, double click of the row, and/or hitting enter while a row is selected.
*
* @ptype rowexpander
*/
Ext.ux.grid.RowExpander = Ext.extend(Ext.util.Observable, {
/**
* @cfg {Boolean} expandOnEnter
* <tt>true</tt> to toggle selected row(s) between expanded/collapsed when the enter
* key is pressed (defaults to <tt>true</tt>).
*/
expandOnEnter : true,
/**
* @cfg {Boolean} expandOnDblClick
* <tt>true</tt> to toggle a row between expanded/collapsed when double clicked
* (defaults to <tt>true</tt>).
*/
expandOnDblClick : true,
header : '',
width : 20,
sortable : false,
fixed : true,
hideable: false,
menuDisabled : true,
dataIndex : '',
id : 'expander',
lazyRender : true,
enableCaching : true,
constructor: function (config) {
Ext.apply(this, config);
this.addEvents({
/**
* @event beforeexpand
* Fires before the row expands. Have the listener return false to prevent the row from expanding.
* @param {Object} this RowExpander object.
* @param {Object} Ext.data.Record Record for the selected row.
* @param {Object} body body element for the secondary row.
* @param {Number} rowIndex The current row index.
*/
beforeexpand: true,
/**
* @event expand
* Fires after the row expands.
* @param {Object} this RowExpander object.
* @param {Object} Ext.data.Record Record for the selected row.
* @param {Object} body body element for the secondary row.
* @param {Number} rowIndex The current row index.
*/
expand: true,
/**
* @event beforecollapse
* Fires before the row collapses. Have the listener return false to prevent the row from collapsing.
* @param {Object} this RowExpander object.
* @param {Object} Ext.data.Record Record for the selected row.
* @param {Object} body body element for the secondary row.
* @param {Number} rowIndex The current row index.
*/
beforecollapse: true,
/**
* @event collapse
* Fires after the row collapses.
* @param {Object} this RowExpander object.
* @param {Object} Ext.data.Record Record for the selected row.
* @param {Object} body body element for the secondary row.
* @param {Number} rowIndex The current row index.
*/
collapse: true
});
Ext.ux.grid.RowExpander.superclass.constructor.call(this);
if (this.tpl) {
if (typeof this.tpl == 'string') {
this.tpl = new Ext.Template(this.tpl);
}
this.tpl.compile();
}
this.state = {};
this.bodyContent = {};
},
getRowClass : function (record, rowIndex, p, ds) {
p.cols = p.cols - 1;
var content = this.bodyContent[record.id];
if (!content && !this.lazyRender) {
content = this.getBodyContent(record, rowIndex);
}
if (content) {
p.body = content;
}
return this.state[record.id] ? 'x-grid3-row-expanded' : 'x-grid3-row-collapsed';
},
init : function (grid) {
this.grid = grid;
var view = grid.getView();
view.getRowClass = this.getRowClass.createDelegate(this);
view.enableRowBody = true;
grid.on('render', this.onRender, this);
grid.on('destroy', this.onDestroy, this);
},
// @private
onRender : function () {
var grid = this.grid;
var mainBody = grid.getView().mainBody;
mainBody.on('mousedown', this.onMouseDown, this, {delegate: '.x-grid3-row-expander'});
if (this.expandOnEnter) {
this.keyNav = new Ext.KeyNav(this.grid.getGridEl(), {
'enter' : this.onEnter,
scope: this
});
}
if (this.expandOnDblClick) {
grid.on('rowdblclick', this.onRowDblClick, this);
}
},
// @private
onDestroy : function () {
if (this.keyNav) {
this.keyNav.disable();
delete this.keyNav;
}
/*
* A majority of the time, the plugin will be destroyed along with the grid,
* which means the mainBody won't be available. On the off chance that the plugin
* isn't destroyed with the grid, take care of removing the listener.
*/
var mainBody = this.grid.getView().mainBody;
if (mainBody) {
mainBody.un('mousedown', this.onMouseDown, this);
}
},
// @private
onRowDblClick : function (grid, rowIdx, e) {
this.toggleRow(rowIdx);
},
onEnter : function (e) {
var g = this.grid;
var sm = g.getSelectionModel();
var sels = sm.getSelections();
for (var i = 0, len = sels.length; i < len; i++) {
var rowIdx = g.getStore().indexOf(sels[i]);
this.toggleRow(rowIdx);
}
},
getBodyContent : function (record, index) {
if (!this.enableCaching) {
return this.tpl.apply(record.data);
}
var content = this.bodyContent[record.id];
if (!content) {
content = this.tpl.apply(record.data);
this.bodyContent[record.id] = content;
}
return content;
},
onMouseDown : function (e, t) {
e.stopEvent();
var row = e.getTarget('.x-grid3-row');
this.toggleRow(row);
},
renderer : function (v, p, record) {
p.cellAttr = 'rowspan="2"';
return '<div class="x-grid3-row-expander"> </div>';
},
beforeExpand : function (record, body, rowIndex) {
if (this.fireEvent('beforeexpand', this, record, body, rowIndex) !== false) {
if (this.tpl && this.lazyRender) {
body.innerHTML = this.getBodyContent(record, rowIndex);
}
return true;
} else {
return false;
}
},
toggleRow : function (row) {
if (typeof row == 'number') {
row = this.grid.view.getRow(row);
}
this[Ext.fly(row).hasClass('x-grid3-row-collapsed')
? 'expandRow'
: 'collapseRow'](row);
},
expandRow : function (row) {
if (typeof row == 'number') {
row = this.grid.view.getRow(row);
}
var record = this.grid.store.getAt(row.rowIndex);
var body = Ext.DomQuery.selectNode('tr:nth(2) div.x-grid3-row-body',
row);
if (this.beforeExpand(record, body, row.rowIndex)) {
this.state[record.id] = true;
Ext.fly(row).replaceClass('x-grid3-row-collapsed',
'x-grid3-row-expanded');
this.fireEvent('expand', this, record, body, row.rowIndex);
}
},
collapseRow : function (row) {
if (typeof row == 'number') {
row = this.grid.view.getRow(row);
}
var record = this.grid.store.getAt(row.rowIndex);
var body = Ext.fly(row).child('tr:nth(1) div.x-grid3-row-body', true);
if (this.fireEvent('beforecollapse', this, record, body, row.rowIndex) !== false) {
this.state[record.id] = false;
Ext.fly(row).replaceClass('x-grid3-row-expanded',
'x-grid3-row-collapsed');
this.fireEvent('collapse', this, record, body, row.rowIndex);
}
}
});
Ext.preg('rowexpander', Ext.ux.grid.RowExpander);
//backwards compat
Ext.grid.RowExpander = Ext.ux.grid.RowExpander;
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, ID, i18n, showResponse, alertFailure*/
Ext.namespace('sitools.widget');
/**
* Basic Box for all admin panels.
* @class sitools.widget.Box
* @extends Ext.Panel
*/
sitools.widget.Box = Ext.extend(Ext.Panel, {
width : '98%',
frame : true,
baseCls : 'x-box',
cls : 'x-box-blue module-root centering',
_title : '',
constructor : function (cfg) {
sitools.widget.Box.superclass.constructor.call(this, Ext.apply({
_title : cfg.label,
_idItem : cfg.idItem
}, cfg));
},
initComponent : function () {
this.items.unshift({
xtype : 'component',
html : this._title,
cls : 'subtitle icon-' + this.idItem
});
sitools.widget.Box.superclass.initComponent.call(this);
}
});
// register type
Ext.reg('s-box', sitools.widget.Box);
/**
* A simple json store with new methods
* @class sitools.widget.JsonStore
* @extends Ext.data.JsonStore
*/
sitools.widget.JsonStore = Ext.extend(Ext.data.JsonStore, {
/**
* dirty : true if one record have been added
* @type Boolean
*/
dirty : false,
/**
* Setter for dirty
* @param {Boolean} value
*/
_setDirty : function (value) {
this.dirty = value;
},
/**
* Get the dirty value
* @return {Boolean}
*/
_getDirty : function () {
return this.dirty;
},
/**
* Set dirty to true
* @param {Array} records the list of records added
*/
add : function (records) {
this.dirty = true;
sitools.widget.JsonStore.superclass.add.call(this, records);
},
/**
* Set dirty to true
* @param {Ext.data.Record} record the record removed
*/
remove : function (record) {
this.dirty = true;
sitools.widget.JsonStore.superclass.remove.call(this, record);
}
});
* A simple Ext.Button with a specific iconCls
* @class sitools.widget.menuButton
* @extends Ext.Button
*/
sitools.widget.menuButton = Ext.extend(Ext.Button, {
constructor : function (config) {
config = Ext.apply({
iconCls : 'menu-button'
}, config);
sitools.widget.menuButton.superclass.constructor.call(this, config);
}
});
Ext.reg('s-menuButton', sitools.widget.menuButton);
/**
* @class TemplateTreeNode
* @extends Ext.tree.AsyncTreeNode
*
*/
sitools.widget.templateTreeNode = function (attributes) {
var tpl;
if (attributes.tpl === undefined) {
tpl = new Ext.Template(
"<div >{text}<b>{nbRecords} records</b><img src='{urlImage}'></img><a style='text-align:right' href='{urlReadme}'>readme</a></div>");
} else {
tpl = attributes.tpl;
}
attributes.text = tpl.apply(attributes);
attributes.leaf = false;
var config = Ext.apply({
children : []
}, attributes);
sitools.widget.templateTreeNode.superclass.constructor.call(this, config);
};
Ext.extend(sitools.widget.templateTreeNode, Ext.tree.AsyncTreeNode, {
});
// add this new node to the list of nodes
Ext.tree.TreePanel.nodeTypes.templateTreeNode = sitools.widget.templateTreeNode;
/**
* Window that contains a tools to sort a store
* @cfg {} pos The position to apply to the window
* @cfg {Ext.data.Store} store the store to sort
* @cfg {} columnModel the dataset ColumnModel to know all columns on wich you can do a sort.
* @class sitools.widget.sortersTool
* @extends Ext.Window
*/
sitools.widget.sortersTool = Ext.extend(Ext.Window, {
initComponent : function () {
var dataCombo = [ [ "", "" ] ];
var columns;
if (! Ext.isEmpty(this.columnModel.columns)) {
var columns = this.columnModel.columns;
}
else {
columns = this.columnModel;
}
Ext.each(columns, function (column) {
dataCombo.push([ column.columnAlias, column.header ]);
});
this.storeCombo = new Ext.data.ArrayStore({
fields : [ "dataIndex", "columnHeader" ],
data : dataCombo
});
this.f = new Ext.form.FormPanel({
padding : 5
});
var sorters = this.store.getSortState(), len;
if (! Ext.isEmpty(sorters)) {
if (Ext.isArray(sorters.sorters)) {
this.sorters = sorters.sorters;
}
else {
this.sorters = [sorters];
}
len = this.sorters.length;
}
else {
this.sorter = [];
len = 3;
}
for (var i = 0; i < len; i++) {
var compositeField = this.buildCompositeField(i);
this.f.add(compositeField);
}
Ext.apply(this, {
title : i18n.get("label.multiSort"),
autoScroll : true,
width : 400,
modal : true,
items : [ this.f ],
buttons : [ {
text : i18n.get('label.add'),
scope : this,
handler : this.onAdd
}, {
text : i18n.get('label.remove'),
scope : this,
handler : this.onRemove
}, {
text : i18n.get('label.ok'),
scope : this,
handler : this.onValidate
}, {
text : i18n.get('label.cancel'),
scope : this,
handler : function () {
this.close();
}
} ]
});
sitools.widget.sortersTool.superclass.initComponent.call(this);
},
/**
* Build a sorters objetct to apply it to a store.
*/
onValidate : function () {
var sorters = [];
Ext.each(this.f.items.items, function (compositeField) {
if (!Ext.isEmpty(compositeField.items.items[0].getValue())) {
sorters.push({
field : compositeField.items.items[0].getValue(),
direction : compositeField.items.items[1].getValue().getGroupValue()
});
}
}, this);
if (sorters.length < 1) {
this.close();
return;
}
else if (sorters.length == 1) {
this.store.sort(sorters[0].field, sorters[0].direction);
}
else {
this.store.sort(sorters);
}
this.close();
},
/**
* Add a new sort option.
* @param {numeric} i the index of the sort option
* @return {Ext.form.CompositeField} the composite field with a comboBox to choose the column and a sort information.
*/
buildCompositeField : function (i) {
var combo = new Ext.form.ComboBox({
typeAhead : true,
name : "field" + 1,
triggerAction : 'all',
lazyRender : true,
mode : 'local',
store : this.storeCombo,
valueField : 'dataIndex',
displayField : 'columnHeader',
flex : 0.6
});
var direction = new Ext.form.RadioGroup({
fieldLabel : i18n.get('label.direction'),
flex : 0.4,
value : 'ASC',
items : [ {
boxLabel : 'ASC',
name : 'direction' + i,
inputValue : 'ASC'
}, {
boxLabel : 'DESC',
name : 'direction' + i,
inputValue : 'DESC'
} ]
});
var compositeField = new Ext.form.CompositeField({
labelWidth : 100,
anchor : '100%',
fieldLabel : i18n.get('label.sortingOrder'),
items : [ combo, direction ]
});
return compositeField;
},
/**
* Called on add button :
* Adds a new sort option.
*/
onAdd : function () {
var i = this.f.items.length;
var compositeField = this.buildCompositeField(i);
this.f.add(compositeField);
this.f.doLayout();
this.doLayout();
},
/**
* Called when remove button is pressed.
* Remove the last sort option.
*/
onRemove : function () {
var i = this.f.items.length - 1;
if (i < 0) {
return;
}
this.f.remove(this.f.getComponent(i));
this.f.doLayout();
this.doLayout();
},
/**
* Fill the panel with the sort configuration of the store.
*/
afterRender : function () {
sitools.widget.sortersTool.superclass.afterRender.call(this);
this.setPosition(this.pos);
var i = 0;
Ext.each(this.sorters, function (sorter) {
var compositeField = this.f.getComponent(i);
compositeField.items.items[0].setValue(sorter.field);
compositeField.items.items[1].setValue(sorter.direction);
i++;
}, this);
}
});
Ext.reg('sitools.widget.sortersTool', sitools.widget.sortersTool);
/**
* Build a window to define filter on a store using Filter API.
* @class sitools.widget.filterTool
* @extends Ext.Window
*/
sitools.widget.filterTool = Ext.extend(Ext.Window, {
paramPrefix : 'filter',
initComponent : function () {
var dataCombo = [ [ "", "" ] ];
var columns;
if (! Ext.isEmpty(this.columnModel.columns)) {
var columns = this.columnModel.columns;
}
else {
columns = this.columnModel;
}
Ext.each(columns, function (column) {
dataCombo.push({
columnAlias : column.columnAlias,
columnHeader : column.header,
columnType : sql2ext.get(column.sqlColumnType)
});
});
this.storeCombo = new Ext.data.JsonStore({
fields : [ "columnAlias", "columnHeader", "columnType" ],
data : dataCombo
});
this.f = new Ext.Panel();
this.filters = this.store.filtersCfg;
var len;
if (! Ext.isEmpty(this.filters)) {
len = this.filters.length;
}
else {
this.filters = [];
len = 3;
}
for (var i = 0; i < len; i++) {
var compositeField = this.buildCompositeField(i);
this.f.add(compositeField);
}
Ext.apply(this, {
title : i18n.get("label.filter"),
autoScroll : true,
width : 400,
modal : true,
items : [ this.f ],
buttons : [ {
text : i18n.get('label.add'),
scope : this,
handler : this.onAdd
}, {
text : i18n.get('label.remove'),
scope : this,
handler : this.onRemove
}, {
text : i18n.get('label.ok'),
scope : this,
handler : this.onValidate
}, {
text : i18n.get('label.cancel'),
scope : this,
handler : function () {
this.close();
}
} ]
});
sitools.widget.sortersTool.superclass.initComponent.call(this);
},
getCompositeField : function (index) {
return this.f.items.items[index];
},
onValidate : function () {
if(Ext.isEmpty(this.store.filters)){
this.store.filters = new sitools.widget.FiltersCollection();
}
this.store.filters.clear();
var filters = [];
var filtersCfg = [];
var i = 0;
var store = this.store;
Ext.each(this.f.items.items, function (compositeField) {
if (!Ext.isEmpty(compositeField.items.items[0].getValue())) {
var filterCmp = compositeField.findBy(function(cmp) {
return cmp.specificType == "filter";
});
var filterValue;
if (!Ext.isEmpty(filterCmp) && ! Ext.isEmpty(filterCmp[0])) {
var filter = filterCmp[0];
//Build the filters for the store query
filterValue = filter.getValue();
Ext.each(filterValue, function (filterValueItem) {
store.filters.add(i++, filterValueItem);
if (!Ext.isEmpty(filterValueItem)) {
filters.push (filterValueItem);
}
});
if (!Ext.isEmpty(filter.getConfig())) {
filtersCfg.push(filter.getConfig());
}
}
}
}, this);
this.store.filtersCfg = filtersCfg;
// this.store.filters = filters;
// var options = this.store.storeOptions() || {};
var options = this.store.lastOptions || {};
//
options.params = options.params || {};
this.cleanParams(options.params);
//var params = this.store.buildQuery(filters);
//set that this a new filter configuration
this.store.isNewFilter = true;
//Ext.apply(options.params, params);
//save the options has last options in the store
//this.store.storeOptions(options);
this.store.load(options);
this.close();
},
cleanParams : function (p) {
// if encoding just delete the property
if (this.encode) {
delete p[this.paramPrefix];
// otherwise scrub the object of filter data
} else {
var regex, key;
regex = new RegExp('^' + this.paramPrefix + '\[[0-9]+\]');
for (key in p) {
if (regex.test(key)) {
delete p[key];
}
}
}
},
buildCompositeField : function (i) {
var combo = new Ext.form.ComboBox({
index : i,
typeAhead : true,
name : "field" + 1,
triggerAction : 'all',
lazyRender : true,
mode : 'local',
store : this.storeCombo,
valueField : 'columnAlias',
displayField : 'columnHeader',
flex : 0.4,
listeners : {
"select" : function (combo, rec, index) {
if (Ext.isEmpty(rec.data.columnAlias)) {
return;
}
var compositeField = combo.ownerCt;
var containerFilter = compositeField.items.items[1];
containerFilter.removeAll();
switch (rec.data.columnType) {
case ("numeric") :
var filter = new sitools.widget.NumericFilter({
columnAlias : rec.data.columnAlias
});
containerFilter.add(filter);
compositeField.setHeight(filter._getHeight());
containerFilter.setHeight(filter._getHeight());
//containerFilter.syncSize();
break;
case ("string") :
var filter = new sitools.widget.StringFilter({
columnAlias : rec.data.columnAlias
});
containerFilter.add(filter);
compositeField.setHeight(filter._getHeight());
containerFilter.setHeight(filter._getHeight());
break;
case ("dateAsString") :
var filter = new sitools.widget.DateFilter({
columnAlias : rec.data.columnAlias
});
containerFilter.add(filter);
compositeField.setHeight(filter._getHeight());
containerFilter.setHeight(filter._getHeight());
break;
default :
var filter = new sitools.widget.StringFilter({
columnAlias : rec.data.columnAlias
});
containerFilter.add(filter);
compositeField.setHeight(filter._getHeight());
containerFilter.setHeight(filter._getHeight());
break;
}
}
}
});
var filter = new Ext.Container({
flex : 0.6
});
var compositeField = new Ext.Container({
layout : "hbox",
items : [ combo, filter ],
style: {
padding: '5px'
}
});
return compositeField;
},
onAdd : function () {
var i = this.f.items.length;
var compositeField = this.buildCompositeField(i);
this.f.add(compositeField);
this.f.doLayout();
this.doLayout();
},
onRemove : function () {
var i = this.f.items.length - 1;
if (i < 0) {
return;
}
this.f.remove(this.f.getComponent(i));
this.f.doLayout();
this.doLayout();
},
afterRender : function () {
sitools.widget.sortersTool.superclass.afterRender.call(this);
this.setPosition(this.pos);
var i = 0;
Ext.each(this.filters, function (filter) {
var compositeField = this.f.getComponent(i);
this.updateFilterUI (compositeField, filter);
i++;
}, this);
},
updateFilterUI : function (container, filter) {
var combo = container.items.items[0];
var store = combo.getStore();
var index = store.find("columnAlias", filter.columnAlias);
if (index)
var rec = store.getAt(index);
combo.setValue(filter.columnAlias);
combo.fireEvent('select', combo, rec, index);
var filterCmp = container.findBy(function(cmp) {
return cmp.specificType == "filter";
});
filterCmp[0].setValue(filter.value);
// console.log(container);
// console.log(filterCmp);
}
});
Ext.reg('sitools.widget.sortersTool', sitools.widget.sortersTool);
/**
* A toolbar with buttons to move rows up or down
*
* @cfg {string} gridId :
* the id of the grid. This is not mandatory if the grid is
* not the scope of the buttons
* @class sitools.widget.GridSorterToolbar
* @extends Ext.Toolbar
*/
sitools.widget.GridSorterToolbar = Ext.extend(Ext.Toolbar, {
initComponent : function () {
sitools.widget.GridSorterToolbar.superclass.initComponent.call(this);
this.add('->', new sitools.widget.GridTop({
gridId : this.gridId
}), new sitools.widget.GridUp({
gridId : this.gridId
}), new sitools.widget.GridDown({
gridId : this.gridId
}), new sitools.widget.GridBottom({
gridId : this.gridId
}));
}
});
Ext.reg('sitools.widget.GridSorterToolbar', sitools.widget.GridSorterToolbar);
/**
* A RowExpander used for plugin grids to add violation informations
* The parameters are the same as the class Ext.ux.grid.RowExpander
*
* @class sitools.admin.resourcesPlugins.violationRowExpander
* @extends Ext.ux.grid.RowExpander
*/
sitools.widget.ViolationRowExpander = Ext.extend(
Ext.ux.grid.RowExpander, {
getRowClass : function (record, index, rowParams, store) {
//call the method from the superclass
var cls = sitools.widget.ViolationRowExpander.superclass.getRowClass.call(this,
record, index, rowParams, store);
//add a class depending on the violation type
var violation = record.get("violation");
if (!Ext.isEmpty(violation)) {
if (violation.level == "CRITICAL") {
cls += " red-row";
} else if (violation.level == "WARNING") {
cls += " orange-row";
}
}
return cls;
}
});
Ext.reg('sitools.widget.ViolationRowExpander', sitools.widget.ViolationRowExpander);
/**
* Color picker on a triggerField *
* @event select when a new color is selected
* @class sitools.widget.colorField
* @extends Ext.form.TriggerField
*/
sitools.widget.colorField = Ext.extend(
Ext.form.TriggerField, {
onTriggerClick : function (e) {
var cp = new Ext.menu.ColorMenu({
scope : this,
handler: function (cm, color) {
this.setValue("#" + color);
this.setFontColor("#" + color);
this.fireEvent("select", this, color);
}
});
cp.showAt(e.getXY());
},
setFontColor : function (color) {
var h2d = function (d) {
return parseInt(d, 16);
};
var value = [
h2d(color.slice(1, 3)),
h2d(color.slice(3, 5)),
h2d(color.slice(5))
];
var avg = (value[0] + value[1] + value[2]) / 3;
this.el.setStyle({
'color' : (avg > 128) ? '#000' : '#FFF',
'background-color' : color,
'background-image' : "none"
});
},
listeners : {
afterrender : function (tf) {
tf.setFontColor(tf.getValue());
}
}
}
)
sitools.widget.DateFieldWithToday = Ext.extend(Ext.form.DateField, {
regToday : new RegExp("^\{\\$TODAY\}"),
invalidTextWithToday : "Impossible to make a date with {0}. A valid example is {$TODAY} + 1",
parseDate : function (value) {
if(!value || Ext.isDate(value)){
return value;
}
//Ajout d'un test sur la valeur pour sortir s'il y a la valeur {$TODAY}
if (this.regToday.test(value)) {
return value;
}
var v = this.safeParse(value, this.format),
af = this.altFormats,
afa = this.altFormatsArray;
if (!v && af) {
afa = afa || af.split("|");
for (var i = 0, len = afa.length; i < len && !v; i++) {
v = this.safeParse(value, afa[i]);
}
}
return v;
},
getErrors : function (value) {
var errors = Ext.form.DateField.superclass.getErrors.apply(this, arguments);
value = this.formatDate(value || this.processValue(this.getRawValue()));
if (value.length < 1) { // if it's blank and textfield didn't flag it then it's valid
return errors;
}
var svalue = value;
// Ne pas parser la date en objet Date si {$TODAY} est présent
var time = false;
if (this.regToday.test(value)) {
try {
value = sitools.common.utils.Date.stringWithTodayToDate(value);
if (!sitools.common.utils.Date.isValidDate(value)) {
throw "";
}
}
catch (err) {
errors.push(String.format(this.invalidTextWithToday, svalue));
return errors;
}
}
else {
value = this.parseDate(value);
}
if (!value) {
errors.push(String.format(this.invalidText, svalue, this.format));
return errors;
}
time = value.getTime();
if (this.minValue && time < this.minValue.clearTime().getTime()) {
errors.push(String.format(this.minText, this.formatDate(this.minValue)));
}
if (this.maxValue && time > this.maxValue.clearTime().getTime()) {
errors.push(String.format(this.maxText, this.formatDate(this.maxValue)));
}
if (this.disabledDays) {
var day = value.getDay();
for(var i = 0; i < this.disabledDays.length; i++) {
if (day === this.disabledDays[i]) {
errors.push(this.disabledDaysText);
break;
}
}
}
var fvalue = this.formatDate(value);
if (this.disabledDatesRE && this.disabledDatesRE.test(fvalue)) {
errors.push(String.format(this.disabledDatesText, fvalue));
}
return errors;
},
setValue : function (date) {
if (this.regToday.test(date)) {
return Ext.form.DateField.superclass.setValue.call(this, date);
}
else {
return Ext.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
}
}
});
sitools.widget.rootTreeLoader = Ext.extend(Ext.tree.TreeLoader, {
createNode : function (attr) {
if (Ext.isEmpty(attr.children)) {
attr.leaf = true;
}
return Ext.tree.TreeLoader.prototype.createNode.call(this, attr);
},
processResponse : function (response, node, callback, scope) {
var json = response.responseText, children, newNode, i = 0, len;
try {
if (!(children = response.responseData)) {
children = Ext.decode(json);
if (this.root) {
if (!this.getRoot) {
this.getRoot = Ext.data.JsonReader.prototype.createAccessor(this.root);
}
children = this.getRoot(children);
}
}
node.beginUpdate();
for (len = children.length; i < len; i++) {
newNode = this.createNode(children[i]);
if (newNode) {
node.appendChild(newNode);
}
}
node.endUpdate();
this.runCallback(callback, scope || node, [ node ]);
} catch (e) {
this.handleFailure(response);
}
},
setUrl : function (url) {
this.url = url;
}
});/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n,document */
Ext.ns("sitools.common.forms");
/**
* A static method to transform a parameter to a sitools component.
* @static
* @param {} parameter the parameter as stored in the formParameter Model
* @param {string} dataUrl the Url to request eventual data
* @param {string} formId the main formId
* @param {} datasetCm the dataset Column model
* @param {string} context should be dataset or project.
* @return {Ext.Container} the container to include into form
*/
sitools.common.forms.formParameterToComponent = function (parameter, dataUrl, formId, datasetCm, context) {
var valuesToSelect = null;
this.component = null;
var value, values, items, i, component, defaultValues, existsWidgetForParameterCode, selectedValue, minValue, maxValue, disabledDates;
//The name of the constructor
var constructor = eval(parameter.jsUserObject);
component = new constructor ({
parameterId : parameter.id,
values : Ext.isArray(parameter.values) ? parameter.values : [],
code : parameter.code,
type : parameter.type,
label : parameter.label,
height : parameter.height,
widthBox : parameter.width,
valueSelection : parameter.valueSelection,
parentParam : parameter.parentParam,
dataUrl : dataUrl,
autoComplete : parameter.autoComplete,
formId : formId,
dimensionId : parameter.dimensionId,
unit : parameter.unit,
css : parameter.css,
defaultValues : parameter.defaultValues,
extraParams : parameter.extraParams,
datasetCm : datasetCm,
context : context
});
return {
parameter : parameter,
component : component
};
};
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, ID, i18n, document, showResponse, alertFailure, locale, ImageChooser,
showHelp, loadUrl*/
Ext.namespace('sitools.common.forms');
/**
* Object to expose methods to build form Components user objects in dataset Context
* @class sitools.common.forms.DatasetContex
*
*/
sitools.common.forms.DatasetContext = function () {
//sitools.user.forms.components.DatasetContext = function () {
this.context = "dataset";
/**
* Return the unit corresponding to a given column Alias
* @param {} scope the initial config
* @return {} the unit founded
*/
this.getRefUnit = function (scope) {
var columnAlias = scope.code[0];
if (Ext.isEmpty(scope.datasetCm)) {
return;
}
var result;
Ext.each(scope.datasetCm, function(column){
if (column.columnAlias == columnAlias) {
result = column.unit;
}
});
return result;
};
};
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, ID, i18n, document, showResponse, alertFailure, locale, ImageChooser,
showHelp, loadUrl*/
Ext.namespace('sitools.common.forms');
/**
* Object to expose methods to build form Components user objects in project Context
* @class sitools.common.forms.ProjectContext
*
*/
sitools.common.forms.ProjectContext = function () {
//sitools.user.forms.components.ProjectContext = function () {
this.context = "project";
/**
* Return the unit corresponding to a given scope
* @param {} scope the initial config
* @return {} the unit founded
*/
this.getRefUnit = function (scope) {
return scope.unit;
};
};
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, ID, i18n, document, showResponse, alertFailure, locale, ImageChooser,
showHelp, loadUrl*/
/*
* @include "DatasetContext.js"
* @include "ProjectContext.js"
*/
Ext.namespace('sitools.common.forms');
/**
* Basic factory to return DatasetFactory or ProjectFactory according with context.
* @param {String} context must be "dataset" or project"
* @class sitools.common.forms.ComponentFactory
* @return {}
*/
sitools.common.forms.ComponentFactory = function (context) {
//sitools.user.forms.components.ComponentFactory = function (context) {
if (context == "dataset") {
return new sitools.common.forms.DatasetContext();
}
if (context == "project") {
return new sitools.common.forms.ProjectContext();
}
};
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools*/
Ext.ns('sitools.common.forms');
/**
* Abstract class to build Sitools form components with units.
* @class sitools.common.forms.AbstractWithUnit
* @extends Ext.Container
*/
sitools.common.forms.AbstractWithUnit = Ext.extend(Ext.Container, {
//sitools.component.users.SubSelectionParameters.AbstractComponentsWithUnit = Ext.extend(Ext.Container, {
dimensionId : null,
userUnit : null,
userDimension : null,
initComponent : function () {
this.userDimension = this.dimensionId;
this.userUnit = this.unit;
this.storeUnits = new Ext.data.JsonStore({
id : 'storeUnitSelect',
root : 'dimension.units',
idProperty : 'id',
fields : [ {
name : 'unitName',
type : 'string'
}, {
name : 'label',
type : 'string'
}]
});
sitools.common.forms.AbstractWithUnit.superclass.initComponent.call(this);
},
/**
* Load all units available with a given dimension.
* On Callback : show a {Ext.Window} with the result in a gridPanel
* @param {} event The click event (to get coordinates)
*/
loadUnits : function (event) {
if (!this.unitsLoaded) {
this.storeUnits.removeAll();
Ext.Ajax.request({
method : "GET",
url : loadUrl.get('APP_URL') + loadUrl.get('APP_DIMENSIONS_ADMIN_URL') + '/dimension/' + this.dimensionId,
scope : this,
success : function (ret) {
var Json = Ext.decode(ret.responseText);
if (!Json.success) {
Ext.Msg.alert(i18n.get('label.warning'), Json.message);
return;
}
var units = Json.dimension.sitoolsUnits;
this.dimensionName = Json.dimension.name;
for (var i = 0; i < units.length; i++) {
this.storeUnits.add(new Ext.data.Record(units[i]));
}
},
failure : alertFailure,
callback : function () {
this.unitsLoaded = true;
this.showWinUnits(event);
}
});
}
else {
this.showWinUnits(event);
}
},
/**
* Create and show a {Ext.Window} window with the loaded units
* build the gridUnits.
* @param {} event The click event to get coordinates for the window
*/
showWinUnits : function (event) {
var cmUnits = new Ext.grid.ColumnModel({
columns : [ {
header : i18n.get('headers.name'),
dataIndex : 'label',
width : 100
}],
defaults : {
sortable : true,
width : 100
}
});
var smUnits = new Ext.grid.RowSelectionModel({
singleSelect : true
});
this.gridUnits = new Ext.grid.GridPanel({
autoScroll : true,
store : this.storeUnits,
cm : cmUnits,
sm : smUnits,
layout : 'fit',
listeners : {
scope : this,
rowClick : function (grid, rowIndex) {
this.onValidateUnits();
}
}
});
var winUnit = new Ext.Window({
layout : 'fit',
width : 200,
title : i18n.get('title.unitList'),
modal : true,
height : 300,
items : [this.gridUnits],
buttons : [{
text : i18n.get('label.ok'),
handler : this.onValidateUnits,
scope : this
}, {
text : i18n.get('label.cancel'),
scope : winUnit,
handler : function () {
this.ownerCt.ownerCt.close();
}
}]
});
winUnit.show();
winUnit.setPosition(event.getXY()[0], event.getXY()[1]);
},
/**
* update property this.userDimension and this.userUnit, depending on the selected record in this.gridUnits
* update the label of the button withe the new unit
*/
onValidateUnits : function () {
var rec = this.gridUnits.getSelectionModel().getSelected();
if (Ext.isEmpty(rec)) {
Ext.Msg.alert(i18n.get('label.error'), i18n.get('label.noSelection'));
return;
}
this.userUnit = rec.data;
this.userDimension = this.dimensionName;
var btn = this.getEl().query("button")[0];
if (! Ext.isEmpty(btn)) {
this.getEl().query("button")[0].update(rec.get('label'));
}
this.gridUnits.ownerCt.close();
},
// /**
// * Return the unit corresponding to a given column Alias
// * @param {String} columnAlias the column Alias to retrieve
// * @return {} the unit founded
// */
// getColumnUnit : function (columnAlias) {
// if (Ext.isEmpty(this.datasetCm)) {
// return;
// }
// var result;
// Ext.each(this.datasetCm, function(column){
// if (column.columnAlias == columnAlias) {
// result = column.unit;
// }
// });
// return result;
// },
/**
* build a {Ext.Container} container with
* <ul><li>a {Ext.Button} button if column unit is not null and administrator defines a dimension</li>
* <li>A simple text if column unit is not null and administrator not defines a dimension</li>
* <li>null when column unit is null</li></ul>
* @return {} null or the builded container
*/
getUnitComponent : function () {
var columnUnit = this.context.getRefUnit(this);
//the administrator defines a dimension for this component
// and the column unit is not null
if (!Ext.isEmpty(this.dimensionId)) {
var btn = new Ext.Button({
scope : this,
text : Ext.isEmpty(columnUnit) ? " " : columnUnit.label,
width : 90,
handler : function (b, e) {
this.loadUnits(e);
//this.userDimension = this.dimensionId;
}
});
unit = new Ext.Container({
layout : "hbox",
layoutConfig : {
pack : "center",
align : "middle"
},
margins : {top:0, right:0, bottom:0, left:10},
width : 100,
items : [btn]
});
}
else {
if (!Ext.isEmpty(columnUnit)) {
unit = new Ext.Container({
html : columnUnit.label,
margins : {top:0, right:0, bottom:0, left:10},
flex : 1
});
}
else {
unit = null;
}
}
return unit;
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*
* ux.ManagedIFrame for ExtJS Library 3.1+
* Copyright(c) 2008-2009 Active Group, Inc.
* licensing@theactivegroup.com
* http://licensing.theactivegroup.com
*/
/**
* @class Ext.ux.plugin.VisibilityMode
* @version 1.3.1
* @author Doug Hendricks. doug[always-At]theactivegroup.com
* @copyright 2007-2010, Active Group, Inc. All rights reserved.
* @license <a href="http://www.gnu.org/licenses/gpl.html">GPL 3.0</a>
* Commercial Developer License (CDL) is available at http://licensing.theactivegroup.com.
* @singleton
* @static
* @desc This plugin provides an alternate mechanism for hiding Ext.Elements and a new hideMode for Ext.Components.<br />
* <p>It is generally designed for use with all browsers <b>except</b> Internet Explorer, but may used on that Browser as well.
* <p>If included in a Component as a plugin, it sets it's hideMode to 'nosize' and provides a new supported
* CSS rule that sets the height and width of an element and all child elements to 0px (rather than
* 'display:none', which causes DOM reflow to occur and re-initializes nested OBJECT, EMBED, and IFRAMES elements)
* @example
var div = Ext.get('container');
new Ext.ux.plugin.VisibilityMode().extend(div);
//You can override the Element (instance) visibilityCls to any className you wish at any time
div.visibilityCls = 'my-hide-class';
div.hide() //or div.setDisplayed(false);
// In Ext Layouts:
someContainer.add({
xtype:'flashpanel',
plugins: [new Ext.ux.plugin.VisibilityMode() ],
...
});
// or, Fix a specific Container only and all of it's child items:
// Note: An upstream Container may still cause Reflow issues when hidden/collapsed
var V = new Ext.ux.plugin.VisibilityMode({ bubble : false }) ;
new Ext.TabPanel({
plugins : V,
defaults :{ plugins: V },
items :[....]
});
*/
Ext.namespace('Ext.ux.plugin');
Ext.onReady(function(){
/* This important rule solves many of the <object/iframe>.reInit issues encountered
* when setting display:none on an upstream(parent) element (on all Browsers except IE).
* This default rule enables the new Panel:hideMode 'nosize'. The rule is designed to
* set height/width to 0 cia CSS if hidden or collapsed.
* Additional selectors also hide 'x-panel-body's within layouts to prevent
* container and <object, img, iframe> bleed-thru.
*/
var CSS = Ext.util.CSS;
if(CSS){
CSS.getRule('.x-hide-nosize') || //already defined?
CSS.createStyleSheet('.x-hide-nosize{height:0px!important;width:0px!important;border:none!important;zoom:1;}.x-hide-nosize * {height:0px!important;width:0px!important;border:none!important;zoom:1;}');
CSS.refreshCache();
}
});
(function(){
var El = Ext.Element, A = Ext.lib.Anim, supr = El.prototype;
var VISIBILITY = "visibility",
DISPLAY = "display",
HIDDEN = "hidden",
NONE = "none";
var fx = {};
fx.El = {
/**
* Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
* @param {Mixed} value Boolean value to display the element using its default display, or a string to set the display directly.
* @return {Ext.Element} this
*/
setDisplayed : function(value) {
var me=this;
me.visibilityCls ? (me[value !== false ?'removeClass':'addClass'](me.visibilityCls)) :
supr.setDisplayed.call(me, value);
return me;
},
/**
* Returns true if display is not "none" or the visibilityCls has not been applied
* @return {Boolean}
*/
isDisplayed : function() {
return !(this.hasClass(this.visibilityCls) || this.isStyle(DISPLAY, NONE));
},
// private
fixDisplay : function(){
var me = this;
supr.fixDisplay.call(me);
me.visibilityCls && me.removeClass(me.visibilityCls);
},
/**
* Checks whether the element is currently visible using both visibility, display, and nosize class properties.
* @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
* @return {Boolean} True if the element is currently visible, else false
*/
isVisible : function(deep) {
var vis = this.visible ||
(!this.isStyle(VISIBILITY, HIDDEN) &&
(this.visibilityCls ?
!this.hasClass(this.visibilityCls) :
!this.isStyle(DISPLAY, NONE))
);
if (deep !== true || !vis) {
return vis;
}
var p = this.dom.parentNode,
bodyRE = /^body/i;
while (p && !bodyRE.test(p.tagName)) {
if (!Ext.fly(p, '_isVisible').isVisible()) {
return false;
}
p = p.parentNode;
}
return true;
},
//Assert isStyle method for Ext 2.x
isStyle: supr.isStyle || function(style, val) {
return this.getStyle(style) == val;
}
};
//Add basic capabilities to the Ext.Element.Flyweight class
Ext.override(El.Flyweight, fx.El);
Ext.ux.plugin.VisibilityMode = function(opt) {
Ext.apply(this, opt||{});
var CSS = Ext.util.CSS;
if(CSS && !Ext.isIE && this.fixMaximizedWindow !== false && !Ext.ux.plugin.VisibilityMode.MaxWinFixed){
//Prevent overflow:hidden (reflow) transitions when an Ext.Window is maximize.
CSS.updateRule ( '.x-window-maximized-ct', 'overflow', '');
Ext.ux.plugin.VisibilityMode.MaxWinFixed = true; //only updates the CSS Rule once.
}
};
Ext.extend(Ext.ux.plugin.VisibilityMode , Object, {
/**
* @cfg {Boolean} bubble If true, the VisibilityMode fixes are also applied to parent Containers which may also impact DOM reflow.
* @default true
*/
bubble : true,
/**
* @cfg {Boolean} fixMaximizedWindow If not false, the ext-all.css style rule 'x-window-maximized-ct' is disabled to <b>prevent</b> reflow
* after overflow:hidden is applied to the document.body.
* @default true
*/
fixMaximizedWindow : true,
/**
*
* @cfg {array} elements (optional) A list of additional named component members to also adjust visibility for.
* <br />By default, the plugin handles most scenarios automatically.
* @default null
* @example ['bwrap','toptoolbar']
*/
elements : null,
/**
* @cfg {String} visibilityCls A specific CSS classname to apply to Component element when hidden/made visible.
* @default 'x-hide-nosize'
*/
visibilityCls : 'x-hide-nosize',
/**
* @cfg {String} hideMode A specific hideMode value to assign to affected Components.
* @default 'nosize'
*/
hideMode : 'nosize' ,
ptype : 'uxvismode',
/**
* Component plugin initialization method.
* @param {Ext.Component} c The Ext.Component (or subclass) for which to apply visibilityMode treatment
*/
init : function(c) {
var hideMode = this.hideMode || c.hideMode,
plugin = this,
bubble = Ext.Container.prototype.bubble,
changeVis = function(){
var els = [this.collapseEl, this.actionMode].concat(plugin.elements||[]);
Ext.each(els, function(el){
plugin.extend( this[el] || el );
},this);
var cfg = {
visFixed : true,
animCollapse : false,
animFloat : false,
hideMode : hideMode,
defaults : this.defaults || {}
};
cfg.defaults.hideMode = hideMode;
Ext.apply(this, cfg);
Ext.apply(this.initialConfig || {}, cfg);
};
c.on('render', function(){
// Bubble up the layout and set the new
// visibility mode on parent containers
// which might also cause DOM reflow when
// hidden or collapsed.
if(plugin.bubble !== false && this.ownerCt){
bubble.call(this.ownerCt, function(){
this.visFixed || this.on('afterlayout', changeVis, this, {single:true} );
});
}
changeVis.call(this);
}, c, {single:true});
},
/**
* @param {Element/Array} el The Ext.Element (or Array of Elements) to extend visibilityCls handling to.
* @param {String} visibilityCls The className to apply to the Element when hidden.
* @return this
*/
extend : function(el, visibilityCls){
el && Ext.each([].concat(el), function(e){
if(e && e.dom){
if('visibilityCls' in e)return; //already applied or defined?
Ext.apply(e, fx.El);
e.visibilityCls = visibilityCls || this.visibilityCls;
}
},this);
return this;
}
});
Ext.preg && Ext.preg('uxvismode', Ext.ux.plugin.VisibilityMode );
/** @sourceURL=<uxvismode.js> */
Ext.provide && Ext.provide('uxvismode');
})();/* global Ext El ElFrame ELD*/
/*
* ******************************************************************************
* This file is distributed on an AS IS BASIS WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* ***********************************************************************************
* License: multidom.js is offered under an MIT License.
* Donations are welcomed: http://donate.theactivegroup.com
*/
/**
* @class multidom
* @version 2.13
* @license MIT
* @author Doug Hendricks. Forum ID: <a href="http://extjs.com/forum/member.php?u=8730">hendricd</a>
* @donate <a target="tag_donate" href="http://donate.theactivegroup.com"><img border="0" src="http://www.paypal.com/en_US/i/btn/x-click-butcc-donate.gif" border="0" alt="Make a donation to support ongoing development"></a>
* @copyright 2007-2010, Active Group, Inc. All rights reserved.
* @description [Designed For Ext Core and ExtJs Frameworks (using ext-base adapter only) 3.0 or higher ONLY]
* The multidom library extends (overloads) Ext Core DOM methods and functions to
* provide document-targeted access to the documents loaded in external (FRAME/IFRAME)
* documents.
* <p>It maintains seperate DOM Element caches (and more) for each document instance encountered by the
* framework, permitting safe access to DOM Elements across document instances that may share
* the same Element id or name. In essence, multidom extends the functionality provided by Ext Core
* into any child document without having to load the Core library into the frame's global context.
* <h3>Custom Element classes.</h3>
* The Ext.get method is enhanced to support resolution of the custom Ext.Element implementations.
* (The ux.ManagedIFrame 2 Element class is an example of such a class.)
* <p>For example: If you were retrieving the Ext.Element instance for an IFRAME and the class
* Ext.Element.IFRAME were defined:
* <pre><code>Ext.get('myFrame')</pre></code>
* would return an instance of Ext.Element.IFRAME for 'myFrame' if it were found.
* @example
// return the Ext.Element with an id 'someDiv' located in external document hosted by 'iframe'
var iframe = Ext.get('myFrame');
var div = Ext.get('someDiv', iframe.getFrameDocument()); //Firefox example
if(div){
div.center();
}
Note: ux.ManagedIFrame provides an equivalent 'get' method of it's own to access embedded DOM Elements
for the document it manages.
<pre><code>iframe.get('someDiv').center();</pre></code>
Likewise, you can retrieve the raw Element of another document with:
var el = Ext.getDom('myDiv', iframe.getFrameDocument());
*/
(function(){
/*
* Ext.Element and Ext.lib.DOM enhancements.
* Primarily provides the ability to interact with any document context
* (not just the one Ext was loaded into).
*/
var El = Ext.Element,
ElFrame,
ELD = Ext.lib.Dom,
A = Ext.lib.Anim,
Evm = Ext.EventManager,
E = Ext.lib.Event,
DOC = document,
emptyFn = function(){},
OP = Object.prototype,
OPString = OP.toString,
HTMLDoc = '[object HTMLDocument]';
if(!Ext.elCache || parseInt( Ext.version.replace(/\./g,''),10) < 311 ) {
alert ('Ext Release '+Ext.version+' is not supported');
}
/**
* @private
*/
Ext._documents= {};
Ext._documents[Ext.id(document,'_doc')]=Ext.elCache;
/**
* @private
* Resolve the Element cache for a given element/window/document context.
*/
var resolveCache = ELD.resolveDocumentCache = function(el, cacheId){
var doc = GETDOC(el),
c = Ext.isDocument(doc) ? Ext.id(doc) : cacheId,
cache = Ext._documents[c] || null;
return cache || (c ? Ext._documents[c] = {}: null);
},
clearCache = ELD.clearDocumentCache = function(cacheId){
delete Ext._documents[cacheId];
};
El.addMethods || ( El.addMethods = function(ov){ Ext.apply(El.prototype, ov||{}); });
Ext.removeNode = function(n){
var dom = n ? n.dom || n : null,
el, elc, elCache = resolveCache(dom), parent;
//clear out any references if found in the El.cache(s)
if(dom && (elc = elCache[dom.id]) && (el = elc.el) ){
if(el.dom){
Ext.enableNestedListenerRemoval ? Evm.purgeElement(el.dom, true) : Evm.removeAll(el.dom);
}
delete elCache[dom.id];
delete el.dom;
delete el._context;
el = null;
}
//No removal for window, documents, or bodies
if(dom && !dom.navigator && !Ext.isDocument(dom) && dom.tagName != 'BODY'){
(parent = dom.parentElement || dom.parentNode) && parent.removeChild(dom);
}
dom = parent = null;
};
var overload = function(pfn, fn ){
var f = typeof pfn === 'function' ? pfn : function t(){};
var ov = f._ovl; //call signature hash
if(!ov){
ov = { base: f};
ov[f.length|| 0] = f;
f= function t(){ //the proxy stub
var o = arguments.callee._ovl;
var fn = o[arguments.length] || o.base;
//recursion safety
return fn && fn != arguments.callee ? fn.apply(this,arguments): undefined;
};
}
var fnA = [].concat(fn);
for(var i=0,l=fnA.length; i<l; ++i){
//ensures no duplicate call signatures, but last in rules!
ov[fnA[i].length] = fnA[i];
}
f._ovl= ov;
var t = null;
return f;
};
Ext.applyIf( Ext, {
overload : overload( overload,
[
function(fn){ return overload(null, fn);},
function(obj, mname, fn){
return obj[mname] = overload(obj[mname],fn);}
]),
isArray : function(v){
return !!v && OPString.apply(v) == '[object Array]';
},
isObject:function(obj){
return !!obj && typeof obj == 'object';
},
/**
* HTMLDocument assertion with optional accessibility testing
* @param {HTMLELement} el The DOM Element to test
* @param {Boolean} testOrigin (optional) True to test "same-origin" access
*
*/
isDocument : function(el, testOrigin){
var elm = el ? el.dom || el : null;
var test = elm && ((OPString.apply(elm) == HTMLDoc) || (elm && elm.nodeType == 9));
if(test && testOrigin){
try{
test = !!elm.location;
}
catch(e){return false;}
}
return test;
},
isWindow : function(el){
var elm = el ? el.dom || el : null;
return elm ? !!elm.navigator || OPString.apply(elm) == "[object Window]" : false;
},
isIterable : function(v){
//check for array or arguments
if(Ext.isArray(v) || v.callee){
return true;
}
//check for node list type
if(/NodeList|HTMLCollection/.test(OPString.call(v))){
return true;
}
//NodeList has an item and length property
//IXMLDOMNodeList has nextNode method, needs to be checked first.
return ((typeof v.nextNode != 'undefined' || v.item) && Ext.isNumber(v.length));
},
isElement : function(obj){
return obj && Ext.type(obj)== 'element';
},
isEvent : function(obj){
return OPString.apply(obj) == '[object Event]' || (Ext.isObject(obj) && !Ext.type(o.constructor) && (window.event && obj.clientX && obj.clientX == window.event.clientX));
},
isFunction: function(obj){
return !!obj && typeof obj == 'function';
},
/**
* Determine whether a specified DOMEvent is supported by a given HTMLElement or Object.
* @param {String} type The eventName (without the 'on' prefix)
* @param {HTMLElement/Object/String} testEl (optional) A specific HTMLElement/Object to test against, otherwise a tagName to test against.
* based on the passed eventName is used, or DIV as default.
* @return {Boolean} True if the passed object supports the named event.
*/
isEventSupported : function(evName, testEl){
var TAGNAMES = {
'select':'input',
'change':'input',
'submit':'form',
'reset':'form',
'load':'img',
'error':'img',
'abort':'img'
},
//Cached results
cache = {},
onPrefix = /^on/i,
//Get a tokenized string of the form nodeName:type
getKey = function(type, el){
var tEl = Ext.getDom(el);
return (tEl ?
(Ext.isElement(tEl) || Ext.isDocument(tEl) ?
tEl.nodeName.toLowerCase() :
el.self ? '#window' : el || '#object')
: el || 'div') + ':' + type;
};
return function (evName, testEl) {
evName = (evName || '').replace(onPrefix,'');
var el, isSupported = false;
var eventName = 'on' + evName;
var tag = (testEl ? testEl : TAGNAMES[evName]) || 'div';
var key = getKey(evName, tag);
if(key in cache){
//Use a previously cached result if available
return cache[key];
}
el = Ext.isString(tag) ? DOC.createElement(tag): testEl;
isSupported = (!!el && (eventName in el));
isSupported || (isSupported = window.Event && !!(String(evName).toUpperCase() in window.Event));
if (!isSupported && el) {
el.setAttribute && el.setAttribute(eventName, 'return;');
isSupported = Ext.isFunction(el[eventName]);
}
//save the cached result for future tests
cache[key] = isSupported;
el = null;
return isSupported;
};
}()
});
/**
* @private
* Determine Ext.Element[tagName] or Ext.Element (default)
*/
var assertClass = function(el){
return El;
return El[(el.tagName || '-').toUpperCase()] || El;
};
var libFlyweight;
function fly(el, doc) {
if (!libFlyweight) {
libFlyweight = new Ext.Element.Flyweight();
}
libFlyweight.dom = Ext.getDom(el, null, doc);
return libFlyweight;
}
Ext.apply(Ext, {
/*
* Overload Ext.get to permit Ext.Element access to other document objects
* This implementation maintains safe element caches for each document queried.
*
*/
get : El.get = function(el, doc){ //document targeted
if(!el ){ return null; }
var isDoc = Ext.isDocument(el);
Ext.isDocument(doc) || (doc = DOC);
var ex, elm, id, cache = resolveCache(doc);
if(typeof el == "string"){ // element id
elm = Ext.getDom(el, null, doc);
if(!elm) return null;
if(cache[el] && cache[el].el){
ex = cache[el].el;
ex.dom = elm;
}else{
ex = El.addToCache(new (assertClass(elm))(elm, null, doc));
}
return ex;
}else if(isDoc){
if(!Ext.isDocument(el, true)){ return false; } //is it accessible
cache = resolveCache(el);
if(cache[Ext.id(el)] && cache[el.id].el){
return cache[el.id].el;
}
// create a bogus element object representing the document object
var f = function(){};
f.prototype = El.prototype;
var docEl = new f();
docEl.dom = el;
docEl.id = Ext.id(el,'_doc');
docEl._isDoc = true;
El.addToCache( docEl, null, cache);
return docEl;
}else if( el instanceof El ){
// refresh dom element in case no longer valid,
// catch case where it hasn't been appended
if(el.dom){
el.id = Ext.id(el.dom);
}else{
el.dom = el.id ? Ext.getDom(el.id, true) : null;
}
if(el.dom){
cache = resolveCache(el);
(cache[el.id] ||
(cache[el.id] = {data : {}, events : {}}
)).el = el; // in case it was created directly with Element(), let's cache it
}
return el;
}else if(el.tagName || Ext.isWindow(el)){ // dom element
cache = resolveCache(el);
id = Ext.id(el);
if(cache[id] && (ex = cache[id].el)){
ex.dom = el;
}else{
ex = El.addToCache(new (assertClass(el))(el, null, doc), null, cache);
}
return ex;
}else if(el.isComposite){
return el;
}else if(Ext.isArray(el)){
return Ext.get(doc,doc).select(el);
}
return null;
},
/**
* Ext.getDom to support targeted document contexts
*/
getDom : function(el, strict, doc){
var D = doc || DOC;
if(!el || !D){
return null;
}
if (el.dom){
return el.dom;
} else {
if (Ext.isString(el)) {
var e = D.getElementById(el);
// IE returns elements with the 'name' and 'id' attribute.
// we do a strict check to return the element with only the id attribute
if (e && Ext.isIE && strict) {
if (el == e.getAttribute('id')) {
return e;
} else {
return null;
}
}
return e;
} else {
return el;
}
}
},
/**
* Returns the current/specified document body as an {@link Ext.Element}.
* @param {HTMLDocument} doc (optional)
* @return Ext.Element The document's body
*/
getBody : function(doc){
var D = ELD.getDocument(doc) || DOC;
return Ext.get(D.body || D.documentElement);
},
getDoc :Ext.overload([
Ext.getDoc,
function(doc){ return Ext.get(doc,doc); }
])
});
// private method for getting and setting element data
El.data = function(el, key, value){
el = El.get(el);
if (!el) {
return null;
}
var c = resolveCache(el)[el.id].data;
if(arguments.length == 2){
return c[key];
}else{
return (c[key] = value);
}
};
El.addToCache = function(el, id, cache ){
id = id || Ext.id(el);
var C = cache || resolveCache(el);
C[id] = {
el: el.dom ? el : Ext.get(el),
data: {},
events: {}
};
var d = C[id].el.dom;
(d.getElementById || d.navigator) && (C[id].skipGC = true);
return C[id].el;
};
El.removeFromCache = function(el, cache){
if(el && el.id){
var C = cache || resolveCache(el);
delete C[el.id];
}
};
/*
* Add new Visibility Mode to element (sets height and width to 0px instead of display:none )
*/
El.ASCLASS = 3;
El.visibilityCls = 'x-hide-nosize';
var propCache = {},
camelRe = /(-[a-z])/gi,
camelFn = function(m, a){ return a.charAt(1).toUpperCase(); },
opacityRe = /alpha\(opacity=(.*)\)/i,
trimRe = /^\s+|\s+$/g,
marginRightRe = /marginRight/,
propFloat = Ext.isIE ? 'styleFloat' : 'cssFloat',
view = DOC.defaultView,
VISMODE = 'visibilityMode',
ELDISPLAY = El.DISPLAY,
ELVISIBILITY = El.VISIBILITY,
ELASCLASS = El.ASCLASS,
ORIGINALDISPLAY = 'originalDisplay',
PADDING = "padding",
MARGIN = "margin",
BORDER = "border",
LEFT = "-left",
RIGHT = "-right",
TOP = "-top",
BOTTOM = "-bottom",
WIDTH = "-width",
MATH = Math,
OPACITY = "opacity",
VISIBILITY = "visibility",
DISPLAY = "display",
OFFSETS = "offsets",
ASCLASS = "asclass",
HIDDEN = "hidden",
NONE = "none",
ISVISIBLE = 'isVisible',
ISCLIPPED = 'isClipped',
OVERFLOW = 'overflow',
OVERFLOWX = 'overflow-x',
OVERFLOWY = 'overflow-y',
ORIGINALCLIP = 'originalClip',
XMASKED = "x-masked",
XMASKEDRELATIVE = "x-masked-relative",
// special markup used throughout Ext when box wrapping elements
borders = {l: BORDER + LEFT + WIDTH, r: BORDER + RIGHT + WIDTH, t: BORDER + TOP + WIDTH, b: BORDER + BOTTOM + WIDTH},
paddings = {l: PADDING + LEFT, r: PADDING + RIGHT, t: PADDING + TOP, b: PADDING + BOTTOM},
margins = {l: MARGIN + LEFT, r: MARGIN + RIGHT, t: MARGIN + TOP, b: MARGIN + BOTTOM},
data = El.data,
GETDOM = Ext.getDom,
GET = Ext.get,
DH = Ext.DomHelper,
propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/,
CSS = Ext.util.CSS, //Not available in Ext Core.
getDisplay = function(dom){
var d = data(dom, ORIGINALDISPLAY);
if(d === undefined){
data(dom, ORIGINALDISPLAY, d = '');
}
return d;
},
getVisMode = function(dom){
var m = data(dom, VISMODE);
if(m === undefined){
data(dom, VISMODE, m = El.prototype.visibilityMode);
}
return m;
};
function chkCache(prop) {
return propCache[prop] || (propCache[prop] = prop == 'float' ? propFloat : prop.replace(camelRe, camelFn));
};
El.addMethods({
/**
* Resolves the current document context of this Element
*/
getDocument : function(){
return this._context || (this._context = GETDOC(this));
},
/**
* Removes this element from the DOM and deletes it from the cache
* @param {Boolean} cleanse (optional) Perform a cleanse of immediate childNodes as well.
* @param {Boolean} deep (optional) Perform a deep cleanse of all nested childNodes as well.
*/
remove : function(cleanse, deep){
var dom = this.dom;
this.isMasked() && this.unmask();
if(dom){
Ext.removeNode(dom);
delete this._context;
delete this.dom;
}
},
/**
* Appends the passed element(s) to this element
* @param {String/HTMLElement/Array/Element/CompositeElement} el
* @param {Document} doc (optional) specific document context for the Element search
* @return {Ext.Element} this
*/
appendChild: function(el, doc){
return GET(el, doc || this.getDocument()).appendTo(this);
},
/**
* Appends this element to the passed element
* @param {Mixed} el The new parent element
* @param {Document} doc (optional) specific document context for the Element search
* @return {Ext.Element} this
*/
appendTo: function(el, doc){
GETDOM(el, false, doc || this.getDocument()).appendChild(this.dom);
return this;
},
/**
* Inserts this element before the passed element in the DOM
* @param {Mixed} el The element before which this element will be inserted
* @param {Document} doc (optional) specific document context for the Element search
* @return {Ext.Element} this
*/
insertBefore: function(el, doc){
(el = GETDOM(el, false, doc || this.getDocument())).parentNode.insertBefore(this.dom, el);
return this;
},
/**
* Inserts this element after the passed element in the DOM
* @param {Mixed} el The element to insert after
* @param {Document} doc (optional) specific document context for the Element search
* @return {Ext.Element} this
*/
insertAfter: function(el, doc){
(el = GETDOM(el, false, doc || this.getDocument())).parentNode.insertBefore(this.dom, el.nextSibling);
return this;
},
/**
* Inserts (or creates) an element (or DomHelper config) as the first child of this element
* @param {Mixed/Object} el The id or element to insert or a DomHelper config to create and insert
* @param {Document} doc (optional) specific document context for the Element search
* @return {Ext.Element} The new child
*/
insertFirst: function(el, returnDom){
el = el || {};
if(el.nodeType || el.dom || typeof el == 'string'){ // element
el = GETDOM(el);
this.dom.insertBefore(el, this.dom.firstChild);
return !returnDom ? GET(el) : el;
}else{ // dh config
return this.createChild(el, this.dom.firstChild, returnDom);
}
},
/**
* Replaces the passed element with this element
* @param {Mixed} el The element to replace
* @param {Document} doc (optional) specific document context for the Element search
* @return {Ext.Element} this
*/
replace: function(el, doc){
el = GET(el, doc || this.getDocument());
this.insertBefore(el);
el.remove();
return this;
},
/**
* Replaces this element with the passed element
* @param {Mixed/Object} el The new element or a DomHelper config of an element to create
* @param {Document} doc (optional) specific document context for the Element search
* @return {Ext.Element} this
*/
replaceWith: function(el, doc){
var me = this;
if(el.nodeType || el.dom || typeof el == 'string'){
el = GETDOM(el, false, doc || me.getDocument());
me.dom.parentNode.insertBefore(el, me.dom);
}else{
el = DH.insertBefore(me.dom, el);
}
var C = resolveCache(me);
Ext.removeNode(me.dom);
me.id = Ext.id(me.dom = el);
El.addToCache(me.isFlyweight ? new (assertClass(me.dom))(me.dom, null, C) : me);
return me;
},
/**
* Inserts an html fragment into this element
* @param {String} where Where to insert the html in relation to this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
* @param {String} html The HTML fragment
* @param {Boolean} returnEl (optional) True to return an Ext.Element (defaults to false)
* @return {HTMLElement/Ext.Element} The inserted node (or nearest related if more than 1 inserted)
*/
insertHtml : function(where, html, returnEl){
var el = DH.insertHtml(where, this.dom, html);
return returnEl ? Ext.get(el, GETDOC(el)) : el;
},
/**
* Sets the element's visibility mode. When setVisible() is called it
* will use this to determine whether to set the visibility or the display property.
* @param {Number} visMode Ext.Element.VISIBILITY or Ext.Element.DISPLAY
* @return {Ext.Element} this
*/
setVisibilityMode : function(visMode){
data(this.dom, VISMODE, visMode);
return this;
},
/**
* Checks whether the element is currently visible using both visibility and display properties.
* @return {Boolean} True if the element is currently visible, else false
*/
isVisible : function() {
return this.visible || Ext.value( data(this.dom, ISVISIBLE ),
!this.isStyle(VISIBILITY, HIDDEN) && !this.isStyle(DISPLAY, NONE));
},
//visibilityMode : El.DISPLAY = 3,
/**
* Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
* the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
* @param {Boolean} visible Whether the element is visible
* @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object, or one of four
* possible hideMode strings: 'display, visibility, offsets, asclass'
* @return {Ext.Element} this
*/
setVisible : function(visible, animate){
var me = this,
dom = me.dom,
isDisplay, isVisibility, isOffsets, isClass;
// hideMode string override
if (typeof animate == 'string'){
isDisplay = animate == DISPLAY;
isVisibility = animate == VISIBILITY;
isOffsets = animate == OFFSETS;
isClass = animate == ASCLASS;
animate = false;
} else {
var visMode = getVisMode(dom);
isDisplay = visMode == ELDISPLAY;
isVisibility = visMode == ELVISIBILITY;
isClass = visMode == ELASCLASS;
}
if (!animate || !me.anim) {
if (isClass){
me[visible?'removeClass':'addClass'](me.visibilityCls || El.visibilityCls);
} else if (isDisplay){
return me.setDisplayed(visible);
} else if (isOffsets){
if (!visible){
me.hideModeStyles = {
position: me.getStyle('position'),
top: me.getStyle('top'),
left: me.getStyle('left')
};
me.applyStyles({position: 'absolute', top: '-10000px', left: '-10000px'});
} else {
me.applyStyles(me.hideModeStyles || {position: '', top: '', left: ''});
delete me.hideModeStyles;
}
}else{
me.fixDisplay();
if (dom) {
dom.style.visibility = visible ? "visible" : HIDDEN;
}
}
}else{
// closure for composites
if(visible){
me.setOpacity(.01);
me.setVisible(true);
}
me.anim({opacity: { to: (visible?1:0) }},
me.preanim(arguments, 1),
null,
.35,
'easeIn',
function(){
if(!visible){
isClass ?
me.addClass(me.visibilityCls || El.visibilityCls) :
dom.style[isDisplay ? DISPLAY : VISIBILITY] = (isDisplay) ? NONE : HIDDEN;
me.setOpacity(1);
}
});
}
data(dom, ISVISIBLE, visible); //set logical visibility state
return me;
},
/**
* Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
* @param {Mixed} value Boolean value to display the element using its default display, or a string to set the display directly.
* @return {Ext.Element} this
*/
setDisplayed : function(value) {
var dom = this.dom,
visMode = getVisMode(dom);
if(typeof value == "boolean"){
if(visMode == El.ASCLASS){
return this.setVisible(value, ASCLASS);
}
data(this.dom, ISVISIBLE, value);
value = value ? getDisplay(dom) : NONE;
}
this.setStyle(DISPLAY, value);
return this;
},
// private
fixDisplay : function(){
var me = this;
if(me.isStyle(DISPLAY, NONE)){
me.setStyle(VISIBILITY, HIDDEN);
me.setStyle(DISPLAY, getDisplay(me.dom)); // first try reverting to default
if(me.isStyle(DISPLAY, NONE)){ // if that fails, default to block
me.setStyle(DISPLAY, "block");
}
}
data(me.dom, ISVISIBLE) || me.removeClass(me.visibilityCls || El.visibilityCls);
},
/**
* Convenience method for setVisibilityMode(Element.DISPLAY)
* @param {String} display (optional) What to set display to when visible
* @return {Ext.Element} this
*/
enableDisplayMode : function(display){
this.setVisibilityMode(El.DISPLAY);
if(!Ext.isEmpty(display)){
data(this.dom, ORIGINALDISPLAY, display);
}
return this;
},
scrollIntoView : function(container, hscroll){
var d = this.getDocument(),
c = Ext.getDom(container, null, d) || Ext.getBody(d).dom,
el = this.dom,
o = this.getOffsetsTo(c),
l = o[0] + c.scrollLeft,
t = o[1] + c.scrollTop,
b = t + el.offsetHeight,
r = l + el.offsetWidth,
ch = c.clientHeight,
ct = parseInt(c.scrollTop, 10),
cl = parseInt(c.scrollLeft, 10),
cb = ct + ch,
cr = cl + c.clientWidth;
if(el.offsetHeight > ch || t < ct){
c.scrollTop = t;
}else if(b > cb){
c.scrollTop = b-ch;
}
// corrects IE, other browsers will ignore
c.scrollTop = c.scrollTop;
if(hscroll !== false){
if(el.offsetWidth > c.clientWidth || l < cl){
c.scrollLeft = l;
}else if(r > cr){
c.scrollLeft = r-c.clientWidth;
}
c.scrollLeft = c.scrollLeft;
}
return this;
},
contains : function(el){
try {
return !el ? false : ELD.isAncestor(this.dom, el.dom ? el.dom : el);
} catch(e) {
return false;
}
},
/**
* Returns the current scroll position of the element.
* @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
*/
getScroll : function(){
var d = this.dom,
doc = this.getDocument(),
body = doc.body,
docElement = doc.documentElement,
l,
t,
ret;
if(Ext.isDocument(d) || d == body){
if(Ext.isIE && ELD.docIsStrict(doc)){
l = docElement.scrollLeft;
t = docElement.scrollTop;
}else{
l = window.pageXOffset;
t = window.pageYOffset;
}
ret = {left: l || (body ? body.scrollLeft : 0), top: t || (body ? body.scrollTop : 0)};
}else{
ret = {left: d.scrollLeft, top: d.scrollTop};
}
return ret;
},
/**
* Normalizes currentStyle and computedStyle.
* @param {String} property The style property whose value is returned.
* @return {String} The current value of the style property for this element.
*/
getStyle : function(){
var getStyle =
view && view.getComputedStyle ?
function GS(prop){
var el = !this._isDoc ? this.dom : null,
v,
cs,
out,
display,
wk = Ext.isWebKit,
display;
if(!el || !el.style) return null;
prop = chkCache(prop);
out = (v = el.style[prop]) ? v :
(cs = view.getComputedStyle(el, '')) ? cs[prop] : null;
// Fix bug caused by this: https://bugs.webkit.org/show_bug.cgi?id=13343
if(wk){
if((marginRightRe.test(prop)) && out != '0px'){
display = this.getStyle('display');
el.style.display = 'inline-block';
out = view.getComputedStyle(el, '');
el.style.display = display;
}
// Webkit returns rgb values for transparent.
if(out == 'rgba(0, 0, 0, 0)'){
out = 'transparent';
}
}
return out;
} :
function GS(prop){ //IE
var el = !this._isDoc ? this.dom : null,
m,
cs;
if(!el || !el.style) return null;
if (prop == OPACITY) {
if (el.style.filter.match) {
if(m = el.style.filter.match(opacityRe)){
var fv = parseFloat(m[1]);
if(!isNaN(fv)){
return fv ? fv / 100 : 0;
}
}
}
return 1;
}
prop = chkCache(prop);
return el.style[prop] || ((cs = el.currentStyle) ? cs[prop] : null);
};
var GS = null;
return getStyle;
}(),
/**
* Wrapper for setting style properties, also takes single object parameter of multiple styles.
* @param {String/Object} property The style property to be set, or an object of multiple styles.
* @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
* @return {Ext.Element} this
*/
setStyle : function(prop, value){
if(this._isDoc || Ext.isDocument(this.dom)) return this;
var tmp, style;
if (typeof prop != 'object') {
tmp = {};
tmp[prop] = value;
prop = tmp;
}
for (style in prop) {
value = prop[style];
if (style == OPACITY) {
this.setOpacity(value)
}
else {
try {
this.dom.style[chkCache(style)] = value;
}
catch (err) {
null;
}
}
}
return this;
},
/**
* Centers the Element in either the viewport, or another Element.
* @param {Mixed} centerIn (optional) The element in which to center the element.
*/
center : function(centerIn){
return this.alignTo(centerIn || this.getDocument(), 'c-c');
},
/**
* Puts a mask over this element to disable user interaction. Requires core.css.
* This method can only be applied to elements which accept child nodes.
* @param {String} msg (optional) A message to display in the mask
* @param {String} msgCls (optional) A css class to apply to the msg element
* @return {Element} The mask element
*/
mask : function(msg, msgCls){
var me = this,
dom = me.dom,
dh = Ext.DomHelper,
EXTELMASKMSG = "ext-el-mask-msg",
el,
mask;
if(me.getStyle("position") == "static"){
me.addClass(XMASKEDRELATIVE);
}
if((el = data(dom, 'maskMsg'))){
el.remove();
}
if((el = data(dom, 'mask'))){
el.remove();
}
mask = dh.append(dom, {cls : "ext-el-mask"}, true);
data(dom, 'mask', mask);
me.addClass(XMASKED);
mask.setDisplayed(true);
if(typeof msg == 'string'){
var mm = dh.append(dom, {cls : EXTELMASKMSG, cn:{tag:'div'}}, true);
data(dom, 'maskMsg', mm);
mm.dom.className = msgCls ? EXTELMASKMSG + " " + msgCls : EXTELMASKMSG;
mm.dom.firstChild.innerHTML = msg;
mm.setDisplayed(true);
mm.center(me);
}
if(Ext.isIE && !(Ext.isIE7 && Ext.isStrict) && me.getStyle('height') == 'auto'){ // ie will not expand full height automatically
mask.setSize(undefined, me.getHeight());
}
return mask;
},
/**
* Removes a previously applied mask.
*/
unmask : function(){
var me = this,
dom = me.dom,
mask = data(dom, 'mask'),
maskMsg = data(dom, 'maskMsg');
if(mask){
if(maskMsg){
maskMsg.remove();
data(dom, 'maskMsg', undefined);
}
mask.remove();
data(dom, 'mask', undefined);
}
me.removeClass([XMASKED, XMASKEDRELATIVE]);
},
/**
* Returns true if this element is masked
* @return {Boolean}
*/
isMasked : function(){
var m = data(this.dom, 'mask');
return m && m.isVisible();
},
/**
* Calculates the x, y to center this element on the screen
* @return {Array} The x, y values [x, y]
*/
getCenterXY : function(){
return this.getAlignToXY(this.getDocument(), 'c-c');
},
/**
* Gets the x,y coordinates specified by the anchor position on the element.
* @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo}
* for details on supported anchor positions.
* @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead
* of page coordinates
* @param {Object} size (optional) An object containing the size to use for calculating anchor position
* {width: (target width), height: (target height)} (defaults to the element's current size)
* @return {Array} [x, y] An array containing the element's x and y coordinates
*/
getAnchorXY : function(anchor, local, s){
//Passing a different size is useful for pre-calculating anchors,
//especially for anchored animations that change the el size.
anchor = (anchor || "tl").toLowerCase();
s = s || {};
var me = this, doc = this.getDocument(),
vp = me.dom == doc.body || me.dom == doc,
w = s.width || vp ? ELD.getViewWidth(false,doc) : me.getWidth(),
h = s.height || vp ? ELD.getViewHeight(false,doc) : me.getHeight(),
xy,
r = Math.round,
o = me.getXY(),
scroll = me.getScroll(),
extraX = vp ? scroll.left : !local ? o[0] : 0,
extraY = vp ? scroll.top : !local ? o[1] : 0,
hash = {
c : [r(w * .5), r(h * .5)],
t : [r(w * .5), 0],
l : [0, r(h * .5)],
r : [w, r(h * .5)],
b : [r(w * .5), h],
tl : [0, 0],
bl : [0, h],
br : [w, h],
tr : [w, 0]
};
xy = hash[anchor];
return [xy[0] + extraX, xy[1] + extraY];
},
/**
* Anchors an element to another element and realigns it when the window is resized.
* @param {Mixed} element The element to align to.
* @param {String} position The position to align to.
* @param {Array} offsets (optional) Offset the positioning by [x, y]
* @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
* @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
* is a number, it is used as the buffer delay (defaults to 50ms).
* @param {Function} callback The function to call after the animation finishes
* @return {Ext.Element} this
*/
anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
var me = this,
dom = me.dom;
function action(){
fly(dom).alignTo(el, alignment, offsets, animate);
Ext.callback(callback, fly(dom));
};
Ext.EventManager.onWindowResize(action, me);
if(!Ext.isEmpty(monitorScroll)){
Ext.EventManager.on(window, 'scroll', action, me,
{buffer: !isNaN(monitorScroll) ? monitorScroll : 50});
}
action.call(me); // align immediately
return me;
},
/**
* Returns the current scroll position of the element.
* @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
*/
getScroll : function(){
var d = this.dom,
doc = this.getDocument(),
body = doc.body,
docElement = doc.documentElement,
l,
t,
ret;
if(d == doc || d == body){
if(Ext.isIE && ELD.docIsStrict(doc)){
l = docElement.scrollLeft;
t = docElement.scrollTop;
}else{
l = window.pageXOffset;
t = window.pageYOffset;
}
ret = {left: l || (body ? body.scrollLeft : 0), top: t || (body ? body.scrollTop : 0)};
}else{
ret = {left: d.scrollLeft, top: d.scrollTop};
}
return ret;
},
/**
* Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
* supported position values.
* @param {Mixed} element The element to align to.
* @param {String} position The position to align to.
* @param {Array} offsets (optional) Offset the positioning by [x, y]
* @return {Array} [x, y]
*/
getAlignToXY : function(el, p, o){
var doc;
el = Ext.get(el, doc = this.getDocument());
if(!el || !el.dom){
throw "Element.getAlignToXY with an element that doesn't exist";
}
o = o || [0,0];
p = (p == "?" ? "tl-bl?" : (!/-/.test(p) && p != "" ? "tl-" + p : p || "tl-bl")).toLowerCase();
var me = this,
d = me.dom,
a1,
a2,
x,
y,
//constrain the aligned el to viewport if necessary
w,
h,
r,
dw = ELD.getViewWidth(false,doc) -10, // 10px of margin for ie
dh = ELD.getViewHeight(false,doc)-10, // 10px of margin for ie
p1y,
p1x,
p2y,
p2x,
swapY,
swapX,
docElement = doc.documentElement,
docBody = doc.body,
scrollX = (docElement.scrollLeft || docBody.scrollLeft || 0)+5,
scrollY = (docElement.scrollTop || docBody.scrollTop || 0)+5,
c = false, //constrain to viewport
p1 = "",
p2 = "",
m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
if(!m){
throw "Element.getAlignToXY with an invalid alignment " + p;
}
p1 = m[1];
p2 = m[2];
c = !!m[3];
//Subtract the aligned el's internal xy from the target's offset xy
//plus custom offset to get the aligned el's new offset xy
a1 = me.getAnchorXY(p1, true);
a2 = el.getAnchorXY(p2, false);
x = a2[0] - a1[0] + o[0];
y = a2[1] - a1[1] + o[1];
if(c){
w = me.getWidth();
h = me.getHeight();
r = el.getRegion();
//If we are at a viewport boundary and the aligned el is anchored on a target border that is
//perpendicular to the vp border, allow the aligned el to slide on that border,
//otherwise swap the aligned el to the opposite border of the target.
p1y = p1.charAt(0);
p1x = p1.charAt(p1.length-1);
p2y = p2.charAt(0);
p2x = p2.charAt(p2.length-1);
swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
if (x + w > dw + scrollX) {
x = swapX ? r.left-w : dw+scrollX-w;
}
if (x < scrollX) {
x = swapX ? r.right : scrollX;
}
if (y + h > dh + scrollY) {
y = swapY ? r.top-h : dh+scrollY-h;
}
if (y < scrollY){
y = swapY ? r.bottom : scrollY;
}
}
return [x,y];
},
// private ==> used outside of core
adjustForConstraints : function(xy, parent, offsets){
return this.getConstrainToXY(parent || this.getDocument(), false, offsets, xy) || xy;
},
// private ==> used outside of core
getConstrainToXY : function(el, local, offsets, proposedXY){
var os = {top:0, left:0, bottom:0, right: 0};
return function(el, local, offsets, proposedXY){
var doc = this.getDocument();
el = Ext.get(el, doc);
offsets = offsets ? Ext.applyIf(offsets, os) : os;
var vw, vh, vx = 0, vy = 0;
if(el.dom == doc.body || el.dom == doc){
vw = ELD.getViewWidth(false,doc);
vh = ELD.getViewHeight(false,doc);
}else{
vw = el.dom.clientWidth;
vh = el.dom.clientHeight;
if(!local){
var vxy = el.getXY();
vx = vxy[0];
vy = vxy[1];
}
}
var s = el.getScroll();
vx += offsets.left + s.left;
vy += offsets.top + s.top;
vw -= offsets.right;
vh -= offsets.bottom;
var vr = vx + vw,
vb = vy + vh,
xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
x = xy[0], y = xy[1],
offset = this.getConstrainOffset(),
w = this.dom.offsetWidth + offset,
h = this.dom.offsetHeight + offset;
// only move it if it needs it
var moved = false;
// first validate right/bottom
if((x + w) > vr){
x = vr - w;
moved = true;
}
if((y + h) > vb){
y = vb - h;
moved = true;
}
// then make sure top/left isn't negative
if(x < vx){
x = vx;
moved = true;
}
if(y < vy){
y = vy;
moved = true;
}
return moved ? [x, y] : false;
};
}(),
// private, used internally
getConstrainOffset : function(){
return 0;
},
/**
* Calculates the x, y to center this element on the screen
* @return {Array} The x, y values [x, y]
*/
getCenterXY : function(){
return this.getAlignToXY(Ext.getBody(this.getDocument()), 'c-c');
},
/**
* Centers the Element in either the viewport, or another Element.
* @param {Mixed} centerIn (optional) The element in which to center the element.
*/
center : function(centerIn){
return this.alignTo(centerIn || Ext.getBody(this.getDocument()), 'c-c');
} ,
/**
* Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
* @param {String} selector The simple selector to test
* @param {Number/Mixed} maxDepth (optional) The max depth to search as a number or element (defaults to 50 || document.body)
* @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
* @return {HTMLElement} The matching DOM node (or null if no match was found)
*/
findParent : function(simpleSelector, maxDepth, returnEl){
var p = this.dom,
D = this.getDocument(),
b = D.body,
depth = 0,
stopEl;
if(Ext.isGecko && OPString.call(p) == '[object XULElement]') {
return null;
}
maxDepth = maxDepth || 50;
if (isNaN(maxDepth)) {
stopEl = Ext.getDom(maxDepth, null, D);
maxDepth = Number.MAX_VALUE;
}
while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
if(Ext.DomQuery.is(p, simpleSelector)){
return returnEl ? Ext.get(p, D) : p;
}
depth++;
p = p.parentNode;
}
return null;
},
/**
* Store the current overflow setting and clip overflow on the element - use <tt>{@link #unclip}</tt> to remove
* @return {Ext.Element} this
*/
clip : function(){
var me = this,
dom = me.dom;
if(!data(dom, ISCLIPPED)){
data(dom, ISCLIPPED, true);
data(dom, ORIGINALCLIP, {
o: me.getStyle(OVERFLOW),
x: me.getStyle(OVERFLOWX),
y: me.getStyle(OVERFLOWY)
});
me.setStyle(OVERFLOW, HIDDEN);
me.setStyle(OVERFLOWX, HIDDEN);
me.setStyle(OVERFLOWY, HIDDEN);
}
return me;
},
/**
* Return clipping (overflow) to original clipping before <tt>{@link #clip}</tt> was called
* @return {Ext.Element} this
*/
unclip : function(){
var me = this,
dom = me.dom;
if(data(dom, ISCLIPPED)){
data(dom, ISCLIPPED, false);
var o = data(dom, ORIGINALCLIP);
if(o.o){
me.setStyle(OVERFLOW, o.o);
}
if(o.x){
me.setStyle(OVERFLOWX, o.x);
}
if(o.y){
me.setStyle(OVERFLOWY, o.y);
}
}
return me;
},
getViewSize : function(){
var doc = this.getDocument(),
d = this.dom,
isDoc = (d == doc || d == doc.body);
// If the body, use Ext.lib.Dom
if (isDoc) {
var extdom = Ext.lib.Dom;
return {
width : extdom.getViewWidth(),
height : extdom.getViewHeight()
};
// Else use clientHeight/clientWidth
} else {
return {
width : d.clientWidth,
height : d.clientHeight
};
}
},
/**
* <p>Returns the dimensions of the element available to lay content out in.<p>
*
* getStyleSize utilizes prefers style sizing if present, otherwise it chooses the larger of offsetHeight/clientHeight and offsetWidth/clientWidth.
* To obtain the size excluding scrollbars, use getViewSize
*
* Sizing of the document body is handled at the adapter level which handles special cases for IE and strict modes, etc.
*/
getStyleSize : function(){
var me = this,
w, h,
doc = this.getDocument(),
d = this.dom,
isDoc = (d == doc || d == doc.body),
s = d.style;
// If the body, use Ext.lib.Dom
if (isDoc) {
var extdom = Ext.lib.Dom;
return {
width : extdom.getViewWidth(),
height : extdom.getViewHeight()
};
}
// Use Styles if they are set
if(s.width && s.width != 'auto'){
w = parseFloat(s.width);
if(me.isBorderBox()){
w -= me.getFrameWidth('lr');
}
}
// Use Styles if they are set
if(s.height && s.height != 'auto'){
h = parseFloat(s.height);
if(me.isBorderBox()){
h -= me.getFrameWidth('tb');
}
}
// Use getWidth/getHeight if style not set.
return {width: w || me.getWidth(true), height: h || me.getHeight(true)};
}
});
//Stop the existing collectorThread
Ext.isDefined(El.collectorThreadId) && clearInterval(El.collectorThreadId);
// private
// Garbage collection - uncache elements/purge listeners on orphaned elements
// so we don't hold a reference and cause the browser to retain them
function garbageCollect(){
if(!Ext.enableGarbageCollector){
clearInterval(El.collectorThreadId);
} else {
var eid,
el,
d,
o,
EC = Ext.elCache;
for(eid in EC){
o = EC[eid];
if(o.skipGC){
continue;
}
el = o.el;
d = el.dom;
// -------------------------------------------------------
// Determining what is garbage:
// -------------------------------------------------------
// !d
// dom node is null, definitely garbage
// -------------------------------------------------------
// !d.parentNode
// no parentNode == direct orphan, definitely garbage
// -------------------------------------------------------
// !d.offsetParent && !document.getElementById(eid)
// display none elements have no offsetParent so we will
// also try to look it up by it's id. However, check
// offsetParent first so we don't do unneeded lookups.
// This enables collection of elements that are not orphans
// directly, but somewhere up the line they have an orphan
// parent.
// -------------------------------------------------------
if(!d || !d.parentNode || (!d.offsetParent && !DOC.getElementById(eid))){
if(Ext.enableListenerCollection){
Ext.EventManager.removeAll(d);
}
delete EC[eid];
}
}
// Cleanup IE COM Object Hash reference leaks
if (Ext.isIE) {
var t = {};
for (eid in EC) {
t[eid] = EC[eid];
}
Ext.elCache = Ext._documents[Ext.id(document)] = t;
t = null;
}
}
}
//Restart if enabled
if(Ext.enableGarbageCollector){
El.collectorThreadId = setInterval(garbageCollect, 30000);
}
Ext.apply(ELD , {
/**
* Resolve the current document context of the passed Element
*/
getDocument : function(el, accessTest){
var dom= null;
try{
dom = Ext.getDom(el, null, null); //will fail if El.dom is non "same-origin" document
}catch(ex){}
var isDoc = Ext.isDocument(dom);
if(isDoc){
if(accessTest){
return Ext.isDocument(dom, accessTest) ? dom : null;
}
return dom;
}
return dom ?
dom.ownerDocument || //Element
dom.document //Window
: null;
},
/**
* Return the Compatability Mode of the passed document or Element
*/
docIsStrict : function(doc){
return (Ext.isDocument(doc) ? doc : this.getDocument(doc)).compatMode == "CSS1Compat";
},
getViewWidth : Ext.overload ([
ELD.getViewWidth || function(full){},
function() { return this.getViewWidth(false);},
function(full, doc) {
return full ? this.getDocumentWidth(doc) : this.getViewportWidth(doc);
}]
),
getViewHeight : Ext.overload ([
ELD.getViewHeight || function(full){},
function() { return this.getViewHeight(false);},
function(full, doc) {
return full ? this.getDocumentHeight(doc) : this.getViewportHeight(doc);
}]),
getDocumentHeight: Ext.overload([
ELD.getDocumentHeight || emptyFn,
function(doc) {
if(doc=this.getDocument(doc)){
return Math.max(
!this.docIsStrict(doc) ? doc.body.scrollHeight : doc.documentElement.scrollHeight
, this.getViewportHeight(doc)
);
}
return undefined;
}
]),
getDocumentWidth: Ext.overload([
ELD.getDocumentWidth || emptyFn,
function(doc) {
if(doc=this.getDocument(doc)){
return Math.max(
!this.docIsStrict(doc) ? doc.body.scrollWidth : doc.documentElement.scrollWidth
, this.getViewportWidth(doc)
);
}
return undefined;
}
]),
getViewportHeight: Ext.overload([
ELD.getViewportHeight || emptyFn,
function(doc){
if(doc=this.getDocument(doc)){
if(Ext.isIE){
return this.docIsStrict(doc) ? doc.documentElement.clientHeight : doc.body.clientHeight;
}else{
return doc.defaultView.innerHeight;
}
}
return undefined;
}
]),
getViewportWidth: Ext.overload([
ELD.getViewportWidth || emptyFn,
function(doc) {
if(doc=this.getDocument(doc)){
return !this.docIsStrict(doc) && !Ext.isOpera ? doc.body.clientWidth :
Ext.isIE ? doc.documentElement.clientWidth : doc.defaultView.innerWidth;
}
return undefined;
}
]),
getXY : Ext.overload([
ELD.getXY || emptyFn,
function(el, doc) {
el = Ext.getDom(el, null, doc);
var D= this.getDocument(el),
bd = D ? (D.body || D.documentElement): null;
if(!el || !bd || el == bd){ return [0, 0]; }
return this.getXY(el);
}
])
});
var GETDOC = ELD.getDocument,
flies = El._flyweights;
/**
* @private
* Add Ext.fly support for targeted document contexts
*/
Ext.fly = El.fly = function(el, named, doc){
var ret = null;
named = named || '_global';
if (el = Ext.getDom(el, null, doc)) {
(ret = flies[named] = (flies[named] || new El.Flyweight())).dom = el;
Ext.isDocument(el) && (ret._isDoc = true);
}
return ret;
};
var flyFn = function(){};
flyFn.prototype = El.prototype;
// dom is optional
El.Flyweight = function(dom){
this.dom = dom;
};
El.Flyweight.prototype = new flyFn();
El.Flyweight.prototype.isFlyweight = true;
function addListener(el, ename, fn, task, wrap, scope){
el = Ext.getDom(el);
if(!el){ return; }
var id = Ext.id(el),
cache = resolveCache(el);
cache[id] || El.addToCache(el, id, cache);
var es = cache[id].events || {}, wfn;
wfn = E.on(el, ename, wrap);
es[ename] = es[ename] || [];
es[ename].push([fn, wrap, scope, wfn, task]);
// this is a workaround for jQuery and should somehow be removed from Ext Core in the future
// without breaking ExtJS.
if(el.addEventListener && ename == "mousewheel" ){
var args = ["DOMMouseScroll", wrap, false];
el.addEventListener.apply(el, args);
Ext.EventManager.addListener(window, 'beforeunload', function(){
el.removeEventListener.apply(el, args);
});
}
if(ename == "mousedown" && DOC == el){ // fix stopped mousedowns on the document
Ext.EventManager.stoppedMouseDownEvent.addListener(wrap);
}
};
function createTargeted(h, o){
return function(){
var args = Ext.toArray(arguments);
if(o.target == Ext.EventObject.setEvent(args[0]).target){
h.apply(this, args);
}
};
};
function createBuffered(h, o, task){
return function(e){
// create new event object impl so new events don't wipe out properties
task.delay(o.buffer, h, null, [new Ext.EventObjectImpl(e)]);
};
};
function createSingle(h, el, ename, fn, scope){
return function(e){
Ext.EventManager.removeListener(el, ename, fn, scope);
h(e);
};
};
function createDelayed(h, o, fn){
return function(e){
var task = new Ext.util.DelayedTask(h);
(fn.tasks || (fn.tasks = [])).push(task);
task.delay(o.delay || 10, h, null, [new Ext.EventObjectImpl(e)]);
};
};
function listen(element, ename, opt, fn, scope){
var o = !Ext.isObject(opt) ? {} : opt,
el = Ext.getDom(element), task;
fn = fn || o.fn;
scope = scope || o.scope;
if(!el){
throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
}
function h(e){
// prevent errors while unload occurring
if(!window.Ext){ return; }
e = Ext.EventObject.setEvent(e);
var t;
if (o.delegate) {
if(!(t = e.getTarget(o.delegate, el))){
return;
}
} else {
t = e.target;
}
if (o.stopEvent) {
e.stopEvent();
}
if (o.preventDefault) {
e.preventDefault();
}
if (o.stopPropagation) {
e.stopPropagation();
}
if (o.normalized) {
e = e.browserEvent;
}
fn.call(scope || el, e, t, o);
};
if(o.target){
h = createTargeted(h, o);
}
if(o.delay){
h = createDelayed(h, o, fn);
}
if(o.single){
h = createSingle(h, el, ename, fn, scope);
}
if(o.buffer){
task = new Ext.util.DelayedTask(h);
h = createBuffered(h, o, task);
}
addListener(el, ename, fn, task, h, scope);
return h;
};
Ext.apply(Evm ,{
addListener : Evm.on = function(element, eventName, fn, scope, options){
if(typeof eventName == 'object'){
var o = eventName, e, val;
for(e in o){
val = o[e];
if(!propRe.test(e)){
if(Ext.isFunction(val)){
// shared options
listen(element, e, o, val, o.scope);
}else{
// individual options
listen(element, e, val);
}
}
}
} else {
listen(element, eventName, options, fn, scope);
}
},
/**
* Removes an event handler from an element. The shorthand version {@link #un} is equivalent. Typically
* you will use {@link Ext.Element#removeListener} directly on an Element in favor of calling this version.
* @param {String/HTMLElement} el The id or html element from which to remove the listener.
* @param {String} eventName The name of the event.
* @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
* @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
* then this must refer to the same object.
*/
removeListener : Evm.un = function(element, eventName, fn, scope){
var el = Ext.getDom(element);
el && Ext.get(el);
var elCache = el ? resolveCache(el) : {},
f = el && ((elCache[el.id]||{events:{}}).events)[eventName] || [],
wrap, i, l, k, len, fnc;
for (i = 0, len = f.length; i < len; i++) {
/* 0 = Original Function,
1 = Event Manager Wrapped Function,
2 = Scope,
3 = Adapter Wrapped Function,
4 = Buffered Task
*/
if (Ext.isArray(fnc = f[i]) && fnc[0] == fn && (!scope || fnc[2] == scope)) {
fnc[4] && fnc[4].cancel();
k = fn.tasks && fn.tasks.length;
if(k) {
while(k--) {
fn.tasks[k].cancel();
}
delete fn.tasks;
}
wrap = fnc[1];
E.un(el, eventName, E.extAdapter ? fnc[3] : wrap);
// jQuery workaround that should be removed from Ext Core
if(wrap && eventName == "mousewheel" && el.addEventListener ){
el.removeEventListener("DOMMouseScroll", wrap, false);
}
if(wrap && eventName == "mousedown" && DOC == el){ // fix stopped mousedowns on the document
Ext.EventManager.stoppedMouseDownEvent.removeListener(wrap);
}
f.splice(i,1);
if (f.length === 0) {
delete elCache[el.id].events[eventName];
}
for (k in elCache[el.id].events) {
return false;
}
elCache[el.id].events = {};
return false;
}
}
},
/**
* Removes all event handers from an element. Typically you will use {@link Ext.Element#removeAllListeners}
* directly on an Element in favor of calling this version.
* @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
*/
removeAll : function(el){
if (!(el = Ext.getDom(el))) {
return;
}
var id = el.id,
elCache = resolveCache(el)||{},
es = elCache[id] || {},
ev = es.events || {},
f, i, len, ename, fn, k, wrap;
for(ename in ev){
if(ev.hasOwnProperty(ename)){
f = ev[ename];
/* 0 = Original Function,
1 = Event Manager Wrapped Function,
2 = Scope,
3 = Adapter Wrapped Function,
4 = Buffered Task
*/
for (i = 0, len = f.length; i < len; i++) {
fn = f[i];
fn[4] && fn[4].cancel();
if(fn[0].tasks && (k = fn[0].tasks.length)) {
while(k--) {
fn[0].tasks[k].cancel();
}
delete fn.tasks;
}
wrap = fn[1];
E.un(el, ename, E.extAdapter ? fn[3] : wrap);
// jQuery workaround that should be removed from Ext Core
if(wrap && el.addEventListener && ename == "mousewheel"){
el.removeEventListener("DOMMouseScroll", wrap, false);
}
// fix stopped mousedowns on the document
if(wrap && DOC == el && ename == "mousedown"){
Ext.EventManager.stoppedMouseDownEvent.removeListener(wrap);
}
}
}
}
elCache[id] && (elCache[id].events = {});
},
getListeners : function(el, eventName) {
el = Ext.getDom(el);
if (!el) {
return;
}
var id = (Ext.get(el)||{}).id,
elCache = resolveCache(el),
es = ( elCache[id] || {} ).events || {};
return es[eventName] || null;
},
purgeElement : function(el, recurse, eventName) {
el = Ext.getDom(el);
var id = Ext.id(el),
elCache = resolveCache(el),
es = (elCache[id] || {}).events || {},
i, f, len;
if (eventName) {
if (es.hasOwnProperty(eventName)) {
f = es[eventName];
for (i = 0, len = f.length; i < len; i++) {
Evm.removeListener(el, eventName, f[i][0]);
}
}
} else {
Evm.removeAll(el);
}
if (recurse && el && el.childNodes) {
for (i = 0, len = el.childNodes.length; i < len; i++) {
Evm.purgeElement(el.childNodes[i], recurse, eventName);
}
}
}
});
// deprecated, call from EventManager
E.getListeners = function(el, eventName) {
return Ext.EventManager.getListeners(el, eventName);
};
/** @sourceURL=<multidom.js> */
Ext.provide && Ext.provide('multidom');
})();/* global Ext */
/*
* Copyright 2007-2010, Active Group, Inc. All rights reserved.
* ******************************************************************************
* This file is distributed on an AS IS BASIS WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* ***********************************************************************************
* @version 2.1.3
* [For Ext 3.1.1 or higher only]
*
* License: ux.ManagedIFrame, ux.ManagedIFrame.Panel, ux.ManagedIFrame.Portlet, ux.ManagedIFrame.Window
* are licensed under the terms of the Open Source GPL 3.0 license:
* http://www.gnu.org/licenses/gpl.html
*
* Commercial use is prohibited without a Commercial Developement License. See
* http://licensing.theactivegroup.com.
*
* Donations are welcomed: http://donate.theactivegroup.com
*
*/
(function(){
var El = Ext.Element,
ElFrame,
ELD = Ext.lib.Dom,
EMPTYFN = function(){},
OP = Object.prototype,
addListener = function () {
var handler;
if (window.addEventListener) {
handler = function F(el, eventName, fn, capture) {
el.addEventListener(eventName, fn, !!capture);
};
} else if (window.attachEvent) {
handler = function F(el, eventName, fn, capture) {
el.attachEvent("on" + eventName, fn);
};
} else {
handler = function F(){};
}
var F = null; //Gbg collect
return handler;
}(),
removeListener = function() {
var handler;
if (window.removeEventListener) {
handler = function F(el, eventName, fn, capture) {
el.removeEventListener(eventName, fn, (capture));
};
} else if (window.detachEvent) {
handler = function F(el, eventName, fn) {
el.detachEvent("on" + eventName, fn);
};
} else {
handler = function F(){};
}
var F = null; //Gbg collect
return handler;
}();
//assert multidom support: REQUIRED for Ext 3 or higher!
if(typeof ELD.getDocument != 'function'){
alert("MIF 2.1 requires multidom support" );
}
//assert Ext 3.1.1+
if(!Ext.elCache || parseInt( Ext.version.replace(/\./g,''),10) < 311 ) {
alert ('Ext Release '+Ext.version+' is not supported');
}
Ext.ns('Ext.ux.ManagedIFrame', 'Ext.ux.plugin');
var MIM, MIF = Ext.ux.ManagedIFrame, MIFC;
var frameEvents = ['documentloaded',
'domready',
'focus',
'blur',
'resize',
'scroll',
'unload',
'scroll',
'exception',
'message',
'reset'];
var reSynthEvents = new RegExp('^('+frameEvents.join('|')+ ')', 'i');
/**
* @class Ext.ux.ManagedIFrame.Element
* @extends Ext.Element
* @version 2.1.3
* @license <a href="http://www.gnu.org/licenses/gpl.html">GPL 3.0</a>
* @author Doug Hendricks. Forum ID: <a href="http://extjs.com/forum/member.php?u=8730">hendricd</a>
* @donate <a target="tag_donate" href="http://donate.theactivegroup.com"><img border="0" src="http://www.paypal.com/en_US/i/btn/x-click-butcc-donate.gif" border="0" alt="Make a donation to support ongoing development"></a>
* @copyright 2007-2010, Active Group, Inc. All rights reserved.
* @constructor Create a new Ext.ux.ManagedIFrame.Element directly.
* @param {String/HTMLElement} element
* @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
* @param {DocumentElement} (optional) Document context uses to resolve an Element search by its id.
*/
Ext.ux.ManagedIFrame.Element = Ext.extend(Ext.Element, {
constructor : function(element, forceNew, doc ){
var d = doc || document,
elCache = ELD.resolveDocumentCache(d),
dom = Ext.getDom(element, false, d);
if(!dom || !(/^(iframe|frame)/i).test(dom.tagName)) { // invalid id/element
return null;
}
var id = Ext.id(dom);
/**
* The DOM element
* @type HTMLElement
*/
this.dom = dom;
/**
* The DOM element ID
* @type String
*/
this.id = id ;
(elCache[id] ||
(elCache[id] = {
el: this,
events : {},
data : {}
})
).el = this;
this.dom.name || (this.dom.name = this.id);
if(Ext.isIE){
document.frames && (document.frames[this.dom.name] || (document.frames[this.dom.name] = this.dom));
}
this.dom.ownerCt = this;
MIM.register(this);
if(!this._observable){
(this._observable = new Ext.util.Observable()).addEvents(
/**
* Fires when the iFrame has reached a loaded/complete state.
* @event documentloaded
* @param {Ext.ux.MIF.Element} this
*/
'documentloaded',
/**
* Fires ONLY when an iFrame's Document(DOM) has reach a
* state where the DOM may be manipulated ('same origin' policy)
* Note: This event is only available when overwriting the iframe
* document using the update or load methods and "same-origin"
* documents. Returning false from the eventHandler stops further event
* (documentloaded) processing.
* @event domready
* @param {Ext.ux.MIF.Element} this
*/
'domready',
/**
* Fires when the frame actions raise an error
* @event exception
* @param {Ext.ux.MIF.Element} this.iframe
* @param {Error/string} exception
*/
'exception',
/**
* Fires when the frame's window is resized. This event, when raised from a "same-origin" frame,
* will send current height/width reports with the event.
* @event resize
* @param {Ext.ux.MIF.Element} this.iframe
* @param {Object} documentSize A height/width object signifying the new document size
* @param {Object} viewPortSize A height/width object signifying the size of the frame's viewport
* @param {Object} viewSize A height/width object signifying the size of the frame's view
*/
'resize',
/**
* Fires upon receipt of a message generated by window.sendMessage
* method of the embedded Iframe.window object
* @event message
* @param {Ext.ux.MIF} this.iframe
* @param {object}
* message (members: type: {string} literal "message", data
* {Mixed} [the message payload], domain [the document domain
* from which the message originated ], uri {string} the
* document URI of the message sender source (Object) the
* window context of the message sender tag {string} optional
* reference tag sent by the message sender
* <p>Alternate event handler syntax for message:tag filtering Fires upon
* receipt of a message generated by window.sendMessage method which
* includes a specific tag value of the embedded Iframe.window object
*/
'message',
/**
* Fires when the frame is blurred (loses focus).
* @event blur
* @param {Ext.ux.MIF} this
* @param {Ext.Event}
* Note: This event is only available when overwriting the
* iframe document using the update method and to pages
* retrieved from a "same domain". Returning false from the
* eventHandler [MAY] NOT cancel the event, as this event is
* NOT ALWAYS cancellable in all browsers.
*/
'blur',
/**
* Fires when the frame gets focus. Note: This event is only available
* when overwriting the iframe document using the update method and to
* pages retrieved from a "same domain". Returning false from the
* eventHandler [MAY] NOT cancel the event, as this event is NOT ALWAYS
* cancellable in all browsers.
* @event focus
* @param {Ext.ux.MIF.Element} this
* @param {Ext.Event}
*
*/
'focus',
/**
* Note: This event is only available when overwriting the iframe
* document using the update method and to pages retrieved from a "same-origin"
* domain. Note: Opera does not raise this event.
* @event unload * Fires when(if) the frames window object raises the unload event
* @param {Ext.ux.MIF.Element} this.
* @param {Ext.Event}
*/
'unload',
/**
* Note: This event is only available when overwriting the iframe
* document using the update method and to pages retrieved from a "same-origin"
* domain. To prevent numerous scroll events from being raised use the buffer listener
* option to limit the number of times the event is raised.
* @event scroll
* @param {Ext.ux.MIF.Element} this.
* @param {Ext.Event}
*/
'scroll',
/**
* Fires when the iFrame has been reset to a neutral domain state (blank document).
* @event reset
* @param {Ext.ux.MIF.Element} this
*/
'reset'
);
// Private internal document state events.
this._observable.addEvents('_docready','_docload');
}
var H = Ext.isIE?'onreadystatechange':'onload';
// Hook the Iframes loaded and error state handlers
this.dom[H] = this.loadHandler.createDelegate(this);
this.dom['onerror'] = this.loadHandler.createDelegate(this);
},
/** @private
* Removes the MIFElement interface from the FRAME Element.
* It does NOT remove the managed FRAME from the DOM. Use the {@link Ext.#ux.ManagedIFrame.Element-remove} method to perfom both functions.
*/
destructor : function () {
this.dom[Ext.isIE?'onreadystatechange':'onload'] = this.dom['onerror'] = EMPTYFN;
MIM.deRegister(this);
this.removeAllListeners();
Ext.destroy(this.frameShim, this.DDM);
this.hideMask(true);
delete this.loadMask;
this.reset();
this.manager = null;
this.dom.ownerCt = null;
},
/**
* Deep cleansing childNode Removal
* @param {Boolean} forceReclean (optional) By default the element
* keeps track if it has been cleansed already so
* you can call this over and over. However, if you update the element and
* need to force a reclean, you can pass true.
* @param {Boolean} deep (optional) Perform a deep cleanse of all childNodes as well.
*/
cleanse : function(forceReclean, deep){
if(this.isCleansed && forceReclean !== true){
return this;
}
var d = this.dom, n = d.firstChild, nx;
while(d && n){
nx = n.nextSibling;
deep && Ext.fly(n).cleanse(forceReclean, deep);
Ext.removeNode(n);
n = nx;
}
this.isCleansed = true;
return this;
},
/** (read-only) The last known URI set programmatically by the Component
* @property
* @type {String|Function}
*/
src : null,
/** (read-only) For "same-origin" frames only. Provides a reference to
* the Ext.util.CSS singleton to manipulate the style sheets of the frame's
* embedded document.
*
* @property
* @type Ext.util.CSS
*/
CSS : null,
/** Provides a reference to the managing Ext.ux.MIF.Manager instance.
*
* @property
* @type Ext.ux.MIF.Manager
*/
manager : null,
/**
* @cfg {Boolean} disableMessaging False to enable cross-frame messaging API
* @default true
*
*/
disableMessaging : true,
/**
* @cfg {Integer} domReadyRetries
* Maximum number of domready event detection retries for IE. IE does not provide
* a native DOM event to signal when the frames DOM may be manipulated, so a polling process
* is used to determine when the documents BODY is available. <p> Certain documents may not contain
* a BODY tag: eg. MHT(rfc/822), XML, or other non-HTML content. Detection polling will stop after this number of 2ms retries
* or when the documentloaded event is raised.</p>
* @default 7500 (* 2 = 15 seconds)
*/
domReadyRetries : 7500,
/**
* True to set focus on the frame Window as soon as its document
* reports loaded. <p>(Many external sites use IE's document.createRange to create
* DOM elements, but to be successful, IE requires that the FRAME have focus before
* such methods are called)</p>
* @cfg focusOnLoad
* @default true if IE
*/
focusOnLoad : Ext.isIE,
/**
* Toggles raising of events for URL actions that the Component did not initiate.
* @cfg {Boolean} eventsFollowFrameLinks set true to propogate domready and documentloaded
* events anytime the IFRAME's URL changes
* @default true
*/
eventsFollowFrameLinks : true,
/**
* Removes the FRAME from the DOM and deletes it from the cache
*/
remove : function(){
this.destructor.apply(this, arguments);
ElFrame.superclass.remove.apply(this,arguments);
},
/**
* Return the ownerDocument property of the IFRAME Element.
* (Note: This is not the document context of the FRAME's loaded document.
* See the getFrameDocument method for that.)
*/
getDocument :
function(){ return this.dom ? this.dom.ownerDocument : document;},
/**
* Loads the frame Element with the response from a form submit to the
* specified URL with the ManagedIframe.Element as it's submit target.
*
* @param {Object} submitCfg A config object containing any of the following options:
* <pre><code>
* myIframe.submitAsTarget({
* form : formPanel.form, //optional Ext.FormPanel, Ext form element, or HTMLFormElement
* url: "your-url.php",
* action : (see url) ,
* params: {param1: "foo", param2: "bar"}, // or URL encoded string or function that returns either
* callback: yourFunction, //optional, called with the signature (frame)
* scope: yourObject, // optional scope for the callback
* method: 'POST', //optional form.method
* encoding : "multipart/form-data" //optional, default = HTMLForm default
* });
*
* </code></pre>
* @return {Ext.ux.ManagedIFrame.Element} this
*
*/
submitAsTarget : function(submitCfg){
var opt = submitCfg || {},
D = this.getDocument(),
form = Ext.getDom(
opt.form ? opt.form.form || opt.form: null, false, D) ||
Ext.DomHelper.append(D.body, {
tag: 'form',
cls : 'x-hidden x-mif-form',
encoding : 'multipart/form-data'
}),
formFly = Ext.fly(form, '_dynaForm'),
formState = {
target: form.target || '',
method: form.method || '',
encoding: form.encoding || '',
enctype: form.enctype || '',
action: form.action || ''
},
encoding = opt.encoding || form.encoding,
method = opt.method || form.method || 'POST';
formFly.set({
target : this.dom.name,
method : method,
encoding: encoding,
action : opt.url || opt.action || form.action
});
if(method == 'POST' || !!opt.enctype){
formFly.set({enctype : opt.enctype || form.enctype || encoding});
}
var hiddens, hd, ps;
// add any additional dynamic params
if(opt.params && (ps = Ext.isFunction(opt.params) ? opt.params() : opt.params)){
hiddens = [];
Ext.iterate(ps = typeof ps == 'string'? Ext.urlDecode(ps, false): ps,
function(n, v){
Ext.fly(hd = D.createElement('input')).set({
type : 'hidden',
name : n,
value: v
});
form.appendChild(hd);
hiddens.push(hd);
});
}
opt.callback &&
this._observable.addListener('_docready',opt.callback, opt.scope,{single:true});
this._frameAction = true;
this._targetURI = location.href;
this.showMask();
//slight delay for masking
(function(){
form.submit();
// remove dynamic inputs
hiddens && Ext.each(hiddens, Ext.removeNode, Ext);
//Remove if dynamically generated, restore state otherwise
if(formFly.hasClass('x-mif-form')){
formFly.remove();
}else{
formFly.set(formState);
}
delete El._flyweights['_dynaForm'];
formFly = null;
this.hideMask(true);
}).defer(100, this);
return this;
},
/**
* @cfg {String} resetUrl Frame document reset string for use with the {@link #Ext.ux.ManagedIFrame.Element-reset} method.
* Defaults:<p> For IE on SSL domains - the current value of Ext.SSL_SECURE_URL<p> "about:blank" for all others.
*/
resetUrl : (function(){
return Ext.isIE && Ext.isSecure ? Ext.SSL_SECURE_URL : 'about:blank';
})(),
/**
* Sets the embedded Iframe src property. Note: invoke the function with
* no arguments to refresh the iframe based on the current src value.
*
* @param {String/Function} url (Optional) A string or reference to a Function that
* returns a URI string when called
* @param {Boolean} discardUrl (Optional) If not passed as <tt>false</tt>
* the URL of this action becomes the default SRC attribute
* for this iframe, and will be subsequently used in future
* setSrc calls (emulates autoRefresh by calling setSrc
* without params).
* @param {Function} callback (Optional) A callback function invoked when the
* frame document has been fully loaded.
* @param {Object} scope (Optional) scope by which the callback function is
* invoked.
*/
setSrc : function(url, discardUrl, callback, scope) {
var src = url || this.src || this.resetUrl;
var O = this._observable;
this._unHook();
Ext.isFunction(callback) && O.addListener('_docload', callback, scope||this, {single:true});
this.showMask();
(discardUrl !== true) && (this.src = src);
var s = this._targetURI = (Ext.isFunction(src) ? src() || '' : src);
try {
this._frameAction = true; // signal listening now
this.dom.src = s;
this.checkDOM();
} catch (ex) {
O.fireEvent.call(O, 'exception', this, ex);
}
return this;
},
/**
* Sets the embedded Iframe location using its replace method (precluding a history update).
* Note: invoke the function with no arguments to refresh the iframe based on the current src value.
*
* @param {String/Function} url (Optional) A string or reference to a Function that
* returns a URI string when called
* @param {Boolean} discardUrl (Optional) If not passed as <tt>false</tt>
* the URL of this action becomes the default SRC attribute
* for this iframe, and will be subsequently used in future
* setSrc calls (emulates autoRefresh by calling setSrc
* without params).
* @param {Function} callback (Optional) A callback function invoked when the
* frame document has been fully loaded.
* @param {Object} scope (Optional) scope by which the callback function is
* invoked.
*
*/
setLocation : function(url, discardUrl, callback, scope) {
var src = url || this.src || this.resetUrl;
var O = this._observable;
this._unHook();
Ext.isFunction(callback) && O.addListener('_docload', callback, scope||this, {single:true});
this.showMask();
var s = this._targetURI = (Ext.isFunction(src) ? src() || '' : src);
if (discardUrl !== true) {
this.src = src;
}
try {
this._frameAction = true; // signal listening now
this.getWindow().location.replace(s);
this.checkDOM();
} catch (ex) {
O.fireEvent.call(O,'exception', this, ex);
}
return this;
},
/**
* Resets the frame to a neutral (blank document) state without
* loadMasking.
*
* @param {String}
* src (Optional) A specific reset string (eg. 'about:blank')
* to use for resetting the frame.
* @param {Function}
* callback (Optional) A callback function invoked when the
* frame reset is complete.
* @param {Object}
* scope (Optional) scope by which the callback function is
* invoked.
*/
reset : function(src, callback, scope) {
this._unHook();
var loadMaskOff = false,
s = src,
win = this.getWindow(),
O = this._observable;
if(this.loadMask){
loadMaskOff = this.loadMask.disabled;
this.loadMask.disabled = false;
}
this.hideMask(true);
if(win){
this.isReset= true;
var cb = callback;
O.addListener('_docload',
function(frame) {
if(this.loadMask){
this.loadMask.disabled = loadMaskOff;
};
Ext.isFunction(cb) && (cb = cb.apply(scope || this, arguments));
O.fireEvent("reset", this);
}, this, {single:true});
Ext.isFunction(s) && ( s = src());
s = this._targetURI = Ext.isEmpty(s, true)? this.resetUrl: s;
win.location ? (win.location.href = s) : O.fireEvent('_docload', this);
}
return this;
},
/**
* @private
* Regular Expression filter pattern for script tag removal.
* @cfg {regexp} scriptRE script removal RegeXp
* Default: "/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/gi"
*/
scriptRE : /(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/gi,
/**
* Write(replacing) string content into the IFrames document structure
* @param {String} content The new content
* @param {Boolean} loadScripts
* (optional) true to also render and process embedded scripts
* @param {Function} callback (Optional) A callback function invoked when the
* frame document has been written and fully loaded. @param {Object}
* scope (Optional) scope by which the callback function is invoked.
*/
update : function(content, loadScripts, callback, scope) {
loadScripts = loadScripts || this.getUpdater().loadScripts || false;
content = Ext.DomHelper.markup(content || '');
content = loadScripts === true ? content : content.replace(this.scriptRE, "");
var doc;
if ((doc = this.getFrameDocument()) && !!content.length) {
this._unHook();
this.src = null;
this.showMask();
Ext.isFunction(callback) &&
this._observable.addListener('_docload', callback, scope||this, {single:true});
this._targetURI = location.href;
doc.open();
this._frameAction = true;
doc.write(content);
doc.close();
this.checkDOM();
} else {
this.hideMask(true);
Ext.isFunction(callback) && callback.call(scope, this);
}
return this;
},
/**
* Executes a Midas command on the current document, current selection, or the given range.
* @param {String} command The command string to execute in the frame's document context.
* @param {Booloean} userInterface (optional) True to enable user interface (if supported by the command)
* @param {Mixed} value (optional)
* @param {Boolean} validate If true, the command is validated to ensure it's invocation is permitted.
* @return {Boolean} indication whether command execution succeeded
*/
execCommand : function(command, userInterface, value, validate){
var doc, assert;
if ((doc = this.getFrameDocument()) && !!command) {
try{
Ext.isIE && this.getWindow().focus();
assert = validate && Ext.isFunction(doc.queryCommandEnabled) ?
doc.queryCommandEnabled(command) : true;
return assert && doc.execCommand(command, !!userInterface, value);
}catch(eex){return false;}
}
return false;
},
/**
* Sets the current DesignMode attribute of the Frame's document
* @param {Boolean/String} active True (or "on"), to enable designMode
*
*/
setDesignMode : function(active){
var doc;
(doc = this.getFrameDocument()) &&
(doc.designMode = (/on|true/i).test(String(active))?'on':'off');
},
/**
* Gets this element's Updater
*
* @return {Ext.ux.ManagedIFrame.Updater} The Updater
*/
getUpdater : function(){
return this.updateManager ||
(this.updateManager = new MIF.Updater(this));
},
/**
* Method to retrieve frame's history object.
* @return {object} or null if permission was denied
*/
getHistory : function(){
var h=null;
try{ h=this.getWindow().history; }catch(eh){}
return h;
},
/**
* Method to retrieve embedded frame Element objects. Uses simple
* caching (per frame) to consistently return the same object.
* Automatically fixes if an object was recreated with the same id via
* AJAX or DOM.
*
* @param {Mixed}
* el The id of the node, a DOM Node or an existing Element.
* @return {Element} The Element object (or null if no matching element
* was found)
*/
get : function(el) {
var doc = this.getFrameDocument();
return doc? Ext.get(el, doc) : doc=null;
},
/**
* Gets the globally shared flyweight Element for the frame, with the
* passed node as the active element. Do not store a reference to this
* element - the dom node can be overwritten by other code.
*
* @param {String/HTMLElement}
* el The dom node or id
* @param {String}
* named (optional) Allows for creation of named reusable
* flyweights to prevent conflicts (e.g. internally Ext uses
* "_internal")
* @return {Element} The shared Element object (or null if no matching
* element was found)
*/
fly : function(el, named) {
var doc = this.getFrameDocument();
return doc ? Ext.fly(el, named, doc) : null;
},
/**
* Return the dom node for the passed string (id), dom node, or
* Ext.Element relative to the embedded frame document context.
*
* @param {Mixed} el
* @return HTMLElement
*/
getDom : function(el) {
var d;
if (!el || !(d = this.getFrameDocument())) {
return (d=null);
}
return Ext.getDom(el, d);
},
/**
* Creates a {@link Ext.CompositeElement} for child nodes based on the
* passed CSS selector (the selector should not contain an id).
*
* @param {String} selector The CSS selector
* @param {Boolean} unique (optional) True to create a unique Ext.Element for
* each child (defaults to false, which creates a single
* shared flyweight object)
* @return {Ext.CompositeElement/Ext.CompositeElementLite} The composite element
*/
select : function(selector, unique) {
var d; return (d = this.getFrameDocument()) ? Ext.Element.select(selector,unique, d) : d=null;
},
/**
* Selects frame document child nodes based on the passed CSS selector
* (the selector should not contain an id).
*
* @param {String} selector The CSS selector
* @return {Array} An array of the matched nodes
*/
query : function(selector) {
var d; return (d = this.getFrameDocument()) ? Ext.DomQuery.select(selector, d): null;
},
/**
* Removes a DOM Element from the embedded document
* @param {Element/String} node The node id or node Element to remove
*/
removeNode : Ext.removeNode,
/**
* @private execScript sandbox and messaging interface
*/
_renderHook : function() {
this._windowContext = null;
this.CSS = this.CSS ? this.CSS.destroy() : null;
this._hooked = false;
try {
if (this.writeScript('(function(){(window.hostMIF = parent.document.getElementById("'
+ this.id
+ '").ownerCt)._windowContext='
+ (Ext.isIE
? 'window'
: '{eval:function(s){return new Function("return ("+s+")")();}}')
+ ';})()')) {
var w, p = this._frameProxy, D = this.getFrameDocument();
if(w = this.getWindow()){
p || (p = this._frameProxy = this._eventProxy.createDelegate(this));
addListener(w, 'focus', p);
addListener(w, 'blur', p);
addListener(w, 'resize', p);
addListener(w, 'unload', p);
D && addListener(Ext.isIE ? w : D, 'scroll', p);
}
D && (this.CSS = new Ext.ux.ManagedIFrame.CSS(D));
}
} catch (ex) {}
return this.domWritable();
},
/** @private : clear all event listeners and Element cache */
_unHook : function() {
if (this._hooked) {
this._windowContext && (this._windowContext.hostMIF = null);
this._windowContext = null;
var w, p = this._frameProxy;
if(p && this.domWritable() && (w = this.getWindow())){
removeListener(w, 'focus', p);
removeListener(w, 'blur', p);
removeListener(w, 'resize', p);
removeListener(w, 'unload', p);
removeListener(Ext.isIE ? w : this.getFrameDocument(), 'scroll', p);
}
}
ELD.clearDocumentCache && ELD.clearDocumentCache(this.id);
this.CSS = this.CSS ? this.CSS.destroy() : null;
this.domFired = this._frameAction = this.domReady = this._hooked = false;
},
/** @private */
_windowContext : null,
/**
* If sufficient privilege exists, returns the frame's current document
* as an HTMLElement.
*
* @return {HTMLElement} The frame document or false if access to document object was denied.
*/
getFrameDocument : function() {
var win = this.getWindow(), doc = null;
try {
doc = (Ext.isIE && win ? win.document : null)
|| this.dom.contentDocument
|| window.frames[this.dom.name].document || null;
} catch (gdEx) {
ELD.clearDocumentCache && ELD.clearDocumentCache(this.id);
return false; // signifies probable access restriction
}
doc = (doc && Ext.isFunction(ELD.getDocument)) ? ELD.getDocument(doc,true) : doc;
return doc;
},
/**
* Returns the frame's current HTML document object as an
* {@link Ext.Element}.
* @return {Ext.Element} The document
*/
getDoc : function() {
var D = this.getFrameDocument();
return Ext.get(D,D);
},
/**
* If sufficient privilege exists, returns the frame's current document
* body as an HTMLElement.
*
* @return {HTMLElement} The frame document body or Null if access to
* document object was denied.
*/
getBody : function() {
var d;
return (d = this.getFrameDocument()) ? this.get(d.body || d.documentElement) : null;
},
/**
* Attempt to retrieve the frames current URI via frame's document object
* @return {string} The frame document's current URI or the last know URI if permission was denied.
*/
getDocumentURI : function() {
var URI, d;
try {
URI = this.src && (d = this.getFrameDocument()) ? d.location.href: null;
} catch (ex) { // will fail on NON-same-origin domains
}
return URI || (Ext.isFunction(this.src) ? this.src() : this.src);
// fallback to last known
},
/**
* Attempt to retrieve the frames current URI via frame's Window object
* @return {string} The frame document's current URI or the last know URI if permission was denied.
*/
getWindowURI : function() {
var URI, w;
try {
URI = (w = this.getWindow()) ? w.location.href : null;
} catch (ex) {
} // will fail on NON-same-origin domains
return URI || (Ext.isFunction(this.src) ? this.src() : this.src);
// fallback to last known
},
/**
* Returns the frame's current window object.
*
* @return {Window} The frame Window object.
*/
getWindow : function() {
var dom = this.dom, win = null;
try {
win = dom.contentWindow || window.frames[dom.name] || null;
} catch (gwEx) {}
return win;
},
/**
* Scrolls a frame document's child element into view within the passed container.
* @param {String} child The id of the element to scroll into view.
* @param {Mixed} container (optional) The container element to scroll (defaults to the frame's document.body). Should be a
* string (id), dom node, or Ext.Element.
* @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
* @return {Ext.ux.ManagedIFrame.Element} this
*/
scrollChildIntoView : function(child, container, hscroll){
this.fly(child, '_scrollChildIntoView').scrollIntoView(this.getDom(container) || this.getBody().dom, hscroll);
return this;
},
/**
* Print the contents of the Iframes (if we own the document)
* @return {Ext.ux.ManagedIFrame.Element} this
*/
print : function() {
try {
var win;
if( win = this.getWindow()){
Ext.isIE && win.focus();
win.print();
}
} catch (ex) {
throw new MIF.Error('printexception' , ex.description || ex.message || ex);
}
return this;
},
/**
* Returns the general DOM modification capability (same-origin status) of the frame.
* @return {Boolean} accessible If True, the frame's inner DOM can be manipulated, queried, and
* Event Listeners set.
*/
domWritable : function() {
return !!Ext.isDocument(this.getFrameDocument(),true) //test access
&& !!this._windowContext;
},
/**
* eval a javascript code block(string) within the context of the
* Iframes' window object.
* @param {String} block A valid ('eval'able) script source block.
* @param {Boolean} useDOM if true, inserts the function
* into a dynamic script tag, false does a simple eval on the function
* definition. (useful for debugging) <p> Note: will only work after a
* successful iframe.(Updater) update or after same-domain document has
* been hooked, otherwise an exception is raised.
* @return {Mixed}
*/
execScript : function(block, useDOM) {
try {
if (this.domWritable()) {
if (useDOM) {
this.writeScript(block);
} else {
return this._windowContext.eval(block);
}
} else {
throw new MIF.Error('execscript-secure-context');
}
} catch (ex) {
this._observable.fireEvent.call(this._observable,'exception', this, ex);
return false;
}
return true;
},
/**
* Write a script block into the iframe's document
* @param {String} block A valid (executable) script source block.
* @param {object} attributes Additional Script tag attributes to apply to the script
* Element (for other language specs [vbscript, Javascript] etc.) <p>
* Note: writeScript will only work after a successful iframe.(Updater)
* update or after same-domain document has been hooked, otherwise an
* exception is raised.
*/
writeScript : function(block, attributes) {
attributes = Ext.apply({}, attributes || {}, {
type : "text/javascript",
text : block
});
try {
var head, script, doc = this.getFrameDocument();
if (doc && typeof doc.getElementsByTagName != 'undefined') {
if (!(head = doc.getElementsByTagName("head")[0])) {
// some browsers (Webkit, Safari) do not auto-create
// head elements during document.write
head = doc.createElement("head");
doc.getElementsByTagName("html")[0].appendChild(head);
}
if (head && (script = doc.createElement("script"))) {
for (var attrib in attributes) {
if (attributes.hasOwnProperty(attrib)
&& attrib in script) {
script[attrib] = attributes[attrib];
}
}
return !!head.appendChild(script);
}
}
} catch (ex) {
this._observable.fireEvent.call(this._observable, 'exception', this, ex);
}finally{
script = head = null;
}
return false;
},
/**
* Eval a function definition into the iframe window context.
* @param {String/Object} fn Name of the function or function map
* object: {name:'encodeHTML',fn:Ext.util.Format.htmlEncode}
* @param {Boolean} useDOM if true, inserts the fn into a dynamic script tag,
* false does a simple eval on the function definition
* @param {Boolean} invokeIt if true, the function specified is also executed in the
* Window context of the frame. Function arguments are not supported.
* @example <pre><code> var trim = function(s){ return s.replace(/^\s+|\s+$/g,''); };
* iframe.loadFunction('trim');
* iframe.loadFunction({name:'myTrim',fn:String.prototype.trim || trim});</code></pre>
*/
loadFunction : function(fn, useDOM, invokeIt) {
var name = fn.name || fn;
var fnSrc = fn.fn || window[fn];
name && fnSrc && this.execScript(name + '=' + fnSrc, useDOM); // fn.toString coercion
invokeIt && this.execScript(name + '()'); // no args only
},
/**
* @private
* Evaluate the Iframes readyState/load event to determine its
* 'load' state, and raise the 'domready/documentloaded' event when
* applicable.
*/
loadHandler : function(e, target) {
var rstatus = (this.dom||{}).readyState || (e || {}).type ;
if (this.eventsFollowFrameLinks || this._frameAction || this.isReset ) {
switch (rstatus) {
case 'domready' : // MIF
case 'DOMFrameContentLoaded' :
case 'domfail' : // MIF
this._onDocReady (rstatus);
break;
case 'load' : // Gecko, Opera, IE
case 'complete' :
this._onDocLoaded(rstatus);
break;
case 'error':
this._observable.fireEvent.apply(this._observable,['exception', this].concat(arguments));
break;
default :
}
this.frameState = rstatus;
}
},
/**
* @private
* @param {String} eventName
*/
_onDocReady : function(eventName ){
var w, obv = this._observable, D;
if(!this.isReset && this.focusOnLoad && (w = this.getWindow())){
w.focus();
}
//raise internal event regardless of state.
obv.fireEvent("_docready", this);
(D = this.getDoc()) && (D.isReady = true);
if ( !this.domFired &&
(this._hooked = this._renderHook())) {
// Only raise if sandBox injection succeeded (same origin)
this.domFired = true;
this.isReset || obv.fireEvent.call(obv, 'domready', this);
}
this.domReady = true;
this.hideMask();
},
/**
* @private
* @param {String} eventName
*/
_onDocLoaded : function(eventName ){
var obv = this._observable, w;
this.domReady || this._onDocReady('domready');
obv.fireEvent("_docload", this); //invoke any callbacks
this.isReset || obv.fireEvent("documentloaded", this);
this.hideMask(true);
this._frameAction = this.isReset = false;
},
/**
* @private
* Poll the Iframes document structure to determine DOM ready
* state, and raise the 'domready' event when applicable.
*/
checkDOM : function( win) {
if ( Ext.isGecko ) { return; }
// initialise the counter
var n = 0, frame = this, domReady = false,
b, l, d,
max = this.domReadyRetries || 2500, //default max 5 seconds
polling = false,
startLocation = (this.getFrameDocument() || {location : {}}).location.href;
(function() { // DOM polling for IE and others
d = frame.getFrameDocument() || {location : {}};
// wait for location.href transition
polling = (d.location.href !== startLocation || d.location.href === frame._targetURI);
if ( frame.domReady) { return;}
domReady = polling && ((b = frame.getBody()) && !!(b.dom.innerHTML || '').length) || false;
// null href is a 'same-origin' document access violation,
// so we assume the DOM is built when the browser updates it
if (d.location.href && !domReady && (++n < max)) {
setTimeout(arguments.callee, 2); // try again
return;
}
frame.loadHandler({ type : domReady ? 'domready' : 'domfail'});
})();
},
/**
* @private
*/
filterEventOptionsRe: /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/,
/**
* @private override to handle synthetic events vs DOM events
*/
addListener : function(eventName, fn, scope, options){
if(typeof eventName == "object"){
var o = eventName;
for(var e in o){
if(this.filterEventOptionsRe.test(e)){
continue;
}
if(typeof o[e] == "function"){
// shared options
this.addListener(e, o[e], o.scope, o);
}else{
// individual options
this.addListener(e, o[e].fn, o[e].scope, o[e]);
}
}
return;
}
if(reSynthEvents.test(eventName)){
var O = this._observable;
if(O){
O.events[eventName] || (O.addEvents(eventName));
O.addListener.call(O, eventName, fn, scope || this, options) ;}
}else {
ElFrame.superclass.addListener.call(this, eventName,
fn, scope || this, options);
}
return this;
},
/**
* @private override
* Removes an event handler from this element.
*/
removeListener : function(eventName, fn, scope){
var O = this._observable;
if(reSynthEvents.test(eventName)){
O && O.removeListener.call(O, eventName, fn, scope || this, options);
}else {
ElFrame.superclass.removeListener.call(this, eventName, fn, scope || this);
}
return this;
},
/**
* Removes all previous added listeners from this element
* @private override
*/
removeAllListeners : function(){
Ext.EventManager.removeAll(this.dom);
var O = this._observable;
O && O.purgeListeners.call(this._observable);
return this;
},
/**
* Forcefully show the defined loadMask
* @param {String} msg Mask text to display during the mask operation, defaults to previous defined
* loadMask config value.
* @param {String} msgCls The CSS class to apply to the loading message element (defaults to "x-mask-loading")
* @param {String} maskCls The CSS class to apply to the mask element
*/
showMask : function(msg, msgCls, maskCls) {
var lmask = this.loadMask;
if (lmask && !lmask.disabled ){
this.mask(msg || lmask.msg, msgCls || lmask.msgCls, maskCls || lmask.maskCls, lmask.maskEl);
}
},
/**
* Hide the defined loadMask
* @param {Boolean} forced True to hide the mask regardless of document ready/loaded state.
*/
hideMask : function(forced) {
var tlm = this.loadMask || {};
if (forced || (tlm.hideOnReady && this.domReady)) {
this.unmask();
}
},
/**
* Puts a mask over the FRAME to disable user interaction. Requires core.css.
* @param {String} msg (optional) A message to display in the mask
* @param {String} msgCls (optional) A css class to apply to the msg element
* @param {String} maskCls (optional) A css class to apply to the mask element
* @param {String/Element} maskEl (optional) A targeted Element (parent of the IFRAME) to use the masking agent
* @return {Element} The mask element
*/
mask : function(msg, msgCls, maskCls, maskEl){
this._mask && this.unmask();
var p = Ext.get(maskEl) || this.parent('.ux-mif-mask-target') || this.parent();
if(p.getStyle("position") == "static" &&
!p.select('iframe,frame,object,embed').elements.length){
p.addClass("x-masked-relative");
}
p.addClass("x-masked");
this._mask = Ext.DomHelper.append(p, {cls: maskCls || "ux-mif-el-mask"} , true);
this._mask.setDisplayed(true);
this._mask._agent = p;
if(typeof msg == 'string'){
this._maskMsg = Ext.DomHelper.append(p, {cls: msgCls || "ux-mif-el-mask-msg" , style: {visibility:'hidden'}, cn:{tag:'div', html:msg}}, true);
this._maskMsg
.setVisibilityMode(Ext.Element.VISIBILITY)
.center(p).setVisible(true);
}
if(Ext.isIE && !(Ext.isIE7 && Ext.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
this._mask.setSize(undefined, this._mask.getHeight());
}
return this._mask;
},
/**
* Removes a previously applied mask.
*/
unmask : function(){
var a;
if(this._mask){
(a = this._mask._agent) && a.removeClass(["x-masked-relative","x-masked"]);
if(this._maskMsg){
this._maskMsg.remove();
delete this._maskMsg;
}
this._mask.remove();
delete this._mask;
}
},
/**
* Creates an (frontal) transparent shim agent for the frame. Used primarily for masking the frame during drag operations.
* @return {Ext.Element} The new shim element.
* @param {String} imgUrl Optional Url of image source to use during shimming (defaults to Ext.BLANK_IMAGE_URL).
* @param {String} shimCls Optional CSS style selector for the shimming agent. (defaults to 'ux-mif-shim' ).
* @return (HTMLElement} the shim element
*/
createFrameShim : function(imgUrl, shimCls ){
this.shimCls = shimCls || this.shimCls || 'ux-mif-shim';
this.frameShim || (this.frameShim = this.next('.'+this.shimCls) || //already there ?
Ext.DomHelper.append(
this.dom.parentNode,{
tag : 'img',
src : imgUrl|| Ext.BLANK_IMAGE_URL,
cls : this.shimCls ,
galleryimg : "no"
}, true)) ;
this.frameShim && (this.frameShim.autoBoxAdjust = false);
return this.frameShim;
},
/**
* Toggles visibility of the (frontal) transparent shim agent for the frame. Used primarily for masking the frame during drag operations.
* @param {Boolean} show Optional True to activate the shim, false to hide the shim agent.
*/
toggleShim : function(show){
var shim = this.frameShim || this.createFrameShim();
var cls = this.shimCls + '-on';
!show && shim.removeClass(cls);
show && !shim.hasClass(cls) && shim.addClass(cls);
},
/**
* Loads this panel's iframe immediately with content returned from an XHR call.
* @param {Object/String/Function} config A config object containing any of the following options:
* <pre><code>
* frame.load({
* url: "your-url.php",
* params: {param1: "foo", param2: "bar"}, // or encoded string
* callback: yourFunction,
* scope: yourObject, // optional scope for the callback
* discardUrl: false,
* nocache: false,
* text: "Loading...",
* timeout: 30,
* scripts: false,
* //optional custom renderer
* renderer:{render:function(el, response, updater, callback){....}}
* });
* </code></pre>
* The only required property is url. The optional properties
* nocache, text and scripts are shorthand for
* disableCaching, indicatorText and loadScripts and are used
* to set their associated property on this panel Updater
* instance.
* @return {Ext.ManagedIFrame.Element} this
*/
load : function(loadCfg) {
var um;
if (um = this.getUpdater()) {
if (loadCfg && loadCfg.renderer) {
um.setRenderer(loadCfg.renderer);
delete loadCfg.renderer;
}
um.update.apply(um, arguments);
}
return this;
},
/** @private
* Frame document event proxy
*/
_eventProxy : function(e) {
if (!e) return;
e = Ext.EventObject.setEvent(e);
var be = e.browserEvent || e, er, args = [e.type, this];
if (!be['eventPhase']
|| (be['eventPhase'] == (be['AT_TARGET'] || 2))) {
if(e.type == 'resize'){
var doc = this.getFrameDocument();
doc && (args.push(
{ height: ELD.getDocumentHeight(doc), width : ELD.getDocumentWidth(doc) },
{ height: ELD.getViewportHeight(doc), width : ELD.getViewportWidth(doc) },
{ height: ELD.getViewHeight(false, doc), width : ELD.getViewWidth(false, doc) }
));
}
er = this._observable ?
this._observable.fireEvent.apply(this._observable, args.concat(
Array.prototype.slice.call(arguments,0)))
: null;
// same-domain unloads should clear ElCache for use with the
// next document rendering
(e.type == 'unload') && this._unHook();
}
return er;
},
/**
* dispatch a message to the embedded frame-window context (same-origin frames only)
* @name sendMessage
* @param {Mixed} message The message payload. The payload can be any supported JS type.
* @param {String} tag Optional reference tag
* @param {String} origin Optional domain designation of the sender (defaults
* to document.domain).
*/
sendMessage : function(message, tag, origin) {
//(implemented by mifmsg.js )
},
/**
* Dispatch a cross-document message (per HTML5 specification) if the browser supports it natively.
* @name postMessage
* @param {String} message Required message payload (String only)
* @param {String} origin (Optional) Site designation of the sender (defaults
* to the current site in the form: http://site.example.com ).
* <p>Notes: on IE8, this action is synchronous.<br/>
* Messaging support requires that the optional messaging driver source
* file (mifmsg.js) is also included in your project.
*
*/
postMessage : function(message ,origin ){
//(implemented by mifmsg.js )
}
});
ElFrame = Ext.Element.IFRAME = Ext.Element.FRAME = Ext.ux.ManagedIFrame.Element;
var fp = ElFrame.prototype;
/**
* @ignore
*/
Ext.override ( ElFrame , {
/**
* Appends an event handler (shorthand for {@link #addListener}).
* @param {String} eventName The type of event to handle
* @param {Function} fn The handler function the event invokes
* @param {Object} scope (optional) The scope (this element) of the handler function
* @param {Object} options (optional) An object containing standard {@link #addListener} options
* @member Ext.Element
* @method on
*/
on : fp.addListener,
/**
* Removes an event handler from this element (shorthand for {@link #removeListener}).
* @param {String} eventName the type of event to remove
* @param {Function} fn the method the event invokes
* @return {MIF.Element} this
* @member Ext.Element
* @method un
*/
un : fp.removeListener,
getUpdateManager : fp.getUpdater
});
/**
* @class Ext.ux.ManagedIFrame.ComponentAdapter
* @version 2.1.3
* @author Doug Hendricks. doug[always-At]theactivegroup.com
* @donate <a target="tag_donate" href="http://donate.theactivegroup.com"><img border="0" src="http://www.paypal.com/en_US/i/btn/x-click-butcc-donate.gif" border="0" alt="Make a donation to support ongoing development"></a>
* @copyright 2007-2010, Active Group, Inc. All rights reserved.
* @license <a href="http://www.gnu.org/licenses/gpl.html">GPL 3.0</a>
* @constructor
* @desc
* Abstract class. This class should not be instantiated.
*/
Ext.ux.ManagedIFrame.ComponentAdapter = function(){};
Ext.ux.ManagedIFrame.ComponentAdapter.prototype = {
/** @property */
version : 2.12,
/**
* @cfg {String} defaultSrc the default src property assigned to the Managed Frame when the component is rendered.
* @default null
*/
defaultSrc : null,
/**
* @cfg {String} unsupportedText Text to display when the IFRAMES/FRAMESETS are disabled by the browser.
*
*/
unsupportedText : 'Inline frames are NOT enabled\/supported by your browser.',
hideMode : !Ext.isIE && !!Ext.ux.plugin.VisibilityMode ? 'nosize' : 'display',
animCollapse : Ext.isIE ,
animFloat : Ext.isIE ,
/**
* @cfg {Boolean} disableMessaging False to enable cross-frame messaging API
* @default true
*
*/
disableMessaging : true,
/**
* @cfg {Boolean} eventsFollowFrameLinks set true to propagate domready and documentloaded
* events anytime the IFRAME's URL changes
* @default true
*/
eventsFollowFrameLinks : true,
/**
* @cfg {object} frameConfig Frames DOM configuration options
* This optional configuration permits override of the IFRAME's DOM attributes
* @example
frameConfig : {
name : 'framePreview',
frameborder : 1,
allowtransparency : true
}
*/
frameConfig : null,
/**
* @cfg focusOnLoad True to set focus on the frame Window as soon as its document
* reports loaded. (Many external sites use IE's document.createRange to create
* DOM elements, but to be successfull IE requires that the FRAME have focus before
* the method is called)
* @default false (true for Internet Explorer)
*/
focusOnLoad : Ext.isIE,
/**
* @property {Object} frameEl An {@link #Ext.ux.ManagedIFrame.Element} reference to rendered frame Element.
*/
frameEl : null,
/**
* @cfg {Boolean} useShim
* True to use to create a transparent shimming agent for use in masking the frame during
* drag operations.
* @default false
*/
useShim : false,
/**
* @cfg {Boolean} autoScroll
* True to use overflow:'auto' on the frame element and show scroll bars automatically when necessary,
* false to clip any overflowing content (defaults to true).
* @default true
*/
autoScroll: true,
/**
* @cfg {String/Object} autoLoad
* Loads this Components frame after the Component is rendered with content returned from an
* XHR call or optionally from a form submission. See {@link #Ext.ux.ManagedIFrame.ComponentAdapter-load} and {@link #Ext.ux.ManagedIFrame.ComponentAdapter-submitAsTarget} methods for
* available configuration options.
* @default null
*/
autoLoad: null,
/** @private */
getId : function(){
return this.id || (this.id = "mif-comp-" + (++Ext.Component.AUTO_ID));
},
stateEvents : ['documentloaded'],
stateful : false,
/**
* Sets the autoScroll state for the frame.
* @param {Boolean} auto True to set overflow:auto on the frame, false for overflow:hidden
* @return {Ext.ux.ManagedIFrame.Component} this
*/
setAutoScroll : function(auto){
var scroll = Ext.value(auto, this.autoScroll === true);
this.rendered && this.getFrame() &&
this.frameEl.setOverflow( (this.autoScroll = scroll) ? 'auto':'hidden');
return this;
},
getContentTarget : function(){
return this.getFrame();
},
/**
* Returns the Ext.ux.ManagedIFrame.Element of the frame.
* @return {Ext.ux.ManagedIFrame.Element} this.frameEl
*/
getFrame : function(){
if(this.rendered){
if(this.frameEl){ return this.frameEl;}
var f = this.items && this.items.first ? this.items.first() : null;
f && (this.frameEl = f.frameEl);
return this.frameEl;
}
return null;
},
/**
* Returns the frame's current window object.
*
* @return {Window} The frame Window object.
*/
getFrameWindow : function() {
return this.getFrame() ? this.frameEl.getWindow() : null;
},
/**
* If sufficient privilege exists, returns the frame's current document
* as an HTMLElement.
*
* @return {HTMLElement} The frame document or false if access to
* document object was denied.
*/
getFrameDocument : function() {
return this.getFrame() ? this.frameEl.getFrameDocument() : null;
},
/**
* Get the embedded iframe's document as an Ext.Element.
*
* @return {Ext.Element object} or null if unavailable
*/
getFrameDoc : function() {
return this.getFrame() ? this.frameEl.getDoc() : null;
},
/**
* If sufficient privilege exists, returns the frame's current document
* body as an HTMLElement.
*
* @return {Ext.Element} The frame document body or Null if access to
* document object was denied.
*/
getFrameBody : function() {
return this.getFrame() ? this.frameEl.getBody() : null;
},
/**
* Reset the embedded frame to a neutral domain state and clear its contents
* @param {String}src (Optional) A specific reset string (eg. 'about:blank')
* to use for resetting the frame.
* @param {Function} callback (Optional) A callback function invoked when the
* frame reset is complete.
* @param {Object} scope (Optional) scope by which the callback function is
* invoked.
* @return {Ext.ux.ManagedIFrame.Component} this
*/
resetFrame : function() {
this.getFrame() && this.frameEl.reset.apply(this.frameEl, arguments);
return this;
},
/**
* Loads the Components frame with the response from a form submit to the
* specified URL with the ManagedIframe.Element as it's submit target.
* @param {Object} submitCfg A config object containing any of the following options:
* <pre><code>
* mifPanel.submitAsTarget({
* form : formPanel.form, //optional Ext.FormPanel, Ext form element, or HTMLFormElement
* url: "your-url.php",
* params: {param1: "foo", param2: "bar"}, // or a URL encoded string
* callback: yourFunction, //optional
* scope: yourObject, // optional scope for the callback
* method: 'POST', //optional form.action (default:'POST')
* encoding : "multipart/form-data" //optional, default HTMLForm default
* });
*
* </code></pre>
*
* @return {Ext.ux.ManagedIFrame.Component} this
*/
submitAsTarget : function(submitCfg){
this.getFrame() && this.frameEl.submitAsTarget.apply(this.frameEl, arguments);
return this;
},
/**
* Loads this Components's frame immediately with content returned from an
* XHR call.
*
* @param {Object/String/Function} loadCfg A config object containing any of the following
* options:
*
* <pre><code>
* mifPanel.load({
* url: "your-url.php",
* params: {param1: "foo", param2: "bar"}, // or a URL encoded string
* callback: yourFunction,
* scope: yourObject, // optional scope for the callback
* discardUrl: false,
* nocache: false,
* text: "Loading...",
* timeout: 30,
* scripts: false,
* submitAsTarget : false, //optional true, to use Form submit to load the frame (see submitAsTarget method)
* renderer:{render:function(el, response, updater, callback){....}} //optional custom renderer
* });
*
* </code></pre>
*
* The only required property is url. The optional properties
* nocache, text and scripts are shorthand for
* disableCaching, indicatorText and loadScripts and are used
* to set their associated property on this panel Updater
* instance.
* @return {Ext.ux.ManagedIFrame.Component} this
*/
load : function(loadCfg) {
if(loadCfg && this.getFrame()){
var args = arguments;
this.resetFrame(null, function(){
loadCfg.submitAsTarget ?
this.submitAsTarget.apply(this,args):
this.frameEl.load.apply(this.frameEl,args);
},this);
}
this.autoLoad = loadCfg;
return this;
},
/** @private */
doAutoLoad : function() {
this.autoLoad && this.load(typeof this.autoLoad == 'object' ?
this.autoLoad : { url : this.autoLoad });
},
/**
* Get the {@link #Ext.ux.ManagedIFrame.Updater} for this panel's iframe. Enables
* Ajax-based document replacement of this panel's iframe document.
*
* @return {Ext.ux.ManagedIFrame.Updater} The Updater
*/
getUpdater : function() {
return this.getFrame() ? this.frameEl.getUpdater() : null;
},
/**
* Sets the embedded Iframe src property. Note: invoke the function with
* no arguments to refresh the iframe based on the current src value.
*
* @param {String/Function} url (Optional) A string or reference to a Function that
* returns a URI string when called
* @param {Boolean} discardUrl (Optional) If not passed as <tt>false</tt>
* the URL of this action becomes the default SRC attribute
* for this iframe, and will be subsequently used in future
* setSrc calls (emulates autoRefresh by calling setSrc
* without params).
* @param {Function} callback (Optional) A callback function invoked when the
* frame document has been fully loaded.
* @param {Object} scope (Optional) scope by which the callback function is
* invoked.
* @return {Ext.ux.ManagedIFrame.Component} this
*/
setSrc : function(url, discardUrl, callback, scope) {
this.getFrame() && this.frameEl.setSrc.apply(this.frameEl, arguments);
return this;
},
/**
* Sets the embedded Iframe location using its replace method. Note: invoke the function with
* no arguments to refresh the iframe based on the current src value.
*
* @param {String/Function} url (Optional) A string or reference to a Function that
* returns a URI string when called
* @param {Boolean} discardUrl (Optional) If not passed as <tt>false</tt>
* the URL of this action becomes the default SRC attribute
* for this iframe, and will be subsequently used in future
* setSrc calls (emulates autoRefresh by calling setSrc
* without params).
* @param {Function} callback (Optional) A callback function invoked when the
* frame document has been fully loaded.
* @param {Object} scope (Optional) scope by which the callback function is
* invoked.
* @return {Ext.ux.ManagedIFrame.Component} this
*/
setLocation : function(url, discardUrl, callback, scope) {
this.getFrame() && this.frameEl.setLocation.apply(this.frameEl, arguments);
return this;
},
/**
* @private //Make it state-aware
*/
getState : function() {
var URI = this.getFrame() ? this.frameEl.getDocumentURI() || null : null;
var state = this.supr().getState.call(this);
state = Ext.apply(state || {},
{defaultSrc : Ext.isFunction(URI) ? URI() : URI,
autoLoad : this.autoLoad
});
return state;
},
/**
* @private
*/
setMIFEvents : function(){
this.addEvents(
/**
* Fires when the iFrame has reached a loaded/complete state.
* @event documentloaded
* @memberOf Ext.ux.ManagedIFrame.ComponentAdapter
* @param {Ext.ux.ManagedIFrame.Element} frameEl
*/
'documentloaded',
/**
* Fires ONLY when an iFrame's Document(DOM) has reach a
* state where the DOM may be manipulated (ie same domain policy)
* Note: This event is only available when overwriting the iframe
* document using the update method and to pages retrieved from a "same
* domain". Returning false from the eventHandler stops further event
* (documentloaded) processing.
* @event domready
* @memberOf Ext.ux.ManagedIFrame.ComponentAdapter
* @param {Ext.ux.ManagedIFrame.Element} this.frameEl
*/
'domready',
/**
* Fires when the frame actions raise an error
* @event exception
* @memberOf Ext.ux.ManagedIFrame.ComponentAdapter
* @param {Ext.ux.MIF.Element} frameEl
* @param {Error/string} exception
*/
'exception',
/**
* Fires upon receipt of a message generated by window.sendMessage
* method of the embedded Iframe.window object
* @event message
* @memberOf Ext.ux.ManagedIFrame.ComponentAdapter
* @param {Ext.ux.ManagedIFrame.Element} this.frameEl
* @param {object}
* message (members: type: {string} literal "message", data
* {Mixed} [the message payload], domain [the document domain
* from which the message originated ], uri {string} the
* document URI of the message sender source (Object) the
* window context of the message sender tag {string} optional
* reference tag sent by the message sender
* <p>Alternate event handler syntax for message:tag filtering Fires upon
* receipt of a message generated by window.sendMessage method which
* includes a specific tag value of the embedded Iframe.window object
*
*/
'message',
/**
* Fires when the frame is blurred (loses focus).
* @event blur
* @memberOf Ext.ux.ManagedIFrame.ComponentAdapter
* @param {Ext.ux.ManagedIFrame.Element} frameEl
* @param {Ext.Event} e Note: This event is only available when overwriting the
* iframe document using the update method and to pages
* retrieved from a "same domain". Returning false from the
* eventHandler [MAY] NOT cancel the event, as this event is
* NOT ALWAYS cancellable in all browsers.
*/
'blur',
/**
* Fires when the frame gets focus. Note: This event is only available
* when overwriting the iframe document using the update method and to
* pages retrieved from a "same domain". Returning false from the
* eventHandler [MAY] NOT cancel the event, as this event is NOT ALWAYS
* cancellable in all browsers.
* @event focus
* @memberOf Ext.ux.ManagedIFrame.ComponentAdapter
* @param {Ext.ux.ManagedIFrame.Element} frameEl
* @param {Ext.Event} e
*
*/
'focus',
/**
* Note: This event is only available when overwriting the iframe
* document using the update method and to pages retrieved from a "same-origin"
* domain. To prevent numerous scroll events from being raised use the <i>buffer</i> listener
* option to limit the number of times the event is raised.
* @event scroll
* @param {Ext.ux.MIF.Element} this.
* @param {Ext.Event}
*/
'scroll',
/**
* Fires when the frames window is resized. Note: This event is only available
* when overwriting the iframe document using the update method and to
* pages retrieved from a "same domain".
* @event resize
* @memberOf Ext.ux.ManagedIFrame.ComponentAdapter
* @param {Ext.ux.ManagedIFrame.Element} frameEl
* @param {Ext.Event} e
* @param {Object} documentSize A height/width object signifying the new document size
* @param {Object} viewPortSize A height/width object signifying the size of the frame's viewport
* @param {Object} viewSize A height/width object signifying the size of the frame's view
*
*/
'resize',
/**
* Fires when(if) the frames window object raises the unload event
* Note: This event is only available when overwriting the iframe
* document using the update method and to pages retrieved from a "same-origin"
* domain. Note: Opera does not raise this event.
* @event unload
* @memberOf Ext.ux.ManagedIFrame.ComponentAdapter
* @param {Ext.ux.ManagedIFrame.Element} frameEl
* @param {Ext.Event}
*/
'unload',
/**
* Fires when the iFrame has been reset to a neutral domain state (blank document).
* @event reset
* @param {Ext.ux.ManagedIFrame.Element} frameEl
*/
'reset'
);
},
/**
* dispatch a message to the embedded frame-window context (same-origin frames only)
* @name sendMessage
* @memberOf Ext.ux.ManagedIFrame.Element
* @param {Mixed} message The message payload. The payload can be any supported JS type.
* @param {String} tag Optional reference tag
* @param {String} origin Optional domain designation of the sender (defaults
* to document.domain).
*/
sendMessage : function(message, tag, origin) {
//(implemented by mifmsg.js )
},
//Suspend (and queue) host container events until the child MIF.Component is rendered.
onAdd : function(C){
C.relayTarget && this.suspendEvents(true);
},
initRef: function() {
if(this.ref){
var t = this,
levels = this.ref.split('/'),
l = levels.length,
i;
for (i = 0; i < l; i++) {
if(t.ownerCt){
t = t.ownerCt;
}
}
this.refName = levels[--i];
t[this.refName] || (t[this.refName] = this);
this.refOwner = t;
}
}
};
/*
* end Adapter
*/
/**
* @class Ext.ux.ManagedIFrame.Component
* @extends Ext.BoxComponent
* @version 2.1.3
* @author Doug Hendricks. doug[always-At]theactivegroup.com
* @donate <a target="tag_donate" href="http://donate.theactivegroup.com"><img border="0" src="http://www.paypal.com/en_US/i/btn/x-click-butcc-donate.gif" border="0" alt="Make a donation to support ongoing development"></a>
* @copyright 2007-2010, Active Group, Inc. All rights reserved.
* @license <a href="http://www.gnu.org/licenses/gpl.html">GPL 3.0</a>
* @constructor
* @base Ext.ux.ManagedIFrame.ComponentAdapter
* @param {Object} config The config object
*/
Ext.ux.ManagedIFrame.Component = Ext.extend(Ext.BoxComponent , {
ctype : "Ext.ux.ManagedIFrame.Component",
/** @private */
initComponent : function() {
var C = {
monitorResize : this.monitorResize || (this.monitorResize = !!this.fitToParent),
plugins : (this.plugins ||[]).concat(
this.hideMode === 'nosize' && Ext.ux.plugin.VisibilityMode ?
[new Ext.ux.plugin.VisibilityMode(
{hideMode :'nosize',
elements : ['bwrap']
})] : [] )
};
MIF.Component.superclass.initComponent.call(
Ext.apply(this,
Ext.apply(this.initialConfig, C)
));
this.setMIFEvents();
},
/** @private */
onRender : function(ct, position){
//default child frame's name to that of MIF-parent id (if not specified on frameCfg).
var frCfg = this.frameCfg || this.frameConfig || (this.relayTarget ? {name : this.relayTarget.id}: {}) || {};
//backward compatability with MIF 1.x
var frDOM = frCfg.autoCreate || frCfg;
frDOM = Ext.apply({tag : 'iframe', id: Ext.id()}, frDOM);
var el = Ext.getDom(this.el);
(el && el.tagName == 'iframe') ||
(this.autoEl = Ext.apply({
name : frDOM.id,
frameborder : 0
}, frDOM ));
MIF.Component.superclass.onRender.apply(this, arguments);
if(this.unsupportedText){
ct.child('noframes') || ct.createChild({tag: 'noframes', html : this.unsupportedText || null});
}
var frame = this.el ;
var F;
if( F = this.frameEl = (this.el ? new MIF.Element(this.el.dom, true): null)){
Ext.apply(F,{
ownerCt : this.relayTarget || this,
disableMessaging : Ext.value(this.disableMessaging, true),
focusOnLoad : Ext.value(this.focusOnLoad, Ext.isIE),
eventsFollowFrameLinks : Ext.value(this.eventsFollowFrameLinks ,true)
});
F.ownerCt.frameEl = F;
F.addClass('ux-mif');
if (this.loadMask) {
//resolve possible maskEl by Element name eg. 'body', 'bwrap', 'actionEl'
var mEl = this.loadMask.maskEl;
F.loadMask = Ext.apply({
disabled : false,
hideOnReady : false,
msgCls : 'ext-el-mask-msg x-mask-loading',
maskCls : 'ext-el-mask'
},
{
maskEl : F.ownerCt[String(mEl)] || F.parent('.' + String(mEl)) || F.parent('.ux-mif-mask-target') || mEl
},
Ext.isString(this.loadMask) ? {msg:this.loadMask} : this.loadMask
);
Ext.get(F.loadMask.maskEl) && Ext.get(F.loadMask.maskEl).addClass('ux-mif-mask-target');
}
F._observable &&
(this.relayTarget || this).relayEvents(F._observable, frameEvents.concat(this._msgTagHandlers || []));
delete this.contentEl;
}
},
/** @private */
afterRender : function(container) {
MIF.Component.superclass.afterRender.apply(this,arguments);
// only resize (to Parent) if the panel is NOT in a layout.
// parentNode should have {style:overflow:hidden;} applied.
if (this.fitToParent && !this.ownerCt) {
var pos = this.getPosition(), size = (Ext.get(this.fitToParent)
|| this.getEl().parent()).getViewSize();
this.setSize(size.width - pos[0], size.height - pos[1]);
}
this.getEl().setOverflow('hidden'); //disable competing scrollers
this.setAutoScroll();
var F;
/* Enable auto-Shims if the Component participates in (nested?)
* border layout.
* Setup event handlers on the SplitBars and region panels to enable the frame
* shims when needed
*/
if(F = this.frameEl){
var ownerCt = this.ownerCt;
while (ownerCt) {
ownerCt.on('afterlayout', function(container, layout) {
Ext.each(['north', 'south', 'east', 'west'],
function(region) {
var reg;
if ((reg = layout[region]) &&
reg.split && reg.split.dd &&
!reg._splitTrapped) {
reg.split.dd.endDrag = reg.split.dd.endDrag.createSequence(MIM.hideShims, MIM );
reg.split.on('beforeresize',MIM.showShims,MIM);
reg._splitTrapped = MIM._splitTrapped = true;
}
}, this);
}, this, { single : true}); // and discard
ownerCt = ownerCt.ownerCt; // nested layouts?
}
/*
* Create an img shim if the component participates in a layout or forced
*/
if(!!this.ownerCt || this.useShim ){ this.frameShim = F.createFrameShim(); }
this.getUpdater().showLoadIndicator = this.showLoadIndicator || false;
//Resume Parent containers' events
var resumeEvents = this.relayTarget && this.ownerCt ?
this.ownerCt.resumeEvents.createDelegate(this.ownerCt) : null;
if(this.autoload){
this.doAutoLoad();
} else if(this.frameMarkup || this.html) {
F.update(this.frameMarkup || this.html, true, resumeEvents);
delete this.html;
delete this.frameMarkup;
return;
}else{
if(this.defaultSrc){
F.setSrc(this.defaultSrc, false);
}else{
/* If this is a no-action frame, reset it first, then resume parent events
* allowing access to a fully reset frame by upstream afterrender/layout events
*/
F.reset(null, resumeEvents);
return;
}
}
resumeEvents && resumeEvents();
}
},
/** @private */
beforeDestroy : function() {
var F;
if(F = this.getFrame()){
F.remove();
this.frameEl = this.frameShim = null;
}
this.relayTarget && (this.relayTarget.frameEl = null);
MIF.Component.superclass.beforeDestroy.call(this);
}
});
Ext.override(MIF.Component, MIF.ComponentAdapter.prototype);
Ext.reg('mif', MIF.Component);
/*
* end Component
*/
/**
* @private
* this function renders a child MIF.Component to MIF.Panel and MIF.Window
* designed to be called by the constructor of higher-level MIF.Components only.
*/
function embed_MIF(config){
config || (config={});
config.layout = 'fit';
config.items = {
xtype : 'mif',
ref : 'mifChild',
useShim : true,
autoScroll : Ext.value(config.autoScroll , this.autoScroll),
defaultSrc : Ext.value(config.defaultSrc , this.defaultSrc),
frameMarkup : Ext.value(config.html , this.html),
loadMask : Ext.value(config.loadMask , this.loadMask),
disableMessaging : Ext.value(config.disableMessaging, this.disableMessaging),
eventsFollowFrameLinks : Ext.value(config.eventsFollowFrameLinks, this.eventsFollowFrameLinks),
focusOnLoad : Ext.value(config.focusOnLoad, this.focusOnLoad),
frameConfig : Ext.value(config.frameConfig || config.frameCfg , this.frameConfig),
relayTarget : this //direct relay of events to the parent component
};
delete config.html;
this.setMIFEvents();
return config;
};
/**
* @class Ext.ux.ManagedIFrame.Panel
* @extends Ext.Panel
* @version 2.1.3
* @author Doug Hendricks. doug[always-At]theactivegroup.com
* @donate <a target="tag_donate" href="http://donate.theactivegroup.com"><img border="0" src="http://www.paypal.com/en_US/i/btn/x-click-butcc-donate.gif" border="0" alt="Make a donation to support ongoing development"></a>
* @copyright 2007-2010, Active Group, Inc. All rights reserved.
* @license <a href="http://www.gnu.org/licenses/gpl.html">GPL 3.0</a>
* @constructor
* @base Ext.ux.ManagedIFrame.ComponentAdapter
* @param {Object} config The config object
*/
Ext.ux.ManagedIFrame.Panel = Ext.extend( Ext.Panel , {
ctype : 'Ext.ux.ManagedIFrame.Panel',
bodyCssClass: 'ux-mif-mask-target',
constructor : function(config){
MIF.Panel.superclass.constructor.call(this, embed_MIF.call(this, config));
}
});
Ext.override(MIF.Panel, MIF.ComponentAdapter.prototype);
Ext.reg('iframepanel', MIF.Panel);
/*
* end Panel
*/
/**
* @class Ext.ux.ManagedIFrame.Portlet
* @extends Ext.ux.ManagedIFrame.Panel
* @version 2.1.3
* @donate <a target="tag_donate" href="http://donate.theactivegroup.com"><img border="0" src="http://www.paypal.com/en_US/i/btn/x-click-butcc-donate.gif" border="0" alt="Make a donation to support ongoing development"></a>
* @license <a href="http://www.gnu.org/licenses/gpl.html">GPL 3.0</a>
* @author Doug Hendricks. Forum ID: <a href="http://extjs.com/forum/member.php?u=8730">hendricd</a>
* @copyright 2007-2010, Active Group, Inc. All rights reserved.
* @constructor Create a new Ext.ux.ManagedIFramePortlet
* @param {Object} config The config object
*/
Ext.ux.ManagedIFrame.Portlet = Ext.extend(Ext.ux.ManagedIFrame.Panel, {
ctype : "Ext.ux.ManagedIFrame.Portlet",
anchor : '100%',
frame : true,
collapseEl : 'bwrap',
collapsible: true,
draggable : true,
cls : 'x-portlet'
});
Ext.reg('iframeportlet', MIF.Portlet);
/*
* end Portlet
*/
/**
* @class Ext.ux.ManagedIFrame.Window
* @extends Ext.Window
* @version 2.1.3
* @author Doug Hendricks.
* @donate <a target="tag_donate" href="http://donate.theactivegroup.com"><img border="0" src="http://www.paypal.com/en_US/i/btn/x-click-butcc-donate.gif" border="0" alt="Make a donation to support ongoing development"></a>
* @copyright 2007-2010, Active Group, Inc. All rights reserved.
* @license <a href="http://www.gnu.org/licenses/gpl.html">GPL 3.0</a>
* @constructor
* @base Ext.ux.ManagedIFrame.ComponentAdapter
* @param {Object} config The config object
*/
Ext.ux.ManagedIFrame.Window = Ext.extend( Ext.Window ,
{
ctype : "Ext.ux.ManagedIFrame.Window",
bodyCssClass: 'ux-mif-mask-target',
constructor : function(config){
MIF.Window.superclass.constructor.call(this, embed_MIF.call(this, config));
}
});
Ext.override(MIF.Window, MIF.ComponentAdapter.prototype);
Ext.reg('iframewindow', MIF.Window);
/*
* end Window
*/
/**
* @class Ext.ux.ManagedIFrame.Updater
* @extends Ext.Updater
* @version 2.1.3
* @donate <a target="tag_donate" href="http://donate.theactivegroup.com"><img border="0" src="http://www.paypal.com/en_US/i/btn/x-click-butcc-donate.gif" border="0" alt="Make a donation to support ongoing development"></a>
* @license <a href="http://www.gnu.org/licenses/gpl.html">GPL 3.0</a>
* @author Doug Hendricks. Forum ID: <a href="http://extjs.com/forum/member.php?u=8730">hendricd</a>
* @copyright 2007-2010, Active Group, Inc. All rights reserved.
* @constructor Creates a new Ext.ux.ManagedIFrame.Updater instance.
* @param {String/Object} el The element to bind the Updater instance to.
*/
Ext.ux.ManagedIFrame.Updater = Ext.extend(Ext.Updater, {
/**
* Display the element's "loading" state. By default, the element is updated with {@link #indicatorText}. This
* method may be overridden to perform a custom action while this Updater is actively updating its contents.
*/
showLoading : function(){
this.showLoadIndicator && this.el && this.el.mask(this.indicatorText);
},
/**
* Hide the Frames masking agent.
*/
hideLoading : function(){
this.showLoadIndicator && this.el && this.el.unmask();
},
// private
updateComplete : function(response){
MIF.Updater.superclass.updateComplete.apply(this,arguments);
this.hideLoading();
},
// private
processFailure : function(response){
MIF.Updater.superclass.processFailure.apply(this,arguments);
this.hideLoading();
}
});
var styleCamelRe = /(-[a-z])/gi;
var styleCamelFn = function(m, a) {
return a.charAt(1).toUpperCase();
};
/**
* @class Ext.ux.ManagedIFrame.CSS
* Stylesheet interface object
* @version 2.1.3
* @author Doug Hendricks. doug[always-At]theactivegroup.com
* @donate <a target="tag_donate" href="http://donate.theactivegroup.com"><img border="0" src="http://www.paypal.com/en_US/i/btn/x-click-butcc-donate.gif" border="0" alt="Make a donation to support ongoing development"></a>
* @copyright 2007-2010, Active Group, Inc. All rights reserved.
* @license <a href="http://www.gnu.org/licenses/gpl.html">GPL 3.0</a>
*/
Ext.ux.ManagedIFrame.CSS = function(hostDocument) {
var doc;
if (hostDocument) {
doc = hostDocument;
return {
rules : null,
/** @private */
destroy : function(){ return doc = null; },
/**
* Creates a stylesheet from a text blob of rules. These rules
* will be wrapped in a STYLE tag and appended to the HEAD of
* the document.
*
* @param {String}
* cssText The text containing the css rules
* @param {String} id An (optional) id to add to the stylesheet for later removal
* @return {StyleSheet}
*/
createStyleSheet : function(cssText, id) {
var ss;
if (!doc)return;
var head = doc.getElementsByTagName("head")[0];
var rules = doc.createElement("style");
rules.setAttribute("type", "text/css");
Ext.isString(id) && rules.setAttribute("id", id);
if (Ext.isIE) {
head.appendChild(rules);
ss = rules.styleSheet;
ss.cssText = cssText;
} else {
try {
rules.appendChild(doc.createTextNode(cssText));
} catch (e) {
rules.cssText = cssText;
}
head.appendChild(rules);
ss = rules.styleSheet
? rules.styleSheet
: (rules.sheet || doc.styleSheets[doc.styleSheets.length - 1]);
}
this.cacheStyleSheet(ss);
return ss;
},
/**
* Removes a style or link tag by id
*
* @param {String}
* id The id of the tag
*/
removeStyleSheet : function(id) {
if (!doc || !id)return;
var existing = doc.getElementById(id);
if (existing) {
existing.parentNode.removeChild(existing);
}
},
/**
* Dynamically swaps an existing stylesheet reference for a new
* one
*
* @param {String}
* id The id of an existing link tag to remove
* @param {String}
* url The href of the new stylesheet to include
*/
swapStyleSheet : function(id, url) {
if (!doc)return;
this.removeStyleSheet(id);
var ss = doc.createElement("link");
ss.setAttribute("rel", "stylesheet");
ss.setAttribute("type", "text/css");
Ext.isString(id) && ss.setAttribute("id", id);
ss.setAttribute("href", url);
doc.getElementsByTagName("head")[0].appendChild(ss);
},
/**
* Refresh the rule cache if you have dynamically added stylesheets
* @return {Object} An object (hash) of rules indexed by selector
*/
refreshCache : function() {
return this.getRules(true);
},
// private
cacheStyleSheet : function(ss, media) {
this.rules || (this.rules = {});
try{// try catch for cross domain access issue
Ext.each(ss.cssRules || ss.rules || [],
function(rule){
this.hashRule(rule, ss, media);
}, this);
//IE @imports
Ext.each(ss.imports || [],
function(sheet){
sheet && this.cacheStyleSheet(sheet,this.resolveMedia([sheet, sheet.parentStyleSheet]));
}
,this);
}catch(e){}
},
// @private
hashRule : function(rule, sheet, mediaOverride){
var mediaSelector = mediaOverride || this.resolveMedia(rule);
//W3C @media
if( rule.cssRules || rule.rules){
this.cacheStyleSheet(rule, this.resolveMedia([rule, rule.parentRule ]));
}
//W3C @imports
if(rule.styleSheet){
this.cacheStyleSheet(rule.styleSheet, this.resolveMedia([rule, rule.ownerRule, rule.parentStyleSheet]));
}
rule.selectorText &&
Ext.each((mediaSelector || '').split(','),
function(media){
this.rules[((media ? media.trim() + ':' : '') + rule.selectorText).toLowerCase()] = rule;
}, this);
},
/**
* @private
* @param {Object/Array} rule CSS Rule (or array of Rules/sheets) to evaluate media types.
* @return a comma-delimited string of media types.
*/
resolveMedia : function(rule){
var media;
Ext.each([].concat(rule),function(r){
if(r && r.media && r.media.length){
media = r.media;
return false;
}
});
return media ? (Ext.isIE ? String(media) : media.mediaText ) : '';
},
/**
* Gets all css rules for the document
*
* @param {Boolean}
* refreshCache true to refresh the internal cache
* @return {Object} An object (hash) of rules indexed by
* selector
*/
getRules : function(refreshCache) {
if (!this.rules || refreshCache) {
this.rules = {};
if (doc) {
var ds = doc.styleSheets;
for (var i = 0, len = ds.length; i < len; i++) {
try {
this.cacheStyleSheet(ds[i]);
} catch (e) {}
}
}
}
return this.rules;
},
/**
* Gets an an individual CSS rule by selector(s)
* @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
* @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
* @param {String} mediaSelector Name of optional CSS media context (eg. print, screen)
* @return {CSSRule} The CSS rule or null if one is not found
*/
getRule : function(selector, refreshCache, mediaSelector) {
var rs = this.getRules(refreshCache);
if(Ext.type(mediaSelector) == 'string'){
mediaSelector = mediaSelector.trim() + ':';
}else{
mediaSelector = '';
}
if(!Ext.isArray(selector)){
return rs[(mediaSelector + selector).toLowerCase()];
}
var select;
for(var i = 0; i < selector.length; i++){
select = (mediaSelector + selector[i]).toLowerCase();
if(rs[select]){
return rs[select];
}
}
return null;
},
/**
* Updates a rule property
* @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
* @param {String} property The css property
* @param {String} value The new value for the property
* @param {String} mediaSelector Name(s) of optional media contexts. Multiple may be specified, delimited by commas (eg. print,screen)
* @return {Boolean} true If a rule was found and updated
*/
updateRule : function(selector, property, value, mediaSelector){
Ext.each((mediaSelector || '').split(','), function(mediaSelect){
if(!Ext.isArray(selector)){
var rule = this.getRule(selector, false, mediaSelect);
if(rule){
rule.style[property.replace(camelRe, camelFn)] = value;
return true;
}
}else{
for(var i = 0; i < selector.length; i++){
if(this.updateRule(selector[i], property, value, mediaSelect)){
return true;
}
}
}
return false;
}, this);
}
};
}
};
/**
* @class Ext.ux.ManagedIFrame.Manager
* @version 2.1.3
* @author Doug Hendricks. doug[always-At]theactivegroup.com
* @donate <a target="tag_donate" href="http://donate.theactivegroup.com"><img border="0" src="http://www.paypal.com/en_US/i/btn/x-click-butcc-donate.gif" border="0" alt="Make a donation to support ongoing development"></a>
* @copyright 2007-2010, Active Group, Inc. All rights reserved.
* @license <a href="http://www.gnu.org/licenses/gpl.html">GPL 3.0</a>
* @singleton
*/
Ext.ux.ManagedIFrame.Manager = function() {
var frames = {};
var implementation = {
// private DOMFrameContentLoaded handler for browsers (Gecko, Webkit, Opera) that support it.
_DOMFrameReadyHandler : function(e) {
try {
var $frame ;
if ($frame = e.target.ownerCt){
$frame.loadHandler.call($frame,e);
}
} catch (rhEx) {} //nested iframes will throw when accessing target.id
},
/**
* @cfg {String} shimCls
* @default "ux-mif-shim"
* The default CSS rule applied to MIF image shims to toggle their visibility.
*/
shimCls : 'ux-mif-shim',
/** @private */
register : function(frame) {
frame.manager = this;
frames[frame.id] = frames[frame.name] = {ref : frame };
return frame;
},
/** @private */
deRegister : function(frame) {
delete frames[frame.id];
delete frames[frame.name];
},
/**
* Toggles the built-in MIF shim off on all visible MIFs
* @methodOf Ext.ux.MIF.Manager
*
*/
hideShims : function() {
var mm = MIF.Manager;
mm.shimsApplied && Ext.select('.' + mm.shimCls, true).removeClass(mm.shimCls+ '-on');
mm.shimsApplied = false;
},
/**
* Shim ALL MIFs (eg. when a region-layout.splitter is on the move or before start of a drag operation)
* @methodOf Ext.ux.MIF.Manager
*/
showShims : function() {
var mm = MIF.Manager;
!mm.shimsApplied && Ext.select('.' + mm.shimCls, true).addClass(mm.shimCls+ '-on');
mm.shimsApplied = true;
},
/**
* Retrieve a MIF instance by its DOM ID
* @methodOf Ext.ux.MIF.Manager
* @param {Ext.ux.MIF/string} id
*/
getFrameById : function(id) {
return typeof id == 'string' ? (frames[id] ? frames[id].ref
|| null : null) : null;
},
/**
* Retrieve a MIF instance by its DOM name
* @methodOf Ext.ux.MIF.Manager
* @param {Ext.ux.MIF/string} name
*/
getFrameByName : function(name) {
return this.getFrameById(name);
},
/** @private */
// retrieve the internal frameCache object
getFrameHash : function(frame) {
return frames[frame.id] || frames[frame.id] || null;
},
/** @private */
destroy : function() {
if (document.addEventListener && !Ext.isOpera) {
window.removeEventListener("DOMFrameContentLoaded", this._DOMFrameReadyHandler , false);
}
}
};
// for Gecko and any who might support it later
document.addEventListener && !Ext.isOpera &&
window.addEventListener("DOMFrameContentLoaded", implementation._DOMFrameReadyHandler , false);
Ext.EventManager.on(window, 'beforeunload', implementation.destroy, implementation);
return implementation;
}();
MIM = MIF.Manager;
MIM.showDragMask = MIM.showShims;
MIM.hideDragMask = MIM.hideShims;
/**
* Shim all MIF's during a Window drag operation.
*/
var winDD = Ext.Window.DD;
Ext.override(winDD, {
startDrag : winDD.prototype.startDrag.createInterceptor(MIM.showShims),
endDrag : winDD.prototype.endDrag.createInterceptor(MIM.hideShims)
});
//Previous release compatibility
Ext.ux.ManagedIFramePanel = MIF.Panel;
Ext.ux.ManagedIFramePortlet = MIF.Portlet;
Ext.ux.ManagedIframe = function(el,opt){
var args = Array.prototype.slice.call(arguments, 0),
el = Ext.get(args[0]),
config = args[0];
if (el && el.dom && el.dom.tagName == 'IFRAME') {
config = args[1] || {};
} else {
config = args[0] || args[1] || {};
el = config.autoCreate ? Ext.get(Ext.DomHelper.append(
config.autoCreate.parent || Ext.getBody(), Ext.apply({
tag : 'iframe',
frameborder : 0,
cls : 'x-mif',
src : (Ext.isIE && Ext.isSecure)? Ext.SSL_SECURE_URL: 'about:blank'
}, config.autoCreate)))
: null;
if(el && config.unsupportedText){
Ext.DomHelper.append(el.dom.parentNode, {tag:'noframes',html: config.unsupportedText } );
}
}
var mif = new MIF.Element(el,true);
if(mif){
Ext.apply(mif, {
disableMessaging : Ext.value(config.disableMessaging , true),
focusOnLoad : Ext.value(config.focusOnLoad , Ext.isIE),
eventsFollowFrameLinks : Ext.value(config.eventsFollowFrameLinks ,true),
loadMask : !!config.loadMask ? Ext.apply({
msg : 'Loading..',
msgCls : 'x-mask-loading',
maskEl : null,
hideOnReady : false,
disabled : false
}, config.loadMask) : false,
_windowContext : null
});
config.listeners && mif.on(config.listeners);
if(!!config.html){
mif.update(config.html);
} else {
!!config.src && mif.setSrc(config.src);
}
}
return mif;
};
/**
* Internal Error class for ManagedIFrame Components
* @class Ext.ux.ManagedIFrame.Error
* @extends Ext.Error
* @version 2.1.3
* @donate <a target="tag_donate" href="http://donate.theactivegroup.com"><img border="0" src="http://www.paypal.com/en_US/i/btn/x-click-butcc-donate.gif" border="0" alt="Make a donation to support ongoing development"></a>
* @license <a href="http://www.gnu.org/licenses/gpl.html">GPL 3.0</a>
* @author Doug Hendricks. Forum ID: <a href="http://extjs.com/forum/member.php?u=8730">hendricd</a>
* @copyright 2007-2010, Active Group, Inc. All rights reserved.
* @constructor
* @param {String} message
* @param {Mixed} arg optional argument to include in Error object.
*/
Ext.ux.ManagedIFrame.Error = Ext.extend(Ext.Error, {
constructor : function(message, arg) {
this.arg = arg;
Ext.Error.call(this, message);
},
name : 'Ext.ux.ManagedIFrame'
});
Ext.apply(Ext.ux.ManagedIFrame.Error.prototype, {
lang: {
'documentcontext-remove': 'An attempt was made to remove an Element from the wrong document context.',
'execscript-secure-context': 'An attempt was made at script execution within a document context with limited access permissions.',
'printexception': 'An Error was encountered attempting the print the frame contents (document access is likely restricted).'
}
});
/** @private */
Ext.onReady(function() {
// Generate CSS Rules but allow for overrides.
var CSS = new Ext.ux.ManagedIFrame.CSS(document), rules = [];
CSS.getRule('.ux-mif-fill')|| (rules.push('.ux-mif-fill{height:100%;width:100%;}'));
CSS.getRule('.ux-mif-mask-target')|| (rules.push('.ux-mif-mask-target{position:relative;zoom:1;}'));
CSS.getRule('.ux-mif-el-mask')|| (rules.push(
'.ux-mif-el-mask {z-index: 100;position: absolute;top:0;left:0;-moz-opacity: 0.5;opacity: .50;*filter: alpha(opacity=50);width: 100%;height: 100%;zoom: 1;} ',
'.ux-mif-el-mask-msg {z-index: 1;position: absolute;top: 0;left: 0;border:1px solid;background:repeat-x 0 -16px;padding:2px;} ',
'.ux-mif-el-mask-msg div {padding:5px 10px 5px 10px;border:1px solid;cursor:wait;} '
));
if (!CSS.getRule('.ux-mif-shim')) {
rules.push('.ux-mif-shim {z-index:8500;position:absolute;top:0px;left:0px;background:transparent!important;overflow:hidden;display:none;}');
rules.push('.ux-mif-shim-on{width:100%;height:100%;display:block;zoom:1;}');
rules.push('.ext-ie6 .ux-mif-shim{margin-left:5px;margin-top:3px;}');
}
if (!CSS.getRule('.x-hide-nosize')){
rules.push ('.x-hide-nosize{height:0px!important;width:0px!important;visibility:hidden!important;border:none!important;zoom:1;}.x-hide-nosize * {height:0px!important;width:0px!important;visibility:hidden!important;border:none!important;zoom:1;}');
}
!!rules.length && CSS.createStyleSheet(rules.join(' '), 'mifCSS');
});
/** @sourceURL=<mif.js> */
Ext.provide && Ext.provide('mif');
})();
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*!
* Ext JS Library 3.3.0
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
Ext.ns('Ext.ux.tree');
/**
* @class Ext.ux.tree.TreeGridSorter
* @extends Ext.tree.TreeSorter
* Provides sorting of nodes in a {@link Ext.ux.tree.TreeGrid}. The TreeGridSorter automatically monitors events on the
* associated TreeGrid that might affect the tree's sort order (beforechildrenrendered, append, insert and textchange).
* Example usage:<br />
* <pre><code>
new Ext.ux.tree.TreeGridSorter(myTreeGrid, {
folderSort: true,
dir: "desc",
sortType: function(node) {
// sort by a custom, typed attribute:
return parseInt(node.id, 10);
}
});
</code></pre>
* @constructor
* @param {TreeGrid} tree
* @param {Object} config
*/
Ext.ux.tree.TreeGridSorter = Ext.extend(Ext.tree.TreeSorter, {
/**
* @cfg {Array} sortClasses The CSS classes applied to a header when it is sorted. (defaults to <tt>['sort-asc', 'sort-desc']</tt>)
*/
sortClasses : ['sort-asc', 'sort-desc'],
/**
* @cfg {String} sortAscText The text displayed in the 'Sort Ascending' menu item (defaults to <tt>'Sort Ascending'</tt>)
*/
sortAscText : 'Sort Ascending',
/**
* @cfg {String} sortDescText The text displayed in the 'Sort Descending' menu item (defaults to <tt>'Sort Descending'</tt>)
*/
sortDescText : 'Sort Descending',
constructor : function(tree, config) {
if(!Ext.isObject(config)) {
config = {
property: tree.columns[0].dataIndex || 'text',
folderSort: true
}
}
Ext.ux.tree.TreeGridSorter.superclass.constructor.apply(this, arguments);
this.tree = tree;
tree.on('headerclick', this.onHeaderClick, this);
tree.ddAppendOnly = true;
var me = this;
this.defaultSortFn = function(n1, n2){
var desc = me.dir && me.dir.toLowerCase() == 'desc',
prop = me.property || 'text',
sortType = me.sortType,
caseSensitive = me.caseSensitive === true,
leafAttr = me.leafAttr || 'leaf',
attr1 = n1.attributes,
attr2 = n2.attributes;
if(me.folderSort){
if(attr1[leafAttr] && !attr2[leafAttr]){
return 1;
}
if(!attr1[leafAttr] && attr2[leafAttr]){
return -1;
}
}
var prop1 = attr1[prop],
prop2 = attr2[prop],
v1 = sortType ? sortType(prop1) : (caseSensitive ? prop1 : prop1.toUpperCase());
v2 = sortType ? sortType(prop2) : (caseSensitive ? prop2 : prop2.toUpperCase());
if(v1 < v2){
return desc ? +1 : -1;
}else if(v1 > v2){
return desc ? -1 : +1;
}else{
return 0;
}
};
tree.on('afterrender', this.onAfterTreeRender, this, {single: true});
tree.on('headermenuclick', this.onHeaderMenuClick, this);
},
onAfterTreeRender : function() {
if(this.tree.hmenu){
this.tree.hmenu.insert(0,
{itemId:'asc', text: this.sortAscText, cls: 'xg-hmenu-sort-asc'},
{itemId:'desc', text: this.sortDescText, cls: 'xg-hmenu-sort-desc'}
);
}
this.updateSortIcon(0, 'asc');
},
onHeaderMenuClick : function(c, id, index) {
if(id === 'asc' || id === 'desc') {
this.onHeaderClick(c, null, index);
return false;
}
},
onHeaderClick : function(c, el, i) {
if(c && !this.tree.headersDisabled){
var me = this;
me.property = c.dataIndex;
me.dir = c.dir = (c.dir === 'desc' ? 'asc' : 'desc');
me.sortType = c.sortType;
me.caseSensitive === Ext.isBoolean(c.caseSensitive) ? c.caseSensitive : this.caseSensitive;
me.sortFn = c.sortFn || this.defaultSortFn;
this.tree.root.cascade(function(n) {
if(!n.isLeaf()) {
me.updateSort(me.tree, n);
}
});
this.updateSortIcon(i, c.dir);
}
},
// private
updateSortIcon : function(col, dir){
var sc = this.sortClasses,
hds = this.tree.innerHd.select('td').removeClass(sc);
hds.item(col).addClass(sc[dir == 'desc' ? 1 : 0]);
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*!
* Ext JS Library 3.3.0
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
/**
* @class Ext.tree.ColumnResizer
* @extends Ext.util.Observable
*/
Ext.tree.ColumnResizer = Ext.extend(Ext.util.Observable, {
/**
* @cfg {Number} minWidth The minimum width the column can be dragged to.
* Defaults to <tt>14</tt>.
*/
minWidth: 14,
constructor: function(config){
Ext.apply(this, config);
Ext.tree.ColumnResizer.superclass.constructor.call(this);
},
init : function(tree){
this.tree = tree;
tree.on('render', this.initEvents, this);
},
initEvents : function(tree){
tree.mon(tree.innerHd, 'mousemove', this.handleHdMove, this);
this.tracker = new Ext.dd.DragTracker({
onBeforeStart: this.onBeforeStart.createDelegate(this),
onStart: this.onStart.createDelegate(this),
onDrag: this.onDrag.createDelegate(this),
onEnd: this.onEnd.createDelegate(this),
tolerance: 3,
autoStart: 300
});
this.tracker.initEl(tree.innerHd);
tree.on('beforedestroy', this.tracker.destroy, this.tracker);
},
handleHdMove : function(e, t){
var hw = 5,
x = e.getPageX(),
hd = e.getTarget('.x-treegrid-hd', 3, true);
if(hd){
var r = hd.getRegion(),
ss = hd.dom.style,
pn = hd.dom.parentNode;
if(x - r.left <= hw && hd.dom !== pn.firstChild) {
var ps = hd.dom.previousSibling;
while(ps && Ext.fly(ps).hasClass('x-treegrid-hd-hidden')) {
ps = ps.previousSibling;
}
if(ps) {
this.activeHd = Ext.get(ps);
ss.cursor = Ext.isWebKit ? 'e-resize' : 'col-resize';
}
} else if(r.right - x <= hw) {
var ns = hd.dom;
while(ns && Ext.fly(ns).hasClass('x-treegrid-hd-hidden')) {
ns = ns.previousSibling;
}
if(ns) {
this.activeHd = Ext.get(ns);
ss.cursor = Ext.isWebKit ? 'w-resize' : 'col-resize';
}
} else{
delete this.activeHd;
ss.cursor = '';
}
}
},
onBeforeStart : function(e){
this.dragHd = this.activeHd;
return !!this.dragHd;
},
onStart : function(e){
this.dragHeadersDisabled = this.tree.headersDisabled;
this.tree.headersDisabled = true;
this.proxy = this.tree.body.createChild({cls:'x-treegrid-resizer'});
this.proxy.setHeight(this.tree.body.getHeight());
var x = this.tracker.getXY()[0];
this.hdX = this.dragHd.getX();
this.hdIndex = this.tree.findHeaderIndex(this.dragHd);
this.proxy.setX(this.hdX);
this.proxy.setWidth(x-this.hdX);
this.maxWidth = this.tree.outerCt.getWidth() - this.tree.innerBody.translatePoints(this.hdX).left;
},
onDrag : function(e){
var cursorX = this.tracker.getXY()[0];
this.proxy.setWidth((cursorX-this.hdX).constrain(this.minWidth, this.maxWidth));
},
onEnd : function(e){
var nw = this.proxy.getWidth(),
tree = this.tree,
disabled = this.dragHeadersDisabled;
this.proxy.remove();
delete this.dragHd;
tree.columns[this.hdIndex].width = nw;
tree.updateColumnWidths();
setTimeout(function(){
tree.headersDisabled = disabled;
}, 100);
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*!
* Ext JS Library 3.3.0
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
/**
* @class Ext.ux.tree.TreeGridNodeUI
* @extends Ext.tree.TreeNodeUI
*/
Ext.ux.tree.TreeGridNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
isTreeGridNodeUI: true,
renderElements : function(n, a, targetNode, bulkRender){
var t = n.getOwnerTree(),
cols = t.columns,
c = cols[0],
i, buf, len;
this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
buf = [
'<tbody class="x-tree-node">',
'<tr ext:tree-node-id="', n.id ,'" class="x-tree-node-el x-tree-node-leaf ', a.cls, '">',
'<td class="x-treegrid-col">',
'<span class="x-tree-node-indent">', this.indentMarkup, "</span>",
'<img src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow" />',
'<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon', (a.icon ? " x-tree-node-inline-icon" : ""), (a.iconCls ? " "+a.iconCls : ""), '" unselectable="on" />',
'<a hidefocus="on" class="x-tree-node-anchor" href="', a.href ? a.href : '#', '" tabIndex="1" ',
a.hrefTarget ? ' target="'+a.hrefTarget+'"' : '', '>',
'<span unselectable="on">', (c.tpl ? c.tpl.apply(a) : a[c.dataIndex] || c.text), '</span></a>',
'</td>'
];
for(i = 1, len = cols.length; i < len; i++){
c = cols[i];
buf.push(
'<td class="x-treegrid-col ', (c.cls ? c.cls : ''), '">',
'<div unselectable="on" class="x-treegrid-text"', (c.align ? ' style="text-align: ' + c.align + ';"' : ''), '>',
(c.tpl ? c.tpl.apply(a) : a[c.dataIndex]),
'</div>',
'</td>'
);
}
buf.push(
'</tr><tr class="x-tree-node-ct"><td colspan="', cols.length, '">',
'<table class="x-treegrid-node-ct-table" cellpadding="0" cellspacing="0" style="table-layout: fixed; display: none; width: ', t.innerCt.getWidth() ,'px;"><colgroup>'
);
for(i = 0, len = cols.length; i<len; i++) {
buf.push('<col style="width: ', (cols[i].hidden ? 0 : cols[i].width) ,'px;" />');
}
buf.push('</colgroup></table></td></tr></tbody>');
if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
this.wrap = Ext.DomHelper.insertHtml("beforeBegin", n.nextSibling.ui.getEl(), buf.join(''));
}else{
this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(''));
}
this.elNode = this.wrap.childNodes[0];
this.ctNode = this.wrap.childNodes[1].firstChild.firstChild;
var cs = this.elNode.firstChild.childNodes;
this.indentNode = cs[0];
this.ecNode = cs[1];
this.iconNode = cs[2];
this.anchor = cs[3];
this.textNode = cs[3].firstChild;
},
// private
animExpand : function(cb){
this.ctNode.style.display = "";
Ext.ux.tree.TreeGridNodeUI.superclass.animExpand.call(this, cb);
}
});
Ext.ux.tree.TreeGridRootNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
isTreeGridNodeUI: true,
// private
render : function(){
if(!this.rendered){
this.wrap = this.ctNode = this.node.ownerTree.innerCt.dom;
this.node.expanded = true;
}
if(Ext.isWebKit) {
// weird table-layout: fixed issue in webkit
var ct = this.ctNode;
ct.style.tableLayout = null;
(function() {
ct.style.tableLayout = 'fixed';
}).defer(1);
}
},
destroy : function(){
if(this.elNode){
Ext.dd.Registry.unregister(this.elNode.id);
}
delete this.node;
},
collapse : Ext.emptyFn,
expand : Ext.emptyFn
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*!
* Ext JS Library 3.3.0
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
/**
* @class Ext.ux.tree.TreeGridLoader
* @extends Ext.tree.TreeLoader
*/
Ext.ux.tree.TreeGridLoader = Ext.extend(Ext.tree.TreeLoader, {
createNode : function(attr) {
if (!attr.uiProvider) {
attr.uiProvider = Ext.ux.tree.TreeGridNodeUI;
}
return Ext.tree.TreeLoader.prototype.createNode.call(this, attr);
},
processResponse : function(response, node, callback, scope){
var json = response.responseText,
children,
newNode,
i = 0,
len;
try {
if (!(children = response.responseData)) {
children = Ext.decode(json);
if (this.root) {
if (!this.getRoot) {
this.getRoot = Ext.data.JsonReader.prototype.createAccessor(this.root);
}
children = this.getRoot(children);
}
}
node.beginUpdate();
for(len = children.length; i < len; i++){
if(newNode = this.createNode(children[i])){
node.appendChild(newNode);
}
}
node.endUpdate();
this.runCallback(callback, scope || node, [node]);
}catch(e){
this.handleFailure(response);
}
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*!
* Ext JS Library 3.3.0
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
(function() {
Ext.override(Ext.list.Column, {
init : function() {
var types = Ext.data.Types,
st = this.sortType;
if(this.type){
if(Ext.isString(this.type)){
this.type = Ext.data.Types[this.type.toUpperCase()] || types.AUTO;
}
}else{
this.type = types.AUTO;
}
// named sortTypes are supported, here we look them up
if(Ext.isString(st)){
this.sortType = Ext.data.SortTypes[st];
}else if(Ext.isEmpty(st)){
this.sortType = this.type.sortType;
}
}
});
Ext.tree.Column = Ext.extend(Ext.list.Column, {});
Ext.tree.NumberColumn = Ext.extend(Ext.list.NumberColumn, {});
Ext.tree.DateColumn = Ext.extend(Ext.list.DateColumn, {});
Ext.tree.BooleanColumn = Ext.extend(Ext.list.BooleanColumn, {});
Ext.reg('tgcolumn', Ext.tree.Column);
Ext.reg('tgnumbercolumn', Ext.tree.NumberColumn);
Ext.reg('tgdatecolumn', Ext.tree.DateColumn);
Ext.reg('tgbooleancolumn', Ext.tree.BooleanColumn);
})();
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*!
* Ext JS Library 3.3.0
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
/**
* @class Ext.ux.tree.TreeGrid
* @extends Ext.tree.TreePanel
*
* @xtype treegrid
*/
Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
rootVisible : false,
useArrows : true,
lines : false,
borderWidth : Ext.isBorderBox ? 0 : 2, // the combined left/right border for each cell
cls : 'x-treegrid',
columnResize : true,
enableSort : (this.enableSort!=undefined)?true:this.enableSort,
reserveScrollOffset : true,
enableHdMenu : (this.enableHdMenu!=undefined)?true:this.enableHdMenu,
columnsText : 'Columns',
initComponent : function() {
if(!this.root) {
this.root = new Ext.tree.AsyncTreeNode({text: 'Root'});
}
// initialize the loader
var l = this.loader;
if(!l){
l = new Ext.ux.tree.TreeGridLoader({
dataUrl: this.dataUrl,
requestMethod: this.requestMethod,
store: this.store
});
}else if(Ext.isObject(l) && !l.load){
l = new Ext.ux.tree.TreeGridLoader(l);
}
this.loader = l;
Ext.ux.tree.TreeGrid.superclass.initComponent.call(this);
this.initColumns();
if(this.enableSort) {
this.treeGridSorter = new Ext.ux.tree.TreeGridSorter(this, this.enableSort);
}
if(this.columnResize){
this.colResizer = new Ext.tree.ColumnResizer(this.columnResize);
this.colResizer.init(this);
}
var c = this.columns;
if(!this.internalTpl){
this.internalTpl = new Ext.XTemplate(
'<div class="x-grid3-header">',
'<div class="x-treegrid-header-inner">',
'<div class="x-grid3-header-offset">',
'<table style="table-layout: fixed;" cellspacing="0" cellpadding="0" border="0"><colgroup><tpl for="columns"><col /></tpl></colgroup>',
'<thead><tr class="x-grid3-hd-row">',
'<tpl for="columns">',
'<td class="x-grid3-hd x-grid3-cell x-treegrid-hd" style="text-align: {align};" id="', this.id, '-xlhd-{#}">',
'<div class="x-grid3-hd-inner x-treegrid-hd-inner" unselectable="on">',
this.enableHdMenu ? '<a class="x-grid3-hd-btn" href="#"></a>' : '',
'{header}<img class="x-grid3-sort-icon" src="', Ext.BLANK_IMAGE_URL, '" />',
'</div>',
'</td></tpl>',
'</tr></thead>',
'</table>',
'</div></div>',
'</div>',
'<div class="x-treegrid-root-node">',
'<table class="x-treegrid-root-table" cellpadding="0" cellspacing="0" style="table-layout: fixed;"></table>',
'</div>'
);
}
if(!this.colgroupTpl) {
this.colgroupTpl = new Ext.XTemplate(
'<colgroup><tpl for="columns"><col style="width: {width}px"/></tpl></colgroup>'
);
}
},
initColumns : function() {
var cs = this.columns,
len = cs.length,
columns = [],
i, c;
for(i = 0; i < len; i++){
c = cs[i];
if(!c.isColumn) {
c.xtype = c.xtype ? (/^tg/.test(c.xtype) ? c.xtype : 'tg' + c.xtype) : 'tgcolumn';
c = Ext.create(c);
}
c.init(this);
columns.push(c);
if(this.enableSort !== false && c.sortable !== false) {
c.sortable = true;
this.enableSort = true;
}
}
this.columns = columns;
},
onRender : function(){
Ext.tree.TreePanel.superclass.onRender.apply(this, arguments);
this.el.addClass('x-treegrid');
this.outerCt = this.body.createChild({
cls:'x-tree-root-ct x-treegrid-ct ' + (this.useArrows ? 'x-tree-arrows' : this.lines ? 'x-tree-lines' : 'x-tree-no-lines')
});
this.internalTpl.overwrite(this.outerCt, {columns: this.columns});
this.mainHd = Ext.get(this.outerCt.dom.firstChild);
this.innerHd = Ext.get(this.mainHd.dom.firstChild);
this.innerBody = Ext.get(this.outerCt.dom.lastChild);
this.innerCt = Ext.get(this.innerBody.dom.firstChild);
this.colgroupTpl.insertFirst(this.innerCt, {columns: this.columns});
if(this.hideHeaders){
this.el.child('.x-grid3-header').setDisplayed('none');
}
else if(this.enableHdMenu !== false){
this.hmenu = new Ext.menu.Menu({id: this.id + '-hctx'});
if(this.enableColumnHide !== false){
this.colMenu = new Ext.menu.Menu({id: this.id + '-hcols-menu'});
this.colMenu.on({
scope: this,
beforeshow: this.beforeColMenuShow,
itemclick: this.handleHdMenuClick
});
this.hmenu.add({
itemId:'columns',
hideOnClick: false,
text: this.columnsText,
menu: this.colMenu,
iconCls: 'x-cols-icon'
});
}
this.hmenu.on('itemclick', this.handleHdMenuClick, this);
}
},
setRootNode : function(node){
node.attributes.uiProvider = Ext.ux.tree.TreeGridRootNodeUI;
node = Ext.ux.tree.TreeGrid.superclass.setRootNode.call(this, node);
if(this.innerCt) {
this.colgroupTpl.insertFirst(this.innerCt, {columns: this.columns});
}
return node;
},
clearInnerCt : function(){
if(Ext.isIE){
var dom = this.innerCt.dom;
while(dom.firstChild){
dom.removeChild(dom.firstChild);
}
}else{
Ext.ux.tree.TreeGrid.superclass.clearInnerCt.call(this);
}
},
initEvents : function() {
Ext.ux.tree.TreeGrid.superclass.initEvents.apply(this, arguments);
this.mon(this.innerBody, 'scroll', this.syncScroll, this);
this.mon(this.innerHd, 'click', this.handleHdDown, this);
this.mon(this.mainHd, {
scope: this,
mouseover: this.handleHdOver,
mouseout: this.handleHdOut
});
},
onResize : function(w, h) {
Ext.ux.tree.TreeGrid.superclass.onResize.apply(this, arguments);
var bd = this.innerBody.dom;
var hd = this.innerHd.dom;
if(!bd){
return;
}
if(Ext.isNumber(h)){
bd.style.height = this.body.getHeight(true) - hd.offsetHeight + 'px';
}
if(Ext.isNumber(w)){
var sw = Ext.num(this.scrollOffset, Ext.getScrollBarWidth());
if(this.reserveScrollOffset || ((bd.offsetWidth - bd.clientWidth) > 10)){
this.setScrollOffset(sw);
}else{
var me = this;
setTimeout(function(){
me.setScrollOffset(bd.offsetWidth - bd.clientWidth > 10 ? sw : 0);
}, 10);
}
}
},
updateColumnWidths : function() {
var cols = this.columns,
colCount = cols.length,
groups = this.outerCt.query('colgroup'),
groupCount = groups.length,
c, g, i, j;
for(i = 0; i<colCount; i++) {
c = cols[i];
for(j = 0; j<groupCount; j++) {
g = groups[j];
g.childNodes[i].style.width = (c.hidden ? 0 : c.width) + 'px';
}
}
for(i = 0, groups = this.innerHd.query('td'), len = groups.length; i<len; i++) {
c = Ext.fly(groups[i]);
if(cols[i] && cols[i].hidden) {
c.addClass('x-treegrid-hd-hidden');
}
else {
c.removeClass('x-treegrid-hd-hidden');
}
}
var tcw = this.getTotalColumnWidth();
Ext.fly(this.innerHd.dom.firstChild).setWidth(tcw + (this.scrollOffset || 0));
this.outerCt.select('table').setWidth(tcw);
this.syncHeaderScroll();
},
getVisibleColumns : function() {
var columns = [],
cs = this.columns,
len = cs.length,
i;
for(i = 0; i<len; i++) {
if(!cs[i].hidden) {
columns.push(cs[i]);
}
}
return columns;
},
getTotalColumnWidth : function() {
var total = 0;
for(var i = 0, cs = this.getVisibleColumns(), len = cs.length; i<len; i++) {
total += cs[i].width;
}
return total;
},
setScrollOffset : function(scrollOffset) {
this.scrollOffset = scrollOffset;
this.updateColumnWidths();
},
// private
handleHdDown : function(e, t){
var hd = e.getTarget('.x-treegrid-hd');
if(hd && Ext.fly(t).hasClass('x-grid3-hd-btn')){
var ms = this.hmenu.items,
cs = this.columns,
index = this.findHeaderIndex(hd),
c = cs[index],
sort = c.sortable;
e.stopEvent();
Ext.fly(hd).addClass('x-grid3-hd-menu-open');
this.hdCtxIndex = index;
this.fireEvent('headerbuttonclick', ms, c, hd, index);
this.hmenu.on('hide', function(){
Ext.fly(hd).removeClass('x-grid3-hd-menu-open');
}, this, {single:true});
this.hmenu.show(t, 'tl-bl?');
}
else if(hd) {
var index = this.findHeaderIndex(hd);
this.fireEvent('headerclick', this.columns[index], hd, index);
}
},
// private
handleHdOver : function(e, t){
var hd = e.getTarget('.x-treegrid-hd');
if(hd && !this.headersDisabled){
index = this.findHeaderIndex(hd);
this.activeHdRef = t;
this.activeHdIndex = index;
var el = Ext.get(hd);
this.activeHdRegion = el.getRegion();
el.addClass('x-grid3-hd-over');
this.activeHdBtn = el.child('.x-grid3-hd-btn');
if(this.activeHdBtn){
this.activeHdBtn.dom.style.height = (hd.firstChild.offsetHeight-1)+'px';
}
}
},
// private
handleHdOut : function(e, t){
var hd = e.getTarget('.x-treegrid-hd');
if(hd && (!Ext.isIE || !e.within(hd, true))){
this.activeHdRef = null;
Ext.fly(hd).removeClass('x-grid3-hd-over');
hd.style.cursor = '';
}
},
findHeaderIndex : function(hd){
hd = hd.dom || hd;
var cs = hd.parentNode.childNodes;
for(var i = 0, c; c = cs[i]; i++){
if(c == hd){
return i;
}
}
return -1;
},
// private
beforeColMenuShow : function(){
var cols = this.columns,
colCount = cols.length,
i, c;
this.colMenu.removeAll();
for(i = 1; i < colCount; i++){
c = cols[i];
if(c.hideable !== false){
this.colMenu.add(new Ext.menu.CheckItem({
itemId: 'col-' + i,
text: c.header,
checked: !c.hidden,
hideOnClick:false,
disabled: c.hideable === false
}));
}
}
},
// private
handleHdMenuClick : function(item){
var index = this.hdCtxIndex,
id = item.getItemId();
if(this.fireEvent('headermenuclick', this.columns[index], id, index) !== false) {
index = id.substr(4);
if(index > 0 && this.columns[index]) {
this.setColumnVisible(index, !item.checked);
}
}
return true;
},
setColumnVisible : function(index, visible) {
this.columns[index].hidden = !visible;
this.updateColumnWidths();
},
/**
* Scrolls the grid to the top
*/
scrollToTop : function(){
this.innerBody.dom.scrollTop = 0;
this.innerBody.dom.scrollLeft = 0;
},
// private
syncScroll : function(){
this.syncHeaderScroll();
var mb = this.innerBody.dom;
this.fireEvent('bodyscroll', mb.scrollLeft, mb.scrollTop);
},
// private
syncHeaderScroll : function(){
var mb = this.innerBody.dom;
this.innerHd.dom.scrollLeft = mb.scrollLeft;
this.innerHd.dom.scrollLeft = mb.scrollLeft; // second time for IE (1/2 time first fails, other browsers ignore)
},
registerNode : function(n) {
Ext.ux.tree.TreeGrid.superclass.registerNode.call(this, n);
if(!n.uiProvider && !n.isRoot && !n.ui.isTreeGridNodeUI) {
n.ui = new Ext.ux.tree.TreeGridNodeUI(n);
}
}
});
Ext.reg('treegrid', Ext.ux.tree.TreeGrid);
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext,window*/
function utils_logout() {
Ext.util.Cookies.set('userLogin', '');
Ext.util.Cookies.set('hashCode', '');
Ext.Ajax.defaultHeaders.Authorization = '';
window.location.reload();
}
/* URL class for JavaScript
* Copyright (C) 2003 Johan Känngård, <johan AT kanngard DOT net>
* http://dev.kanngard.net/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* The GPL is located at: http://www.gnu.org/licenses/gpl.txt
*/
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/* Creates a new URL object with the specified url String. */
function URL(url){
if(url.length==0) eval('throw "Invalid URL ['+url+'];');
this.url=url;
this.port=-1;
this.query=(this.url.indexOf('?')>=0)?this.url.substring(this.url.indexOf('?')+1):'';
if(this.query.indexOf('#')>=0) this.query=this.query.substring(0,this.query.indexOf('#'));
this.protocol='';
this.host='';
var protocolSepIndex=this.url.indexOf('://');
if(protocolSepIndex>=0){
this.protocol=this.url.substring(0,protocolSepIndex).toLowerCase();
this.host=this.url.substring(protocolSepIndex+3);
if(this.host.indexOf('/')>=0) this.host=this.host.substring(0,this.host.indexOf('/'));
var atIndex=this.host.indexOf('@');
if(atIndex>=0){
var credentials=this.host.substring(0,atIndex);
var colonIndex=credentials.indexOf(':');
if(colonIndex>=0){
this.username=credentials.substring(0,colonIndex);
this.password=credentials.substring(colonIndex);
}else{
this.username=credentials;
}
this.host=this.host.substring(atIndex+1);
}
var portColonIndex=this.host.indexOf(':');
if(portColonIndex>=0){
this.port=this.host.substring(portColonIndex);
this.host=this.host.substring(0,portColonIndex);
}
this.file=this.url.substring(protocolSepIndex+3);
this.file=this.file.substring(this.file.indexOf('/'));
}else{
this.file=this.url;
}
if(this.file.indexOf('?')>=0) this.file=this.file.substring(0, this.file.indexOf('?'));
var refSepIndex=url.indexOf('#');
if(refSepIndex>=0){
this.file=this.file.substring(0,refSepIndex);
this.reference=this.url.substring(this.url.indexOf('#'));
}else{
this.reference='';
}
this.path=this.file;
if(this.query.length>0) this.file+='?'+this.query;
if(this.reference.length>0) this.file+='#'+this.reference;
this.getPort=getPort;
this.getQuery=getQuery;
this.getProtocol=getProtocol;
this.getHost=getHost;
this.getUserName=getUserName;
this.getPassword=getPassword;
this.getFile=getFile;
this.getReference=getReference;
this.getPath=getPath;
this.getArgumentValue=getArgumentValue;
this.getArgumentValues=getArgumentValues;
this.toString=toString;
/* Returns the port part of this URL, i.e. '8080' in the url 'http://server:8080/' */
function getPort(){
return this.port;
}
/* Returns the query part of this URL, i.e. 'Open' in the url 'http://server/?Open' */
function getQuery(){
return this.query;
}
/* Returns the protocol of this URL, i.e. 'http' in the url 'http://server/' */
function getProtocol(){
return this.protocol;
}
/* Returns the host name of this URL, i.e. 'server.com' in the url 'http://server.com/' */
function getHost(){
return this.host;
}
/* Returns the user name part of this URL, i.e. 'joe' in the url 'http://joe@server.com/' */
function getUserName(){
return this.username;
}
/* Returns the password part of this url, i.e. 'secret' in the url 'http://joe:secret@server.com/' */
function getPassword(){
return this.password;
}
/* Returns the file part of this url, i.e. everything after the host name. */
function getFile(){
return this.file;
}
/* Returns the reference of this url, i.e. 'bookmark' in the url 'http://server/file.html#bookmark' */
function getReference(){
return this.reference;
}
/* Returns the file path of this url, i.e. '/dir/file.html' in the url 'http://server/dir/file.html' */
function getPath(){
return this.path;
}
/* Returns the FIRST matching value to the specified key in the query.
If the url has a non-value argument, like 'Open' in '?Open&bla=12', this method
returns the same as the key: 'Open'...
The url must be correctly encoded, ampersands must encoded as &
I.e. returns 'value' if the key is 'key' in the url 'http://server/?Open&key=value' */
function getArgumentValue(key){
var a=this.getArgumentValues();
if(a.length<1) return '';
for(var i=0;i<a.length;i++){
if(a[i][0]==key) return a[i][1];
}
return '';
}
/* Returns all key / value pairs in the query as a two dimensional array */
function getArgumentValues(){
var a=new Array();
var b=this.query.split('&');
var c='';
if(b.length<1) return a;
for(var i=0;i<b.length;i++){
c=b[i].split('=');
a[i]=new Array(c[0],((c.length==1)?c[0]:c[1]));
}
return a;
}
/* Returns a String representation of this url */
function toString(){
return this.url;
}
}/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n,document, window, SitoolsDesk*/
Ext.namespace('sitools.widget');
/**
* @cfg {string} urlFeed The feed URL
* @cfg {string} feedType the type of the feed ("atom_1.0" or "rss_2")
* @cfg {string} feedSource the source of the feed (OPENSEARCH or CLASSIC)
* @requires sitools.user.component.openSearchResultFeed
*/
sitools.widget.FeedGridFlux = function (config) {
this.datasetName = config.datasetName;
function clickOnRow(self, rowIndex, e) {
e.stopEvent();
var rec = self.store.getAt(rowIndex);
if (Ext.isEmpty(rec)) {
return;
}
// si on est pas sur le bureau
if (Ext.isEmpty(window) || Ext.isEmpty(window.SitoolsDesk)) {
var component = new sitools.widget.feedItemDetails({
record : rec
});
var win = new Ext.Window({
stateful : false,
title : i18n.get('label.viewFeedDetail'),
width : 400,
height : 600,
shim : false,
animCollapse : false,
constrainHeader : true,
layout : 'fit',
modal : true
});
win.add(component);
win.show();
} else {
var componentCfg = {
record : rec
};
var jsObj = sitools.widget.feedItemDetails;
var windowConfig = {
id : "viewFeedDetail",
title : i18n.get('label.viewFeedDetail'),
saveToolbar : false
};
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, jsObj, true);
}
}
Ext.apply(this);
this.layout = "fit";
var gridPanel;
if (config.feedSource !== undefined && config.feedSource === "OPENSEARCH") {
gridPanel = new sitools.user.component.openSearchResultFeed(config);
} else {
config.listeners = {
rowdblclick : clickOnRow
};
if (config.feedType !== undefined && config.feedType === "atom_1.0") {
gridPanel = new sitools.widget.atom1FeedReader(config);
} else {
gridPanel = new sitools.widget.rss2FeedReader(config);
}
}
this.items = [ gridPanel ];
sitools.widget.FeedGridFlux.superclass.constructor.call(this);
};
Ext.extend(sitools.widget.FeedGridFlux, Ext.Panel, {
componentType : "feeds",
_getSettings : function () {
return {
objectName : "feedsReader"
};
},
border : false
});
Ext.reg('appfeedgridflux', sitools.widget.FeedGridFlux);
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n,document,window,SitoolsDesk*/
Ext.namespace('sitools.widget');
* @param urlFeed :
* The feed URL
*/
sitools.widget.rss2FeedReader = function (config) {
Ext.apply(this);
this.layout = "fit";
this.storeFeedsRecords = new Ext.data.Store({
autoLoad : true,
sortInfo : {field : 'pubDate', direction : "DESC"},
proxy : new Ext.data.HttpProxy({
url : config.urlFeed,
restful : true,
listeners : {
scope : this,
exception : onRequestFeedException
}
}),
reader : new Ext.data.XmlReader({
record : 'item'
}, [ 'title', 'author', {
name : 'pubDate',
type : 'date'
}, 'link', 'description', 'content', 'guid', {
name : 'imageUrl',
mapping : "enclosure@url"
}, {
name : 'imageType',
mapping : "enclosure@type"
}])
});
var columns = [ {
id : 'image',
header : "Image",
dataIndex : 'imageUrl',
sortable : false,
width : 120
,
renderer : this.imageRenderer
}, {
id : 'title',
header : "Title",
dataIndex : 'title',
sortable : true,
width : 460,
scope : this,
renderer : this.formatTitle
}, {
header : "Author",
dataIndex : 'author',
width : 100,
hidden : true,
sortable : true
}, {
id : 'last',
header : "Date",
dataIndex : 'pubDate',
width : 150,
renderer : this.formatDate,
sortable : true,
hidden : true
} ];
sitools.widget.rss2FeedReader.superclass.constructor.call(this, {
// height : 300,
columns : columns,
store : this.storeFeedsRecords,
loadMask : {
msg : i18n.get("label.loadingFeed")
},
sm : new Ext.grid.RowSelectionModel({
singleSelect : true
}),
autoExpandColumn : 'title',
hideHeaders : true,
viewConfig : {
forceFit : true,
enableRowBody : true,
showPreview : true,
getRowClass : this.applyRowClass
},
listeners : config.listeners
});
// this.on('rowcontextmenu', this.onContextClick, this);
// this.on('beforeShow',this.loadData);
};
Ext.extend(sitools.widget.rss2FeedReader, Ext.grid.GridPanel, {
loadData : function () {
this.loadFeed('http://feeds.feedburner.com/extblog');
this.doLayout();
},
loadFeed : function (url) {
this.store.baseParams = {
feed : url
};
this.store.load();
},
togglePreview : function (show) {
this.view.showPreview = show;
this.view.refresh();
},
// within this function "this" is actually the GridView
applyRowClass : function (record, rowIndex, p, ds) {
if (this.showPreview) {
var xf = Ext.util.Format;
p.body = '<p class=sous-titre-flux>' + xf.ellipsis(xf.stripTags(record.data.description), 200) + '</p>';
return 'x-grid3-row-expanded';
}
return 'x-grid3-row-collapsed';
},
formatDate : function (date) {
if (!date) {
return '';
}
var now = new Date();
var d = now.clearTime(true);
if (date instanceof Date){
var notime = date.clearTime(true).getTime();
if (notime == d.getTime()) {
return 'Today ' + date.dateFormat('g:i a');
}
d = d.add('d', -6);
if (d.getTime() <= notime) {
return date.dateFormat('D g:i a');
}
return date.dateFormat('n/j g:i a');
}
else {
return date;
}
},
formatTitle : function (value, p, record) {
var link = record.data.link;
var xf = Ext.util.Format;
var author = (Ext.isEmpty(record.data.author)) ? "" : record.data.author;
var dateFormat = this.formatDate(record.data.pubDate);
var res = "";
if (link !== undefined && link !== "") {
res = String.format('<div class="topic"><a href="{0}" title="{1}" target="_blank"><span class="rss_feed_title">{2}</span></a><br/><span class="author">{3}</span></div>', link, value,
xf.ellipsis(xf.stripTags(value), 30), author);
} else {
res = String.format('<div class="topic"><span class="rss_feed_title">{0}</span><br/><span class="author">{1}</span></div>', xf.ellipsis(xf.stripTags(value), 30), author);
}
if (dateFormat != "" && dateFormat != null ){
res += String.format('<p id="feeds-date">{0}</p>', dateFormat);
}
return res;
},
imageRenderer : function (value, p, record) {
if (Ext.isEmpty(value) || Ext.isEmpty(record.data.imageType)) {
return "";
}
if (record.data.imageType.substr(0, 5) != "image") {
return "";
}
return String.format('<img src="{0}" width="50px">', value);
},
sortByDate : function (direction){
this.storeFeedsRecords.sort('pubDate', direction);
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n,document*/
Ext.namespace('sitools.widget');
/**
* Displays a grid of atom1 format feeds
* @class sitools.widget.atom1FeedReader
* @extends Ext.grid.GridPanel
* @cfg {string} datasetId The Dataset id,
* @cfg {string} urlFeed The url to request feed
* @cfg {string} datasetName The dataset name
* @cfg {string} feedSource
* @cfg {boolean} autoLoad store configuration
*/
sitools.widget.atom1FeedReader = function (config) {
Ext.apply(this);
this.layout = "fit";
this.storeFeedsRecords = new Ext.data.Store({
autoLoad : true,
sortInfo : {field : 'pubDate', direction : "DESC"},
proxy : new Ext.data.HttpProxy({
url : config.urlFeed,
restful : true,
listeners : {
scope : this,
exception : onRequestFeedException
}
// url : 'http://extjs.com/forum/external.php?type=RSS2'
}),
reader : new Ext.data.XmlReader({
record : 'entry'
}, [ 'title',
{
name : 'author',
mapping : "author.name"
}, {
name : 'pubDate',
mapping : 'updated',
type : 'date'
}, {
name : 'link',
mapping: "link@href"
},
{
name : 'description',
mapping : 'content'
},
'content',
{
name : 'imageUrl',
createAccessor : function (data, field) {
var q = Ext.DomQuery;
// select node link with attribute type like image%
var node = q.selectNode("link[type^=image]", data);
var result = {};
if (Ext.isEmpty(node)) {
return result;
}
Ext.each(node.attributes, function (attribute) {
result[attribute.name] = attribute.value;
});
return result;
}
}
])
});
var columns = [ {
id : 'image',
header : "Image",
dataIndex : 'imageUrl',
sortable : false,
width : 120
,
renderer : this.imageRenderer
}, {
id : 'title',
header : "Title",
dataIndex : 'title',
sortable : true,
width : 460,
scope : this,
renderer : this.formatTitle
}, {
header : "Author",
dataIndex : 'author',
width : 100,
hidden : true,
sortable : true
}, {
id : 'last',
header : "Date",
dataIndex : 'pubDate',
width : 150,
renderer : this.formatDate,
sortable : true,
hidden : true
} ];
sitools.widget.atom1FeedReader.superclass.constructor.call(this, {
// height : 300,
columns : columns,
store : this.storeFeedsRecords,
loadMask : {
msg : i18n.get("label.loadingFeed")
},
sm : new Ext.grid.RowSelectionModel({
singleSelect : true
}),
autoExpandColumn : 'title',
hideHeaders : true,
viewConfig : {
forceFit : true,
enableRowBody : true,
showPreview : true,
getRowClass : this.applyRowClass
},
listeners : config.listeners
});
};
Ext.extend(sitools.widget.atom1FeedReader, Ext.grid.GridPanel, {
/**
* Load the feeds with the given url
* @param {string} url
*/
loadFeed : function (url) {
this.store.baseParams = {
feed : url
};
this.store.load();
},
/**
* switch from preview to complete view
* @param {boolean} show
*/
togglePreview : function (show) {
this.view.showPreview = show;
this.view.refresh();
},
/**
* override the method getRowClass
* @param {Record} record The {@link Ext.data.Record} corresponding to the current row.
* @param {Number} index The row index.
* @param {Object} rowParams A config object that is passed to the row template during rendering that allows
* customization of various aspects of a grid row.
* <p>If {@link #enableRowBody} is configured <b><tt></tt>true</b>, then the following properties may be set
* by this function, and will be used to render a full-width expansion row below each grid row:</p>
* <ul>
* <li><code>body</code> : String <div class="sub-desc">An HTML fragment to be used as the expansion row's body content (defaults to '').</div></li>
* <li><code>bodyStyle</code> : String <div class="sub-desc">A CSS style specification that will be applied to the expansion row's <tr> element. (defaults to '').</div></li>
* </ul>
* The following property will be passed in, and may be appended to:
* <ul>
* <li><code>tstyle</code> : String <div class="sub-desc">A CSS style specification that willl be applied to the <table> element which encapsulates
* both the standard grid row, and any expansion row.</div></li>
* </ul>
* @param {Store} store The {@link Ext.data.Store} this grid is bound to
*/
applyRowClass : function (record, rowIndex, p, ds) {
if (this.showPreview) {
var xf = Ext.util.Format;
if (record.data.summary != "" && record.data.summary != undefined){
p.body = '<p class=sous-titre-flux>' + xf.ellipsis(xf.stripTags(record.data.summary), 200) + '</p>';
return 'x-grid3-row-expanded';
}
}
return 'x-grid3-row-collapsed';
},
/**
* Custom date format
* @param {Date} date the input date
* @return {String} the date formated
*/
formatDate : function (date) {
if (!date) {
return '';
}
var now = new Date();
var d = now.clearTime(true);
if (date instanceof Date){
var notime = date.clearTime(true).getTime();
if (notime == d.getTime()) {
return 'Today ' + date.dateFormat('g:i a');
}
d = d.add('d', -6);
if (d.getTime() <= notime) {
return date.dateFormat('D g:i a');
}
return date.dateFormat('n/j g:i a');
}
else {
return date;
}
},
/**
* Custom renderer for title columns
* @param {} value the value to format
* @param {} p
* @param {Ext.data.Record} record
* @return {String} The title value formatted.
*/
formatTitle : function (value, p, record) {
var author = (record.data.author.name !== undefined) ? record.data.author.name : "";
var link = record.data.link;
var xf = Ext.util.Format;
var dateFormat = this.formatDate(record.data.updated);
var author = (record.data.author.name !== undefined) ? record.data.author.name : "";
var authorEmail = (record.data.author.email !== undefined) ? record.data.author.email : "";
var res = "";
if (link !== undefined && link !== "") {
res = String.format('<div class="topic"><a href="{0}" title="{1}" target="_blank"><span class="rss_feed_title">{2}</span></a><br/><span class="author">{3}</span></div>', link, value,
xf.ellipsis(xf.stripTags(value), 30), author);
} else {
res = String.format('<div class="topic"><span class="rss_feed_title">{0}</span><br/><span class="author">{1}</span></div>', xf.ellipsis(xf.stripTags(value), 30), author);
}
if (dateFormat != "" && dateFormat != undefined ){
res += String.format('<p id="feeds-date">{0}</p>', dateFormat);
}
return res;
},
imageRenderer : function (value, p, record) {
if (Ext.isEmpty(value) || Ext.isEmpty(value.href)) {
return "";
}
if (value.type.substr(0, 5) != "image") {
return "";
}
return String.format('<img src="{0}" width="50px">', value.href);
},
sortByDate : function (direction){
this.storeFeedsRecords.sort('pubDate', direction);
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n,document*/
Ext.namespace('sitools.widget');
/**
* @param urlFeed :
* The feed URL
*/
sitools.widget.feedItemDetails = Ext.extend(Ext.Panel, {
initComponent : function () {
this.layout = "fit";
var record = this.record;
if (!Ext.isEmpty(record)) {
this.store = new Ext.data.JsonStore({
idProperty: 'title',
fields: [
{name : 'title'},
{name : 'pubDate', type: 'date', dateFormat: 'timestamp'},
{name : 'published', type: 'date', dateFormat: 'timestamp'},
{name : 'author'},
{name : 'link'},
{name : 'description'},
{name : 'imageUrl'},
{name : 'image'}
],
listeners : {
scope : this,
add : function (store, records, ind){
if (record.data.imageUrl == undefined && record.data.image != undefined){
record.data.image = record.data.imageUrl;
}
if (records[0].data.pubDate != ""){
records[0].data.pubDate = this.formatDate(records[0].data.pubDate);
}
}
}
});
this.store.add(record);
this.tpl = new Ext.XTemplate(
'<tpl for=".">',
'<div class="feed-article">',
'<tpl if="this.isDisplayable(imageUrl)">',
'<div class="feed-img">',
'<img src="{imageUrl}" title="{title}" width="70" height="70"/>',
'</div>',
'</tpl>',
'<p class="feed-title"> {title} </p>',
'<tpl if="this.isDisplayable(pubDate)">',
'<div class="feed-date-detail">',
'<b> Date : </b> {pubDate} ',
'</div>',
'</tpl>',
'<tpl if="this.isDisplayable(author)">',
'<div class="feed-author">',
'<b> Author : </b> {author} ',
'</div>',
'</tpl>',
'<div class="feed-description">',
'{description}',
'</div>',
'<div class="feed-complementary">',
'<p style="padding-bottom: 3px;"> <b> Link : </b> <a href="{link}" target="_blank" title="{title}">{link}</a> </p>',
'<tpl if="this.isDisplayable(imageUrl)">',
'<p> <b> Image Url : </b> <a href="{imageUrl}" target="_blank">{imageUrl}</a> </p>',
'</tpl>',
'</div>',
'</div>',
'</tpl>',
{
compiled : true,
isDisplayable : function (item) {
if (item != "" && item != undefined){
return true;
}
else {
return false;
}
}
}
);
this.feedsDataview = new Ext.DataView({
id: 'detailFeed-view',
autoScroll : true,
layout: 'fit',
store : this.store,
tpl : this.tpl,
cls : 'detailFeed-view',
emptyText: i18n.get('label.nothingToDisplay')
});
this.componentType = 'feedDetails';
this.items = [ this.feedsDataview ];
}
sitools.widget.feedItemDetails.superclass.initComponent.call(this);
},
formatDate : function (date) {
if (!date) {
return '';
}
var now = new Date();
var d = now.clearTime(true);
if (date instanceof Date){
var notime = date.clearTime(true).getTime();
if (notime == d.getTime()) {
return 'Today ' + date.dateFormat('g:i a');
}
d = d.add('d', -6);
if (d.getTime() <= notime) {
return date.dateFormat('D g:i a');
}
return date.dateFormat('n/j g:i a');
}
else {
return date;
}
},
/**
* Method called when trying to show this component with fixed navigation
*
* @param {sitools.user.component.viewDataDetail} me the dataDetail view
* @param {} config config options
* @returns
*/
showMeInFixedNav : function (me, config) {
Ext.apply(config.windowSettings, {
width : config.windowSettings.winWidth || DEFAULT_WIN_WIDTH,
height : config.windowSettings.winHeight || DEFAULT_WIN_HEIGHT
});
SitoolsDesk.openModalWindow(me, config);
},
/**
* Method called when trying to show this component with Desktop navigation
*
* @param {sitools.user.component.viewDataDetail} me the dataDetail view
* @param {} config config options
* @returns
*/
showMeInDesktopNav : function (me, config) {
Ext.apply(config.windowSettings, {
width : config.windowSettings.winWidth || DEFAULT_WIN_WIDTH,
height : config.windowSettings.winHeight || DEFAULT_WIN_HEIGHT
});
SitoolsDesk.openModalWindow(me, config);
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext,window*/
function utils_logout() {
Ext.util.Cookies.set('userLogin', '');
Ext.util.Cookies.set('hashCode', '');
Ext.Ajax.defaultHeaders.Authorization = '';
window.location.reload();
}
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, ID, i18n, document, showResponse, alertFailure, locale, ImageChooser,
showHelp, loadUrl*/
Ext.namespace('sitools.user.desktop.navProfile');
/**
* Object to expose methods in desktop Mode
* @class sitools.user.desktop.navProfile.desktop
*
*/
sitools.user.desktop.navProfile.desktop = {
/**
* The name of the context
*/
context : "desktop",
/**
* method called by SitoolsDesk.
* It should create all components in Sitools except modules.
* the default comportement is create a new window in desktop and add a taskButton in desktop TaskBar
* @cfg {} componentCfg the component Configuration.
* @cfg {} windowSettings the window Settings
* @cfg {boolean} reloadComp true to rebuild component if exists
* @cfg {string} JsObj The jsObject to instanciate.
*/
createComponent : function (config) {
var desktop = getDesktop();
var componentCfg = config.componentCfg;
var component = new config.JsObj(componentCfg);
var windowSettings = config.windowSettings;
//déléguer au composant l'ouverture
if (Ext.isFunction(component.showMeInDesktopNav)) {
component.showMeInDesktopNav(component, config);
return;
}
var reloadComp = config.reloadComp;
if (Ext.isEmpty(component._getSettings)) {
component._getSettings = function () {
return {};
};
}
var newwin;
var winHeight = windowSettings.winHeight || DEFAULT_WIN_HEIGHT;
var winWidth = windowSettings.winWidth || DEFAULT_WIN_WIDTH;
var x = windowSettings.x;
var y = windowSettings.y;
var desktopEl = getDesktop().getDesktopEl();
if (x < desktopEl.dom.offsetLeft) {
x = desktopEl.dom.offsetLeft;
}
if (y < desktopEl.dom.offsetTop) {
y = desktopEl.dom.offsetTop;
}
if (x + winWidth > desktopEl.dom.offsetLeft + desktopEl.dom.offsetWidth) {
winWidth = desktopEl.dom.offsetLeft + desktopEl.dom.offsetLeft - x;
}
if (y + winHeight > desktopEl.dom.offsetTop + desktopEl.dom.offsetHeight) {
winHeight = desktopEl.dom.offsetTop + desktopEl.dom.offsetHeight - y;
}
var tbar;
if (!Ext.isEmpty(windowSettings.toolbarItems)) {
// Create the toolbar with the windowSettings.toolbarItems
tbar = new Ext.Toolbar({
xtype : 'toolbar',
items : windowSettings.toolbarItems
});
}
var fileName = "";
var title = windowSettings.title;
if (windowSettings.type === "form") {
fileName = windowSettings.type + componentCfg.formName;
}
else if (windowSettings.type === "data" && Ext.isDefined(component.getWindowTitle)) {
title = component.getWindowTitle(windowSettings.datasetDescription, windowSettings.datasetName);
}
else {
fileName = windowSettings.type;
}
newwin = desktop.createWindow({
id : windowSettings.id,
stateful : false,
title : title,
width : winWidth,
iconCls : windowSettings.iconCls,
height : winHeight,
shim : false,
tbar : tbar,
animCollapse : false,
x : x,
y : y,
constrainHeader : true,
layout : 'fit',
specificType : 'componentWindow',
datasetName : windowSettings.datasetName,
datasetDescription : windowSettings.datasetDescription,
fileName : fileName,
component : component,
autoscroll : true,
typeWindow : windowSettings.type,
maximized : windowSettings.maximized,
listeners : {
render : function (me){
me.getEl().fadeIn({
duration: .5
});
}
},
tools : [ {
id : "save",
scope : this,
qtip : i18n.get('label.saveSettings'),
handler : function (event, toolEl, window) {
if (projectGlobal.isAdmin) {
var ctxMenu = new Ext.menu.Menu({
items: ['<b class="menu-title">' + i18n.get('label.chooseSave') + '</b>',
{
text: i18n.get("label.myself"),
handler : function () {
window.saveSettings(window.component._getSettings(), false);
}
}, {
text: i18n.get("label.publicUser"),
handler : function () {
window.saveSettings(window.component._getSettings(), true);
}
}]
});
ctxMenu.showAt(event.getXY());
}
else {
window.saveSettings(window.component._getSettings());
}
},
hidden : Ext.isEmpty(userLogin) || !windowSettings.saveToolbar
} ]
});
var pos, size;
pos = windowSettings.position;
size = windowSettings.size;
if (size !== null) {
size = Ext.decode(size);
newwin.setSize(size);
}
else {
size = newwin.getSize();
size.width = size.width + 1;
newwin.setSize(size);
}
newwin.show();
newwin.add(component);
if (!Ext.isEmpty(pos)) {
pos = Ext.decode(pos);
newwin.setPosition(pos);
}
// Permet d'ajuster les fenêtres qui sont maximisées à l'espace du bureau
if (SitoolsDesk.desktopMaximizeMode) {
SitoolsDesk.getDesktop().minimize();
SitoolsDesk.getDesktop().maximize();
}
else {
SitoolsDesk.getDesktop().maximize();
SitoolsDesk.getDesktop().minimize();
}
newwin.doLayout();
},
/**
* method called by SitoolsDesk.
* It should create all modules in Sitools.
* the default comportement is create a new window in desktop.
* @param {} The module description
* @returns {Ext.app.Module} the created window.
*/
openModule : function (module) {
var desktop = getDesktop();
var win = desktop.getWindow(module.id);
if (!win) {
win = desktop.createWindow({
id : module.id,
stateful : false,
title : i18n.get(module.title),
width : module.defaultWidth,
height : module.defaultHeight,
iconCls : module.icon,
x : module.x,
y : module.y,
shim : false,
animCollapse : false,
constrainHeader : true,
layout : 'fit',
specificType : "moduleWindow",
listeners : {
render : function (me){
me.getEl().fadeIn({
duration: .5
});
}
},
items : [ {
id : module.id + "_module",
noBorder : true,
layout : 'fit',
xtype : module.xtype,
moduleProperties : module.properties,
listProjectModulesConfig : module.listProjectModulesConfig
} ]
});
if (!Ext.isEmpty(projectGlobal.preferences)) {
Ext.each(projectGlobal.preferences.windowSettings, function (preference) {
if (preference.windowSettings.moduleId == module.id) {
if (preference.windowSettings.maximized) {
win.minimize();
win.maximize();
}
else {
var pos = preference.windowSettings.position;
var size = preference.windowSettings.size;
if (pos !== null && size !== null) {
pos = Ext.decode(pos);
size = Ext.decode(size);
win.setPosition(pos);
win.setSize(size);
}
}
}
});
}
} else {
desktop.getManager().bringToFront(win);
}
win.show();
return win;
},
/**
* Do nothing in fixed mode
*/
initNavbar : function (){
return;
},
/**
* Specific multiDataset search context methods
*/
multiDataset : {
/**
* Returns the right object to show multiDs results
* @returns
*/
getObjectResults : function () {
return sitools.user.component.forms.resultsProjectForm;
},
/**
* Handler of the button show data in the {sitools.user.component.forms.resultsProjectForm} object
* @param {Ext.grid.GridPanel} grid the grid results
* @param {int} rowIndex the index of the clicked row
* @param {int} colIndex the index of the column
* @returns
*/
showDataset : function (grid, rowIndex, colIndex) {
var rec = grid.getStore().getAt(rowIndex);
if (Ext.isEmpty(rec)) {
return;
}
if (rec.get('status') == "REQUEST_ERROR") {
return;
}
sitools.user.clickDatasetIcone(rec.get("url"), "data", {
formMultiDsParams : this.formMultiDsParams
});
}
},
taskbar : {
getContextMenuItems : function () {
return [ {
text : 'Restore',
handler : function () {
if (!this.win.isVisible()) {
this.win.show();
} else {
this.win.restore();
}
},
scope : this
}, {
text : 'Minimize',
handler : this.win.minimize,
scope : this.win
}, {
text : 'Maximize',
handler : this.win.maximize,
scope : this.win
}, '-', {
text : 'Close',
handler : this.closeWin.createDelegate(this, this.win, true),
scope : this.win
} ];
},
handleTaskButton : function (btn) {
var win = btn.win;
if (win.minimized || win.hidden) {
win.show();
} else if (win == win.manager.getActive()) {
win.minimize();
} else {
win.toFront();
}
},
closeWin : function (cMenu, e, win) {
if (!win.isVisible()) {
win.show();
} else {
win.restore();
}
win.close();
},
beforeShowCtxMenu : function () {
var items = this.cmenu.items.items;
var w = this.win;
items[0].setDisabled(w.maximized !== true && w.hidden !== true);
items[1].setDisabled(w.minimized === true);
items[2].setDisabled(w.maximized === true || w.hidden === true);
},
/**
* Add home and remove panel button to taskbar in desktop mode
*/
initTaskbar : function (){
SitoolsDesk.getDesktop().taskbar.setEnableWarning(false);
var showDesktopButton = new Ext.Button({
action : "minimize",
handler : function (btn) {
if (btn.action === "minimize") {
SitoolsDesk.minifyAllWindows();
btn.action = "maximize";
}
else {
SitoolsDesk.openAllWindows();
btn.action = "minimize";
}
},
scale : "medium",
tooltip : {
html : i18n.get("label.showDesktopButton"),
anchor : 'bottom',
trackMouse : false
},
template : new Ext.Template('<table cellspacing="0" class="x-btn {3}"><tbody><tr>',
'<td><em class="{5} unselectable="on">',
'<button type="{1}" id="btn-showDesk" style="height:29px; width:18px;">{0}</button>', '</em></td>',
'<td><i> </i></td>', "</tr></tbody></table>")
});
var removeActivePanel = new Ext.Button({
scope : this,
handler : function () {
SitoolsDesk.removeAllWindows();
},
scale : "medium",
icon : "/sitools/common/res/images/taskbar/black/close-icon.png",
iconCls : 'taskbarButtons-icon',
tooltip : {
html : i18n.get('label.removeActiveModule'),
anchor : 'bottom',
trackMouse : false
},
template : new Ext.Template('<table cellspacing="0" class="x-btn {3}" style="padding-left: 25px;"><tbody><tr>',
'<td><i> </i></td>',
'<td><em class="{5} unselectable="on">',
'<button type="{1}" style="height:28px; width:28px; padding-left:12px;">{0}</button>', '</em></td>',
'<td><i> </i></td>', "</tr></tbody></table>")
});
SitoolsDesk.getDesktop().taskbar.staticButtonPanel.addStaticButton(showDesktopButton);
SitoolsDesk.getDesktop().taskbar.staticButtonPanel.addStaticButton(removeActivePanel);
}
},
/**
* @return the specific JS View to display form
*/
getFormOpenMode : function (){
return sitools.user.component.forms.mainContainer;
},
/**
* @return the specific JS View to display dataset
*/
getDatasetOpenMode : function (dataset){
return dataset.datasetView.jsObject;
},
/**
* @param componentCfg
* the component to add the property
* @param dataset
* the object which contains properties to add
* @return the component with the new properties
*/
addSpecificFormParameters : function (componentCfg, dataset){
return componentCfg;
},
/**
* Add specifics columns to project graph module
* in function of the navigation mode
*
* @param columnsModel
* the columns to display in project graph module
* @return the coumns with specifics columns added (or not)
*/
manageProjectGraphColumns : function (columnsModel) {
return columnsModel.push({
width : 70,
header : i18n.get("label.forms"),
//cls : "grid-column-color",
tpl : new Ext.XTemplate('{[datasetId=""]}', '<tpl if="this.exists(datasetId) && authorized==\'true\'">{url:this.getIcone}</tpl>', {
exists : function (o) {
return typeof o !== 'undefined' && o !== null && o !== '';
},
getIcone : function (value) {
return "<a href='#' onClick='sitools.user.clickDatasetIcone(\"" + value
+ "\", \"forms\"); return false;'><img src='" + loadUrl.get('APP_URL')
+ "/common/res/images/icons/form_list_small.png'></a>";
},
// XTemplate configuration:
compiled : true,
disableFormats : false
}),
align : 'center'
});
},
/**
* Add icon form to datasetView Album depending to navigation mode
*
* @param value
* @return nu
*/
manageDatasetViewAlbumIconForm : function (value){
return "<a href='#' onClick='sitools.user.clickDatasetIcone(\"" + value
+ "\", \"forms\"); return false;'><img src='" + loadUrl.get('APP_URL')
+ "/common/res/images/icons/32x32/form_list_32.png'></a>";
},
/**
* Add icon definition and form to dataset Explorer depending to navigation mode
* @param commonTreeUtils
*/
manageDatasetExplorerShowDefinitionAndForms : function (commonTreeUtils, node, dataset){
commonTreeUtils.addShowDefinition(node, dataset);
commonTreeUtils.addForm(node, dataset);
return commonTreeUtils;
},
/**
* Called when desktop is saved.
* Loop through all windows of the desktop and save settings for each window.
* @param forPublicUser
* @returns {Array} an Array containing all window settings
*/
getDesktopSettings : function (forPublicUser) {
var desktopSettings = [];
getDesktop().getManager().each(function (window) {
var componentSettings;
if (!Ext.isEmpty(window.specificType) && (window.specificType === 'componentWindow' || window.specificType === 'moduleWindow')) {
//Bug 3358501 : add a test on Window.saveSettings.
if (Ext.isFunction(window.saveSettings)) {
var component = window.get(0);
componentSettings = component._getSettings();
desktopSettings.push(window.saveSettings(componentSettings, forPublicUser));
}
}
});
return desktopSettings;
},
/**
* Load the module Window corresponding to the project Preference.
* 1 - load the module Windows
* 2 - load the Component windows (actually only "data", "form" && "formProject" type window)
*/
loadPreferences : function (scope) {
//Chargement des composants ouverts.
Ext.each(projectGlobal.preferences.windowSettings, function (pref) {
//1° cas : les fenêtres de modules
if (Ext.isEmpty(pref.windowSettings.typeWindow)) {
var moduleId = pref.windowSettings.moduleId;
var module = SitoolsDesk.app.getModule(moduleId);
if (!Ext.isEmpty(module) && Ext.isEmpty(module.divIdToDisplay)) {
var win = module.openModule();
var pos = pref.windowSettings.position;
var size = pref.windowSettings.size;
if (pos !== null && size !== null) {
pos = Ext.decode(pos);
size = Ext.decode(size);
win.setPosition(pos[0], pos[1]);
win.setSize(size);
}
}
}
//les autres fenêtres : on nne traite que les cas windowSettings.typeWindow == "data"
else {
var type = pref.windowSettings.typeWindow;
var componentCfg, jsObj, windowSettings;
if (type === "data") {
var datasetUrl = pref.componentSettings.datasetUrl;
Ext.Ajax.request({
method : "GET",
url : datasetUrl,
success : function (ret) {
var Json = Ext.decode(ret.responseText);
if (showResponse(ret)) {
var dataset = Json.dataset;
var componentCfg, javascriptObject;
var windowConfig = {
datasetName : dataset.name,
datasetDescription : dataset.description,
type : type,
saveToolbar : true,
toolbarItems : [],
iconCls : "dataviews"
};
javascriptObject = eval(dataset.datasetView.jsObject);
//add the toolbarItems configuration
Ext.apply(windowConfig, {
id : type + dataset.id
});
if (dataset.description !== "") {
windowConfig.title = dataset.description;
}
else {
windowConfig.title = "Diplay data :" + dataset.name;
}
componentCfg = {
dataUrl : dataset.sitoolsAttachementForUsers,
datasetId : dataset.id,
datasetCm : dataset.columnModel,
datasetName : dataset.name,
datasetViewConfig : dataset.datasetViewConfig,
dictionaryMappings : dataset.dictionaryMappings,
preferencesPath : "/" + dataset.name,
preferencesFileName : "datasetView"
};
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, javascriptObject);
}
},
failure : alertFailure
});
}
if (type === "formProject") {
jsObj = sitools.user.component.forms.projectForm;
componentCfg = {
formId : pref.componentSettings.formId,
formName : pref.componentSettings.formName,
formParameters : pref.componentSettings.formParameters,
formWidth : pref.componentSettings.formWidth,
formHeight : pref.componentSettings.formHeight,
formCss : pref.componentSettings.formCss,
properties : pref.componentSettings.properties,
urlServicePropertiesSearch : pref.componentSettings.urlServicePropertiesSearch,
urlServiceDatasetSearch : pref.componentSettings.urlServiceDatasetSearch,
preferencesPath : pref.componentSettings.preferencesPath,
preferencesFileName : pref.componentSettings.preferencesFileName
};
windowSettings = {
type : "formProject",
title : i18n.get('label.forms') + " : " + pref.componentSettings.formName,
id : "formProject" + pref.componentSettings.formId,
saveToolbar : true,
datasetName : pref.componentSettings.formName,
winWidth : 600,
winHeight : 600,
iconCls : "form"
};
SitoolsDesk.addDesktopWindow(windowSettings, componentCfg, jsObj);
}
if (type === "form") {
jsObj = sitools.user.component.forms.mainContainer;
componentCfg = {
dataUrl : pref.componentSettings.dataUrl,
dataset : pref.componentSettings.dataset,
formId : pref.componentSettings.formId,
formName : pref.componentSettings.formName,
formParameters : pref.componentSettings.formParameters,
formWidth : pref.componentSettings.formWidth,
formHeight : pref.componentSettings.formHeight,
formCss : pref.componentSettings.formCss,
preferencesPath : pref.componentSettings.preferencesPath,
preferencesFileName : pref.componentSettings.preferencesFileName
};
// Si mode de navigation fixe, on ouvre la vue composite form + description
if (projectGlobal.navigationMode == "fixed"){
jsObj = sitools.user.component.DatasetOverview;
componentCfg.sitoolsAttachementForUsers = dataset.sitoolsAttachementForUsers;
}
windowSettings = {
datasetName : pref.componentSettings.dataset.name,
type : "form",
title : i18n.get('label.forms') + " : " + pref.componentSettings.dataset.name + "." + pref.componentSettings.formName,
id : "form" + pref.componentSettings.dataset.id + pref.componentSettings.formId,
saveToolbar : true,
iconCls : "form"
};
SitoolsDesk.addDesktopWindow(windowSettings, componentCfg, jsObj);
}
}
}, scope);
}
};
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, ID, i18n, document, showResponse, alertFailure, locale, ImageChooser,
showHelp, loadUrl*/
Ext.namespace('sitools.user.desktop.navProfile');
/**
* Object to expose methods in fixed Mode
* @class sitools.user.desktop.navProfile.fixed
*
*/
sitools.user.desktop.navProfile.fixed = {
/**
* The name of the context
*/
context : "fixed",
/**
* method called by SitoolsDesk.
* It should create all components in Sitools except modules.
* the default comportement is create a new panel in desktop.
* @cfg {} componentCfg the component Configuration.
* @cfg {} windowSettings the window Settings (contains the title)
* @cfg {boolean} reloadComp not used in this context
* @cfg {string} JsObj The jsObject to instanciate.
*/
createComponent : function (config) {
var component = new config.JsObj(config.componentCfg);
var windowSettings = config.windowSettings;
//déléguer au composant l'ouverture
if (Ext.isFunction(component.showMeInFixedNav)) {
component.showMeInFixedNav(component, config);
return;
}
SitoolsDesk.removeActivePanel();
var desktop = getDesktop();
var desktopEl = desktop.getDesktopEl();
Ext.apply(component, {
height : desktopEl.getHeight()
});
desktop.activePanel = desktop.createPanel({
title : windowSettings.title,
border : false,
// cls : "sitools-module-panel",
layout : 'fit',
height : desktop.getDesktopEl().getHeight(),
width : desktop.getDesktopEl().getWidth(),
iconCls : windowSettings.iconCls,
renderTo : desktop.getDesktopEl(),
noBorder : true,
items : [component],
listeners : {
render : function (me){
me.getEl().fadeIn({
duration: .5
});
},
resizeDesktop : function (me) {
me.setSize(desktop.getDesktopEl().getSize());
var child = me.items.items[0];
if (child && child.getEl()) {
child.fireEvent("resize", child, me.body.getWidth(), me.body.getHeight(), child.getWidth(), child.getHeight());
}
},
maximizeDesktop : function (me) {
me.fireEvent("resize", me);
},
minimizeDesktop : function (me) {
me.fireEvent("resize", me);
}
}
});
// SitoolsDesk.addToHistory(desktop.activePanel);
},
/**
* method called by SitoolsDesk.
* It should create all modules in Sitools.
* the default comportement is create a new panel in desktop.
* @param {} The module description
* @returns {Ext.app.Module} the created panel.
*/
openModule : function (module) {
var desktop = getDesktop();
SitoolsDesk.removeActivePanel();
//Minimiser toutes les fenêtres actives ou les détruire si elles ne peuvent pas être minimisées.
SitoolsDesk.minifyAllWindows();
var panelToOpen = Ext.getCmp(module.id);
if (panelToOpen) {
panelToOpen.setSize(SitoolsDesk.getDesktop().getDesktopEl().getSize());
SitoolsDesk.getDesktop().activePanel = panelToOpen;
panelToOpen.show();
return;
}
desktop.activePanel = desktop.createPanel({
id : module.id,
border : false,
title : i18n.get(module.title),
cls : "sitools-module-panel",
layout : 'fit',
specificType : "module",
iconCls : module.icon,
height : desktop.getDesktopEl().getHeight(),
width : desktop.getDesktopEl().getWidth(),
renderTo : desktop.getDesktopEl(),
noBorder : true,
items : [ {
noBorder : true,
layout : 'fit',
xtype : module.xtype,
moduleProperties : module.properties,
listProjectModulesConfig : module.listProjectModulesConfig
}],
listeners : {
render : function (me){
me.getEl().fadeIn({
duration: .5
});
},
resizeDesktop : function (me) {
me.setSize(desktop.getDesktopEl().getSize());
var child = me.items.items[0];
if (child && child.getEl()) {
child.fireEvent("resize", child, me.body.getWidth(), me.body.getHeight(), child.getWidth(), child.getHeight());
}
},
maximizeDesktop : function (me) {
me.fireEvent("resize", me);
},
minimizeDesktop : function (me) {
me.fireEvent("resize", me);
}
}
});
// SitoolsDesk.addToHistory(desktop.activePanel);
return desktop.activePanel;
},
/**
* Specific multiDataset search context methods
*/
multiDataset : {
/**
* Returns the right object to show multiDs results
* @returns
*/
getObjectResults : function () {
return sitools.user.component.forms.overviewResultsProjectForm;
},
/**
* Handler of the button show data in the {sitools.user.component.forms.resultsProjectForm} object
* @param {Ext.grid.GridPanel} grid the grid results
* @param {int} rowIndex the index of the clicked row
* @param {int} colIndex the index of the column
* @returns
*/
showDataset : function (grid, rowIndex, colIndex) {
var rec = grid.getStore().getAt(rowIndex);
if (Ext.isEmpty(rec)) {
return;
}
if (rec.get('status') == "REQUEST_ERROR") {
return;
}
Ext.Ajax.request({
method : "GET",
url : rec.get('url'),
scope : this,
success : function (ret) {
var Json = Ext.decode(ret.responseText);
if (showResponse(ret)) {
var dataset = Json.dataset;
var componentCfg, JsObj;
JsObj = eval(dataset.datasetView.jsObject);
componentCfg = {
title : dataset.name,
closable : true,
dataUrl : dataset.sitoolsAttachementForUsers,
datasetId : dataset.Id,
datasetCm : dataset.columnModel,
datasetName : dataset.name,
dictionaryMappings : dataset.dictionaryMappings,
datasetViewConfig : dataset.datasetViewConfig,
sitoolsAttachementForUsers : dataset.sitoolsAttachementForUsers,
formMultiDsParams : this.formMultiDsParams
};
var dataview = new JsObj(componentCfg);
this.ownerCt.southPanel.add(dataview);
this.ownerCt.southPanel.setVisible(true);
this.ownerCt.southPanel.expand();
this.ownerCt.southPanel.setActiveTab(this.ownerCt.southPanel.items.length - 1);
this.ownerCt.doLayout();
}
},
failure : alertFailure
});
}
},
taskbar : {
getContextMenuItems : function () {
return [ {
text : 'Close',
handler : this.closeWin.createDelegate(this, this.win, true),
scope : this.win
} ];
},
handleTaskButton : function (btn, event) {
var panel = btn.win;
SitoolsDesk.removeActivePanel();
panel.setSize(SitoolsDesk.getDesktop().getDesktopEl().getSize());
SitoolsDesk.getDesktop().activePanel = panel;
panel.show();
},
closeWin : function (cMenu, e, win) {
var tb = getDesktop().taskbar;
if (getDesktop().activePanel == win) {
SitoolsDesk.removeActivePanel();
}
var btn = win.taskButton;
var btnToActive = tb.getPreviousBtn(btn) || tb.getNextBtn(btn);
if (btnToActive) {
SitoolsDesk.navProfile.taskbar.handleTaskButton.call(this, btnToActive);
}
win.destroy();
tb.removeTaskButton(btn);
},
beforeShowCtxMenu : function () {
return true;
},
initTaskbar : function (){
SitoolsDesk.getDesktop().taskbar.setEnableWarning(true);
var removeActivePanel = new Ext.Button({
scope : this,
handler : function () {
var btns = SitoolsDesk.getDesktop().taskbar.getAllTaskButtons();
if (Ext.isEmpty(btns)) {
var tmp = new Ext.ux.Notification({
iconCls : 'x-icon-information',
title : i18n.get('label.information'),
html : i18n.get("label.desktopAlreadyEmpty"),
autoDestroy : true,
hideDelay : 1000
}).show(document);
return;
}
Ext.each(btns, function (btn) {
SitoolsDesk.navProfile.taskbar.closeWin(null, null, btn.win);
});
},
scale : "medium",
icon : "/sitools/common/res/images/taskbar/black/close-icon.png",
iconCls : 'taskbarButtons-icon',
tooltip : {
html : i18n.get('label.removeAllPanels'),
anchor : 'bottom',
trackMouse : false
},
template : new Ext.Template('<table cellspacing="0" style="padding-right:0px;" class="x-btn {3}"><tbody><tr>',
'<td><i> </i></td>',
'<td><em class="{5} unselectable="on">',
'<button type="{1}" style="height:28px; width:28px;">{0}</button>', '</em></td>',
'<td><i> </i></td>', "</tr></tbody></table>")
});
var previous = new Ext.Button({
scope : this,
handler : function () {
var tb = SitoolsDesk.getDesktop().taskbar;
var activeBtn = tb.getActiveButton();
var btnToActive = tb.getPreviousBtn(activeBtn);
if (btnToActive) {
SitoolsDesk.navProfile.taskbar.handleTaskButton.call(this, btnToActive);
}
},
scale : "medium",
icon : "/sitools/common/res/images/taskbar/black/arrow-left-black.png",
iconCls : 'taskbarButtons-icon',
tooltip : {
html : i18n.get('label.previous'),
anchor : 'bottom',
trackMouse : false
},
template : new Ext.Template('<table cellspacing="0" style="padding-right:0px;" class="x-btn {3}"><tbody><tr>',
'<td><i> </i></td>',
'<td><em class="{5} unselectable="on">',
'<button type="{1}" style="height:28px; width:28px;">{0}</button>', '</em></td>',
'<td><i> </i></td>', "</tr></tbody></table>")
});
var next = new Ext.Button({
scope : this,
handler : function () {
var tb = SitoolsDesk.getDesktop().taskbar;
var activeBtn = tb.getActiveButton();
var btnToActive = tb.getNextBtn(activeBtn);
if (btnToActive) {
SitoolsDesk.navProfile.taskbar.handleTaskButton.call(this, btnToActive);
}
},
scale : "medium",
icon : "/sitools/common/res/images/taskbar/black/arrow-right-black.png",
iconCls : 'taskbarButtons-icon',
tooltip : {
html : i18n.get('label.next'),
anchor : 'bottom',
trackMouse : false
},
template : new Ext.Template('<table cellspacing="0" style="padding-right:0px;" class="x-btn {3}"><tbody><tr>',
'<td><i> </i></td>',
'<td><em class="{5} unselectable="on">',
'<button type="{1}" style="height:28px; width:28px;">{0}</button>', '</em></td>',
'<td><i> </i></td>', "</tr></tbody></table>")
});
SitoolsDesk.getDesktop().taskbar.staticButtonPanel.addStaticButton(previous);
SitoolsDesk.getDesktop().taskbar.staticButtonPanel.addStaticButton(next);
SitoolsDesk.getDesktop().taskbar.staticButtonPanel.addStaticButton(removeActivePanel);
}
},
/**
* Add home and remove panel button to navbar in fixed mode
*/
initNavbar : function () {
return;
},
/**
* @return the specific JS View to display form
*/
getFormOpenMode : function (){
return sitools.user.component.DatasetOverview;
},
/**
* @return the specific JS View to display dataset
*/
getDatasetOpenMode : function (dataset){
return sitools.user.component.DatasetOverview;
},
/**
* @param componentCfg
* the component to add the property
* @param dataset
* the object which contains properties to add
* @return the component with the new properties
*/
addSpecificFormParameters : function (componentCfg, dataset){
componentCfg.sitoolsAttachementForUsers = dataset.sitoolsAttachementForUsers;
return componentCfg;
},
/**
* Add specifics columns to project graph module
* in function of the navigation mode
*
* @param columnsModel
* the columns to display in project graph module
* @return the coumns with specifics columns added (or not)
*/
manageProjectGraphColumns : function (columnsModel) {
return columnsModel;
},
/**
* Add icon form to datasetView Album depending to navigation mode
*
* @param value
* @return nu
*/
manageDatasetViewAlbumIconForm : function (value){
return null;
return "<a href='#' onClick='sitools.user.clickDatasetIcone(\"" + value
+ "\", \"forms\"); return false;'><img src='" + loadUrl.get('APP_URL')
+ "/common/res/images/icons/form_list_small.png'></a>";
},
/**
* Add icon definition to dataset Explorer depending to navigation mode
* @param commonTreeUtils
*/
manageDatasetExplorerShowDefinitionAndForms : function (commonTreeUtils, node, dataset){
return;
},
/**
* Called when desktop is saved.
* Add the active panel id to the desktopSettings
* @param forPublicUser
* @returns {Array} an array containing the activePanelId.
*/
getDesktopSettings : function (forPublicUser) {
var desktopSettings = [], activePanel = getDesktop().activePanel;
if (activePanel) {
if (activePanel.specificType === 'module') {
desktopSettings.push({
activeModuleId : activePanel.id
});
}
}
return desktopSettings;
},
/**
* Load the module Window corresponding to the project Preference.
* 1 - load the module Windows
*/
loadPreferences : function (scope) {
//Chargement des composants ouverts.
Ext.each(projectGlobal.preferences.windowSettings, function (pref) {
var module = SitoolsDesk.app.getModule(pref.activeModuleId);
if (!Ext.isEmpty(module) && Ext.isEmpty(module.divIdToDisplay)) {
module.openModule();
}
}, scope);
}
};
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global alertFailure, showResponse, loadUrl, showVersion, userPreferences:true, modulesExistants:true, utils_logout, sitools, userStorage, publicStorage, DEFAULT_PREFERENCES_FOLDER,
getDesktop, Ext, window, i18n, SitoolsDesk, userLogin, projectGlobal, createModule, sql2ext, dules, DEFAULT_WIN_HEIGHT, DEFAULT_WIN_WIDTH,
loadPreferences, getConfigAndCreateModule, desktopReady, publicStorage, document, locale*/
/*
* @include "../../../client-public/js/desktop/App.js"
* @include "../../../client-public/js/desktop/Desktop.js"
* @include "../sitoolsProject.js"
*/
/**
* <a href="http://sourceforge.net/tracker/?func=detail&aid=3358501&group_id=531341&atid=2158259">[3358501]</a><br/>
* 2011/08/03 D.Arpin {Some windows did not have saveSettings Method. In this case, don't save this window Settings}
*/
Ext.namespace('Ext.ux', "sitools.user.desktop");
/**
* Main Application of sitools desktop
* When instanciate, it will :
* - build an instance of Ext.app.App ()
* - launch initProject on projectGlobal object.
*
* @requires Ext.app.App
* @class sitools.user.Desktop.App
*/
sitools.user.desktop.App = function() {
/**
* Initialize every modules that should be displayed in a specific Div.
* For each of them, creates a Ext.Panel renderTo the div defined in project administration.
*/
function initModulesDiv(modules) {
Ext.each(projectGlobal.modulesInDiv, function(module) {
var contentEl = Ext.get(module.divIdToDisplay);
if (Ext.isEmpty(contentEl)) {
Ext.Msg.alert(i18n.get('label.error'), String.format(i18n
.get('label.invalidModuleDivId'),
module.name, module.divIdToDisplay));
} else {
module = new Ext.Panel({
id : module.id,
border : false,
cls : "sitools-module-panel",
layout : 'fit',
renderTo : module.divIdToDisplay,
forceLayout : true,
height : contentEl.getHeight(),
width : contentEl.getWidth(),
listProjectModulesConfig : module.listProjectModulesConfig,
items : [{
layout : 'fit',
xtype : module.xtype,
moduleProperties : module.properties
}],
listeners : {
resize : function(me) {
if (module.container) {
me.setSize(Ext.get(module.container).getSize());
}
},
maximizeDesktop : function(me) {
me.hide();
me.doLayout();
},
minimizeDesktop : function(me) {
me.setVisible(true);
me.doLayout();
}
}
});
SitoolsDesk.app.modulesInDiv.push(module);
}
});
}
/**
* Initialize The footer :
* Build a {sitools.user.component.bottom.Bottom}
*/
function initBottom() {
var modules = projectGlobal.modules;
var bottom = new sitools.user.component.bottom.Bottom({
id : "bottomCompId"
});
}
/**
* Initialize The headers :
* Build a {sitools.user.component.entete.Entete} and render it to x-headers div.
*/
function initEntete() {
var entete = new sitools.user.component.entete.Entete({
renderTo : "x-headers",
id : "headersCompId",
htmlContent : projectGlobal.htmlHeader,
modules : projectGlobal.modules,
listeners : {
resize : function(me) {
me.setSize(SitoolsDesk.getEnteteEl().getSize());
}
}
});
}
/**
* <p>Create each module.</p>
* <p>1 - request the project to get All modules defined. </p>
* <p>2 - As callback, create a module for each module of the project.
* In case user is logged, will check if the module is in the preference list, before adding module.</p>
*/
function callbackRESTCreateProject() {
// tableau de modules a passer a l'application
var modules = [];
// Check for user authorization
var isAuthorized = false;
Ext.Ajax.request({
scope : this,
url : projectGlobal.sitoolsAttachementForUsers,
method : 'GET',
success : function(response) {
var data = Ext.decode(response.responseText);
isAuthorized = true;
if (data.project.maintenance) {
desktopReady.call(this);
Ext.get('ux-taskbar').mask();
var alertWindow = new Ext.Window({
title : i18n.get('label.maintenance'),
width : 600,
height : 400,
autoScroll : true,
closable : false,
items : [{
xtype : 'panel',
layout : 'fit',
autoScroll : true,
html : data.project.maintenanceText,
padding : "5"
}],
modal : true
});
alertWindow.show();
return;
}
//we get the configured modules, now we have to create each Module object.
projectGlobal.modules = data.project.modules;
projectGlobal.modulesInDiv = [];
//Mise a l'écart des modules qui s'affichent dnas une div
Ext.each(projectGlobal.modules, function(module) {
if (!Ext.isEmpty(module.divIdToDisplay)) {
projectGlobal.modulesInDiv.push(module);
}
}, this);
SitoolsDesk.modulesACharger = projectGlobal.modules.size();
if (SitoolsDesk.modulesACharger === 0) {
Ext.Msg.alert(i18n.get("label.warning"), i18n
.get("label.noModules"));
SitoolsDesk.fireEvent('allJsIncludesDone', this);
}
getListOfModulesAndCreateModules(projectGlobal.sitoolsAttachementForUsers, projectGlobal.modules);
// TODO : change here loading project modules
// Ext.each(projectGlobal.modules, function(config) {
// getConfigAndCreateModule(config, this);
// SitoolsDesk.modulesACharger++;
// }, this);
},
failure : function(response) {
Ext.get('ux-taskbar').mask();
Ext.Msg.alert('Status', i18n.get('warning.not.authorized'),
function() {
window.location = loadUrl.get('APP_URL')
+ loadUrl.get('APP_CLIENT_USER_URL');
});
return;
}
});
}
/**
* Called on a desktop Resize.
* It will redefine the height and size of desktop Element.
* Fires events for each component so that they can resize according to their container
* Fires event resizeDesktop on activePanel
* Fires event resize on entete and bottom component.
* Fires event resize on each module representation included in a specific Div
*/
function fireResize(newW, newH) {
try {
var desktop = SitoolsDesk.getDesktop();
if (SitoolsDesk.desktopMaximizeMode) {
desktop.getDesktopAndTaskBarEl().setHeight(Ext.getBody()
.getHeight()
- this.getEnteteEl().getHeight());
desktop.getDesktopAndTaskBarEl().setWidth(Ext.getBody()
.getWidth());
desktop.getDesktopEl().setHeight(Ext.getBody().getHeight()
- this.getEnteteEl().getHeight()
- desktop.taskbar.tbPanel.getHeight());
desktop.getDesktopEl().setWidth(Ext.getBody().getWidth());
}
if (!Ext.isEmpty(desktop.activePanel)) {
desktop.activePanel.fireEvent("resizeDesktop",
desktop.activePanel);
}
SitoolsDesk.getEnteteComp().fireEvent("resize",
SitoolsDesk.getEnteteComp(), newW, newH);
SitoolsDesk.getEnteteComp().fireEvent("windowResize",
SitoolsDesk.getEnteteComp(), newW, newH);
SitoolsDesk.getBottomComp().fireEvent("resize",
SitoolsDesk.getBottomComp(), newW, newH);
SitoolsDesk.getBottomComp().fireEvent("windowResize",
SitoolsDesk.getBottomComp(), newW, newH);
for (var int = 0; int < projectGlobal.modulesInDiv.length; int++) {
var module = projectGlobal.modulesInDiv[int];
var panel = Ext.getCmp(module.id);
panel.fireEvent("resize", panel, newW, newH);
}
} catch (err) {
return null;
}
}
/**
* Method called to instanciate the right profile object to get specific methods accdording to the navigation profile.
* @returns
*/
function initNavigationMode() {
if (projectGlobal.navigationMode == "desktop") {
SitoolsDesk.navProfile = sitools.user.desktop.navProfile.desktop;
} else {
SitoolsDesk.navProfile = sitools.user.desktop.navProfile.fixed;
}
}
/**
* Method called on allJsIncludesDone event.
* After that, we are sure that every needed JS is loaded.
* First load the user preferences
*/
function _onAllJsIncludesDone() {
initNavigationMode();
SitoolsDesk.loadPreferences(this);
this.fireEvent('modulesLoaded');
//when preferences are loaded fireEvent Ready.
this.fireEvent('ready');
}
/**
* Method called on moduleLoaded event.
* Add home and remove panel button to taskbar or navbar
* (depending desktop or fixed mode)
*/
function initTaskAndNavBar() {
SitoolsDesk.navProfile.taskbar.initTaskbar();
SitoolsDesk.navProfile.initNavbar();
}
/**
* Called on modulesLoaded event.
* After modules are loaded and built, initialize the headers and footer components
* Load every modules defined to be displayed in a specific div.
*/
function _onModulesLoaded() {
initEntete();
initBottom();
initTaskAndNavBar();
initModulesDiv(projectGlobal.modules);
if (projectGlobal.preferences
&& projectGlobal.preferences.projectSettings
&& projectGlobal.preferences.projectSettings.desktopMaximizeMode) {
getDesktop().maximize();
}
}
/**
* Initialize the project.
* Load sql2Ext settings,
* Call the projectGloabal initProject method
*/
function initProject() {
//Add the app listeners
SitoolsDesk.app.addListener("allJsIncludesDone", _onAllJsIncludesDone);
SitoolsDesk.app.addListener("ready", desktopReady);
SitoolsDesk.app.addListener("modulesLoaded", _onModulesLoaded);
sql2ext.load(loadUrl.get('APP_URL')
+ "/client-user/conf/sql2ext.properties");
//handle windowResize event
Ext.EventManager.onWindowResize(fireResize, SitoolsDesk);
projectGlobal.initProject(callbackRESTCreateProject);
// Ext.QuickTips.init();
// Apply a set of config properties to the singleton
Ext.apply(Ext.QuickTips.getQuickTip(), {
maxWidth : 200,
minWidth : 100,
showDelay : 50,
trackMouse : true
});
}
/**
* Called when deletePrefButton is pressed.
* Remove the public Preferences.
*/
function deletePublicPref() {
publicStorage.remove();
}
/**
* Called when login is pressed.
* Show a {sitools.userProfile.Login} window
*/
function _onLogin() {
var tmp = new sitools.userProfile.Login({
closable : true,
url : loadUrl.get('APP_URL') + '/login',
register : loadUrl.get('APP_URL') + '/inscriptions/user',
reset : loadUrl.get('APP_URL') + '/resetPassword'
}).show();
}
/**
* Called when logout is pressed.
*/
function _onLogout() {
utils_logout();
}
/**
* private
* Create the component according to the componentCfg and JsObj param.
* Uses the navProfile to create either a window or a panel.
*
* @param {} windowSettings
* {string} id (required) : windowId
* {string} title (required) : windowTitle,
* {string} datasetName (required) : datasetName,
* {string} moduleId : String
* {} position : [xpos, ypos]
* {} size : {
* width : w
* height : h
* }
* {string} specificType : sitoolsSpecificType
* [Ext.Button] toolbarItems
* @param {} componentCfg Object containing the configuration
* @param {string} JsObj the name of the Javascript Object used to build the component inside the window
* @param {boolean} reloadComp true to reload the window (only in desktop navigation moede)
* @returns
*/
function addWinData(windowSettings, componentCfg, JsObj, reloadComp) {
var desktop = getDesktop();
var win = desktop.getWindow(windowSettings.id);
if (win) {
if (reloadComp) {
win.removeAll();
win.add(new JsObj(componentCfg));
win.doLayout();
}
if (win.minimized) {
win.show();
}
win.toFront();
return;
}
//Create the component according to the navigation profile.
try {
SitoolsDesk.navProfile.createComponent({
componentCfg : componentCfg,
windowSettings : windowSettings,
reloadComp : reloadComp,
JsObj : JsObj
});
} catch (r) {
Ext.Msg.alert(i18n.get("label.warning"), i18n
.get("label.nocomponentfound"));
throw (r);
}
}
/**
* Unmask desktop Elements
*/
function desktopReady() {
if (Ext.getBody().isMasked()) {
Ext.getBody().unmask();
}
Ext.get("ux-taskbar").setVisible(true);
SitoolsDesk.getEnteteComp().fireEvent("desktopReady",
SitoolsDesk.getEnteteComp());
document.onkeypress = function(event) {
if (event.keyCode == event.DOM_VK_F1) {
// cancel browser app event handler for F1 key
event.stopPropagation()
event.preventDefault()
}
}
}
/**
* Mask all the desktop element.
*/
function maskDesktop() {
Ext.getBody().mask(i18n.get("label.loadingSitools"));
Ext.get("ux-taskbar").hide();
}
/**
* Build a Ext.app.Module according to the config.
* Includes All Css and Js defined in the module configuration.
* Especially defined the default method openModule called to open a Module.
*
* @param {} the module Configuration.
* @returns {Ext.app.Module}
*/
function createModule(config) {
function includeCss(url) {
var headID = document.getElementsByTagName("head")[0];
var newCss = document.createElement('link');
newCss.type = 'text/css';
newCss.rel = 'stylesheet';
newCss.href = url;
newCss.media = 'screen';
// pas possible de monitorer l'evenement onload sur une balise link
headID.appendChild(newCss);
}
function includeJs(ConfUrls, indexAInclure) {
//Test if all inclusions are done for this module
if (indexAInclure < ConfUrls.length) {
// if not : include the Js Script
var DSLScript = document.createElement("script");
DSLScript.type = "text/javascript";
DSLScript.onload = includeJs.createDelegate(this, [ConfUrls,
indexAInclure + 1]);
DSLScript.onreadystatechange = includeJs.createDelegate(this, [
ConfUrls, indexAInclure + 1]);
DSLScript.src = ConfUrls[indexAInclure].url;
var headID = document.getElementsByTagName('head')[0];
headID.appendChild(DSLScript);
} else {
//if all includes are done, Add 1 to the modulesCharges
SitoolsDesk.modulesCharges++;
//test if all modules are loaded.
if (SitoolsDesk.modulesCharges === SitoolsDesk.modulesACharger) {
//End of loading all Javascript files.
SitoolsDesk.app.fireEvent('allJsIncludesDone', this);
}
}
}
var module = new Ext.app.Module(Ext.apply(config, {
init : function() {
// s'il y a des dependances
if (config.dependencies) {
if (config.dependencies.css) {
Ext.each(config.dependencies.css, function(
dependenceCss) {
includeCss(dependenceCss.url);
});
}
if (config.dependencies.js) {
includeJs(config.dependencies.js, 0);
}
} else {
SitoolsDesk.app.modulesCharges++;
}
},
getWindow : function() {
return Ext.getCmp(config.id);
},
openModule : function() {
var desktop = getDesktop();
return SitoolsDesk.navProfile.openModule(module);
}
}));
return module;
}
/**
* Request the module configuration and call createModule method.
* @warning Old version, do not use
*/
function getConfigAndCreateModule(config) {
Ext.Ajax.request({
method : "GET",
url : loadUrl.get('APP_URL')
+ loadUrl.get('APP_PROJECTS_MODULES_URL') + "/" + config.id,
scope : this,
success : function(response) {
var json = Ext.decode(response.responseText);
if (json.success) {
var configModule = Ext.applyIf(config, json.projectModule
|| {});
var module = createModule(configModule);
SitoolsDesk.app.modules.push(module);
} else {
Ext.Msg.alert(i18n.get('label.error'), String.format(i18n
.get('label.undefinedModule'),
config.name));
//if all includes are done, Add 1 to the modulesCharges
SitoolsDesk.modulesCharges++;
//test if all modules are loaded.
if (SitoolsDesk.modulesCharges === SitoolsDesk.modulesACharger) {
//End of loading all Javascript files.
SitoolsDesk.app.fireEvent('allJsIncludesDone', this);
}
}
},
failure : alertFailure
});
}
/**
* Gets the list of modules for the project and creates all the modules
* @recommanded New version of getConfigAndCreateModule
*/
function getListOfModulesAndCreateModules(projectAttachment, configs) {
Ext.Ajax.request({
method : "GET",
url : projectAttachment + "/projectModules",
scope : this,
success : function(response) {
var json = Ext.decode(response.responseText);
Ext.each(json.data, function(projectModule){
var projectConfig = findProjectModuleConfig(configs, projectModule.id);
if (!Ext.isEmpty(projectConfig)) {
var configModule = Ext.applyIf(projectConfig, projectModule || {});
var module = createModule(configModule);
SitoolsDesk.app.modules.push(module);
}
else {
Ext.Msg.alert(i18n.get('label.error'), String.format(i18n
.get('label.undefinedModule'),
config.name));
//if all includes are done, Add 1 to the modulesCharges
SitoolsDesk.modulesCharges++;
//test if all modules are loaded.
if (SitoolsDesk.modulesCharges === SitoolsDesk.modulesACharger) {
//End of loading all Javascript files.
SitoolsDesk.app.fireEvent('allJsIncludesDone', this);
}
}
}, this);
},
failure : alertFailure
});
}
function findProjectModuleConfig(configs, id) {
var configOut;
Ext.each(configs, function(conf){
if(conf.id == id) {
configOut = conf;
return;
}
}, this);
return configOut;
}
/**
* Instanciation of a Ext.app.App object.
* Overrides some methods.
* @returns {Ext.app.App} the application.
*/
function createApplication() {
return new Ext.app.App({
//initialize app
init : function() {
Ext.QuickTips.init();
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
//WTF with IE...
if (Ext.isIE) {
Ext.Msg.confirm(i18n.get('label.warning'), i18n
.get('label.IEWarning'),
function(buttonId) {
if (buttonId === "yes") {
maskDesktop();
initProject();
} else {
window.location
.replace("https://www.google.com/chrome/index.html");
}
});
} else {
maskDesktop();
initProject();
}
},
//overrides getModules
getModules : function() {
return this.modules;
},
//overrides getModulesInDiv
getModulesInDiv : function() {
return this.modulesInDiv;
},
//overrides
findModule : function(moduleId) {
var result;
Ext.each(this.modules.concat(this.modulesInDiv), function(
module) {
if (module.id === moduleId) {
result = module;
}
});
return result;
},
//add some method
saveWindowSettings : function(forPublicUser) {
var desktopSettings = SitoolsDesk.navProfile
.getDesktopSettings();
userPreferences = {};
userPreferences.windowSettings = desktopSettings;
var projectSettings = {};
if (!Ext.isEmpty(SitoolsDesk.getDesktop().activePanel)) {
projectSettings.activeModuleId = SitoolsDesk.getDesktop().activePanel.id;
}
projectSettings.desktopMaximizeMode = SitoolsDesk.desktopMaximizeMode;
userPreferences.projectSettings = projectSettings;
if (forPublicUser) {
publicStorage.set("desktop", "/"
+ DEFAULT_PREFERENCES_FOLDER + "/"
+ projectGlobal.projectName,
userPreferences);
} else {
userStorage.set("desktop", "/" + DEFAULT_PREFERENCES_FOLDER
+ "/" + projectGlobal.projectName,
userPreferences);
}
}
});
}
/**
* Find the portal preferences.
* @param portalPrefCb A method to call after portal Preferences Request.
*/
function getPortalPreferences(portalPrefCb) {
if (!Ext.isEmpty(userLogin)) {
var portalPrefSuccess = function(response) {
if (Ext.isEmpty(response.responseText)) {
return;
}
try {
var json = Ext.decode(response.responseText);
if (!Ext.isEmpty(json.language)) {
this.app.language = json.language;
}
} catch (err) {
return;
}
};
var filePath = "/" + DEFAULT_PREFERENCES_FOLDER + '/portal';
userStorage.get("portal", filePath, this, portalPrefSuccess,
Ext.emptyFn, portalPrefCb);
} else {
portalPrefCb.call(this);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
return {
maxSizeHistory : 5,
history : [],
/**
* the Navigation profile.
*/
navProfile : null,
activeComponent : null,
/**
* True if desktop is maximized, false otherwize
*/
desktopMaximizeMode : false,
/**
* {integer} modulesCharges The number of loaded Modules
*/
modulesCharges : 0,
/**
* {integer} modulesACharger The number of modules to load at start.
*/
modulesACharger : 0,
/**
* the sitools Ext.app.App instance
* @type Ext.app.App
*/
app : this.app,
/**
* Method called to historize the navigation in the desktop.
* @param {} panel The panel to be historized.
* @returns
*/
addToHistory : function(panel) {
panel.rendered = false;
SitoolsDesk.history.push(panel);
},
/**
* The entry Point of SITools application.
* Create the Ext.app.App stored as SitoolsDesk.app.
* Load the context files (loadUrl, i18n, ...)
* After All, call SitoolsDesk.app.initApp() to instanciate an Ext.Desktop.
* @returns
*/
initDesktopApplication : function() {
// START HERE !!!
Ext.QuickTips.init();
if (!Ext.isEmpty(Ext.util.Cookies.get('userLogin'))) {
var auth = Ext.util.Cookies.get('hashCode');
Ext.Ajax.defaultHeaders = {
"Authorization" : auth,
"Accept" : "application/json",
"X-User-Agent" : "Sitools"
};
} else {
Ext.Ajax.defaultHeaders = {
"Accept" : "application/json",
"X-User-Agent" : "Sitools"
};
}
//Instanciation de l'objet Ext.app.App.
this.app = createApplication();
//récupération de la langue contenue dans le cookie, ou à défaut, au niveau du navigateur.
this.app.language = locale.getLocale();
/* Définition des appels en cascade :
* - méthode N°1 : loadUrl.load (Chargements des urls dynamiques)
* - méthode N°2 : getPortalPreferences (Chargement des préférences du portail)
* - méthode N°3 : i18n.load (Chargement du fichier de langue défini)
* - méthode N°4 : projectGlobal.getUserRoles (Récupération du rôle de l'utilisateur)
* - méthode N°5 : SitoolsDesk.app.initApp (Instancie l'objet Ext.Desktop et appel à SitoolsDesk.app.init())
*
*/
var initApplication = function() {
SitoolsDesk.app.initApp();
};
var i18nCb = function() {
projectGlobal.getUserRoles(initApplication);
};
var portalPrefCb = function() {
i18n.load('/sitools/res/i18n/' + SitoolsDesk.app.language
+ '/gui.properties', i18nCb);
};
var callbackSiteMap = function() {
getPortalPreferences(portalPrefCb);
};
loadUrl.load('/sitools/client-user/siteMap', callbackSiteMap);
},
/**
* public dynamically add a new application to the desktop
*
* 1. moduleFactory.createModule
* 2. ajout du module dans le fisheyeMenu
*/
addApplication : function(composant) {
modulesExistants = SitoolsDesk.app.getModules();
if (!modulesExistants) {
modulesExistants = [];
}
var nouveauModule = getConfigAndCreateModule(composant, this);
modulesExistants.push(nouveauModule);
SitoolsDesk.app.addModule(nouveauModule);
},
/**
* public dynamically remove an application from the desktop
*
* On supprime son icone du menu demarrer et du fisheyeMenu ainsi que de
* la liste des modules existants
*/
removeApplication : function(idApplication) {
var moduleToRemove = SitoolsDesk.app.getModule(idApplication);
modulesExistants = SitoolsDesk.app.getModules();
SitoolsDesk.app.removeModule(moduleToRemove);
},
/**
* Load the module Window corresponding to the project Preference.
* 1 - load the module Windows
* 2 - load the Component windows (actually only "data", "form" && "formProject" type window)
*/
loadPreferences : function(scope) {
if (!Ext.isEmpty(projectGlobal.preferences)) {
SitoolsDesk.navProfile.loadPreferences(scope);
}
},
/**
* @method
* public load the preferences for a window if the user is logged and then build the window
*
* @param {} windowSettings Window Settings object build with attributes
* {string} id (required) : windowId
* {string} title (required) : windowTitle,
* {string} type (required if saveToolbar) : the type of the window, will determine the userStorage path
* [forms, data]
* {string} datasetName (required if saveToolbar) : name of the dataset, will determine the userStorage name
* {string} urlPreferences (required if saveToolbar) : the url to request to get the userPreferences
* {boolean} saveToolbar : true if the saveSettings toolbar should be displayed
* default false
*
* @param {} component : the items to add to the Window
* @param {string} JsObj : the name of the Javascript Object used to build the component inside the window
*/
addDesktopWindow : function(windowSettings, component, JsObj,
reloadComp) {
if (Ext.isEmpty(windowSettings.saveToolbar)) {
windowSettings.saveToolbar = false;
}
if (Ext.isEmpty(windowSettings.title)) {
throw ("NoWinTitle");
}
if (Ext.isEmpty(reloadComp)) {
reloadComp = false;
}
//If Window does not have save abilities.
if (windowSettings.saveToolbar === false) {
addWinData(windowSettings, component, JsObj, reloadComp);
return;
}
//construction de l'url pour les préférences utilisateur.
var baseFilePath = "/" + DEFAULT_PREFERENCES_FOLDER + "/"
+ projectGlobal.projectName;
var filePath = component.preferencesPath;
var fileName = component.preferencesFileName;
if (Ext.isEmpty(filePath) || Ext.isEmpty(fileName)) {
addWinData(windowSettings, component, JsObj, reloadComp);
return;
}
filePath = baseFilePath + filePath;
//Méthod to call if no userPreferences found
var addWinPublic = function(windowSettings, component, JsObj,
reloadComp) {
var successPublic = function(response, opts) {
try {
var json = Ext.decode(response.responseText);
Ext.apply(windowSettings, json.windowSettings);
Ext.apply(component, {
userPreference : json.componentSettings
});
addWinData(windowSettings, component, JsObj, reloadComp);
} catch (err) {
addWinData(windowSettings, component, JsObj, reloadComp);
}
};
var failurePublic = function(response, opts) {
addWinData(windowSettings, component, JsObj, reloadComp);
};
publicStorage.get(fileName, filePath, this, successPublic,
failurePublic);
};
if (Ext.isEmpty(userLogin)) {
addWinPublic(windowSettings, component, JsObj, reloadComp);
} else {
//Méthode appelée si l'on trouve des préférences pour le user
var successMethod = function(response, opts) {
try {
var json = Ext.decode(response.responseText);
Ext.apply(windowSettings, json.windowSettings);
Ext.apply(component, {
userPreference : json.componentSettings
});
addWinData(windowSettings, component, JsObj, reloadComp);
} catch (err) {
addWinPublic(windowSettings, component, JsObj,
reloadComp);
}
};
//Si pas de préférences trouvées, on utilise addWinPublic
var failureMethod = function(response, opts) {
addWinPublic(windowSettings, component, JsObj, reloadComp);
};
userStorage.get(fileName, filePath, this, successMethod,
failureMethod);
}
},
/**
* Returns the Ext.Desktop instance.
* @returns {Ext.Desktop}
*/
getDesktop : function() {
return this.app.desktop;
},
/**
* Returns the desktop Header Element.
* @returns {Ext.Element}
*/
getEnteteEl : function() {
return Ext.get('x-headers');
},
/**
* Returns the panel charged of displaying headers of Sitools.
* @returns {sitools.user.component.entete.Entete} The headers component
*/
getEnteteComp : function() {
return Ext.getCmp("headersCompId");
},
/**
* Returns the footer Element.
* @returns {Ext.Element}
*/
getBottomEl : function() {
return Ext.get('x-bottom');
},
/**
* Returns the panel charged of displaying bottom of Sitools.
* @returns {sitools.user.component.bottom.Bottom} The footer component
*/
getBottomComp : function() {
return Ext.getCmp("bottomCompId");
},
/**
* Remove the active Panel in desktop (the module representation incrusted in background of the desktop)
*
*/
removeActivePanel : function() {
if (this.getDesktop().activePanel) {
var panel = this.getDesktop().activePanel;
this.getDesktop().activePanel = null;
panel.hide();
return;
}
},
/**
* Close every window in desktop.
*/
removeAllWindows : function() {
this.getDesktop().getManager().each(function(win) {
win.close();
});
},
/**
* Minify every window in desktop.
*/
minifyAllWindows : function() {
SitoolsDesk.getDesktop().getManager().each(function(win) {
if (Ext.isFunction(win.minimize)) {
win.minimize();
} else {
win.destroy();
}
});
},
/**
* Open and shows all hidden windows that have a taskButton
* @returns
*/
openAllWindows : function() {
SitoolsDesk.getDesktop().getManager().each(function(win) {
if (!win.isVisible() && win.taskButton) {
win.show();
}
});
},
/**
* Open a modal window in the desktop.
* @param {Ext.Panel} panel the component to add to the modal window
* @param {} config a config object containg windowSettings
* @returns
*/
openModalWindow : function(panel, config) {
var windowConfig = config.windowSettings || {};
Ext.apply(windowConfig, {
modal : true,
layout : 'fit'
});
if (!Ext.isEmpty(windowConfig.toolbarItems)) {
Ext.apply(windowConfig, {
tbar : {
items : windowConfig.toolbarItems
},
listeners : {
afterrender : function(me) {
if (me.getHeight() > Ext.getBody()
.getHeight()) {
me.setHeight(Ext.getBody().getHeight());
}
if (me.getWidth() > Ext.getBody()
.getWidth()) {
me.setWidth(Ext.getBody().getWidth());
}
me.doLayout();
}
}
});
}
Ext.applyIf(windowConfig, {
width : DEFAULT_WIN_WIDTH,
height : DEFAULT_WIN_HEIGHT
})
var win = new Ext.Window(windowConfig);
win.show();
win.add(panel);
win.setZIndex(12000);
win.doLayout();
},
/**
* Open the sitools.user.component.help window
* @param {Ext.Button} b The pressed btn
* @param {Ext.event} e the click Event.
* @returns
*/
showHelp : function(b, e) {
var help = Ext.getCmp("helpWindow");
if (!Ext.isEmpty(help)) {
help.show();
help.setZIndex(12000);
return;
}
var componentCfg = {};
help = new sitools.user.component.help();
var config = {};
config.windowSettings = {
id : "helpWindow",
title : i18n.get('label.help'),
saveToolbar : false,
closeAction : 'hide'
};
SitoolsDesk.openModalWindow(help, config);
},
showFormFromEditor : function (formUrl) {
Ext.Ajax.request({
url : formUrl,
method : 'GET',
success : function (response) {
try {
var json = Ext.decode(response.responseText);
if (! json.success) {
Ext.Msg.alert(i18n.get('label.error'), json.message);
return;
}
var rec = {};
rec.data = json.data[0];
Ext.Ajax.request({
url : rec.data.parentUrl,
method : 'GET',
success : function (response) {
try {
var json2 = Ext.decode(response.responseText);
var dataset = json2.dataset;
var jsObj = SitoolsDesk.navProfile.getFormOpenMode();
var componentCfg = {
dataUrl : rec.data.parentUrl,
dataset : dataset,
formId : rec.data.id,
formName : rec.data.name,
formParameters : rec.data.parameters,
formWidth : rec.data.width,
formHeight : rec.data.height,
formCss : rec.data.css,
preferencesPath : "/" + dataset.name + "/forms",
preferencesFileName : rec.data.name
};
SitoolsDesk.navProfile.addSpecificFormParameters(componentCfg, dataset);
var windowSettings = {
datasetName : dataset.name,
type : "form",
title : i18n.get('label.forms') + " : " + dataset.name + "." + rec.data.name,
id : "form" + dataset.id + rec.data.id,
saveToolbar : true,
iconCls : "form"
};
SitoolsDesk.addDesktopWindow(windowSettings, componentCfg, jsObj);
return;
}
catch (err) {
Ext.Msg.alert(i18n.get('label.error'), err);
return;
}
}
});
}
catch (err) {
Ext.Msg.alert(i18n.get('label.error'), err);
return;
}
},
failure : function () {
Ext.Msg.alert(i18n.get('label.error'), i18n.get('label.noActiveDatasetFound'));
return;
}
});
}
};
};
/*******************************************************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* SITools2 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* SITools2. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/*global Ext, sitools, OpenLayers*/
Ext.ns("sitools.user.data");
sitools.user.data.featureReader = Ext.extend(GeoExt.data.FeatureReader, {
totalRecords : null,
/**
* Overrides parent method to call readRecords with entire response (containing the totalRecords)
* @returns
*/
read : function (response) {
return this.readRecords(response);
},
/** api: method[readRecords]
* :param features: ``Array(OpenLayers.Feature.Vector)`` List of
* features for creating records
* :return: ``Object`` An object with ``records`` and ``totalRecords``
* properties.
*
* Create a data block containing :class:`GeoExt.data.FeatureRecord`
* objects from an array of features.
*/
readRecords : function (response) {
var result = sitools.user.data.featureReader.superclass.readRecords.call(this, response.features);
return Ext.apply(result, {
totalRecords : response.totalResults
});
}
});
/*******************************************************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* SITools2 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* SITools2. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/*global Ext, sitools, OpenLayers*/
Ext.ns("sitools.user.data");
sitools.user.data.FormatGeoJson = Ext.extend(OpenLayers.Format.GeoJSON, {
totalProperty : null,
/**
* APIMethod: read
* Deserialize a GeoJSON string.
*
* Parameters:
* json - {String} A GeoJSON string
* type - {String} Optional string that determines the structure of
* the output. Supported values are "Geometry", "Feature", and
* "FeatureCollection". If absent or null, a default of
* "FeatureCollection" is assumed.
* filter - {Function} A function which will be called for every key and
* value at every level of the final result. Each value will be
* replaced by the result of the filter function. This can be used to
* reform generic objects into instances of classes, or to transform
* date strings into Date objects.
*
* Returns:
* {Object} The return depends on the value of the type argument. If type
* is "FeatureCollection" (the default), the return will be an array
* of <OpenLayers.Feature.Vector>. If type is "Geometry", the input json
* must represent a single geometry, and the return will be an
* <OpenLayers.Geometry>. If type is "Feature", the input json must
* represent a single feature, and the return will be an
* <OpenLayers.Feature.Vector>.
*/
read: function (json, type, filter) {
type = (type) ? type : "FeatureCollection";
var results = null;
var obj = null;
if (typeof json == "string") {
obj = OpenLayers.Format.JSON.prototype.read.apply(this,
[json, filter]);
} else {
obj = json;
}
if (!obj) {
OpenLayers.Console.error("Bad JSON: " + json);
} else if (typeof(obj.type) != "string") {
OpenLayers.Console.error("Bad GeoJSON - no type: " + json);
} else if (this.isValidType(obj, type)) {
switch (type) {
case "Geometry" :
try {
results = this.parseGeometry(obj);
} catch (err) {
OpenLayers.Console.error(err);
}
break;
case "Feature":
try {
results = this.parseFeature(obj);
results.type = "Feature";
} catch(err) {
OpenLayers.Console.error(err);
}
break;
case "FeatureCollection":
// for type FeatureCollection, we allow input to be any type
results = [];
switch(obj.type) {
case "Feature":
try {
results.push(this.parseFeature(obj));
} catch(err) {
results = null;
OpenLayers.Console.error(err);
}
break;
case "FeatureCollection":
for(var i=0, len=obj.features.length; i<len; ++i) {
try {
results.push(this.parseFeature(obj.features[i]));
} catch(err) {
results = null;
OpenLayers.Console.error(err);
}
}
break;
default:
try {
var geom = this.parseGeometry(obj);
results.push(new OpenLayers.Feature.Vector(geom));
} catch(err) {
results = null;
OpenLayers.Console.error(err);
}
}
break;
}
}
return {
features : results,
totalResults : obj[this.totalProperty]
};
}
});
/*******************************************************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* SITools2 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* SITools2. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/*global Ext, sitools, OpenLayers*/
Ext.ns("sitools.user.data");
sitools.user.data.ProtocolHttp = function (config) {
sitools.user.data.ProtocolHttp.superclass.constructor.call(this, Ext.apply({
url: config.url,
totalProperty : config.totalProperty,
format: new sitools.user.data.FormatGeoJson({
totalProperty : config.totalProperty
})
}));
};
Ext.extend(sitools.user.data.ProtocolHttp, OpenLayers.Protocol.HTTP, {
/**
* Method: handleResponse
* Overrides the OpenLayers.Protocol.HTTP method :
* As we use a sitools.user.data.FormatGeoJson, the return of parseFeatures will be different :
*
* initial return of this.parseFeatures : Array of features
*
* sitools.user.data.FormatGeoJson return : {
* features : [],
* totalResults : {integer} (should be null if no totalProperty defined)
* }
*
* Called by CRUD specific handlers.
*
* Parameters:
* resp - {<OpenLayers.Protocol.Response>} The response object to pass to
* any user callback.
* options - {Object} The user options passed to the create, read, update,
* or delete call.
*/
handleResponse: function(resp, options) {
var request = resp.priv;
if(options.callback) {
if(request.status >= 200 && request.status < 300) {
// success
if(resp.requestType != "delete") {
//Here is the main changes :
//resp.features = this.parseFeatures(request);
Ext.apply (resp, this.parseFeatures(request));
}
resp.code = OpenLayers.Protocol.Response.SUCCESS;
} else {
// failure
resp.code = OpenLayers.Protocol.Response.FAILURE;
}
options.callback.call(options.scope, resp);
}
}
});
/*******************************************************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* SITools2 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* SITools2. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/*global Ext, sitools, OpenLayers*/
Ext.ns("sitools.user.data");
sitools.user.data.ProtocolProxy = function (config) {
sitools.user.data.ProtocolProxy.superclass.constructor.call(this, Ext.apply({
api : {
create : Ext.emptyFn,
destroy : Ext.emptyFn,
read : Ext.emptyFn,
update : Ext.emptyFn
},
protocol: new sitools.user.data.ProtocolHttp({
url: config.url,
totalProperty : config.totalProperty,
format: new OpenLayers.Format.GeoJSON()
})
}));
};
Ext.extend(sitools.user.data.ProtocolProxy, GeoExt.data.ProtocolProxy, {});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*!
* Ext JS Library 3.2.0
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
Ext.namespace('Ext.ux.grid.filter');
/**
* @class Ext.ux.grid.filter.Filter
* @extends Ext.util.Observable
* Abstract base class for filter implementations.
*/
Ext.ux.grid.filter.Filter = Ext.extend(Ext.util.Observable, {
/**
* @cfg {Boolean} active
* Indicates the initial status of the filter (defaults to false).
*/
active : false,
/**
* True if this filter is active. Use setActive() to alter after configuration.
* @type Boolean
* @property active
*/
/**
* @cfg {String} dataIndex
* The {@link Ext.data.Store} dataIndex of the field this filter represents.
* The dataIndex does not actually have to exist in the store.
*/
dataIndex : null,
* The filter configuration menu that will be installed into the filter submenu of a column menu.
* @type Ext.menu.Menu
* @property
*/
menu : null,
/**
* @cfg {Number} updateBuffer
* Number of milliseconds to wait after user interaction to fire an update. Only supported
* by filters: 'list', 'numeric', and 'string'. Defaults to 500.
*/
updateBuffer : 500,
constructor : function (config) {
Ext.apply(this, config);
this.addEvents(
/**
* @event activate
* Fires when an inactive filter becomes active
* @param {Ext.ux.grid.filter.Filter} this
*/
'activate',
/**
* @event deactivate
* Fires when an active filter becomes inactive
* @param {Ext.ux.grid.filter.Filter} this
*/
'deactivate',
/**
* @event serialize
* Fires after the serialization process. Use this to attach additional parameters to serialization
* data before it is encoded and sent to the server.
* @param {Array/Object} data A map or collection of maps representing the current filter configuration.
* @param {Ext.ux.grid.filter.Filter} filter The filter being serialized.
*/
'serialize',
/**
* @event update
* Fires when a filter configuration has changed
* @param {Ext.ux.grid.filter.Filter} this The filter object.
*/
'update'
);
Ext.ux.grid.filter.Filter.superclass.constructor.call(this);
this.menu = new Ext.menu.Menu();
this.init(config);
if(config && config.value){
this.setValue(config.value);
this.setActive(config.active !== false, true);
delete config.value;
}
},
/**
* Destroys this filter by purging any event listeners, and removing any menus.
*/
destroy : function(){
if (this.menu){
this.menu.destroy();
}
this.purgeListeners();
},
/**
* Template method to be implemented by all subclasses that is to
* initialize the filter and install required menu items.
* Defaults to Ext.emptyFn.
*/
init : Ext.emptyFn,
/**
* Template method to be implemented by all subclasses that is to
* get and return the value of the filter.
* Defaults to Ext.emptyFn.
* @return {Object} The 'serialized' form of this filter
* @methodOf Ext.ux.grid.filter.Filter
*/
getValue : Ext.emptyFn,
/**
* Template method to be implemented by all subclasses that is to
* set the value of the filter and fire the 'update' event.
* Defaults to Ext.emptyFn.
* @param {Object} data The value to set the filter
* @methodOf Ext.ux.grid.filter.Filter
*/
setValue : Ext.emptyFn,
/**
* Template method to be implemented by all subclasses that is to
* return <tt>true</tt> if the filter has enough configuration information to be activated.
* Defaults to <tt>return true</tt>.
* @return {Boolean}
*/
isActivatable : function(){
return true;
},
/**
* Template method to be implemented by all subclasses that is to
* get and return serialized filter data for transmission to the server.
* Defaults to Ext.emptyFn.
*/
getSerialArgs : Ext.emptyFn,
/**
* Template method to be implemented by all subclasses that is to
* validates the provided Ext.data.Record against the filters configuration.
* Defaults to <tt>return true</tt>.
* @param {Ext.data.Record} record The record to validate
* @return {Boolean} true if the record is valid within the bounds
* of the filter, false otherwise.
*/
validateRecord : function(){
return true;
},
/**
* Returns the serialized filter data for transmission to the server
* and fires the 'serialize' event.
* @return {Object/Array} An object or collection of objects containing
* key value pairs representing the current configuration of the filter.
* @methodOf Ext.ux.grid.filter.Filter
*/
serialize : function(){
var args = this.getSerialArgs();
this.fireEvent('serialize', args, this);
return args;
},
/** @private */
fireUpdate : function(){
if (this.active) {
this.fireEvent('update', this);
}
this.setActive(this.isActivatable());
},
/**
* Sets the status of the filter and fires the appropriate events.
* @param {Boolean} active The new filter state.
* @param {Boolean} suppressEvent True to prevent events from being fired.
* @methodOf Ext.ux.grid.filter.Filter
*/
setActive : function(active, suppressEvent){
if(this.active != active){
this.active = active;
if (suppressEvent !== true) {
this.fireEvent(active ? 'activate' : 'deactivate', this);
}
}
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*!
* Ext JS Library 3.2.0
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
/**
* @class Ext.ux.grid.filter.StringFilter
* @extends Ext.ux.grid.filter.Filter
* Filter by a configurable Ext.form.TextField
* <p><b><u>Example Usage:</u></b></p>
* <pre><code>
var filters = new Ext.ux.grid.GridFilters({
...
filters: [{
// required configs
type: 'string',
dataIndex: 'name',
// optional configs
value: 'foo',
active: true, // default is false
iconCls: 'ux-gridfilter-text-icon' // default
// any Ext.form.TextField configs accepted
}]
});
* </code></pre>
*/
Ext.ux.grid.filter.StringFilter = Ext.extend(Ext.ux.grid.filter.Filter, {
/**
* @cfg {String} iconCls
* The iconCls to be applied to the menu item.
* Defaults to <tt>'ux-gridfilter-text-icon'</tt>.
*/
iconCls : 'ux-gridfilter-text-icon',
emptyText: 'Enter Filter Text...',
selectOnFocus: true,
width: 125,
/**
* @private
* Template method that is to initialize the filter and install required menu items.
*/
init : function (config) {
Ext.applyIf(config, {
enableKeyEvents: true,
iconCls: this.iconCls,
listeners: {
scope: this,
keyup: this.onInputKeyUp
}
});
this.inputItem = new Ext.form.TextField(config);
this.menu.add(this.inputItem);
this.updateTask = new Ext.util.DelayedTask(this.fireUpdate, this);
},
/**
* @private
* Template method that is to get and return the value of the filter.
* @return {String} The value of this filter
*/
getValue : function () {
return this.inputItem.getValue();
},
/**
* @private
* Template method that is to set the value of the filter.
* @param {Object} value The value to set the filter
*/
setValue : function (value) {
this.inputItem.setValue(value);
this.fireEvent('update', this);
},
/**
* @private
* Template method that is to return <tt>true</tt> if the filter
* has enough configuration information to be activated.
* @return {Boolean}
*/
isActivatable : function () {
return this.inputItem.getValue().length > 0;
},
/**
* @private
* Template method that is to get and return serialized filter data for
* transmission to the server.
* @return {Object/Array} An object or collection of objects containing
* key value pairs representing the current configuration of the filter.
*/
getSerialArgs : function () {
return {type: 'string', value: this.getValue()};
},
/**
* Template method that is to validate the provided Ext.data.Record
* against the filters configuration.
* @param {Ext.data.Record} record The record to validate
* @return {Boolean} true if the record is valid within the bounds
* of the filter, false otherwise.
*/
validateRecord : function (record) {
var val = record.get(this.dataIndex);
if(typeof val != 'string') {
return (this.getValue().length === 0);
}
return val.toLowerCase().indexOf(this.getValue().toLowerCase()) > -1;
},
/**
* @private
* Handler method called when there is a keyup event on this.inputItem
*/
onInputKeyUp : function (field, e) {
var k = e.getKey();
if (k == e.RETURN && field.isValid()) {
e.stopEvent();
this.menu.hide(true);
return;
}
// restart the timer
this.updateTask.delay(this.updateBuffer);
}
});
//DA : ajout de l'opérateur de comparaison meme dans le cas d'un filtre de type String.
// Ajout de cotes autour de la valeur retournée
Ext.override (Ext.ux.grid.filter.StringFilter, {
getSerialArgs : function () {
return {type: 'string', value: this.getValue() , comparison: 'LIKE'};
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*!
* Ext JS Library 3.2.0
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
/**
* @class Ext.ux.grid.filter.DateFilter
* @extends Ext.ux.grid.filter.Filter
* Filter by a configurable Ext.menu.DateMenu
* <p><b><u>Example Usage:</u></b></p>
* <pre><code>
var filters = new Ext.ux.grid.GridFilters({
...
filters: [{
// required configs
type: 'date',
dataIndex: 'dateAdded',
// optional configs
dateFormat: 'm/d/Y', // default
beforeText: 'Before', // default
afterText: 'After', // default
onText: 'On', // default
pickerOpts: {
// any DateMenu configs
},
active: true // default is false
}]
});
* </code></pre>
*/
Ext.ux.grid.filter.DateFilter = Ext.extend(Ext.ux.grid.filter.Filter, {
/**
* @cfg {String} afterText
* Defaults to 'After'.
*/
afterText : 'After',
/**
* @cfg {String} beforeText
* Defaults to 'Before'.
*/
beforeText : 'Before',
/**
* @cfg {Object} compareMap
* Map for assigning the comparison values used in serialization.
*/
compareMap : {
before: 'lt',
after: 'gt',
on: 'eq'
},
/**
* @cfg {String} dateFormat
* The date format to return when using getValue.
* Defaults to 'm/d/Y'.
*/
dateFormat : SITOOLS_DATE_FORMAT,
/**
* @cfg {Date} maxDate
* Allowable date as passed to the Ext.DatePicker
* Defaults to undefined.
*/
/**
* @cfg {Date} minDate
* Allowable date as passed to the Ext.DatePicker
* Defaults to undefined.
*/
* @cfg {Array} menuItems
* The items to be shown in this menu
* Defaults to:<pre>
* menuItems : ['before', 'after', '-', 'on'],
* </pre>
*/
menuItems : ['before', 'after', '-', 'on'],
* @cfg {Object} menuItemCfgs
* Default configuration options for each menu item
*/
menuItemCfgs : {
selectOnFocus: true,
width: 125
},
/**
* @cfg {String} onText
* Defaults to 'On'.
*/
onText : 'On',
/**
* @cfg {Object} pickerOpts
* Configuration options for the date picker associated with each field.
*/
pickerOpts : {
showTime : true
},
/**
* @private
* Template method that is to initialize the filter and install required menu items.
*/
init : function (config) {
var menuCfg, i, len, item, cfg, Cls;
menuCfg = Ext.apply(this.pickerOpts, {
minDate: this.minDate,
maxDate: this.maxDate,
format: this.dateFormat,
listeners: {
scope: this,
select: this.onMenuSelect
}
});
this.fields = {};
for (i = 0, len = this.menuItems.length; i < len; i++) {
item = this.menuItems[i];
if (item !== '-') {
cfg = {
itemId: 'range-' + item,
text: this[item + 'Text'],
menu: new Ext.menu.DateMenu(
Ext.apply(menuCfg, {
itemId: item
})
),
listeners: {
scope: this,
checkchange: this.onCheckChange
}
};
Cls = Ext.menu.CheckItem;
item = this.fields[item] = new Cls(cfg);
}
//this.add(item);
this.menu.add(item);
}
},
onCheckChange : function () {
this.setActive(this.isActivatable());
this.fireEvent('update', this);
},
/**
* @private
* Handler method called when there is a keyup event on an input
* item of this menu.
*/
onInputKeyUp : function (field, e) {
var k = e.getKey();
if (k == e.RETURN && field.isValid()) {
e.stopEvent();
this.menu.hide(true);
return;
}
},
* Handler for when the menu for a field fires the 'select' event
* @param {Object} date
* @param {Object} menuItem
* @param {Object} value
* @param {Object} picker
*/
onMenuSelect : function (menuItem, value, picker) {
var fields = this.fields,
field = this.fields[menuItem.itemId];
field.setChecked(true);
if (field == fields.on) {
fields.before.setChecked(false, true);
fields.after.setChecked(false, true);
} else {
fields.on.setChecked(false, true);
if (field == fields.after && fields.before.menu.picker.value < value) {
fields.before.setChecked(false, true);
} else if (field == fields.before && fields.after.menu.picker.value > value) {
fields.after.setChecked(false, true);
}
}
this.fireEvent('update', this);
},
/**
* @private
* Template method that is to get and return the value of the filter.
* @return {String} The value of this filter
*/
getValue : function () {
var key, result = {};
for (key in this.fields) {
if (this.fields[key].checked) {
result[key] = this.fields[key].menu.picker.getValue();
}
}
return result;
},
/**
* @private
* Template method that is to set the value of the filter.
* @param {Object} value The value to set the filter
* @param {Boolean} preserve true to preserve the checked status
* of the other fields. Defaults to false, unchecking the
* other fields
*/
setValue : function (value, preserve) {
var key;
for (key in this.fields) {
if(value[key]){
this.fields[key].menu.picker.setValue(value[key]);
this.fields[key].setChecked(true);
} else if (!preserve) {
this.fields[key].setChecked(false);
}
}
this.fireEvent('update', this);
},
/**
* @private
* Template method that is to return <tt>true</tt> if the filter
* has enough configuration information to be activated.
* @return {Boolean}
*/
isActivatable : function () {
var key;
for (key in this.fields) {
if (this.fields[key].checked) {
return true;
}
}
return false;
},
/**
* @private
* Template method that is to get and return serialized filter data for
* transmission to the server.
* @return {Object/Array} An object or collection of objects containing
* key value pairs representing the current configuration of the filter.
*/
getSerialArgs : function () {
var args = [];
for (var key in this.fields) {
if(this.fields[key].checked){
args.push({
type: 'date',
comparison: this.compareMap[key],
value: this.getFieldValue(key).format(this.dateFormat)
});
}
}
return args;
},
/**
* Get and return the date menu picker value
* @param {String} item The field identifier ('before', 'after', 'on')
* @return {Date} Gets the current selected value of the date field
*/
getFieldValue : function(item){
return this.fields[item].menu.picker.getValue();
},
/**
* Gets the menu picker associated with the passed field
* @param {String} item The field identifier ('before', 'after', 'on')
* @return {Object} The menu picker
*/
getPicker : function(item){
return this.fields[item].menu.picker;
},
/**
* Template method that is to validate the provided Ext.data.Record
* against the filters configuration.
* @param {Ext.data.Record} record The record to validate
* @return {Boolean} true if the record is valid within the bounds
* of the filter, false otherwise.
*/
validateRecord : function (record) {
var key,
pickerValue,
val = record.get(this.dataIndex);
if(!Ext.isDate(val)){
return false;
}
val = val.clearTime(true).getTime();
for (key in this.fields) {
if (this.fields[key].checked) {
pickerValue = this.getFieldValue(key).clearTime(true).getTime();
if (key == 'before' && pickerValue <= val) {
return false;
}
if (key == 'after' && pickerValue >= val) {
return false;
}
if (key == 'on' && pickerValue != val) {
return false;
}
}
}
return true;
}
});
////DA : Ajout de cotes autour de la valeur retournée
//Ext.override (Ext.ux.grid.filter.DateFilter, {
// getSerialArgs : function () {
// var args = [];
// for (var key in this.fields) {
// if(this.fields[key].checked){
// args.push({
// type: 'date',
// comparison: this.compareMap[key],
// value: this.getFieldValue(key).format(this.dateFormat)
// });
// }
// }
// return args;
// }
//});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*!
* Ext JS Library 3.2.0
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
/**
* @class Ext.ux.grid.filter.ListFilter
* @extends Ext.ux.grid.filter.Filter
* <p>List filters are able to be preloaded/backed by an Ext.data.Store to load
* their options the first time they are shown. ListFilter utilizes the
* {@link Ext.ux.menu.ListMenu} component.</p>
* <p>Although not shown here, this class accepts all configuration options
* for {@link Ext.ux.menu.ListMenu}.</p>
*
* <p><b><u>Example Usage:</u></b></p>
* <pre><code>
var filters = new Ext.ux.grid.GridFilters({
...
filters: [{
type: 'list',
dataIndex: 'size',
phpMode: true,
// options will be used as data to implicitly creates an ArrayStore
options: ['extra small', 'small', 'medium', 'large', 'extra large']
}]
});
* </code></pre>
*
*/
Ext.ux.grid.filter.ListFilter = Ext.extend(Ext.ux.grid.filter.Filter, {
/**
* @cfg {Array} options
* <p><code>data</code> to be used to implicitly create a data store
* to back this list when the data source is <b>local</b>. If the
* data for the list is remote, use the <code>{@link #store}</code>
* config instead.</p>
* <br><p>Each item within the provided array may be in one of the
* following formats:</p>
* <div class="mdetail-params"><ul>
* <li><b>Array</b> :
* <pre><code>
options: [
[11, 'extra small'],
[18, 'small'],
[22, 'medium'],
[35, 'large'],
[44, 'extra large']
]
* </code></pre>
* </li>
* <li><b>Object</b> :
* <pre><code>
labelField: 'name', // override default of 'text'
options: [
{id: 11, name:'extra small'},
{id: 18, name:'small'},
{id: 22, name:'medium'},
{id: 35, name:'large'},
{id: 44, name:'extra large'}
]
* </code></pre>
* </li>
* <li><b>String</b> :
* <pre><code>
* options: ['extra small', 'small', 'medium', 'large', 'extra large']
* </code></pre>
* </li>
*/
/**
* @cfg {Boolean} phpMode
* <p>Adjust the format of this filter. Defaults to false.</p>
* <br><p>When GridFilters <code>@cfg encode = false</code> (default):</p>
* <pre><code>
// phpMode == false (default):
filter[0][data][type] list
filter[0][data][value] value1
filter[0][data][value] value2
filter[0][field] prod
// phpMode == true:
filter[0][data][type] list
filter[0][data][value] value1, value2
filter[0][field] prod
* </code></pre>
* When GridFilters <code>@cfg encode = true</code>:
* <pre><code>
// phpMode == false (default):
filter : [{"type":"list","value":["small","medium"],"field":"size"}]
// phpMode == true:
filter : [{"type":"list","value":"small,medium","field":"size"}]
* </code></pre>
*/
phpMode : false,
/**
* @cfg {Ext.data.Store} store
* The {@link Ext.data.Store} this list should use as its data source
* when the data source is <b>remote</b>. If the data for the list
* is local, use the <code>{@link #options}</code> config instead.
*/
/**
* @private
* Template method that is to initialize the filter and install required menu items.
* @param {Object} config
*/
init : function (config) {
this.dt = new Ext.util.DelayedTask(this.fireUpdate, this);
// if a menu already existed, do clean up first
if (this.menu){
this.menu.destroy();
}
this.menu = new Ext.ux.menu.ListMenu(config);
this.menu.on('checkchange', this.onCheckChange, this);
},
/**
* @private
* Template method that is to get and return the value of the filter.
* @return {String} The value of this filter
*/
getValue : function () {
return this.menu.getSelected();
},
/**
* @private
* Template method that is to set the value of the filter.
* @param {Object} value The value to set the filter
*/
setValue : function (value) {
this.menu.setSelected(value);
this.fireEvent('update', this);
},
/**
* @private
* Template method that is to return <tt>true</tt> if the filter
* has enough configuration information to be activated.
* @return {Boolean}
*/
isActivatable : function () {
return this.getValue().length > 0;
},
/**
* @private
* Template method that is to get and return serialized filter data for
* transmission to the server.
* @return {Object/Array} An object or collection of objects containing
* key value pairs representing the current configuration of the filter.
*/
getSerialArgs : function () {
var args = {type: 'list', value: this.phpMode ? this.getValue().join(',') : this.getValue()};
return args;
},
/** @private */
onCheckChange : function(){
this.dt.delay(this.updateBuffer);
},
/**
* Template method that is to validate the provided Ext.data.Record
* against the filters configuration.
* @param {Ext.data.Record} record The record to validate
* @return {Boolean} true if the record is valid within the bounds
* of the filter, false otherwise.
*/
validateRecord : function (record) {
return this.getValue().indexOf(record.get(this.dataIndex)) > -1;
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*!
* Ext JS Library 3.2.0
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
/**
* @class Ext.ux.grid.filter.NumericFilter
* @extends Ext.ux.grid.filter.Filter
* Filters using an Ext.ux.menu.RangeMenu.
* <p><b><u>Example Usage:</u></b></p>
* <pre><code>
var filters = new Ext.ux.grid.GridFilters({
...
filters: [{
type: 'numeric',
dataIndex: 'price'
}]
});
* </code></pre>
*/
Ext.ux.grid.filter.NumericFilter = Ext.extend(Ext.ux.grid.filter.Filter, {
/**
* @cfg {Object} fieldCls
* The Class to use to construct each field item within this menu
* Defaults to:<pre>
* fieldCls : Ext.form.NumberField
* </pre>
*/
fieldCls : Ext.form.NumberField,
/**
* @cfg {Object} fieldCfg
* The default configuration options for any field item unless superseded
* by the <code>{@link #fields}</code> configuration.
* Defaults to:<pre>
* fieldCfg : {}
* </pre>
* Example usage:
* <pre><code>
fieldCfg : {
width: 150,
},
* </code></pre>
*/
/**
* @cfg {Object} fields
* The field items may be configured individually
* Defaults to <tt>undefined</tt>.
* Example usage:
* <pre><code>
fields : {
gt: { // override fieldCfg options
width: 200,
fieldCls: Ext.ux.form.CustomNumberField // to override default {@link #fieldCls}
}
},
* </code></pre>
*/
/**
* @cfg {Object} iconCls
* The iconCls to be applied to each comparator field item.
* Defaults to:<pre>
iconCls : {
gt : 'ux-rangemenu-gt',
lt : 'ux-rangemenu-lt',
eq : 'ux-rangemenu-eq'
}
* </pre>
*/
iconCls : {
gte : 'ux-rangemenu-gte',
lte : 'ux-rangemenu-lte',
eq : 'ux-rangemenu-eq',
gt : 'ux-rangemenu-gt',
lt : 'ux-rangemenu-lt'
},
* @cfg {Object} menuItemCfgs
* Default configuration options for each menu item
* Defaults to:<pre>
menuItemCfgs : {
emptyText: 'Enter Filter Text...',
selectOnFocus: true,
width: 125
}
* </pre>
*/
menuItemCfgs : {
emptyText: 'Enter Filter Text...',
selectOnFocus: true,
width: 125,
decimalPrecision : 20
},
* @cfg {Array} menuItems
* The items to be shown in this menu. Items are added to the menu
* according to their position within this array. Defaults to:<pre>
* menuItems : ['lt','gt','-','eq']
* </pre>
*/
menuItems : ['lte', 'gte', '-', 'eq', '-', 'lt', 'gt'],
/**
* @private
* Template method that is to initialize the filter and install required menu items.
*/
init : function (config) {
// if a menu already existed, do clean up first
if (this.menu){
this.menu.destroy();
}
this.menu = new Ext.ux.menu.RangeMenu(Ext.apply(config, {
// pass along filter configs to the menu
fieldCfg : this.fieldCfg || {},
fieldCls : this.fieldCls,
fields : this.fields || {},
iconCls: this.iconCls,
menuItemCfgs: this.menuItemCfgs,
menuItems: this.menuItems,
updateBuffer: this.updateBuffer
}));
// relay the event fired by the menu
this.menu.on('update', this.fireUpdate, this);
},
/**
* @private
* Template method that is to get and return the value of the filter.
* @return {String} The value of this filter
*/
getValue : function () {
return this.menu.getValue();
},
/**
* @private
* Template method that is to set the value of the filter.
* @param {Object} value The value to set the filter
*/
setValue : function (value) {
this.menu.setValue(value);
},
/**
* @private
* Template method that is to return <tt>true</tt> if the filter
* has enough configuration information to be activated.
* @return {Boolean}
*/
isActivatable : function () {
var values = this.getValue();
for (key in values) {
if (values[key] !== undefined) {
return true;
}
}
return false;
},
/**
* @private
* Template method that is to get and return serialized filter data for
* transmission to the server.
* @return {Object/Array} An object or collection of objects containing
* key value pairs representing the current configuration of the filter.
*/
getSerialArgs : function () {
var key,
args = [],
values = this.menu.getValue();
for (key in values) {
args.push({
type: 'numeric',
comparison: key,
value: values[key]
});
}
return args;
},
/**
* Template method that is to validate the provided Ext.data.Record
* against the filters configuration.
* @param {Ext.data.Record} record The record to validate
* @return {Boolean} true if the record is valid within the bounds
* of the filter, false otherwise.
*/
validateRecord : function (record) {
var val = record.get(this.dataIndex),
values = this.getValue();
if (values.eq !== undefined && val != values.eq) {
return false;
}
if (values.lt !== undefined && val >= values.lt) {
return false;
}
if (values.gt !== undefined && val <= values.gt) {
return false;
}
return true;
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*!
* Ext JS Library 3.2.0
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
/**
* @class Ext.ux.grid.filter.BooleanFilter
* @extends Ext.ux.grid.filter.Filter
* Boolean filters use unique radio group IDs (so you can have more than one!)
* <p><b><u>Example Usage:</u></b></p>
* <pre><code>
var filters = new Ext.ux.grid.GridFilters({
...
filters: [{
// required configs
type: 'boolean',
dataIndex: 'visible'
// optional configs
defaultValue: null, // leave unselected (false selected by default)
yesText: 'Yes', // default
noText: 'No' // default
}]
});
* </code></pre>
*/
Ext.ux.grid.filter.BooleanFilter = Ext.extend(Ext.ux.grid.filter.Filter, {
/**
* @cfg {Boolean} defaultValue
* Set this to null if you do not want either option to be checked by default. Defaults to false.
*/
defaultValue : false,
/**
* @cfg {String} yesText
* Defaults to 'Yes'.
*/
yesText : "yes",
/**
* @cfg {String} noText
* Defaults to 'No'.
*/
noText : "no",
comparison : 'eq',
/**
* @private
* Template method that is to initialize the filter and install required menu items.
*/
init : function (config) {
this.yesText = i18n.get('label.true');
this.noText = i18n.get('label.false');
var gId = Ext.id();
this.options = [
new Ext.menu.CheckItem({text: this.yesText, group: gId, checked: this.defaultValue === true}),
new Ext.menu.CheckItem({text: this.noText, group: gId, checked: this.defaultValue === false})];
this.menu.add(this.options[0], this.options[1]);
for(var i=0; i<this.options.length; i++){
this.options[i].on('click', this.fireUpdate, this);
this.options[i].on('checkchange', this.fireUpdate, this);
}
},
/**
* @private
* Template method that is to get and return the value of the filter.
* @return {String} The value of this filter
*/
getValue : function () {
return this.options[0].checked;
},
/**
* @private
* Template method that is to set the value of the filter.
* @param {Object} value The value to set the filter
*/
setValue : function (value) {
this.options[value ? 0 : 1].setChecked(true);
},
/**
* @private
* Template method that is to get and return serialized filter data for
* transmission to the server.
* @return {Object/Array} An object or collection of objects containing
* key value pairs representing the current configuration of the filter.
*/
getSerialArgs : function () {
var args = {type: 'boolean', comparison : this.comparison, value: this.getValue()};
return args;
},
/**
* Template method that is to validate the provided Ext.data.Record
* against the filters configuration.
* @param {Ext.data.Record} record The record to validate
* @return {Boolean} true if the record is valid within the bounds
* of the filter, false otherwise.
*/
validateRecord : function (record) {
return record.get(this.dataIndex) == this.getValue();
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*!
* Ext JS Library 3.2.0
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
Ext.ns('Ext.ux.menu');
* @class Ext.ux.menu.RangeMenu
* @extends Ext.menu.Menu
* Custom implementation of Ext.menu.Menu that has preconfigured
* items for gt, lt, eq.
* <p><b><u>Example Usage:</u></b></p>
* <pre><code>
* </code></pre>
*/
Ext.ux.menu.RangeMenu = Ext.extend(Ext.menu.Menu, {
constructor : function (config) {
Ext.ux.menu.RangeMenu.superclass.constructor.call(this, config);
this.addEvents(
* @event update
* Fires when a filter configuration has changed
* @param {Ext.ux.grid.filter.Filter} this The filter object.
*/
'update'
);
this.updateTask = new Ext.util.DelayedTask(this.fireUpdate, this);
var i, len, item, cfg, Cls;
for (i = 0, len = this.menuItems.length; i < len; i++) {
item = this.menuItems[i];
if (item !== '-') {
// defaults
cfg = {
itemId: 'range-' + item,
enableKeyEvents: true,
iconCls: this.iconCls[item] || 'no-icon',
listeners: {
scope: this,
keyup: this.onInputKeyUp
}
};
Ext.apply(
cfg,
// custom configs
Ext.applyIf(this.fields[item] || {}, this.fieldCfg[item]),
// configurable defaults
this.menuItemCfgs
);
Cls = cfg.fieldCls || this.fieldCls;
item = this.fields[item] = new Cls(cfg);
}
this.add(item);
}
},
* @private
* called by this.updateTask
*/
fireUpdate : function () {
this.fireEvent('update', this);
},
* Get and return the value of the filter.
* @return {String} The value of this filter
*/
getValue : function () {
var result = {}, key, field;
for (key in this.fields) {
field = this.fields[key];
if (field.isValid() && String(field.getValue()).length > 0) {
result[key] = field.getValue();
}
}
return result;
},
* Set the value of this menu and fires the 'update' event.
* @param {Object} data The data to assign to this menu
*/
setValue : function (data) {
var key;
for (key in this.fields) {
this.fields[key].setValue(data[key] !== undefined ? data[key] : '');
}
this.fireEvent('update', this);
},
* @private
* Handler method called when there is a keyup event on an input
* item of this menu.
*/
onInputKeyUp : function (field, e) {
var k = e.getKey();
if (k == e.RETURN && field.isValid()) {
e.stopEvent();
this.hide(true);
return;
}
if (field == this.fields.eq) {
if (this.fields.gt) {
this.fields.gt.setValue(null);
}
if (this.fields.lt) {
this.fields.lt.setValue(null);
}
}
else {
this.fields.eq.setValue(null);
}
// restart the timer
this.updateTask.delay(this.updateBuffer);
}
});
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*!
* Ext JS Library 3.2.0
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
Ext.namespace('Ext.ux.menu');
* @class Ext.ux.menu.ListMenu
* @extends Ext.menu.Menu
* This is a supporting class for {@link Ext.ux.grid.filter.ListFilter}.
* Although not listed as configuration options for this class, this class
* also accepts all configuration options from {@link Ext.ux.grid.filter.ListFilter}.
*/
Ext.ux.menu.ListMenu = Ext.extend(Ext.menu.Menu, {
* @cfg {String} labelField
* Defaults to 'text'.
*/
labelField : 'text',
* @cfg {String} paramPrefix
* Defaults to 'Loading...'.
*/
loadingText : 'Loading...',
* @cfg {Boolean} loadOnShow
* Defaults to true.
*/
loadOnShow : true,
* @cfg {Boolean} single
* Specify true to group all items in this list into a single-select
* radio button group. Defaults to false.
*/
single : false,
constructor : function (cfg) {
this.selected = [];
this.addEvents(
* @event checkchange
* Fires when there is a change in checked items from this list
* @param {Object} item Ext.menu.CheckItem
* @param {Object} checked The checked value that was set
*/
'checkchange'
);
Ext.ux.menu.ListMenu.superclass.constructor.call(this, cfg = cfg || {});
if(!cfg.store && cfg.options){
var options = [];
for(var i=0, len=cfg.options.length; i<len; i++){
var value = cfg.options[i];
switch(Ext.type(value)){
case 'array': options.push(value); break;
case 'object': options.push([value.id, value[this.labelField]]); break;
case 'string': options.push([value, value]); break;
}
}
this.store = new Ext.data.Store({
reader: new Ext.data.ArrayReader({id: 0}, ['id', this.labelField]),
data: options,
listeners: {
'load': this.onLoad,
scope: this
}
});
this.loaded = true;
} else {
this.add({text: this.loadingText, iconCls: 'loading-indicator'});
this.store.on('load', this.onLoad, this);
}
},
destroy : function () {
if (this.store) {
this.store.destroy();
}
Ext.ux.menu.ListMenu.superclass.destroy.call(this);
},
* Lists will initially show a 'loading' item while the data is retrieved from the store.
* In some cases the loaded data will result in a list that goes off the screen to the
* right (as placement calculations were done with the loading item). This adapter will
* allow show to be called with no arguments to show with the previous arguments and
* thus recalculate the width and potentially hang the menu from the left.
*/
show : function () {
var lastArgs = null;
return function(){
if(arguments.length === 0){
Ext.ux.menu.ListMenu.superclass.show.apply(this, lastArgs);
} else {
lastArgs = arguments;
if (this.loadOnShow && !this.loaded) {
this.store.load();
}
Ext.ux.menu.ListMenu.superclass.show.apply(this, arguments);
}
};
}(),
onLoad : function (store, records) {
var visible = this.isVisible();
this.hide(false);
this.removeAll(true);
var gid = this.single ? Ext.id() : null;
for(var i=0, len=records.length; i<len; i++){
var item = new Ext.menu.CheckItem({
text: records[i].get(this.labelField),
group: gid,
checked: this.selected.indexOf(records[i].id) > -1,
hideOnClick: false});
item.itemId = records[i].id;
item.on('checkchange', this.checkChange, this);
this.add(item);
}
this.loaded = true;
if (visible) {
this.show();
}
this.fireEvent('load', this, records);
},
* Get the selected items.
* @return {Array} selected
*/
getSelected : function () {
return this.selected;
},
setSelected : function (value) {
value = this.selected = [].concat(value);
if (this.loaded) {
this.items.each(function(item){
item.setChecked(false, true);
for (var i = 0, len = value.length; i < len; i++) {
if (item.itemId == value[i]) {
item.setChecked(true, true);
}
}
}, this);
}
},
* Handler for the 'checkchange' event from an check item in this menu
* @param {Object} item Ext.menu.CheckItem
* @param {Object} checked The checked value that was set
*/
checkChange : function (item, checked) {
var value = [];
this.items.each(function(item){
if (item.checked) {
value.push(item.itemId);
}
},this);
this.selected = value;
this.fireEvent('checkchange', item, checked);
}
});
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*!
* Ext JS Library 3.2.0
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
Ext.namespace('Ext.ux.grid');
/**
* @class Ext.ux.grid.GridFilters
* @extends Ext.util.Observable
* <p>GridFilter is a plugin (<code>ptype='gridfilters'</code>) for grids that
* allow for a slightly more robust representation of filtering than what is
* provided by the default store.</p>
* <p>Filtering is adjusted by the user using the grid's column header menu
* (this menu can be disabled through configuration). Through this menu users
* can configure, enable, and disable filters for each column.</p>
* <p><b><u>Features:</u></b></p>
* <div class="mdetail-params"><ul>
* <li><b>Filtering implementations</b> :
* <div class="sub-desc">
* Default filtering for Strings, Numeric Ranges, Date Ranges, Lists (which can
* be backed by a Ext.data.Store), and Boolean. Additional custom filter types
* and menus are easily created by extending Ext.ux.grid.filter.Filter.
* </div></li>
* <li><b>Graphical indicators</b> :
* <div class="sub-desc">
* Columns that are filtered have {@link #filterCls a configurable css class}
* applied to the column headers.
* </div></li>
* <li><b>Paging</b> :
* <div class="sub-desc">
* If specified as a plugin to the grid's configured PagingToolbar, the current page
* will be reset to page 1 whenever you update the filters.
* </div></li>
* <li><b>Automatic Reconfiguration</b> :
* <div class="sub-desc">
* Filters automatically reconfigure when the grid 'reconfigure' event fires.
* </div></li>
* <li><b>Stateful</b> :
* Filter information will be persisted across page loads by specifying a
* <code>stateId</code> in the Grid configuration.
* <div class="sub-desc">
* The filter collection binds to the
* <code>{@link Ext.grid.GridPanel#beforestaterestore beforestaterestore}</code>
* and <code>{@link Ext.grid.GridPanel#beforestatesave beforestatesave}</code>
* events in order to be stateful.
* </div></li>
* <li><b>Grid Changes</b> :
* <div class="sub-desc"><ul>
* <li>A <code>filters</code> <i>property</i> is added to the grid pointing to
* this plugin.</li>
* <li>A <code>filterupdate</code> <i>event</i> is added to the grid and is
* fired upon onStateChange completion.</li>
* </ul></div></li>
* <li><b>Server side code examples</b> :
* <div class="sub-desc"><ul>
* <li><a href="http://www.vinylfox.com/extjs/grid-filter-php-backend-code.php">PHP</a> - (Thanks VinylFox)</li>
* <li><a href="http://extjs.com/forum/showthread.php?p=77326#post77326">Ruby on Rails</a> - (Thanks Zyclops)</li>
* <li><a href="http://extjs.com/forum/showthread.php?p=176596#post176596">Ruby on Rails</a> - (Thanks Rotomaul)</li>
* <li><a href="http://www.debatablybeta.com/posts/using-extjss-grid-filtering-with-django/">Python</a> - (Thanks Matt)</li>
* <li><a href="http://mcantrell.wordpress.com/2008/08/22/extjs-grids-and-grails/">Grails</a> - (Thanks Mike)</li>
* </ul></div></li>
* </ul></div>
* <p><b><u>Example usage:</u></b></p>
* <pre><code>
var store = new Ext.data.GroupingStore({
...
});
var filters = new Ext.ux.grid.GridFilters({
autoReload: false, //don't reload automatically
local: true, //only filter locally
// filters may be configured through the plugin,
// or in the column definition within the column model configuration
filters: [{
type: 'numeric',
dataIndex: 'id'
}, {
type: 'string',
dataIndex: 'name'
}, {
type: 'numeric',
dataIndex: 'price'
}, {
type: 'date',
dataIndex: 'dateAdded'
}, {
type: 'list',
dataIndex: 'size',
options: ['extra small', 'small', 'medium', 'large', 'extra large'],
phpMode: true
}, {
type: 'boolean',
dataIndex: 'visible'
}]
});
var cm = new Ext.grid.ColumnModel([{
...
}]);
var grid = new Ext.grid.GridPanel({
ds: store,
cm: cm,
view: new Ext.grid.GroupingView(),
plugins: [filters],
height: 400,
width: 700,
bbar: new Ext.PagingToolbar({
store: store,
pageSize: 15,
plugins: [filters] //reset page to page 1 if filters change
})
});
store.load({params: {start: 0, limit: 15}});
// a filters property is added to the grid
grid.filters
* </code></pre>
*/
Ext.ux.grid.GridFilters = Ext.extend(Ext.util.Observable, {
/**
* @cfg {Boolean} autoReload
* Defaults to true, reloading the datasource when a filter change happens.
* Set this to false to prevent the datastore from being reloaded if there
* are changes to the filters. See <code>{@link updateBuffer}</code>.
*/
autoReload : true,
/**
* @cfg {Boolean} encode
* Specify true for {@link #buildQuery} to use Ext.util.JSON.encode to
* encode the filter query parameter sent with a remote request.
* Defaults to false.
*/
/**
* @cfg {Array} filters
* An Array of filters config objects. Refer to each filter type class for
* configuration details specific to each filter type. Filters for Strings,
* Numeric Ranges, Date Ranges, Lists, and Boolean are the standard filters
* available.
*/
/**
* @cfg {String} filterCls
* The css class to be applied to column headers with active filters.
* Defaults to <tt>'ux-filterd-column'</tt>.
*/
filterCls : 'ux-filtered-column',
/**
* @cfg {Boolean} local
* <tt>true</tt> to use Ext.data.Store filter functions (local filtering)
* instead of the default (<tt>false</tt>) server side filtering.
*/
local : false,
* @cfg {String} menuFilterText
* defaults to <tt>'Filters'</tt>.
*/
menuFilterText : 'Filters',
/**
* @cfg {String} paramPrefix
* The url parameter prefix for the filters.
* Defaults to <tt>'filter'</tt>.
*/
paramPrefix : 'filter',
* @cfg {Boolean} showMenu
* Defaults to true, including a filter submenu in the default header menu.
*/
showMenu : true,
/**
* @cfg {String} stateId
* Name of the value to be used to store state information.
*/
stateId : undefined,
/**
* @cfg {Integer} updateBuffer
* Number of milliseconds to defer store updates since the last filter change.
*/
updateBuffer : 500,
/** @private */
constructor : function (config) {
config = config || {};
this.deferredUpdate = new Ext.util.DelayedTask(this.reload, this);
this.filters = new Ext.util.MixedCollection();
this.filters.getKey = function (o) {
return o ? o.dataIndex : null;
};
this.addFilters(config.filters);
delete config.filters;
Ext.apply(this, config);
},
/** @private */
init : function (grid) {
if (grid instanceof Ext.grid.GridPanel) {
this.grid = grid;
this.bindStore(this.grid.getStore(), true);
// assumes no filters were passed in the constructor, so try and use ones from the colModel
// if(this.filters.getCount() == 0){
// this.addFilters(this.grid.getColumnModel());
// }
this.grid.filters = this;
this.grid.addEvents({'filterupdate': true});
grid.on({
scope: this,
beforestaterestore: this.applyState,
beforestatesave: this.saveState,
beforedestroy: this.destroy,
reconfigure: this.onReconfigure
});
if (grid.rendered){
this.onRender();
} else {
grid.on({
scope: this,
single: true,
render: this.onRender
});
}
} else if (grid instanceof Ext.PagingToolbar) {
this.toolbar = grid;
}
},
/**
* @private
* Handler for the grid's beforestaterestore event (fires before the state of the
* grid is restored).
* @param {Object} grid The grid object
* @param {Object} state The hash of state values returned from the StateProvider.
*/
applyState : function (grid, state) {
var key, filter;
this.applyingState = true;
this.clearFilters();
if (state.filters) {
for (key in state.filters) {
filter = this.filters.get(key);
if (filter) {
filter.setValue(state.filters[key]);
filter.setActive(true);
}
}
}
this.deferredUpdate.cancel();
if (this.local) {
this.reload();
}
delete this.applyingState;
},
/**
* Saves the state of all active filters
* @param {Object} grid
* @param {Object} state
* @return {Boolean}
*/
saveState : function (grid, state) {
var filters = {};
this.filters.each(function (filter) {
if (filter.active) {
filters[filter.dataIndex] = filter.getValue();
}
});
return (state.filters = filters);
},
/**
* @private
* Handler called when the grid is rendered
*/
onRender : function () {
this.grid.getView().on('refresh', this.onRefresh, this);
this.createMenu();
},
/**
* @private
* Handler called by the grid 'beforedestroy' event
*/
destroy : function () {
this.removeAll();
this.purgeListeners();
if(this.filterMenu){
Ext.menu.MenuMgr.unregister(this.filterMenu);
this.filterMenu.destroy();
this.filterMenu = this.menu.menu = null;
}
},
/**
* Remove all filters, permanently destroying them.
*/
removeAll : function () {
if(this.filters){
Ext.destroy.apply(Ext, this.filters.items);
// remove all items from the collection
this.filters.clear();
}
},
/**
* Changes the data store bound to this view and refreshes it.
* @param {Store} store The store to bind to this view
*/
bindStore : function(store, initial){
if(!initial && this.store){
if (this.local) {
store.un('load', this.onLoad, this);
} else {
store.un('beforeload', this.onBeforeLoad, this);
}
}
if(store){
if (this.local) {
store.on('load', this.onLoad, this);
} else {
store.on('beforeload', this.onBeforeLoad, this);
}
}
this.store = store;
},
/**
* @private
* Handler called when the grid reconfigure event fires
*/
onReconfigure : function () {
this.bindStore(this.grid.getStore());
this.store.clearFilter();
this.removeAll();
this.addFilters(this.grid.getColumnModel());
this.updateColumnHeadings();
},
createMenu : function () {
var view = this.grid.getView(),
hmenu = view.hmenu;
if (this.showMenu && hmenu) {
this.sep = hmenu.addSeparator();
this.filterMenu = new Ext.menu.Menu({
id: this.grid.id + '-filters-menu'
});
this.menu = hmenu.add({
checked: false,
itemId: 'filters',
text: this.menuFilterText,
menu: this.filterMenu
});
this.menu.on({
scope: this,
checkchange: this.onCheckChange,
beforecheckchange: this.onBeforeCheck
});
hmenu.on('beforeshow', this.onMenu, this);
}
this.updateColumnHeadings();
},
* @private
* Get the filter menu from the filters MixedCollection based on the clicked header
*/
getMenuFilter : function () {
var view = this.grid.getView();
if (!view || view.hdCtxIndex === undefined) {
return null;
}
return this.filters.get(
view.cm.config[view.hdCtxIndex].dataIndex
);
},
* @private
* Handler called by the grid's hmenu beforeshow event
*/
onMenu : function (filterMenu) {
var filter = this.getMenuFilter();
if (filter) {
/*
TODO: lazy rendering
if (!filter.menu) {
filter.menu = filter.createMenu();
}
*/
this.menu.menu = filter.menu;
this.menu.setChecked(filter.active, false);
// disable the menu if filter.disabled explicitly set to true
this.menu.setDisabled(filter.disabled === true);
}
this.menu.setVisible(filter !== undefined);
this.sep.setVisible(filter !== undefined);
},
/** @private */
onCheckChange : function (item, value) {
this.getMenuFilter().setActive(value);
},
/** @private */
onBeforeCheck : function (check, value) {
return !value || this.getMenuFilter().isActivatable();
},
/**
* @private
* Handler for all events on filters.
* @param {String} event Event name
* @param {Object} filter Standard signature of the event before the event is fired
*/
onStateChange : function (event, filter) {
if (event === 'serialize') {
return;
}
if (filter == this.getMenuFilter()) {
this.menu.setChecked(filter.active, false);
}
if ((this.autoReload || this.local) && !this.applyingState) {
this.deferredUpdate.delay(this.updateBuffer);
}
this.updateColumnHeadings();
if (!this.applyingState) {
this.grid.saveState();
}
this.grid.fireEvent('filterupdate', this, filter);
},
/**
* @private
* Handler for store's beforeload event when configured for remote filtering
* @param {Object} store
* @param {Object} options
*/
onBeforeLoad : function (store, options) {
options.params = options.params || {};
this.cleanParams(options.params);
var params = this.buildQuery(this.getFilterData());
Ext.apply(options.params, params);
//save the options has last options in the store
store.storeOptions(options);
},
/**
* @private
* Handler for store's load event when configured for local filtering
* @param {Object} store
* @param {Object} options
*/
onLoad : function (store, options) {
store.filterBy(this.getRecordFilter());
},
/**
* @private
* Handler called when the grid's view is refreshed
*/
onRefresh : function () {
this.updateColumnHeadings();
},
/**
* Update the styles for the header row based on the active filters
*/
updateColumnHeadings : function () {
var view = this.grid.getView(),
i, len, filter;
if (view.mainHd) {
for (i = 0, len = view.cm.config.length; i < len; i++) {
filter = this.getFilter(view.cm.config[i].dataIndex);
Ext.fly(view.getHeaderCell(i))[filter && filter.active ? 'addClass' : 'removeClass'](this.filterCls);
}
}
},
/** @private */
reload : function () {
if (this.local) {
this.grid.store.clearFilter(true);
this.grid.store.filterBy(this.getRecordFilter());
} else {
var start,
store = this.grid.store;
this.deferredUpdate.cancel();
if (this.toolbar) {
start = store.paramNames.start;
if (store.lastOptions && store.lastOptions.params && store.lastOptions.params[start]) {
store.lastOptions.params[start] = 0;
}
}
//set that there as been a new filter added, or one removed
store.isNewFilter = true;
store.reload();
}
},
/**
* Method factory that generates a record validator for the filters active at the time
* of invokation.
* @private
*/
getRecordFilter : function () {
var f = [], len, i;
this.filters.each(function (filter) {
if (filter.active) {
f.push(filter);
}
});
len = f.length;
return function (record) {
for (i = 0; i < len; i++) {
if (!f[i].validateRecord(record)) {
return false;
}
}
return true;
};
},
/**
* Adds a filter to the collection and observes it for state change.
* @param {Object/Ext.ux.grid.filter.Filter} config A filter configuration or a filter object.
* @return {Ext.ux.grid.filter.Filter} The existing or newly created filter object.
*/
addFilter : function (config) {
var Cls = this.getFilterClass(config.type),
filter = config.menu ? config : (new Cls(config));
this.filters.add(filter);
Ext.util.Observable.capture(filter, this.onStateChange, this);
return filter;
},
/**
* Adds filters to the collection.
* @param {Array/Ext.grid.ColumnModel} filters Either an Array of
* filter configuration objects or an Ext.grid.ColumnModel. The columns
* of a passed Ext.grid.ColumnModel will be examined for a <code>filter</code>
* property and, if present, will be used as the filter configuration object.
*/
addFilters : function (filters) {
if (filters) {
var i, len, filter, cm = false, dI;
if (filters instanceof Ext.grid.ColumnModel) {
filters = filters.config;
cm = true;
}
for (i = 0, len = filters.length; i < len; i++) {
filter = false;
if (cm) {
dI = filters[i].dataIndex;
cA = filters[i].columnAlias;
filter = filters[i].filter || filters[i].filterable;
if (filter){
filter = (filter === true) ? {} : filter;
Ext.apply(filter, {dataIndex:dI, columnAlias : cA});
// filter type is specified in order of preference:
// filter type specified in config
// type specified in store's field's type config
filter.type = filter.type || this.store.fields.get(dI).type.type;
}
} else {
filter = filters[i];
}
// if filter config found add filter for the column
if (filter) {
this.addFilter(filter);
}
}
}
},
/**
* Returns a filter for the given dataIndex, if one exists.
* @param {String} dataIndex The dataIndex of the desired filter object.
* @return {Ext.ux.grid.filter.Filter}
*/
getFilter : function (dataIndex) {
return this.filters.get(dataIndex);
},
/**
* Turns all filters off. This does not clear the configuration information
* (see {@link #removeAll}).
*/
clearFilters : function () {
this.filters.each(function (filter) {
filter.setActive(false);
});
},
/**
* Returns an Array of the currently active filters.
* @return {Array} filters Array of the currently active filters.
*/
getFilterData : function () {
var filters = [], i, len;
this.filters.each(function (f) {
if (f.active) {
var d = [].concat(f.serialize());
for (i = 0, len = d.length; i < len; i++) {
filters.push({
field: f.dataIndex,
data: d[i]
});
}
}
});
return filters;
},
/**
* Function to take the active filters data and build it into a query.
* The format of the query depends on the <code>{@link #encode}</code>
* configuration:
* <div class="mdetail-params"><ul>
*
* <li><b><tt>false</tt></b> : <i>Default</i>
* <div class="sub-desc">
* Flatten into query string of the form (assuming <code>{@link #paramPrefix}='filters'</code>:
* <pre><code>
filters[0][field]="someDataIndex"&
filters[0][data][comparison]="someValue1"&
filters[0][data][type]="someValue2"&
filters[0][data][value]="someValue3"&
* </code></pre>
* </div></li>
* <li><b><tt>true</tt></b> :
* <div class="sub-desc">
* JSON encode the filter data
* <pre><code>
filters[0][field]="someDataIndex"&
filters[0][data][comparison]="someValue1"&
filters[0][data][type]="someValue2"&
filters[0][data][value]="someValue3"&
* </code></pre>
* </div></li>
* </ul></div>
* Override this method to customize the format of the filter query for remote requests.
* @param {Array} filters A collection of objects representing active filters and their configuration.
* Each element will take the form of {field: dataIndex, data: filterConf}. dataIndex is not assured
* to be unique as any one filter may be a composite of more basic filters for the same dataIndex.
* @return {Object} Query keys and values
*/
buildQuery : function (filters) {
var p = {}, i, f, root, dataPrefix, key, tmp,
len = filters.length;
if (!this.encode){
for (i = 0; i < len; i++) {
f = filters[i];
root = [this.paramPrefix, '[', i, ']'].join('');
p[root + '[field]'] = f.field;
dataPrefix = root + '[data]';
for (key in f.data) {
p[[dataPrefix, '[', key, ']'].join('')] = f.data[key];
}
}
} else {
tmp = [];
for (i = 0; i < len; i++) {
f = filters[i];
tmp.push(Ext.apply(
{},
{field: f.field},
f.data
));
}
// only build if there is active filter
if (tmp.length > 0){
p[this.paramPrefix] = Ext.util.JSON.encode(tmp);
}
}
return p;
},
/**
* Removes filter related query parameters from the provided object.
* @param {Object} p Query parameters that may contain filter related fields.
*/
cleanParams : function (p) {
// if encoding just delete the property
if (this.encode) {
delete p[this.paramPrefix];
// otherwise scrub the object of filter data
} else {
var regex, key;
regex = new RegExp('^' + this.paramPrefix + '\[[0-9]+\]');
for (key in p) {
if (regex.test(key)) {
delete p[key];
}
}
}
},
/**
* Function for locating filter classes, overwrite this with your favorite
* loader to provide dynamic filter loading.
* @param {String} type The type of filter to load ('Filter' is automatically
* appended to the passed type; eg, 'string' becomes 'StringFilter').
* @return {Class} The Ext.ux.grid.filter.Class
*/
getFilterClass : function (type) {
// map the supported Ext.data.Field type values into a supported filter
switch(type) {
case 'auto':
case 'string':
type = 'string';
break;
case 'int':
case 'float':
type = 'numeric';
break;
case 'date' :
case 'dateAsString' :
type = 'date'
break;
}
return Ext.ux.grid.filter[type.substr(0, 1).toUpperCase() + type.substr(1) + 'Filter'];
}
});
// register ptype
Ext.preg('gridfilters', Ext.ux.grid.GridFilters);
* Overrides the methods getFilterData and buildQuery
* @class Ext.ux.grid.GridFiltersSpe
* @extends Ext.ux.grid.GridFilters
*/
Ext.ux.grid.GridFiltersSpe = Ext.extend(Ext.ux.grid.GridFilters, {
* Returns an Array of the currently active filters.
* @return {Array} filters Array of the currently active filters.
*/
getFilterData : function () {
var filters = [], i, len;
this.filters.each(function (f) {
if (f.active) {
var d = [].concat(f.serialize());
for (i = 0, len = d.length; i < len; i++) {
filters.push({
//David Arpin : définir le columnAlias au niveau du champ
columnAlias: f.columnAlias,
data: d[i]
});
}
}
});
return filters;
},
* Function to take the active filters data and build it into a query.
* The format of the query depends on the <code>{@link #encode}</code>
* configuration:
* <div class="mdetail-params"><ul>
*
* <li><b><tt>false</tt></b> : <i>Default</i>
* <div class="sub-desc">
* Flatten into query string of the form (assuming <code>{@link #paramPrefix}='filters'</code>:
* <pre><code>
filters[0][columnAlias]="someDataIndex"&
filters[0][data][comparison]="someValue1"&
filters[0][data][type]="someValue2"&
filters[0][data][value]="someValue3"&
* </code></pre>
* </div></li>
* <li><b><tt>true</tt></b> :
* <div class="sub-desc">
* JSON encode the filter data
* <pre><code>
filters[0][columnAlias]="someDataIndex"&
filters[0][data][comparison]="someValue1"&
filters[0][data][type]="someValue2"&
filters[0][data][value]="someValue3"&
* </code></pre>
* </div></li>
* </ul></div>
* Override this method to customize the format of the filter query for remote requests.
* @param {Array} filters A collection of objects representing active filters and their configuration.
* Each element will take the form of {field: dataIndex, data: filterConf}. dataIndex is not assured
* to be unique as any one filter may be a composite of more basic filters for the same dataIndex.
* @return {Object} Query keys and values
*/
buildQuery : function (filters) {
var p = {}, i, f, root, dataPrefix, key, tmp,
len = filters.length;
if (!this.encode){
for (i = 0; i < len; i++) {
f = filters[i];
root = [this.paramPrefix, '[', i, ']'].join('');
p[root + '[columnAlias]'] = f.columnAlias;
dataPrefix = root + '[data]';
for (key in f.data) {
p[[dataPrefix, '[', key, ']'].join('')] = f.data[key];
}
}
} else {
tmp = [];
for (i = 0; i < len; i++) {
f = filters[i];
tmp.push(Ext.apply(
{},
{columnAlias: f.columnAlias},
f.data
));
}
// only build if there is active filter
if (tmp.length > 0){
p[this.paramPrefix] = Ext.util.JSON.encode(tmp);
}
}
return p;
}
});
Ext.preg('gridfiltersspe', Ext.ux.grid.GridFiltersSpe);
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
* Ext.ux.grid.livegrid.GridPanel Copyright (c) 2007-2008,
* http://www.siteartwork.de
*
* Ext.ux.grid.livegrid.GridPanel is licensed under the terms of the GNU Open
* Source GPL 3.0 license.
*
* Commercial use is prohibited. Visit <http://www.siteartwork.de/livegrid> if
* you need to obtain a commercial license.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/gpl.html>.
*
*/
/*global Ext, sitools, i18n, extColModelToSrv*/
Ext.namespace('Ext.ux.grid.livegrid');
/**
* @class Ext.ux.grid.livegrid.GridPanel
* @extends Ext.grid.GridPanel
* @constructor
* @param {Object}
* config
*
* @author Thorsten Suckow-Homberg <ts@siteartwork.de>
*/
Ext.ux.grid.livegrid.GridPanel = Ext.extend(Ext.grid.GridPanel, {
initComponent : function () {
if (this.cls) {
this.cls += ' ext-ux-livegrid';
} else {
this.cls = 'ext-ux-livegrid';
}
Ext.ux.grid.livegrid.GridPanel.superclass.initComponent.call(this);
},
/**
* Overriden to make sure the attached store loads only when the grid has
* been fully rendered if, and only if the store's "autoLoad" property is
* set to true.
*
*/
onRender : function (ct, position) {
Ext.ux.grid.livegrid.GridPanel.superclass.onRender.call(this, ct, position);
var ds = this.getStore();
if (ds._autoLoad === true) {
delete ds._autoLoad;
ds.load();
}
},
/**
* Overriden since the original implementation checks for getCount() of the
* store, not getTotalCount().
*
*/
walkCells : function (row, col, step, fn, scope) {
var ds = this.store;
var _oF = ds.getCount;
ds.getCount = ds.getTotalCount;
var ret = Ext.ux.grid.livegrid.GridPanel.superclass.walkCells.call(this, row, col, step, fn, scope);
ds.getCount = _oF;
return ret;
}
});
/**
* Ext.ux.grid.livegrid.GridView Copyright (c) 2007-2008,
* http://www.siteartwork.de
*
* Ext.ux.grid.livegrid.GridView is licensed under the terms of the GNU Open
* Source GPL 3.0 license.
*
* Commercial use is prohibited. Visit <http://www.siteartwork.de/livegrid> if
* you need to obtain a commercial license.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/gpl.html>.
*
*/
Ext.namespace('Ext.ux.grid.livegrid');
/**
* @class Ext.ux.grid.livegrid.GridView
* @extends Ext.grid.GridView
* @constructor
* @param {Object}
* config
*
* @author Thorsten Suckow-Homberg <ts@siteartwork.de>
*/
Ext.ux.grid.livegrid.GridView = function (config) {
this.addEvents({
/**
* @event beforebuffer Fires when the store is about to buffer new data.
* @param {Ext.ux.BufferedGridView}
* this
* @param {Ext.data.Store}
* store The store
* @param {Number}
* rowIndex
* @param {Number}
* visibleRows
* @param {Number}
* totalCount
* @param {Number}
* options The options with which the buffer request was
* called
*/
'beforebuffer' : true,
/**
* @event buffer Fires when the store is finsihed buffering new data.
* @param {Ext.ux.BufferedGridView}
* this
* @param {Ext.data.Store}
* store The store
* @param {Number}
* rowIndex
* @param {Number}
* visibleRows
* @param {Number}
* totalCount
* @param {Object}
* options
*/
'buffer' : true,
/**
* @event bufferfailure Fires when buffering failed.
* @param {Ext.ux.BufferedGridView}
* this
* @param {Ext.data.Store}
* store The store
* @param {Object}
* options The options the buffer-request was initiated with
*/
'bufferfailure' : true,
/**
* @event cursormove Fires when the the user scrolls through the data.
* @param {Ext.ux.BufferedGridView}
* this
* @param {Number}
* rowIndex The index of the first visible row in the grid
* absolute to it's position in the model.
* @param {Number}
* visibleRows The number of rows visible in the grid.
* @param {Number}
* totalCount
*/
'cursormove' : true,
/**
* @event abortrequest Fires when the store is about to reload (this
* does NOT mean buffering). If you are using a custom proxy in
* your store, you should listen to this event and abort any
* ongoing server request established in your custom proxy.
* @param {Ext.data.Store}
* store
* @param {Object}
* options
*/
'abortrequest' : true
});
/**
* @cfg {Number} scrollDelay The number of microseconds a call to the
* onLiveScroll-lisener should be delayed when the scroll event fires
*/
/**
* @cfg {Number} bufferSize The number of records that will at least always
* be available in the store for rendering. This value will be send to
* the server as the <tt>limit</tt> parameter and should not change
* during the lifetime of a grid component. Note: In a paging grid,
* this number would indicate the page size. The value should be set
* high enough to make a userfirendly scrolling possible and should be
* greater than the sum of {nearLimit} and {visibleRows}. Usually, a
* value in between 150 and 200 is good enough. A lesser value will
* more often make the store re-request new data, while a larger number
* will make loading times higher.
*/
/**
* @cfg {Number} nearLimit This value represents a near value that is
* responsible for deciding if a request for new data is needed. The
* lesser the number, the more often new data will be requested. The
* number should be set to a value that lies in between 1/4 to 1/2 of
* the {bufferSize}.
*/
/**
* @cfg {Number} horizontalScrollOffset The height of a horizontal aligned
* scrollbar. The scrollbar is shown if the total width of all visible
* columns exceeds the width of the grid component. On Windows XP (IE7,
* FF2), this value defaults to 17.
*/
this.horizontalScrollOffset = 17;
/**
* @type {Boolean} _checkEmptyBody Since Ext 3.0, would initially
* added to the mainBody as the first child if there are no rows to
* render. This element has to be removed when the first rows get
* added so the UI does not crash. This property is here to determine
* if this element was already removed, so we don't have to query
* innerHTML all the time.
*/
this._checkEmptyBody = true;
Ext.apply(this, config);
this.templates = {};
/**
* The master template adds an addiiotnal scrollbar to make cursoring in the
* data possible.
*/
this.templates.master = new Ext.Template(
'<div class="x-grid3" hidefocus="true"><div class="liveScroller"><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div>',
'<div class="x-grid3-viewport"">',
'<div class="x-grid3-header"><div class="x-grid3-header-inner"><div class="x-grid3-header-offset" style="{ostyle}">{header}</div></div><div class="x-clear"></div></div>',
'<div class="x-grid3-scroller" style="overflow-y:hidden !important;"><div class="x-grid3-body" style="{bstyle}">{body}</div><a href="#" class="x-grid3-focus" tabIndex="-1"></a></div>',
"</div>", '<div class="x-grid3-resize-marker"> </div>',
'<div class="x-grid3-resize-proxy"> </div>', "</div>");
// shorthands for often used parent classes
this._gridViewSuperclass = Ext.ux.grid.livegrid.GridView.superclass;
this._gridViewSuperclass.constructor.call(this);
};
Ext.extend(Ext.ux.grid.livegrid.GridView, Ext.ux.sitoolsGridView, {
// {{{
// --------------------------properties-------------------------------------
/**
* Stores the height of the header. Needed for recalculating scroller inset
* height.
*
* @param {Number}
*/
hdHeight : 0,
/**
* Indicates wether the last row in the grid is clipped and thus not fully
* display. 1 if clipped, otherwise 0.
*
* @param {Number}
*/
rowClipped : 0,
/**
* This is the actual y-scroller that does control sending request to the
* server based upon the position of the scrolling cursor.
*
* @param {Ext.Element}
*/
liveScroller : null,
/**
* This array holds the divs that represent the amount of data in a given
* repository. The sum of heights of this divs gets computed via the total
* amount of records multiplied with the fixed(!) row height. There is a
* total of 3 divs responsible for the scroll amount to prevent issues with
* the max number of pxiels a div alone can grow in height.
*
* @param {native
* HTMLObject}
*/
liveScrollerInsets : null,
/**
* The <b>fixed</b> row height for <b>every</b> row in the grid. The value
* is computed once the store has been loaded for the first time and used
* for various calculations during the lifetime of the grid component, such
* as the height of the scroller and the number of visible rows.
*
* @param {Number}
*/
rowHeight : -1,
/**
* Stores the number of visible rows that have to be rendered.
*
* @param {Number}
*/
visibleRows : 1,
/**
* Stores the last offset relative to a previously scroll action. This is
* needed for deciding wether the user scrolls up or down.
*
* @param {Number}
*/
lastIndex : -1,
/**
* Stores the last visible row at position "0" in the table view before a
* new scroll event was created and fired.
*
* @param {Number}
*/
lastRowIndex : 0,
/**
* Stores the value of the <tt>liveScroller</tt>'s <tt>scrollTop</tt>
* DOM property.
*
* @param {Number}
*/
lastScrollPos : 0,
/**
* The current index of the row in the model that is displayed as the first
* visible row in the view.
*
* @param {Number}
*/
rowIndex : 0,
/**
* Set to <tt>true</tt> if the store is busy with loading new data.
*
* @param {Boolean}
*/
isBuffering : false,
/**
* If a request for new data was made and the user scrolls to a new position
* that lays not within the requested range of the new data, the queue will
* hold the latest requested position. If the buffering succeeds and the
* value of requestQueue is not within the range of the current buffer, data
* may be re-requested.
*
* @param {Number}
*/
requestQueue : -1,
/**
* An {@Ext.LoadMask} config that will be shown when a request to data was
* made and there are no rows in the buffer left to render.
*
* @param {Object}
*/
loadMask : false,
/**
* A shortcut to indicate whether the loadMask is currently being displayed.
*
* @type {Boolean}
* @private
*/
loadMaskDisplayed : false,
/**
* Set to <tt>true</tt> if a request for new data has been made while
* there are still rows in the buffer that can be rendered before the
* request finishes.
*
* @param {Boolean}
*/
isPrebuffering : false,
/**
* The dom node for which the node mask will be rendered.
*
* @type {Ext.Element}
* @private
*/
_loadMaskAnchor : null,
/**
* used to know if you have to display Warning if too many rows
*/
_displayWarningTooManyRows : true,
// }}}
// {{{ --------------------------public API
// methods-----------------------------
/**
* Resets the view to display the first row in the data model. This will
* change the scrollTop property of the scroller and may trigger a request
* to buffer new data, if the row index "0" is not within the buffer range
* and forceReload is set to true.
*
* @param {Boolean}
* forceReload <tt>true</tt> to reload the buffers contents,
* othwerwise <tt>false</tt>
*
* @return {Boolean} Whether the store loads after reset(true); returns
* false if any of the attached beforeload listeners cancels the
* load-event
*/
reset : function (forceReload) {
if (forceReload === false) {
this.ds.modified = [];
// this.grid.selModel.clearSelections(true);
this.rowIndex = 0;
this.lastScrollPos = 0;
this.lastRowIndex = 0;
this.lastIndex = 0;
this.adjustVisibleRows();
this.adjustScrollerPos(-this.liveScroller.dom.scrollTop, true);
this.showLoadMask(false);
var _ofn = this.processRows;
this.processRows = Ext.emptyFn;
this.refresh(true);
this.processRows = _ofn;
this.processRows(0);
this.fireEvent('cursormove', this, 0, Math.min(this.ds.totalLength, this.visibleRows - this.rowClipped),
this.ds.totalLength);
return false;
} else {
var params = {
colModel : Ext.util.JSON.encode(extColModelToSrv(this.cm))
};
var sInfo = this.ds.sortInfo;
if (sInfo) {
Ext.apply(params, {
dir : sInfo.direction,
sort : sInfo.field
});
}
return this.ds.load({
params : params
});
}
},
// {{{ ------------adjusted methods for applying custom
// behavior----------------
// private
render : function() {
if (this.autoFill) {
var ct = this.grid.ownerCt;
if (ct && ct.getLayout()) {
ct.on('afterlayout', function() {
this.fitColumns(true, true);
this.updateHeaders();
this.updateHeaderSortState();
}, this, {single: true});
}
} else if (this.forceFit) {
this.fitColumns(true, false);
} else if (this.grid.autoExpandColumn) {
this.autoExpand(true);
}
this.grid.getGridEl().dom.innerHTML = this.renderUI();
this.afterRenderUI();
},
/**
* Overwritten so the {@link Ext.ux.grid.livegrid.DragZone} can be used with
* this view implementation.
*
* Since detaching a previously created DragZone from a grid panel seems to
* be impossible, a little workaround will tell the parent implementation
* that drad/drop is not enabled for this view's grid, and right after that
* the custom DragZone will be created, if neccessary.
*/
renderUI : function () {
var g = this.grid;
var dEnabled = g.enableDragDrop || g.enableDrag;
g.enableDragDrop = false;
g.enableDrag = false;
var m = this._gridViewSuperclass.renderUI.call(this);
g = this.grid;
g.enableDragDrop = dEnabled;
g.enableDrag = dEnabled;
if (dEnabled) {
this.dragZone = new Ext.ux.grid.livegrid.DragZone(g, {
ddGroup : g.ddGroup || 'GridDD'
});
}
return m;
},
afterRenderUI : function()
{
this._gridViewSuperclass.afterRenderUI.call(this);
if (this.loadMask) {
this._loadMaskAnchor = Ext.get(this.mainBody.dom.parentNode.parentNode);
Ext.apply(this.loadMask, {
msgCls : 'x-mask-loading'
});
this._loadMaskAnchor.mask(this.loadMask.msg, this.loadMask.msgCls);
var dom = this._loadMaskAnchor.dom;
var data = Ext.Element.data;
data(dom, 'mask').addClass('ext-ux-livegrid');
data(dom, 'mask').setDisplayed(false);
data(dom, 'maskMsg').setDisplayed(false);
}
},
/**
* The extended implementation attaches an listener to the beforeload event
* of the store of the grid. It is guaranteed that the listener will only be
* executed upon reloading of the store, sorting and initial loading of
* data. When the store does "buffer", all events are suspended and the
* beforeload event will not be triggered.
*
* @param {Ext.grid.GridPanel}
* grid The grid panel this view is attached to
*/
init : function (grid) {
this._gridViewSuperclass.init.call(this, grid);
grid.on('expand', this._onExpand, this);
},
initData : function (ds, cm) {
if (this.ds) {
this.ds.un('bulkremove', this.onBulkRemove, this);
this.ds.un('beforeload', this.onBeforeLoad, this);
}
if (ds) {
ds.on('bulkremove', this.onBulkRemove, this);
ds.on('beforeload', this.onBeforeLoad, this);
}
this._gridViewSuperclass.initData.call(this, ds, cm);
},
/**
* Only render the viewable rect of the table. The number of rows visible to
* the user is defined in <tt>visibleRows</tt>. This implementation does
* completely overwrite the parent's implementation.
*/
// private
renderBody : function () {
var markup = this.renderRows(0, this.visibleRows - 1);
return this.templates.body.apply({
rows : markup
});
},
/**
* Overriden so the renderer of the specific cells gets the index of the row
* as available in the view passed (row's rowIndex property)-
*
*/
doRender : function (cs, rs, ds, startRow, colCount, stripe) {
return this._gridViewSuperclass.doRender.call(this, cs, rs, ds, startRow + this.ds.bufferRange[0], colCount,
stripe);
},
/**
* Inits the DOM native elements for this component. The properties
* <tt>liveScroller</tt> and <tt>liveScrollerInsets</tt> will be
* respected as provided by the master template. The <tt>scroll</tt>
* listener for the <tt>liverScroller</tt> will also be added here as the
* <tt>mousewheel</tt> listener. This method overwrites the parents
* implementation.
*/
// private
initElements : function () {
var E = Ext.Element;
var el = this.grid.getGridEl().dom.firstChild;
var cs = el.childNodes;
this.el = new E(el);
this.mainWrap = new E(cs[1]);
// liveScroller and liveScrollerInsets
this.liveScroller = new E(cs[0]);
var f = this.liveScroller.dom.firstChild;
this.liveScrollerInsets = [ f ];
var divSuivante = f.nextSibling;
while (!Ext.isEmpty(divSuivante)) {
this.liveScrollerInsets.push(divSuivante);
divSuivante = divSuivante.nextSibling;
}
//this.liveScrollerInsets = [ f, f.nextSibling, f.nextSibling.nextSibling, f.nextSibling.nextSibling.nextSibling, f.nextSibling.nextSibling.nextSibling.nextSibling, f.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling ];
this.liveScroller.on('scroll', this.onLiveScroll, this, {
buffer : this.scrollDelay
});
var thd = this.mainWrap.dom.firstChild;
this.mainHd = new E(thd);
this.hdHeight = thd.offsetHeight;
this.innerHd = this.mainHd.dom.firstChild;
this.scroller = new E(this.mainWrap.dom.childNodes[1]);
if (this.forceFit) {
this.scroller.setStyle('overflow-x', 'hidden');
}
this.mainBody = new E(this.scroller.dom.firstChild);
// addd the mousewheel event to the table's body
this.mainBody.on('mousewheel', this.handleWheel, this);
this.focusEl = new E(this.scroller.dom.childNodes[1]);
this.focusEl.swallowEvent("click", true);
this.resizeMarker = new E(cs[2]);
this.resizeProxy = new E(cs[3]);
},
/**
* Layouts the grid's view taking the scroller into account. The height of
* the scroller gets adjusted depending on the total width of the columns.
* The width of the grid view will be adjusted so the header and the rows do
* not overlap the scroller. This method will also compute the row-height
* based on the first row this grid displays and will adjust the number of
* visible rows if a resize of the grid component happened. This method
* overwrites the parents implementation.
*/
// private
layout : function () {
if (!this.mainBody) {
return; // not rendered
}
var g = this.grid;
var c = g.getGridEl(), cm = this.cm, expandCol = g.autoExpandColumn, gv = this;
var csize = c.getSize(true);
// set vw to 19 to take scrollbar width into account!
var vw = csize.width;
if (!g.hideHeaders && vw < 20 || csize.height < 20) { // display:
// none?
return;
}
if (g.autoHeight) {
this.scroller.dom.style.overflow = 'visible';
if (Ext.isWebKit) {
this.scroller.dom.style.position = 'static';
}
} else {
this.el.setSize(csize.width, csize.height);
var hdHeight = this.mainHd.getHeight();
var vh = csize.height - (hdHeight);
this.scroller.setSize(vw, vh);
if (this.innerHd) {
this.innerHd.style.width = (vw) + 'px';
}
}
this.liveScroller.dom.style.top = this.hdHeight + "px";
if (this.forceFit) {
if (this.lastViewWidth != vw) {
this.fitColumns(false, false);
this.lastViewWidth = vw;
}
} else {
this.autoExpand();
}
// adjust the number of visible rows and the height of the scroller.
this.adjustVisibleRows();
this.adjustBufferInset();
this.onLayout(vw, vh);
},
/**
* Overriden for Ext 2.2 to prevent call to focus Row.
*
*/
removeRow : function (row) {
Ext.removeNode(this.getRow(row));
},
/**
* Overriden for Ext 2.2 to prevent call to focus Row. This method i s here
* for dom operations only - the passed arguments are the index of the nodes
* in the dom, not in the model.
*
*/
removeRows : function (firstRow, lastRow) {
var bd = this.mainBody.dom;
for (var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++) {
Ext.removeNode(bd.childNodes[firstRow]);
}
},
// {{{ ----------------------dom/mouse
// listeners--------------------------------
/**
* Tells the view to recalculate the number of rows displayable and the
* buffer inset, when it gets expanded after it has been collapsed.
*
*/
_onExpand : function (panel) {
this.adjustVisibleRows();
this.adjustBufferInset();
this.adjustScrollerPos(this.rowHeight * this.rowIndex, true);
},
// private
onColumnMove : function (cm, oldIndex, newIndex) {
this.indexMap = null;
this.replaceLiveRows(this.rowIndex, true);
this.updateHeaders();
this.updateHeaderSortState();
this.afterMove(newIndex);
this.grid.fireEvent('columnmove', oldIndex, newIndex);
},
/**
* Called when a column width has been updated. Adjusts the scroller height
* and the number of visible rows wether the horizontal scrollbar is shown
* or not.
*/
onColumnWidthUpdated : function (col, w, tw) {
this.adjustVisibleRows();
this.adjustBufferInset();
},
/**
* Called when the width of all columns has been updated. Adjusts the
* scroller height and the number of visible rows wether the horizontal
* scrollbar is shown or not.
*/
onAllColumnWidthsUpdated : function (ws, tw) {
this.adjustVisibleRows();
this.adjustBufferInset();
},
/**
* Callback for selecting a row. The index of the row is the absolute index
* in the datamodel. If the row is not rendered, this method will do
* nothing.
*/
// private
onRowSelect : function (row) {
if (row < this.rowIndex || row > this.rowIndex+this.visibleRows) {
return;
}
this.addRowClass(row, this.selectedRowClass);
},
/**
* Callback for deselecting a row. The index of the row is the absolute
* index in the datamodel. If the row is not currently rendered in the view,
* this method will do nothing.
*/
// private
onRowDeselect : function (row) {
if (row < this.rowIndex || row > this.rowIndex+this.visibleRows) {
return;
}
this.removeRowClass(row, this.selectedRowClass);
},
// {{{ ----------------------data
// listeners-------------------------------------
/**
* Called when the buffer gets cleared. Simply calls the updateLiveRows
* method with the adjusted index and should force the store to reload
*/
// private
onClear : function () {
this.reset(false);
},
/**
* Callback for the "bulkremove" event of the attached datastore.
*
* @param {Ext.ux.grid.livegrid.Store}
* store
* @param {Array}
* removedData
*
*/
onBulkRemove : function (store, removedData) {
var record = null;
var index = 0;
var viewIndex = 0;
var len = removedData.length;
var removedInView = false;
var removedAfterView = false;
var scrollerAdjust = 0;
if (len === 0) {
return;
}
var tmpRowIndex = this.rowIndex;
var removedBefore = 0;
var removedAfter = 0;
var removedIn = 0;
for (var i = 0; i < len; i++) {
record = removedData[i][0];
index = removedData[i][1];
viewIndex = (index != Number.MIN_VALUE && index != Number.MAX_VALUE) ? index + this.ds.bufferRange[0] : index;
if (viewIndex < this.rowIndex) {
removedBefore++;
} else if (viewIndex >= this.rowIndex && viewIndex <= this.rowIndex + (this.visibleRows - 1)) {
removedIn++;
} else if (viewIndex >= this.rowIndex + this.visibleRows) {
removedAfter++;
}
this.fireEvent("beforerowremoved", this, viewIndex, record);
this.fireEvent("rowremoved", this, viewIndex, record);
}
var totalLength = this.ds.totalLength;
this.rowIndex = Math.max(0, Math.min(this.rowIndex - removedBefore, totalLength - (this.visibleRows - 1)));
this.lastRowIndex = this.rowIndex;
this.adjustScrollerPos(-(removedBefore * this.rowHeight), true);
this.updateLiveRows(this.rowIndex, true);
this.adjustBufferInset();
this.processRows(0, undefined, false);
},
/**
* Callback for the underlying store's remove method. The current
* implementation does only remove the selected row which record is in the
* current store.
*
* @see onBulkRemove()
*/
// private
onRemove : function (ds, record, index) {
this.onBulkRemove(ds, [ [ record, index ] ]);
},
/**
* The callback for the underlying data store when new data was added. If
* <tt>index</tt> equals to <tt>Number.MIN_VALUE</tt> or
* <tt>Number.MAX_VALUE</tt>, the method can't tell at which position in
* the underlying data model the records where added. However, if
* <tt>index</tt> equals to <tt>Number.MIN_VALUE</tt>, the
* <tt>rowIndex</tt> property will be adjusted to
* <tt>rowIndex+records.length</tt>, and the <tt>liveScroller</tt>'s
* properties get adjusted so it matches the new total number of records of
* the underlying data model. The same will happen to any records that get
* added at the store index which is currently represented by the first
* visible row in the view. Any other value will cause the method to compute
* the number of rows that have to be (re-)painted and calling the
* <tt>insertRows</tt> method, if neccessary.
*
* This method triggers the <tt>beforerowsinserted</tt> and
* <tt>rowsinserted</tt> event, passing the indexes of the records as they
* may default to the positions in the underlying data model. However, due
* to the fact that any sort algorithm may have computed the indexes of the
* records, it is not guaranteed that the computed indexes equal to the
* indexes of the underlying data model.
*
* @param {Ext.ux.grid.livegrid.Store}
* ds The datastore that buffers records from the underlying data
* model
* @param {Array}
* records An array containing the newly added
* {@link Ext.data.Record}s
* @param {Number}
* index The index of the position in the underlying
* {@link Ext.ux.grid.livegrid.Store} where the rows were added.
*/
// private
onAdd : function (ds, records, index) {
if (this._checkEmptyBody) {
if (this.mainBody.dom.innerHTML == ' ') {
this.mainBody.dom.innerHTML = '';
}
this._checkEmptyBody = false;
}
var recordLen = records.length;
// values of index which equal to Number.MIN_VALUE or Number.MAX_VALUE
// indicate that the records were not added to the store. The component
// does not know which index those records do have in the underlying
// data model
if (index == Number.MAX_VALUE || index == Number.MIN_VALUE) {
this.fireEvent("beforerowsinserted", this, index, index);
// if index equals to Number.MIN_VALUE, shift rows!
if (index == Number.MIN_VALUE) {
this.rowIndex = this.rowIndex + recordLen;
this.lastRowIndex = this.rowIndex;
this.adjustBufferInset();
this.adjustScrollerPos(this.rowHeight * recordLen, true);
this.fireEvent("rowsinserted", this, index, index, recordLen);
this.processRows(0, undefined, false);
// the cursor did virtually move
this.fireEvent('cursormove', this, this.rowIndex, Math.min(this.ds.totalLength, this.visibleRows - this.rowClipped), this.ds.totalLength);
return;
}
this.adjustBufferInset();
this.fireEvent("rowsinserted", this, index, index, recordLen);
return;
}
// only insert the rows which affect the current view.
var start = index + this.ds.bufferRange[0];
var end = start + (recordLen - 1);
var len = this.getRows().length;
var firstRow = 0;
var lastRow = 0;
// rows would be added at the end of the rows which are currently
// displayed, so fire the event, resize buffer and adjust visible
// rows and return
if (start > this.rowIndex + (this.visibleRows - 1)) {
this.fireEvent("beforerowsinserted", this, start, end);
this.fireEvent("rowsinserted", this, start, end, recordLen);
this.adjustVisibleRows();
this.adjustBufferInset();
}
// rows get added somewhere in the current view.
else if (start >= this.rowIndex && start <= this.rowIndex + (this.visibleRows - 1)) {
firstRow = index;
// compute the last row that would be affected of an insert
// operation
lastRow = index + (recordLen - 1);
this.lastRowIndex = this.rowIndex;
this.rowIndex = (start > this.rowIndex) ? this.rowIndex : start;
this.insertRows(ds, firstRow, lastRow);
if (this.lastRowIndex != this.rowIndex) {
this.fireEvent('cursormove', this, this.rowIndex, Math.min(this.ds.totalLength, this.visibleRows - this.rowClipped), this.ds.totalLength);
}
this.adjustVisibleRows();
this.adjustBufferInset();
}
// rows get added before the first visible row, which would not affect
// any
// rows to be re-rendered
else if (start < this.rowIndex) {
this.fireEvent("beforerowsinserted", this, start, end);
this.rowIndex = this.rowIndex + recordLen;
this.lastRowIndex = this.rowIndex;
this.adjustVisibleRows();
this.adjustBufferInset();
this.adjustScrollerPos(this.rowHeight * recordLen, true);
this.fireEvent("rowsinserted", this, start, end, recordLen);
this.processRows(0, undefined, true);
this.fireEvent('cursormove', this, this.rowIndex, Math.min(this.ds.totalLength, this.visibleRows - this.rowClipped), this.ds.totalLength);
}
},
// {{{ ----------------------store
// listeners------------------------------------
/**
* This callback for the store's "beforeload" event will adjust the start
* position and the limit of the data in the model to fetch. It is
* guaranteed that this method will only be called when the store initially
* loads, remeote-sorts or reloads. All other load events will be suspended
* when the view requests buffer data. See {updateLiveRows}. Note: If you
* are using a custom proxy, such as {Ext.data.DirectProxy}, you should
* listen to the 'abortrequest'-event, which will tell that an ongoing
* "read" request should be aborted, since the grid's store gets refreshed.
* If the store is using an instance of {Ext.data.HttpProxy}, the method
* will still be fired, but the request made through this proxy will be
* aborted automatically.
*
*
* @param {Ext.data.Store}
* store The store the Grid Panel uses
* @param {Object}
* options The configuration object for the proxy that loads data
* from the server
*/
onBeforeLoad : function (store, options) {
var proxy = store.proxy;
if (proxy.activeRequest && proxy.activeRequest[Ext.data.Api.actions.read]) {
proxy.getConnection().abort(proxy.activeRequest[Ext.data.Api.actions.read]);
}
this.fireEvent('abortrequest', store, options);
this.isBuffering = false;
this.isPreBuffering = false;
options.params = options.params || {};
var apply = Ext.apply;
apply(options, {
scope : this,
callback : function () {
this.reset(false);
},
suspendLoadEvent : false
});
apply(options.params, {
start : 0,
limit : this.ds.bufferSize
});
return true;
},
/**
* Method is used as a callback for the load-event of the attached data
* store. Adjusts the buffer inset based upon the <tt>totalCount</tt>
* property returned by the response. Overwrites the parent's
* implementation.
*/
onLoad : function (o1, o2, options) {
this.adjustBufferInset();
},
/**
* This will be called when the data in the store has changed, i.e. a
* re-buffer has occured. If the table was not rendered yet, a call to
* <tt>refresh</tt> will initially render the table, which DOM elements
* will then be used to re-render the table upon scrolling.
*
*/
// private
onDataChange : function (store) {
this.updateHeaderSortState();
},
/**
* A callback for the store when new data has been buffered successfully. If
* the current row index is not within the range of the newly created data
* buffer or another request to new data has been made while the store was
* loading, new data will be re-requested.
*
* Additionally, if there are any rows that have been selected which were
* not in the data store, the method will request the pending selections
* from the grid's selection model and add them to the selections if
* available. This is because the component assumes that a user who scrolls
* through the rows and updates the view's buffer during scrolling, can
* check the selected rows which come into the view for integrity. It is up
* to the user to deselect those rows not matchuing the selection.
* Additionally, if the version of the store changes during various requests
* and selections are still pending, the versionchange event of the store
* can delete the pending selections after a re-bufer happened and before
* this method was called.
*
*/
// private
liveBufferUpdate : function (records, options, success) {
if (success === true) {
this.adjustBufferInset();
this.fireEvent('buffer', this, this.ds, this.rowIndex, Math.min(this.ds.totalLength, this.visibleRows - this.rowClipped), this.ds.totalLength, options);
// this is needed since references to records which have been
// unloaded
// get lost when the store gets loaded with new data.
// from the store
this.grid.selModel.replaceSelections(records);
this.isBuffering = false;
this.isPrebuffering = false;
this.showLoadMask(false);
if (this.requestQueue >= 0) {
var offset = this.requestQueue;
this.requestQueue = -1;
this.updateLiveRows(offset);
return;
}
if (this.isInRange(this.rowIndex)) {
this.replaceLiveRows(this.rowIndex, options.forceRepaint);
} else {
this.updateLiveRows(this.rowIndex);
}
return;
} else {
this.fireEvent('bufferfailure', this, this.ds, options);
}
this.requestQueue = -1;
this.isBuffering = false;
this.isPrebuffering = false;
this.showLoadMask(false);
},
// {{{ ----------------------scroll
// listeners------------------------------------
/**
* Handles mousewheel event on the table's body. This is neccessary since
* the <tt>liveScroller</tt> element is completely detached from the
* table's body.
*
* @param {Ext.EventObject}
* e The event object
*/
handleWheel : function (e) {
if (this.rowHeight == -1) {
e.stopEvent();
return;
}
var d = e.getWheelDelta();
this.adjustScrollerPos(-(d * this.rowHeight));
e.stopEvent();
},
/**
* Handles scrolling through the grid. Since the grid is fixed and rows get
* removed/ added subsequently, the only way to determine the actual row in
* view is to measure the <tt>scrollTop</tt> property of the
* <tt>liveScroller</tt>'s DOM element.
*
*/
onLiveScroll : function () {
var scrollTop = this.liveScroller.dom.scrollTop;
var cursor = Math.floor((scrollTop) / this.rowHeight);
this.rowIndex = cursor;
// the lastRowIndex will be set when refreshing the view has finished
if (cursor == this.lastRowIndex) {
return;
}
this.updateLiveRows(cursor);
this.lastScrollPos = this.liveScroller.dom.scrollTop;
},
// {{{
// --------------------------helpers----------------------------------------
// private
refreshRow : function (record) {
var ds = this.ds, index;
if (typeof record == 'number') {
index = record;
record = ds.getAt(index);
} else {
index = ds.indexOf(record);
}
var viewIndex = index + this.ds.bufferRange[0];
if (viewIndex < this.rowIndex || viewIndex >= this.rowIndex + this.visibleRows) {
this.fireEvent("rowupdated", this, viewIndex, record);
return;
}
this.insertRows(ds, index, index, true);
this.fireEvent("rowupdated", this, viewIndex, record);
},
/**
* Overwritten so the rowIndex can be changed to the absolute index.
*
* If the third parameter equals to <tt>true</tt>, the method will also
* repaint the selections.
*/
// private
processRows : function (startRow, skipStripe, paintSelections) {
if (!this.ds || this.ds.getCount() < 1) {
return;
}
skipStripe = skipStripe || !this.grid.stripeRows;
var cursor = this.rowIndex;
var rows = this.getRows();
var index = 0;
var row = null;
for (var idx = 0, len = rows.length; idx < len; idx++) {
row = rows[idx];
row.rowIndex = index = cursor + idx;
row.className = row.className.replace(this.rowClsRe, ' ');
if (!skipStripe && (index + 1) % 2 === 0) {
row.className += ' x-grid3-row-alt';
}
if (paintSelections !== false) {
if (this.grid.selModel.isSelected(this.ds.getAt(index)) === true) {
this.addRowClass(index, this.selectedRowClass);
} else {
this.removeRowClass(index, this.selectedRowClass);
}
this.fly(row).removeClass("x-grid3-row-over");
}
}
// add first/last-row classes
if (cursor === 0) {
Ext.fly(rows[0]).addClass(this.firstRowCls);
} else if (cursor + rows.length == this.ds.totalLength) {
Ext.fly(rows[rows.length - 1]).addClass(this.lastRowCls);
}
},
/**
* API only, since the passed arguments are the indexes in the buffer store.
* However, the method will try to compute the indexes so they might match
* the indexes of the records in the underlying data model.
*
*/
// private
insertRows : function (dm, firstRow, lastRow, isUpdate) {
var viewIndexFirst = firstRow + this.ds.bufferRange[0];
var viewIndexLast = lastRow + this.ds.bufferRange[0];
if (!isUpdate) {
this.fireEvent("beforerowsinserted", this, viewIndexFirst, viewIndexLast);
}
// first off, remove the rows at the bottom of the view to match the
// visibleRows value and to not cause any spill in the DOM
if (isUpdate !== true && (this.getRows().length + (lastRow - firstRow)) >= this.visibleRows) {
this.removeRows((this.visibleRows - 1) - (lastRow - firstRow), this.visibleRows - 1);
} else if (isUpdate) {
this.removeRows(viewIndexFirst - this.rowIndex, viewIndexLast - this.rowIndex);
}
// compute the range of possible records which could be drawn into the
// view without
// causing any spill
var lastRenderRow = (firstRow == lastRow) ? lastRow : Math.min(lastRow,
(this.rowIndex - this.ds.bufferRange[0]) + (this.visibleRows - 1));
var html = this.renderRows(firstRow, lastRenderRow);
var before = this.getRow(viewIndexFirst);
if (before) {
Ext.DomHelper.insertHtml('beforeBegin', before, html);
} else {
Ext.DomHelper.insertHtml('beforeEnd', this.mainBody.dom, html);
}
// if a row is replaced, we need to set the row index for this
// row
if (isUpdate === true) {
var rows = this.getRows();
var cursor = this.rowIndex;
for (var i = 0, max_i = rows.length; i < max_i; i++) {
rows[i].rowIndex = cursor + i;
}
}
if (!isUpdate) {
this.fireEvent("rowsinserted", this, viewIndexFirst, viewIndexLast, (viewIndexLast - viewIndexFirst) + 1);
this.processRows(0, undefined, true);
}
},
/**
* Return the
* <TR> HtmlElement which represents a Grid row for the specified index. The
* passed argument is assumed to be the absolute index and will get
* translated to the index of the row that represents the data in the view.
*
* @param {Number}
* index The row index
*
* @return {null|HtmlElement} The
* <TR> element, or null if the row is not rendered in the view.
*/
getRow : function (row) {
if (row - this.rowIndex < 0) {
return null;
}
return this.getRows()[row - this.rowIndex];
},
/**
* Returns the grid's
* <TD> HtmlElement at the specified coordinates. Returns null if the
* specified row is not currently rendered.
*
* @param {Number}
* row The row index in which to find the cell.
* @param {Number}
* col The column index of the cell.
* @return {HtmlElement} The <TD> at the specified coordinates.
*/
getCell : function (row, col) {
var arow = this.getRow(row);
return arow ? arow.getElementsByTagName('td')[col] : null;
},
/**
* Focuses the specified cell.
*
* @param {Number}
* row The row index
* @param {Number}
* col The column index
*/
focusCell : function (row, col, hscroll) {
var xy = this.ensureVisible(row, col, hscroll);
if (!xy) {
return;
}
this.focusEl.setXY(xy);
if (Ext.isGecko) {
this.focusEl.focus();
} else {
this.focusEl.focus.defer(1, this.focusEl);
}
},
/**
* Makes sure that the requested /row/col is visible in the viewport. The
* method may invoke a request for new buffer data and triggers the
* scroll-event of the <tt>liveScroller</tt> element.
*
*/
// private
ensureVisible : function (row, col, hscroll) {
if (typeof row != "number") {
row = row.rowIndex;
}
if (row < 0 || row >= this.ds.totalLength) {
return;
}
col = (col !== undefined ? col : 0);
var rowInd = row - this.rowIndex;
if (this.rowClipped && row == this.rowIndex + this.visibleRows - 1) {
this.adjustScrollerPos(this.rowHeight);
} else if (row >= this.rowIndex + this.visibleRows) {
this.adjustScrollerPos(((row - (this.rowIndex + this.visibleRows)) + 1) * this.rowHeight);
} else if (row <= this.rowIndex) {
this.adjustScrollerPos((rowInd) * this.rowHeight);
}
var rowEl = this.getRow(row), cellEl;
if (!rowEl) {
return;
}
if (!(hscroll === false && col === 0)) {
while (this.cm.isHidden(col)) {
col++;
}
cellEl = this.getCell(row, col);
}
var c = this.scroller.dom;
if (hscroll !== false) {
var cleft = parseInt(cellEl.offsetLeft, 10);
var cright = cleft + cellEl.offsetWidth;
var sleft = parseInt(c.scrollLeft, 10);
var sright = sleft + c.clientWidth;
if (cleft < sleft) {
c.scrollLeft = cleft;
} else if (cright > sright) {
c.scrollLeft = cright - c.clientWidth;
}
}
return cellEl ? Ext.fly(cellEl).getXY() : [ c.scrollLeft + this.el.getX(), Ext.fly(rowEl).getY() ];
},
/**
* Return strue if the passed record is in the visible rect of this view.
*
* @param {Ext.data.Record}
* record
*
* @return {Boolean} true if the record is rendered in the view, otherwise
* false.
*/
isRecordRendered : function (record) {
var ind = this.ds.indexOf(record);
if (ind >= this.rowIndex && ind < this.rowIndex + this.visibleRows) {
return true;
}
return false;
},
/**
* Checks if the passed argument <tt>cursor</tt> lays within a renderable
* area. The area is renderable, if the sum of cursor and the visibleRows
* property does not exceed the current upper buffer limit.
*
* If this method returns <tt>true</tt>, it's basically save to re-render
* the view with <tt>cursor</tt> as the absolute position in the model as
* the first visible row.
*
* @param {Number}
* cursor The absolute position of the row in the data model.
*
* @return {Boolean} <tt>true</tt>, if the row can be rendered, otherwise
* <tt>false</tt>
*
*/
isInRange : function (rowIndex) {
var lastRowIndex = Math.min(this.ds.totalLength - 1, rowIndex + (this.visibleRows - 1));
return (rowIndex >= this.ds.bufferRange[0]) && (lastRowIndex <= this.ds.bufferRange[1]);
},
/**
* Calculates the bufferRange start index for a buffer request
*
* @param {Boolean}
* inRange If the index is within the current buffer range
* @param {Number}
* index The index to use as a reference for the calculations
* @param {Boolean}
* down Wether the calculation was requested when the user
* scrolls down
*/
getPredictedBufferIndex : function (index, inRange, down) {
if (!inRange) {
if (index + this.ds.bufferSize >= this.ds.totalLength) {
return this.ds.totalLength - this.ds.bufferSize;
}
// we need at last to render the index + the visible Rows
return Math.max(0, (index + this.visibleRows) - Math.round(this.ds.bufferSize / 2));
}
if (!down) {
return Math.max(0, (index - this.ds.bufferSize) + this.visibleRows);
}
if (down) {
return Math.max(0, Math.min(index, this.ds.totalLength - this.ds.bufferSize));
}
},
/**
* Updates the table view. Removes/appends rows as needed and fetches the
* cells content out of the available store. If the needed rows are not
* within the buffer, the method will advise the store to update it's
* contents.
*
* The method puts the requested cursor into the queue if a previously
* called buffering is in process.
*
* @param {Number}
* cursor The row's position, absolute to it's position in the
* data model
*
*/
updateLiveRows : function (index, forceRepaint, forceReload) {
var inRange = this.isInRange(index);
if (this.isBuffering) {
if (this.isPrebuffering) {
if (inRange) {
this.replaceLiveRows(index, forceRepaint);
} else {
this.showLoadMask(true);
}
}
this.fireEvent('cursormove', this, index,
Math.min(this.ds.totalLength, this.visibleRows - this.rowClipped), this.ds.totalLength);
this.requestQueue = index;
return;
}
var lastIndex = this.lastIndex;
this.lastIndex = index;
inRange = this.isInRange(index);
var down = false;
if (inRange && forceReload !== true) {
// repaint the table's view
this.replaceLiveRows(index, forceRepaint);
// has to be called AFTER the rowIndex was recalculated
this.fireEvent('cursormove', this, index,
Math.min(this.ds.totalLength, this.visibleRows - this.rowClipped), this.ds.totalLength);
// lets decide if we can void this method or stay in here for
// requesting a buffer update
if (index > lastIndex) { // scrolling down
down = true;
var totalCount = this.ds.totalLength;
// while scrolling, we have not yet reached the row index
// that would trigger a re-buffer
if (index + this.visibleRows + this.nearLimit <= this.ds.bufferRange[1]) {
return;
}
// If we have already buffered the last range we can ever get
// by the queried data repository, we don't need to buffer
// again.
// This basically means that a re-buffer would only occur again
// if we are scrolling up.
if (this.ds.bufferRange[1] + 1 >= totalCount) {
return;
}
} else if (index < lastIndex) { // scrolling up
down = false;
// We are scrolling up in the first buffer range we can ever get
// Re-buffering would only occur upon scrolling down.
if (this.ds.bufferRange[0] <= 0) {
return;
}
// if we are scrolling up and we are moving in an acceptable
// buffer range, lets return.
if (index - this.nearLimit > this.ds.bufferRange[0]) {
return;
}
} else {
return;
}
this.isPrebuffering = true;
}
// prepare for rebuffering
this.isBuffering = true;
var bufferOffset = this.getPredictedBufferIndex(index, inRange, down);
if (!inRange) {
this.showLoadMask(true);
}
this.ds.suspendEvents();
var sInfo = this.ds.sortInfo;
var params = {};
if (this.ds.lastOptions) {
Ext.apply(params, this.ds.lastOptions.params);
}
params.start = bufferOffset;
params.limit = this.ds.bufferSize;
// if(this.ds.doCount){
params.nocount = true;
/*}else{
params.nocount = false;
}*/
if (sInfo) {
params.dir = sInfo.direction;
params.sort = sInfo.field;
}
var opts = {
forceRepaint : forceRepaint,
callback : this.liveBufferUpdate,
scope : this,
params : params,
suspendLoadEvent : true
};
this.fireEvent('beforebuffer', this, this.ds, index, Math.min(this.ds.totalLength, this.visibleRows - this.rowClipped), this.ds.totalLength, opts);
this.ds.load(opts);
this.ds.resumeEvents();
},
/**
* Shows this' view own load mask to indicate that a large amount of buffer
* data was requested by the store.
*
* @param {Boolean}
* show <tt>true</tt> to show the load mask, otherwise
* <tt>false</tt>
*/
showLoadMask : function (show) {
if (!this.loadMask || show == this.loadMaskDisplayed) {
return;
}
var dom = this._loadMaskAnchor.dom;
var data = Ext.Element.data;
var mask = data(dom, 'mask');
var maskMsg = data(dom, 'maskMsg');
if (show) {
mask.setDisplayed(true);
maskMsg.setDisplayed(true);
maskMsg.center(this._loadMaskAnchor);
// this lines will help IE8 to re-calculate the height of the
// loadmask
if (Ext.isIE && !(Ext.isIE7 && Ext.isStrict) && this._loadMaskAnchor.getStyle('height') == 'auto') {
mask.setSize(undefined, this._loadMaskAnchor.getHeight());
}
} else {
mask.setDisplayed(false);
maskMsg.setDisplayed(false);
}
this.loadMaskDisplayed = show;
},
/**
* Renders the table body with the contents of the model. The method will
* prepend/ append rows after removing from either the end or the beginning
* of the table DOM to reduce expensive DOM calls. It will also take care of
* rendering the rows selected, taking the property
* <tt>bufferedSelections</tt> of the {@link BufferedRowSelectionModel}
* into account. Instead of calling this method directly, the
* <tt>updateLiveRows</tt> method should be called which takes care of
* rebuffering if needed, since this method will behave erroneous if data of
* the buffer is requested which may not be available.
*
* @param {Number}
* cursor The position of the data in the model to start
* rendering.
*
* @param {Boolean}
* forceReplace <tt>true</tt> for recomputing the DOM in the
* view, otherwise <tt>false</tt>.
*/
// private
replaceLiveRows : function (cursor, forceReplace, processRows) {
var spill = cursor - this.lastRowIndex;
if (spill === 0 && forceReplace !== true) {
return;
}
// decide wether to prepend or append rows
// if spill is negative, we are scrolling up. Thus we have to prepend
// rows. If spill is positive, we have to append the buffers data.
var append = spill > 0;
// abs spill for simplyfiying append/prepend calculations
spill = Math.abs(spill);
// adjust cursor to the buffered model index
var bufferRange = this.ds.bufferRange;
var cursorBuffer = cursor - bufferRange[0];
// compute the last possible renderindex
var lpIndex = Math.min(cursorBuffer + this.visibleRows - 1, bufferRange[1] - bufferRange[0]);
// we can skip checking for append or prepend if the spill is larger
// than
// visibleRows. We can paint the whole rows new then-
if (spill >= this.visibleRows || spill === 0) {
this.mainBody.update(this.renderRows(cursorBuffer, lpIndex));
} else {
if (append) {
this.removeRows(0, spill - 1);
if (cursorBuffer + this.visibleRows - spill <= bufferRange[1] - bufferRange[0]) {
var html = this.renderRows(cursorBuffer + this.visibleRows - spill, lpIndex);
Ext.DomHelper.insertHtml('beforeEnd', this.mainBody.dom, html);
}
} else {
this.removeRows(this.visibleRows - spill, this.visibleRows - 1);
html = this.renderRows(cursorBuffer, cursorBuffer + spill - 1);
Ext.DomHelper.insertHtml('beforeBegin', this.mainBody.dom.firstChild, html);
}
}
if (processRows !== false) {
this.processRows(0, undefined, true);
}
this.lastRowIndex = cursor;
},
/**
* Adjusts the scroller height to make sure each row in the dataset will be
* can be displayed, no matter which value the current height of the grid
* component equals to.
*/
// protected
adjustBufferInset : function () {
var liveScrollerDom = this.liveScroller.dom;
var g = this.grid, ds = g.store;
var c = g.getGridEl();
var elWidth = c.getSize().width;
// hidden rows is the number of rows which cannot be
// displayed and for which a scrollbar needs to be
// rendered. This does also take clipped rows into account
var hiddenRows = (ds.totalLength == this.visibleRows - this.rowClipped) ? 0 : Math.max(0, ds.totalLength - (this.visibleRows - this.rowClipped));
if (hiddenRows === 0) {
this.scroller.setWidth(elWidth);
liveScrollerDom.style.display = 'none';
return;
} else {
this.scroller.setWidth(elWidth - this.getScrollOffset());
liveScrollerDom.style.display = '';
}
var scrollbar = this.cm.getTotalWidth() + this.getScrollOffset() > elWidth;
// adjust the height of the scrollbar
var contHeight = liveScrollerDom.parentNode.offsetHeight + ((ds.totalLength > 0 && scrollbar) ? -this.horizontalScrollOffset : 0) - this.hdHeight;
liveScrollerDom.style.height = Math.max(contHeight, this.horizontalScrollOffset * 2) + "px";
this.liveScroller.dom.style.width = (this.getScrollOffset() + 2) + "px";
if (this.rowHeight == -1) {
return;
}
var cm = this.cm;
var vw = elWidth - this.getScrollOffset();
var hso = 0, hh = 0;
// horizontal scrollbar shown?
if (cm.getTotalWidth() > vw) {
// yes!
hso = this.horizontalScrollOffset;
}
hh = this.mainHd.getHeight();
var h = (hiddenRows === 0 ? 0 : ds.totalLength * this.rowHeight + hso + hh);//contHeight + (hiddenRows * this.rowHeight));
//DA : Ajouter une limitation a la taille de la div générée. Générer un message pour l'utilisateur en cas de dépassement.
if (h > 35791380) {
h = 35000000;
var nbRecords = Math.floor(h / this.rowHeight);
if (this._displayWarningTooManyRows) {
Ext.Msg.alert(i18n.get('label.warning'), String.format(i18n.get("label.tooManyRecords"), nbRecords, this.visibleRows + hiddenRows));
this._displayWarningTooManyRows = false;
}
}
var oh = h;
var len = this.liveScrollerInsets.length;
if (h === 0) {
h = 0;
} else {
h = Math.round(h / len);
}
for (var i = 0; i < len; i++) {
if (i == len - 1 && h !== 0) {
h = oh - (h * i);
}
this.liveScrollerInsets[i].style.height = h + "px";
}
},
/**
* Recomputes the number of visible rows in the table based upon the height
* of the component. The method adjusts the <tt>rowIndex</tt> property as
* needed, if the sum of visible rows and the current row index exceeds the
* number of total data available.
*/
// protected
adjustVisibleRows : function () {
if (this.rowHeight == -1) {
if (this.getRows()[0]) {
this.rowHeight = this.getRows()[0].offsetHeight;
if (this.rowHeight <= 0) {
this.rowHeight = -1;
return;
}
} else {
return;
}
}
var g = this.grid, ds = g.store;
var c = g.getGridEl();
var cm = this.cm;
var size = c.getSize();
var width = size.width;
var vh = size.height;
var vw = width - this.getScrollOffset();
// horizontal scrollbar shown?
if (cm.getTotalWidth() > vw) {
// yes!
vh -= this.horizontalScrollOffset;
}
vh -= this.mainHd.getHeight();
var totalLength = ds.totalLength || 0;
var visibleRows = Math.max(1, Math.floor(vh / this.rowHeight));
this.rowClipped = 0;
// only compute the clipped row if the total length of records
// exceeds the number of visible rows displayable
if (totalLength > visibleRows && this.rowHeight / 3 < (vh - (visibleRows * this.rowHeight))) {
visibleRows = Math.min(visibleRows + 1, totalLength);
this.rowClipped = 1;
}
// if visibleRows didn't change, simply void and return.
if (this.visibleRows == visibleRows) {
return;
}
this.visibleRows = visibleRows;
// skip recalculating the row index if we are currently buffering, but
// not if we
// are just pre-buffering
if (this.isBuffering && !this.isPrebuffering) {
return;
}
// when re-rendering, doe not take the clipped row into account
if (this.rowIndex + (visibleRows - this.rowClipped) > totalLength) {
this.rowIndex = Math.max(0, totalLength - (visibleRows - this.rowClipped));
this.lastRowIndex = this.rowIndex;
}
this.updateLiveRows(this.rowIndex, true);
},
adjustScrollerPos : function (pixels, suspendEvent) {
if (pixels === 0) {
return;
}
var liveScroller = this.liveScroller;
var scrollDom = liveScroller.dom;
if (suspendEvent === true) {
liveScroller.un('scroll', this.onLiveScroll, this);
}
this.lastScrollPos = scrollDom.scrollTop;
scrollDom.scrollTop += pixels;
if (suspendEvent === true) {
scrollDom.scrollTop = scrollDom.scrollTop;
liveScroller.on('scroll', this.onLiveScroll, this, {
buffer : this.scrollDelay
});
}
}
});
/**
* Ext.ux.grid.livegrid.JsonReader Copyright (c) 2007-2008,
* http://www.siteartwork.de
*
* Ext.ux.grid.livegrid.JsonReader is licensed under the terms of the GNU Open
* Source GPL 3.0 license.
*
* Commercial use is prohibited. Visit <http://www.siteartwork.de/livegrid> if
* you need to obtain a commercial license.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/gpl.html>.
*
*/
Ext.namespace('Ext.ux.grid.livegrid');
/**
* @class Ext.ux.grid.livegrid.JsonReader
* @extends Ext.data.JsonReader
* @constructor
* @param {Object}
* config
*
* @author Thorsten Suckow-Homberg <ts@siteartwork.de>
*/
Ext.ux.grid.livegrid.JsonReader = function (meta, recordType) {
Ext.ux.grid.livegrid.JsonReader.superclass.constructor.call(this, meta, recordType);
};
Ext.extend(Ext.ux.grid.livegrid.JsonReader, Ext.data.JsonReader, {
/**
* @cfg {String} versionProperty Name of the property from which to retrieve
* the version of the data repository this reader parses the reponse
* from
*/
buildExtractors : function () {
if (this.ef) {
return;
}
var s = this.meta;
if (s.versionProperty) {
this.getVersion = this.createAccessor(s.versionProperty);
}
Ext.ux.grid.livegrid.JsonReader.superclass.buildExtractors.call(this);
},
/**
* Create a data block containing Ext.data.Records from a JSON object.
*
* @param {Object}
* o An object which contains an Array of row objects in the
* property specified in the config as 'root, and optionally a
* property, specified in the config as 'totalProperty' which
* contains the total size of the dataset.
* @return {Object} data A data block which is used by an Ext.data.Store
* object as a cache of Ext.data.Records.
*/
readRecords : function (o) {
// shorten for future calls
if (!this.__readRecords) {
this.__readRecords = Ext.ux.grid.livegrid.JsonReader.superclass.readRecords;
}
var intercept = this.__readRecords.call(this, o);
if (this.meta.versionProperty) {
var v = this.getVersion(o);
intercept.version = (v === undefined || v === "") ? null : v;
}
//TODO
if (Ext.isEmpty(o.total)) {
intercept.totalRecords = this.totalRecordsSitools;
} else {
this.totalRecordsSitools = o.total;
}
return intercept;
}
});
/**
* Ext.ux.grid.livegrid.RowSelectionModel Copyright (c) 2007-2008,
* http://www.siteartwork.de
*
* Ext.ux.grid.livegrid.RowSelectionModel is licensed under the terms of the GNU
* Open Source GPL 3.0 license.
*
* Commercial use is prohibited. Visit <http://www.siteartwork.de/livegrid> if
* you need to obtain a commercial license.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/gpl.html>.
*
*/
Ext.namespace('Ext.ux.grid.livegrid');
/**
* @class Ext.ux.grid.livegrid.RowSelectionModel
* @extends Ext.grid.RowSelectionModel
* @constructor
* @param {Object}
* config
*
* @author Thorsten Suckow-Homberg <ts@siteartwork.de>
*/
Ext.ux.grid.livegrid.RowSelectionModel = function (config) {
this.addEvents({
/**
* The selection dirty event will be triggered in case records were
* inserted/ removed at view indexes that may affect the current
* selection ranges which are only represented by view indexes, but not
* current record-ids
*/
'selectiondirty' : true,
//SITOOLS, MG, nouvel event pour gérer les selections
'handleMouseDown' : true
});
Ext.apply(this, config);
this.pendingSelections = {};
Ext.ux.grid.livegrid.RowSelectionModel.superclass.constructor.call(this);
};
Ext.extend(Ext.ux.grid.livegrid.RowSelectionModel, Ext.grid.RowSelectionModel, {
// private
initEvents : function () {
Ext.ux.grid.livegrid.RowSelectionModel.superclass.initEvents.call(this);
this.grid.view.on('rowsinserted', this.onAdd, this);
this.grid.store.on('selectionsload', this.onSelectionsLoad, this);
},
// private : DA : supprimer le view.focusRow (celui ci provoque un probleme
// lorsque le scroll horizontal est important
//SITOOLS, MG, nouvel event pour gérer les selections
handleMouseDown : function (g, rowIndex, e) {
if (e.button !== 0 || this.isLocked()) {
return;
}
var view = this.grid.getView();
if (e.shiftKey && !this.singleSelect && this.last !== false) {
var last = this.last;
this.selectRange(last, rowIndex, e.ctrlKey);
this.last = last;
// view.focusRow(rowIndex);
this.fireEvent('handleMouseDown', this);
} else {
var isSelected = this.isSelected(rowIndex);
if (e.ctrlKey && isSelected) {
this.deselectRow(rowIndex);
this.fireEvent('handleMouseDown', this);
} else if (!isSelected || this.getCount() > 1) {
this.selectRow(rowIndex, e.ctrlKey || e.shiftKey);
this.fireEvent('handleMouseDown', this);
// view.focusRow(rowIndex);
}
}
},
/**
* Callback is called when a row gets removed in the view. The process to
* invoke this method is as follows:
*
* <ul>
* <li>1. store.remove(record);</li>
* <li>2. view.onRemove(store, record, indexInStore, isUpdate)<br />
* [view triggers rowremoved event]</li>
* <li>3. this.onRemove(view, indexInStore, record)</li>
* </ul>
*
* If r defaults to <tt>null</tt> and index is within the pending
* selections range, the selectionchange event will be called, too.
* Additionally, the method will shift all selections and trigger the
* selectiondirty event if any selections are pending.
*
*/
onRemove : function (v, index, r) {
var ranges = this.getPendingSelections();
var rangesLength = ranges.length;
var selectionChanged = false;
// if index equals to Number.MIN_VALUE or Number.MAX_VALUE, mark current
// pending selections as dirty
if (index == Number.MIN_VALUE || index == Number.MAX_VALUE) {
if (r) {
// if the record is part of the current selection, shift the
// selection down by 1
// if the index equals to Number.MIN_VALUE
if (this.isIdSelected(r.id) && index == Number.MIN_VALUE) {
// bufferRange already counted down when this method gets
// called
this.shiftSelections(this.grid.store.bufferRange[1], -1);
}
this.selections.remove(r);
selectionChanged = true;
}
// clear all pending selections that are behind the first
// bufferrange, and shift all pending Selections that lay in front
// front of the second bufferRange down by 1!
if (index == Number.MIN_VALUE) {
this.clearPendingSelections(0, this.grid.store.bufferRange[0]);
} else {
// clear pending selections that are in front of bufferRange[1]
this.clearPendingSelections(this.grid.store.bufferRange[1]);
}
// only fire the selectiondirty event if there were pendning ranges
if (rangesLength !== 0) {
this.fireEvent('selectiondirty', this, index, 1);
}
} else {
selectionChanged = this.isIdSelected(r.id);
// if the record was not part of the selection, return
if (!selectionChanged) {
return;
}
this.selections.remove(r);
// this.last = false;
// if there are currently pending selections, look up the interval
// to tell whether removing the record would mark the selection
// dirty
if (rangesLength !== 0) {
var startRange = ranges[0];
var endRange = ranges[rangesLength - 1];
if (index <= endRange || index <= startRange) {
this.shiftSelections(index, -1);
this.fireEvent('selectiondirty', this, index, 1);
}
}
}
if (selectionChanged) {
this.fireEvent('selectionchange', this);
}
},
/**
* If records where added to the store, this method will work as a callback,
* called by the views' rowsinserted event. Selections will be shifted down
* if, and only if, the listeners for the selectiondirty event will return
* <tt>true</tt>.
*
*/
onAdd : function (store, index, endIndex, recordLength) {
var ranges = this.getPendingSelections();
var rangesLength = ranges.length;
// if index equals to Number.MIN_VALUE or Number.MAX_VALUE, mark current
// pending selections as dirty
if ((index == Number.MIN_VALUE || index == Number.MAX_VALUE)) {
if (index == Number.MIN_VALUE) {
// bufferRange already counted down when this method gets
// called
this.clearPendingSelections(0, this.grid.store.bufferRange[0]);
this.shiftSelections(this.grid.store.bufferRange[1], recordLength);
} else {
this.clearPendingSelections(this.grid.store.bufferRange[1]);
}
// only fire the selectiondirty event if there were pendning ranges
if (rangesLength !== 0) {
this.fireEvent('selectiondirty', this, index, r);
}
return;
}
// it is safe to say that the selection is dirty when the inserted index
// is less or equal to the first selection range index or less or equal
// to the last selection range index
var startRange = ranges[0];
var endRange = ranges[rangesLength - 1];
var viewIndex = index;
if (viewIndex <= endRange || viewIndex <= startRange) {
this.fireEvent('selectiondirty', this, viewIndex, recordLength);
this.shiftSelections(viewIndex, recordLength);
}
},
/**
* Shifts current/pending selections. This method can be used when rows
* where inserted/removed and the selection model has to synchronize itself.
*/
shiftSelections : function (startRow, length) {
var index = 0;
var newIndex = 0;
var newRequests = {};
var ds = this.grid.store;
var storeIndex = startRow - ds.bufferRange[0];
var newStoreIndex = 0;
var totalLength = this.grid.store.totalLength;
var rec = null;
// this.last = false;
var ranges = this.getPendingSelections();
var rangesLength = ranges.length;
if (rangesLength === 0) {
return;
}
for (var i = 0; i < rangesLength; i++) {
index = ranges[i];
if (index < startRow) {
continue;
}
newIndex = index + length;
newStoreIndex = storeIndex + length;
if (newIndex >= totalLength) {
break;
}
rec = ds.getAt(newStoreIndex);
if (rec) {
this.selections.add(rec);
} else {
newRequests[newIndex] = true;
}
//DA : Ajout de l'objet allSelections
this.allSelections[newIndex] = true;
}
this.pendingSelections = newRequests;
},
/**
*
* @param {Array}
* records The records that have been loaded
* @param {Array}
* ranges An array representing the model index ranges the reords
* have been loaded for.
*/
onSelectionsLoad : function (store, records, ranges) {
this.replaceSelections(records);
},
/**
* Returns true if there is a next record to select
*
* @return {Boolean}
*/
hasNext : function () {
return this.last !== false && (this.last + 1) < this.grid.store.getTotalCount();
},
/**
* Gets the number of selected rows.
*
* @return {Number}
*/
getCount : function () {
return this.selections.length + this.getPendingSelections().length;
},
/**
* Returns True if the specified row is selected.
*
* @param {Number/Record}
* record The record or index of the record to check
* @return {Boolean}
*/
isSelected : function (index) {
if (typeof index == "number") {
var orgInd = index;
index = this.grid.store.getAt(orgInd);
if (!index) {
var ind = this.getPendingSelections().indexOf(orgInd);
if (ind != -1) {
return true;
}
return false;
}
}
var r = index;
return (r && this.selections.key(r.id) ? true : false);
},
/**
* Deselects a record. The emthod assumes that the record is physically
* available, i.e. pendingSelections will not be taken into account
*/
deselectRecord : function (record, preventViewNotify) {
if (this.locked) {
return;
}
var isSelected = this.selections.key(record.id);
if (!isSelected) {
return;
}
var store = this.grid.store;
var index = store.indexOfId(record.id);
if (index == -1) {
index = store.findInsertIndex(record);
if (index != Number.MIN_VALUE && index != Number.MAX_VALUE) {
index += store.bufferRange[0];
}
} else {
// just to make sure, though this should not be
// set if the record was availablein the selections
delete this.pendingSelections[index];
}
if (this.last == index) {
this.last = false;
}
if (this.lastActive == index) {
this.lastActive = false;
}
//DA : suppression de l'item ds allSelections
delete this.allSelections[index];
this.selections.remove(record);
if (!preventViewNotify) {
this.grid.getView().onRowDeselect(index);
}
this.fireEvent("rowdeselect", this, index, record);
this.fireEvent("selectionchange", this);
},
/**
* Deselects a row.
*
* @param {Number}
* row The index of the row to deselect
*/
deselectRow : function (index, preventViewNotify) {
if (this.locked) {
return;
}
if (this.last == index) {
this.last = false;
}
if (this.lastActive == index) {
this.lastActive = false;
}
var r = this.grid.store.getAt(index);
//DA : gestion de l'objet allSelections
delete this.allSelections[index];
delete this.pendingSelections[index];
if (r) {
this.selections.remove(r);
}
if (!preventViewNotify) {
this.grid.getView().onRowDeselect(index);
}
this.fireEvent("rowdeselect", this, index, r);
this.fireEvent("selectionchange", this);
},
/**
* Selects a row.
*
* @param {Number}
* row The index of the row to select
* @param {Boolean}
* keepExisting (optional) True to keep existing selections
*/
selectRow : function (index, keepExisting, preventViewNotify) {
if (// this.last === index
// ||
this.locked || index < 0 || index >= this.grid.store.getTotalCount()) {
return;
}
var r = this.grid.store.getAt(index);
if (this.fireEvent("beforerowselect", this, index, keepExisting, r) !== false) {
if (!keepExisting || this.singleSelect) {
this.clearSelections();
}
if (r) {
this.selections.add(r);
delete this.pendingSelections[index];
} else {
this.pendingSelections[index] = true;
}
//DA : gestion de l'objet allSelections
this.allSelections[index] = true;
this.last = this.lastActive = index;
if (!preventViewNotify) {
this.grid.getView().onRowSelect(index);
}
this.fireEvent("rowselect", this, index, r);
this.fireEvent("selectionchange", this);
}
},
clearPendingSelections : function (startIndex, endIndex) {
if (endIndex === undefined) {
endIndex = Number.MAX_VALUE;
}
var newSelections = {};
var ranges = this.getPendingSelections();
var rangesLength = ranges.length;
var index = 0;
for (var i = 0; i < rangesLength; i++) {
index = ranges[i];
if (index <= endIndex && index >= startIndex) {
continue;
}
newSelections[index] = true;
}
this.pendingSelections = newSelections;
},
/**
* Replaces already set data with new data from the store if those records
* can be found within this.selections or this.pendingSelections
*
* @param {Array}
* An array with records buffered by the store
*/
replaceSelections : function (records) {
if (!records || records.length === 0) {
return;
}
var ds = this.grid.store;
var rec = null;
var assigned = [];
var ranges = this.getPendingSelections();
var rangesLength = ranges.length;
var selections = this.selections;
var index = 0;
for (var i = 0; i < rangesLength; i++) {
index = ranges[i];
rec = ds.getAt(index);
if (rec) {
selections.add(rec);
assigned.push(rec.id);
delete this.pendingSelections[index];
}
}
var id = null;
var len = null;
for (i = 0, len = records.length; i < len; i++) {
rec = records[i];
id = rec.id;
if (assigned.indexOf(id) == -1 && selections.containsKey(id)) {
selections.add(rec);
}
}
},
getPendingSelections : function (asRange) {
var index = 1;
var ranges = [];
var currentRange = 0;
var tmpArray = [];
for (var i in this.pendingSelections) {
tmpArray.push(parseInt(i));
}
tmpArray.sort(function (o1, o2) {
if (o1 > o2) {
return 1;
} else if (o1 < o2) {
return -1;
} else {
return 0;
}
});
if (!asRange) {
return tmpArray;
}
var max_i = tmpArray.length;
if (max_i === 0) {
return [];
}
ranges[currentRange] = [ tmpArray[0], tmpArray[0] ];
for (var i = 0, max_i = max_i - 1; i < max_i; i++) {
if (tmpArray[i + 1] - tmpArray[i] == 1) {
ranges[currentRange][1] = tmpArray[i + 1];
} else {
currentRange++;
ranges[currentRange] = [ tmpArray[i + 1], tmpArray[i + 1] ];
}
}
return ranges;
},
getAllSelections : function (asRange) {
var index = 1;
var ranges = [];
var currentRange = 0;
var tmpArray = [];
for (var i in this.allSelections) {
tmpArray.push(parseInt(i));
}
tmpArray.sort(function (o1, o2) {
if (o1 > o2) {
return 1;
} else if (o1 < o2) {
return -1;
} else {
return 0;
}
});
if (!asRange) {
return tmpArray;
}
var max_i = tmpArray.length;
if (max_i === 0) {
return [];
}
ranges[currentRange] = [ tmpArray[0], tmpArray[0] ];
for (var i = 0, max_i = max_i - 1; i < max_i; i++) {
if (tmpArray[i + 1] - tmpArray[i] == 1) {
ranges[currentRange][1] = tmpArray[i + 1];
} else {
currentRange++;
ranges[currentRange] = [ tmpArray[i + 1], tmpArray[i + 1] ];
}
}
return ranges;
},
/**
* Clears all selections.
*/
clearSelections : function (fast) {
if (this.locked) {
return;
}
if (fast !== true) {
var ds = this.grid.store;
var s = this.selections;
var ind = -1;
s.each(function (r) {
ind = ds.indexOfId(r.id);
if (ind != -1) {
this.deselectRow(ind + ds.bufferRange[0]);
}
}, this);
s.clear();
this.pendingSelections = {};
} else {
this.selections.clear();
this.pendingSelections = {};
}
this.allSelections = {};
this.last = false;
},
/**
* Selects a range of rows. All rows in between startRow and endRow are also
* selected.
*
* @param {Number}
* startRow The index of the first row in the range
* @param {Number}
* endRow The index of the last row in the range
* @param {Boolean}
* keepExisting (optional) True to retain existing selections
*/
selectRange : function (startRow, endRow, keepExisting) {
if (this.locked) {
return;
}
if (!keepExisting) {
this.clearSelections();
}
if (startRow <= endRow) {
for (var i = startRow; i <= endRow; i++) {
this.selectRow(i, true);
}
} else {
for (var i = startRow; i >= endRow; i--) {
this.selectRow(i, true);
}
}
}
});
/**
* Ext.ux.grid.livegrid.Store Copyright (c) 2007-2008, http://www.siteartwork.de
*
* Ext.ux.grid.livegrid.Store is licensed under the terms of the GNU Open Source
* GPL 3.0 license.
*
* Commercial use is prohibited. Visit <http://www.siteartwork.de/livegrid> if
* you need to obtain a commercial license.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/gpl.html>.
*
*/
Ext.namespace('Ext.ux.grid.livegrid');
/**
* @class Ext.ux.grid.livegrid.Store
* @extends Ext.data.Store
*
* The BufferedGridSore is a special implementation of a Ext.data.Store. It is
* used for loading chunks of data from the underlying data repository as
* requested by the Ext.ux.BufferedGridView. It's size is limited to the config
* parameter bufferSize and is thereby guaranteed to never hold more than this
* amount of records in the store.
*
* Requesting selection ranges: ---------------------------- This store
* implementation has 2 Http-proxies: A data proxy for requesting data from the
* server for displaying and another proxy to request pending selections:
* Pending selections are represented by row indexes which have been selected
* but which records have not yet been available in the store. The
* loadSelections method will initiate a request to the data repository (same
* url as specified in the url config parameter for the store) to fetch the
* pending selections. The additional parameter send to the server is the
* "ranges" parameter, which will hold a json encoded string representing ranges
* of row indexes to load from the data repository. As an example, pending
* selections with the indexes 1,2,3,4,5,9,10,11,16 would have to be translated
* to [1,5],[9,11],[16]. Please note, that by indexes we do not understand
* (primary) keys of the data, but indexes as represented by the view. To get
* the ranges of pending selections, you can use the getPendingSelections method
* of the BufferedRowSelectionModel, which should be used as the default
* selection model of the grid.
*
* Version-property: ----------------- This implementation does also introduce a
* new member called "version". The version property will help you in
* determining if any pending selections indexes are still valid or may have
* changed. This is needed to reduce the danger of data inconsitence when you
* are requesting data from the server: As an example, a range of indexes must
* be read from the server but may have been become invalid when the row
* represented by the index is no longer available in teh underlying data store,
* caused by a delete or insert operation. Thus, you have to take care of the
* version property by yourself (server side) and change this value whenever a
* row was deleted or inserted. You can specify the path to the version property
* in the BufferedJsonReader, which should be used as the default reader for
* this store. If the store recognizes a version change, it will fire the
* versionchange event. It is up to the user to remove all selections which are
* pending, or use them anyway.
*
* Inserting data: --------------- Another thing to notice is the way a user
* inserts records into the data store. A user should always provide a sortInfo
* for the grid, so the findInsertIndex method can return a value that comes
* close to the value as it would have been computed by the underlying store's
* sort algorithm. Whenever a record should be added to the store, the insert
* index should be calculated and the used as the parameter for the insert
* method. The findInsertIndex method will return a value that equals to
* Number.MIN_VALUE or Number.MAX_VALUE if the added record would not change the
* current state of the store. If that happens, this data is not available in
* the store, and may be requested later on when a new request for new data is
* made.
*
* Sorting: -------- remoteSort will always be set to true, no matter what value
* the user provides using the config object.
*
* @constructor Creates a new Store.
* @param {Object}
* config A config object containing the objects needed for the Store
* to access data, and read the data into Records.
*
* @author Thorsten Suckow-Homberg <ts@siteartwork.de>
*/
Ext.ux.grid.livegrid.Store = function (config) {
config = config || {};
// remoteSort will always be set to true.
config.remoteSort = true;
// we will intercept the autoLoad property and set it to false so we do not
// load any contents of the store before the View has not fully initialized
// itself. if autoLoad was set to true, the Ext.ux.grid.livegrid.GridPanel
// will take care of loading the store once it has been rendered
this._autoLoad = config.autoLoad ? true : false;
config.autoLoad = false;
this.addEvents(
/**
* @event bulkremove Fires when a bulk remove operation was finished.
* @param {Ext.ux.BufferedGridStore}
* this
* @param {Array}
* An array with the records that have been removed. The values
* for each array index are record - the record that was removed
* index - the index of the removed record in the store
*/
'bulkremove',
/**
* @event versionchange Fires when the version property has changed.
* @param {Ext.ux.BufferedGridStore}
* this
* @param {String}
* oldValue
* @param {String}
* newValue
*/
'versionchange',
/**
* @event beforeselectionsload Fires before the store sends a request for
* ranges of records to the server.
* @param {Ext.ux.BufferedGridStore}
* this
* @param {Array}
* ranges
*/
'beforeselectionsload',
/**
* @event selectionsload Fires when selections have been loaded.
* @param {Ext.ux.BufferedGridStore}
* this
* @param {Array}
* records An array containing the loaded records from the
* server.
* @param {Array}
* ranges An array containing the ranges of indexes this records
* may represent.
*/
'selectionsload');
Ext.ux.grid.livegrid.Store.superclass.constructor.call(this, config);
this.totalLength = 0;
/**
* The array represents the range of rows available in the buffer absolute
* to the indexes of the data model. Initialized with [-1, -1] which tells
* that no records are currrently buffered
*
* @param {Array}
*/
this.bufferRange = [ -1, -1 ];
this.on('clear', function () {
this.bufferRange = [ -1, -1 ];
}, this);
if (this.url && !this.selectionsProxy) {
this.selectionsProxy = new Ext.data.HttpProxy({
url : this.url
});
}
};
Ext.extend(Ext.ux.grid.livegrid.Store, Ext.data.Store, {
/**
* The version of the data in the store. This value is represented by the
* versionProperty-property of the BufferedJsonReader.
*
* @property
*/
version : null,
/**
* Inserts a record at the position as specified in index. If the index
* equals to Number.MIN_VALUE or Number.MAX_VALUE, the record will not be
* added to the store, but still fire the add-event to indicate that the set
* of data in the underlying store has been changed. If the index equals to
* 0 and the length of data in the store equals to bufferSize, the add-event
* will be triggered with Number.MIN_VALUE to indicate that a record has
* been prepended. If the index equals to bufferSize, the method will assume
* that the record has been appended and trigger the add event with index
* set to Number.MAX_VALUE.
*
* Note: ----- The index parameter is not a view index, but a value in the
* range of [0, this.bufferSize].
*
* You are strongly advised to not use this method directly. Instead, call
* findInsertIndex wirst and use the return-value as the first parameter for
* for this method.
*/
insert : function (index, records) {
// hooray for haskell!
records = [].concat(records);
index = index >= this.bufferSize ? Number.MAX_VALUE : index;
if (index == Number.MIN_VALUE || index == Number.MAX_VALUE) {
var l = records.length;
if (index == Number.MIN_VALUE) {
this.bufferRange[0] += l;
this.bufferRange[1] += l;
}
this.totalLength += l;
this.fireEvent("add", this, records, index);
return;
}
var split = false;
var insertRecords = records;
if (records.length + index >= this.bufferSize) {
split = true;
insertRecords = records.splice(0, this.bufferSize - index);
}
this.totalLength += insertRecords.length;
// if the store was loaded without data and the bufferRange
// has to be filled first
if (this.bufferRange[0] <= -1) {
this.bufferRange[0] = 0;
}
if (this.bufferRange[1] < (this.bufferSize - 1)) {
this.bufferRange[1] = Math.min(this.bufferRange[1] + insertRecords.length, this.bufferSize - 1);
}
for (var i = 0, len = insertRecords.length; i < len; i++) {
this.data.insert(index, insertRecords[i]);
insertRecords[i].join(this);
}
while (this.getCount() > this.bufferSize) {
this.data.remove(this.data.last());
}
this.fireEvent("add", this, insertRecords, index);
if (split === true) {
this.fireEvent("add", this, records, Number.MAX_VALUE);
}
},
/**
* Remove a Record from the Store and fires the remove event.
*
* This implementation will check for the appearance of the record id in the
* store. The record to be removed does not neccesarily be bound to the
* instance of this store. If the record is not within the store, the method
* will try to guess it's index by calling findInsertIndex.
*
* Please note that this method assumes that the records that's about to be
* removed from the store does belong to the data within the store or the
* underlying data store, thus the remove event will always be fired. This
* may lead to inconsitency if you have to stores up at once. Let A be the
* store that reads from the data repository C, and B the other store that
* only represents a subset of data of the data repository C. If you now
* remove a record X from A, which has not been in the store, but is assumed
* to be available in the data repository, and would like to sync the
* available data of B, then you have to check first if X may have apperead
* in the subset of data C represented by B before calling remove from the B
* store (because the remove operation will always trigger the "remove"
* event, no matter what). (Common use case: you have selected a range of
* records which are then stored in the row selection model. User scrolls
* through the data and the store's buffer gets refreshed with new data for
* displaying. Now you want to remove all records which are within the
* rowselection model, but not anymore within the store.) One possible
* workaround is to only remove the record X from B if, and only if the
* return value of a call to [object instance of store B].data.indexOf(X)
* does not return a value less than 0. Though not removing the record from
* B may not update the view of an attached BufferedGridView immediately.
*
* @param {Ext.data.Record}
* record
* @param {Boolean}
* suspendEvent true to suspend the "remove"-event
*
* @return Number the index of the record removed.
*/
remove : function (record, suspendEvent) {
// check wether the record.id can be found in this store
var index = this._getIndex(record);
if (index < 0) {
this.totalLength -= 1;
if (this.pruneModifiedRecords) {
this.modified.remove(record);
}
// adjust the buffer range if a record was removed
// in the range that is actually behind the bufferRange
this.bufferRange[0] = Math.max(-1, this.bufferRange[0] - 1);
this.bufferRange[1] = Math.max(-1, this.bufferRange[1] - 1);
if (suspendEvent !== true) {
this.fireEvent("remove", this, record, index);
}
return index;
}
this.bufferRange[1] = Math.max(-1, this.bufferRange[1] - 1);
this.data.removeAt(index);
if (this.pruneModifiedRecords) {
this.modified.remove(record);
}
this.totalLength -= 1;
if (suspendEvent !== true) {
this.fireEvent("remove", this, record, index);
}
return index;
},
_getIndex : function (record) {
var index = this.indexOfId(record.id);
if (index < 0) {
index = this.findInsertIndex(record);
}
return index;
},
/**
* Removes a larger amount of records from the store and fires the
* "bulkremove" event. This helps listeners to determine whether the remove
* operation of multiple records is still pending.
*
* @param {Array}
* records
*/
bulkRemove : function (records) {
var rec = null;
var recs = [];
var ind = 0;
var len = records.length;
var orgIndexes = [];
for (var i = 0; i < len; i++) {
rec = records[i];
orgIndexes[rec.id] = this._getIndex(rec);
}
for (var i = 0; i < len; i++) {
rec = records[i];
this.remove(rec, true);
recs.push([ rec, orgIndexes[rec.id] ]);
}
this.fireEvent("bulkremove", this, recs);
},
/**
* Remove all Records from the Store and fires the clear event. The method
* assumes that there will be no data available anymore in the underlying
* data store.
*/
removeAll : function () {
this.totalLength = 0;
this.bufferRange = [ -1, -1 ];
this.data.clear();
if (this.pruneModifiedRecords) {
this.modified = [];
}
this.fireEvent("clear", this);
},
/**
* Requests a range of data from the underlying data store. Similiar to the
* start and limit parameter usually send to the server, the method needs an
* array of ranges of indexes. Example: To load all records at the positions
* 1,2,3,4,9,12,13,14, the supplied parameter should equal to
* [[1,4],[9],[12,14]]. The request will only be done if the
* beforeselectionsloaded events return value does not equal to false.
*/
loadRanges : function (ranges) {
var max_i = ranges.length;
if (max_i > 0 && !this.selectionsProxy.activeRequest[Ext.data.Api.actions.read] && this.fireEvent("beforeselectionsload", this, ranges) !== false) {
var lParams = this.lastOptions.params;
var params = {};
params.ranges = Ext.encode(ranges);
if (lParams) {
if (lParams.sort) {
params.sort = lParams.sort;
}
if (lParams.dir) {
params.dir = lParams.dir;
}
}
var options = {};
for (var i in this.lastOptions) {
options.i = this.lastOptions.i;
}
options.ranges = params.ranges;
this.selectionsProxy.doRequest(Ext.data.Api.actions.read, null, options, this.reader,
this.selectionsLoaded, this, options);
}
},
/**
* Alias for loadRanges.
*/
loadSelections : function (ranges) {
if (ranges.length === 0) {
return;
}
this.loadRanges(ranges);
},
/**
* Called as a callback by the proxy which loads pending selections. Will
* fire the selectionsload event with the loaded records if, and only if the
* return value of the checkVersionChange event does not equal to false.
*/
selectionsLoaded : function (o, options, success) {
if (this.checkVersionChange(o, options, success) !== false) {
var r = o.records;
for (var i = 0, len = r.length; i < len; i++) {
r[i].join(this);
}
this.fireEvent("selectionsload", this, o.records, Ext.decode(options.ranges));
} else {
this.fireEvent("selectionsload", this, [], Ext.decode(options.ranges));
}
},
/**
* Checks if the version supplied in <tt>o</tt> differs from the version
* property of the current instance of this object and fires the
* versionchange event if it does.
*/
// private
checkVersionChange : function (o, options, success) {
if (o && success !== false) {
if (o.version !== undefined) {
var old = this.version;
this.version = o.version;
if (this.version !== old) {
return this.fireEvent('versionchange', this, old, this.version);
}
}
}
},
/**
* The sort procedure tries to respect the current data in the buffer. If
* the found index would not be within the bufferRange, Number.MIN_VALUE is
* returned to indicate that the record would be sorted below the first
* record in the buffer range, while Number.MAX_VALUE would indicate that
* the record would be added after the last record in the buffer range.
*
* The method is not guaranteed to return the relative index of the record
* in the data model as returned by the underlying domain model.
*/
findInsertIndex : function (record) {
this.remoteSort = false;
var index = Ext.ux.grid.livegrid.Store.superclass.findInsertIndex.call(this, record);
this.remoteSort = true;
// special case... index is 0 and we are at the very first record
// buffered
if (this.bufferRange[0] <= 0 && index === 0) {
return index;
} else if (this.bufferRange[0] > 0 && index === 0) {
return Number.MIN_VALUE;
} else if (index >= this.bufferSize) {
return Number.MAX_VALUE;
}
return index;
},
/**
* Removed snapshot check
*/
// private
sortData : function (f, direction) {
direction = direction || 'ASC';
var st = this.fields.get(f).sortType;
var fn = function (r1, r2) {
var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
};
this.data.sort(direction, fn);
},
/**
* @cfg {Number} bufferSize The number of records that will at least always
* be available in the store for rendering. This value will be send to
* the server as the <tt>limit</tt> parameter and should not change
* during the lifetime of a grid component. Note: In a paging grid,
* this number would indicate the page size. The value should be set
* high enough to make a userfirendly scrolling possible and should be
* greater than the sum of {nearLimit} and {visibleRows}. Usually, a
* value in between 150 and 200 is good enough. A lesser value will
* more often make the store re-request new data, while a larger number
* will make loading times higher.
*/
// private
onMetaChange : function (meta, rtype, o) {
this.version = null;
Ext.ux.grid.livegrid.Store.superclass.onMetaChange.call(this, meta, rtype, o);
},
/**
* Will fire the versionchange event if the version of incoming data has
* changed.
*/
// private
loadRecords : function (o, options, success) {
this.checkVersionChange(o, options, success);
// we have to stay in sync with rows that may have been skipped while
// the request was loading.
// if the response didn't make it through, set buffer range to -1,-1
if (!o) {
this.bufferRange = [ -1, -1 ];
} else {
this.bufferRange = [ options.params.start,
Math.max(0, Math.min((options.params.start + options.params.limit) - 1, o.totalRecords - 1)) ];
}
if (options.suspendLoadEvent === true) {
this.suspendEvents();
}
Ext.ux.grid.livegrid.Store.superclass.loadRecords.call(this, o, options, success);
if (options.suspendLoadEvent === true) {
this.resumeEvents();
}
},
/**
* Get the Record at the specified index. The function will take the
* bufferRange into account and translate the passed argument to the index
* of the record in the current buffer.
*
* @param {Number}
* index The index of the Record to find.
* @return {Ext.data.Record} The Record at the passed index. Returns
* undefined if not found.
*/
getAt : function (index) {
// anything buffered yet?
if (this.bufferRange[0] == -1) {
return undefined;
}
var modelIndex = index - this.bufferRange[0];
return this.data.itemAt(modelIndex);
},
// --------------------------------------EMPTY-----------------------------------
// no interface concept, so simply overwrite and leave them empty as for now
clearFilter : function () {
},
isFiltered : function () {
},
collect : function () {
},
createFilterFn : function () {
},
sum : function () {
},
filter : function () {
},
filterBy : function () {
},
query : function () {
},
queryBy : function () {
},
find : function () {
},
findBy : function () {
}
});
/**
* Ext.ux.grid.livegrid.Toolbar Copyright (c) 2007-2008,
* http://www.siteartwork.de
*
* Ext.ux.grid.livegrid.Toolbar is licensed under the terms of the GNU Open
* Source GPL 3.0 license.
*
* Commercial use is prohibited. Visit <http://www.siteartwork.de/livegrid> if
* you need to obtain a commercial license.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/gpl.html>.
*
*/
Ext.namespace('Ext.ux.grid.livegrid');
/**
* toolbar that is bound to a {@link Ext.ux.grid.livegrid.GridView} and provides
* information about the indexes of the requested data and the buffer state.
*
* @class Ext.ux.grid.livegrid.Toolbar
* @extends Ext.Toolbar
* @constructor
* @param {Object}
* config
*
* @author Thorsten Suckow-Homberg <ts@siteartwork.de>
*/
Ext.ux.grid.livegrid.Toolbar = Ext.extend(Ext.Toolbar, {
/**
* @cfg {Ext.grid.GridPanel} grid The grid the toolbar is bound to. If
* ommited, use the cfg property "view"
*/
/**
* @cfg {Ext.grid.GridView} view The view the toolbar is bound to The grid
* the toolbar is bound to. If ommited, use the cfg property "grid"
*/
/**
* @cfg {Boolean} displayInfo True to display the displayMsg (defaults to
* false)
*/
/**
* @cfg {String} displayMsg The paging status message to display (defaults
* to "Displaying {start} - {end} of {total}")
*/
displayMsg : "",
/**
* @cfg {String} emptyMsg The message to display when no records are found
* (defaults to "No data to display")
*/
emptyMsg : 'No data to display',
/**
* Value to display as the tooltip text for the refresh button. Defaults to
* "Refresh"
*
* @param {String}
*/
refreshText : "Refresh",
initComponent : function () {
this.displayMsg = i18n.get('paging.display');
Ext.ux.grid.livegrid.Toolbar.superclass.initComponent.call(this);
if (this.grid) {
this.view = this.grid.getView();
}
var me = this;
this.view.init = this.view.init.createSequence(function () {
me.bind(this);
}, this.view);
},
// private
updateInfo : function (rowIndex, visibleRows, totalCount) {
if (this.displayEl) {
var msg = totalCount === 0 ? this.emptyMsg : String.format(this.displayMsg, rowIndex + 1, Math.min(rowIndex + 1 + visibleRows, totalCount), totalCount);
this.displayEl.update(msg);
}
},
/**
* Unbinds the toolbar.
*
* @param {Ext.grid.GridView|Ext.gid.GridPanel}
* view Either The view to unbind or the grid
*/
unbind : function (view) {
var st;
var vw;
if (view instanceof Ext.grid.GridView) {
vw = view;
} else {
// assuming parameter is of type Ext.grid.GridPanel
vw = view.getView();
}
st = view.ds;
st.un('loadexception', this.enableLoading, this);
st.un('beforeload', this.disableLoading, this);
st.un('load', this.enableLoading, this);
vw.un('rowremoved', this.onRowRemoved, this);
vw.un('rowsinserted', this.onRowsInserted, this);
vw.un('beforebuffer', this.beforeBuffer, this);
vw.un('cursormove', this.onCursorMove, this);
vw.un('buffer', this.onBuffer, this);
vw.un('bufferfailure', this.enableLoading, this);
this.view = undefined;
},
/**
* Binds the toolbar to the specified {@link Ext.ux.grid.Livegrid}
*
* @param {Ext.grird.GridView}
* view The view to bind
*/
bind : function (view) {
this.view = view;
var st = view.ds;
st.on('loadexception', this.enableLoading, this);
st.on('beforeload', this.disableLoading, this);
st.on('load', this.enableLoading, this);
view.on('rowremoved', this.onRowRemoved, this);
view.on('rowsinserted', this.onRowsInserted, this);
view.on('beforebuffer', this.beforeBuffer, this);
view.on('cursormove', this.onCursorMove, this);
view.on('buffer', this.onBuffer, this);
view.on('bufferfailure', this.enableLoading, this);
},
// ----------------------------------- Listeners
// -------------------------------
enableLoading : function () {
this.loading.setDisabled(false);
},
disableLoading : function () {
this.loading.setDisabled(true);
},
onCursorMove : function (view, rowIndex, visibleRows, totalCount) {
this.updateInfo(rowIndex, visibleRows, totalCount);
},
// private
onRowsInserted : function (view, start, end) {
this.updateInfo(view.rowIndex, Math.min(view.ds.totalLength, view.visibleRows - view.rowClipped),
view.ds.totalLength);
},
// private
onRowRemoved : function (view, index, record) {
this.updateInfo(view.rowIndex, Math.min(view.ds.totalLength, view.visibleRows - view.rowClipped),
view.ds.totalLength);
},
// private
beforeBuffer : function (view, store, rowIndex, visibleRows, totalCount, options) {
this.loading.disable();
this.updateInfo(rowIndex, visibleRows, totalCount);
},
// private
onBuffer : function (view, store, rowIndex, visibleRows, totalCount) {
this.loading.enable();
this.updateInfo(rowIndex, visibleRows, totalCount);
//plot refresh when data is buffered
var plotComp = Ext.getCmp("plot" + this.ownerCt.datasetId);
if (plotComp) {
var rightPanel = plotComp.findById('plot-right-panel');
var success = rightPanel.fireEvent('buffer', store, rowIndex, visibleRows, totalCount);
}
},
// private
onClick : function (type) {
switch (type) {
case 'refresh':
if (this.view.reset(true)) {
this.loading.disable();
} else {
this.loading.enable();
}
break;
}
},
// private
onRender : function (ct, position) {
Ext.PagingToolbar.superclass.onRender.call(this, ct, position);
this.loading = new Ext.Toolbar.Button({
tooltip : this.refreshText,
iconCls : "x-tbar-loading",
handler : this.onClick.createDelegate(this, [ "refresh" ])
});
this.addButton(this.loading);
this.addSeparator();
if (this.displayInfo) {
this.displayEl = Ext.fly(this.el.dom).createChild({
cls : 'x-paging-info'
});
}
}
});
/**
* Ext.ux.grid.livegrid.DragZone Copyright (c) 2007-2008,
* http://www.siteartwork.de
*
* Ext.ux.grid.livegrid.DragZone is licensed under the terms of the GNU Open
* Source GPL 3.0 license.
*
* Commercial use is prohibited. Visit <http://www.siteartwork.de/livegrid> if
* you need to obtain a commercial license.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/gpl.html>.
*
*/
Ext.namespace('Ext.ux.grid.livegrid');
/**
* @class Ext.ux.grid.livegrid.DragZone
* @extends Ext.dd.DragZone
* @author Thorsten Suckow-Homberg <ts@siteartwork.de>
*/
Ext.ux.grid.livegrid.DragZone = function (grid, config) {
Ext.ux.grid.livegrid.DragZone.superclass.constructor.call(this, grid, config);
this.view.ds.on('beforeselectionsload', this._onBeforeSelectionsLoad, this);
this.view.ds.on('selectionsload', this._onSelectionsLoad, this);
};
Ext.extend(Ext.ux.grid.livegrid.DragZone, Ext.grid.GridDragZone, {
/**
* Tells whether a drop is valid. Used inetrnally to determine if pending
* selections need to be loaded/ have been loaded.
*
* @type {Boolean}
*/
isDropValid : true,
/**
* Overriden for loading pending selections if needed.
*/
onInitDrag : function (e) {
this.view.ds.loadSelections(this.grid.selModel.getPendingSelections(true));
Ext.ux.grid.livegrid.DragZone.superclass.onInitDrag.call(this, e);
},
/**
* Gets called before pending selections are loaded. Any drop operations are
* invalid/get paused if the component needs to wait for selections to load
* from the server.
*
*/
_onBeforeSelectionsLoad : function () {
this.isDropValid = false;
Ext.fly(this.proxy.el.dom.firstChild).addClass('ext-ux-livegrid-drop-waiting');
},
/**
* Gets called after pending selections have been loaded. Any paused drop
* operation will be resumed.
*
*/
_onSelectionsLoad : function () {
this.isDropValid = true;
this.ddel.innerHTML = this.grid.getDragDropText();
Ext.fly(this.proxy.el.dom.firstChild).removeClass('ext-ux-livegrid-drop-waiting');
}
});
/**
* Ext.ux.grid.livegrid.EditorGridPanel Copyright (c) 2007-2008,
* http://www.siteartwork.de
*
* Ext.ux.grid.livegrid.EditorGridPanel is licensed under the terms of the GNU
* Open Source GPL 3.0 license.
*
* Commercial use is prohibited. Visit <http://www.siteartwork.de/livegrid> if
* you need to obtain a commercial license.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/gpl.html>.
*
*/
Ext.namespace('Ext.ux.grid.livegrid');
/**
* @class Ext.ux.grid.livegrid.EditorGridPanel
* @extends Ext.grid.EditorGridPanel
* @constructor
* @param {Object}
* config
*
* @author Thorsten Suckow-Homberg <ts@siteartwork.de>
*/
Ext.ux.grid.livegrid.EditorGridPanel = Ext.extend(Ext.grid.EditorGridPanel, {
/**
* Overriden so the panel listens to the "cursormove" event for cancelling
* any edit that is in progress.
*
* @private
*/
initEvents : function () {
Ext.ux.grid.livegrid.EditorGridPanel.superclass.initEvents.call(this);
this.view.on("cursormove", this.stopEditing, this, [ true ]);
},
/**
* Starts editing the specified for the specified row/column Will be
* cancelled if the requested row index to edit is not represented by data
* due to out of range regarding the view's store buffer.
*
* @param {Number}
* rowIndex
* @param {Number}
* colIndex
*/
startEditing : function (row, col) {
this.stopEditing();
if (this.colModel.isCellEditable(col, row)) {
this.view.ensureVisible(row, col, true);
if (!this.store.getAt(row)) {
return;
}
}
return Ext.ux.grid.livegrid.EditorGridPanel.superclass.startEditing.call(this, row, col);
},
// Since we do not have multiple inheritance, we need to override the
// same methods in this class we have overriden for
// Ext.ux.grid.livegrid.GridPanel
walkCells : function (row, col, step, fn, scope) {
return Ext.ux.grid.livegrid.GridPanel.prototype.walkCells.call(this, row, col, step, fn, scope);
},
onRender : function (ct, position) {
return Ext.ux.grid.livegrid.GridPanel.prototype.onRender.call(this, ct, position);
},
initComponent : function () {
if (this.cls) {
this.cls += ' ext-ux-livegrid';
} else {
this.cls = 'ext-ux-livegrid';
}
return Ext.ux.grid.livegrid.EditorGridPanel.superclass.initComponent.call(this);
}
});
/*******************************************************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* SITools2 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* SITools2. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/*global Ext, sitools, i18n, sql2ext, extColModelToSrv, window,
extColModelToJsonColModel, DEFAULT_NEAR_LIMIT_SIZE,
DEFAULT_LIVEGRID_BUFFER_SIZE, SITOOLS_DEFAULT_IHM_DATE_FORMAT,
DEFAULT_PREFERENCES_FOLDER, SitoolsDesk, getDesktop, userLogin, projectGlobal, ColumnRendererEnum, SITOOLS_DATE_FORMAT
*/
Ext.namespace('sitools.user.component.dataviews');
/**
* A Simple Object to publish common methods to use dataviews in Sitools2.
* @type
*/
sitools.user.component.dataviews.dataviewUtils = {
//sitools.user.component.liveGrid.dataviewUtils = {
/**
* build the param that will represent the active selection.
* @param [Ext.data.Record] recSelected the selected records
* @returns {} this object contains the param that will use FORM API
*/
getFormParamsFromRecsSelected : function (recSelected) {
var rec = recSelected[0], result = {};
var primaryKeyName = "";
Ext.each(rec.fields.items, function (field) {
if (field.primaryKey) {
primaryKeyName = field.name;
}
});
if (Ext.isEmpty(primaryKeyName)) {
Ext.Msg.alert(i18n.get('label.error'), i18n.get('label.noPrimaryKey'));
return;
}
// build the primaryKey Value
var primaryKeyValues = [];
Ext.each(recSelected, function (record) {
primaryKeyValues.push(encodeURIComponent(record.get(primaryKeyName)));
});
// use the form API to request the selected records
result["p[0]"] = "LISTBOXMULTIPLE|" + primaryKeyName + "|" + primaryKeyValues.join("|");
return result;
},
/**
* Get the renderer for a column from its featureType for the DataView
* @param {Object} item col the Column definition
* @param {Object} dataviewConfig the specific dataview Configuration.
* @return {function} the renderer for a column
*/
getRendererLiveGrid : function (item, dataviewConfig) {
var renderer;
if (!Ext.isEmpty(item.columnRenderer)) {
renderer = function (value, metadata, record, rowIndex, colIndex,
store) {
if (!Ext.isEmpty(value)) {
if (!Ext.isEmpty(item.columnRenderer.toolTip)){
metadata.attr = 'ext:qtip="' + item.columnRenderer.toolTip + '"';
}
var imageStyle = "max-width:" + (item.width - 10) + "px;";
if (!Ext.isEmpty(dataviewConfig) && !Ext.isEmpty(dataviewConfig.lineHeight)) {
imageStyle += "max-height: " + (dataviewConfig.lineHeight - 10) + "px;";
}
var html = sitools.user.component.dataviews.dataviewUtils.getRendererHTML(item, imageStyle);
var str;
if (!Ext.isEmpty(html)) {
if (item.columnRenderer.behavior == ColumnRendererEnum.IMAGE_FROM_SQL) {
var imageUrl = record.get(item.columnRenderer.columnAlias);
str = String.format(html, value, imageUrl);
} else {
str = String.format(html, value);
}
}
return str;
} else {
return value;
}
};
} else {
renderer = function (value) {
var valueFormat = value;
if (sql2ext.get(item.sqlColumnType) == 'dateAsString') {
valueFormat = sitools.user.component.dataviews.dataviewUtils.formatDate(
value, item);
}
if (sql2ext.get(item.sqlColumnType) == 'boolean') {
valueFormat = value ? i18n.get('label.true') : i18n
.get('label.false');
}
return valueFormat;
};
}
return renderer;
},
/**
* Get the template to render a column from its featureType for the DataView
* @param {Object} col the Column definition
* @param {String} style the style to add to the label part
* @param {Object} dataviewConfig the specific dataview Configuration.
* @return {String} a template to render a column from its featureType for the DataView
*/
getRendererDataView : function (col, style, dataviewConfig) {
var tplString = "", value, behavior, label, valueDisplayed;
var columnRenderer = col.columnRenderer;
if (!Ext.isEmpty(columnRenderer)) {
behavior = columnRenderer.behavior;
var html = sitools.user.component.dataviews.dataviewUtils.getRendererHTML(col, dataviewConfig);
switch (behavior) {
case ColumnRendererEnum.URL_LOCAL :
case ColumnRendererEnum.URL_EXT_NEW_TAB :
case ColumnRendererEnum.URL_EXT_DESKTOP :
case ColumnRendererEnum.DATASET_ICON_LINK :
if (!Ext.isEmpty(columnRenderer.linkText)) {
tplString += String.format("<tpl if=\"this.isNotEmpty({0})\">", col.columnAlias);
value = String.format(html, "{" + col.columnAlias + "}");
tplString += String.format('<span class="dataview_columnValue"><div class=x-view-entete style="{2}">{0} </div> {1}</span>', col.header, value, style);
tplString += "</tpl>";
tplString += String.format("<tpl if=\"this.isEmpty({0})\">", col.columnAlias);
value = "";
tplString += String.format('<span class="dataview_columnValue"><div class=x-view-entete style="{2}">{0} </div> {1}</span>', col.header, value, style);
tplString += "</tpl>";
} else if (!Ext.isEmpty(columnRenderer.image)) {
tplString += String.format("<tpl if=\"this.isNotEmpty({0})\">", col.columnAlias);
tplString += String.format('<li class="img-link" ext:qtip="{0}">', col.header);
tplString += String.format(html, "{" + col.columnAlias + "}");
tplString += '</li></tpl>';
}
break;
case ColumnRendererEnum.IMAGE_THUMB_FROM_IMAGE :
tplString += String.format("<tpl if=\"this.isNotEmpty({0})\">", col.columnAlias);
tplString += String.format('<li class="img-link" ext:qtip="{0}">', col.header);
tplString += String.format(html, "{" + col.columnAlias + "}");
tplString += '</li></tpl>';
break;
case ColumnRendererEnum.IMAGE_FROM_SQL :
var imageUrl = "";
if (!Ext.isEmpty(columnRenderer.url)) {
imageUrl = columnRenderer.url;
} else if (!Ext.isEmpty(columnRenderer.columnAlias)) {
imageUrl = "{" + columnRenderer.columnAlias + "}";
}
tplString += String.format("<tpl if=\"this.isNotEmpty({0})\">", col.columnAlias);
tplString += String.format('<li class="img-link" ext:qtip="{0}">', col.header, imageUrl);
tplString += String.format(html, "{" + col.columnAlias + "}", imageUrl);
tplString += '</li></tpl>';
break;
default :
tplString += String.format("<tpl if=\"this.isNotEmpty({0})\">", col.columnAlias);
value = String.format(html, "{" + col.columnAlias + "}");
tplString += String.format('<span class="dataview_columnValue"><div class=x-view-entete style="{2}">{0} </div> {1}</span>', col.header, value, style);
tplString += "</tpl>";
tplString += String.format("<tpl if=\"this.isEmpty({0})\">", col.columnAlias);
value = "";
tplString += String.format('<span class="dataview_columnValue"><div class=x-view-entete style="{2}">{0} </div> {1}</span>', col.header, value, style);
tplString += "</tpl>";
break;
}
} else {
if (sql2ext.get(col.sqlColumnType) == 'dateAsString') {
tplString += String.format('<span class="dataview_columnValue"><div class=x-view-entete style="{2}">{0} </div> <tpl if=\"this.isValidDate({1})\">{[Date.parseDate(values.{1}, SITOOLS_DATE_FORMAT).format("{3}")]}</tpl></span>',
col.header,
col.columnAlias,
style,
Ext.isEmpty(col.format) ? SITOOLS_DEFAULT_IHM_DATE_FORMAT : col.format);
}
else {
tplString += String.format('<span class="dataview_columnValue"><div class=x-view-entete style="{2}">{0} </div> {{1}}</span>', col.header, col.columnAlias, style);
}
}
return tplString;
},
/**
* Get the HTML specific part to render a column corresponding to its featureType (columnRenderer)
* It is a formated date where {0} must be replaced by the column value and {1} by the imageUrl to display in big only for ColumnRendererEnum.IMAGE_FROM_SQL
* @param {Object} item the column definition
* @param {Object} dataviewConfig the specific dataview Configuration.
* @return {String} a formated HTML String
*/
getRendererHTML : function (item, imageStyle) {
var renderer, valueDisplayed, imageUrl;
var html;
if (!Ext.isEmpty(item.columnRenderer) && !Ext.isEmpty(item.columnRenderer.behavior)) {
var columnRenderer = item.columnRenderer;
switch (columnRenderer.behavior) {
case ColumnRendererEnum.URL_LOCAL :
valueDisplayed = "";
if (!Ext.isEmpty(columnRenderer.linkText)) {
valueDisplayed = columnRenderer.linkText;
} else if (!Ext.isEmpty(columnRenderer.image)) {
valueDisplayed = "<img src=\"" + columnRenderer.image.url + "\" class='sitools-display-image' style ='" + imageStyle + "' ></img>";
}
html = "<a href='#' onClick='sitools.user.component.dataviews.dataviewUtils.downloadData(\"{0}\");'>" + valueDisplayed + "</a>";
break;
case ColumnRendererEnum.URL_EXT_NEW_TAB :
valueDisplayed = "";
if (!Ext.isEmpty(columnRenderer.linkText)) {
valueDisplayed = columnRenderer.linkText;
} else if (!Ext.isEmpty(columnRenderer.image)) {
valueDisplayed = "<img src=\"" + columnRenderer.image.url + "\" class='sitools-display-image' style ='" + imageStyle + "' ></img>";
}
html = "<a href='#' onClick='window.open(\"{0}\");'>" + valueDisplayed + "</a>";
break;
case ColumnRendererEnum.URL_EXT_DESKTOP :
valueDisplayed = "";
if (!Ext.isEmpty(columnRenderer.linkText)) {
valueDisplayed = columnRenderer.linkText;
} else if (!Ext.isEmpty(columnRenderer.image)) {
valueDisplayed = "<img src=\"" + columnRenderer.image.url + "\" class='sitools-display-image' style ='" + imageStyle + "' ></img>";
}
html = "<a href='#' onClick='sitools.user.component.dataviews.dataviewUtils.showDisplayableUrl(\"{0}\", " + columnRenderer.displayable + ");'>" + valueDisplayed + "</a>";
break;
case ColumnRendererEnum.IMAGE_NO_THUMB :
html = "<a href='#' onClick='sitools.user.component.dataviews.dataviewUtils.showPreview(\"{0}\",\"" + columnRenderer.linkText + "\");'>" + columnRenderer.linkText + "</a>";
break;
case ColumnRendererEnum.IMAGE_THUMB_FROM_IMAGE :
html = "<a href='#' onClick='sitools.user.component.dataviews.dataviewUtils.showPreview(\"{0}\",\"" + item.header + "\");'><img class='sitools-display-image' src='{0}' style ='" + imageStyle + "'></img></a>";
break;
case ColumnRendererEnum.IMAGE_FROM_SQL :
html = "<div style='text-align:center;'><a href='#' onClick='sitools.user.component.dataviews.dataviewUtils.showPreview(\"{0}\",\"" + item.header + "\");'><img class='sitools-display-image' src='{1}' style ='" + imageStyle + "'></a></div>";
break;
case ColumnRendererEnum.DATASET_LINK :
html = "<a href='#' onClick='sitools.user.component.dataviews.dataviewUtils.showDetailsData(\"{0}\"," +
"\"" + columnRenderer.columnAlias + "\", \""
+ columnRenderer.datasetLinkUrl + "\");'>{0}</a>";
break;
case ColumnRendererEnum.DATASET_ICON_LINK :
if (!Ext.isEmpty(columnRenderer.image)) {
imageUrl = columnRenderer.image.url;
}
html = "<a href='#' onClick='sitools.user.component.dataviews.dataviewUtils.showDetailsData(\"{0}\", \"" + columnRenderer.columnAlias + "\", \""
+ columnRenderer.datasetLinkUrl + "\");'><img style ='" + imageStyle + "' class='sitools-display-image' src='" + imageUrl + "'></a>";
break;
default :
html = "{0}";
break;
}
}
return html;
},
getRendererViewDataDetails : function (item) {
},
formatDate : function (value, item) {
var valueFormat;
var result = Date.parseDate(value, SITOOLS_DATE_FORMAT, true);
// try to build Date with "Y-m-d" format
if (Ext.isEmpty(result)) {
valueFormat = "";
}
else {
if (Ext.isEmpty(item.format)) {
valueFormat = result.format(SITOOLS_DEFAULT_IHM_DATE_FORMAT);
}
else {
try {
valueFormat = result.format(item.format);
}
catch (err) {
valueFormat = "unable to format Date";
}
}
}
return valueFormat;
},
/**
* @static
* Execute a REST OPTION request to the value url.
* Switch on Content-Type value to determine if we open a new iframe, or a window.
* @param {} value the url to request
*/
downloadData : function (value) {
// value = encodeURIComponent(value);
//build first request to get the headers
Ext.Ajax.request({
url : value,
method : 'HEAD',
scope : this,
success : function (ret) {
try {
var headerFile = ret.getResponseHeader("Content-Type")
.split(";")[0].split("/")[0];
if (headerFile == "text") {
Ext.Ajax.request({
url : value,
method : 'GET',
scope : this,
success : function (ret) {
var windowConfig = {
id : "winPreferenceDetailId",
title : value,
iconCls : "version"
};
var jsObj = Ext.Panel;
var componentCfg = {
layout : 'fit',
autoScroll : true,
html : ret.responseText
};
SitoolsDesk.addDesktopWindow(
windowConfig, componentCfg,
jsObj);
}
});
} else if (headerFile == "image") {
sitools.user.component.dataviews.dataviewUtils.showPreview(value, item.header);
} else {
sitools.user.component.dataviews.dataviewUtils.downloadFile(value);
}
} catch (err) {
Ext.Msg.alert(i18n.get('label.error'), err);
}
},
failure : function (ret) {
return null;
}
});
},
/**
* @static
* Build a MIF panel with a given url and load it into the desktop
* @param {} value the url to request
* @param {boolean} true if the url is displayable in a window, false otherwise
*/
showDisplayableUrl : function (value, isDisplayable, customConfig) {
if (isDisplayable) {
if (customConfig){
var windowConfig = customConfig;
}
else {
var windowConfig = {
title : value,
id : value,
iconCls : "version"
};
}
var jsObj = Ext.ux.ManagedIFrame.Panel;
var componentCfg = {
defaults : {
padding : 10
},
layout : 'fit',
region : 'center',
defaultSrc : value
};
SitoolsDesk.addDesktopWindow(
windowConfig, componentCfg,
jsObj);
} else {
sitools.user.component.dataviews.dataviewUtils.downloadFile(value);
}
},
/**
* Use a spcialized MIF to download datas...
* @param {String} url the url to request.
*/
downloadFile : function (url) {
if (Ext.getCmp("mifToDownload")) {
Ext.getCmp("mifToDownload").destroy();
}
var mifToDownload = new Ext.ux.ManagedIFrame.Panel({
layout : 'fit',
id : "mifToDownload",
region : 'center',
defaultSrc : url,
renderTo : Ext.getBody(),
cls : 'x-hidden'
});
},
/**
* @static
* Definition of the showDetailData method used by the columnRenderer. Calls the
* Livegrid corresponding to the dataset linked to the column. To filter the
* data : use the form API : ["RADIO|" + columnAlias + "|'" + value + "'"]
* @param {string} value
* @param {string} columnAlias
* @param {string} datasetUrl
*/
showDetailsData : function (value, columnAlias, datasetUrl) {
var desktop = getDesktop();
// récupération des données du dataset
Ext.Ajax.request({
scope : this,
method : 'GET',
url : datasetUrl,
success : function (response, opts) {
try {
var json = Ext.decode(response.responseText);
if (!json.success) {
Ext.Msg.alert(i18n.get('label.error'), json.message);
return;
}
var formParams = [ "RADIO|" + columnAlias + "|" + value ];
var dataset = json.dataset;
var jsObj = eval(dataset.datasetView.jsObject);
var componentCfg = {
dataUrl : dataset.sitoolsAttachementForUsers,
datasetId : dataset.id,
datasetCm : dataset.columnModel,
formParams : formParams,
datasetName : dataset.name,
dictionaryMappings : dataset.dictionaryMappings,
datasetViewConfig : dataset.datasetViewConfig,
preferencesPath : "/" + dataset.name,
preferencesFileName : "datasetView"
};
var windowConfig = {
id : "wind" + dataset.id + columnAlias + value,
title : i18n.get('label.dataTitle') + " : " + dataset.name,
datasetName : dataset.name,
type : "data",
saveToolbar : true,
iconCls : "dataDetail"
};
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, jsObj);
} catch (err) {
}
}
});
},
/**
* @static
* Definition of the showPreview method used by the columnRenderer.
* @param {string} value The img src
*/
showPreview : function (value, title) {
var previewWin = new sitools.widget.WindowImageViewer({
title : title,
src : value,
hideAction : 'close',
resizeImage : false
});
previewWin.show();
previewWin.toFront();
},
/**
* Return true if the column is NoClientAccess
* @param {Object} column the column object
* @return {boolean} true if the column should not be used in client
*/
isNoClientAccess : function (column) {
return !Ext.isEmpty(column.columnRenderer) && ColumnRendererEnum.NO_CLIENT_ACCESS == column.columnRenderer.behavior;
},
/**
* @param {Array} listeColonnes
* ColumnModel of the grid
* @param {Array} activeFilters
* Definition of the filters used to build the grid
*
* @returns {Array} The filters configuration for the grid
*/
getFilters : function (listeColonnes, activeFilters) {
var filters = [];
var i = 0;
if (!Ext.isEmpty(listeColonnes)) {
// First loop on all the columns
Ext.each(listeColonnes, function (item, index, totalItems) {
if (item.filter) {
var boolActiveFilter = false, activeFilterValue = "", activeComparison = "";
// loop on active filters to determine if there is an active
// filter on the column
Ext.each(activeFilters, function (activeFilter) {
if (item.columnAlias == activeFilter.columnAlias) {
boolActiveFilter = true;
// construct the value for the specific filter
if (activeFilter.data.type == 'numeric') {
if (!Ext.isObject(activeFilterValue)) {
activeFilterValue = {};
}
activeFilterValue[activeFilter.data.comparison] = activeFilter.data.value;
} else if (activeFilter.data.type == 'date') {
var date = new Date();
var tmp = activeFilter.data.value.split('-');
date.setFullYear(tmp[0], tmp[1] - 1, tmp[2]);
if (!Ext.isObject(activeFilterValue)) {
activeFilterValue = {};
}
if (activeFilter.data.comparison == 'eq') {
activeFilterValue.on = date;
}
if (activeFilter.data.comparison == 'gt') {
activeFilterValue.after = date;
}
if (activeFilter.data.comparison == 'lt') {
activeFilterValue.before = date;
}
} else {
activeFilterValue = activeFilter.data.value;
}
}
});
var filter = {
type : sql2ext.get(item.sqlColumnType),
active : boolActiveFilter,
dataIndex : item.columnAlias,
columnAlias : item.columnAlias,
value : activeFilterValue
};
filters.push(filter);
}
i++;
}, this);
}
return filters;
}
};/*******************************************************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* SITools2 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* SITools2. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/*global Ext, sitools, i18n, sql2ext, extColModelToSrv, window,
extColModelToJsonColModel, DEFAULT_NEAR_LIMIT_SIZE,
DEFAULT_LIVEGRID_BUFFER_SIZE, SITOOLS_DEFAULT_IHM_DATE_FORMAT,
DEFAULT_PREFERENCES_FOLDER, SitoolsDesk, getDesktop, userLogin, projectGlobal, ColumnRendererEnum, SITOOLS_DATE_FORMAT
*/
Ext.namespace('sitools.user.component.dataviews');
/**
* A Simple Object to publish common methods to use stores dataviews in Sitools2.
* @type
*/
sitools.user.component.dataviews.storeUtils = {
/**
* @param {Array}
* ColumnModel of the grid
*
* @returns {Array} The fields used to build the grid
*/
getFields : function (listeColonnes) {
var fields = [];
var i = 0;
if (!Ext.isEmpty(listeColonnes)) {
Ext.each(listeColonnes, function (item, index, totalItems) {
fields[i] = new Ext.data.Field({
name : item.columnAlias,
primaryKey : item.primaryKey,
type : sql2ext.get(item.sqlColumnType)
});
if (sql2ext.get(item.sqlColumnType) === 'boolean') {
Ext.apply(fields[i], {
convert : function (value, record) {
if (value == "f" || value == "false" || value === 0) {
return 0;
}
if (value == "t" || value == "true" || value == 1) {
return 1;
}
return value;
}
});
}
i++;
}, this);
}
return fields;
},
/**
* @param {Array}
* ColumnModel of the grid
*
* @returns {String} The columnAlias of the primaryKey
*/
getPrimaryKey : function (listeColonnes) {
var i = 0, primaryKey = "";
if (!Ext.isEmpty(listeColonnes)) {
Ext.each(listeColonnes, function (item, index, totalItems) {
if (!Ext.isEmpty(item.primaryKey)) {
if (item.primaryKey) {
primaryKey = item.columnAlias;
}
}
}, this);
}
return primaryKey;
},
getFormParams : function () {
return this.formParams;
},
/**
* Build a string using a form param Value.
* @param {} paramValue An object with attributes : at least type, code, value and optionnal userDimension, userUnit
* @return {string} something like "TEXTFIELD|ColumnAlias|value"
*/
paramValueToApi : function (paramValue) {
var stringParam = paramValue.type + "|" + paramValue.code + "|" + paramValue.value;
if (!Ext.isEmpty(paramValue.userDimension) && !Ext.isEmpty(paramValue.userUnit)) {
stringParam += "|" + paramValue.userDimension + "|" + paramValue.userUnit.unitName;
}
return stringParam;
}
};/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n, extColModelToStorage, projectId, userStorage, window,
extColModelToSrv, userLogin, alertFailure, DEFAULT_LIVEGRID_BUFFER_SIZE, projectGlobal, SitoolsDesk, DEFAULT_ORDER_FOLDER, DEFAULT_PREFERENCES_FOLDER, getColumnModel */
/*
* @include "../../../env.js"
* @include "Ext.ux.livegrid/Ext.ux.livegrid-all-debug.js"
* @include "../../../def.js"
*/
Ext.namespace('sitools.user.component.dataviews.livegrid');
// Surcharge de l'objet Store de la liveGrid pour gestion du multiSort.
Ext.override(Ext.ux.grid.livegrid.Store, {
/**
* Sort by multiple fields in the specified order.
*
* @param {Array}
* An Array of field sort specifications, or, if ascending sort
* is required on all columns, an Array of field names. A field
* specification looks like:
*
* <pre><code>
* {
* ordersList : [ {
* field : firstname,
* direction : ASC
* }, {
* field : name
* direction : DESC
* } ]
* }
*
* </code>
*
*/
multiSort : function (sorters, direction) {
this.hasMultiSort = true;
direction = direction || "ASC";
if (this.multiSortInfo && direction == this.multiSortInfo.direction) {
direction = direction.toggle("ASC", "DESC");
}
this.multiSortInfo = {
sorters : sorters,
direction : direction
};
if (this.remoteSort) {
// this.singleSort(sorters[0].field, sorters[0].direction);
this.load(this.lastOptions);
} else {
this.applySort();
this.fireEvent('datachanged', this);
}
},
getSortState : function () {
return this.hasMultiSort ? this.multiSortInfo : this.sortInfo;
},
// application du tri multiple sur le store
load : function (options) {
options = Ext.apply({}, options);
this.storeOptions(options);
if ((this.sortInfo || this.multiSortInfo) && this.remoteSort) {
var pn = this.paramNames;
options.params = Ext.apply({}, options.params);
this.isInSort = true;
var root = pn.sort;
if (this.hasMultiSort) {
options.params[pn.sort] = Ext.encode({
"ordersList" : this.multiSortInfo.sorters
});
} else {
options.params[pn.sort] = Ext.encode({
"ordersList" : [ this.sortInfo ]
});
}
}
try {
return this.execute('read', null, options);
} catch (e) {
this.handleException(e);
return false;
}
}
});
/**
* @class sitools.user.component.dataviews.livegrid.StoreLiveGrid
* @extends Ext.ux.grid.livegrid.Store
* @cfg [] datasetCm The Dataset columnModel,
* @cfg {string} urlRecords The url to request the API
* @cfg {string} sitoolsAttachementForUsers the dataset Attachement
* @cfg {} userPreference Object containing all userPreference for this dataset
* @cfg {numeric} bufferSize the buffer Size of the store
* @cfg [] formParams an array of all formParams to apply to the store
* @cfg [] formMultiDsParams an array of all formParams to apply to the store
* @cfg {} mainView the View of the grid
* @cfg {string} datasetId the DatasetId
* @requires Ext.ux.grid.livegrid.JsonReader
* @requires sql2ext
* @return {Boolean}
*/
sitools.user.component.dataviews.livegrid.StoreLiveGrid = function (config) {
this.storeUtils = sitools.user.component.dataviews.storeUtils;
if (Ext.isEmpty(config)) {
return false;
}
/**
* Construction of the column Model : user preferences have priority on the
* initial definition of the model column in the dataset
*/
var colModel;
if (!Ext.isEmpty(config.userPreference) && config.userPreference.datasetView == "Ext.ux.livegrid" && !Ext.isEmpty(config.userPreference.colModel)) {
colModel = Ext.applyIf(config.userPreference.colModel, config.datasetCm);
}
else {
colModel = config.datasetCm;
}
var cm = getColumnModel(colModel);
/**
* the fields of the store
*/
var map = this.storeUtils.getFields(config.datasetCm);
var primaryKey = this.storeUtils.getPrimaryKey(config.datasetCm);
/*
* JSON Reader : BufferedJsonReader derives from Ext.data.JsonReader and
* allows to pass a version value representing the current state of the
* underlying data repository. Version handling on server side is totally up
* to the user. The version property should change whenever a record gets
* added or deleted on the server side, so the store can be notified of
* changes between the previous and current request. If the store notices a
* version change, it will fire the version change event. Speaking of data
* integrity: If there are any selections pending, the user can react to
* this event and cancel all pending selections.
*/
var bufferedReaderSimple = new Ext.ux.grid.livegrid.JsonReader({
idProperty : primaryKey,
root : 'data',
versionProperty : 'version',
totalProperty : 'total'
}, map);
/*
* Building the params used to request the data :
*/
var params;
// sending the columnModel to the server
if (this.userPreference) {
colModel = extColModelToSrv(cm);
params = {
colModel : Ext.util.JSON.encode(colModel)
};
} else {
params = {};
}
var i = 0;
// sending the formParams to the server
this.formParams = {};
if (!Ext.isEmpty(config.formParams)) {
Ext.each(config.formParams, function (param) {
this.formParams["p[" + i + "]"] = param;
i += 1;
}, this);
Ext.apply(params, this.formParams);
}
// sending the formParams to the server
i = 0;
if (!Ext.isEmpty(config.formMultiDsParams)) {
Ext.each(config.formMultiDsParams, function (param) {
this.formParams["c[" + i + "]"] = param;
i += 1;
}, this);
Ext.apply(params, this.formParams);
}
Ext.apply(config, {
autoLoad : true,
bufferSize : DEFAULT_LIVEGRID_BUFFER_SIZE,
restful : true,
reader : bufferedReaderSimple,
storeUtils : sitools.user.component.dataviews.storeUtils,
url : config.urlRecords,
dataUrl : config.sitoolsAttachementForUsers,
baseParams : params,
listeners : {
scope : this,
exception : function (dp, type, action, options, response, arg) {
// load the alert & close the window.
this.removeAll();
Ext.Msg.show({
title : i18n.get('label.error'),
msg : response.responseText,
buttons : Ext.Msg.OK,
width : 400
});
this.fireEvent("load", this, []);
}
}
});
sitools.user.component.dataviews.livegrid.StoreLiveGrid.superclass.constructor.call(this, config);
};
Ext.extend(sitools.user.component.dataviews.livegrid.StoreLiveGrid, Ext.ux.grid.livegrid.Store, {
getFormParams : function () {
return this.storeUtils.getFormParams();
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* SITools2 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* SITools2. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/*global Ext, sitools, i18n, extColModelToStorage, projectId, userStorage, window, extColModelToSrv, userLogin, alertFailure, DEFAULT_LIVEGRID_BUFFER_SIZE, projectGlobal, SitoolsDesk, DEFAULT_ORDER_FOLDER, DEFAULT_PREFERENCES_FOLDER, loadUrl */
/*
* @include "../../viewDataDetail/viewDataDetail.js"
* @include "resourcePluginParamsPanel.js"
* @include "goToTaskPanel.js"
* @include "../../../env.js"
* @include "../../../sitoolsProject.js"
* @include "../../../def.js"
*/
Ext.namespace('sitools.user.component.dataviews');
* Define the contextMenu and the toolbar menu for the Sitools data Views.
*
* @class sitools.user.component.dataviews.ctxMenu
* @extends Ext.menu.Menu
* @cfg {} grid The object that calls ContextMenu
* @cfg {Array} selections The selected Records
* @cfg {} event The Html Event
* @cfg {string} dataUrl The url Attachement of the dataset
* @cfg {string} datasetId Dataset Id
* @cfg {string} datasetName Dataset Name
* @cfg {string} origin A string representing the caller of the contextMenu
* @cfg {string} urlDetail the Url to request the Detailed record.
* @requires sitools.user.component.viewDataDetail
* @requires sitools.user.component.dataviews.resourcePluginParamsPanel
* @requires sitools.user.component.dataviews.goToTaskPanel
*/
sitools.user.component.dataviews.ctxMenu = Ext.extend(Ext.menu.Menu, {
//sitools.user.component.livegrid.ctxMenu = Ext.extend(Ext.menu.Menu, {
* the url to request the API records
* @type {string}
*/
dataUrl : null,
* The caller of the context Menu
* @type {Ext.grid.GridPanel}
*/
grid : null,
* The dataset Name
* @type {string}
*/
datasetName : null,
* The dataset Id
* @type {string}
*/
datasetId : null,
* The string name of the object that call contextMenu
* @type {string}
*/
origin : null,
* The rightClick event
* @type
*/
event : null,
* The url to request a single record
* @type {string}
*/
urlDetail : null,
constructor : function (config) {
this.dataUrl = config.dataUrl;
this.grid = config.grid;
this.datasetId = config.datasetId;
this.datasetName = config.datasetName;
this.origin = config.origin;
this.event = config.event;
this.urlDetail = config.urlDetail;
this.config = config;
if (this.origin == "sitools.user.modules.projectServices") {
this.selections = this.grid.getSelectionModel().getSelected();
}
sitools.user.component.dataviews.ctxMenu.superclass.constructor.call(this, config);
/* RESOURCE PART */
if (!this.resourceStore) {
this.resourceStore = new Ext.data.JsonStore({
root : "data",
fields : [ {
name : "parameters"
}, {
name : "name",
type : "string"
}, {
name : "description",
type : "string"
}, {
name : "dataSetSelection",
type : "string"
}, {
name : "behavior",
type : "string"
} ],
url : this.dataUrl + "/services",
listeners : {
load : function (store, records, options) {
Ext.each(records, function (rec) {
if (rec.get("dataSetSelection") === "NONE") {
store.remove(rec);
}
}, this);
}
}
});
}
this.resourceStore.on('beforeload', this.onBeforeLoad, this);
this.resourceStore.on('load', this.onLoad, this);
/* END OF RESOURCE PART */
this.on('show', this.onMenuLoad, this);
},
* Event on show ContextMenu : Load the resources store
*/
onMenuLoad : function () {
this.resourceStore.load();
},
* Define the beforeload event of the resources and resource store :
* Call updateMenuItems.
*/
onBeforeLoad : function () {
/* RESOURCE PART */
this.resourceStore.baseParams = this.baseParams;
/* END OF RESOURCE PART */
this.updateMenuItems(false);
},
* Define the beforeload event of the resources store :
* call updateMenuItems
* @param {Ext.Data.Store} store
* @param [] records Array of {Ext.data.Record}
*/
onLoad : function (store, records) {
this.updateMenuItems(true, records);
},
* Build the contextMenu : add the items entry for resources
* @param {boolean} loadedState
* @param []records
*/
updateMenuItems : function (loadedState, records) {
this.selections = this.grid.getSelections();
this.removeAll();
this.el.sync();
this.menuResources = new Ext.menu.Menu();
this.resourcePresent = false;
if (loadedState) {
this.resourceStore.each(function (resRec) {
var resource = resRec.data;
this.resourcePresent = true;
// get resource caracteristics from the parameters
var parameters = resource.parameters;
var url, runTypeUserInput, icon, methods;
parameters.each(function (param) {
switch (param.name) {
case "methods":
methods = param.value;
break;
case "runTypeUserInput":
runTypeUserInput = param.value;
break;
case "url":
url = this.dataUrl + param.value;
break;
case "image":
icon = param.value;
break;
}
}, this);
this.menuResources.add({
text : resource.name,
cls : 'x-btn-text-icon',
icon : icon,
listeners : {
scope : this,
click : function () {
this.resourceClick(resource, url, methods, runTypeUserInput, parameters);
}
}
});
}, this);
} else {
this.menuResources.add('<span class="loading-indicator">' + this.loadingText + '</span>');
}
this.add({
text : i18n.get('label.addSelection'),
listeners : {
scope : this,
click : function (button, e) {
e.stopEvent();
this.orderAction = "add";
this._onOrder();
}
},
icon : loadUrl.get('APP_URL') + "/common/res/images/icons/add_selection.png"
});
this.add({
text : i18n.get('label.export.all.CSV'),
listeners : {
scope : this,
click : function () {
this._onExportCsv();
}
},
icon : loadUrl.get('APP_URL') + "/common/res/images/icons/csv.png"
});
if (this.origin === "Ext.ux.livegrid" || this.origin === "sitools.user.component.dataviews.tplView.TplView") {
this.add({
text : i18n.get('label.downloadFile'),
listeners : {
scope : this,
click : function () {
this.orderAction = "download";
this._onOrder();
}
},
icon : loadUrl.get('APP_URL') + "/common/res/images/icons/add_request.png"
});
}
this.add({
text : i18n.get('label.details'),
listeners : {
scope : this,
click : function (menuItem, e) {
e.stopEvent();
e.stopPropagation();
this._onDetails();
}
},
icon : loadUrl.get('APP_URL') + "/common/res/images/icons/toolbar_details.png"
});
/* RESOURCE PART */
if (this.resourcePresent) {
this.add({
text : i18n.get('label.resources'),
menu : this.menuResources,
icon : loadUrl.get('APP_URL') + "/common/res/images/icons/tree_datasets_resource.png"
});
}
/* END OF RESOURCE PART */
},
* Called when user click on option "add to my selections" and "add request"
* Build a Window to specify a name for the future file,
* check that there is no records in the pending selections.
*/
_onOrder : function () {
if (this.orderAction === "add" && Ext.isEmpty(this.selections)) {
Ext.Msg.alert(i18n.get('label.warning'), i18n.get('warning.noselection'));
return;
}
if (this.origin === "Ext.ux.livegrid") {
if (this.grid.selModel.getPendingSelections().length > 0) {
Ext.Msg.alert(i18n.get('label.warning'), i18n.get("livegrid.selection.invalide.txt"));
return;
}
}
var title = "";
if (this.orderAction === "add") {
title = i18n.get('label.addSelection');
} else {
title = i18n.get('label.addRequest');
}
var winProperty = new Ext.Window({
title : title,
width : 300,
modal : true,
items : [ {
xtype : 'form',
labelWidth : 75,
items : [ {
xtype : 'textfield',
fieldLabel : i18n.get('label.name'),
name : 'orderName',
anchor : '100%'
} ],
buttons : [ {
text : i18n.get('label.ok'),
scope : this,
handler : function () {
var orderName = winProperty.findByType('form')[0].getForm().getFieldValues().orderName;
if (this.orderAction === "add") {
this._addSelection(this.selections, this.grid, this.datasetId, orderName);
} else {
this._onDownload(this.datasetId, this.grid, orderName);
}
winProperty.close();
}
}, {
text : i18n.get('label.cancel'),
handler : function () {
winProperty.close();
}
} ]
} ]
});
winProperty.show();
},
* Create an entry in the user storage with all the selected records.
* @param {Array} selections An array of selected {Ext.data.Record} records
* @param {Ext.grid.GridPanel} grid the grid
* @param {string} datasetId
* @param {string} orderName the name of the future file.
*/
_addSelection : function (selections, grid, datasetId, orderName) {
var primaryKey = "";
var rec = selections[0];
Ext.each(rec.fields.items, function (field) {
if (field.primaryKey) {
primaryKey = field.name;
}
}, rec);
if (Ext.isEmpty(primaryKey) || Ext.isEmpty(rec.get(primaryKey))) {
Ext.Msg.alert(i18n.get('label.warning'), i18n.get('warning.noPrimaryKey'));
return;
}
var putObject = {};
putObject.orderRecord = {};
putObject.orderRecord.records = [];
var colModel = extColModelToStorage(grid.getColumnModel());
Ext.each(selections, function (rec) {
var data = {};
Ext.each(colModel, function (column) {
if (!column.hidden || column.primaryKey) {
data[column.columnAlias] = rec.get(column.columnAlias);
}
});
putObject.orderRecord.records.push(data);
});
putObject.orderRecord.colModel = colModel;
putObject.orderRecord.datasetId = datasetId;
putObject.orderRecord.projectId = projectId;
putObject.orderRecord.dataUrl = this.dataUrl;
putObject.orderRecord.datasetName = this.datasetName;
userStorage.set(orderName + ".json", "/" + DEFAULT_ORDER_FOLDER + "/records", putObject);
},
* Create an external link to get the CSV file generated.
* @return {Boolean}
*/
_onExportCsv : function () {
var csvUrl = this.selections;
var pathUrl = window.location.protocol + "//" + window.location.host + this.dataUrl + "/records";
var request = "";
try {
request = this.grid.getRequestParam();
}
catch (err) {
Ext.Msg.alert(i18n.get('label.error'), String.format(i18n.get('label.notImplementedService'), err));
return false;
}
pathUrl += "?media=csv" + request + "&limit=" + this.grid.store.totalLength;
window.open(pathUrl);
},
* Create an entry in the userSpace with the request of the current grid.
* @param {string} datasetId
* @param {Ext.grid.GridPanel} grid The current grid.
* @param {string} orderName the future file name
*/
_onDownload : function (datasetId, grid, orderName) {
var putObject = {};
putObject.orderRequest = {};
putObject.orderRequest.datasetId = datasetId;
putObject.orderRequest.datasetUrl = grid.dataUrl;
var filters = grid.getFilters();
if (!Ext.isEmpty(filters)) {
putObject.orderRequest.filters = filters.getFilterData(filters);
}
var storeSort = grid.getStore().getSortState();
if (!Ext.isEmpty(storeSort)) {
putObject.orderRequest.sort = storeSort;
}
// if the filter config isn't empty ( download from dataview ) we store
// it
var filtersCfg = grid.getStore().filtersCfg;
if (!Ext.isEmpty(filtersCfg)) {
putObject.orderRequest.filtersCfg = filtersCfg;
}
var colModel = Ext.util.JSON.encode(extColModelToStorage(grid.getColumnModel()));
putObject.orderRequest.colModel = colModel;
putObject.orderRequest.datasetId = datasetId;
putObject.orderRequest.projectId = projectId;
putObject.orderRequest.formParams = grid.getStore().getFormParams();
userStorage.set(orderName + ".json", "/" + DEFAULT_ORDER_FOLDER + "/request", putObject);
},
* Show a {sitools.user.component.viewDataDetail} window.
*/
_onDetails : function () {
var rec = this.grid.getSelections()[0];
if (Ext.isEmpty(rec)) {
Ext.Msg.alert(i18n.get('label.warning'), i18n.get('warning.noselection'));
return;
}
var componentCfg = {
baseUrl : this.urlDetail + "/records/",
grid : this.grid,
fromWhere : this.origin,
datasetId : this.datasetId,
selections : this.grid.getSelections(),
datasetName : this.datasetName,
datasetUrl : this.urlDetail,
preferencesPath : "/" + this.datasetName,
preferencesFileName : "dataDetails"
};
var jsObj = sitools.user.component.viewDataDetail;
var windowConfig = {
id : "dataDetail" + this.datasetId,
title : i18n.get('label.viewDataDetail') + " : " + this.datasetName,
iconCls : "dataDetail",
datasetName : this.datasetName,
saveToolbar : true,
type : "dataDetail",
toolbarItems : [ {
iconCls : 'arrow-back',
handler : function () {
this.ownerCt.ownerCt.items.items[0].goPrevious();
}
}, {
iconCls : 'arrow-next',
handler : function () {
this.ownerCt.ownerCt.items.items[0].goNext();
}
} ]
};
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, jsObj, true);
},
* Get the number of selected records
* @return {number}
*/
getNbRowsSelected : function () {
if (this.grid.getNbRowsSelected()) {
return this.grid.getNbRowsSelected();
// return this.grid.getSelectionModel().getAllSelections(false).length;
}
else {
return null;
}
},
* Get the number of grid records
* @return {number}
*/
getNbGridRecords : function () {
return this.grid.getStore().totalLength;
},
* Sets the grid attribute
* @param {} cmp
*/
setGrid : function (cmp) {
this.grid = cmp;
},
* sets the selections attribute
* @param {} selections
*/
setSelections : function (selections) {
this.selections = selections;
},
* Method called when a resource item is clicked.
*
* @param {} resource The resource description
* @param {string} url the url to call to execute query
* @param {Array} methods A list of permissed methods.
* @param {} runType The runType of the resource.
* @param {Array} parameters An array of parameters.
*/
resourceClick : function (resource, url, methods, runType, parameters) {
this.checkResourceParameters(resource, url, methods, runType, parameters);
},
/**
* handle the click on a Resource after the parameters have been checked
*
* @param {} resource The resource description
* @param {string} url the url to call to execute query
* @param {Array} methods A list of permissed methods.
* @param {} runType The runType of the resource.
* @param {Array} parameters An array of parameters.
*/
handleResourceClick : function (resource, url, methods, runType, parameters) {
//check that the number of records allowed is not reached
var showParameterBox = false;
var params = [];
Ext.each(parameters, function (parameter) {
if (parameter.type === "PARAMETER_USER_INPUT" && parameter.userUpdatable) {
showParameterBox = true;
}
params[parameter.name] = parameter.value;
});
if (methods.split("|") && methods.split("|").length > 1) {
showParameterBox = true;
}
var resourceWindow;
if (showParameterBox && this.origin !== "sitools.user.modules.projectServices") {
var windowConfig = {
title : i18n.get("label.resourceReqParam"),
iconCls : "datasetRessource"
};
var jsObj = sitools.user.component.dataviews.resourcePluginParamsPanel;
var componentCfg = {
resource : resource,
url : url,
methods : methods,
runType : runType,
parameters : parameters,
contextMenu : this,
withSelection : (this.getNbRowsSelected() !== 0)
};
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, jsObj);
}
else if (showParameterBox) {
var windowConfig = {
title : i18n.get("label.resourceReqParam"),
iconCls : "datasetRessource"
};
var jsObj = sitools.user.component.dataviews.resourcePluginParamsPanel;
var componentCfg = {
resource : resource,
url : url,
methods : methods,
runType : runType,
parameters : parameters,
contextMenu : this,
withSelection : false
};
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, jsObj);
}
else {
this.onResourceCallClick(resource, url, methods, runType, null, params);
}
},
* the action used when click on a Resource menu. Request Resource tasks to the URL
* datasetUrlAttachment + "/sva/" + sva.id + "/tasks If there is no selected
* record : Build the request with the actual params of the grid : sort,
* filters, formParams, ColModel else Build the request with a list of
* records primaryKeyValue by using the formRequest API LISTBOXMULTIPLE|
*
* @param {} resource the resource object.
* @param url :
* the Url to request the data
* @param method :
* the method used to request the data
* @param grid :
* the liveGrid
* @param method :
* the method for the resource : POST or GET
* @param userSyncChoice :
* the user choice : "sync" || "async"
* @param limit :
* the request limit
* @param userParameters :
* a list of key/value object
*
*/
onResourceCallClick : function (resource, url, method, userSyncChoice, limit, userParameters) {
if ((method === "POST" || method === "PUT" || method === "DELETE") && userSyncChoice === "TASK_RUN_SYNC") {
Ext.Msg.alert(i18n.get('label.error'), String.format(i18n.get("error.invalidMethodOrSyncRessourceCall"), method, userSyncChoice));
return;
}
var request = "";
if (this.origin !== "sitools.user.modules.projectServices") {
try {
request = this.grid.getRequestParam();
}
catch (err) {
Ext.Msg.alert(i18n.get('label.error'), String.format(i18n.get('label.notImplementedService'), err));
return false;
}
}
url += "?1=1" + request;
if (!Ext.isEmpty(limit)) {
url += "&limit=" + limit;
}
if (! Ext.isEmpty(userParameters)) {
Ext.iterate(userParameters, function (key, value) {
url += "&" + key + "=" + value;
});
}
// If Get => the Resource MUST be synchrone and then send a representation
if (method === "GET") {
switch (resource.behavior) {
case "DISPLAY_IN_NEW_TAB" :
window.open(url);
Ext.getBody().unmask();
break;
case "DISPLAY_IN_DESKTOP" :
var windowConfig = {
title : i18n.get('downloadedResource'),
iconCls : "datasetRessource"
};
var jsObj = Ext.ux.ManagedIFrame.Panel;
var componentCfg = {
layout : 'fit',
defaultSrc: url,
autoScroll : true
};
Ext.Ajax.request({
method : "HEAD",
url : url,
success : function (ret) {
var headerFile = "";
try {
headerFile = ret.getResponseHeader("Content-Type").split(";")[0].split("/")[0];
}
catch (err) {
headerFile = "";
}
var contentDisp = ret.getResponseHeader("Content-Disposition");
if (headerFile === "text" && Ext.isEmpty(contentDisp)) {
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, jsObj);
}
else {
var iFrame = Ext.getCmp("tempMifDownload");
if (Ext.isEmpty(iFrame)) {
iFrame = new Ext.ux.ManagedIFrame.Panel({
layout : 'fit',
defaultSrc: url,
autoScroll : true,
renderTo : Ext.getBody(),
id : "tempMifDownload"
});
}
else {
iFrame.setSrc(url);
}
}
},
failure : alertFailure
});
break;
case "DOWNLOAD" :
//générer un panel caché
var iFrame = Ext.getCmp("tempMifDownload");
if (Ext.isEmpty(iFrame)) {
iFrame = new Ext.ux.ManagedIFrame.Panel({
layout : 'fit',
defaultSrc: url,
autoScroll : true,
renderTo : Ext.getBody(),
id : "tempMifDownload"
});
}
else {
iFrame.setSrc(url);
}
break;
}
return;
} else {
this._executeRequestForResource(url, method);
}
},
* Execute the resource.
* @param {string} url the url to request
* @param {string} method The method (GET, POST, PUT, DELETE)
* @param {} postObject The object that will be passed with the request.
*/
_executeRequestForResource : function (url, method, postObject) {
var config = {
method : method,
url : url,
scope : this,
success : function (response, opts) {
// try {
var json = Ext.decode(response.responseText);
if (!json.success) {
Ext.Msg.show({
title : i18n.get('label.error'),
msg : json.message,
width : 300,
buttons : Ext.MessageBox.OK
});
return;
}
var task = json.TaskModel;
if (!Ext.isEmpty(task.urlResult)) {
window.open(task.urlResult);
} else {
var componentCfg = {
task : task
};
var jsObj = sitools.user.component.dataviews.goToTaskPanel;
var windowConfig = {
title : i18n.get('label.info'),
saveToolbar : false,
iconCls : "datasetRessource"
};
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, jsObj, true);
}
},
failure : function (response, opts) {
Ext.Msg.show({
title : i18n.get('label.error'),
msg : response.responseText,
width : 300,
buttons : Ext.MessageBox.OK
});
},
callback : function () {
if (Ext.getBody().isMasked()) {
Ext.getBody().unmask();
}
}
};
if (!Ext.isEmpty(postObject)) {
Ext.apply(config, postObject);
}
Ext.Ajax.request(config);
},
* check that the request is compatible with the resource parameters.
* If the parameters are ok, call the method handleResourceClick to handle the resource call
* @param {} resource The resource description
* @param {string} url the url to call to execute query
* @param {Array} methods A list of permissed methods.
* @param {} runType The runType of the resource.
* @param {Array} parameters An array of parameters.
*
*/
checkResourceParameters : function (resource, url, methods, runType, parameters) {
var ok = true;
//in the case of a OrderResource, let's check that the number of records is not superior to too_many_selected_threshold => stop the resource execution
var maxThreshold = this.getParameterFromName(parameters, "too_many_selected_threshold");
var nbRows;
if (!Ext.isEmpty(maxThreshold)) {
var maxThresholdTextParam, maxTresholdText;
//get the number of rows either from a selection or all the rows
nbRows = (Ext.isEmpty(this.getNbRowsSelected()) || this.getNbRowsSelected() === 0) ? this.getNbGridRecords() : this.getNbRowsSelected();
if (!Ext.isEmpty(maxThreshold.value) && parseInt(maxThreshold.value) !== -1 && nbRows > parseInt(maxThreshold.value)) {
maxThresholdTextParam = this.getParameterFromName(parameters, "too_many_selected_threshold_text");
maxTresholdText = i18n.get("label.defaultMaxThresholdText");
if (!Ext.isEmpty(maxThresholdTextParam)) {
maxTresholdText = maxThresholdTextParam.value;
}
Ext.Msg.alert(i18n.get("label.error"), maxTresholdText);
return;
}
}
//in the case of a OrderResource, let's check that the number of records is not superior to max_warning_threshold => ask the user to continue or stop the resource execution
var warningThreshold = this.getParameterFromName(parameters, "max_warning_threshold");
if (!Ext.isEmpty(warningThreshold)) {
//get the number of rows either from a selection or all the rows
nbRows = (Ext.isEmpty(this.getNbRowsSelected()) || this.getNbRowsSelected() === 0) ? this.getNbGridRecords() : this.getNbRowsSelected();
if (!Ext.isEmpty(warningThreshold.value) && parseInt(warningThreshold.value) !== -1 && nbRows > parseInt(warningThreshold.value)) {
var warningThresholdTextParam = this.getParameterFromName(parameters, "max_warning_threshold_text");
var warningTresholdText = i18n.get("label.defaultWarningThresholdText");
if (!Ext.isEmpty(warningThresholdTextParam)) {
warningTresholdText = warningThresholdTextParam.value;
}
Ext.Msg.show({
title : i18n.get('label.warning'),
buttons : Ext.Msg.YESNO,
msg : warningTresholdText,
scope : this,
fn : function (btn, text) {
if (btn === 'yes') {
this.handleResourceClick(resource, url, methods, runType, parameters);
}
}
});
return;
}
}
this.handleResourceClick(resource, url, methods, runType, parameters);
},
* get the parameter with the given name from the given list of parameter
* @param {Array} parameters the Array of parameters
* @param {string} name the name of the Parameter to search
* @return {Object} a Parameter with the given name or null if the parameter is not found
*/
getParameterFromName : function (parameters, name) {
var paramOut = null;
for (var index = 0; index < parameters.length && paramOut === null; index++) {
if (parameters[index].name === name) {
paramOut = parameters[index];
}
}
return paramOut;
}
});
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n, extColModelToStorage, projectId, userStorage, window,
GeoExt, userLogin, alertFailure, DEFAULT_LIVEGRID_BUFFER_SIZE, projectGlobal, SitoolsDesk, DEFAULT_ORDER_FOLDER, DEFAULT_PREFERENCES_FOLDER, getColumnModel */
Ext.namespace('sitools.user.component.dataviews.cartoView');
*/
sitools.user.component.dataviews.cartoView.featureSelectionModel = function (config) {
sitools.user.component.dataviews.cartoView.featureSelectionModel.superclass.constructor.call(this, config);
this.addEvents('gridFeatureSelected');
};
Ext.extend(sitools.user.component.dataviews.cartoView.featureSelectionModel, GeoExt.grid.FeatureSelectionModel, {
handleMouseDown : function (g, rowIndex, e) {
sitools.user.component.dataviews.cartoView.featureSelectionModel.superclass.handleMouseDown.call(this, g, rowIndex, e);
this.fireEvent("gridFeatureSelected", g, rowIndex, e);
}
});
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* SITools2 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* SITools2. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/*global Ext, sitools, i18n, sql2ext, extColModelToSrv, window, sitoolsUtils,
extColModelToJsonColModel, DEFAULT_NEAR_LIMIT_SIZE, GeoExt,
DEFAULT_LIVEGRID_BUFFER_SIZE, SITOOLS_DEFAULT_IHM_DATE_FORMAT, OpenLayers,
DEFAULT_PREFERENCES_FOLDER, SitoolsDesk, getDesktop, userLogin, projectGlobal, getColumnModel, loadUrl, getApp
*/
Ext.ns("sitools.user.component.dataviews.cartoView");
/**
* The LiveGrid used to show Dataset Datas.
*
* @cfg {string} dataUrl (Required) The datasetAttachment to request to load the datas
* @cfg {string} datasetId (Required) The DatasetId,
* @cfg {Ext.grid.ColumnModel} datasetCm (Required) A definition of a ColumnModel
* @cfg {} userPreference {} {
* componentSettings {Array} : Array of the Columns as saved by the user
* windowSettings {Object} : {
* moduleId : String
* position : [xpos, ypos]
* size : {
* width : w
* height : h
* }
* specificType : String
* }
* }
* @cfg {Array} formParams list of the form params used to search thrue
* the grid ["TEXTFIELD|AliasColumn1|X", "TEXTFIELD|AliasColumn2|Y"]
* @cfg {Array} filters Array of Ext.ux.Filter : [{
* columnAlias : Alias1,
* data : {
* comparison : "LIKE",
* type : "string",
* value : "01"
* }
* }, {
* columnAlias : Alias2,
* data : {
* comparison : "gt",
* type : "date",
* value : "199-11-04"
* }
* }]
*
* @requires sitools.user.component.dataviews.ctxMenu
* @requires sitools.user.component.columnsDefinition
* @requires sitools.user.component.viewDataDetail
* @requires Ext.ux.grid.GridFiltersSpe
* @requires sitools.user.component.dataPlotter
* @class sitools.user.component.dataviews.cartoView.cartoView
* @extends Ext.ux.grid.livegrid.EditorGridPanel
*
*
*/
sitools.user.component.dataviews.cartoView.mapPanel = function (config) {
this.map = new OpenLayers.Map();
var layer;
var dataviewConfig = sitoolsUtils.arrayProperties2Object(config.datasetViewConfig);
var layersDef = Ext.decode(dataviewConfig.layers), mapLayers = [], baseLayer;
//Définir le column Model.
var colModel = config.datasetCm;
var cm = getColumnModel(colModel, config.dictionaryMappings, dataviewConfig);
Ext.each(layersDef, function (layerDef) {
layer = new OpenLayers.Layer.WMS(
layerDef.layerName,
layerDef.url,
{
layers: layerDef.layerName,
format : "image/png"
},
{
isBaseLayer: layerDef.baseLayer ? true : false,
opacity : layerDef.baseLayer ? 1 : 0.5
}
);
this.map.addLayer(layer);
}, this);
// create vector layer
this.featureLayer = new OpenLayers.Layer.Vector(config.datasetName);
var selectCtrl = new OpenLayers.Control.SelectFeature(this.featureLayer, {
id : "selectCtrl",
onSelect : function (feature) {
console.log(feature);
}
});
//Ajout d'un controle pour choisir les layers
this.map.addControl(new OpenLayers.Control.LayerSwitcher());
//Ajout d'un controle pour la souris
this.map.addControl(new OpenLayers.Control.MousePosition());
this.featureLayer.events.on({
featureselected: function (e) {
var feature = e.feature;
var selectCtrl = this.map.getControlsByClass("OpenLayers.Control.SelectFeature");
if (!Ext.isEmpty(selectCtrl)) {
selectCtrl = selectCtrl[0];
}
// var popup = new GeoExt.Popup({
// title: 'My Popup',
// location: feature,
// manager : getDesktop().getManager(),
// width: 200,
// html: "toto",
// maximizable: true,
// collapsible: true,
// layer : feature.layer,
// feature : feature,
// selectCtrl : selectCtrl
// });
// unselect feature when the popup
// is closed
// popup.on({
// close: function () {
// if (OpenLayers.Util.indexOf(this.layer.selectedFeatures, this.feature) > -1) {
// this.selectCtrl.unselect(this.feature);
// }
// }
// });
// popup.show();
},
scope : this
});
this.map.addLayers([this.featureLayer]);
// -- CONSTRUCTOR --
sitools.user.component.dataviews.cartoView.mapPanel.superclass.constructor.call(Ext.apply(this, {
title: "Map",
region: "center",
map: this.map,
center: new OpenLayers.LonLat(5, 45),
zoom: 6
}));
};
Ext.extend(sitools.user.component.dataviews.cartoView.mapPanel, GeoExt.MapPanel, {
getFeaturesLayer : function () {
return this.featureLayer;
},
getMap : function () {
return this.map;
}
});/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n, userLogin, DEFAULT_ORDER_FOLDER, document, alertFailure, SITOOLS_DATE_FORMAT, SITOOLS_DEFAULT_IHM_DATE_FORMAT, sql2ext,
getDesktop, getColumnModel, extColModelToStorage, SitoolsDesk, projectGlobal, DEFAULT_PREFERENCES_FOLDER, DEFAULT_LIVEGRID_BUFFER_SIZE, loadUrl, ColumnRendererEnum*/
Ext.namespace('sitools.user.component.dataviews.tplView');
/**
* Defines a toolbar for the specific view {sitools.user.component.dataviews.tplView.TplView}
* Redefine method doLoad
* @class sitools.user.component.dataviews.tplView.dataViewPagingToolbar
* @extends Ext.PagingToolbar
*/
sitools.user.component.dataviews.tplView.dataViewPagingToolbar = Ext.extend(Ext.PagingToolbar, {
//sitools.user.component.dataViewPagingToolbar = Ext.extend(Ext.PagingToolbar, {
doLoad : function (start) {
var lastOptions = this.store.lastOptions || {};
var o = lastOptions.params, pn = this.getParams();
o[pn.start] = start;
o[pn.limit] = this.pageSize;
if (this.fireEvent('beforechange', this, o) !== false) {
this.store.load({params : o});
}
//Fire Event on plot window if opened !
var plotComp = Ext.getCmp("plot" + this.ownerCt.datasetId);
if (plotComp) {
var rightPanel = plotComp.findById('plot-right-panel');
var success = rightPanel.fireEvent('buffer', this.store);
}
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n, userLogin, DEFAULT_ORDER_FOLDER, document, alertFailure, SITOOLS_DATE_FORMAT, SITOOLS_DEFAULT_IHM_DATE_FORMAT, sql2ext,
getDesktop, getColumnModel, extColModelToStorage, SitoolsDesk, projectGlobal, DEFAULT_PREFERENCES_FOLDER, DEFAULT_LIVEGRID_BUFFER_SIZE, loadUrl, ColumnRendererEnum*/
/*
* @include "contextMenu.js"
* @include "../../viewDataDetail/viewDataDetail.js"
* @include "../../plot/dataPlotter.js"
* @include "contextMenu.js"
* @include "storeLiveGrid.js"
*/
Ext.namespace('sitools.user.component.dataviews.tplView');
/**
* Define the store for the dataview.
* Redefine the getAt function.
* @class sitools.user.component.dataviews.tplView.StoreTplView
* @extends sitools.user.component.dataviews.livegrid.StoreLiveGrid
* @requires sitools.user.component.columnsDefinition
*/
sitools.user.component.dataviews.tplView.StoreTplView = Ext.extend(sitools.user.component.dataviews.livegrid.StoreLiveGrid, {
//sitools.user.component.dataViewStore = Ext.extend(sitools.user.component.dataviews.livegrid.StoreLiveGrid, {
paramPrefix : "filter",
getAt : function (index) {
return this.data.itemAt(index);
},
buildQuery : function (filters) {
if (Ext.isEmpty(filters)) {
return;
}
var p = {}, i, f, root, dataPrefix, key, tmp,
len = filters.length;
for (i = 0; i < len; i++) {
f = filters[i];
root = [this.paramPrefix, '[', i, ']'].join('');
p[root + '[columnAlias]'] = f.columnAlias;
dataPrefix = root + '[data]';
for (key in f.data) {
p[[dataPrefix, '[', key, ']'].join('')] = f.data[key];
}
}
return p;
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n, extColModelToStorage, projectId, userStorage, window,
extColModelToSrv, userLogin, alertFailure, DEFAULT_LIVEGRID_BUFFER_SIZE, projectGlobal, SitoolsDesk, DEFAULT_ORDER_FOLDER, DEFAULT_PREFERENCES_FOLDER, getColumnModel */
/*
* @include "../../../env.js"
* @include "Ext.ux.livegrid/Ext.ux.livegrid-all-debug.js"
* @include "../../../def.js"
*/
Ext.namespace('sitools.user.component.dataviews.cartoView');
/**
* @class sitools.user.component.dataviews.cartoView.featureStore
* @extends Ext.ux.grid.livegrid.Store
* @cfg [] datasetCm The Dataset columnModel,
* @cfg {string} urlRecords The url to request the API
* @cfg {string} sitoolsAttachementForUsers the dataset Attachement
* @cfg {} userPreference Object containing all userPreference for this dataset
* @cfg {numeric} bufferSize the buffer Size of the store
* @cfg [] formParams an array of all formParams to apply to the store
* @cfg [] formMultiDsParams an array of all formParams to apply to the store
* @cfg {} mainView the View of the grid
* @cfg {string} datasetId the DatasetId
* @requires Ext.ux.grid.livegrid.JsonReader
* @requires sql2ext
* @return {Boolean}
*/
sitools.user.component.dataviews.cartoView.featureStore = function (config) {
this.storeUtils = sitools.user.component.dataviews.storeUtils;
if (Ext.isEmpty(config)) {
return false;
}
/*
* Building the params used to request the data :
*/
var params;
// sending the columnModel to the server
if (this.userPreference) {
colModel = extColModelToSrv(config.datasetCm);
params = {
colModel : Ext.util.JSON.encode(colModel)
};
} else {
params = {};
}
var i = 0;
// sending the formParams to the server
this.formParams = {};
if (!Ext.isEmpty(config.formParams)) {
Ext.each(config.formParams, function (param) {
this.formParams["p[" + i + "]"] = param;
i += 1;
}, this);
Ext.apply(params, this.formParams);
}
// sending the formParams to the server
i = 0;
if (!Ext.isEmpty(config.formMultiDsParams)) {
Ext.each(config.formMultiDsParams, function (param) {
this.formParams["c[" + i + "]"] = param;
i += 1;
}, this);
Ext.apply(params, this.formParams);
}
var reader = config.reader || new sitools.user.data.featureReader({
totalProperty : "totalResults"
}, config.fields);
Ext.apply(config, {
bufferSize : DEFAULT_LIVEGRID_BUFFER_SIZE,
restful : true,
reader : reader,
totalProperty : "totalResults",
storeUtils : sitools.user.component.dataviews.storeUtils,
url : config.urlRecords,
dataUrl : config.urlRecords,
baseParams : params
});
sitools.user.component.dataviews.cartoView.featureStore.superclass.constructor.call(this, config);
this.load({
params : {
start : 0,
limit : DEFAULT_LIVEGRID_BUFFER_SIZE
}
});
};
Ext.extend(sitools.user.component.dataviews.cartoView.featureStore, GeoExt.data.FeatureStore, {
getFormParams : function () {
return this.storeUtils.getFormParams();
},
loadRecords : function (o, options, success) {
this.bufferRange = [ -1, -1 ];
if (o && options && options.params) {
this.bufferRange = [ options.params.start,
Math.max(0, Math.min((options.params.start + options.params.limit) - 1, o.totalRecords - 1)) ];
}
sitools.user.component.dataviews.cartoView.featureStore.superclass.loadRecords.call(this, o, options, success);
},
load : function (options) {
sitools.user.component.dataviews.cartoView.featureStore.superclass.load.call(this, options);
},
/**
* Override
*/
singleSort: function(fieldName, dir) {
var field = this.fields.get(fieldName);
if (!field) {
return false;
}
var name = field.name,
sortInfo = this.sortInfo || null,
sortToggle = this.sortToggle ? this.sortToggle[name] : null;
if (!dir) {
if (sortInfo && sortInfo.field == name) {
dir = (this.sortToggle[name] || 'ASC').toggle('ASC', 'DESC');
} else {
dir = field.sortDir;
}
}
this.sortToggle[name] = dir;
this.sortInfo = {field: name, direction: dir};
this.hasMultiSort = false;
if (this.remoteSort) {
//DA : disable this
this.load(this.lastOptions);
// if (!this.load(this.lastOptions)) {
// if (sortToggle) {
// this.sortToggle[name] = sortToggle;
// }
// if (sortInfo) {
// this.sortInfo = sortInfo;
// }
} else {
this.applySort();
this.fireEvent('datachanged', this);
}
return true;
},
});
/*******************************************************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* SITools2 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* SITools2. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/*global Ext, sitools, i18n, SitoolsDesk */
Ext.namespace('sitools.user.component.dataviews');
* @cfg {Ext.menu.menu} contextMenu the contextMenu that call the plugin and will execute onResourceCallClick method
* @cfg {Ext.data.Record} resource the resource record
* @cfg {string} url the base url of the resource
* @cfg {string} methods the methods allowed with the format method1|method2|...|methodN
* @cfg {string} runType the runTypeUserInput defined in the resource
* @cfg {boolean} withSelection true if there was a selection, false otherwise
* @cfg {Array} parameters the parameters
* @class sitools.user.component.dataviews.resourcePluginParamsPanel
* @extends Ext.Window
*/
sitools.user.component.dataviews.resourcePluginParamsPanel = Ext.extend(Ext.Panel, {
//sitools.user.component.livegrid.resourcePluginParamsWindow = Ext.extend(Ext.Window, {
width : "450",
showMethod : false,
defaultMethod : "",
showRunType : false,
initComponent : function () {
var methodsArray = this.methods.split("|");
this.showMethod = methodsArray.length > 1;
this.defaultMethod = methodsArray[0];
this.methodsStore = new Ext.data.ArrayStore({
fields: ["method"],
idIndex: 0
});
Ext.each(methodsArray, function (item, index) {
this.methodsStore.add(new Ext.data.Record({
method : item
}));
}, this);
var formCommonParametersFields = [];
var comboMethod = new Ext.form.ComboBox({
xtype : 'combo',
mode : 'local',
triggerAction : 'all',
editable : false,
name : 'method',
fieldLabel : i18n.get('label.method'),
width : 100,
store : this.methodsStore,
valueField : 'method',
displayField : 'method',
anchor : "100%",
value : this.defaultMethod,
forceSelection : true
});
this.items = [];
if (this.showMethod) {
formCommonParametersFields.push(comboMethod);
this.formParams = new Ext.form.FormPanel({
padding: 5,
// title : "Request parameters",
items : [{
xtype : 'fieldset',
title : i18n.get("label.commonParameters"),
items : formCommonParametersFields
}]
});
this.items.push(this.formParams);
}
var userInputParams = [];
Ext.each(this.resource.parameters, function (value, index) {
if (value.type == "PARAMETER_USER_INPUT" && value.userUpdatable) {
var item = this.buildFormItemFromParam(value);
userInputParams.push(item);
if (value.name == "runTypeUserInput") {
this.showRunType = true;
}
}
}, this);
if (!Ext.isEmpty(userInputParams)) {
this.formParamsUserInput = new Ext.form.FormPanel({
padding: 5,
labelWidth : 150,
items : {
xtype : 'fieldset',
title : i18n.get("label.specificParameter"),
items : userInputParams
}
});
this.items.push(this.formParamsUserInput);
}
this.buttons = [{
text : i18n.get('label.submit'),
scope : this,
handler : this.onCall
}, {
text : i18n.get('label.cancel'),
scope : this,
handler : function () {
this.ownerCt.close();
}
}];
sitools.user.component.dataviews.resourcePluginParamsPanel.superclass.initComponent.call(this);
},
onCall : function () {
var method;
if (this.showMethod) {
var form = this.formParams.getForm();
method = form.findField("method").getValue();
}
else {
method = this.defaultMethod;
}
var runTypeUserInput;
if (this.showRunType) {
runTypeUserInput = this.formParamsUserInput.getForm().findField("runTypeUserInput").getValue();
}
else {
runTypeUserInput = this.runType;
}
var limit;
var userParameters = {};
if (!Ext.isEmpty(this.formParamsUserInput)) {
var formParams = this.formParamsUserInput.getForm();
Ext.iterate(formParams.getValues(), function (key, value) {
userParameters[key] = value;
});
}
this.contextMenu.onResourceCallClick(this.resource, this.url, method, runTypeUserInput, limit, userParameters);
this.ownerCt.close();
},
buildFormItemFromParam : function (value, userInputParams) {
var valueType = value.valueType;
var item = {};
//specific case for boolean
if (valueType.indexOf("xs:boolean") != -1) {
valueType = "xs:enum[true,false]";
}
if (valueType.indexOf("xs:enum") != -1) {
var enumeration = valueType.split("[");
enumeration = enumeration[1].split("]");
enumeration = enumeration[0].split(",");
var multiple = false;
if (valueType.indexOf("xs:enum-multiple") >= 0 || valueType.indexOf("xs:enum-editable-multiple") >= 0) {
multiple = true;
}
var storeItems = [];
for (var i = 0; i < enumeration.length; i++) {
var tmp = enumeration[i].trim();
storeItems.push([ tmp, tmp]);
}
var store = new Ext.data.ArrayStore({
fields : ['value', 'text'],
data : storeItems,
valueField : 'value',
displayField : 'text'
});
if (multiple) {
item = {
store : store,
name : value.name,
xtype : "multiselect",
values : value.value,
delimiter : '|',
fieldLabel : value.name,
width : 235,
tooltip : value.description
};
}
else {
item = {
store : store,
name : value.name,
xtype : "combo",
value : value.value,
valueField : "value",
displayField : "text",
mode: 'local',
fieldLabel : value.name,
triggerAction : 'all',
selectOnFocus : true,
editable : false,
anchor : "100%",
tooltip : value.description
};
}
}
else {
item = {
name : value.name,
xtype : 'textfield',
value : value.value,
fieldLabel : value.name,
anchor : "100%",
tooltip : value.description
};
}
return item;
},
/**
* Method called when trying to show this component with fixed navigation
*
* @param {sitools.user.component.viewDataDetail} me the dataDetail view
* @param {} config config options
* @returns
*/
showMeInFixedNav : function (me, config) {
Ext.apply(config.windowSettings, {
width : config.windowSettings.winWidth || DEFAULT_WIN_WIDTH,
height : config.windowSettings.winHeight || DEFAULT_WIN_HEIGHT
});
SitoolsDesk.openModalWindow(me, config);
},
/**
* Method called when trying to show this component with Desktop navigation
*
* @param {sitools.user.component.viewDataDetail} me the dataDetail view
* @param {} config config options
* @returns
*/
showMeInDesktopNav : function (me, config) {
Ext.apply(config.windowSettings, {
width : config.windowSettings.winWidth || DEFAULT_WIN_WIDTH,
height : config.windowSettings.winHeight || DEFAULT_WIN_HEIGHT
});
SitoolsDesk.openModalWindow(me, config);
}
});/*******************************************************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* SITools2 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* SITools2. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/*global Ext, sitools, i18n, SitoolsDesk, alertFailure, window, loadUrl */
Ext.namespace('sitools.user.component.dataviews');
/**
* A simple window that displays result of Resource Tasks.
* @class sitools.user.component.dataviews.goToTaskPanel
* @extends Ext.Panel
*/
sitools.user.component.dataviews.goToTaskPanel = Ext.extend(Ext.Panel, {
//sitools.user.component.livegrid.goToTaskPanel = Ext.extend(Ext.Window, {
// modal : true,
width : "500",
buttonAlign : 'left',
layout : 'fit',
initComponent : function () {
this.mainPanel = this.createNewFormComponent(this.task);
this.buttons = ["->", {
text : i18n.get('label.goToTask'),
scope : this,
handler : this.goToTask
}, {
text : i18n.get('label.close'),
scope : this,
handler : function () {
this.ownerCt.close();
}
} ];
this.items = [this.mainPanel];
sitools.user.component.dataviews.goToTaskPanel.superclass.initComponent.call(this);
},
refreshTask : function () {
// var form = this.mainPanel;
var url = this.task.statusUrl;
Ext.Ajax.request({
url : url,
method : "GET",
scope : this,
success : function (ret) {
var data = Ext.decode(ret.responseText);
if (!data.success) {
Ext.Msg.alert(i18n.get('label.warning'), data.message);
return false;
}
this.task = data.TaskModel;
this.mainPanel = this.createNewFormComponent(this.task);
this.removeAll();
this.add(this.mainPanel);
this.doLayout();
},
failure : alertFailure
});
},
createNewFormComponent : function (task) {
var html = String.format(i18n.get("label.taskLaunched"), task.status);
html += String.format("<a href='#'>{0}</a><br>", i18n.get("label.detail"));
if (!Ext.isEmpty(task.urlResult)) {
html += "<br>" + String.format(i18n.get("label.taskResult"), task.urlResult);
html += String.format("<a href='#'>{0}</a><br>", i18n.get("label.result"));
}
else {
html += "<br>" + i18n.get("label.refreshTaskWindow");
html += String.format("<a href='#'>{0}</a><br>", i18n.get("label.refresh"));
}
var panel = new Ext.Panel({
padding: 5,
layout : "fit",
html : html,
listeners : {
scope : this,
afterrender : function (panel) {
panel.getEl().child('a').on("click", function () {
this.showTaskDetail(task);
}, this);
var resultOrRefreshLink = panel.getEl().child('a').next('a');
if (!Ext.isEmpty(task.urlResult)) {
resultOrRefreshLink.on("click", function () {
this.showTaskResults(task);
}, this);
}
else {
resultOrRefreshLink.on("click", function () {
this.refreshTask();
}, this);
}
}
}
});
return panel;
// var formPanel = new Ext.form.FormPanel({
// title : i18n.get("label.taskDetails"),
// padding: 5,
// items : [ {
// name : 'statusUrl',
// xtype : 'textfield',
// value : task.statusUrl,
// hidden : true
// }, {
// name : 'status',
// fieldLabel : i18n.get('label.status'),
// anchor : "100%",
// xtype : 'textfield',
// value : task.status
// }, {
// name : 'id',
// fieldLabel : i18n.get('label.id'),
// anchor : "100%",
// xtype : 'textfield',
// value : task.id
// }, {
// itemValue : task.statusUrl,
// fieldLabel : i18n.get('label.url'),
// xtype : 'box',
// html : "<a href='#'> " + task.statusUrl + "</a>"
// ,
// listeners : {
// scope : this,
// render : function (cmp) {
// cmp.getEl().on('click', function () {
// var jsObj = sitools.user.modules.userSpaceDependencies.svaTasksDetails;
// var componentCfg = {
// sva : task
// };
// var windowConfig = {
// id : "taskStatusDetails",
// title : i18n.get("label.taskDetails") + ":" + task.id
// };
// SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, jsObj);
// });
// }
// }
// }
// ]
// });
//
// if (!Ext.isEmpty(task.urlResult)) {
// var item = new Ext.BoxComponent({
// itemValue : task.urlResult,
// fieldLabel : i18n.get('label.result'),
// html : "<a href='#'> " + task.urlResult + "</a>",
// listeners : {
// scope : this,
// render : function (cmp) {
// cmp.getEl().on('click', function () {
// var orderUrl = loadUrl.get('APP_URL') + loadUrl.get('APP_ORDERS_USER_URL');
// if (cmp.itemValue.indexOf(orderUrl) != -1) {
// this._showOrderDetails(cmp.itemValue);
// } else if (cmp.itemValue.indexOf("/records") != -1) {
// this._showDatasetDetails(cmp.itemValue);
// }
// else {
// window.open(cmp.itemValue);
// }
// }, this);
// }
// }
// });
// formPanel.add(item);
// }
//
// return formPanel;
},
/**
* Handler of the button goToTask.
* Open the home Module Window with the taskPanel opened.
*/
goToTask : function () {
this.ownerCt.close();
var jsObj = sitools.user.component.entete.userProfile.tasks;
var windowConfig = {
title : i18n.get('label.Tasks'),
saveToolbar : false,
iconCls : "tasks"
};
SitoolsDesk.addDesktopWindow(windowConfig, {}, jsObj, true);
},
/**
* Open a sitools.user.modules.userSpaceDependencies.orderProp window.
* @param {String} url the Url to request the task.
*/
_showOrderDetails : function (url) {
Ext.Ajax.request({
url : url,
method : 'GET',
scope : this,
success : function (ret) {
var data = Ext.decode(ret.responseText);
if (!data.success) {
Ext.Msg.alert(i18n.get('label.warning'), data.message);
return false;
}
var rec = new Ext.data.Record(data.order);
var jsObj = sitools.user.modules.userSpaceDependencies.orderProp;
var componentCfg = {
action : 'detail',
orderRec : rec
};
var title = i18n.get('label.details') + " : ";
title += rec.data.userId;
title += " " + i18n.get('label.the');
title += " " + rec.data.dateOrder;
var windowConfig = {
id : "showDataDetailId",
title : title,
specificType : "dataDetail",
iconCls : "dataDetail"
};
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, jsObj);
},
failure : alertFailure
});
},
/**
* Only in NoSql, open a dataset view
* @param {} url
*/
_showDatasetDetails : function (url) {
var urlDataset = url.substring(0, url.indexOf("/records"));
Ext.Ajax.request({
url : urlDataset,
method : 'GET',
scope : this,
success : function (ret) {
var data = Ext.decode(ret.responseText);
if (!data.success) {
Ext.Msg.alert(i18n.get('label.warning'), data.message);
return false;
}
var dataset = new Ext.data.Record(data.dataset).data;
var windowConfig = {
title : i18n.get('label.dataTitle') + " : " + dataset.name,
datasetName : dataset.name,
datasetDescription : dataset.description,
type : "data",
saveToolbar : true,
toolbarItems : [],
iconCls : "dataDetail"
};
//open the dataView according to the dataset Configuration.
var javascriptObject = eval(dataset.datasetView.jsObject);
//add the toolbarItems configuration
Ext.apply(windowConfig, {
id : "data" + dataset.datasetId
});
var componentCfg = {
dataUrl : dataset.sitoolsAttachementForUsers,
datasetId : dataset.id,
datasetCm : dataset.columnModel,
datasetName : dataset.name,
dictionaryMappings : dataset.dictionaryMappings,
datasetViewConfig : dataset.datasetViewConfig,
preferencesPath : "/" + dataset.name,
preferencesFileName : "datasetView"
};
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, javascriptObject);
},
failure : alertFailure
});
},
/**
* Opens a sitools.user.modules.userSpaceDependencies.svaTasksDetails window to see the task Details.
* @param {} task
*/
showTaskDetail : function (task) {
var jsObj = sitools.user.component.entete.userProfile.tasksDetails;
var componentCfg = {
sva : task
};
var windowConfig = {
id : "taskStatusDetails",
title : i18n.get("label.taskDetails") + ":" + task.id,
iconCls : "dataDetail"
};
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, jsObj);
},
/**
* parse the task.urlResult to see if this is an Specialized resource (noSQl or Order).
* If not, open a new Window to get the result of the resource.
* @param {} task
*/
showTaskResults : function (task) {
var orderUrl = loadUrl.get('APP_URL') + loadUrl.get('APP_ORDERS_USER_URL');
if (task.urlResult.indexOf(orderUrl) != -1) {
this._showOrderDetails(task.urlResult);
} else if (task.urlResult.indexOf("/records") != -1) {
this._showDatasetDetails(task.urlResult);
}
else {
window.open(task.urlResult);
}
},
/**
* Method called when trying to show this component with fixed navigation
*
* @param {sitools.user.component.viewDataDetail} me the dataDetail view
* @param {} config config options
* @returns
*/
showMeInFixedNav : function (me, config) {
Ext.apply(config.windowSettings, {
width : config.windowSettings.winWidth || DEFAULT_WIN_WIDTH,
height : config.windowSettings.winHeight || DEFAULT_WIN_HEIGHT
});
SitoolsDesk.openModalWindow(me, config);
},
/**
* Method called when trying to show this component with Desktop navigation
*
* @param {sitools.user.component.viewDataDetail} me the dataDetail view
* @param {} config config options
* @returns
*/
showMeInDesktopNav : function (me, config) {
Ext.apply(config.windowSettings, {
width : config.windowSettings.winWidth || DEFAULT_WIN_WIDTH,
height : config.windowSettings.winHeight || DEFAULT_WIN_HEIGHT
});
SitoolsDesk.openModalWindow(me, config);
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, showResponse, i18n, extColModelToJsonColModel, loadUrl*/
Ext.namespace('sitools.user.component');
//sitools.component.users.datasets.columnsDefinition = function (config) {
/**
* A Panel that displays a grid with columns definition.
* @cfg {string} datasetId The datasetId
* @cfg {Ext.grid.ColumnModel} datasetCm The dataset Column Model
* @cfg {string} datasetName The dataset Name
* @cfg {Array} dictionnaryMappings The dataset Dictionnary Mapping
* @class sitools.user.component.columnsDefinition
* @extends Ext.Panel
*/
sitools.user.component.columnsDefinition = function (config) {
Ext.apply(this, config);
this.dictionaryMappings = config.dictionaryMappings[0];
var fields = [{
name : 'columnAlias',
type : 'string'
}, {
name : 'unit',
type : 'string'
}];
var columns = [{
header : i18n.get('label.columnAlias'),
dataIndex : 'columnAlias',
width : 100,
sortable : true
}, {
header : i18n.get('label.unit'),
dataIndex : 'unit',
width : 100,
sortable : true
}];
if (!Ext.isEmpty(this.dictionaryMappings) && !Ext.isEmpty(this.dictionaryMappings.mapping)
&& !Ext.isEmpty(this.dictionaryMappings.mapping[0])) {
var conceptAsTemplate = this.dictionaryMappings.mapping[0].concept;
//columns
columns.push({
header : i18n.get("headers.name"),
dataIndex : 'name',
width : 100
});
columns.push({
header : i18n.get("headers.description"),
dataIndex : 'description',
width : 120
});
//fields
fields.push({
name : 'name',
type : 'string'
});
fields.push({
name : 'description',
type : 'string'
});
for (var i = 0; i < conceptAsTemplate.properties.length; i++) {
var property = conceptAsTemplate.properties[i];
columns.push({
header : property.name,
dataIndex : property.name,
width : 80
});
fields.push({
name : property.name,
type : 'string'
});
}
}
var reader = new Ext.data.JsonReader({
fields : fields,
idProperty : 'columnAlias'
});
this.grid = new Ext.grid.GridPanel({
store : new Ext.data.GroupingStore({
idProperty : 'id',
fields : fields,
autoload : false,
groupField : false,
reader : reader,
sortInfo : {
field : 'columnAlias',
direction : 'ASC'
},
remoteSort : false
}),
cm : new Ext.grid.ColumnModel({
columns : columns
}),
view : new Ext.grid.GroupingView({
groupTextTpl : '{text} ({[values.rs.length]} {[values.rs.length > 1 ? "Items" : "Item"]})',
autoFill : true,
forceFit : true
}),
layout : 'fit'
});
this.layout = "fit";
this.items = [this.grid];
sitools.user.component.columnsDefinition.superclass.constructor.call(this);
};
Ext.extend(sitools.user.component.columnsDefinition, Ext.Panel, {
componentType : "defi",
_getSettings : function () {
var colModel = [];
return {
colModel : extColModelToJsonColModel(this.grid.getColumnModel().config),
datasetName : this.datasetName,
preferencesPath : this.preferencesPath,
preferencesFileName : this.preferencesFileName
};
},
/**
* overrides onRender method :
* Adds records in the store for each columns.
*/
onRender : function () {
sitools.user.component.columnsDefinition.superclass.onRender.apply(this, arguments);
var store = this.grid.getStore();
var concepts, record;
Ext.each(this.datasetCm, function (column) {
concepts = this.getConcepts(column);
if (!Ext.isEmpty(concepts)) {
Ext.each(concepts, function (concept) {
var rec = {
columnAlias : column.columnAlias,
unit : column.unit && column.unit.label
};
rec = Ext.apply(rec, {
id : concept.id,
name : concept.name,
description : concept.description
});
for (var j = 0; j < concept.properties.length; j++) {
var property = concept.properties[j];
rec[property.name] = property.value;
}
record = new Ext.data.Record(rec);
store.add(record);
});
} else {
var rec = {
columnAlias : column.columnAlias
};
record = new Ext.data.Record(rec);
store.add(record);
}
}, this);
},
/**
* @param {Ext.grid.Column} column
* @return {Array} the concepts of the column
*/
getConcepts : function (column) {
if (Ext.isEmpty(this.dictionaryMappings)) {
return;
}
var mapping = this.dictionaryMappings.mapping;
var concepts = [], map;
for (var i = 0; i < mapping.length; i++) {
map = mapping[i];
if (column.columnAlias == map.columnAlias) {
concepts.push(map.concept);
}
}
return concepts;
},
/**
* Enable or disable grouping View
*/
toggleGroup : function () {
var store = this.grid.getStore();
if (store.groupField === false) {
store.groupBy("columnAlias");
var indexColumnAlias = this.grid.getColumnModel().findColumnIndex("columnAlias");
this.grid.getColumnModel().setHidden(indexColumnAlias, true);
this.grid.getView().enableGrouping = true;
this.grid.getView().refresh();
} else {
store.clearGrouping();
this.grid.getColumnModel().setHidden(0, false);
}
},
/**
* Method called when trying to show this component with fixed navigation
*
* @param {sitools.user.component.columnsDefinition} me the semantic view
* @param {} config config options
* @returns
*/
showMeInFixedNav : function (me, config) {
Ext.apply(config.windowSettings, {
width : 400,
height : 400
});
SitoolsDesk.openModalWindow(me, config);
}
});
Ext.reg('sitools.user.component.columnsDefinition', sitools.user.component.columnsDefinition);
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, showResponse, i18n, extColModelToJsonColModel, loadUrl, alertFailure*/
Ext.namespace('sitools.user.component');
//sitools.component.users.datasets.columnsDefinition = function (config) {
/**
* A Panel that displays a grid with columns definition.
* @cfg {string} datasetId The datasetId
* @class sitools.user.component.DatasetOverview
* @extends Ext.Panel
*/
sitools.user.component.DatasetOverview = function (config) {
this.DEFAULT_HEIGHT = 600;
this.DEFAULT_WIDTH = 800;
this.DEFAULT_WIDTH_FORMS_PANEL = 400;
this.DEFAULT_HEIGHT_SEMANTIC_PANEL = 200;
this.DEFAULT_WIDTH_EAST_PANEL = 200;
Ext.apply(this, config);
this.formsTabPanel = new Ext.TabPanel({
items : []
});
this.formsContainerPanel = new Ext.Panel({
title : "forms",
layout : "fit",
region : "west",
collapsible : true,
split : true,
width : this.DEFAULT_WIDTH_FORMS_PANEL,
items : [this.formsTabPanel]
});
this.semanticPanel = new Ext.Panel({
title : i18n.get('label.semantic'),
layout : "fit",
region : "south",
html : " ",
collapsible : true,
split : true,
hidden : true,
height : this.DEFAULT_HEIGHT_SEMANTIC_PANEL
});
this.descriptionPanel = new Ext.Panel({
title : i18n.get('label.description'),
autoScroll : true,
layout : "fit",
region : "center",
html : " "
});
this.mainPanel = new Ext.Panel({
layout : "fit",
region : "center",
border : false,
items : [{
layout : "border",
items : [this.descriptionPanel, this.semanticPanel]
}]
});
this.eastPanel = new Ext.Panel({
layout : "fit",
region : "east",
hidden : true,
collapsible : true,
split : true,
items : [],
width : this.DEFAULT_WIDTH_EAST_PANEL
});
sitools.user.component.DatasetOverview.superclass.constructor.call(this, {
layout : "border",
items : [this.formsContainerPanel, this.mainPanel, this.eastPanel],
listeners : {
scope : this,
beforerender : function () {
this.loadDataset();
return true;
},
datasetLoaded : function () {
this.loadForms();
},
formsLoaded : function () {
this.loadSemantic();
},
semanticLoaded : function () {
this.loadDescription();
},
descriptionLoaded : function () {
// this.unMask();
return;
}
}
});
};
Ext.extend(sitools.user.component.DatasetOverview, Ext.Panel, {
componentType : "datasetOverview",
_getSettings : function () {
var colModel = {};
if (this.dataview) {
colModel = extColModelToJsonColModel(this.dataview.colModel.config);
}
else {
colModel = extColModelToJsonColModel(this.dataset.columnModel);
}
return {
sitoolsAttachementForUsers : this.sitoolsAttachementForUsers,
preferencesPath : this.preferencesPath,
preferencesFileName : this.preferencesFileName,
formsPanelWidth : 50,
formsPanelCollapsed : true,
formsActivePanel : 1,
datasetName : this.dataset.name,
colModel : colModel,
datasetView : "datasetOverview",
datasetUrl : this.sitoolsAttachementForUsers,
dictionaryMappings : this.dataset.dictionaryMappings
};
},
loadDataset : function () {
Ext.Ajax.request({
method : "GET",
scope : this,
url : this.sitoolsAttachementForUsers,
success : function (response) {
var json = Ext.decode(response.responseText);
if (!json.success) {
Ext.Msg.alert(i18n.get('label.error'), i18n.get('warning.datasetRequestError'));
return false;
} else {
this.dataset = json.dataset;
this.fireEvent("datasetLoaded");
}
},
failure : alertFailure
});
},
loadForms : function () {
Ext.Ajax.request({
method : "GET",
scope : this,
url : this.dataset.sitoolsAttachementForUsers + '/forms',
success : function (response) {
var json = Ext.decode(response.responseText);
var eventToFire = 'formsLoaded';
if (!json.success) {
Ext.Msg.alert(i18n.get('label.error'), i18n.get('warning.datasetRequestError'));
return false;
} else {
this.forms = json.data;
if (!Ext.isEmpty(this.forms)) {
// If forms exist : fire loadSemantic event
var eventToFire = 'semanticLoaded';
Ext.each(this.forms, function (form) {
var panel = new sitools.user.component.forms.mainContainer({
title : form.name,
dataUrl : this.dataset.sitoolsAttachementForUsers,
dataset : this.dataset,
formId : form.id,
id : form.id,
formName : form.name,
formParameters : form.parameters,
formWidth : form.width,
formHeight : form.height,
formCss : form.css,
preferencesPath : "/" + this.dataset.name + "/forms",
preferencesFileName : form.name,
searchAction : this.searchAction,
scope : this
});
this.formsTabPanel.add(panel);
}, this);
this.formsTabPanel.doLayout();
if (this.formId) {
this.formsTabPanel.setActiveTab(this.formId);
}
else {
this.formsTabPanel.setActiveTab(0);
}
}
else {
this.semanticPanel.show();
var jsObj = eval(this.dataset.datasetView.jsObject);
var componentCfg = {
dataUrl : this.dataset.sitoolsAttachementForUsers,
datasetId : this.dataset.id,
datasetCm : this.dataset.columnModel,
datasetName : this.dataset.name,
dictionaryMappings : this.dataset.dictionaryMappings,
datasetViewConfig : this.dataset.datasetViewConfig,
preferencesPath : "/" + this.dataset.name,
preferencesFileName : "datasetView"
};
this.dataview = new jsObj(componentCfg);
this.formsContainerPanel.removeAll();
this.formsContainerPanel.hide();
this.eastPanel.setVisible(true);
this.eastPanel.add(this.mainPanel.items.items);
this.mainPanel.removeAll();
this.mainPanel.add(this.dataview);
this.doLayout();
}
this.mainPanel.doLayout();
this.fireEvent(eventToFire);
}
},
failure : alertFailure
});
},
loadSemantic : function () {
var panel = new sitools.user.component.columnsDefinition({
datasetId : this.dataset.id,
datasetCm : this.dataset.columnModel,
datasetName : this.dataset.name,
dictionaryMappings : this.dataset.dictionaryMappings
});
this.semanticPanel.removeAll();
this.semanticPanel.add(panel);
this.semanticPanel.doLayout();
this.fireEvent('semanticLoaded');
},
loadDescription : function () {
var contentTarget = this.descriptionPanel.getContentTarget();
if (!Ext.isEmpty(this.dataset.descriptionHTML)) {
contentTarget.update(Ext.DomHelper.markup(this.dataset.descriptionHTML));
}
this.fireEvent("descriptionLoaded");
},
searchAction : function (formParams, dataset, scope) {
var jsObj = eval(dataset.datasetView.jsObject);
var componentCfg = {
dataUrl : dataset.sitoolsAttachementForUsers,
datasetId : dataset.id,
datasetCm : dataset.columnModel,
datasetName : dataset.name,
formParams : formParams,
dictionaryMappings : dataset.dictionaryMappings,
datasetViewConfig : dataset.datasetViewConfig,
preferencesPath : "/" + dataset.name,
preferencesFileName : "datasetView",
userPreference : {
datasetName : this.dataset.name,
colModel : extColModelToJsonColModel(this.dataset.columnModel),
datasetView : "datasetOverview",
datasetUrl : this.sitoolsAttachementForUsers,
dictionaryMappings : this.dataset.dictionaryMappings
}
};
scope.dataview = new jsObj(componentCfg);
// scope.formsContainerPanel.collapse();
// scope.semanticPanel.collapse();
scope.mainPanel.removeAll();
scope.mainPanel.add(scope.dataview);
scope.doLayout();
}
});
Ext.reg('sitools.user.component.DatasetOverview', sitools.user.component.DatasetOverview);
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n, alert, showResponse, alertFailure, SitoolsDesk, window, userLogin, loadUrl, DEFAULT_WIN_WIDTH, DEFAULT_WIN_HEIGHT */
Ext.namespace('sitools.user.component.entete.userProfile');
/**
* @class sitools.user.component.entete.userProfile.tasksDetails
* @extends Ext.FormPanel
*/
sitools.user.component.entete.userProfile.tasksDetails = Ext.extend(Ext.FormPanel, {
labelWidth : 120,
frame : true,
autoScroll : true,
initComponent : function () {
//this.svaIntern = this.sva;
var itemsForm = [];
Ext.iterate(this.sva, function (key, value) {
if (value != undefined && value != ""){
itemsForm.push({
xtype : 'textfield',
name : key,
fieldLabel : i18n.get('label.' + key),
disabled : true,
disabledClass : 'x-item-disabled-custom',
labelStyle : 'font-weight:bold;',
anchor : '100%',
value : value
});
}
});
this.items = itemsForm;
sitools.user.component.entete.userProfile.tasksDetails.superclass.initComponent.call(this);
},
/**
* Method called when trying to show this component with fixed navigation
*
* @param {sitools.user.component.viewDataDetail} me the dataDetail view
* @param {} config config options
* @returns
*/
showMeInFixedNav : function (me, config) {
Ext.apply(config.windowSettings, {
width : config.windowSettings.winWidth || DEFAULT_WIN_WIDTH,
height : config.windowSettings.winHeight || DEFAULT_WIN_HEIGHT
});
SitoolsDesk.openModalWindow(me, config);
},
/**
* Method called when trying to show this component with Desktop navigation
*
* @param {sitools.user.component.viewDataDetail} me the dataDetail view
* @param {} config config options
* @returns
*/
showMeInDesktopNav : function (me, config) {
Ext.apply(config.windowSettings, {
width : config.windowSettings.winWidth || DEFAULT_WIN_WIDTH,
height : config.windowSettings.winHeight || DEFAULT_WIN_HEIGHT
});
SitoolsDesk.openModalWindow(me, config);
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n, userLogin, document, alertFailure, SitoolsDesk, userLogin, DEFAULT_ORDER_FOLDER, loadUrl, viewFileContent*/
Ext.namespace('sitools.user.component.entete.userProfile');
/**
* @class sitools.user.component.entete.userProfile.diskSpace
* @extends Ext.tree.TreePanel
*/
sitools.user.component.entete.userProfile.diskSpace = Ext.extend(Ext.tree.TreePanel, {
autoScroll : true,
initComponent : function () {
this.AppUserStorage = loadUrl.get('APP_USERSTORAGE_USER_URL').replace('{identifier}', userLogin) + "/files";
this.tbar = new Ext.ux.StatusBar({
statusAlign: 'right'
});
this.buttons = [ {
text : i18n.get('label.refreshResource'),
scope : this,
handler : this._onRefresh
}, {
text : i18n.get('label.deleteResource'),
scope : this,
handler : this._onDelete
}, {
text : i18n.get('label.close'),
scope : this,
handler : function () {
this.ownerCt.destroy();
}
} ];
sitools.user.component.entete.userProfile.diskSpace.superclass.initComponent.call(Ext.apply(this, {
expanded : true,
useArrows : true,
autoScroll : true,
layout : 'fit',
animate : true,
enableDD : false,
containerScroll : true,
//frame : true,
loader : new Ext.tree.TreeLoader(),
rootVisible : true,
root : {
text : userLogin,
children : [],
nodeType : 'async',
url : loadUrl.get('APP_URL') + this.AppUserStorage + "/"
},
// auto create TreeLoader
listeners : {
scope : this,
beforeload : function (node) {
return node.isRoot || Ext.isDefined(node.attributes.children);
},
beforeexpandnode : function (node) {
node.removeAll();
Ext.Ajax.request({
url : node.attributes.url,
method : 'GET',
scope : this,
success : function (ret) {
try {
var Json = Ext.decode(ret.responseText);
Ext.each(Json, function (child) {
var text = child.text;
if (child.leaf) {
text += "<span style='font-style:italic'> (" + Ext.util.Format.fileSize(child.size) + ")</span>";
}
node.appendChild({
cls : child.cls,
text : text,
url : child.url,
leaf : child.leaf,
children : [],
checked : child.checked
});
});
return true;
} catch (err) {
Ext.Msg.alert(i18n.get('warning'), err);
return false;
}
},
failure : function (ret) {
return null;
}
});
return true;
},
click : function (n) {
if (n.attributes.leaf) {
var url = n.attributes.url;
viewFileContent(url, n.attributes.text);
}
}
}
}));
},
onRender : function () {
sitools.user.component.entete.userProfile.diskSpace.superclass.onRender.apply(this, arguments);
this.setUserStorageSize();
},
setUserStorageSize : function () {
Ext.Ajax.request({
method : "GET",
scope : this,
url : loadUrl.get('APP_URL') + loadUrl.get('APP_USERSTORAGE_USER_URL').replace("{identifier}", userLogin) + "/status",
success : function (ret) {
var json = Ext.decode(ret.responseText);
if (!json.success) {
return;
}
var storage = json.userstorage.storage;
var totalSpace = storage.quota;
var usedSpace = storage.busyUserSpace;
var pourcentage = usedSpace / totalSpace * 100;
var cls = null;
if (pourcentage >= 90 && pourcentage < 100) {
cls = "x-status-warning";
}
else if (pourcentage > 100) {
cls = "x-status-error";
}
var str = String.format(i18n.get('label.diskSpaceLong'), Ext.util.Format.round(pourcentage, 0), Ext.util.Format.fileSize(totalSpace));
this.getTopToolbar().setText(str);
this.getTopToolbar().setIcon(cls);
this.doLayout();
}
});
},
_onRefresh : function () {
this.getRootNode().collapse();
this.setUserStorageSize();
// this.treePanel.getLoader().load(this.treePanel.getRootNode());
},
_onDelete : function () {
var selNodes = this.getChecked();
if (selNodes.length === 0) {
return;
}
Ext.each(selNodes, function (node) {
Ext.Ajax.request({
method : 'DELETE',
url : node.attributes.url + "?recursive=true",
scope : this,
success : function (response, opts) {
var notify = new Ext.ux.Notification({
iconCls : 'x-icon-information',
title : i18n.get('label.information'),
html : i18n.get('label.resourceDeleted'),
autoDestroy : true,
hideDelay : 1000
});
notify.show(document);
node.destroy();
},
failure : alertFailure
}, this);
});
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n, alert, showResponse, alertFailure, SitoolsDesk, window, userLogin, loadUrl*/
Ext.namespace('sitools.user.component.entete.userProfile');
sitools.user.component.entete.userProfile.tasks = Ext.extend(Ext.grid.GridPanel, {
border : false,
sm : new Ext.grid.RowSelectionModel(),
layout : {
type : 'vbox',
// flex : 1,
align : 'stretch'
},
height : 430,
pageSize : 10,
// loadMask: true,
initComponent : function () {
this.url = loadUrl.get('APP_URL') + loadUrl.get('APP_USERRESOURCE_ROOT_URL') + '/' + userLogin + '/tasks';
this.store = new Ext.data.JsonStore({
root : 'data',
restful : true,
url : this.url,
remoteSort : true,
idProperty : 'id',
fields : [ {
name : 'id',
type : 'string'
}, {
name : 'status',
type : 'string'
}, {
name : 'modelId',
type : 'string'
}, {
name : 'customStatus',
type : 'string'
}, {
name : 'timestamp',
type : 'string'
}, {
name : 'statusUrl',
type : 'string'
}, {
name : 'urlResult',
type : 'string'
}, {
name : 'userId',
type : 'string'
}, {
name : 'startDate',
type : 'string'
}, {
name : 'endDate',
type : 'string'
}, {
name : 'runType',
type : 'string'
}, {
name : 'modelName',
type : 'string'
}]
});
this.cm = new Ext.grid.ColumnModel({
// specify any defaults for each column
defaults : {
sortable : false
},
columns : [ {
header : i18n.get('label.taskId'),
dataIndex : 'id',
width : 220,
hidden : true
}, {
header : i18n.get('label.startDate'),
dataIndex : 'startDate',
width : 170
}, {
header : i18n.get('label.endDate'),
dataIndex : 'endDate',
width : 170
}, {
header : i18n.get('label.status'),
dataIndex : 'status',
width : 180
}, {
header : i18n.get('label.customStatus'),
dataIndex : 'customStatus',
width : 100
} ]
});
this.bbar = {
xtype : 'paging',
pageSize : this.pageSize,
store : this.store,
displayInfo : true,
displayMsg : i18n.get('paging.display'),
emptyMsg : i18n.get('paging.empty')
};
this.tbar = {
xtype : 'toolbar',
defaults : {
scope : this
},
items : [ {
text : i18n.get('label.delete'),
// icon: 'res/images/icons/toolbar_project_add.png',
icon : loadUrl.get('APP_URL') + '/common/res/images/icons/toolbar_delete.png',
handler : this._onDelete,
xtype : 's-menuButton'
}, {
text : i18n.get('label.clean'),
// icon: 'res/images/icons/toolbar_project_add.png',
icon : loadUrl.get('APP_URL') + '/common/res/images/icons/toolbar_clean.png',
handler : this._onClean,
xtype : 's-menuButton'
}, {
text : i18n.get('label.viewResult'),
// icon: 'res/images/icons/toolbar_project_add.png',
icon : loadUrl.get('APP_URL') + '/common/res/images/icons/view_result.png',
handler : this._onViewResult,
xtype : 's-menuButton'
}, {
text : i18n.get('label.viewStatusDetails'),
// icon: 'res/images/icons/toolbar_project_add.png',
icon : loadUrl.get('APP_URL') + '/common/res/images/icons/toolbar_details.png',
handler : this._onViewStatusDetails,
xtype : 's-menuButton'
}, {
text : i18n.get('label.setFinish'),
// icon: 'res/images/icons/toolbar_project_add.png',
icon : loadUrl.get('APP_URL') + '/common/res/images/icons/set_finish.png',
handler : this._onFinish,
xtype : 's-menuButton'
} ]
};
sitools.user.component.entete.userProfile.tasks.superclass.initComponent.call(Ext.apply(this, {
viewConfig : {
forceFit : true
}
}));
},
onRender : function () {
sitools.user.component.entete.userProfile.tasks.superclass.onRender.apply(this, arguments);
this.store.load({
params : {
start : 0,
limit : this.pageSize
}
});
},
_onDelete : function () {
var rec = this.getSelectionModel().getSelected();
if (!rec) {
return false;
}
var tot = Ext.Msg.show({
title : i18n.get('label.delete'),
buttons : Ext.Msg.YESNO,
msg : i18n.get('tasks.delete'),
scope : this,
fn : function (btn, text) {
if (btn == 'yes') {
this.doDelete(rec);
}
}
});
},
doDelete : function (rec) {
// var rec = this.getSelectionModel().getSelected();
// if (!rec) return false;
Ext.Ajax.request({
url : this.url + "/" + rec.data.id,
method : 'DELETE',
scope : this,
success : function (ret) {
if (showResponse(ret)) {
this.store.reload();
}
},
failure : alertFailure
});
},
_onViewResult : function () {
var rec = this.getSelectionModel().getSelected();
if (!rec) {
return false;
}
if (!Ext.isEmpty(rec.data.urlResult)) {
var orderUrl = loadUrl.get('APP_URL') + loadUrl.get('APP_ORDERS_USER_URL');
if (rec.data.urlResult.indexOf(orderUrl) != -1) {
this._showOrderDetails(rec.data.urlResult);
} else {
var pathUrl = window.location.protocol + "//" + window.location.host;
if (rec.data.urlResult.indexOf("http://") != -1) {
window.open(rec.data.urlResult);
} else {
window.open(pathUrl + rec.data.urlResult);
}
}
}
},
_onFinish : function () {
var rec = this.getSelectionModel().getSelected();
if (!rec) {
return false;
}
Ext.Ajax.request({
url : this.url + "/" + rec.data.id + "?action=finish",
method : 'PUT',
scope : this,
success : function (ret) {
if (showResponse(ret)) {
this.store.reload();
}
},
failure : alertFailure
});
},
_onClean : function () {
var tot = Ext.Msg.show({
title : i18n.get('label.delete'),
buttons : Ext.Msg.YESNO,
msg : i18n.get('tasks.delete.all'),
scope : this,
fn : function (btn, text) {
if (btn == 'yes') {
this._doClean();
}
}
});
},
_doClean : function () {
Ext.Ajax.request({
url : this.url,
method : 'DELETE',
scope : this,
success : function (ret) {
if (showResponse(ret)) {
this.store.reload();
}
},
failure : alertFailure
});
},
_onViewStatusDetails : function () {
var rec = this.getSelectionModel().getSelected();
if (!rec) {
return Ext.Msg.alert(i18n.get('label.warning'), i18n.get('warning.noselection'));
}
var jsObj = sitools.user.component.entete.userProfile.tasksDetails;
var componentCfg = {
sva : rec.data
};
var windowConfig = {
id : "taskStatusDetails",
title : i18n.get("label.taskDetails") + ":" + rec.data.id,
iconCls : "dataDetail"
};
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, jsObj);
},
_showOrderDetails : function (url) {
Ext.Ajax.request({
url : url,
method : 'GET',
scope : this,
success : function (ret) {
var data = Ext.decode(ret.responseText);
if (!data.success) {
Ext.Msg.alert(i18n.get('label.warning'), data.message);
return false;
}
var rec = new Ext.data.Record(data.order);
var jsObj = sitools.user.modules.userSpaceDependencies.orderProp;
var componentCfg = {
action : 'detail',
orderRec : rec
};
var title = i18n.get('label.details') + " : ";
title += rec.data.userId;
title += " " + i18n.get('label.the');
title += " " + rec.data.dateOrder;
var windowConfig = {
id : "showDataDetailId",
title : title,
specificType : "dataDetail",
iconCls : "dataDetail"
};
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, jsObj);
},
failure : alertFailure
});
}
});
/*******************************************************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* SITools2 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* SITools2. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/*global Ext, sitools, i18n, SitoolsDesk, alertFailure, window, loadUrl, DEFAULT_WIN_WIDTH, DEFAULT_WIN_HEIGHT */
Ext.namespace('sitools.user.component.entete.viewTextPanel');
/**
* A simple panel that displays text
*
* @cfg {String} text The text to display
* @cfg {Boolean} formatJson true to format the text as json, false otherwise
* @class sitools.user.component.entete.userProfile.viewTextPanel
* @extends Ext.Panel
*/
sitools.user.component.entete.userProfile.viewTextPanel = Ext.extend(Ext.Panel, {
layout : 'fit',
autoScroll : true,
initComponent : function () {
if (this.formatJson) {
try {
if (Ext.isFunction(JSON.parse) && Ext.isFunction(JSON.stringify)) {
var obj = JSON.parse(this.text);
this.html = JSON.stringify(obj, null, 4);
this.style = "white-space: pre";
}
} catch (err) {
this.html = this.text;
}
}
else {
this.html = this.text;
}
sitools.user.component.entete.userProfile.viewTextPanel.superclass.initComponent.call(this);
},
/**
* Method called when trying to show this component with fixed navigation
*
* @param {sitools.user.component.viewDataDetail} me the dataDetail view
* @param {} config config options
* @returns
*/
showMeInFixedNav : function (me, config) {
Ext.apply(config.windowSettings, {
width : config.windowSettings.winWidth || DEFAULT_WIN_WIDTH,
height : config.windowSettings.winHeight || DEFAULT_WIN_HEIGHT
});
SitoolsDesk.openModalWindow(me, config);
},
/**
* Method called when trying to show this component with Desktop navigation
*
* @param {sitools.user.component.viewDataDetail} me the dataDetail view
* @param {} config config options
* @returns
*/
showMeInDesktopNav : function (me, config) {
Ext.apply(config.windowSettings, {
width : config.windowSettings.winWidth || DEFAULT_WIN_WIDTH,
height : config.windowSettings.winHeight || DEFAULT_WIN_HEIGHT
});
SitoolsDesk.openModalWindow(me, config);
}
});
/*******************************************************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* SITools2 is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* SITools2. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/*global Ext, sitools, i18n, loadUrl */
Ext.namespace('sitools.user.component');
/**
* Help Component
* @class sitools.user.component.help
* @extends Ext.Panel
*/
sitools.user.component.help = Ext.extend(Ext.Panel, {
/**
* the node to activate
* @type Ext.tree.TreeNode
*/
activeNode : null,
initComponent : function () {
this.url = loadUrl.get('APP_URL') + "/client-user/res/help/fr/Client-userUG.html";
this.layout = "border";
var htmlReaderCfg = {
defaults : {
padding : 10
},
layout : 'fit',
region : 'center'
};
if (!Ext.isEmpty(this.cfgCmp) && !Ext.isEmpty(this.cfgCmp.activeNode)) {
this.activeNode = this.cfgCmp.activeNode;
} else {
htmlReaderCfg.defaultSrc = this.url;
}
this.tree = new Ext.tree.TreePanel({
region : 'west',
animate : true,
width : 200,
rootVisible : false,
useArrows : true,
autoScroll : true,
split : true,
collapsible : true,
collapsed : false,
title : "menu",
root : {
nodeType : 'async',
text : "rootHelp"
},
loader : new Ext.tree.TreeLoader({
requestMethod : 'GET',
url : loadUrl.get('APP_URL') + "/client-user/tmp/help.json",
listeners : {
scope : this,
load : function () {
if (!Ext.isEmpty(this.activeNode)) {
var node = this.tree.getNodeById(this.activeNode);
if (!Ext.isEmpty(node)) {
this.tree.selectPath(node.getPath());
this.treeAction(node);
} else {
Ext.Msg.alert(i18n.get('label.warning'), i18n.get('msg.nodeundefined'));
}
}
}
}
}),
listeners : {
scope : this,
click : function (node, e) {
this.treeAction(node);
}
}
});
this.htmlReader = new Ext.ux.ManagedIFrame.Panel(htmlReaderCfg);
this.items = [ this.tree, this.htmlReader ];
// tree.getRootNode().expand(true);
sitools.user.component.help.superclass.initComponent.call(this);
},
onRender : function () {
sitools.user.component.help.superclass.onRender.apply(this, arguments);
this.tree.getRootNode().expand(true);
},
/**
* Action executed ; 'this' refers to this component
*
* @param node
* @returns
*/
treeAction : function (node) {
// Getting node urlArticle
var nodeAnchor = node.attributes.nodeAnchor;
if (!Ext.isDefined(nodeAnchor)) {
Ext.Msg.alert(i18n.get('label.warning'), i18n.get('msg.nodeundefined'));
return;
}
this.htmlReader.setSrc(this.url + "#" + nodeAnchor);
}
});
Ext.reg('sitools.user.component.help', sitools.user.component.help);
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, showResponse, i18n, SitoolsDesk, extColModelToJsonColModel, loadUrl*/
Ext.namespace('sitools.user.component.entete');
/**
* Populate the div x-headers of the sitools Desktop.
* @cfg {String} htmlContent html content of the headers,
* @cfg {Array} modules the modules list
* @class sitools.user.component.entete.Entete
* @extends Ext.Panel
*/
sitools.user.component.entete.Entete = Ext.extend(Ext.Panel, {
heightNormalMode : 0,
heightMaximizeDesktopMode : 0,
initComponent : function () {
this.navBarModule = new sitools.user.component.entete.NavBar({
modules : this.modules,
observer : this
});
this.navToolbarButtons = new sitools.user.component.entete.NavBarButtons({
observer : this,
width: '162px' // width without save button
});
this.NavBarsPanel = new Ext.Panel({
border : false,
layout : 'hbox',
height : 35,
flex : 1,
listeners : {
scope : this,
maximizeDesktop : this.onMaximizeDesktopNavbar,
minimizeDesktop : this.onMinimizeDesktopNavbar
},
items : [ this.navBarModule, this.navToolbarButtons ]
});
this.entetePanel = new Ext.Panel({
html : this.htmlContent,
border : false,
layout : "fit",
flex : 1,
listeners : {
scope : this,
desktopReady : this.showUserContainer
}
});
sitools.user.component.entete.Entete.superclass.initComponent.call(Ext.apply(this, {
items : [this.entetePanel, this.NavBarsPanel],
border : false,
layout : "vbox",
layoutConfig : {
align : "stretch"
},
listeners : {
scope : this,
afterRender : function (me) {
var enteteEl = SitoolsDesk.getEnteteEl();
me.setHeight(enteteEl.getHeight());
me.doLayout();
me.heightNormalMode = enteteEl.getHeight();
me.heightMaximizeDesktopMode = this.NavBarsPanel.getHeight();
},
maximizeDesktop : this.onMaximizeDesktop,
minimizeDesktop : this.onMinimizeDesktop,
// navBarRendered : function (navBar) {
// this.entetePanel.fireEvent("navBarRendered", navBar);
// },
windowResize : function (me) {
this.userContainer.hide();
},
desktopReady : function (me) {
this.entetePanel.fireEvent("desktopReady", this.navToolbarButtons);
}
}
}));
},
/**
* listeners of maximizeDesktop event :
*/
onMaximizeDesktop : function () {
this.entetePanel.hide();
this.container.setHeight(this.heightMaximizeDesktopMode);
this.setHeight(this.heightMaximizeDesktopMode);
this.NavBarsPanel.fireEvent("maximizeDesktop");
// this.userContainer.setVisible(! SitoolsDesk.desktopMaximizeMode);
if (this.userContainer) {
this.userContainer.fireEvent("maximizeDesktop", this.userContainer, this.navToolbarButtons);
}
this.doLayout();
},
/**
* listeners of minimizeDesktop event :
*/
onMinimizeDesktop : function () {
this.entetePanel.setVisible(true);
this.container.dom.style.height = "";
this.setHeight(this.heightNormalMode);
this.NavBarsPanel.fireEvent("minimizeDesktop");
// this.userContainer.setVisible(! SitoolsDesk.desktopMaximizeMode);
if (this.userContainer) {
this.userContainer.fireEvent("minimizeDesktop", this.userContainer, this.navToolbarButtons);
}
this.doLayout();
},
showUserContainer : function (navBar) {
var tpl, textToDisplay = i18n.get("label.welcome"), userContainerHeight, userContainerWidth;
if (projectGlobal.user) {
textToDisplay += " " + projectGlobal.user.firstName + " " + projectGlobal.user.lastName;
userContainerHeight = 30;
userContainerWidth = 250;
}
else {
textToDisplay += " " + i18n.get('label.guest') + "<br>" + i18n.get("label.clickToConnect");
userContainerHeight = 50;
userContainerWidth = 250;
}
if (SitoolsDesk.desktopMaximizeMode) {
tpl = new Ext.XTemplate("<div style='left:{width - 60}px;' class='sitools-userContainer-arrow-border-up'></div>",
"<div style='left:{width - 60}px;' class='sitools-userContainer-arrow-up'></div>",
"<div><img class='sitools-userContainer-icon' src='/sitools/cots/extjs/resources/images/default/window/icon-info.gif'>{text}</div>");
}
else {
tpl = new Ext.XTemplate("<div><img class='sitools-userContainer-icon' src='/sitools/cots/extjs/resources/images/default/window/icon-info.gif'>{text}</div>",
"<div style='left:{width - 60}px;' class='sitools-userContainer-arrow-border-down'></div>",
"<div style='left:{width - 60}px;' class='sitools-userContainer-arrow-down'></div>");
}
this.userContainer = new Ext.BoxComponent({
data : {
text : textToDisplay,
height : userContainerHeight,
width : userContainerWidth
},
cls : "sitools-userContainer",
width : userContainerWidth,
height : userContainerHeight,
renderTo : SitoolsDesk.getEnteteEl(),
tpl : tpl,
listeners : {
scope : this,
afterRender : function (me) {
var el = Ext.get(me.id);
el.on("click", function (e, t, o) {
this.getEl().fadeOut({
easing: 'easeOut',
duration: 1,
endOpacity : 0,
useDisplay: false
});
}, me);
},
maximizeDesktop : function (me, navBar) {
// me.setPosition(me.getPosition()[0], this.calcUserContainerYPos(navBar));
if (me.isVisible()) {
me.destroy();
// this.showUserContainer(navBar);
}
},
minimizeDesktop : function (me, navBar) {
if (me.isVisible()) {
me.destroy();
// this.showUserContainer(navBar);
}
}
}
});
var enteteEl = SitoolsDesk.getEnteteEl();
var userContEl = this.userContainer.getEl();
var x, y;
x = Ext.getBody().getWidth() - this.userContainer.getWidth();
y = this.calcUserContainerYPos(navBar);
this.userContainer.setPosition([x, y]);
userContEl.highlight("948B8B", {
attr: 'background-color',
duration: 1
});
userContEl.fadeOut({
easing: 'easeOut',
duration: 1,
endOpacity : 0,
useDisplay: false
});
// this.userContainer.setVisible(! SitoolsDesk.desktopMaximizeMode);
},
/**
* Calculates the y position of the userContainer.
* @param navBar (the navBar component
* @returns {integer} the yPosition
*/
calcUserContainerYPos : function (navBar) {
var enteteEl = SitoolsDesk.getEnteteEl();
var userContEl = this.userContainer.getEl();
var y;
if (SitoolsDesk.desktopMaximizeMode) {
y = navBar.getHeight();
}
else {
y = enteteEl.getHeight() - navBar.getHeight() - this.userContainer.getHeight();
if (!Ext.isEmpty(userContEl.getMargins())) {
y -= userContEl.getMargins().bottom;
y -= userContEl.getMargins().top;
}
}
return y;
},
/**
* Return the Navbar Buttons
*/
getNavbarButtons : function (){
return this.navToolbarButtons;
},
/**
* Return the Navbar Modules
*/
getNavbarModules : function () {
return this.navBarModule;
},
/**
* listeners of maximizeDesktop event
*/
onMaximizeDesktopNavbar : function () {
this.navBarModule.fireEvent("maximizeDesktop");
this.navToolbarButtons.fireEvent("maximizeDesktop");
},
/**
* listeners of minimizeDesktop event
*/
onMinimizeDesktopNavbar : function () {
this.navBarModule.fireEvent("minimizeDesktop");
this.navToolbarButtons.fireEvent("minimizeDesktop");
}
});
Ext.reg('sitools.user.component.entete.Entete', sitools.user.component.entete.Entete);
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, window, showVersion, publicStorage, userLogin, projectGlobal, SitoolsDesk, showResponse, i18n, extColModelToJsonColModel, loadUrl*/
Ext.namespace('sitools.user.component.entete');
/**
* @cfg {Array} modules la liste des modules
* @class sitools.user.component.entete.NavBar
* @extends Ext.Toolbar
*/
sitools.user.component.entete.NavBar = Ext.extend(Ext.Toolbar, {
initComponent : function () {
var items = [];
var categories = this.categorizeModules();
var homeButton = new Ext.Button({
handler : function () {
projectGlobal.getPreferences(function () {
SitoolsDesk.removeActivePanel();
SitoolsDesk.removeAllWindows();
SitoolsDesk.loadPreferences();
});
},
scale : "medium",
icon : "/sitools/common/res/images/icons/button-home.png",
iconCls : 'navBarButtons-icon',
tooltip : {
html : i18n.get("label.homeButton"),
anchor : 'bottom',
trackMouse : false
},
template : new Ext.Template('<table cellspacing="0" class="x-btn {3}" style="padding-left:5px;"><tbody><tr>',
'<td><i> </i></td>',
'<td><em class="{5} unselectable="on">',
'<button type="{1}" style="height:28px; width:28px;">{0}</button>', '</em></td>',
'<td><i> </i></td>', "</tr></tbody></table>")
});
items.push(homeButton);
items.push('|');
Ext.each(categories, function (category) {
var modules = category.modules;
//Le module n'appartient pas à une catégorie: inclusion en tant que bouton dans le menu.
if (Ext.isEmpty(category.category)) {
var module = modules[0];
var xtype = module.xtype;
try {
if (Ext.isEmpty(module.divIdToDisplay)) {
var handler = null;
var item = {
text : i18n.get(module.label),
iconCls : module.icon,
scope : module,
tooltip : {
html : i18n.get(module.description),
anchor : 'bottom',
trackMouse : false
},
cls : "x-navBar-items",
clickEvent : 'mousedown',
template : new Ext.Template('<table cellspacing="0" class="x-btn {3}"><tbody><tr>',
'<td class="ux-taskbutton-left"><i> </i></td>',
'<td class="ux-taskbutton-center"><em class="{5} unselectable="on">',
'<button class="x-btn-text {2}" type="{1}" style="height:28px;">{0}</button>', '</em></td>',
'<td class="ux-taskbutton-right"><i> </i></td>', "</tr></tbody></table>")
};
var xtype = module.xtype;
var func = xtype + ".openModule";
if (!Ext.isEmpty(xtype) && Ext.isFunction(eval(func))) {
handler = eval(func);
}
else {
handler = module.openModule
}
Ext.apply(item, {
handler : handler
});
items.push(item);
items.push('|');
}
}
catch(err) {
//Nothing to do
var tmp = null;
}
}
//Le module est dans une catégorie : On crée un menu contenant tous les modules de la catégorie
else {
var menuItems = [];
Ext.each(category.modules, function (moduleInCategory) {
try {
if (Ext.isEmpty(moduleInCategory)) {
return;
}
if (Ext.isEmpty(moduleInCategory.divIdToDisplay)) {
var item = {
text : i18n.get(moduleInCategory.label),
iconCls : moduleInCategory.icon,
scope : this
};
//Test spécifique pour savoir si on doit inclure un sous menu :
var xtype = moduleInCategory.xtype;
if (Ext.isEmpty(xtype)) {
return;
}
var Func = eval(xtype + ".getStaticParameters");
if (Ext.isFunction(Func)) {
var staticParameters = Func();
if (staticParameters && staticParameters.showAsMenu) {
Ext.apply(item, {
menu : {
xtype : moduleInCategory.xtype,
cls : "sitools-navbar-menu"
}
});
}
else {
Ext.apply(item, {
handler : moduleInCategory.openModule
});
}
}
func = xtype + ".openModule";
if (Ext.isFunction(eval(func))) {
handler = eval(func);
}
else {
handler = moduleInCategory.openModule
}
Ext.apply(item, {
handler : handler
});
menuItems.push(item);
}
}
catch (err) {
//nothing to do
var tmp = null;
}
});
if (!Ext.isEmpty(menuItems)) {
var menu = new Ext.menu.Menu({
items : menuItems,
cls : "sitools-navbar-menu"
});
items.push({
text : category.category,
menu : menu,
icon : "/sitools/common/res/images/icons/white_arrow.gif",
iconAlign : "left",
clickEvent : 'mousedown',
cls : "x-navBar-items",
template : new Ext.Template('<table cellspacing="0" class="x-btn {3}"><tbody><tr>',
'<td class="ux-taskbutton-center"><em class="{2} unselectable="on">',
'<button class="x-btn-text {2}" type="{1}" style="height:28px;">{0}</button>', '</em></td>',
"</tr></tbody></table>")
});
items.push('|');
}
}
});
sitools.user.component.entete.NavBar.superclass.initComponent.call(Ext.apply(this, {
id : "navBarId",
enableOverflow: true,
defaults : {
overCls : "x-navBar-items-over",
ctCls : "x-navBar-items-ct"
},
items : items,
cls : "x-navBar",
overCls : "x-navBar-over",
ctCls : "x-navBar-ct",
flex : 1,
listeners : {
scope : this,
afterRender : function (me) {
this.observer.fireEvent("navBarRendered", me);
}
},
border : false
}));
},
/**
* From the modules attribute, return an array of categories.
* Each items of the array could be either
* - {
* modules : [module]
* }
* - {
* category : categoryName,
* modules : [modules]
* }
* @returns {Array}
*/
categorizeModules : function () {
function getCategoryIndex(category, categoryList) {
var idx = -1;
for (var i = 0; i < categoryList.length; i++) {
if (categoryList[i].category === category) {
return i;
}
}
return idx;
}
var categoryModules = [];
Ext.each(this.modules, function (module) {
if (Ext.isEmpty(module.categoryModule)) {
categoryModules.push({
modules : [module]
});
}
else {
var idx = getCategoryIndex(module.categoryModule, categoryModules);
if (idx >= 0) {
categoryModules[idx].modules.push(module);
}
else {
categoryModules.push({
category : module.categoryModule,
modules : [module]
});
}
}
});
return categoryModules;
}
});
Ext.reg('sitools.user.component.entete.NavBar', sitools.user.component.entete.NavBar);
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, window, showVersion, publicStorage, userLogin, projectGlobal, SitoolsDesk, showResponse, i18n, extColModelToJsonColModel, loadUrl*/
Ext.namespace('sitools.user.component.entete');
/**
* @cfg {Array} modules la liste des modules
* @class sitools.user.component.entete.NavBarButtons
* @extends Ext.Toolbar
*/
sitools.user.component.entete.NavBarButtons = Ext.extend(Ext.Toolbar, {
/**
* The id of the button to open the profile window
*/
profileButtonId : "profileButtonId",
initComponent : function () {
var itemsButtons = [];
if (!Ext.isEmpty(userLogin)) {
// width with save button
this.width = '204px';
}
/**
* The btn to open profileWindow
*/
this.profilButton = new Ext.Button({
scope : this,
handler : this.showProfil,
iconCls : 'navBarButtons-icon',
cls : 'navBarTransition',
// scale : "medium",
icon : "/sitools/common/res/images/icons/navBarButtons/user-icon.png",
tooltip : {
html : i18n.get('label.profil'),
anchor : 'bottom',
trackMouse : false
},
id : this.profileButtonId
});
itemsButtons.push(this.profilButton);
this.versionButton = new Ext.Button({
iconCls : 'navBarButtons-icon',
// scale : "medium",
id : "versionBtnId",
icon : "/sitools/common/res/images/icons/navBarButtons/version-icon.png",
handler : function () {
showVersion();
},
tooltip : {
html : i18n.get('label.version'),
anchor : 'bottom',
trackMouse : false
}
});
itemsButtons.push(this.versionButton);
if (!Ext.isEmpty(userLogin)) {
this.saveButton = new Ext.Button({
scope : this,
iconCls : 'navBarButtons-icon',
handler : this.saveAction,
// scale : "medium",
icon : "/sitools/common/res/images/icons/navBarButtons/save-icon.png",
tooltip : {
html : i18n.get('label.save'),
anchor : 'bottom',
trackMouse : false
},
id : "saveBtnId"
});
itemsButtons.push(this.saveButton);
}
this.helpButton = new Ext.Button({
iconCls : 'navBarButtons-icon',
// scale : "medium",
scope : this,
icon : "/sitools/common/res/images/icons/navBarButtons/help-icon.png",
handler : SitoolsDesk.showHelp,
tooltip : {
html : i18n.get('label.help'),
anchor : 'bottom',
trackMouse : false
}
});
itemsButtons.push(this.helpButton);
/**A specialized btn to switch between normal and maximize mode */
this.maximizeButton = new Ext.Button({
// scope : this,
iconCls : 'navBarButtons-icon',
handler : function () {
if (SitoolsDesk.desktopMaximizeMode) {
SitoolsDesk.getDesktop().minimize();
}
else {
SitoolsDesk.getDesktop().maximize();
}
},
icon : SitoolsDesk.desktopMaximizeMode ? "/sitools/common/res/images/icons/navBarButtons/mini-icon.png" : "/sitools/common/res/images/icons/navBarButtons/maxi-icon.png",
tooltip : {
id : 'tooltipId',
html : SitoolsDesk.desktopMaximizeMode ? i18n.get('label.maximize') : i18n.get('label.minimize'),
anchor : 'bottom',
trackMouse : false,
listeners : {
show : function (tooltip){
if (SitoolsDesk.desktopMaximizeMode) {
tooltip.update(i18n.get('label.minimize'));
}
else {
tooltip.update(i18n.get('label.maximize'));
}
}
}
}
});
itemsButtons.push(this.maximizeButton);
sitools.user.component.entete.NavBarButtons.superclass.initComponent.call(Ext.apply(this, {
id : 'navBarButtonsId',
enableOverflow: true,
defaults : {
overCls : "x-navBar-items-over",
ctCls : "x-navBar-items-ct"
},
items : itemsButtons,
cls : "x-navBar-buttons",
overCls : "x-navBar-over",
ctCls : "x-navBar-ct",
width : this.width,
listeners : {
scope : this,
maximizeDesktop : this.onMaximizeDesktop,
minimizeDesktop : this.onMinimizeDesktop
},
border : false
}));
},
/**
* listeners of maximizeDesktop event
*/
onMaximizeDesktop : function () {
this.maximizeButton.setIcon("/sitools/common/res/images/icons/navBarButtons/mini-icon.png");
SitoolsDesk.desktopMaximizeMode = true;
this.maximizeButton.tooltip.html = i18n.get('label.minimize');
},
/**
* listeners of minimizeDesktop event
*/
onMinimizeDesktop : function () {
this.maximizeButton.setIcon("/sitools/common/res/images/icons/navBarButtons/maxi-icon.png");
SitoolsDesk.desktopMaximizeMode = false;
this.maximizeButton.tooltip.html = i18n.get('label.maximize');
},
/**
* Returns the maximizeBtn
* @returns {Ext.Button}
*/
getMaximizeButton : function () {
return this.maximizeButton;
},
/**
* Handler of profileBtn : Open the sitools.user.component.entete.UserProfile window
* @param {Ext.Button} b The pressed btn
* @param {Ext.event} e the click Event.
* @returns
*/
showProfil : function (b, e) {
var win = new sitools.user.component.entete.UserProfile({
buttonId : this.profileButtonId
});
win.show();
},
/**
* Handler of Save Btn. If admin Role : open a menu, else save desktop.
* @param {Ext.Button} btn The pressed btn
* @param {Ext.event} event the click Event.
* @returns
*/
saveAction : function (btn, event) {
if (!Ext.isEmpty(userLogin) && projectGlobal && projectGlobal.isAdmin) {
var ctxMenu = new Ext.menu.Menu({
items: ['<b class="menu-title">' + i18n.get('label.chooseSaveType') + '</b>', '-',
{
text: i18n.get("label.myself"),
handler : function () {
SitoolsDesk.app.saveWindowSettings();
}
}, {
text: i18n.get("label.publicUser"),
handler : function () {
SitoolsDesk.app.saveWindowSettings(true);
}
}, {
text : i18n.get('label.deletePublicPref'),
handler : function () {
publicStorage.remove();
}
}]
});
ctxMenu.showAt([event.getXY()[0], SitoolsDesk.getEnteteEl().getHeight()]);
}
else {
SitoolsDesk.app.saveWindowSettings();
}
}
});
Ext.reg('sitools.user.component.entete.NavBarButtons', sitools.user.component.entete.NavBarButtons);
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, utils_logout, sitools, SitoolsDesk, window, userLogin, showResponse, projectGlobal,
userStorage, DEFAULT_PREFERENCES_FOLDER, i18n, extColModelToJsonColModel, loadUrl*/
Ext.namespace('sitools.user.component.entete');
/**
* @cfg {String} buttonId the id of the button that displays the window
* @class sitools.user.component.entete.UserProfile
* @extends Ext.Window
*/
sitools.user.component.entete.UserProfile = Ext.extend(Ext.Window, {
initComponent : function () {
this.header = false;
this.user = projectGlobal.user || {
firstName : "public",
identifier : "public",
email : " "
};
this.userPublic = this.user.identifier === "public";
var userLanguage = SitoolsDesk.app.language, userLargeIcon;
Ext.each(projectGlobal.languages, function (language) {
if (userLanguage === language.localName) {
userLargeIcon = language.largeIcon;
}
});
var freeDisk = 0;
var totalDisk = 0;
var userTasksRunning = 0;
var userTotalTasks = 0;
var data = [{
identifier : "language",
name: i18n.get("label.langues"),
url : userLargeIcon,
action : "changeLanguage"
}];
this.height = this.user.identifier === "public" ? 140 : 220;
this.width = 400;
if (this.user.identifier !== "public") {
data.push({
identifier : "editProfile",
name: i18n.get("label.editProfile"),
url : '/sitools/common/res/images/icons/menu/regcrud.png',
action : "editProfile",
comment : ""
}, {
identifier : "userDiskSpace",
name: i18n.get('label.userDiskSpace'),
url : '/sitools/common/res/images/icons/menu/dataAccess.png',
action : "showDisk",
comment : String.format(i18n.get("label.userDiskUse"), freeDisk, totalDisk)
}, {
identifier : "tasks",
name: i18n.get("label.Tasks"),
url : "/sitools/common/res/images/icons/menu/applications2.png",
action : "showTasks",
comment : String.format(i18n.get("label.taskRunning"), userTasksRunning, userTotalTasks)
});
}
var store = new Ext.data.JsonStore({
fields : ['name', 'url', 'action', 'comment', 'identifier'],
data : data
});
var tpl = new Ext.XTemplate('<tpl for=".">',
'<div class="userButtons" id="{identifier}">',
'<div class="userButtons-thumb"><img src="{url}" title="{name}"></div>',
'<span class="userButtons-name">{name}</span>',
'<span class="userButtons-comment">{comment}</span></div>',
'</tpl>',
'<div class="x-clear"></div>'
);
var buttonsDataView = new Ext.DataView({
store: store,
cls : "userButtonsDataview",
tpl: tpl,
autoHeight : true,
width : this.userPublic ? 100 : 400,
multiSelect: true,
overClass: 'x-view-over',
emptyText: 'No images to display',
itemSelector: 'div.userButtons',
listeners : {
scope : this,
click : this.actionItemClick,
afterRender : function () {
this.fillDiskInformations();
this.fillTaskInformations();
}
}
});
var userInfoStore = new Ext.data.JsonStore({
fields : ['firstName', 'lastName', 'image', 'email', 'identifier'],
data : [Ext.apply(this.user, {
"image" : "/sitools/common/res/images/icons/menu/usersGroups.png"
})]
});
var logout = new Ext.Button({
scope : this,
text : i18n.get('label.logout'),
handler : function () {
utils_logout();
}
});
var login = new Ext.Button({
scope : this,
cls : "userProfileBtn",
text : i18n.get('label.login'),
handler : function () {
var tmp = new sitools.userProfile.Login({
closable : true,
url : loadUrl.get('APP_URL') + '/login',
register : loadUrl.get('APP_URL') + '/inscriptions/user',
reset : loadUrl.get('APP_URL') + '/resetPassword'
}).show();
}
});
var register = new Ext.Button({
scope : this,
cls : "userProfileBtn",
text : i18n.get('label.register'),
handler : function () {
var register = new sitools.widget.Register({
closable : true,
url : "/sitools/inscriptions/user",
login : "/sitools/login"
});
register.show();
}
});
var closeBtn = new Ext.Button({
scope : this,
icon : "/sitools/common/res/images/icons/close-icon.png",
handler : function () {
this.destroy();
},
x : this.width - 30,
y : this.height * -1 + 1,
style : {
"position" : "relative",
"height" : 16,
"width" : 16,
"z-index" : 200
}
});
var displayInfo = new Ext.DataView({
flex : 1,
logoutBtn : logout,
loginBtn : login,
closeBtn : closeBtn,
registerBtn : register,
cls : "x-panel-body",
tpl : new Ext.XTemplate('<tpl for=".">',
'<div class="userProfileItem" id="{identifier}">',
'<div class="userProfile userProfileItem-thumb"><img style="height:60px;" src="{image}" title="{name}"></div>',
'<div class="userProfile"><span class="userProfileName">{firstName} {lastName}</span>',
'<span class="userProfileEmail">{email}</span>',
'<div id="logBtn"></div>',
'</div>',
'</tpl>',
'<div class="x-clear"></div>'
),
store : userInfoStore,
listeners : {
scope : this,
afterRender : function (me) {
if (this.user.identifier !== "public") {
me.logoutBtn.render("logBtn");
}
else {
me.loginBtn.render("logBtn");
me.registerBtn.render("logBtn");
}
me.closeBtn.render(this.id);
}
}
});
sitools.user.component.entete.UserProfile.superclass.initComponent.call(Ext.apply(this, {
id : "userProfileWindow",
header : false,
stateful : false,
shadow : false,
layout : this.user.identifier === "public" ? 'hbox' : 'vbox',
layoutConfig : {
align : "stretch"
},
border : false,
hideBorders : true,
closable : false,
x : Ext.getBody().getWidth() - 400,
y : SitoolsDesk.getEnteteEl().getHeight(),
resizable : false,
bodyBorder : false,
listeners : {
scope : this,
beforeRender : function () {
Ext.getBody().on("click", this.interceptOnClick, this);
},
beforeDestroy : function (me) {
Ext.getBody().un("click", this.interceptOnClick, this);
Ext.getCmp(this.buttonId).enable();
}
},
items : [displayInfo, {
xtype : "panel",
items : [buttonsDataView]
}]
}));
},
/**
* while this window is active, checked if any click is done on this window, or somewhere Else.
*
* @param {Ext.event} evt the clic Event.
* @param {HtmlElement} target the Html target element.
* @returns
*/
interceptOnClick : function (evt, target) {
//le click est sur le bouton pour ouvrir la fenêtre : Désactiver le bouton... et fin de l'action.
if (Ext.DomQuery.select("table[id=" + this.buttonId + "] button[id=" + target.id + "]").length === 1) {
Ext.getCmp(this.buttonId).disable();
return;
}
//Le clic est sur un élément de la fenêtre : rien à faire.
if (this.isDescendant(Ext.DomQuery.select("div[id=userProfileWindow]")[0], target)) {
if (evt.shiftKey && evt.ctrlKey) {
breakout().getBackToDesktop();
}
return;
}
//Le clic est quelque part en dehors de la fenêtre, on détruit la fenêtre (-> beforeDestroy est exécuté)
this.destroy();
},
/**
* Handler of any click on the dataview used to display actions btn :
* Execute the method specified in each store.action attribute.
*
* @param {Ext.DataView} dataView the clicked Dataview
* @param {numeric} index the index of the clicked node
* @param {Html Element} node the clicked html element
* @param {Ext.event} e The click event
* @returns
*/
actionItemClick : function (dataView, index, node, e) {
try {
var data = dataView.getSelectedRecords()[0].data;
eval("this." + data.action).call(this, dataView, index, node, e);
}
catch (err) {
return;
}
},
isDescendant : function (parent, child) {
var node = child.parentNode;
while (node !== null) {
if (node === parent) {
return true;
}
node = node.parentNode;
}
return false;
},
/**
* Open a Ext.Menu.menu containing all projectGlobal.languages options.
* @param {Ext.DataView} dataView the clicked Dataview
* @param {numeric} index the index of the clicked node
* @param {Html Element} node the clicked html element
* @param {Ext.event} e The click event
*/
changeLanguage : function (dataView, index, node, e) {
var menuLangues = new Ext.menu.Menu({
plain : true
});
Ext.each(projectGlobal.languages, function (language) {
menuLangues.add({
text : language.displayName,
scope : this,
handler : function () {
var callback = function () {
Ext.util.Cookies.set('language', language.localName);
window.location.reload();
};
var date = new Date();
Ext.util.Cookies.set('language', language.localName, date.add(Date.MINUTE, 20));
var userPreferences = {};
userPreferences.language = language.localName;
if (!Ext.isEmpty(userLogin)) {
userStorage.set(loadUrl.get('APP_PORTAL_URL'), "/" + DEFAULT_PREFERENCES_FOLDER + loadUrl.get('APP_PORTAL_URL'), userPreferences, callback);
} else {
window.location.reload();
}
},
icon : language.image
});
}, this);
menuLangues.showAt([Ext.get(node.id).getLeft(), Ext.get(node.id).getBottom()]);
},
/**
* Open a window in the desktop with the sitools.userProfile.editProfile object.
* @param {Ext.DataView} dataView the clicked Dataview
* @param {numeric} index the index of the clicked node
* @param {Html Element} node the clicked html element
* @param {Ext.event} e The click event
*/
editProfile : function (dataView, index, node, e) {
if (this.user.identifier === "public") {
return;
}
var componentCfg = {
identifier : this.user.identifier,
url: '/sitools/editProfile/' + this.user.identifier,
handler : function (user) {
projectGlobal.user = user;
}
};
var jsObj = sitools.userProfile.editProfile;
var windowConfig = {
title : i18n.get('label.editProfile'),
saveToolbar : false,
iconCls : "editProfile"
};
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, jsObj, true);
this.destroy();
},
/**
* Open a window in the desktop with the sitools.user.component.entete.userProfile.tasks object.
* @param {Ext.DataView} dataView the clicked Dataview
* @param {numeric} index the index of the clicked node
* @param {Html Element} node the clicked html element
* @param {Ext.event} e The click event
*/
showTasks : function () {
var jsObj = sitools.user.component.entete.userProfile.tasks;
var windowConfig = {
title : i18n.get('label.Tasks'),
saveToolbar : false,
iconCls : 'tasks'
};
SitoolsDesk.addDesktopWindow(windowConfig, {}, jsObj, true);
this.destroy();
},
/**
* Open a window in the desktop with the sitools.user.component.entete.userProfile.diskSpace object.
* @param {Ext.DataView} dataView the clicked Dataview
* @param {numeric} index the index of the clicked node
* @param {Html Element} node the clicked html element
* @param {Ext.event} e The click event
*/
showDisk : function () {
var jsObj = sitools.user.component.entete.userProfile.diskSpace;
var windowConfig = {
title : i18n.get('label.userSpace'),
saveToolbar : false,
iconCls : "diskSpace"
};
SitoolsDesk.addDesktopWindow(windowConfig, {}, jsObj, true);
this.destroy();
},
/**
* Send a request on user task resource to determine how many tasks are launched and finished.
* Update the task comment div with the formated result.
*/
fillDiskInformations : function () {
var el = Ext.DomQuery.select("div[id='userDiskSpace'] span[class='userButtons-comment']")[0];
if (Ext.isEmpty(el)) {
return;
}
Ext.Ajax.request({
method : "GET",
url : loadUrl.get('APP_URL') + loadUrl.get('APP_USERSTORAGE_USER_URL').replace("{identifier}", this.user.identifier) + "/status",
success : function (ret) {
var json = Ext.decode(ret.responseText);
if (!json.success) {
return;
}
var storage = json.userstorage.storage;
var totalSpace = storage.quota;
var usedSpace = storage.busyUserSpace;
var pourcentage = usedSpace / totalSpace * 100;
var cls = null;
if (pourcentage >= 90 && pourcentage < 100) {
Ext.get("userDiskSpace").addClass("sitools-userProfile-warning-icon");
cls = "sitools-userProfile-warning-text";
}
else if (pourcentage > 100) {
Ext.get("userDiskSpace").addClass("sitools-userProfile-error-icon");
cls = "sitools-userProfile-error-text";
}
var str = "";
if (!Ext.isEmpty(cls)) {
str += "<span class='" + cls + "'>";
}
str += String.format(i18n.get('label.diskSpace'), Ext.util.Format.round(pourcentage, 0), Ext.util.Format.fileSize(totalSpace));
if (!Ext.isEmpty(cls)) {
str += "</span>";
}
el.update(str);
}
});
},
/**
* Send a request on user userstorage resource to determine the space allowed and consumed.
* Update the diskSpace comment div with the formated result.
*/
fillTaskInformations : function () {
var el = Ext.DomQuery.select("div[id='tasks'] span[class='userButtons-comment']")[0];
if (Ext.isEmpty(el)) {
return;
}
Ext.Ajax.request({
method : "GET",
url : loadUrl.get('APP_URL') + loadUrl.get('APP_USERRESOURCE_ROOT_URL') + "/" + this.user.identifier + "/tasks",
success : function (ret) {
var json = Ext.decode(ret.responseText);
if (!json.success) {
return;
}
var runningTasks = 0, totalTasks = 0;
Ext.each(json.data, function (task) {
if (task.status === "TASK_STATUS_RUNNING" || task.status === "TASK_STATUS_PENDING") {
runningTasks++;
}
totalTasks++;
});
if (runningTasks > 0) {
el.update(String.format(i18n.get('label.taskRunning'), runningTasks));
} else {
el.update("");
}
}
});
}
});/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, showResponse, i18n, extColModelToJsonColModel, loadUrl, projectGlobal, SitoolsDesk */
Ext.namespace('sitools.user.component.bottom');
//sitools.component.users.datasets.columnsDefinition = function (config) {
/**
* Create the desktop footer component with the sitools footer by default or with the template footer of the project (if it's not empty)
*
* @cfg {String} htmlContent html content of the headers,
* @cfg {Array} modules the modules list
* @class sitools.user.component.bottom.Bottom
* @extends Ext.Panel
*/
sitools.user.component.bottom.Bottom = Ext.extend(Ext.Panel, {
heightNormalMode : 0,
heightMaximizeDesktopMode : 0,
forceLayout : true,
layout : "hbox",
border : false,
layoutConfig : {
align : 'stretch',
pack : 'start'
},
bodyCssClass : 'sitools_footer',
initComponent : function () {
this.defaultBottom = Ext.get('x-bottom').dom.children.length === 0 ;
if (this.defaultBottom){
this.renderTo = 'x-bottom';
this.panelLeft = new Ext.Panel({
border : false,
flex : 0.5,
html : "<img id='sitools_logo' src='" + loadUrl.get("APP_URL") + "/res/images/logo_01_petiteTaille.png' alt='sitools_logo'/>",
bodyCssClass : 'no-background',
listeners : {
scope : this,
afterRender : function () {
Ext.get("sitools_logo").on('load', function () {
Ext.get("sitools_logo").alignTo(this.panelLeft.getEl(), "c-c");
}, this);
}
}
});
this.panelMiddle = new Ext.Panel({
border : false,
flex : 1,
bodyCssClass : 'no-background',
items : [{
xtype : "panel",
html : "<span style='color:white'>" + i18n.get("label.build_by_sitools2") + "</span>",
id : 'sitools_build_by',
cls : "sitools_footer_build_by",
bodyCssClass : 'no-background'
}]
});
this.linkStore = new Ext.data.Store({
fields : [ 'name', 'url']
});
var linkDataview = new Ext.DataView({
store : this.linkStore,
tpl : new Ext.XTemplate('<div class="sitools_footer_right" id="sitools_footer_right">',
'<tpl for=".">',
'<a rel="contents" href="#" onclick="sitools.user.component.bottom.Bottom.showFooterLink(\'{url}\',\'{name}\');">',
'{[this.getLabel(values.name)]}',
'</a>',
'<tpl if="(xindex < xcount)">',
' | ',
'</tpl>',
'</tpl>', '</div>',
{
compiled : true,
disableFormats : true,
getLabel : function (labelName) {
return i18n.get(labelName);
}
})
});
this.panelRight = new Ext.Panel({
border : false,
flex : 0.5,
bodyCssClass : 'no-background',
items : [linkDataview]
});
this.items = [this.panelLeft, this.panelMiddle, this.panelRight];
}
else {
var el = Ext.get('x-bottom').createChild({
tag :'div'
});
this.renderTo = el;
}
sitools.user.component.bottom.Bottom.superclass.initComponent.call(Ext.apply(this, {
// html : this.htmlContent,
listeners : {
scope : this,
afterRender : function (me) {
if (!this.defaultBottom){
me.setHeight(0);
}
else {
var bottomEl = SitoolsDesk.getBottomEl();
me.fillLinks();
me.setHeight(bottomEl.getHeight());
me.heightNormalMode = bottomEl.getHeight();
me.doLayout();
Ext.get("sitools_build_by").alignTo(this.panelMiddle.getEl(), "bl-bl");
var fr = Ext.get("sitools_footer_right");
if (Ext.isDefined(fr) && !Ext.isEmpty(fr)){
fr.alignTo(this.panelRight.getEl(), "c-c");
}
}
},
resize : function (me) {
if (!this.defaultBottom){
me.setHeight(0);
}
else {
me.setSize(SitoolsDesk.getBottomEl().getSize());
me.doLayout();
Ext.get("sitools_logo").alignTo(this.panelLeft.getEl(), "c-c");
Ext.get("sitools_build_by").alignTo(this.panelMiddle.getEl(), "bl-bl");
var fr = Ext.get("sitools_footer_right");
if (Ext.isDefined(fr) && !Ext.isEmpty(fr)){
fr.alignTo(this.panelRight.getEl(), "c-c");
}
}
},
maximizeDesktop : this.onMaximizeDesktop,
minimizeDesktop : this.onMinimizeDesktop
}
}));
},
onMaximizeDesktop : function () {
this.container.setHeight(0);
this.hide();
this.doLayout();
},
onMinimizeDesktop : function () {
this.container.dom.style.height = "";
this.setVisible(true);
this.doLayout();
},
fillLinks : function () {
var projectLinks = projectGlobal.links;
Ext.each(projectLinks, function (value) {
this.linkStore.add(new Ext.data.Record(value));
}, this);
}
});
* @static
*/
sitools.user.component.bottom.Bottom.showFooterLink = function (url, linkName) {
var windowConfig = {
title : i18n.get(linkName),
id : linkName,
iconCls : "version"
};
var jsObj = Ext.ux.ManagedIFrame.Panel;
var componentCfg = {
defaults : {
padding : 10
},
layout : 'fit',
region : 'center',
defaultSrc : url
};
SitoolsDesk.addDesktopWindow(
windowConfig, componentCfg,
jsObj);
};
Ext.reg('sitools.user.component.bottom.Bottom', sitools.user.component.bottom.Bottom);
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, MULTIDS_TIME_DELAY, sitools, i18n, commonTreeUtils, projectGlobal, showResponse, document, SitoolsDesk, alertFailure, loadUrl*/
/*
* @include "../../components/forms/forms.js"
*/
Ext.namespace('sitools.user.component.forms');
/**
* Displays The result of a multiDatasets Reasearch.
* @cfg {string} urlTask The url to request
* @cfg {string} formId The form Id
* @cfg {string} formName The form Name
* @cfg {Array} formMultiDsParams an array of formParams (represent concepts selection)
* @cfg {Array} datasets Array of Datasets Ids
* @class sitools.user.component.forms.resultsProjectForm
* @extends Ext.grid.GridPanel
*/
sitools.user.component.forms.resultsProjectForm = Ext.extend(Ext.grid.GridPanel, {
initComponent : function () {
var params = {};
params.datasetsList = this.datasets.join("|");
var i = 0;
if (!Ext.isEmpty(this.formMultiDsParams)) {
Ext.each(this.formMultiDsParams, function (param) {
params["c[" + i + "]"] = param;
i += 1;
}, this);
}
var task = new Ext.util.DelayedTask(function () {
return;
});
var store = new Ext.data.JsonStore({
url : this.urlTask,
baseParams : params,
restful : true,
root : 'TaskModel.properties',
fields : [{
name : "id",
type : "string"
}, {
name : "name",
type : "string"
}, {
name : "description",
type : "string"
}, {
name : "image"
}, {
name : "nbRecord"
}, {
name : "url",
type : "string"
}, {
name : "status",
type : "string"
}, {
name : "errorMessage",
type : "string"
}],
autoLoad : true,
listeners : {
scope : this,
load : function (store, recs, options) {
task.cancel();
if (store.reader.jsonData.TaskModel.status == "TASK_STATUS_RUNNING" ||
store.reader.jsonData.TaskModel.status == "TASK_STATUS_PENDING") {
this.getBottomToolbar().setStatus({
// text: ret.error ? ret.error :
// i18n.get('warning.serverUnreachable'),
text : i18n.get('label.loading'),
iconCls : 'x-status-busy'
});
task.delay(MULTIDS_TIME_DELAY, function () {
store.load();
});
}
else {
Ext.Ajax.request({
scope : this,
url : this.urlTask,
method : "DELETE",
success : function (ret) {
var callerCmp = Ext.getCmp(this.callerId);
callerCmp.fireEvent("multiDsSearchDone");
},
failure : alertFailure
});
if (store.reader.jsonData.TaskModel.status == "TASK_STATUS_FAILURE") {
this.getBottomToolbar().setStatus({
text : store.reader.jsonData.TaskModel.customStatus,
iconCls : 'x-status-error'
});
}
else {
this.getBottomToolbar().setStatus({
text : i18n.get("label.requestDone"),
iconCls : 'x-status-valid'
});
}
}
store.each(function (record) {
var error = record.get("errorMessage");
if (!Ext.isEmpty(error)) {
var index = store.indexOf(record);
var htmlLineEl = this.getView().getRow(index);
var el = Ext.get(htmlLineEl);
var cls = "x-form-invalid-tip";
var ttConfig = {
html : error,
dismissDelay : 0,
target : el,
cls : cls
};
var ttip = new Ext.ToolTip(ttConfig);
}
}, this);
}
}
});
var cm = new Ext.grid.ColumnModel({
columns : [{
width : 25,
dataIndex : 'image',
header : "",
renderer : function (value) {
return ! Ext.isEmpty(value) && ! Ext.isEmpty(value.url) ? String.format("<img src='{0}' width=20 height=20>", value.url) : "";
}
}, {
width : 100,
dataIndex : 'name',
header : i18n.get('label.name')
}, {
width : 100,
dataIndex : 'nbRecord',
header : i18n.get('label.nbRecords')
}, {
width : 150,
dataIndex : 'description',
header : i18n.get('label.description'),
renderer : function (value, metaData, record, rowIndex, colIndex, store) {
metaData.attr = "ext:qtip='" + value + "'";
return value;
}
}, {
xtype: 'actioncolumn',
header : i18n.get('label.showData'),
width: 100,
items: [{
getClass : function (value, meta, rec) {
if (rec.get('status') == "REQUEST_ERROR") {
return "multids-error";
}
},
icon : loadUrl.get('APP_URL') + '/common/res/images/icons/tree_datasets.png', // Use a URL in the icon config
tooltip: i18n.get('label.showData'),
scope : this,
handler: SitoolsDesk.navProfile.multiDataset.showDataset
}]
}, {
xtype: 'actioncolumn',
header : i18n.get('label.showDefinition'),
width: 100,
items: [{
icon : loadUrl.get('APP_URL') + '/common/res/images/icons/tree_dictionary.png',
tooltip: i18n.get('label.showDefinition'),
scope : this,
handler: function (grid, rowIndex, colIndex) {
var rec = grid.getStore().getAt(rowIndex);
if (Ext.isEmpty(rec)) {
return;
}
sitools.user.clickDatasetIcone(rec.get("url"), "defi", {
formMultiDsParams : this.formMultiDsParams
});
}
}]
}]
});
var bbar = new Ext.ux.StatusBar({
text : i18n.get('label.ready'),
iconCls : 'x-status-valid'
});
Ext.apply(this, {
cm : cm,
store : store,
layout : "fit",
bbar : bbar,
listeners : {
scope : this,
viewready : function (grid) {
var callerCmp = Ext.getCmp(this.callerId);
callerCmp.fireEvent("multiDsSeachDone");
}
},
viewConfig : {
forceFit : true,
getRowClass : function (rec) {
if (rec.get('status') == "REQUEST_ERROR") {
return "red-row";
}
if (rec.get('status') == "UNAUTHORIZED") {
return "orange-row";
}
}
}
});
sitools.user.component.forms.resultsProjectForm.superclass.initComponent.call(this);
}
});
Ext.reg('sitools.user.component.forms.resultsProjectForm', sitools.user.component.forms.resultsProjectForm);
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, MULTIDS_TIME_DELAY, sitools, i18n, commonTreeUtils, projectGlobal, showResponse, document, SitoolsDesk, alertFailure, loadUrl*/
/*
* @include "../../components/forms/forms.js"
*/
Ext.namespace('sitools.user.component.forms');
/**
* Displays The result of a multiDatasets Reasearch.
* @cfg {string} urlTask The url to request
* @cfg {string} formId The form Id
* @cfg {string} formName The form Name
* @cfg {Array} formMultiDsParams an array of formParams (represent concepts selection)
* @cfg {Array} datasets Array of Datasets Ids
* @class sitools.user.component.forms.overviewResultsProjectForm
* @extends Ext.Panel
*/
sitools.user.component.forms.overviewResultsProjectForm = Ext.extend(Ext.Panel, {
initComponent : function () {
var results = new sitools.user.component.forms.resultsProjectForm(this);
Ext.apply(results, {
region : "center"
});
var description = i18n.get('label.descriptionMultiDS');
this.southPanel = new Ext.TabPanel({
title : i18n.get('label.results'),
region : "south",
height : 300,
split : true,
autoScroll : false,
collapsible : false,
collapsed : true
});
Ext.apply(this, {
layout : "border",
items : [results, this.southPanel]
});
if (description !== "label.descriptionMultiDS") {
this.items.unshift({
xtype : 'panel',
height : 100,
html : description,
padding : "10px",
region : "north",
collapsible : true,
split : true,
autoScroll : true,
title : i18n.get('label.description')
});
}
sitools.user.component.forms.overviewResultsProjectForm.superclass.initComponent.call(this);
}
});
Ext.reg('sitools.user.component.forms.overviewResultsProjectForm', sitools.user.component.forms.overviewResultsProjectForm);
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, SITOOLS_DATE_FORMAT, SITOOLS_DEFAULT_IHM_DATE_FORMAT, i18n, userLogin, DEFAULT_WIN_HEIGHT, DEFAULT_WIN_WIDTH, getDesktop, projectGlobal, SitoolsDesk, DEFAULT_PREFERENCES_FOLDER, alertFailure*/
/*global loadUrl*/
/*
* @include "formComponentsPanel.js"
* @include "resultsProjectForm.js"
*/
Ext.namespace('sitools.user.component.forms');
/**
* The global Panel. A panel with a formComponentsPanel and the buttons.
* @cfg {string} formId Id of the selected Form
* @cfg {string} formName Name of the selected Form
* @cfg {Array} formParameters Array of all form Parameters
* @cfg {number} formWidth Form Width
* @cfg {number} formHeight Form Height
* @cfg {string} formCss Name of a specific css class to apply to form
* @cfg {Array} properties An array of Properties.
* @cfg {string} urlServicePropertiesSearch The url to request properties
* @cfg {string} urlServiceDatasetSearch the url to request for Multids Search
* @cfg {string} dictionaryName the Name of the dictionary attached to the form
* @class sitools.user.component.forms.projectForm
* @extends Ext.Panel
* @requires sitools.user.component.formComponentsPanel
*/
sitools.user.component.forms.projectForm = Ext.extend(Ext.Panel, {
initComponent : function () {
var config = this;
this.componentType = "formProject";
/**
* The panel that displays all form components as defined by the administrator.
*/
this.componentList = new sitools.user.component.formComponentsPanel({
width : config.formWidth,
height : config.formHeight,
css : config.formCss,
formId : config.formId
});
if (!Ext.isEmpty(config.formParameters)) {
this.componentList.loadParameters(config.formParameters, config.dataUrl, "project");
}
var displayComponentPanel = new Ext.Panel({
title : i18n.get('label.formConcepts'),
region : "center",
flex : 2,
autoScroll : true,
items : [ this.componentList ],
layout : "absolute",
listeners : {
scope : this,
resize : function () {
if (!Ext.isEmpty(this.componentList.getEl())) {
var cmpChildSize = this.componentList.getSize();
var size = this.body.getSize();
var xpos = 0, ypos = 0;
if (size.height > cmpChildSize.height) {
ypos = (size.height - cmpChildSize.height) / 2;
}
if (size.width > cmpChildSize.width) {
xpos = (size.width - cmpChildSize.width) / 2;
}
this.componentList.setPosition(xpos, ypos);
}
}
}
});
/**
* The panel that displays Property search
* Each property adds a formField with the buildPropertyField method
*/
this.propertyPanel = new Ext.form.FormPanel({
title : i18n.get("label.defineProperties"),
padding : 10,
labelWidth : 100,
flex : 2,
autoScroll : true,
defaults : {
labelSeparator : ""
},
buttons : [{
text : i18n.get('label.refreshDatasets'),
scope : this,
handler : this.propertySearch
}]
});
if (!Ext.isEmpty(this.properties)) {
Ext.each(this.properties, function (prop) {
var field = this.buildPropertyField(prop);
this.propertyPanel.add(field);
}, this);
}
var storeDatasets = new Ext.data.JsonStore({
restful : true,
fields : [{
name : "id",
type : "string"
}, {
name : "name",
type : "string"
}, {
name : "visible",
type : "boolean"
}],
url : projectGlobal.sitoolsAttachementForUsers + this.urlServicePropertiesSearch,
root : "collection.dataSets",
listeners : {
load : function (store, recs) {
Ext.each(recs, function (rec) {
rec.set("visible", true);
});
}
},
autoLoad : true
});
var visible = new Ext.grid.CheckColumn({
header : i18n.get('headers.visible'),
dataIndex : 'visible',
width : 55
});
var cmDatasets = new Ext.grid.ColumnModel({
columns : [ {
header : i18n.get('headers.name'),
dataIndex : 'name',
width : 120
}, visible]
});
var smDatasets = new Ext.grid.RowSelectionModel({
singleSelect : true
});
/**
* The dataset list.
* It is updated when user pressed on refresh dataset button.
*/
this.datasetPanel = new Ext.grid.EditorGridPanel({
title : i18n.get('label.defineDatasets'),
store : storeDatasets,
cm : cmDatasets,
sm : smDatasets,
flex : 1,
autoScroll : true,
viewConfig : {
forceFit : true
},
plugins : [visible]
});
var firstPanel = new Ext.Panel({
height : 300,
items : [this.propertyPanel, this.datasetPanel],
layout : "hbox",
collapsedTitle : i18n.get('label.advancedSearch'),
region : "north",
collapsible : true,
collapsed : true,
flex : 2,
layoutConfig : {
align : "stretch"
}
});
/**
* A simple button to launch the main request on each selected dataset.
*/
this.searchButton = new Ext.Button({
text : i18n.get('label.search'),
scope : this,
handler : function (button) {
this.onSearch(button);
}
});
Ext.apply(this, {
height : config.formHeight,
layout : "border",
layoutConfig : {
align : "stretch"
},
items : [ firstPanel, displayComponentPanel ],
buttons : [this.searchButton],
listeners : {
scope : this,
propertyChanged : function () {
var properties = this.propertyPanel.items.items;
var params = {};
var j = 0;
var k = {};
for (var i = 0; i < properties.length; i++) {
var prop = properties[i];
if (!Ext.isEmpty(prop.getAPIValue())) {
params["k[" + j + "]"] = prop.getAPIValue();
j++;
}
}
this.datasetPanel.getStore().load({
params : params
});
},
multiDsSearchDone : function () {
this.searchButton.setDisabled(false);
}
}
});
sitools.user.component.forms.projectForm.superclass.initComponent.call(this);
},
/**
* Build the query for the multiDs search
* @param {Ext.Button} button The button that launch the request (to be disabled)
* @returns
*/
onSearch : function (button) {
button.setDisabled(true);
var containers = this.find("stype", 'sitoolsFormContainer');
var formMultiDsParams = [];
var glue = "";
var i = 0;
var datasets = [];
this.datasetPanel.getStore().each(function (rec) {
if (rec.get("visible")) {
datasets.push(rec.get('id'));
}
});
if (datasets.length <= 0) {
Ext.Msg.alert(i18n.get('label.error'), i18n.get('label.atLeastOneDataset'));
button.setDisabled(false);
return;
}
if (! Ext.isEmpty(this.nbDatasetsMax) && datasets.length > this.nbDatasetsMax) {
Ext.Msg.alert(i18n.get('label.error'), String.format(i18n.get('label.toManyDatasetsAllowed'), this.nbDatasetsMax));
button.setDisabled(false);
return;
}
Ext.each(containers, function (container) {
// var f = form.getForm();
if (Ext.isFunction(container.getParameterValue)) {
var param = container.getParameterValue();
if (!Ext.isEmpty(param)) {
formMultiDsParams.push(this.paramValueToApi(param));
}
}
}, this);
var urlService = projectGlobal.sitoolsAttachementForUsers + this.urlServiceDatasetSearch;
var params = {};
params.datasetsList = datasets.join("|");
i = 0;
if (!Ext.isEmpty(formMultiDsParams)) {
Ext.each(formMultiDsParams, function (param) {
params["c[" + i + "]"] = param;
i += 1;
}, this);
}
//Launch the first POST Request on service:
Ext.Ajax.request({
method : "POST",
params : params,
//Just to be sure that params are passed with the url request
jsonData : {},
scope : this,
url : urlService,
success : function (response) {
try {
var json = Ext.decode(response.responseText);
if (! json.success) {
Ext.Msg.alert(i18n.get('label.error'), json.message);
return;
}
var jsObj = SitoolsDesk.navProfile.multiDataset.getObjectResults();
var componentCfg = {
urlTask : json.TaskModel.statusUrl,
formId : this.formId,
formMultiDsParams : formMultiDsParams,
datasets : datasets,
formName : this.formName,
callerId : this.id
};
var windowConfig = {
id : "windMultiDsResultForm" + this.formId,
title : i18n.get('label.MultiDsResultForm') + " : " + this.formName,
saveToolbar : false,
iconCls : "dataviews"
};
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, jsObj);
}
catch (err) {
Ext.Msg.alert(i18n.get('label.error'), err);
return;
}
},
failure : alertFailure
});
var desktop = getDesktop();
var win = desktop.getWindow("windMultiDsResultForm" + this.formId);
if (win) {
win.close();
}
},
/**
* A method to save all the window settings to be abble to reload it when desktop is reloaded.
* @return {}
*/
_getSettings : function () {
return {
objectName : "projectForm",
formId : this.formId,
formName : this.formName,
formParameters : this.formParameters,
formWidth : this.formWidth,
formHeight : this.formHeight,
formCss : this.formCss,
properties : this.properties,
urlServicePropertiesSearch : this.urlServicePropertiesSearch,
urlServiceDatasetSearch : this.urlServiceDatasetSearch,
componentType : this.componentType,
dictionaryName : this.dictionaryName,
preferencesPath : this.preferencesPath,
preferencesFileName : this.preferencesFileName
};
},
/**
* Build a string using a form param Value.
* @param {} paramValue An object with attributes : at least type, code, value and optionnal userDimension, userUnit
* @return {string} something like "TEXTFIELD|ColumnAlias|value"
*/
paramValueToApi : function (paramValue) {
var stringParam = paramValue.type + "|" + this.dictionaryName + "," + paramValue.code + "|" + paramValue.value;
if (!Ext.isEmpty(paramValue.userDimension) && !Ext.isEmpty(paramValue.userUnit)) {
stringParam += "|" + paramValue.userDimension + "|" + paramValue.userUnit.unitName;
}
return stringParam;
},
/**
* Returns the search Button.
* @return {}
*/
getSearchButton : function () {
return this.searchButton;
},
/**
* Build for a properties a new formField depending on property type.
* The property type could be one of :
* - TEXTFIELD,
* - NUMERIC_FIELD,
* - NUMERIC_BETWEEN,
* - DATE_BETWEEN
* @param {} prop the Json definition of a property.
* @return {Ext.form.Field} a simple or composite field.
*/
buildPropertyField : function (prop) {
var field;
switch (prop.type) {
case "TEXTFIELD" :
field = {
xtype : "textfield",
name : prop.name,
anchor : '98%',
enableKeyEvents : true,
fieldLabel : prop.name,
getAPIValue : function () {
if (Ext.isEmpty(this.getValue())) {
return null;
}
return String.format("{0}|{1}|{2}", prop.type, prop.name, this.getValue());
}
};
break;
case "NUMBER_FIELD" :
field = {
xtype : "numberfield",
name : prop.name,
anchor : '98%',
enableKeyEvents : true,
fieldLabel : prop.name,
getAPIValue : function () {
if (Ext.isEmpty(this.getValue())) {
return null;
}
return String.format("{0}|{1}|{2}", prop.type, prop.name, this.getValue());
}
};
break;
case "NUMERIC_BETWEEN" :
field = {
xtype: 'compositefield',
defaults: {
flex: 1
},
msgTarget: 'under',
anchor : '98%',
items: [
{
xtype: 'numberfield',
name : prop.name + "deb",
enableKeyEvents : true
},
{
xtype: 'numberfield',
name : prop.name + "fin"
}
],
fieldLabel : prop.name,
getAPIValue : function () {
var deb = this.items.itemAt(0).getValue();
var fin = this.items.itemAt(1).getValue();
if (Ext.isEmpty(deb) || Ext.isEmpty(fin)) {
return null;
}
return String.format("{0}|{1}|{2}|{3}", prop.type, prop.name, deb, fin);
}
};
break;
case "DATE_BETWEEN" :
field = {
xtype: 'compositefield',
defaults: {
flex: 1
},
msgTarget: 'under',
anchor : '98%',
items: [
{
xtype: 'datefield',
name : prop.name + "deb",
enableKeyEvents : true,
format : SITOOLS_DEFAULT_IHM_DATE_FORMAT,
showTime : true
},
{
xtype: 'datefield',
name : prop.name + "fin",
format : SITOOLS_DEFAULT_IHM_DATE_FORMAT,
showTime : true
}
],
fieldLabel : prop.name,
getAPIValue : function () {
var deb, fin;
try {
deb = this.items.itemAt(0).getValue().format(SITOOLS_DATE_FORMAT);
fin = this.items.itemAt(1).getValue().format(SITOOLS_DATE_FORMAT);
}
catch (err) {
return null;
}
if (Ext.isEmpty(deb) || Ext.isEmpty(fin)) {
return null;
}
return String.format("{0}|{1}|{2}|{3}", prop.type, prop.name, deb, fin);
}
};
break;
}
return field;
},
/**
* Method called when user pressed on refresh Datasets button.
* Course properties and creates the parameters of the query to search the list of datasets
*/
propertySearch : function () {
var properties = this.propertyPanel.items.items;
var params = {};
var j = 0;
var k = {};
for (var i = 0; i < properties.length; i++) {
var prop = properties[i];
if (!Ext.isEmpty(prop.getAPIValue())) {
params["k[" + j + "]"] = prop.getAPIValue();
j++;
}
}
this.datasetPanel.getStore().load({
params : params
});
this.datasetPanel.getView().refresh();
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n, userLogin, DEFAULT_WIN_HEIGHT, DEFAULT_WIN_WIDTH, getDesktop, projectGlobal, SitoolsDesk, DEFAULT_PREFERENCES_FOLDER*/
/*global loadUrl*/
/*
* @include "../../../../client-public/js/forms/formParameterToComponent.js"
*/
Ext.namespace('sitools.user.component');
/**
* The container (absolute Layout) that contains all the containers with each parameter
* @cfg {number} width The width Form
* @cfg {number} height the Height Form
* @cfg {string} css A specific Css Class
* @cfg {string} formId the Form Id
* @cfg {Ext.grid.ColumnModel} datasetCm The dataset ColumnModel
* @class sitools.user.component.formComponentsPanel
* @extends Ext.Panel
*/
sitools.user.component.formComponentsPanel = Ext.extend(Ext.Panel, {
//sitools.component.users.datasets.formsContainer = Ext.extend(Ext.Panel, {
initComponent : function () {
// this.indexes = new Array();
// this.loadParameters (this.formParameters,
// this.formParameters[0].code);
Ext.apply(this, {
// title: this.formName,
id : "panelResultForm" + this.formId,
bodyCssClass : this.css,
height : this.height,
width : this.width,
border : false,
bodyBorder : false,
layout : "absolute",
labelWidth : 100,
// autoHeight :true,
// width:600,
padding : 10,
items : [],
/** The parameters retrieved from server. * */
parameters : []
});
this.addEvents(
/**
* @event added
* Fires when a parameter changes the value
* @param formContainer : this
* @param componentChanged : the component that triggered the event
*/
'componentChanged'
);
this.on('componentChanged', function (formContainer, componentChanged) {
//look for all the childrens of the component
var childrens = formContainer.find("parentParam", componentChanged.parameterId);
//For each children, add a query string on the componentChanged value and reset children Value.
//Also, fire the event ComponentChanged for the children to cascade changes.
Ext.each(childrens, function (children) {
if (children.valueSelection == 'D') {
var store = children.find("stype", "sitoolsFormItem")[0].store;
var baseParams = store.baseParams;
if (!Ext.isEmpty(componentChanged.getSelectedValue())) {
var filter = componentChanged.getParameterValue();
baseParams["p[0]"] = this.paramToAPI(filter);
}
else {
baseParams["p[0]"] = null;
}
store.baseParams = baseParams;
children.setSelectedValue(null);
store.reload({
callback : function () {
formContainer.fireEvent('componentChanged', formContainer, children);
}
});
}
}, this);
});
this.listeners = {
scope : this,
afterrender : function () {
try {
var cmpChildSize = this.getSize();
var size = this.ownerCt.ownerCt.body.getSize();
var xpos = 0, ypos = 0;
if (size.height > cmpChildSize.height) {
ypos = (size.height - cmpChildSize.height) / 2;
}
if (size.width > cmpChildSize.width) {
xpos = (size.width - cmpChildSize.width) / 2;
}
this.setPosition(xpos, ypos);
}
catch (err) {
return;
}
}
};
sitools.user.component.formComponentsPanel.superclass.initComponent.apply(this, arguments);
},
/**
* Construct a container for each parameter
* @param {Array} parameters array of parameters
* @param {string} dataUrl the Url to request the data
* @param {string} context the context should be "dataset" or "project"
*/
loadParameters : function (parameters, dataUrl, context) {
Ext.each(parameters, function (parameter) {
var y = Ext.isEmpty(parameter.ypos) ? y + 50 : parameter.ypos;
var x = Ext.isEmpty(parameter.xpos) ? x : parameter.xpos;
var containerItems = [ sitools.common.forms.formParameterToComponent(parameter, dataUrl, this.formId, this.datasetCm, context).component];
var container = new Ext.Container({
width : parameter.width,
height : parameter.height,
x : x,
y : y,
bodyCssClass : "noborder",
cls : parameter.css,
items : containerItems
});
this.add(container);
}, this);
},
paramToAPI : function (paramValue) {
var stringParam = paramValue.type + "|" + paramValue.code + "|" + paramValue.value;
if (!Ext.isEmpty(paramValue.userDimension) && !Ext.isEmpty(paramValue.userUnit)) {
stringParam += "|" + paramValue.userDimension + "|" + paramValue.userUnit.unitName;
}
return stringParam;
}
});
Ext.reg('sitools.user.component.formComponentsPanel', sitools.user.component.formComponentsPanel);
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n, userLogin, DEFAULT_WIN_HEIGHT, DEFAULT_WIN_WIDTH, getDesktop, projectGlobal, SitoolsDesk, DEFAULT_PREFERENCES_FOLDER*/
/*global loadUrl*/
/*
* @include "formComponentsPanel.js"
*/
Ext.namespace('sitools.user.component.forms');
/**
* The global Panel. A panel with a formComponentsPanel and the buttons.
* @cfg {string} dataUrl Attachement Url of the dataset
* @cfg {string} datasetId datasetId
* @cfg {string} datasetName Dataset Name
* @cfg {Ext.grid.ColumnModel} datasetCm Column model of the dataset
* @cfg {string} formId Form Id
* @cfg {string} formName Form Name
* @cfg {Array} formParameters Array of form parameters
* @cfg {number} formWidth Form Width
* @cfg {number} formHeight Form Height
* @cfg {string} formCss Name of a specific css class to apply to form
* @cfg {string} datasetView Name of the datasetView Object
* @cfg {Array} dictionaryMappings the Mapping between dataset column Model and concepts
* @class sitools.user.component.forms.mainContainer
* @extends Ext.Panel
* @requires sitools.user.component.formComponentsPanel
*/
sitools.user.component.forms.mainContainer = function (config) {
//sitools.component.users.datasets.forms = function (config) {
// console.dir (config.node);
Ext.apply(this, config);
this.componentType = "form";
this.componentList = new sitools.user.component.formComponentsPanel({
width : config.formWidth,
height : config.formHeight,
css : config.formCss,
formId : config.formId
});
if (Ext.isEmpty(config.dataset)) {
Ext.Ajax.request({
url : config.dataUrl,
method : "GET",
scope : this,
success : function (ret) {
if (showResponse(ret)) {
var json = Ext.decode(ret.responseText);
this.componentList.datasetCm = json.dataset.columnModel;
this.componentList.loadParameters(config.formParameters, config.dataUrl, "dataset");
this.datasetId = json.dataset.id;
this.datasetName = json.dataset.name;
this.datasetCm = json.dataset.columnModel;
this.datasetView = json.dataset.datasetView;
this.dictionaryMappings = json.dataset.dictionaryMappings;
}
}
});
}
else {
this.componentList.datasetCm = config.dataset.columnModel;
this.componentList.loadParameters(config.formParameters, config.dataUrl, "dataset");
this.datasetId = config.dataset.id;
this.datasetName = config.dataset.name;
this.datasetCm = config.dataset.columnModel;
this.datasetView = config.dataset.datasetView;
this.dictionaryMappings = config.dataset.dictionaryMappings;
}
sitools.user.component.forms.mainContainer.superclass.constructor.call(this, Ext.apply({
height : config.formHeight,
width : config.formWidth,
autoScroll : true,
bodyBorder : false,
border : false,
items : [ this.componentList ],
layout : "absolute",
buttons : [ {
text : i18n.get('label.search'),
scope : this,
handler : function () {
this.onSearch(config);
}
} ],
listeners : {
scope : this,
resize : function () {
if (!Ext.isEmpty(this.componentList.getEl())) {
var cmpChildSize = this.componentList.getSize();
var size = this.body.getSize();
var xpos = 0, ypos = 0;
if (size.height > cmpChildSize.height) {
ypos = (size.height - cmpChildSize.height) / 2;
}
if (size.width > cmpChildSize.width) {
xpos = (size.width - cmpChildSize.width) / 2;
}
this.componentList.setPosition(xpos, ypos);
}
}
}
}));
};
Ext.extend(sitools.user.component.forms.mainContainer, Ext.Panel, {
onSearch : function (config) {
//Execute a request to get the dataset config
Ext.Ajax.request({
url : config.dataUrl,
method : "GET",
scope : this,
success : function (ret) {
var Json = Ext.decode(ret.responseText);
if (!Json.success) {
Ext.Msg.alert(i18n.get('label.warning'), Json.message);
return;
} else {
var dataset = Json.dataset;
this.doSearch(config, dataset);
}
},
failure : alertFailure
});
},
/**
* Build the query for the liveGrid and build the livegrid component
* @param config
* @returns
*/
doSearch : function (config, dataset) {
var containers = this.find("stype", 'sitoolsFormContainer');
var formParams = [];
var glue = "";
var i = 0;
Ext.each(containers, function (container) {
// var f = form.getForm();
if (Ext.isFunction(container.getParameterValue)) {
var param = container.getParameterValue();
if (!Ext.isEmpty(param)) {
formParams.push(this.paramValueToApi(param));
}
}
}, this);
var desktop = getDesktop();
var win = desktop.getWindow("windResultForm" + config.formId);
if (win) {
win.close();
}
if (Ext.isFunction(this.searchAction)) {
this.searchAction(formParams, dataset, this.scope);
}
else {
this.defaultSearchAction(formParams, dataset);
}
},
defaultSearchAction : function (formParams, dataset) {
var jsObj = eval(dataset.datasetView.jsObject);
var componentCfg = {
dataUrl : dataset.sitoolsAttachementForUsers,
datasetId : dataset.id,
datasetCm : dataset.columnModel,
datasetName : dataset.name,
formParams : formParams,
dictionaryMappings : dataset.dictionaryMappings,
datasetViewConfig : dataset.datasetViewConfig,
preferencesPath : "/" + dataset.name,
preferencesFileName : "datasetView"
};
var windowConfig = {
// id : "windResultForm" + config.formId,
title : i18n.get('label.dataTitle') + " : " + dataset.name,
datasetName : dataset.name,
type : "data",
saveToolbar : true,
iconCls : "dataviews"
};
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, jsObj);
},
_getSettings : function () {
return {
objectName : "forms",
dataUrl : this.dataUrl,
dataset : this.dataset,
formId : this.formId,
formName : this.formName,
formParameters : this.formParameters,
formWidth : this.formWidth,
formHeight : this.formHeight,
formCss : this.formCss,
datasetView : this.datasetView,
dictionaryMappings : this.dictionaryMappings,
preferencesPath : this.preferencesPath,
preferencesFileName : this.preferencesFileName
};
},
/**
* Build a string using a form param Value.
* @param {} paramValue An object with attributes : at least type, code, value and optionnal userDimension, userUnit
* @return {string} something like "TEXTFIELD|ColumnAlias|value"
*/
paramValueToApi : function (paramValue) {
var stringParam = paramValue.type + "|" + paramValue.code + "|" + paramValue.value;
if (!Ext.isEmpty(paramValue.userDimension) && !Ext.isEmpty(paramValue.userUnit)) {
stringParam += "|" + paramValue.userDimension + "|" + paramValue.userUnit.unitName;
}
return stringParam;
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, i18n, sitools, formPanel, result, window, SitoolsDesk, loadUrl*/
/*
* @include "openSearchResultFeed.js"
*/
Ext.namespace('sitools.user.component');
//sitools.component.users.datasets.datasetOpensearch = function (config) {
/**
* A Panel to display OpenSearch queries and result.
*
* @cfg {string} datasetId DatasetId
* @cfg {string} datasetUrl the attachementUrl of the dataset
* @cfg {string} datasetName the dataset Name.
* @class sitools.user.component.datasetOpensearch
* @extends Ext.Panel
* @requires sitools.user.component.openSearchResultFeed
*/
sitools.user.component.datasetOpensearch = function (config) {
Ext.apply(this, config);
// set the uri for the opensearch engine
// exemple de requete avec pagination
// http://localhost:8182/sitools/solr/db?q=fu*&start=10&rows=20
var uri = config.dataUrl + "/opensearch/search";
var uriSuggest = config.dataUrl + "/opensearch/suggest";
/**
* click handler for the search button gets the search query and update the
* RSS feed URI to display the results
*/
function _clickOnSearch() {
// create the opensearch url
var searchQuery = formPanel.getForm().getValues().searchQuery;
result.updateStore(uri + "?q=" + searchQuery);
}
var search;
var ds = new Ext.data.JsonStore({
url : uriSuggest,
restful : true,
root : 'data',
fields : [ {
name : 'field',
type : 'string'
}, {
name : 'name',
type : 'string'
}, {
name : 'nb',
type : 'string'
} ]
});
// Custom rendering Template
var resultTpl = new Ext.XTemplate('<tpl for="."><div class="search-item">', '<h3>{name}<span> ({field} / {nb} results ) </span></h3>', '</div></tpl>');
search = new Ext.form.ComboBox({
store : ds,
displayField : 'name',
typeAhead : false,
loadingText : i18n.get("label.searching"),
hideTrigger : true,
name : 'searchQuery',
anchor : "90%",
tpl : resultTpl,
itemSelector : 'div.search-item',
minChars : 2,
queryParam : 'q',
enableKeyEvents : true,
scope : this,
listeners : {
scope : this,
beforequery : function (queryEvent) {
if (queryEvent.query.indexOf(" ") == -1) {
return true;
} else {
return false;
}
},
specialkey : function (field, e) {
if (e.getKey() == e.ENTER) {
_clickOnSearch();
}
},
beforeselect : function (self, record, index) {
var tabName = record.data.name.split(':');
if (tabName.length > 1) {
record.data.name = tabName[1];
}
record.data.name = record.data.field + ":" + record.data.name;
return true;
}
}
});
var link = new Ext.Button({
icon : loadUrl.get('APP_URL') + '/common/res/images/icons/help.png',
scope : this,
handler : function () {
var helpModule = SitoolsDesk.app.findModule("helpWindow");
if (!Ext.isEmpty(helpModule.getWindow())) {
helpModule.getWindow().close();
}
helpModule.openModule({
activeNode : "Recherche_OpenSearch"
});
},
width : 20
});
var field = new Ext.form.CompositeField({
fieldLabel : i18n.get("label.search"),
anchor : '100%',
defaults : {
flex : 1
},
items : [ search, link ]
});
// set the items of the form
var items = field;
// set the search button
var buttonForm = [ {
text : i18n.get("label.search"),
scope : this,
handler : _clickOnSearch
} ];
// set the search form
var formPanel = new Ext.FormPanel({
labelWidth : 75, // label settings here cascade unless overridden
height : 75,
frame : true,
defaultType : 'textfield',
items : items,
buttons : buttonForm
});
// instanciate the RSS feed component
var result = new sitools.user.component.openSearchResultFeed({
input : search,
dataUrl : config.dataUrl,
pagging : true,
datasetName : config.datasetName,
datasetId : config.datasetId,
exceptionHttpHandler : function (proxy, type, action, options, response, args) {
// si on a un cookie de session et une erreur 403
if ((response.status == 403) && !Ext.isEmpty(Ext.util.Cookies.get('hashCode'))) {
Ext.MessageBox.minWidth = 360;
Ext.MessageBox.alert(i18n.get('label.session.expired'), response.responseText);
return false;
}
return true;
}
});
// instanciate the panel component
sitools.user.component.datasetOpensearch.superclass.constructor.call(this, Ext.apply({
items : [ formPanel, result ],
layout : 'vbox',
datasetName : config.datasetName,
layoutConfig : {
align : 'stretch',
pack : 'start'
}
}, config));
};
Ext.extend(sitools.user.component.datasetOpensearch, Ext.Panel, {
componentType : "openSearch",
_getSettings : function () {
return {
objectName : "datasetOpenSearch",
datasetName : this.datasetName,
preferencesPath : this.preferencesPath,
preferencesFileName : this.preferencesFileName
};
}
});
Ext.reg('sitools.user.component.datasetOpensearch', sitools.user.component.datasetOpensearch);
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n, window, userLogin, projectGlobal, SitoolsDesk, DEFAULT_PREFERENCES_FOLDER, loadUrl, onRequestFeedException*/
/*
* @include "../viewDataDetail/simpleViewDataDetails.js"
* @include "../viewDataDetail/viewDataDetail.js"
*/
Ext.namespace('sitools.user.component');
/**
* Component used to display opensearch results param : url : the url of the RSS
* feed
*
* @cfg {string} urlFeed the url of the feed
* @cfg {string} input The input value to set
* @cfg {boolean} autoLoad If the store needs to be loaded on start
* @cfg {string} dataUrl the url of the dataset
* @cfg {boolean} pagging true to activate the pagging, false otherwise
* @cfg {} dsInfo informations about the dataset
* @cfg {} exceptionHttpHandler the handler for httpProxy errors
* @requires sitools.user.component.simpleViewDataDetail
* @requires sitools.user.component.viewDataDetail
* @class sitools.user.component.openSearchResultFeed
* @extends Ext.grid.GridPanel
*/
sitools.user.component.openSearchResultFeed = function (config) {
//sitools.component.users.datasets.openSearchResultFeed = function (config) {
this.pageSize = 10;
var urlParam = config.urlFeed;
this.input = config.input;
this.uriRecords = config.dataUrl + "/records";
var pagging = config.pagging;
var url = (urlParam === undefined) ? "/tmp" : urlParam;
var exceptionHttpHandler = (Ext.isEmpty(config.exceptionHttpHandler)) ? onRequestFeedException : config.exceptionHttpHandler;
this.httpProxy = new Ext.data.HttpProxy({
url : url,
restful : true,
listeners : {
scope : this,
exception : exceptionHttpHandler
}
});
this.xmlReader = new sitools.component.users.datasets.XmlReader({
record : 'item',
totalProperty : 'opensearch:totalResults'
}, [ 'title', 'link', 'guid', 'pubDate', 'description' ]);
this.store = new Ext.data.Store({
proxy : this.httpProxy,
reader : this.xmlReader,
autoLoad : config.autoLoad,
paramNames : {
start : 'start',
limit : 'rows'
},
listeners : {
scope : this,
load : function (self, records, index) {
if (!pagging && !Ext.isEmpty(this.displayNbResults)) {
this.displayNbResults.setText('Total number of results : ' + this.store.getTotalCount());
// this.getBottomToolbar().doLayout();
}
return true;
},
exception : function (proxy, type, action, options, response, arg) {
var data = Ext.decode(response.responseText);
if (!data.success) {
this.input.markInvalid(i18n.get(data.message));
this.store.removeAll();
}
return true;
}
}
});
this.store.setDefaultSort('pubDate', "DESC");
// if (config.autoLoad !== null && config.autoLoad !== undefined &&
// config.autoLoad) {
// this.store.load();
// }
var columns = [ {
id : 'title',
header : "Title",
dataIndex : 'title',
sortable : true,
renderer : this.formatTitle
}, {
id : 'last',
header : "Date",
dataIndex : 'pubDate',
renderer: this.formatDate,
sortable : true
} ];
if (pagging) {
this.bbar = {
xtype : 'paging',
pageSize : this.pageSize,
store : this.store,
displayInfo : true,
displayMsg : i18n.get('paging.display'),
emptyMsg : i18n.get('paging.empty'),
totalProperty : 'totalCount'
};
} else {
this.displayNbResults = new Ext.form.Label({
text : 'Total number of results : '
});
this.bbar = {
items : [ '->', this.displayNbResults
]
};
}
function clickOnRow(self, rowIndex, e) {
e.stopEvent();
var rec = self.store.getAt(rowIndex);
var guid = rec.get("guid");
if (Ext.isEmpty(guid)) {
Ext.Msg.alert(i18n.get('label.warning'), i18n.get('warning.noGuidFieldDefined') + "<br/>" + i18n.get('warning.noPrimaryKeyDefinedOSNotice'));
return;
}
// si on est pas sur le bureau
if (Ext.isEmpty(window) || Ext.isEmpty(window.SitoolsDesk)) {
var component = new sitools.user.component.simpleViewDataDetail({
fromWhere : "openSearch",
urlDataDetail : guid
});
var win = new Ext.Window({
stateful : false,
title : i18n.get('label.viewDataDetail'),
width : 400,
height : 600,
shim : false,
animCollapse : false,
constrainHeader : true,
layout : 'fit'
});
win.add(component);
win.show();
} else {
var componentCfg = {
grid : this,
fromWhere : "openSearch",
datasetId : config.datasetId,
datasetUrl : config.dataUrl,
datasetName : config.datasetName,
preferencesPath : "/" + config.datasetName,
preferencesFileName : "dataDetails"
};
var jsObj = sitools.user.component.viewDataDetail;
var windowConfig = {
id : "dataDetail" + config.datasetId,
title : i18n.get('label.viewDataDetail') + " : " + config.datasetName,
datasetName : config.datasetName,
iconCls : "openSearch",
saveToolbar : true,
type : "dataDetail",
toolbarItems : [{
icon : loadUrl.get('APP_URL') + "/common/res/images/icons/simple-arrow-left.png",
handler : function () {
this.ownerCt.ownerCt.items.items[0].goPrevious();
}
}, {
icon : loadUrl.get('APP_URL') + "/common/res/images/icons/simple-arrow-right.png",
handler : function () {
this.ownerCt.ownerCt.items.items[0].goNext();
}
}]
};
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, jsObj, true);
}
}
sitools.user.component.openSearchResultFeed.superclass.constructor.call(this, {
columns : columns,
//hideHeaders : true,
// region : 'center',
layout : 'fit',
flex : 1,
store : this.store,
loadMask : {
msg : i18n.get("label.loadingFeed")
},
sm : new Ext.grid.RowSelectionModel({
singleSelect : true
}),
autoExpandColumn : 'title',
viewConfig : {
forceFit : true,
enableRowBody : true,
showPreview : true,
getRowClass : this.applyRowClass
},
listeners : {
rowdblclick : clickOnRow
}
});
this.updateStore = function (url) {
this.httpProxy.setUrl(url, true);
this.store.load();
};
};
Ext.extend(sitools.user.component.openSearchResultFeed, Ext.grid.GridPanel, {
componentType : "feeds",
// within this function "this" is actually the GridView
applyRowClass : function (record, rowIndex, p, ds) {
if (this.showPreview) {
var xf = Ext.util.Format;
p.body = '<p class=sous-titre-flux>' + xf.ellipsis(xf.stripTags(record.data.description), 200) + '</p>';
return 'x-grid3-row-expanded';
}
return 'x-grid3-row-collapsed';
},
formatDate : function (date) {
if (!date) {
return '';
}
var now = new Date();
var d = now.clearTime(true);
if (date instanceof Date){
var notime = date.clearTime(true).getTime();
if (notime == d.getTime()) {
return 'Today ' + date.dateFormat('g:i a');
}
d = d.add('d', -6);
if (d.getTime() <= notime) {
return date.dateFormat('D g:i a');
}
return date.dateFormat('n/j g:i a');
}
else {
return date;
}
},
/**
* Specific renderer for title Column
* @param {} value
* @param {} p
* @param {Ext.data.Record} record
* @return {string}
*/
formatTitle : function (value, p, record) {
var link = record.data.link;
var xf = Ext.util.Format;
var res = "";
if (link !== undefined && link !== "") {
res = String.format('<div class="topic"><a href="{0}" title="{1}"><span class="rss_feed_title">{2}</span></a></div>', link, value,
xf.ellipsis(xf.stripTags(value), 30));
} else {
res = String.format('<div class="topic"><span class="rss_feed_title">{0}</span></div>', xf.ellipsis(xf.stripTags(value), 30));
}
return res;
}
});
Ext.reg('sitools.user.component.openSearchResultFeed', sitools.user.component.openSearchResultFeed);
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n, alertFailure, window, loadUrl, sql2ext, SITOOLS_DEFAULT_IHM_DATE_FORMAT, ColumnRendererEnum, SITOOLS_DATE_FORMAT*/
Ext.namespace('sitools.user.component');
/**
* Data detail Panel view.
*
* @cfg {string} fromWhere (required) : "Ext.ux.livegrid" or "openSearch", "plot", "dataView"
* used to know how to determine the Url of the record
* @cfg grid : the grid that contains all the datas
* @cfg {string} baseUrl used only in "data" case.
* used to build the url of the record. Contains datasetAttachement + "/records"
* @cfg {string} datasetId the datasetId
* @cfg {string} datasetUrl the dataset url attachment
* @class sitools.user.component.viewDataDetail
* @extends Ext.Panel
*/
sitools.user.component.viewDataDetail = Ext.extend(Ext.Panel, {
//sitools.component.users.viewDataDetail = Ext.extend(Ext.Panel, {
datasetColumnModel : null,
initComponent : function () {
var rec;
switch (this.fromWhere) {
case "openSearch" :
this.grid = this.grid;
this.recSelected = this.grid.getSelectionModel().getSelected();
this.url = this.recSelected.data.guid;
break;
case "dataView" :
break;
case "plot" :
break;
default :
this.recSelected = this.selections[0];
if (Ext.isEmpty(this.recSelected)) {
Ext.Msg.alert(i18n.get('label.error'), i18n.get('label.noSelection'));
return;
}
var primaryKeyValue = "", primaryKeyName = "";
Ext.each(this.recSelected.fields.items, function (field) {
if (field.primaryKey) {
this.primaryKeyName = field.name;
}
}, this);
this.primaryKeyValue = this.recSelected.get(this.primaryKeyName);
this.primaryKeyValue = encodeURIComponent(this.primaryKeyValue);
this.url = this.baseUrl + this.primaryKeyValue;
break;
}
this.layout = "border";
this.linkStore = new Ext.data.Store({
fields : [ 'name', 'value', 'image', 'behavior', 'columnRenderer']
});
var linkDataview = new Ext.DataView({
store : this.linkStore,
tpl : new Ext.XTemplate('<ul>', '<tpl for=".">',
'<li id="{name}" class="img-link"',
'<tpl if="this.hasToolTip(toolTip)">',
'ext:qtip="{toolTip}">',
'</tpl>',
'<tpl if="this.hasToolTip(toolTip) == false">',
'ext:qtip="{name}">',
'</tpl>',
'<img src="{image}" />',
'</li>', '</tpl>', '</ul>',
{
compiled : true,
disableFormats : true,
hasToolTip : function (toolTip){
return !Ext.isEmpty(toolTip);
}
}),
cls : 'linkImageDataView',
itemSelector : 'li.img-link',
overClass : 'nodes-hover',
selectedClass : '',
singleSelect : true,
multiSelect : false,
autoScroll : true,
listeners : {
scope : this,
click : this.handleClickOnLink
}
});
// set the text form
this.formPanel = new Ext.FormPanel({
labelAlign : "top",
anchor : "100%",
defaults : {
labelStyle: 'font-weight:bold;'
},
padding : 10
});
// set the text form
this.linkPanel = new Ext.Panel({
title : i18n.get("label.complementaryInformation"),
items : [linkDataview],
anchor : "100%"
});
// set the search form
this.formPanelImg = new Ext.FormPanel({
frame : true,
autoScroll : true,
region : "east",
hideLabels : true,
split : (this.fromWhere != 'dataView'),
collapsible : (this.fromWhere != 'dataView'),
collapsed : (this.fromWhere != 'dataView'),
flex : 1,
title : (this.fromWhere == 'dataView') ? i18n.get("label.formImagePanelTitle") : null
});
var centerPanelItems;
if (this.fromWhere == 'dataView') {
centerPanelItems = [this.formPanel, this.formPanelImg, this.linkPanel];
}
else {
centerPanelItems = [this.formPanel, this.linkPanel];
}
//set the center Panel
this.centerPanel = new Ext.Panel({
autoScroll : true,
frame : true,
region : "center",
split : true,
layout : {
type : 'anchor'
},
items : centerPanelItems
});
this.getCmDefAndbuildForm();
this.componentType = 'dataDetail';
if (this.fromWhere == 'dataView') {
this.items = [this.centerPanel];
}
else {
this.items = [ this.centerPanel, this.formPanelImg ];
}
this.listeners = {
scope : this,
afterrender : function (panel) {
panel.getEl().on("contextmenu", function (e, t, o) {
e.stopPropagation();
}, this);
}
};
sitools.user.component.viewDataDetail.superclass.initComponent.call(this);
},
afterRender : function () {
this._loadMaskAnchor = Ext.get(this.body.dom);
sitools.user.component.viewDataDetail.superclass.afterRender.apply(this, arguments);
},
/**
* Need to save the window Settings
* @return {}
*/
_getSettings : function () {
return {
objectName : "viewDataDetail",
preferencesPath : this.preferencesPath,
preferencesFileName : this.preferencesFileName
};
},
/**
* Go to the Next record of the grid passed into parameters
*/
goNext : function () {
if (Ext.isEmpty(this.grid)) {
return;
}
var rec, rowSelect;
switch (this.fromWhere) {
case "openSearch" :
rowSelect = this.grid.getSelectionModel();
if (! rowSelect.selectNext()) {
return;
}
rec = rowSelect.getSelected();
this.url = rec.data.guid;
break;
case "sitools.user.component.dataviews.tplView.TplView" :
var index = this.grid.getStore().indexOf(this.recSelected);
var nextRec = this.grid.getStore().getAt(index + 1);
if (Ext.isEmpty(nextRec)) {
return;
}
this.primaryKeyValue = nextRec.get(this.primaryKeyName);
this.primaryKeyValue = encodeURIComponent(this.primaryKeyValue);
this.url = this.baseUrl + this.primaryKeyValue;
this.recSelected = nextRec;
this.grid.select(nextRec);
break;
default :
rowSelect = this.grid.getSelectionModel();
if (! rowSelect.selectNext()) {
return;
}
rec = rowSelect.getSelected();
this.primaryKeyValue = rec.get(this.primaryKeyName);
this.primaryKeyValue = encodeURIComponent(this.primaryKeyValue);
this.url = this.baseUrl + this.primaryKeyValue;
break;
}
this.getCmDefAndbuildForm();
},
/**
* Go to the Previous record of the grid passed into parameters
*/
goPrevious : function () {
if (Ext.isEmpty(this.grid)) {
return;
}
var rec, rowSelect;
switch (this.fromWhere) {
case "openSearch" :
rowSelect = this.grid.getSelectionModel();
if (! rowSelect.selectPrevious()) {
return;
}
rec = rowSelect.getSelected();
this.url = rec.data.guid;
break;
case "sitools.user.component.dataviews.tplView.TplView" :
var index = this.grid.getStore().indexOf(this.recSelected);
var nextRec = this.grid.getStore().getAt(index - 1);
if (Ext.isEmpty(nextRec)) {
return;
}
this.primaryKeyValue = nextRec.get(this.primaryKeyName);
this.primaryKeyValue = encodeURIComponent(this.primaryKeyValue);
this.url = this.baseUrl + this.primaryKeyValue;
this.recSelected = nextRec;
this.grid.select(nextRec);
break;
default :
rowSelect = this.grid.getSelectionModel();
if (! rowSelect.selectPrevious()) {
return;
}
rec = rowSelect.getSelected();
this.primaryKeyValue = rec.get(this.primaryKeyName);
this.primaryKeyValue = encodeURIComponent(this.primaryKeyValue);
this.url = this.baseUrl + this.primaryKeyValue;
break;
}
this.getCmDefAndbuildForm();
},
/**
* Build the form according with the values loaded via the Url
*/
getCmDefAndbuildForm : function () {
if (Ext.isEmpty(this.datasetColumnModel)) {
Ext.Ajax.request({
url : this.datasetUrl,
method : 'GET',
scope : this,
success : function (ret) {
try {
var Json = Ext.decode(ret.responseText);
if (!Json.success) {
throw Json.message;
}
this.datasetColumnModel = Json.dataset.columnModel;
this.buildForm();
}
catch (err) {
Ext.Msg.alert(i18n.get('label.error'), err);
}
},
failure : alertFailure
});
}
else {
this.buildForm();
}
},
buildForm : function () {
if (!Ext.isEmpty(this._loadMaskAnchor)) {
this._loadMaskAnchor.mask(i18n.get('label.waitMessage'), "x-mask-loading");
}
if (!Ext.isEmpty(this.url)) {
this.linkStore.removeAll();
Ext.Ajax.request({
url : this.url,
method : 'GET',
scope : this,
success : function (ret) {
var data = Ext.decode(ret.responseText);
var itemsForm = [];
var itemsFormImg = [];
if (!data.success) {
Ext.Msg.alert(i18n.get('label.information'), "Server error");
return false;
}
var record = data.record;
var id = record.id;
var attributes = record.attributeValues;
if (attributes !== undefined) {
var i;
for (i = 0; i < attributes.length; i++) {
var name = attributes[i].name;
var column = this.findColumn(name);
var value = attributes[i].value;
var valueFormat = value;
if (sql2ext.get(column.sqlColumnType) == 'dateAsString') {
valueFormat = sitools.user.component.dataviews.dataviewUtils.formatDate(value, column);
}
if (sql2ext.get(column.sqlColumnType) == 'boolean') {
valueFormat = value ? i18n.get('label.true') : i18n.get('label.false');
}
var item = new Ext.BoxComponent({
fieldLabel : column.header,
labelSeparator : "",
html : (Ext.isEmpty(valueFormat) || !Ext.isFunction(valueFormat.toString))
? valueFormat
: valueFormat.toString()
});
if (Ext.isEmpty(column) || Ext.isEmpty(column.columnRenderer)) {
itemsForm.push(item);
}
else {
var columnRenderer = column.columnRenderer;
var behavior = "";
if (!Ext.isEmpty(column.columnRenderer)) {
behavior = column.columnRenderer.behavior;
var html = sitools.user.component.dataviews.dataviewUtils.getRendererHTML(column, {});
switch (behavior) {
case ColumnRendererEnum.URL_LOCAL :
case ColumnRendererEnum.URL_EXT_NEW_TAB :
case ColumnRendererEnum.URL_EXT_DESKTOP :
case ColumnRendererEnum.DATASET_ICON_LINK :
if (! Ext.isEmpty(value)) {
if (!Ext.isEmpty(columnRenderer.linkText)) {
item = new Ext.BoxComponent({
fieldLabel : column.header,
labelSeparator : "",
html : String.format(html, value)
});
itemsForm.push(item);
} else if (!Ext.isEmpty(columnRenderer.image)) {
var rec = {
name : name,
value : value,
image : columnRenderer.image.url,
behavior : behavior,
columnRenderer : columnRenderer,
toolTip : columnRenderer.toolTip
};
rec = new Ext.data.Record(rec);
this.linkStore.add(rec);
}
}
break;
case ColumnRendererEnum.IMAGE_FROM_SQL :
case ColumnRendererEnum.IMAGE_THUMB_FROM_IMAGE :
if (! Ext.isEmpty(value)) {
var tooltip = "";
var imageUrl = "";
if (Ext.isEmpty(columnRenderer.toolTip)){
tooltip = columnRenderer.toolTip;
}
else {
tooltip = col.header;
}
if (!Ext.isEmpty(columnRenderer.url)) {
imageUrl = columnRenderer.url;
} else if (!Ext.isEmpty(columnRenderer.columnAlias)) {
imageUrl = this.findRecordValue(record, columnRenderer.columnAlias);
}
item = new Ext.BoxComponent({
html : String.format(html, value, imageUrl),
tooltip : tooltip,
cls : "x-form-item"
});
}
itemsFormImg.push(item);
break;
case ColumnRendererEnum.NO_CLIENT_ACCESS :
break;
default :
item = new Ext.BoxComponent({
fieldLabel : column.header,
labelSeparator : "",
html : String.format(html, value)
});
itemsForm.push(item);
break;
}
}
}
}
this.formPanel.removeAll();
this.formPanelImg.removeAll();
this.formPanel.add(itemsForm);
this.formPanel.doLayout();
if (this.linkStore.getCount() === 0) {
this.linkPanel.setVisible(false);
} else {
this.linkPanel.setVisible(true);
this.linkPanel.doLayout();
}
if (itemsFormImg.length === 0) {
this.formPanelImg.setVisible(false);
} else {
this.formPanelImg.add(itemsFormImg);
this.formPanelImg.setVisible(true);
this.linkPanel.doLayout();
}
this.doLayout();
if (this._loadMaskAnchor && this._loadMaskAnchor.isMasked()) {
this._loadMaskAnchor.unmask();
}
}
},
failure : function () {
alertFailure();
if (this._loadMaskAnchor && this._loadMaskAnchor.isMasked()) {
this._loadMaskAnchor.unmask();
}
}
});
}
},
findColumn : function (columnAlias) {
var result = null;
Ext.each(this.datasetColumnModel, function (column) {
if (column.columnAlias == columnAlias) {
result = column;
return;
}
}, this);
return result;
},
findRecordValue : function (record, columnAlias) {
var result = null;
Ext.each(record.attributeValues, function (attr) {
if (attr.name == columnAlias) {
result = attr.value;
return;
}
}, this);
return result;
},
handleClickOnLink : function (dataView, index, node, e) {
var data = dataView.getRecord(node).data;
var behavior = data.behavior;
switch (behavior) {
case ColumnRendererEnum.URL_LOCAL:
sitools.user.component.dataviews.dataviewUtils.downloadData(data.value);
break;
case ColumnRendererEnum.URL_EXT_NEW_TAB :
window.open(data.value);
break;
case ColumnRendererEnum.URL_EXT_DESKTOP :
sitools.user.component.dataviews.dataviewUtils.showDisplayableUrl(data.value, data.columnRenderer.displayable);
break;
case ColumnRendererEnum.DATASET_ICON_LINK :
sitools.user.component.dataviews.dataviewUtils.showDetailsData(data.value, data.columnRenderer.columnAlias, data.columnRenderer.datasetLinkUrl);
break;
default :
break;
}
},
/**
* Method called when trying to show this component with fixed navigation
*
* @param {sitools.user.component.viewDataDetail} me the dataDetail view
* @param {} config config options
* @returns
*/
showMeInFixedNav : function (me, config) {
Ext.apply(config.windowSettings, {
width : config.windowSettings.winWidth || DEFAULT_WIN_WIDTH,
height : config.windowSettings.winHeight || DEFAULT_WIN_HEIGHT
});
SitoolsDesk.openModalWindow(me, config);
},
/**
* Method called when trying to show this component with Desktop navigation
*
* @param {sitools.user.component.viewDataDetail} me the dataDetail view
* @param {} config config options
* @returns
*/
showMeInDesktopNav : function (me, config) {
Ext.apply(config.windowSettings, {
width : config.windowSettings.winWidth || DEFAULT_WIN_WIDTH,
height : config.windowSettings.winHeight || DEFAULT_WIN_HEIGHT
});
SitoolsDesk.openModalWindow(me, config);
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n, alertFailure*/
Ext.namespace('sitools.user.component');
/**
* A simple form view to visualize a record.
* Builds a form Panel with a form item for each field of the record.
* @cfg {string} urlDataDetail the url to request the Record.
* @class sitools.user.component.simpleViewDataDetail
* @extends Ext.Panel
*/
sitools.user.component.simpleViewDataDetail = Ext.extend(Ext.Panel, {
//sitools.component.users.simpleViewDataDetail = Ext.extend(Ext.Panel, {
initComponent : function () {
this.url = this.urlDataDetail;
//get the end of the uri and encode it
var urlSplited = this.url.split('/');
this.url = "";
for (var i = 0; i < urlSplited.length; i++) {
if (i < urlSplited.length - 1) {
this.url += urlSplited[i] + "/";
} else {
this.url += encodeURIComponent(urlSplited[i]);
}
}
this.layout = "fit";
this.autoScroll = true;
/*
* var store = new Ext.data.JsonStore({ // store configs autoDestroy:
* true, url: this.url, // reader configs root:
* 'record.attributeValues', fields: ['name', 'value'], autoLoad : true
*
* });
*/
// set the search form
this.formPanel = new Ext.FormPanel({
frame : true,
autoScroll : true,
labelWidth : 150,
labelAlign : "top"
});
var itemsForm = [];
Ext.Ajax.request({
url : this.url,
method : 'GET',
scope : this,
success : function (ret) {
var data = Ext.decode(ret.responseText);
if (!data.success) {
Ext.Msg.alert(i18n.get('label.information'), "Server error");
return false;
}
var record = data.record;
var id = record.id;
var attributes = record.attributeValues;
if (attributes !== undefined) {
var i;
for (i = 0; i < attributes.length; i++) {
var name = attributes[i].name;
var value = attributes[i].value;
var item;
if (value !== null && value.length > 100) {
item = new Ext.form.TextArea({
fieldLabel : name,
value : value,
anchor : "90%",
readOnly : true
});
} else {
item = new Ext.form.TextField({
fieldLabel : name,
value : value,
anchor : "90%",
readOnly : true
});
}
itemsForm.push(item);
}
this.formPanel.add(itemsForm);
this.formPanel.doLayout();
}
},
failure : alertFailure
});
this.componentType = 'detail';
this.items = [ this.formPanel ];
sitools.user.component.simpleViewDataDetail.superclass.initComponent.call(this);
},
_getSettings : function () {
return {};
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, ID, i18n, document, showResponse, alertFailure, window*/
/*!
* Ext JS Library 3.3.1
* Copyright(c) 2006-2010 Sencha Inc.
* licensing@sencha.com
* http://www.sencha.com/license
*/
/*
* This is code is also distributed under MIT license for use
* with jQuery and prototype JavaScript libraries.
*/
/**
* @class sitools.component.users.datasets.DomQuery Provides high performance
* selector/xpath processing by compiling queries into reusable
* functions. New pseudo classes and matchers can be plugged. It works on
* HTML and XML documents (if a content node is passed in).
*
*
* DomQuery supports most of the CSS3 selectors spec, along with some custom
* selectors and basic XPath.
*
*
*
* All selectors, attribute filters and pseudos below can be combined infinitely
* in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would
* be a perfectly valid selector. Node filters are processed in the order in
* which they appear, which allows you to optimize your queries for your
* document structure.
*
* Element Selectors:
* * any element
*
* E an element with the tag E
*
* E F All descendent elements of E that have the tag F
*
* E > F or E/F all direct children elements of E that have the tag F
*
* E + F all elements with the tag F that are immediately preceded by an element
* with the tag E
*
* E ~ F all elements with the tag F that are preceded by a sibling element with
* the tag E
*
*
* Attribute Selectors:
*
* The use of @ and quotes are optional. For example, div[@foo='bar'] is also a
* valid attribute selector.
*
*
* E[foo] has an attribute "foo"
*
* E[foo=bar] has an attribute "foo" that equals "bar"
*
* E[foo^=bar] has an attribute "foo" that starts with "bar"
*
* E[foo$=bar] has an attribute "foo" that ends with "bar"
*
* E[foo*=bar] has an attribute "foo" that contains the substring "bar"
*
* E[foo%=2] has an attribute "foo" that is evenly divisible by 2
*
* E[foo!=bar] attribute "foo" does not equal "bar"
*
*
* Pseudo Classes:
*
*
* E:first-child E is the first child of its parent
*
* E:last-child E is the last child of its parent
*
* E:nth-child(n) E is the nth child of its parent (1 based as per the spec)
*
* E:nth-child(odd) E is an odd child of its parent
*
* E:nth-child(even) E is an even child of its parent
*
* E:only-child E is the only child of its parent
*
* E:checked E is an element that is has a checked attribute that is true (e.g.
* a radio or checkbox)
*
* E:first the first E in the resultset
*
* E:last the last E in the resultset
*
* E:nth(n) the nth E in the resultset (1 based)
*
* E:odd shortcut for :nth-child(odd)
*
* E:even shortcut for :nth-child(even)
*
* E:contains(foo) E's innerHTML contains the substring "foo"
*
* E:nodeValue(foo) E contains a textNode with a nodeValue that equals "foo"
*
* E:not(S) an E element that does not match simple selector S
*
* E:has(S) an E element that has a descendent that matches simple selector S
*
* E:next(S) an E element whose next sibling matches simple selector S
*
* E:prev(S) an E element whose previous sibling matches simple selector S
*
* E:any(S1|S2|S2) an E element which matches any of the simple selectors S1, S2
* or S3//\\
*
*
* CSS Value Selectors:
*
*
* E{display=none} css value "display" that equals "none"
*
* E{display^=none} css value "display" that starts with "none"
*
* E{display$=none} css value "display" that ends with "none"
*
* E{display*=none} css value "display" that contains the substring "none"
*
* E{display%=2} css value "display" that is evenly divisible by 2
*
* E{display!=none} css value "display" that does not equal "none"
*
*
* @singleton
*/
Ext.namespace("sitools.component.users.datasets");
sitools.component.users.datasets.DomQuery = function () {
var cache = {}, simpleCache = {}, valueCache = {}, nonSpace = /\S/, trimRe = /^\s+|\s+$/g, tplRe = /\{(\d+)\}/g, modeRe = /^(\s?[\/>+~]\s?|\s|$)/, tagTokenRe = /^(#)?((?:opensearch:)?[\w-\*]+)/, nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/,
// This is for IE MSXML which does not support expandos.
// IE runs the same speed using setAttribute, however FF slows way down
// and Safari completely fails so they need to continue to use expandos.
isIE = window.ActiveXObject ? true : false, key = 30803;
// this eval is stop the compressor from
// renaming the variable to something shorter
eval("var batch = 30803;");
// Retrieve the child node from a particular
// parent at the specified index.
function child(parent, index) {
var i = 0, n = parent.firstChild;
while (n) {
if (n.nodeType == 1) {
if (++i == index) {
return n;
}
}
n = n.nextSibling;
}
return null;
}
// retrieve the next element node
function next(n) {
while ((n = n.nextSibling) && n.nodeType != 1)
;
return n;
}
// retrieve the previous element node
function prev(n) {
while ((n = n.previousSibling) && n.nodeType != 1)
;
return n;
}
// Mark each child node with a nodeIndex skipping and
// removing empty text nodes.
function children (parent) {
var n = parent.firstChild, nodeIndex = -1, nextNode;
while (n) {
nextNode = n.nextSibling;
// clean worthless empty nodes.
if (n.nodeType == 3 && !nonSpace.test(n.nodeValue)) {
parent.removeChild(n);
} else {
// add an expando nodeIndex
n.nodeIndex = ++nodeIndex;
}
n = nextNode;
}
return this;
}
// nodeSet - array of nodes
// cls - CSS Class
function byClassName (nodeSet, cls) {
if (!cls) {
return nodeSet;
}
var result = [], ri = -1;
for ( var i = 0, ci; ci = nodeSet[i]; i++) {
if ((' ' + ci.className + ' ').indexOf(cls) != -1) {
result[++ri] = ci;
}
}
return result;
}
;
function attrValue (n, attr) {
// if its an array, use the first node.
if (!n.tagName && typeof n.length != "undefined") {
n = n[0];
}
if (!n) {
return null;
}
if (attr == "for") {
return n.htmlFor;
}
if (attr == "class" || attr == "className") {
return n.className;
}
return n.getAttribute(attr) || n[attr];
}
;
// ns - nodes
// mode - false, /, >, +, ~
// tagName - defaults to "*"
function getNodes (ns, mode, tagName) {
var result = [], ri = -1, cs;
if (!ns) {
return result;
}
tagName = tagName || "*";
// convert to array
if (typeof ns.getElementsByTagName != "undefined") {
ns = [ ns ];
}
// no mode specified, grab all elements by tagName
// at any depth
if (!mode) {
for ( var i = 0, ni; ni = ns[i]; i++) {
cs = ni.getElementsByTagName(tagName);
for ( var j = 0, ci; ci = cs[j]; j++) {
result[++ri] = ci;
}
}
// Direct Child mode (/ or >)
// E > F or E/F all direct children elements of E that have the tag
} else if (mode == "/" || mode == ">") {
var utag = tagName.toUpperCase();
for ( var i = 0, ni, cn; ni = ns[i]; i++) {
cn = ni.childNodes;
for ( var j = 0, cj; cj = cn[j]; j++) {
if (cj.nodeName == utag || cj.nodeName == tagName || tagName == '*') {
result[++ri] = cj;
}
}
}
// Immediately Preceding mode (+)
// E + F all elements with the tag F that are immediately preceded
// by an element with the tag E
} else if (mode == "+") {
var utag = tagName.toUpperCase();
for ( var i = 0, n; n = ns[i]; i++) {
while ((n = n.nextSibling) && n.nodeType != 1)
;
if (n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')) {
result[++ri] = n;
}
}
// Sibling mode (~)
// E ~ F all elements with the tag F that are preceded by a sibling
// element with the tag E
} else if (mode == "~") {
var utag = tagName.toUpperCase();
for ( var i = 0, n; n = ns[i]; i++) {
while ((n = n.nextSibling)) {
if (n.nodeName == utag || n.nodeName == tagName || tagName == '*') {
result[++ri] = n;
}
}
}
}
return result;
}
function concat (a, b) {
if (b.slice) {
return a.concat(b);
}
for ( var i = 0, l = b.length; i < l; i++) {
a[a.length] = b[i];
}
return a;
}
function byTag (cs, tagName) {
if (cs.tagName || cs == document) {
cs = [ cs ];
}
if (!tagName) {
return cs;
}
var result = [], ri = -1;
tagName = tagName.toLowerCase();
for ( var i = 0, ci; ci = cs[i]; i++) {
if (ci.nodeType == 1 && ci.tagName.toLowerCase() == tagName) {
result[++ri] = ci;
}
}
return result;
}
function byId (cs, id) {
if (cs.tagName || cs == document) {
cs = [ cs ];
}
if (!id) {
return cs;
}
var result = [], ri = -1;
for ( var i = 0, ci; ci = cs[i]; i++) {
if (ci && ci.id == id) {
result[++ri] = ci;
return result;
}
}
return result;
}
// operators are =, !=, ^=, $=, *=, %=, |= and ~=
// custom can be "{"
function byAttribute (cs, attr, value, op, custom) {
var result = [], ri = -1, useGetStyle = custom == "{", fn = sitools.component.users.datasets.DomQuery.operators[op], a, xml, hasXml;
for ( var i = 0, ci; ci = cs[i]; i++) {
// skip non-element nodes.
if (ci.nodeType != 1) {
continue;
}
// only need to do this for the first node
if (!hasXml) {
xml = sitools.component.users.datasets.DomQuery.isXml(ci);
hasXml = true;
}
// we only need to change the property names if we're dealing with
// html nodes, not XML
if (!xml) {
if (useGetStyle) {
a = sitools.component.users.datasets.DomQuery.getStyle(ci, attr);
} else if (attr == "class" || attr == "className") {
a = ci.className;
} else if (attr == "for") {
a = ci.htmlFor;
} else if (attr == "href") {
// getAttribute href bug
// http://www.glennjones.net/Post/809/getAttributehrefbug.htm
a = ci.getAttribute("href", 2);
} else {
a = ci.getAttribute(attr);
}
} else {
a = ci.getAttribute(attr);
}
if ((fn && fn(a, value)) || (!fn && a)) {
result[++ri] = ci;
}
}
return result;
}
function byPseudo (cs, name, value) {
return sitools.component.users.datasets.DomQuery.pseudos[name](cs, value);
}
function nodupIEXml (cs) {
var d = ++key, r;
cs[0].setAttribute("_nodup", d);
r = [ cs[0] ];
for ( var i = 1, len = cs.length; i < len; i++) {
var c = cs[i];
if (!c.getAttribute("_nodup") != d) {
c.setAttribute("_nodup", d);
r[r.length] = c;
}
}
for ( var i = 0, len = cs.length; i < len; i++) {
cs[i].removeAttribute("_nodup");
}
return r;
}
function nodup (cs) {
if (!cs) {
return [];
}
var len = cs.length, c, i, r = cs, cj, ri = -1;
if (!len || typeof cs.nodeType != "undefined" || len == 1) {
return cs;
}
if (isIE && typeof cs[0].selectSingleNode != "undefined") {
return nodupIEXml(cs);
}
var d = ++key;
cs[0]._nodup = d;
for (i = 1; c = cs[i]; i++) {
if (c._nodup != d) {
c._nodup = d;
} else {
r = [];
for ( var j = 0; j < i; j++) {
r[++ri] = cs[j];
}
for (j = i + 1; cj = cs[j]; j++) {
if (cj._nodup != d) {
cj._nodup = d;
r[++ri] = cj;
}
}
return r;
}
}
return r;
}
function quickDiffIEXml (c1, c2) {
var d = ++key, r = [];
for ( var i = 0, len = c1.length; i < len; i++) {
c1[i].setAttribute("_qdiff", d);
}
for ( var i = 0, len = c2.length; i < len; i++) {
if (c2[i].getAttribute("_qdiff") != d) {
r[r.length] = c2[i];
}
}
for ( var i = 0, len = c1.length; i < len; i++) {
c1[i].removeAttribute("_qdiff");
}
return r;
}
function quickDiff (c1, c2) {
var len1 = c1.length, d = ++key, r = [];
if (!len1) {
return c2;
}
if (isIE && typeof c1[0].selectSingleNode != "undefined") {
return quickDiffIEXml(c1, c2);
}
for ( var i = 0; i < len1; i++) {
c1[i]._qdiff = d;
}
for ( var i = 0, len = c2.length; i < len; i++) {
if (c2[i]._qdiff != d) {
r[r.length] = c2[i];
}
}
return r;
}
function quickId (ns, mode, root, id) {
if (ns == root) {
var d = root.ownerDocument || root;
return d.getElementById(id);
}
ns = getNodes(ns, mode, "*");
return byId(ns, id);
}
return {
getStyle : function (el, name) {
return Ext.fly(el).getStyle(name);
},
/**
* Compiles a selector/xpath query into a reusable function. The
* returned function takes one parameter "root" (optional), which is the
* context node from where the query should start.
*
* @param {String}
* selector The selector/xpath query
* @param {String}
* type (optional) Either "select" (the default) or "simple"
* for a simple selector match
* @return {Function}
*/
compile : function (path, type) {
type = type || "select";
// setup fn preamble
var fn = [ "var f = function(root){\n var mode; ++batch; var n = root || document;\n" ], mode, lastPath, matchers = sitools.component.users.datasets.DomQuery.matchers, matchersLn = matchers.length, modeMatch,
// accept leading mode switch
lmode = path.match(modeRe);
if (lmode && lmode[1]) {
fn[fn.length] = 'mode="' + lmode[1].replace(trimRe, "") + '";';
path = path.replace(lmode[1], "");
}
// strip leading slashes
while (path.substr(0, 1) == "/") {
path = path.substr(1);
}
while (path && lastPath != path) {
lastPath = path;
var tokenMatch = path.match(tagTokenRe);
if (type == "select") {
if (tokenMatch) {
// ID Selector
if (tokenMatch[1] == "#") {
fn[fn.length] = 'n = quickId(n, mode, root, "' + tokenMatch[2] + '");';
} else {
fn[fn.length] = 'n = getNodes(n, mode, "' + tokenMatch[2] + '");';
}
path = path.replace(tokenMatch[0], "");
} else if (path.substr(0, 1) != '@') {
fn[fn.length] = 'n = getNodes(n, mode, "*");';
}
// type of "simple"
} else {
if (tokenMatch) {
if (tokenMatch[1] == "#") {
fn[fn.length] = 'n = byId(n, "' + tokenMatch[2] + '");';
} else {
fn[fn.length] = 'n = byTag(n, "' + tokenMatch[2] + '");';
}
path = path.replace(tokenMatch[0], "");
}
}
while (!(modeMatch = path.match(modeRe))) {
var matched = false;
for ( var j = 0; j < matchersLn; j++) {
var t = matchers[j];
var m = path.match(t.re);
if (m) {
fn[fn.length] = t.select.replace(tplRe, function (x, i) {
return m[i];
});
path = path.replace(m[0], "");
matched = true;
break;
}
}
// prevent infinite loop on bad selector
if (!matched) {
throw 'Error parsing selector, parsing failed at "' + path + '"';
}
}
if (modeMatch[1]) {
fn[fn.length] = 'mode="' + modeMatch[1].replace(trimRe, "") + '";';
path = path.replace(modeMatch[1], "");
}
}
// close fn out
fn[fn.length] = "return nodup(n);\n}";
// eval fn and return it
eval(fn.join(""));
return f;
},
/**
* Selects a group of elements.
*
* @param {String}
* selector The selector/xpath query (can be a comma
* separated list of selectors)
* @param {Node/String}
* root (optional) The start of the query (defaults to
* document).
* @return {Array} An Array of DOM elements which match the selector. If
* there are no matches, and empty Array is returned.
*/
jsSelect : function (path, root, type) {
// set root to doc if not specified.
path = path || "";
root = root || document;
if (typeof root == "string") {
root = document.getElementById(root);
}
var paths = path.split(","), results = [];
// loop over each selector
for ( var i = 0, len = paths.length; i < len; i++) {
var subPath = paths[i].replace(trimRe, "");
// compile and place in cache
if (!cache[subPath]) {
cache[subPath] = sitools.component.users.datasets.DomQuery.compile(subPath);
if (!cache[subPath]) {
throw subPath + " is not a valid selector";
}
}
var result = cache[subPath](root);
if (result && result != document) {
results = results.concat(result);
}
}
// if there were multiple selectors, make sure dups
// are eliminated
if (paths.length > 1) {
return nodup(results);
}
return results;
},
isXml : function (el) {
var docEl = (el ? el.ownerDocument || el : 0).documentElement;
return docEl ? docEl.nodeName !== "HTML" : false;
},
select : document.querySelectorAll ? function (path, root, type) {
root = root || document;
if (!sitools.component.users.datasets.DomQuery.isXml(root)) {
try {
var cs = root.querySelectorAll(path);
return Ext.toArray(cs);
} catch (ex) {
}
}
return sitools.component.users.datasets.DomQuery.jsSelect.call(this, path, root, type);
} : function (path, root, type) {
return sitools.component.users.datasets.DomQuery.jsSelect.call(this, path, root, type);
},
/**
* Selects a single element.
*
* @param {String}
* selector The selector/xpath query
* @param {Node}
* root (optional) The start of the query (defaults to
* document).
* @return {Element} The DOM element which matched the selector.
*/
selectNode : function (path, root) {
return sitools.component.users.datasets.DomQuery.select(path, root)[0];
},
/**
* Selects the value of a node, optionally replacing null with the
* defaultValue.
*
* @param {String}
* selector The selector/xpath query
* @param {Node}
* root (optional) The start of the query (defaults to
* document).
* @param {String}
* defaultValue
* @return {String}
*/
selectValue : function (path, root, defaultValue) {
path = path.replace(trimRe, "");
if (!valueCache[path]) {
valueCache[path] = sitools.component.users.datasets.DomQuery.compile(path, "select");
}
var n = valueCache[path](root), v;
n = n[0] ? n[0] : n;
// overcome a limitation of maximum textnode size
// Rumored to potentially crash IE6 but has not been confirmed.
// http://reference.sitepoint.com/javascript/Node/normalize
// https://developer.mozilla.org/En/DOM/Node.normalize
if (typeof n.normalize == 'function')
n.normalize();
v = (n && n.firstChild ? n.firstChild.nodeValue : null);
return ((v === null || v === undefined || v === '') ? defaultValue : v);
},
/**
* Selects the value of a node, parsing integers and floats. Returns the
* defaultValue, or 0 if none is specified.
*
* @param {String}
* selector The selector/xpath query
* @param {Node}
* root (optional) The start of the query (defaults to
* document).
* @param {Number}
* defaultValue
* @return {Number}
*/
selectNumber : function (path, root, defaultValue) {
var v = sitools.component.users.datasets.DomQuery.selectValue(path, root, defaultValue || 0);
return parseFloat(v);
},
/**
* Returns true if the passed element(s) match the passed simple
* selector (e.g. div.some-class or span:first-child)
*
* @param {String/HTMLElement/Array}
* el An element id, element or array of elements
* @param {String}
* selector The simple selector to test
* @return {Boolean}
*/
is : function (el, ss) {
if (typeof el == "string") {
el = document.getElementById(el);
}
var isArray = Ext.isArray(el), result = sitools.component.users.datasets.DomQuery.filter(isArray ? el : [ el ], ss);
return isArray ? (result.length == el.length) : (result.length > 0);
},
/**
* Filters an array of elements to only include matches of a simple
* selector (e.g. div.some-class or span:first-child)
*
* @param {Array}
* el An array of elements to filter
* @param {String}
* selector The simple selector to test
* @param {Boolean}
* nonMatches If true, it returns the elements that DON'T
* match the selector instead of the ones that match
* @return {Array} An Array of DOM elements which match the selector. If
* there are no matches, and empty Array is returned.
*/
filter : function (els, ss, nonMatches) {
ss = ss.replace(trimRe, "");
if (!simpleCache[ss]) {
simpleCache[ss] = sitools.component.users.datasets.DomQuery.compile(ss, "simple");
}
var result = simpleCache[ss](els);
return nonMatches ? quickDiff(result, els) : result;
},
/**
* Collection of matching regular expressions and code snippets. Each
* capture group within () will be replace the {} in the select
* statement as specified by their index.
*/
matchers : [ {
re : /^\.([\w-]+)/,
select : 'n = byClassName(n, " {1} ");'
}, {
re : /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
select : 'n = byPseudo(n, "{1}", "{2}");'
}, {
re : /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
select : 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
}, {
re : /^#([\w-]+)/,
select : 'n = byId(n, "{1}");'
}, {
re : /^@([\w-]+)/,
select : 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
} ],
/**
* Collection of operator comparison functions. The default operators
* are =, !=, ^=, $=, *=, %=, |= and ~=. New operators can be added as
* long as the match the format c= where c is any character other than
* space, > <.
*/
operators : {
"=" : function (a, v) {
return a == v;
},
"!=" : function (a, v) {
return a != v;
},
"^=" : function (a, v) {
return a && a.substr(0, v.length) == v;
},
"$=" : function (a, v) {
return a && a.substr(a.length - v.length) == v;
},
"*=" : function (a, v) {
return a && a.indexOf(v) !== -1;
},
"%=" : function (a, v) {
return (a % v) == 0;
},
"|=" : function (a, v) {
return a && (a == v || a.substr(0, v.length + 1) == v + '-');
},
"~=" : function (a, v) {
return a && (' ' + a + ' ').indexOf(' ' + v + ' ') != -1;
}
},
/**
*
*
* Object hash of "pseudo class" filter functions which are used when
* filtering selections. Each function is passed two parameters:
* * c : Array An Array of DOM elements to filter. * v : String The
* argument (if any) supplied in the selector.
*
*
*
*
*
*
* A filter function returns an Array of DOM elements which conform to
* the pseudo class.
*
*
*
* In addition to the provided pseudo classes listed above such as
* first-child and nth-child, developers may add additional, custom
* psuedo class filters to select elements according to
* application-specific requirements.
*
*
*
* For example, to filter <a> elements to only return links to external
* resources:
*
*
*
* sitools.component.users.datasets.DomQuery.pseudos.external =
* function(c, v){ var r = [], ri = -1; for(var i = 0, ci; ci = c[i];
* i++){ // Include in result set only if it's a link to an external
* resource if(ci.hostname != location.hostname){ r[++ri] = ci; } }
* return r; };
*
*
* Then external links could be gathered with the following statement:
*
* var externalLinks = Ext.select("a:external");
*
*
*/
pseudos : {
"first-child" : function (c) {
var r = [], ri = -1, n;
for ( var i = 0, ci; ci = n = c[i]; i++) {
while ((n = n.previousSibling) && n.nodeType != 1)
;
if (!n) {
r[++ri] = ci;
}
}
return r;
},
"last-child" : function (c) {
var r = [], ri = -1, n;
for ( var i = 0, ci; ci = n = c[i]; i++) {
while ((n = n.nextSibling) && n.nodeType != 1)
;
if (!n) {
r[++ri] = ci;
}
}
return r;
},
"nth-child" : function (c, a) {
var r = [], ri = -1, m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a), f = (m[1] || 1) - 0, l = m[2] - 0;
for ( var i = 0, n; n = c[i]; i++) {
var pn = n.parentNode;
if (batch != pn._batch) {
var j = 0;
for ( var cn = pn.firstChild; cn; cn = cn.nextSibling) {
if (cn.nodeType == 1) {
cn.nodeIndex = ++j;
}
}
pn._batch = batch;
}
if (f == 1) {
if (l == 0 || n.nodeIndex == l) {
r[++ri] = n;
}
} else if ((n.nodeIndex + l) % f == 0) {
r[++ri] = n;
}
}
return r;
},
"only-child" : function (c) {
var r = [], ri = -1;
;
for ( var i = 0, ci; ci = c[i]; i++) {
if (!prev(ci) && !next(ci)) {
r[++ri] = ci;
}
}
return r;
},
"empty" : function (c) {
var r = [], ri = -1;
for ( var i = 0, ci; ci = c[i]; i++) {
var cns = ci.childNodes, j = 0, cn, empty = true;
while (cn = cns[j]) {
++j;
if (cn.nodeType == 1 || cn.nodeType == 3) {
empty = false;
break;
}
}
if (empty) {
r[++ri] = ci;
}
}
return r;
},
"contains" : function (c, v) {
var r = [], ri = -1;
for ( var i = 0, ci; ci = c[i]; i++) {
if ((ci.textContent || ci.innerText || '').indexOf(v) != -1) {
r[++ri] = ci;
}
}
return r;
},
"nodeValue" : function (c, v) {
var r = [], ri = -1;
for ( var i = 0, ci; ci = c[i]; i++) {
if (ci.firstChild && ci.firstChild.nodeValue == v) {
r[++ri] = ci;
}
}
return r;
},
"checked" : function (c) {
var r = [], ri = -1;
for ( var i = 0, ci; ci = c[i]; i++) {
if (ci.checked == true) {
r[++ri] = ci;
}
}
return r;
},
"not" : function (c, ss) {
return sitools.component.users.datasets.DomQuery.filter(c, ss, true);
},
"any" : function (c, selectors) {
var ss = selectors.split('|'), r = [], ri = -1, s;
for ( var i = 0, ci; ci = c[i]; i++) {
for ( var j = 0; s = ss[j]; j++) {
if (sitools.component.users.datasets.DomQuery.is(ci, s)) {
r[++ri] = ci;
break;
}
}
}
return r;
},
"odd" : function (c) {
return this["nth-child"](c, "odd");
},
"even" : function (c) {
return this["nth-child"](c, "even");
},
"nth" : function (c, a) {
return c[a - 1] || [];
},
"first" : function (c) {
return c[0] || [];
},
"last" : function (c) {
return c[c.length - 1] || [];
},
"has" : function (c, ss) {
var s = sitools.component.users.datasets.DomQuery.select, r = [], ri = -1;
for ( var i = 0, ci; ci = c[i]; i++) {
if (s(ss, ci).length > 0) {
r[++ri] = ci;
}
}
return r;
},
"next" : function (c, ss) {
var is = sitools.component.users.datasets.DomQuery.is, r = [], ri = -1;
for ( var i = 0, ci; ci = c[i]; i++) {
var n = next(ci);
if (n && is(n, ss)) {
r[++ri] = ci;
}
}
return r;
},
"prev" : function (c, ss) {
var is = sitools.component.users.datasets.DomQuery.is, r = [], ri = -1;
for ( var i = 0, ci; ci = c[i]; i++) {
var n = prev(ci);
if (n && is(n, ss)) {
r[++ri] = ci;
}
}
return r;
}
}
};
}();
/**
* Selects an array of DOM nodes by CSS/XPath selector. Shorthand of
* {@link sitools.component.users.datasets.DomQuery#select}
*
* @param {String}
* path The selector/xpath query
* @param {Node}
* root (optional) The start of the query (defaults to document).
* @return {Array}
* @member Ext
* @method query
*/
Ext.query = sitools.component.users.datasets.DomQuery.select;
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, i18n, window*/
Ext.namespace('sitools.component.users.datasets');
sitools.component.users.datasets.XmlReader = function (meta, recordType) {
meta = meta || {};
// backwards compat, convert idPath or id / success
Ext.applyIf(meta, {
idProperty : meta.idProperty || meta.idPath || meta.id,
successProperty : meta.successProperty || meta.success
});
sitools.component.users.datasets.XmlReader.superclass.constructor.call(this, meta, recordType || meta.fields);
};
Ext.extend(sitools.component.users.datasets.XmlReader, Ext.data.XmlReader, {
/**
* Creates a function to return some particular key of data from a response.
*
* @param {String}
* key
* @return {Function}
* @private
* @ignore
*/
createAccessor : function () {
var q = sitools.component.users.datasets.DomQuery;
return function (key) {
if (Ext.isFunction(key)) {
return key;
}
switch (key) {
case this.meta.totalProperty:
return function (root, def) {
return q.selectNumber(key, root, def);
};
break;
case this.meta.successProperty:
return function (root, def) {
var sv = q.selectValue(key, root, true);
var success = sv !== false && sv !== 'false';
return success;
};
break;
default:
return function (root, def) {
return q.selectValue(key, root, def);
};
break;
}
};
}()
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/* Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>
* Version: 1.0
* LastModified: Dec 25 1999
* This library is free. You can redistribute it and/or modify it.
*/
/*
* Interfaces:
* b64 = base64encode(data);
* data = base64decode(b64);
*/
(function() {
var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var base64DecodeChars = [
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1];
function base64encode(str) {
var out, i, len;
var c1, c2, c3;
len = str.length;
i = 0;
out = "";
while(i < len) {
c1 = str.charCodeAt(i++) & 0xff;
if(i == len)
{
out += base64EncodeChars.charAt(c1 >> 2);
out += base64EncodeChars.charAt((c1 & 0x3) << 4);
out += "==";
break;
}
c2 = str.charCodeAt(i++);
if(i == len)
{
out += base64EncodeChars.charAt(c1 >> 2);
out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
out += base64EncodeChars.charAt((c2 & 0xF) << 2);
out += "=";
break;
}
c3 = str.charCodeAt(i++);
out += base64EncodeChars.charAt(c1 >> 2);
out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6));
out += base64EncodeChars.charAt(c3 & 0x3F);
}
return out;
}
function base64decode(str) {
var c1, c2, c3, c4;
var i, len, out;
len = str.length;
i = 0;
out = "";
while(i < len) {
/* c1 */
do {
c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
} while(i < len && c1 == -1);
if(c1 == -1)
break;
/* c2 */
do {
c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
} while(i < len && c2 == -1);
if(c2 == -1)
break;
out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));
/* c3 */
do {
c3 = str.charCodeAt(i++) & 0xff;
if(c3 == 61)
return out;
c3 = base64DecodeChars[c3];
} while(i < len && c3 == -1);
if(c3 == -1)
break;
out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));
/* c4 */
do {
c4 = str.charCodeAt(i++) & 0xff;
if(c4 == 61)
return out;
c4 = base64DecodeChars[c4];
} while(i < len && c4 == -1);
if(c4 == -1)
break;
out += String.fromCharCode(((c3 & 0x03) << 6) | c4);
}
return out;
}
if (!window.btoa) window.btoa = base64encode;
if (!window.atob) window.atob = base64decode;
})();
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*
* Canvas2Image v0.1
* Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com
* MIT License [http://www.opensource.org/licenses/mit-license.php]
*/
var Canvas2Image = (function () {
// check if we have canvas support
var oCanvas = document.createElement("canvas");
// no canvas, bail out.
if (!oCanvas.getContext) {
return {
saveAsBMP : function () {
},
saveAsPNG : function () {
},
saveAsJPEG : function () {
}
};
}
var bHasImageData = !!(oCanvas.getContext("2d").getImageData);
var bHasDataURL = !!(oCanvas.toDataURL);
var bHasBase64 = !!(window.btoa);
var strDownloadMime = "image/octet-stream";
// ok, we're good
var readCanvasData = function (oCanvas) {
var iWidth = parseInt(oCanvas.width);
var iHeight = parseInt(oCanvas.height);
return oCanvas.getContext("2d").getImageData(0, 0, iWidth, iHeight);
};
// base64 encodes either a string or an array of charcodes
var encodeData = function (data) {
var strData = "";
if (typeof data == "string") {
strData = data;
} else {
var aData = data;
for ( var i = 0; i < aData.length; i++) {
strData += String.fromCharCode(aData[i]);
}
}
return btoa(strData);
};
// creates a base64 encoded string containing BMP data
// takes an imagedata object as argument
var createBMP = function (oData) {
var aHeader = [];
var iWidth = oData.width;
var iHeight = oData.height;
aHeader.push(0x42); // magic 1
aHeader.push(0x4D);
var iFileSize = iWidth * iHeight * 3 + 54; // total header size = 54
// bytes
aHeader.push(iFileSize % 256);
iFileSize = Math.floor(iFileSize / 256);
aHeader.push(iFileSize % 256);
iFileSize = Math.floor(iFileSize / 256);
aHeader.push(iFileSize % 256);
iFileSize = Math.floor(iFileSize / 256);
aHeader.push(iFileSize % 256);
aHeader.push(0); // reserved
aHeader.push(0);
aHeader.push(0); // reserved
aHeader.push(0);
aHeader.push(54); // data offset
aHeader.push(0);
aHeader.push(0);
aHeader.push(0);
var aInfoHeader = [];
aInfoHeader.push(40); // info header size
aInfoHeader.push(0);
aInfoHeader.push(0);
aInfoHeader.push(0);
var iImageWidth = iWidth;
aInfoHeader.push(iImageWidth % 256);
iImageWidth = Math.floor(iImageWidth / 256);
aInfoHeader.push(iImageWidth % 256);
iImageWidth = Math.floor(iImageWidth / 256);
aInfoHeader.push(iImageWidth % 256);
iImageWidth = Math.floor(iImageWidth / 256);
aInfoHeader.push(iImageWidth % 256);
var iImageHeight = iHeight;
aInfoHeader.push(iImageHeight % 256);
iImageHeight = Math.floor(iImageHeight / 256);
aInfoHeader.push(iImageHeight % 256);
iImageHeight = Math.floor(iImageHeight / 256);
aInfoHeader.push(iImageHeight % 256);
iImageHeight = Math.floor(iImageHeight / 256);
aInfoHeader.push(iImageHeight % 256);
aInfoHeader.push(1); // num of planes
aInfoHeader.push(0);
aInfoHeader.push(24); // num of bits per pixel
aInfoHeader.push(0);
aInfoHeader.push(0); // compression = none
aInfoHeader.push(0);
aInfoHeader.push(0);
aInfoHeader.push(0);
var iDataSize = iWidth * iHeight * 3;
aInfoHeader.push(iDataSize % 256);
iDataSize = Math.floor(iDataSize / 256);
aInfoHeader.push(iDataSize % 256);
iDataSize = Math.floor(iDataSize / 256);
aInfoHeader.push(iDataSize % 256);
iDataSize = Math.floor(iDataSize / 256);
aInfoHeader.push(iDataSize % 256);
for ( var i = 0; i < 16; i++) {
aInfoHeader.push(0); // these bytes not used
}
var iPadding = (4 - ((iWidth * 3) % 4)) % 4;
var aImgData = oData.data;
var strPixelData = "";
var y = iHeight;
do {
var iOffsetY = iWidth * (y - 1) * 4;
var strPixelRow = "";
for ( var x = 0; x < iWidth; x++) {
var iOffsetX = 4 * x;
strPixelRow += String.fromCharCode(aImgData[iOffsetY + iOffsetX + 2]);
strPixelRow += String.fromCharCode(aImgData[iOffsetY + iOffsetX + 1]);
strPixelRow += String.fromCharCode(aImgData[iOffsetY + iOffsetX]);
}
for ( var c = 0; c < iPadding; c++) {
strPixelRow += String.fromCharCode(0);
}
strPixelData += strPixelRow;
} while (--y);
return encodeData(aHeader.concat(aInfoHeader)) + encodeData(strPixelData);
};
// sends the generated file to the client
var saveFile = function (strData, fileName) {
if (!window.open(strData)) {
document.location.href = strData;
}
};
var makeDataURI = function (strData, strMime) {
return "data:" + strMime + ";base64," + strData;
};
// generates a <img> object containing the imagedata
var makeImageObject = function (strSource) {
var oImgElement = document.createElement("img");
oImgElement.src = strSource;
return oImgElement;
};
var scaleCanvas = function (oCanvas, iWidth, iHeight) {
if (iWidth && iHeight) {
var oSaveCanvas = document.createElement("canvas");
oSaveCanvas.width = iWidth;
oSaveCanvas.height = iHeight;
oSaveCanvas.style.width = iWidth + "px";
oSaveCanvas.style.height = iHeight + "px";
var oSaveCtx = oSaveCanvas.getContext("2d");
oSaveCtx.drawImage(oCanvas, 0, 0, oCanvas.width, oCanvas.height, 0, 0, iWidth, iWidth);
return oSaveCanvas;
}
return oCanvas;
};
return {
saveAsPNG : function (oCanvas, fileName, bReturnImg, iWidth, iHeight) {
if (!bHasDataURL) {
return false;
}
var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight);
var strData = oScaledCanvas.toDataURL("image/png");
if (bReturnImg) {
return makeImageObject(strData);
} else {
// saveFile(strData.replace("image/png", strDownloadMime));
// uses the HTML5 fileSaver API
oScaledCanvas.toBlob(function(blob) {
saveAs(
blob
, fileName + ".png"
);
}, "image/png");
}
return true;
},
saveAsJPEG : function (oCanvas, bReturnImg, iWidth, iHeight) {
if (!bHasDataURL) {
return false;
}
var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight);
var strMime = "image/jpeg";
var strData = oScaledCanvas.toDataURL(strMime);
// check if browser actually supports jpeg by looking for the mime
// type in the data uri.
// if not, return false
if (strData.indexOf(strMime) != 5) {
return false;
}
if (bReturnImg) {
return makeImageObject(strData);
} else {
saveFile(strData.replace(strMime, strDownloadMime));
}
return true;
},
saveAsBMP : function (oCanvas, bReturnImg, iWidth, iHeight) {
if (!(bHasImageData && bHasBase64)) {
return false;
}
var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight);
var oData = readCanvasData(oScaledCanvas);
var strImgData = createBMP(oData);
if (bReturnImg) {
return makeImageObject(makeDataURI(strImgData, "image/bmp"));
} else {
saveFile(makeDataURI(strImgData, strDownloadMime));
}
return true;
}
};
})();
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/**
* This code is released to the public domain by Jim Studt, 2007.
* He may keep some sort of up to date copy at http://www.federated.com/~jim/canvastext/
* It as been modified by Fabien M�nager to handle font style like size, weight, color and rotation.
* A partial support for accentuated letters as been added too.
*/
var CanvasText = {
/** The letters definition. It is a list of letters,
* with their width, and the coordinates of points compositing them.
* The syntax for the points is : [x, y], null value means "pen up"
*/
letters: {
'\n':{ width: -1, points: [] },
' ': { width: 10, points: [] },
'!': { width: 10, points: [[5,21],[5,7],null,[5,2],[4,1],[5,0],[6,1],[5,2]] },
'"': { width: 16, points: [[4,21],[4,14],null,[12,21],[12,14]] },
'#': { width: 21, points: [[11,25],[4,-7],null,[17,25],[10,-7],null,[4,12],[18,12],null,[3,6],[17,6]] },
'$': { width: 20, points: [[8,25],[8,-4],null,[12,25],[12,-4],null,[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] },
'%': { width: 24, points: [[21,21],[3,0],null,[8,21],[10,19],[10,17],[9,15],[7,14],[5,14],[3,16],[3,18],[4,20],[6,21],[8,21],null,[17,7],[15,6],[14,4],[14,2],[16,0],[18,0],[20,1],[21,3],[21,5],[19,7],[17,7]] },
'&': { width: 26, points: [[23,12],[23,13],[22,14],[21,14],[20,13],[19,11],[17,6],[15,3],[13,1],[11,0],[7,0],[5,1],[4,2],[3,4],[3,6],[4,8],[5,9],[12,13],[13,14],[14,16],[14,18],[13,20],[11,21],[9,20],[8,18],[8,16],[9,13],[11,10],[16,3],[18,1],[20,0],[22,0],[23,1],[23,2]] },
'\'':{ width: 10, points: [[5,19],[4,20],[5,21],[6,20],[6,18],[5,16],[4,15]] },
'(': { width: 14, points: [[11,25],[9,23],[7,20],[5,16],[4,11],[4,7],[5,2],[7,-2],[9,-5],[11,-7]] },
')': { width: 14, points: [[3,25],[5,23],[7,20],[9,16],[10,11],[10,7],[9,2],[7,-2],[5,-5],[3,-7]] },
'*': { width: 16, points: [[8,21],[8,9],null,[3,18],[13,12],null,[13,18],[3,12]] },
'+': { width: 26, points: [[13,18],[13,0],null,[4,9],[22,9]] },
',': { width: 10, points: [[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] },
'-': { width: 26, points: [[4,9],[22,9]] },
'.': { width: 10, points: [[5,2],[4,1],[5,0],[6,1],[5,2]] },
'/': { width: 22, points: [[20,25],[2,-7]] },
'0': { width: 20, points: [[9,21],[6,20],[4,17],[3,12],[3,9],[4,4],[6,1],[9,0],[11,0],[14,1],[16,4],[17,9],[17,12],[16,17],[14,20],[11,21],[9,21]] },
'1': { width: 20, points: [[6,17],[8,18],[11,21],[11,0]] },
'2': { width: 20, points: [[4,16],[4,17],[5,19],[6,20],[8,21],[12,21],[14,20],[15,19],[16,17],[16,15],[15,13],[13,10],[3,0],[17,0]] },
'3': { width: 20, points: [[5,21],[16,21],[10,13],[13,13],[15,12],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] },
'4': { width: 20, points: [[13,21],[3,7],[18,7],null,[13,21],[13,0]] },
'5': { width: 20, points: [[15,21],[5,21],[4,12],[5,13],[8,14],[11,14],[14,13],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] },
'6': { width: 20, points: [[16,18],[15,20],[12,21],[10,21],[7,20],[5,17],[4,12],[4,7],[5,3],[7,1],[10,0],[11,0],[14,1],[16,3],[17,6],[17,7],[16,10],[14,12],[11,13],[10,13],[7,12],[5,10],[4,7]] },
'7': { width: 20, points: [[17,21],[7,0],null,[3,21],[17,21]] },
'8': { width: 20, points: [[8,21],[5,20],[4,18],[4,16],[5,14],[7,13],[11,12],[14,11],[16,9],[17,7],[17,4],[16,2],[15,1],[12,0],[8,0],[5,1],[4,2],[3,4],[3,7],[4,9],[6,11],[9,12],[13,13],[15,14],[16,16],[16,18],[15,20],[12,21],[8,21]] },
'9': { width: 20, points: [[16,14],[15,11],[13,9],[10,8],[9,8],[6,9],[4,11],[3,14],[3,15],[4,18],[6,20],[9,21],[10,21],[13,20],[15,18],[16,14],[16,9],[15,4],[13,1],[10,0],[8,0],[5,1],[4,3]] },
':': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],null,[5,2],[4,1],[5,0],[6,1],[5,2]] },
';': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],null,[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] },
'<': { width: 24, points: [[20,18],[4,9],[20,0]] },
'=': { width: 26, points: [[4,12],[22,12],null,[4,6],[22,6]] },
'>': { width: 24, points: [[4,18],[20,9],[4,0]] },
'?': { width: 18, points: [[3,16],[3,17],[4,19],[5,20],[7,21],[11,21],[13,20],[14,19],[15,17],[15,15],[14,13],[13,12],[9,10],[9,7],null,[9,2],[8,1],[9,0],[10,1],[9,2]] },
'@': { width: 27, points: [[18,13],[17,15],[15,16],[12,16],[10,15],[9,14],[8,11],[8,8],[9,6],[11,5],[14,5],[16,6],[17,8],null,[12,16],[10,14],[9,11],[9,8],[10,6],[11,5],null,[18,16],[17,8],[17,6],[19,5],[21,5],[23,7],[24,10],[24,12],[23,15],[22,17],[20,19],[18,20],[15,21],[12,21],[9,20],[7,19],[5,17],[4,15],[3,12],[3,9],[4,6],[5,4],[7,2],[9,1],[12,0],[15,0],[18,1],[20,2],[21,3],null,[19,16],[18,8],[18,6],[19,5]] },
'A': { width: 18, points: [[9,21],[1,0],null,[9,21],[17,0],null,[4,7],[14,7]] },
'B': { width: 21, points: [[4,21],[4,0],null,[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],null,[4,11],[13,11],[16,10],[17,9],[18,7],[18,4],[17,2],[16,1],[13,0],[4,0]] },
'C': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5]] },
'D': { width: 21, points: [[4,21],[4,0],null,[4,21],[11,21],[14,20],[16,18],[17,16],[18,13],[18,8],[17,5],[16,3],[14,1],[11,0],[4,0]] },
'E': { width: 19, points: [[4,21],[4,0],null,[4,21],[17,21],null,[4,11],[12,11],null,[4,0],[17,0]] },
'F': { width: 18, points: [[4,21],[4,0],null,[4,21],[17,21],null,[4,11],[12,11]] },
'G': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[18,8],null,[13,8],[18,8]] },
'H': { width: 22, points: [[4,21],[4,0],null,[18,21],[18,0],null,[4,11],[18,11]] },
'I': { width: 8, points: [[4,21],[4,0]] },
'J': { width: 16, points: [[12,21],[12,5],[11,2],[10,1],[8,0],[6,0],[4,1],[3,2],[2,5],[2,7]] },
'K': { width: 21, points: [[4,21],[4,0],null,[18,21],[4,7],null,[9,12],[18,0]] },
'L': { width: 17, points: [[4,21],[4,0],null,[4,0],[16,0]] },
'M': { width: 24, points: [[4,21],[4,0],null,[4,21],[12,0],null,[20,21],[12,0],null,[20,21],[20,0]] },
'N': { width: 22, points: [[4,21],[4,0],null,[4,21],[18,0],null,[18,21],[18,0]] },
'O': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21]] },
'P': { width: 21, points: [[4,21],[4,0],null,[4,21],[13,21],[16,20],[17,19],[18,17],[18,14],[17,12],[16,11],[13,10],[4,10]] },
'Q': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21],null,[12,4],[18,-2]] },
'R': { width: 21, points: [[4,21],[4,0],null,[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[4,11],null,[11,11],[18,0]] },
'S': { width: 20, points: [[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] },
'T': { width: 16, points: [[8,21],[8,0],null,[1,21],[15,21]] },
'U': { width: 22, points: [[4,21],[4,6],[5,3],[7,1],[10,0],[12,0],[15,1],[17,3],[18,6],[18,21]] },
'V': { width: 18, points: [[1,21],[9,0],null,[17,21],[9,0]] },
'W': { width: 24, points: [[2,21],[7,0],null,[12,21],[7,0],null,[12,21],[17,0],null,[22,21],[17,0]] },
'X': { width: 20, points: [[3,21],[17,0],null,[17,21],[3,0]] },
'Y': { width: 18, points: [[1,21],[9,11],[9,0],null,[17,21],[9,11]] },
'Z': { width: 20, points: [[17,21],[3,0],null,[3,21],[17,21],null,[3,0],[17,0]] },
'[': { width: 14, points: [[4,25],[4,-7],null,[5,25],[5,-7],null,[4,25],[11,25],null,[4,-7],[11,-7]] },
'\\':{ width: 14, points: [[0,21],[14,-3]] },
']': { width: 14, points: [[9,25],[9,-7],null,[10,25],[10,-7],null,[3,25],[10,25],null,[3,-7],[10,-7]] },
'^': { width: 14, points: [[3,10],[8,18],[13,10]] },
'_': { width: 16, points: [[0,-2],[16,-2]] },
'`': { width: 10, points: [[6,21],[5,20],[4,18],[4,16],[5,15],[6,16],[5,17]] },
'a': { width: 19, points: [[15,14],[15,0],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
'b': { width: 19, points: [[4,21],[4,0],null,[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] },
'c': { width: 18, points: [[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
'd': { width: 19, points: [[15,21],[15,0],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
'e': { width: 18, points: [[3,8],[15,8],[15,10],[14,12],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
'f': { width: 12, points: [[10,21],[8,21],[6,20],[5,17],[5,0],null,[2,14],[9,14]] },
'g': { width: 19, points: [[15,14],[15,-2],[14,-5],[13,-6],[11,-7],[8,-7],[6,-6],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
'h': { width: 19, points: [[4,21],[4,0],null,[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] },
'i': { width: 8, points: [[3,21],[4,20],[5,21],[4,22],[3,21],null,[4,14],[4,0]] },
'j': { width: 10, points: [[5,21],[6,20],[7,21],[6,22],[5,21],null,[6,14],[6,-3],[5,-6],[3,-7],[1,-7]] },
'k': { width: 17, points: [[4,21],[4,0],null,[14,14],[4,4],null,[8,8],[15,0]] },
'l': { width: 8, points: [[4,21],[4,0]] },
'm': { width: 30, points: [[4,14],[4,0],null,[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0],null,[15,10],[18,13],[20,14],[23,14],[25,13],[26,10],[26,0]] },
'n': { width: 19, points: [[4,14],[4,0],null,[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] },
'o': { width: 19, points: [[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3],[16,6],[16,8],[15,11],[13,13],[11,14],[8,14]] },
'p': { width: 19, points: [[4,14],[4,-7],null,[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] },
'q': { width: 19, points: [[15,14],[15,-7],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
'r': { width: 13, points: [[4,14],[4,0],null,[4,8],[5,11],[7,13],[9,14],[12,14]] },
's': { width: 17, points: [[14,11],[13,13],[10,14],[7,14],[4,13],[3,11],[4,9],[6,8],[11,7],[13,6],[14,4],[14,3],[13,1],[10,0],[7,0],[4,1],[3,3]] },
't': { width: 12, points: [[5,21],[5,4],[6,1],[8,0],[10,0],null,[2,14],[9,14]] },
'u': { width: 19, points: [[4,14],[4,4],[5,1],[7,0],[10,0],[12,1],[15,4],null,[15,14],[15,0]] },
'v': { width: 16, points: [[2,14],[8,0],null,[14,14],[8,0]] },
'w': { width: 22, points: [[3,14],[7,0],null,[11,14],[7,0],null,[11,14],[15,0],null,[19,14],[15,0]] },
'x': { width: 17, points: [[3,14],[14,0],null,[14,14],[3,0]] },
'y': { width: 16, points: [[2,14],[8,0],null,[14,14],[8,0],[6,-4],[4,-6],[2,-7],[1,-7]] },
'z': { width: 17, points: [[14,14],[3,0],null,[3,14],[14,14],null,[3,0],[14,0]] },
'{': { width: 14, points: [[9,25],[7,24],[6,23],[5,21],[5,19],[6,17],[7,16],[8,14],[8,12],[6,10],null,[7,24],[6,22],[6,20],[7,18],[8,17],[9,15],[9,13],[8,11],[4,9],[8,7],[9,5],[9,3],[8,1],[7,0],[6,-2],[6,-4],[7,-6],null,[6,8],[8,6],[8,4],[7,2],[6,1],[5,-1],[5,-3],[6,-5],[7,-6],[9,-7]] },
'|': { width: 8, points: [[4,25],[4,-7]] },
'}': { width: 14, points: [[5,25],[7,24],[8,23],[9,21],[9,19],[8,17],[7,16],[6,14],[6,12],[8,10],null,[7,24],[8,22],[8,20],[7,18],[6,17],[5,15],[5,13],[6,11],[10,9],[6,7],[5,5],[5,3],[6,1],[7,0],[8,-2],[8,-4],[7,-6],null,[8,8],[6,6],[6,4],[7,2],[8,1],[9,-1],[9,-3],[8,-5],[7,-6],[5,-7]] },
'~': { width: 24, points: [[3,6],[3,8],[4,11],[6,12],[8,12],[10,11],[14,8],[16,7],[18,7],[20,8],[21,10],null,[3,8],[4,10],[6,11],[8,11],[10,10],[14,7],[16,6],[18,6],[20,7],[21,10],[21,12]] },
'�': { diacritic: '�', letter: 'e' },
'�': { diacritic: '`', letter: 'e' },
'�': { diacritic: '^', letter: 'e' },
'�': { diacritic: '�', letter: 'e' },
'�': { diacritic: '`', letter: 'a' },
'�': { diacritic: '�', letter: 'c' },
'�': { diacritic: '~', letter: 'n' },
'�': { diacritic: '^', letter: 'o' },
'�': { diacritic: '�', letter: 'E' },
'�': { diacritic: '`', letter: 'E' },
'�': { diacritic: '^', letter: 'E' },
'�': { diacritic: '�', letter: 'E' },
'�': { diacritic: '`', letter: 'A' },
'�': { diacritic: '�', letter: 'C' },
'�': { diacritic: '~', letter: 'N' },
'�': { diacritic: '^', letter: 'O' }
},
specialchars: {
'pi': { width: 19, points: [[6,14],[6,0],null,[14,14],[14,0],null,[2,13],[6,16],[13,13],[17,16]] }
},
/** Diacritics, used to draw accentuated letters */
diacritics: {
'�': { entity: 'cedil', points: [[6,-4],[4,-6],[2,-7],[1,-7]] },
'�': { entity: 'acute', points: [[8,19],[13,22]] },
'`': { entity: 'grave', points: [[7,22],[12,19]] },
'^': { entity: 'circ', points: [[5.5,19],[9.5,23],[12.5,19]] },
'�': { entity: 'trema', points: [[5,21],[6,20],[7,21],[6,22],[5,21],null,[12,21],[13,20],[14,21],[13,22],[12,21]] },
'~': { entity: 'tilde', points: [[4,18],[7,22],[10,18],[13,22]] }
},
/** The default font styling */
style: {
size: 8, // font height in pixels
font: null, // not yet implemented
color: '#000000', //
weight: 1, // float, 1 for 'normal'
halign: 'l', // l: left, r: right, c: center
valign: 'b', // t: top, m: middle, b: bottom
adjustAlign: false, // modifies the alignments if the angle is different from 0 to make the spin point always at the good position
angle: 0, // in radians, anticlockwise
tracking: 1, // space between the letters, float, 1 for 'normal'
boundingBoxColor: '#ff0000', //null // color of the bounding box (null to hide), can be used for debug and font drawing
originPointColor: '#000000' //null // color of the bounding box (null to hide), can be used for debug and font drawing
},
debug: false,
_bufferLexemes: {},
/** Get the letter data corresponding to a char
* @param {String} ch - The char
*/
letter: function(ch) {
return CanvasText.letters[ch];
},
parseLexemes: function(str) {
if (CanvasText._bufferLexemes[str])
return CanvasText._bufferLexemes[str];
var i, c, matches = str.match(/&[A-Za-z]{2,5};|\s|./g);
var result = [], chars = [];
for (i = 0; i < matches.length; i++) {
c = matches[i];
if (c.length == 1)
chars.push(c);
else {
var entity = c.substring(1, c.length-1);
if (CanvasText.specialchars[entity])
chars.push(entity);
else
chars = chars.concat(c.toArray());
}
}
for (i = 0; i < chars.length; i++) {
c = chars[i];
if (c = CanvasText.letters[c] || CanvasText.specialchars[c])
result.push(c);
}
return CanvasText._bufferLexemes[str] = result.compact();
},
/** Get the font ascent for a given style
* @param {Object} style - The reference style
*/
ascent: function(style) {
style = style || {};
return (style.size || CanvasText.style.size);
},
/** Get the font descent for a given style
* @param {Object} style - The reference style
* */
descent: function(style) {
style = style || {};
return 7.0*(style.size || CanvasText.style.size)/25.0;
},
/** Measure the text horizontal size
* @param {String} str - The text
* @param {Object} style - Text style
* */
measure: function(str, style) {
if (!str) return;
style = style || {};
var i, width, lexemes = CanvasText.parseLexemes(str),
total = 0;
for (i = lexemes.length-1; i > -1; --i) {
c = lexemes[i];
width = (c.diacritic) ? CanvasText.letter(c.letter).width : c.width;
total += width * (style.tracking || CanvasText.style.tracking) * (style.size || CanvasText.style.size) / 25.0;
}
return total;
},
getDimensions: function(str, style) {
var width = CanvasText.measure(str, style),
height = style.size || CanvasText.style.size,
angle = style.angle || CanvasText.style.angle;
if (style.angle == 0) return {width: width, height: height};
return {
width: Math.abs(Math.cos(angle) * width) + Math.abs(Math.sin(angle) * height),
height: Math.abs(Math.sin(angle) * width) + Math.abs(Math.cos(angle) * height)
};
},
getBestAlign: function(angle, style) {
angle += CanvasText.getAngleFromAlign(style.halign, style.valign);
var a = {h:'c', v:'m'};
if (Math.round(Math.cos(angle)*1000)/1000 != 0)
a.h = (Math.cos(angle) > 0 ? 'r' : 'l');
if (Math.round(Math.sin(angle)*1000)/1000 != 0)
a.v = (Math.sin(angle) > 0 ? 't' : 'b');
return a;
},
getAngleFromAlign: function(halign, valign) {
var pi = Math.PI, table = {
'rm': 0,
'rt': pi/4,
'ct': pi/2,
'lt': 3*(pi/4),
'lm': pi,
'lb': -3*(pi/4),
'cb': -pi/2,
'rb': -pi/4,
'cm': 0
};
return table[halign+valign];
},
/** Draws serie of points at given coordinates
* @param {Canvas context} ctx - The canvas context
* @param {Array} points - The points to draw
* @param {Number} x - The X coordinate
* @param {Number} y - The Y coordinate
* @param {Number} mag - The scale
*/
drawPoints: function (ctx, points, x, y, mag, offset) {
var i, a, penUp = true, needStroke = 0;
offset = offset || {x:0, y:0};
ctx.beginPath();
for (i = 0; i < points.length; i++) {
a = points[i];
if (!a) {
penUp = true;
continue;
}
if (penUp) {
ctx.moveTo(x + a[0]*mag + offset.x, y - a[1]*mag + offset.y);
penUp = false;
}
else {
ctx.lineTo(x + a[0]*mag + offset.x, y - a[1]*mag + offset.y);
}
}
ctx.stroke();
},
/** Draws a text at given coordinates and with a given style
* @param {Canvas context} ctx - The canvas context
* @param {String} str - The text to draw
* @param {Number} xOrig - The X coordinate
* @param {Number} yOrig - The Y coordinate
* @param {Object} style - The font style
*/
draw: function(ctx, str, xOrig, yOrig, style) {
if (!str) return;
style = style || CanvasText.style;
style.halign = style.halign || CanvasText.style.halign;
style.valign = style.valign || CanvasText.style.valign;
style.angle = style.angle || CanvasText.style.angle;
style.size = style.size || CanvasText.style.size;
style.adjustAlign = style.adjustAlign || CanvasText.style.adjustAlign;
var i, c, total = 0,
mag = style.size / 25.0,
x = 0, y = 0,
lexemes = CanvasText.parseLexemes(str);
var offset = {x:0, y:0},
measure = CanvasText.measure(str, style),
align;
if (style.adjustAlign) {
align = CanvasText.getBestAlign(style.angle, style);
style.halign = align.h;
style.valign = align.v;
}
switch (style.halign) {
case 'l': break;
case 'c': offset.x = -measure / 2; break;
case 'r': offset.x = -measure; break;
}
switch (style.valign) {
case 'b': break;
case 'm': offset.y = style.size / 2; break;
case 't': offset.y = style.size; break;
}
ctx.save();
ctx.translate(xOrig, yOrig);
ctx.rotate(style.angle);
ctx.lineCap = "round";
ctx.lineWidth = 2.0 * mag * (style.weight || CanvasText.style.weight);
ctx.strokeStyle = style.color || CanvasText.style.color;
for (i = 0; i < lexemes.length; i++) {
c = lexemes[i];
if (c.width == -1) {
x = 0;
y = style.size * 1.4;
continue;
}
var points = c.points,
width = c.width;
if (c.diacritic) {
var dia = CanvasText.diacritics[c.diacritic];
var charactere = CanvasText.letter(c.letter);
CanvasText.drawPoints(ctx, dia.points, x, y - (c.letter.toUpperCase() == c.letter ? 3 : 0), mag, offset);
points = charactere.points;
width = charactere.width;
}
CanvasText.drawPoints(ctx, points, x, y, mag, offset);
if (CanvasText.debug) {
ctx.save();
ctx.lineJoin = "miter";
ctx.lineWidth = 0.5;
ctx.strokeStyle = (style.boundingBoxColor || CanvasText.style.boundingBoxColor);
ctx.strokeRect(x+offset.x, y+offset.y, width*mag, -style.size);
ctx.fillStyle = (style.originPointColor || CanvasText.style.originPointColor);
ctx.beginPath();
ctx.arc(0, 0, 1.5, 0, Math.PI*2, true);
ctx.fill();
ctx.restore();
}
x += width*mag*(style.tracking || CanvasText.style.tracking);
}
ctx.restore();
return total;
},
/** Enables the text function for a Canvas context
* @param {Canvas context} ctx - The canvas context
*/
enable: function(ctx) {
ctx.drawText = function(text, x, y, style) { return CanvasText.draw(ctx, text, x, y, style); };
ctx.measureText = function(text, style) { return CanvasText.measure(text, style); };
ctx.getTextBounds = function(text, style) { return CanvasText.getDimensions(text, style); };
ctx.fontAscent = function(style) { return CanvasText.ascent(style); };
ctx.fontDescent = function(style) { return CanvasText.descent(style); };
}
};
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
//Flotr 0.2.0-alpha Copyright (c) 2009 Bas Wenneker, <http://solutoire.com>, MIT License.
/* $Id: flotr.js 82 2009-01-12 19:19:31Z fabien.menager $ */
var Flotr = {
version : '0.2.0-alpha',
author : 'Bas Wenneker',
website : 'http://www.solutoire.com',
/**
* An object of the default registered graph types. Use Flotr.register(type,
* functionName) to add your own type.
*/
_registeredTypes : {
'lines' : 'drawSeriesLines',
'points' : 'drawSeriesPoints',
'bars' : 'drawSeriesBars',
'candles' : 'drawSeriesCandles',
'pie' : 'drawSeriesPie'
},
/**
* Can be used to register your own chart type. Default types are 'lines',
* 'points' and 'bars'. This is still experimental.
*
* @todo Test and confirm.
* @param {String}
* type - type of chart, like 'pies', 'bars' etc.
* @param {String}
* functionName - Name of the draw function, like
* 'drawSeriesPies', 'drawSeriesBars' etc.
*/
register : function (type, functionName) {
Flotr._registeredTypes[type] = functionName + '';
},
/**
* Draws the graph. This function is here for backwards compatibility with
* Flotr version 0.1.0alpha. You could also draw graphs by directly calling
* Flotr.Graph(element, data, options).
*
* @param {Element}
* el - element to insert the graph into
* @param {Object}
* data - an array or object of dataseries
* @param {Object}
* options - an object containing options
* @param {Class}
* _GraphKlass_ - (optional) Class to pass the arguments to,
* defaults to Flotr.Graph
* @return {Class} returns a new graph object and of course draws the graph.
*/
draw : function (el, data, options, _GraphKlass_) {
_GraphKlass_ = _GraphKlass_ || Flotr.Graph;
return new _GraphKlass_(el, data, options);
},
/**
* Collects dataseries from input and parses the series into the right
* format. It returns an Array of Objects each having at least the 'data'
* key set.
*
* @param {Array/Object}
* data - Object or array of dataseries
* @return {Array} Array of Objects parsed into the right format ({(...,)
* data: [[x1,y1], [x2,y2], ...] (, ...)})
*/
getSeries : function (data) {
return data.collect(function (serie) {
var i, serie = (serie.data) ? Object.clone(serie) : {
'data' : serie
};
for (i = serie.data.length - 1; i > -1; --i) {
serie.data[i][1] = (serie.data[i][1] === null ? null : parseFloat(serie.data[i][1]));
}
return serie;
});
},
/**
* Recursively merges two objects.
*
* @param {Object}
* src - source object (likely the object with the least
* properties)
* @param {Object}
* dest - destination object (optional, object with the most
* properties)
* @return {Object} recursively merged Object
*/
merge : function (src, dest) {
var result = dest || {};
for ( var i in src) {
result[i] = (src[i] != null && typeof (src[i]) == 'object' && !(src[i].constructor == Array || src[i].constructor == RegExp) && !Object
.isElement(src[i])) ? Flotr.merge(src[i], dest[i]) : result[i] = src[i];
}
return result;
},
/**
* Function calculates the ticksize and returns it.
*
* @param {Integer}
* noTicks - number of ticks
* @param {Integer}
* min - lower bound integer value for the current axis
* @param {Integer}
* max - upper bound integer value for the current axis
* @param {Integer}
* decimals - number of decimals for the ticks
* @return {Integer} returns the ticksize in pixels
*/
getTickSize : function (noTicks, min, max, decimals) {
var delta = (max - min) / noTicks;
var magn = Flotr.getMagnitude(delta);
// Norm is between 1.0 and 10.0.
var norm = delta / magn;
var tickSize = 10;
if (norm < 1.5)
tickSize = 1;
else if (norm < 2.25)
tickSize = 2;
else if (norm < 3)
tickSize = ((decimals == 0) ? 2 : 2.5);
else if (norm < 7.5)
tickSize = 5;
return tickSize * magn;
},
/**
* Default tick formatter.
*
* @param {String/Integer}
* val - tick value integer
* @return {String} formatted tick string
*/
defaultTickFormatter : function (val) {
return val + '';
},
/**
* Formats the mouse tracker values.
*
* @param {Object}
* obj - Track value Object {x:..,y:..}
* @return {String} Formatted track string
*/
defaultTrackFormatter : function (obj) {
return '(' + obj.x + ', ' + obj.y + ')';
},
defaultPieLabelFormatter : function (slice) {
return (slice.fraction * 100).toFixed(2) + '%';
},
/**
* Returns the magnitude of the input value.
*
* @param {Integer/Float}
* x - integer or float value
* @return {Integer/Float} returns the magnitude of the input value
*/
getMagnitude : function (x) {
return Math.pow(10, Math.floor(Math.log(x) / Math.LN10));
},
toPixel : function (val) {
return Math.floor(val) + 0.5;// ((val-Math.round(val) < 0.4) ?
// (Math.floor(val)-0.5) : val);
},
toRad : function (angle) {
return -angle * (Math.PI / 180);
},
/**
* Parses a color string and returns a corresponding Color.
*
* @param {String}
* str - string thats representing a color
* @return {Color} returns a Color object or false
*/
parseColor : function (str) {
if (str instanceof Flotr.Color)
return str;
var result, Color = Flotr.Color;
// rgb(num,num,num)
if ((result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str)))
return new Color(parseInt(result[1]), parseInt(result[2]), parseInt(result[3]));
// rgba(num,num,num,num)
if ((result = /rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str)))
return new Color(parseInt(result[1]), parseInt(result[2]), parseInt(result[3]), parseFloat(result[4]));
// rgb(num%,num%,num%)
if ((result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str)))
return new Color(parseFloat(result[1]) * 2.55, parseFloat(result[2]) * 2.55, parseFloat(result[3]) * 2.55);
// rgba(num%,num%,num%,num)
if ((result = /rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str)))
return new Color(parseFloat(result[1]) * 2.55, parseFloat(result[2]) * 2.55, parseFloat(result[3]) * 2.55, parseFloat(result[4]));
// #a0b1c2
if ((result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str)))
return new Color(parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16));
// #fff
if ((result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str)))
return new Color(parseInt(result[1] + result[1], 16), parseInt(result[2] + result[2], 16), parseInt(result[3] + result[3], 16));
// Otherwise, we're most likely dealing with a named color.
var name = str.strip().toLowerCase();
if (name == 'transparent') {
return new Color(255, 255, 255, 0);
}
return ((result = Color.lookupColors[name])) ? new Color(result[0], result[1], result[2]) : false;
},
* Extracts the background-color of the passed element.
*
* @param {Element}
* element
* @return {String} color string
*/
extractColor : function (element) {
var color;
// Loop until we find an element with a background color and stop when
// we hit the body element.
do {
color = element.getStyle('background-color').toLowerCase();
if (!(color == '' || color == 'transparent'))
break;
element = element.up(0);
} while (!element.nodeName.match(/^body$/i));
// Catch Safari's way of signaling transparent.
return (color == 'rgba(0, 0, 0, 0)') ? 'transparent' : color;
}
};
/**
* Flotr Graph class that plots a graph on creation.
*
*/
Flotr.Graph = Class
.create({
/**
* Flotr Graph constructor.
*
* @param {Element}
* el - element to insert the graph into
* @param {Object}
* data - an array or object of dataseries
* @param {Object}
* options - an object containing options
*/
initialize : function (el, data, options) {
this.el = $(el);
if (!this.el)
throw 'The target container doesn\'t exist';
this.data = data;
this.series = Flotr.getSeries(data);
this.setOptions(options);
// Initialize some variables
this.lastMousePos = {
pageX : null,
pageY : null
};
this.selection = {
first : {
x : -1,
y : -1
},
second : {
x : -1,
y : -1
}
};
this.prevSelection = null;
this.selectionInterval = null;
this.ignoreClick = false;
this.prevHit = null;
// Create and prepare canvas.
this.constructCanvas();
// Add event handlers for mouse tracking, clicking and selection
this.initEvents();
this.findDataRanges();
this.calculateTicks(this.axes.x);
this.calculateTicks(this.axes.x2);
this.calculateTicks(this.axes.y);
this.calculateTicks(this.axes.y2);
this.calculateSpacing();
this.draw();
this.insertLegend();
// Graph and Data tabs
if (this.options.spreadsheet.show)
this.constructTabs();
},
/**
* Sets options and initializes some variables and color specific
* values, used by the constructor.
*
* @param {Object}
* opts - options object
*/
setOptions : function (opts) {
var options = {
colors : [ '#00A8F0', '#C0D800', '#CB4B4B', '#4DA74D', '#9440ED' ], // =>
// The
// default
// colorscheme.
// When
// there
// are
// > 5
// series,
// additional
// colors
// are
// generated.
title : null,
subtitle : null,
legend : {
show : true, // => setting to true will show the
// legend, hide otherwise
noColumns : 1, // => number of colums in legend table
// // @todo: doesn't work for HtmlText =
// false
labelFormatter : Prototype.K, // => fn: string ->
// string
labelBoxBorderColor : '#CCCCCC', // => border color
// for the little
// label boxes
labelBoxWidth : 14,
labelBoxHeight : 10,
labelBoxMargin : 5,
container : null, // => container (as jQuery object)
// to put legend in, null means
// default on top of graph
position : 'nw', // => position of default legend
// container within plot
margin : 5, // => distance from grid edge to default
// legend container within plot
backgroundColor : null, // => null means auto-detect
backgroundOpacity : 0.85
// => set to 0 to avoid background, set to 1 for a solid
// background
},
xaxis : {
ticks : null, // => format: either [1, 3] or [[1,
// 'a'], 3]
showLabels : true, // => setting to true will show the
// axis ticks labels, hide otherwise
labelsAngle : 0, // => Labels' angle, in degrees
title : null, // => axis title
titleAngle : 0, // => axis title's angle, in degrees
noTicks : 5, // => number of ticks for automagically
// generated ticks
tickFormatter : Flotr.defaultTickFormatter, // => fn:
// number ->
// string
tickDecimals : null, // => no. of decimals, null
// means auto
min : null, // => min. value to show, null means set
// automatically
max : null, // => max. value to show, null means set
// automatically
autoscaleMargin : 0, // => margin in % to add if
// auto-setting min/max
color : null
},
x2axis : {},
yaxis : {
ticks : null, // => format: either [1, 3] or [[1,
// 'a'], 3]
showLabels : true, // => setting to true will show the
// axis ticks labels, hide otherwise
labelsAngle : 0, // => Labels' angle, in degrees
title : null, // => axis title
titleAngle : 90, // => axis title's angle, in degrees
noTicks : 5, // => number of ticks for automagically
// generated ticks
tickFormatter : Flotr.defaultTickFormatter, // => fn:
// number ->
// string
tickDecimals : null, // => no. of decimals, null
// means auto
min : null, // => min. value to show, null means set
// automatically
max : null, // => max. value to show, null means set
// automatically
autoscaleMargin : 0, // => margin in % to add if
// auto-setting min/max
color : null
},
y2axis : {
titleAngle : 270
},
points : {
show : false, // => setting to true will show points,
// false will hide
radius : 3, // => point radius (pixels)
lineWidth : 2, // => line width in pixels
fill : true, // => true to fill the points with a
// color, false for (transparent) no
// fill
fillColor : '#FFFFFF', // => fill color
fillOpacity : 0.4
},
lines : {
show : false, // => setting to true will show lines,
// false will hide
lineWidth : 2, // => line width in pixels
fill : false, // => true to fill the area from the
// line to the x axis, false for
// (transparent) no fill
fillColor : null, // => fill color
fillOpacity : 0.4
// => opacity of the fill color, set to 1 for a solid fill,
// 0 hides the fill
},
bars : {
show : false, // => setting to true will show bars,
// false will hide
lineWidth : 2, // => in pixels
barWidth : 1, // => in units of the x axis
fill : true, // => true to fill the area from the
// line to the x axis, false for
// (transparent) no fill
fillColor : null, // => fill color
fillOpacity : 0.4, // => opacity of the fill color, set
// to 1 for a solid fill, 0 hides
// the fill
horizontal : false,
stacked : false
},
candles : {
show : false, // => setting to true will show candle
// sticks, false will hide
lineWidth : 1, // => in pixels
wickLineWidth : 1, // => in pixels
candleWidth : 0.6, // => in units of the x axis
fill : true, // => true to fill the area from the
// line to the x axis, false for
// (transparent) no fill
upFillColor : '#00A8F0',// => up sticks fill color
downFillColor : '#CB4B4B',// => down sticks fill color
fillOpacity : 0.5, // => opacity of the fill color, set
// to 1 for a solid fill, 0 hides
// the fill
barcharts : false
// => draw as barcharts (not standard bars but financial
// barcharts)
},
pie : {
show : false, // => setting to true will show bars,
// false will hide
lineWidth : 1, // => in pixels
fill : true, // => true to fill the area from the
// line to the x axis, false for
// (transparent) no fill
fillColor : null, // => fill color
fillOpacity : 0.6, // => opacity of the fill color, set
// to 1 for a solid fill, 0 hides
// the fill
explode : 6,
sizeRatio : 0.6,
startAngle : Math.PI / 4,
labelFormatter : Flotr.defaultPieLabelFormatter,
pie3D : false,
pie3DviewAngle : (Math.PI / 2 * 0.8),
pie3DspliceThickness : 20
},
grid : {
color : '#545454', // => primary color used for outline
// and labels
backgroundColor : null, // => null for transparent, else
// color
tickColor : '#DDDDDD', // => color used for the ticks
labelMargin : 3, // => margin in pixels
verticalLines : true, // => whether to show gridlines
// in vertical direction
horizontalLines : true, // => whether to show gridlines
// in horizontal direction
outlineWidth : 2
// => width of the grid outline/border in pixels
},
selection : {
mode : null, // => one of null, 'x', 'y' or 'xy'
color : '#B6D9FF', // => selection box color
fps : 20
// => frames-per-second
},
mouse : {
track : false, // => true to track the mouse, no
// tracking otherwise
position : 'se', // => position of the value box
// (default south-east)
relative : false, // => next to the mouse cursor
trackFormatter : Flotr.defaultTrackFormatter, // =>
// formats
// the
// values
// in
// the
// value
// box
margin : 5, // => margin in pixels of the valuebox
lineColor : '#FF3F19', // => line color of points that
// are drawn when mouse comes
// near a value of a series
trackDecimals : 1, // => decimals for the track values
sensibility : 2, // => the lower this number, the
// more precise you have to aim to
// show a value
radius : 3
// => radius of the track point
},
shadowSize : 4, // => size of the 'fake' shadow
defaultType : 'lines', // => default series type
HtmlText : true, // => wether to draw the text using HTML
// or on the canvas
fontSize : 7.5, // => canvas' text font size
spreadsheet : {
show : false, // => show the data grid using two tabs
tabGraphLabel : 'Graph',
tabDataLabel : 'Data',
toolbarDownload : 'Download CSV', // @todo: add
// language support
toolbarSelectAll : 'Select all'
}
};
options.x2axis = Object.extend(Object.clone(options.xaxis), options.x2axis);
options.y2axis = Object.extend(Object.clone(options.yaxis), options.y2axis);
this.options = Flotr.merge((opts || {}), options);
this.axes = {
x : {
options : this.options.xaxis,
n : 1
},
x2 : {
options : this.options.x2axis,
n : 2
},
y : {
options : this.options.yaxis,
n : 1
},
y2 : {
options : this.options.y2axis,
n : 2
}
};
// Initialize some variables used throughout this function.
var assignedColors = [], colors = [], ln = this.series.length, neededColors = this.series.length, oc = this.options.colors, usedColors = [], variation = 0, c, i, j, s, tooClose;
// Collect user-defined colors from series.
for (i = neededColors - 1; i > -1; --i) {
c = this.series[i].color;
if (c != null) {
--neededColors;
if (Object.isNumber(c))
assignedColors.push(c);
else
usedColors.push(Flotr.parseColor(c));
}
}
// Calculate the number of colors that need to be generated.
for (i = assignedColors.length - 1; i > -1; --i)
neededColors = Math.max(neededColors, assignedColors[i] + 1);
// Generate needed number of colors.
for (i = 0; colors.length < neededColors;) {
c = (oc.length == i) ? new Flotr.Color(100, 100, 100) : Flotr.parseColor(oc[i]);
// Make sure each serie gets a different color.
var sign = variation % 2 == 1 ? -1 : 1;
var factor = 1 + sign * Math.ceil(variation / 2) * 0.2;
c.scale(factor, factor, factor);
/**
* @todo if we're getting too close to something else, we
* should probably skip this one
*/
colors.push(c);
if (++i >= oc.length) {
i = 0;
++variation;
}
}
// Fill the options with the generated colors.
for (i = 0, j = 0; i < ln; ++i) {
s = this.series[i];
// Assign the color.
if (s.color == null) {
s.color = colors[j++].toString();
} else if (Object.isNumber(s.color)) {
s.color = colors[s.color].toString();
}
if (!s.xaxis)
s.xaxis = this.axes.x;
if (s.xaxis == 1)
s.xaxis = this.axes.x;
else if (s.xaxis == 2)
s.xaxis = this.axes.x2;
if (!s.yaxis)
s.yaxis = this.axes.y;
if (s.yaxis == 1)
s.yaxis = this.axes.y;
else if (s.yaxis == 2)
s.yaxis = this.axes.y2;
// Apply missing options to the series.
s.lines = Object.extend(Object.clone(this.options.lines), s.lines);
s.points = Object.extend(Object.clone(this.options.points), s.points);
s.bars = Object.extend(Object.clone(this.options.bars), s.bars);
s.candles = Object.extend(Object.clone(this.options.candles), s.candles);
s.pie = Object.extend(Object.clone(this.options.pie), s.pie);
s.mouse = Object.extend(Object.clone(this.options.mouse), s.mouse);
if (s.shadowSize == null)
s.shadowSize = this.options.shadowSize;
}
},
/**
* Initializes the canvas and it's overlay canvas element. When the
* browser is IE, this makes use of excanvas. The overlay canvas is
* inserted for displaying interactions. After the canvas elements
* are created, the elements are inserted into the container
* element.
*/
constructCanvas : function () {
var el = this.el, size, c, oc;
this.canvas = el.select('.flotr-canvas')[0];
this.overlay = el.select('.flotr-overlay')[0];
el.childElements().invoke('remove');
// For positioning labels and overlay.
el.setStyle({
position : 'relative',
cursor : 'default'
});
this.canvasWidth = el.getWidth();
this.canvasHeight = el.getHeight();
size = {
'width' : this.canvasWidth,
'height' : this.canvasHeight
};
if (this.canvasWidth <= 0 || this.canvasHeight <= 0) {
throw 'Invalid dimensions for plot, width = ' + this.canvasWidth + ', height = ' + this.canvasHeight;
}
// Insert main canvas.
if (!this.canvas) {
c = this.canvas = new Element('canvas', size);
c.className = 'flotr-canvas';
c = c.writeAttribute('style', 'position:absolute;left:0px;top:0px;');
} else {
c = this.canvas.writeAttribute(size);
}
el.insert(c);
if (Prototype.Browser.IE) {
c = window.G_vmlCanvasManager.initElement(c);
}
this.ctx = c.getContext('2d');
// Insert overlay canvas for interactive features.
if (!this.overlay) {
oc = this.overlay = new Element('canvas', size);
oc.className = 'flotr-overlay';
oc = oc.writeAttribute('style', 'position:absolute;left:0px;top:0px;');
} else {
oc = this.overlay.writeAttribute(size);
}
el.insert(oc);
if (Prototype.Browser.IE) {
oc = window.G_vmlCanvasManager.initElement(oc);
}
this.octx = oc.getContext('2d');
// Enable text functions
if (window.CanvasText) {
CanvasText.enable(this.ctx);
CanvasText.enable(this.octx);
this.textEnabled = true;
}
// Fill in with white
this.ctx.globalAlpha = 1.0;
this.ctx.fillStyle = '#FFFFFF';
this.ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
},
getTextDimensions : function (text, canvasStyle, HtmlStyle, className) {
if (!text)
return {
width : 0,
height : 0
};
if (!this.options.HtmlText && this.textEnabled) {
var bounds = this.ctx.getTextBounds(text, canvasStyle);
return {
width : bounds.width + 2,
height : bounds.height + 6
};
} else {
var dummyDiv = this.el.insert(
'<div style="position:absolute;top:-10000px;' + HtmlStyle + '" class="' + className + ' flotr-dummy-div">' + text + '</div>')
.select(".flotr-dummy-div")[0];
dim = dummyDiv.getDimensions();
dummyDiv.remove();
return dim;
}
},
loadDataGrid : function () {
if (this.seriesData)
return this.seriesData;
var s = this.series;
var dg = [];
/*
* The data grid is a 2 dimensions array. There is a row for
* each X value. Each row contains the x value and the
* corresponding y value for each serie ('undefined' if there
* isn't one)
*/
for (i = 0; i < s.length; ++i) {
s[i].data.each(function (v) {
var x = v[0], y = v[1];
if (r = dg.find(function (row) {
return row[0] == x;
})) {
r[i + 1] = y;
} else {
var newRow = [];
newRow[0] = x;
newRow[i + 1] = y;
dg.push(newRow);
}
});
}
// The data grid is sorted by x value
dg = dg.sortBy(function (v) {
return v[0];
});
return this.seriesData = dg;
},
// @todo: make a tab manager (Flotr.Tabs)
showTab : function (tabName, onComplete) {
var elementsClassNames = 'canvas, .flotr-labels, .flotr-legend, .flotr-legend-bg, .flotr-title, .flotr-subtitle';
switch (tabName) {
case 'graph':
this.datagrid.up().hide();
this.el.select(elementsClassNames).invoke('show');
this.tabs.data.removeClassName('selected');
this.tabs.graph.addClassName('selected');
break;
case 'data':
this.constructDataGrid();
this.datagrid.up().show();
this.el.select(elementsClassNames).invoke('hide');
this.tabs.data.addClassName('selected');
this.tabs.graph.removeClassName('selected');
break;
}
},
constructTabs : function () {
var tabsContainer = new Element('div', {
className : 'flotr-tabs-group',
style : 'position:absolute;left:0px;top:' + this.canvasHeight + 'px;width:' + this.canvasWidth + 'px;'
});
this.el.insert({
bottom : tabsContainer
});
this.tabs = {
graph : new Element('div', {
className : 'flotr-tab selected',
style : 'float:left;'
}).update(this.options.spreadsheet.tabGraphLabel),
data : new Element('div', {
className : 'flotr-tab',
style : 'float:left;'
}).update(this.options.spreadsheet.tabDataLabel)
};
tabsContainer.insert(this.tabs.graph).insert(this.tabs.data);
this.el.setStyle({
height : this.canvasHeight + this.tabs.data.getHeight() + 2 + 'px'
});
this.tabs.graph.observe('click', (function () {
this.showTab('graph');
}).bind(this));
this.tabs.data.observe('click', (function () {
this.showTab('data');
}).bind(this));
},
// @todo: make a spreadsheet manager (Flotr.Spreadsheet)
constructDataGrid : function () {
// If the data grid has already been built, nothing to do here
if (this.datagrid)
return this.datagrid;
var i, j, s = this.series, datagrid = this.loadDataGrid();
var t = this.datagrid = new Element('table', {
className : 'flotr-datagrid',
style : 'height:100px;'
});
var colgroup = [ '<colgroup><col />' ];
// First row : series' labels
var html = [ '<tr class="first-row">' ];
html.push('<th> </th>');
for (i = 0; i < s.length; ++i) {
html.push('<th scope="col">' + (s[i].label || String.fromCharCode(65 + i)) + '</th>');
colgroup.push('<col />');
}
html.push('</tr>');
// Data rows
for (j = 0; j < datagrid.length; ++j) {
html.push('<tr>');
for (i = 0; i < s.length + 1; ++i) {
var tag = 'td';
var content = (datagrid[j][i] != null ? Math.round(datagrid[j][i] * 100000) / 100000 : '');
if (i == 0) {
tag = 'th';
var label;
if (this.options.xaxis.ticks) {
var tick = this.options.xaxis.ticks.find(function (x) {
return x[0] == datagrid[j][i];
});
if (tick)
label = tick[1];
} else {
label = this.options.xaxis.tickFormatter(content);
}
if (label)
content = label;
}
html.push('<' + tag + (tag == 'th' ? ' scope="row"' : '') + '>' + content + '</' + tag + '>');
}
html.push('</tr>');
}
colgroup.push('</colgroup>');
t.update(colgroup.join('') + html.join(''));
if (!Prototype.Browser.IE) {
t.select('td').each(function (td) {
td.observe('mouseover', function (e) {
td = e.element();
var siblings = td.previousSiblings();
t.select('th[scope=col]')[siblings.length - 1].addClassName('hover');
t.select('colgroup col')[siblings.length].addClassName('hover');
});
td.observe('mouseout', function () {
t.select('colgroup col.hover, th.hover').each(function (e) {
e.removeClassName('hover');
});
});
});
}
var toolbar = new Element('div', {
className : 'flotr-datagrid-toolbar'
}).insert(new Element('button', {
type : 'button',
className : 'flotr-datagrid-toolbar-button'
}).update(this.options.spreadsheet.toolbarDownload).observe('click', this.downloadCSV.bind(this))).insert(new Element('button', {
type : 'button',
className : 'flotr-datagrid-toolbar-button'
}).update(this.options.spreadsheet.toolbarSelectAll).observe('click', this.selectAllData.bind(this)));
var container = new Element('div', {
className : 'flotr-datagrid-container',
style : 'left:0px;top:0px;width:' + this.canvasWidth + 'px;height:' + this.canvasHeight + 'px;overflow:auto;'
});
container.insert(toolbar);
t.wrap(container.hide());
this.el.insert(container);
return t;
},
selectAllData : function () {
if (this.tabs) {
var selection, range, doc, win, node = this.constructDataGrid();
this.showTab('data');
// deferred to be able to select the table
(function () {
if ((doc = node.ownerDocument) && (win = doc.defaultView) && win.getSelection && doc.createRange && (selection = window.getSelection())
&& selection.removeAllRanges) {
range = doc.createRange();
range.selectNode(node);
selection.removeAllRanges();
selection.addRange(range);
} else if (document.body && document.body.createTextRange && (range = document.body.createTextRange())) {
range.moveToElementText(node);
range.select();
}
}).defer();
return true;
} else
return false;
},
downloadCSV : function () {
var i, csv = '"x"', series = this.series, dg = this.loadDataGrid();
for (i = 0; i < series.length; ++i) {
csv += '%09"' + (series[i].label || String.fromCharCode(65 + i)) + '"'; // \t
}
csv += "%0D%0A"; // \r\n
for (i = 0; i < dg.length; ++i) {
if (this.options.xaxis.ticks) {
var tick = this.options.xaxis.ticks.find(function (x) {
return x[0] == dg[i][0];
});
if (tick)
dg[i][0] = tick[1];
} else {
dg[i][0] = this.options.xaxis.tickFormatter(dg[i][0]);
}
csv += dg[i].join('%09') + "%0D%0A"; // \t and \r\n
}
if (Prototype.Browser.IE) {
csv = csv.gsub('%09', '\t').gsub('%0A', '\n').gsub('%0D', '\r');
window.open().document.write(csv);
} else {
window.open('data:text/csv,' + csv);
}
},
/**
* Initializes event some handlers.
*/
initEvents : function () {
// @todo: maybe stopObserving with only flotr functions
this.overlay.stopObserving();
this.overlay.observe('mousedown', this.mouseDownHandler.bind(this));
this.overlay.observe('mousemove', this.mouseMoveHandler.bind(this));
this.overlay.observe('click', this.clickHandler.bind(this));
},
/**
* Function determines the min and max values for the xaxis and
* yaxis.
*/
findDataRanges : function () {
var s = this.series, a = this.axes;
a.x.datamin = 0;
a.x.datamax = 0;
a.x2.datamin = 0;
a.x2.datamax = 0;
a.y.datamin = 0;
a.y.datamax = 0;
a.y2.datamin = 0;
a.y2.datamax = 0;
if (s.length > 0) {
var i, j, h, x, y, data, xaxis, yaxis;
// Get datamin, datamax start values
for (i = 0; i < s.length; ++i) {
data = s[i].data, xaxis = s[i].xaxis, yaxis = s[i].yaxis;
if (data.length > 0 && !s[i].hide) {
if (!xaxis.used)
xaxis.datamin = xaxis.datamax = data[0][0];
if (!yaxis.used)
yaxis.datamin = yaxis.datamax = data[0][1];
xaxis.used = true;
yaxis.used = true;
for (h = data.length - 1; h > -1; --h) {
x = data[h][0];
if (x < xaxis.datamin)
xaxis.datamin = x;
else if (x > xaxis.datamax)
xaxis.datamax = x;
for (j = 1; j < 2; j++) {
// PATCH for(j = 1; j < data[h].length;
// j++){
y = data[h][j];
if (y < yaxis.datamin)
yaxis.datamin = y;
else if (y > yaxis.datamax)
yaxis.datamax = y;
}
}
}
}
}
this.findXAxesValues();
this.calculateRange(a.x);
this.extendXRangeIfNeededByBar(a.x);
if (a.x2.used) {
this.calculateRange(a.x2);
this.extendXRangeIfNeededByBar(a.x2);
}
this.calculateRange(a.y);
this.extendYRangeIfNeededByBar(a.y);
if (a.y2.used) {
this.calculateRange(a.y2);
this.extendYRangeIfNeededByBar(a.y2);
}
},
/**
* Calculates the range of an axis to apply autoscaling.
*/
calculateRange : function (axis) {
var o = axis.options, min = o.min != null ? o.min : axis.datamin, max = o.max != null ? o.max : axis.datamax, margin;
if (max - min == 0.0) {
var widen = (max == 0.0) ? 1.0 : 0.01;
min -= widen;
max += widen;
}
axis.tickSize = Flotr.getTickSize(o.noTicks, min, max, o.tickDecimals);
// Autoscaling.
if (o.min == null) {
// Add a margin.
margin = o.autoscaleMargin;
if (margin != 0) {
min -= axis.tickSize * margin;
// Make sure we don't go below zero if all values are
// positive.
if (min < 0 && axis.datamin >= 0)
min = 0;
min = axis.tickSize * Math.floor(min / axis.tickSize);
}
}
if (o.max == null) {
margin = o.autoscaleMargin;
if (margin != 0) {
max += axis.tickSize * margin;
if (max > 0 && axis.datamax <= 0)
max = 0;
max = axis.tickSize * Math.ceil(max / axis.tickSize);
}
}
axis.min = min;
axis.max = max;
},
/**
* Bar series autoscaling in x direction.
*/
extendXRangeIfNeededByBar : function (axis) {
if (axis.options.max == null) {
var newmax = axis.max, i, s, b, c, stackedSums = [], lastSerie = null;
for (i = 0; i < this.series.length; ++i) {
s = this.series[i];
b = s.bars;
c = s.candles;
if (s.axis == axis && (b.show || c.show)) {
if (!b.horizontal && (b.barWidth + axis.datamax > newmax) || (c.candleWidth + axis.datamax > newmax)) {
newmax = axis.max + s.bars.barWidth;
}
if (b.stacked && b.horizontal) {
for (j = 0; j < s.data.length; j++) {
if (s.bars.show && s.bars.stacked) {
var x = s.data[j][0];
stackedSums[x] = (stackedSums[x] || 0) + s.data[j][1];
lastSerie = s;
}
}
for (j = 0; j < stackedSums.length; j++) {
newmax = Math.max(stackedSums[j], newmax);
}
}
}
}
axis.lastSerie = lastSerie;
axis.max = newmax;
}
},
/**
* Bar series autoscaling in y direction.
*/
extendYRangeIfNeededByBar : function (axis) {
if (axis.options.max == null) {
var newmax = axis.max, i, s, b, c, stackedSums = [], lastSerie = null;
for (i = 0; i < this.series.length; ++i) {
s = this.series[i];
b = s.bars;
c = s.candles;
if (s.yaxis == axis && b.show && !s.hide) {
if (b.horizontal && (b.barWidth + axis.datamax > newmax) || (c.candleWidth + axis.datamax > newmax)) {
newmax = axis.max + b.barWidth;
}
if (b.stacked && !b.horizontal) {
for (j = 0; j < s.data.length; j++) {
if (s.bars.show && s.bars.stacked) {
var x = s.data[j][0];
stackedSums[x] = (stackedSums[x] || 0) + s.data[j][1];
lastSerie = s;
}
}
for (j = 0; j < stackedSums.length; j++) {
newmax = Math.max(stackedSums[j], newmax);
}
}
}
}
axis.lastSerie = lastSerie;
axis.max = newmax;
}
},
/**
* Find every values of the x axes
*/
findXAxesValues : function () {
for (i = this.series.length - 1; i > -1; --i) {
s = this.series[i];
s.xaxis.values = s.xaxis.values || [];
for (j = s.data.length - 1; j > -1; --j) {
s.xaxis.values[s.data[j][0]] = {};
}
}
},
/**
* Calculate axis ticks.
*
* @param {Object}
* axis - axis object
* @param {Object}
* o - axis options
*/
calculateTicks : function (axis) {
var o = axis.options, i, v;
axis.ticks = [];
if (o.ticks) {
var ticks = o.ticks, t, label;
if (Object.isFunction(ticks)) {
ticks = ticks({
min : axis.min,
max : axis.max
});
}
// Clean up the user-supplied ticks, copy them over.
for (i = 0; i < ticks.length; ++i) {
t = ticks[i];
if (typeof (t) == 'object') {
v = t[0];
label = (t.length > 1) ? t[1] : o.tickFormatter(v);
} else {
v = t;
label = o.tickFormatter(v);
}
axis.ticks[i] = {
v : v,
label : label
};
}
} else {
// Round to nearest multiple of tick size.
var start = axis.tickSize * Math.ceil(axis.min / axis.tickSize), decimals;
// Then store all possible ticks.
for (i = 0; start + i * axis.tickSize <= axis.max; ++i) {
v = start + i * axis.tickSize;
// Round (this is always needed to fix numerical
// instability).
decimals = o.tickDecimals;
if (decimals == null)
decimals = 1 - Math.floor(Math.log(axis.tickSize) / Math.LN10);
if (decimals < 0)
decimals = 0;
v = v.toFixed(decimals);
axis.ticks.push({
v : v,
label : o.tickFormatter(v)
});
}
}
},
/**
* Calculates axis label sizes.
*/
calculateSpacing : function () {
var a = this.axes, options = this.options, series = this.series, margin = options.grid.labelMargin, x = a.x, x2 = a.x2, y = a.y, y2 = a.y2, maxOutset = 2, i, j, l, dim;
// Labels width and height
[ x, x2, y, y2 ].each(function (axis) {
var maxLabel = '';
if (axis.options.showLabels) {
for (i = 0; i < axis.ticks.length; ++i) {
l = axis.ticks[i].label.length;
if (l > maxLabel.length) {
maxLabel = axis.ticks[i].label;
}
}
}
axis.maxLabel = this.getTextDimensions(maxLabel, {
size : options.fontSize,
angle : Flotr.toRad(axis.options.labelsAngle)
}, 'font-size:smaller;', 'flotr-grid-label');
axis.titleSize = this.getTextDimensions(axis.options.title, {
size : options.fontSize * 1.2,
angle : Flotr.toRad(axis.options.titleAngle)
}, 'font-weight:bold;', 'flotr-axis-title');
}, this);
// Title height
dim = this.getTextDimensions(options.title, {
size : options.fontSize * 1.5
}, 'font-size:1em;font-weight:bold;', 'flotr-title');
this.titleHeight = dim.height;
// Subtitle height
dim = this.getTextDimensions(options.subtitle, {
size : options.fontSize
}, 'font-size:smaller;', 'flotr-subtitle');
this.subtitleHeight = dim.height;
// Grid outline line width.
if (options.show) {
maxOutset = Math.max(maxOutset, options.points.radius + options.points.lineWidth / 2);
}
for (j = 0; j < options.length; ++j) {
if (series[j].points.show) {
maxOutset = Math.max(maxOutset, series[j].points.radius + series[j].points.lineWidth / 2);
}
}
var p = this.plotOffset = {
left : 0,
right : 0,
top : 0,
bottom : 0
};
p.left = p.right = p.top = p.bottom = maxOutset;
p.bottom += (x.options.showLabels ? (x.maxLabel.height + margin) : 0) + (x.options.title ? (x.titleSize.height + margin) : 0);
p.top += (x2.options.showLabels ? (x2.maxLabel.height + margin) : 0) + (x2.options.title ? (x2.titleSize.height + margin) : 0)
+ this.subtitleHeight + this.titleHeight;
p.left += (y.options.showLabels ? (y.maxLabel.width + margin) : 0) + (y.options.title ? (y.titleSize.width + margin) : 0);
p.right += (y2.options.showLabels ? (y2.maxLabel.width + margin) : 0) + (y2.options.title ? (y2.titleSize.width + margin) : 0);
p.top = Math.floor(p.top); // In order the outline not to be
// blured
this.plotWidth = this.canvasWidth - p.left - p.right;
this.plotHeight = this.canvasHeight - p.bottom - p.top;
x.scale = this.plotWidth / (x.max - x.min);
x2.scale = this.plotWidth / (x2.max - x2.min);
y.scale = this.plotHeight / (y.max - y.min);
y2.scale = this.plotHeight / (y2.max - y2.min);
},
/**
* Draws grid, labels and series.
*/
draw : function () {
this.drawGrid();
this.drawLabels();
this.drawTitles();
if (this.series.length) {
this.el.fire('flotr:beforedraw', [ this.series, this ]);
for ( var i = 0; i < this.series.length; i++) {
if (!this.series[i].hide)
this.drawSeries(this.series[i]);
}
}
this.el.fire('flotr:afterdraw', [ this.series, this ]);
},
/**
* Translates absolute horizontal x coordinates to relative
* coordinates.
*
* @param {Integer}
* x - absolute integer x coordinate
* @return {Integer} translated relative x coordinate
*/
tHoz : function (x, axis) {
axis = axis || this.axes.x;
return (x - axis.min) * axis.scale;
},
/**
* Translates absolute vertical x coordinates to relative
* coordinates.
*
* @param {Integer}
* y - absolute integer y coordinate
* @return {Integer} translated relative y coordinate
*/
tVert : function (y, axis) {
axis = axis || this.axes.y;
return this.plotHeight - (y - axis.min) * axis.scale;
},
/**
* Draws a grid for the graph.
*/
drawGrid : function () {
var v, o = this.options, ctx = this.ctx;
if (o.grid.verticalLines || o.grid.horizontalLines) {
this.el.fire('flotr:beforegrid', [ this.axes.x, this.axes.y, o, this ]);
}
ctx.save();
ctx.translate(this.plotOffset.left, this.plotOffset.top);
// Draw grid background, if present in options.
if (o.grid.backgroundColor != null) {
ctx.fillStyle = o.grid.backgroundColor;
ctx.fillRect(0, 0, this.plotWidth, this.plotHeight);
}
// Draw grid lines in vertical direction.
ctx.lineWidth = 1;
ctx.strokeStyle = o.grid.tickColor;
ctx.beginPath();
if (o.grid.verticalLines) {
for ( var i = 0; i < this.axes.x.ticks.length; ++i) {
v = this.axes.x.ticks[i].v;
// Don't show lines on upper and lower bounds.
if ((v == this.axes.x.min || v == this.axes.x.max) && o.grid.outlineWidth != 0)
continue;
ctx.moveTo(Math.floor(this.tHoz(v)) + ctx.lineWidth / 2, 0);
ctx.lineTo(Math.floor(this.tHoz(v)) + ctx.lineWidth / 2, this.plotHeight);
}
}
// Draw grid lines in horizontal direction.
if (o.grid.horizontalLines) {
for ( var j = 0; j < this.axes.y.ticks.length; ++j) {
v = this.axes.y.ticks[j].v;
// Don't show lines on upper and lower bounds.
if ((v == this.axes.y.min || v == this.axes.y.max) && o.grid.outlineWidth != 0)
continue;
ctx.moveTo(0, Math.floor(this.tVert(v)) + ctx.lineWidth / 2);
ctx.lineTo(this.plotWidth, Math.floor(this.tVert(v)) + ctx.lineWidth / 2);
}
}
ctx.stroke();
// Draw axis/grid border.
if (o.grid.outlineWidth != 0) {
ctx.lineWidth = o.grid.outlineWidth;
ctx.strokeStyle = o.grid.color;
ctx.lineJoin = 'round';
ctx.strokeRect(0, 0, this.plotWidth, this.plotHeight);
}
ctx.restore();
if (o.grid.verticalLines || o.grid.horizontalLines) {
this.el.fire('flotr:aftergrid', [ this.axes.x, this.axes.y, o, this ]);
}
},
/**
* Draws labels for x and y axis.
*/
drawLabels : function () {
// Construct fixed width label boxes, which can be styled
// easily.
var noLabels = 0, axis, xBoxWidth, i, html, tick, options = this.options, ctx = this.ctx, a = this.axes;
for (i = 0; i < a.x.ticks.length; ++i) {
if (a.x.ticks[i].label) {
++noLabels;
}
}
xBoxWidth = this.plotWidth / noLabels;
if (!options.HtmlText && this.textEnabled) {
var style = {
size : options.fontSize,
adjustAlign : true
};
// Add x labels.
axis = a.x;
style.color = axis.options.color || options.grid.color;
for (i = 0; i < axis.ticks.length && axis.options.showLabels && axis.used; ++i) {
tick = axis.ticks[i];
if (!tick.label || tick.label.length == 0)
continue;
style.angle = Flotr.toRad(axis.options.labelsAngle);
style.halign = 'c';
style.valign = 't';
ctx.drawText(tick.label, this.plotOffset.left + this.tHoz(tick.v, axis), this.plotOffset.top + this.plotHeight
+ options.grid.labelMargin, style);
}
// Add x2 labels.
axis = a.x2;
style.color = axis.options.color || options.grid.color;
for (i = 0; i < axis.ticks.length && axis.options.showLabels && axis.used; ++i) {
tick = axis.ticks[i];
if (!tick.label || tick.label.length == 0)
continue;
style.angle = Flotr.toRad(axis.options.labelsAngle);
style.halign = 'c';
style.valign = 'b';
ctx.drawText(tick.label, this.plotOffset.left + this.tHoz(tick.v, axis), this.plotOffset.top + options.grid.labelMargin, style);
}
// Add y labels.
axis = a.y;
style.color = axis.options.color || options.grid.color;
for (i = 0; i < axis.ticks.length && axis.options.showLabels && axis.used; ++i) {
tick = axis.ticks[i];
if (!tick.label || tick.label.length == 0)
continue;
style.angle = Flotr.toRad(axis.options.labelsAngle);
style.halign = 'r';
style.valign = 'm';
ctx.drawText(tick.label, this.plotOffset.left - options.grid.labelMargin, this.plotOffset.top + this.tVert(tick.v, axis), style);
}
// Add y2 labels.
axis = a.y2;
style.color = axis.options.color || options.grid.color;
for (i = 0; i < axis.ticks.length && axis.options.showLabels && axis.used; ++i) {
tick = axis.ticks[i];
if (!tick.label || tick.label.length == 0)
continue;
style.angle = Flotr.toRad(axis.options.labelsAngle);
style.halign = 'l';
style.valign = 'm';
ctx.drawText(tick.label, this.plotOffset.left + this.plotWidth + options.grid.labelMargin, this.plotOffset.top
+ this.tVert(tick.v, axis), style);
ctx.save();
ctx.strokeStyle = style.color;
ctx.beginPath();
ctx.moveTo(this.plotOffset.left + this.plotWidth - 8, this.plotOffset.top + this.tVert(tick.v, axis));
ctx.lineTo(this.plotOffset.left + this.plotWidth, this.plotOffset.top + this.tVert(tick.v, axis));
ctx.stroke();
ctx.restore();
}
} else if (a.x.options.showLabels || a.x2.options.showLabels || a.y.options.showLabels || a.y2.options.showLabels) {
html = [ '<div style="font-size:smaller;color:' + options.grid.color + ';" class="flotr-labels">' ];
// Add x labels.
axis = a.x;
if (axis.options.showLabels) {
for (i = 0; i < axis.ticks.length; ++i) {
tick = axis.ticks[i];
if (!tick.label || tick.label.length == 0)
continue;
html
.push('<div style="position:absolute;top:' + (this.plotOffset.top + this.plotHeight + options.grid.labelMargin)
+ 'px;left:' + (this.plotOffset.left + this.tHoz(tick.v, axis) - xBoxWidth / 2) + 'px;width:' + xBoxWidth
+ 'px;text-align:center;' + (axis.options.color ? ('color:' + axis.options.color + ';') : '')
+ '" class="flotr-grid-label">' + tick.label + '</div>');
}
}
// Add x2 labels.
axis = a.x2;
if (axis.options.showLabels && axis.used) {
for (i = 0; i < axis.ticks.length; ++i) {
tick = axis.ticks[i];
if (!tick.label || tick.label.length == 0)
continue;
html.push('<div style="position:absolute;top:' + (this.plotOffset.top - options.grid.labelMargin - axis.maxLabel.height)
+ 'px;left:' + (this.plotOffset.left + this.tHoz(tick.v, axis) - xBoxWidth / 2) + 'px;width:' + xBoxWidth
+ 'px;text-align:center;' + (axis.options.color ? ('color:' + axis.options.color + ';') : '')
+ '" class="flotr-grid-label">' + tick.label + '</div>');
}
}
// Add y labels.
axis = a.y;
if (axis.options.showLabels) {
for (i = 0; i < axis.ticks.length; ++i) {
tick = axis.ticks[i];
if (!tick.label || tick.label.length == 0)
continue;
html
.push('<div style="position:absolute;top:' + (this.plotOffset.top + this.tVert(tick.v, axis) - axis.maxLabel.height / 2)
+ 'px;left:0;width:' + (this.plotOffset.left - options.grid.labelMargin) + 'px;text-align:right;'
+ (axis.options.color ? ('color:' + axis.options.color + ';') : '') + '" class="flotr-grid-label">' + tick.label
+ '</div>');
}
}
// Add y2 labels.
axis = a.y2;
if (axis.options.showLabels && axis.used) {
ctx.save();
ctx.strokeStyle = axis.options.color || options.grid.color;
ctx.beginPath();
for (i = 0; i < axis.ticks.length; ++i) {
tick = axis.ticks[i];
if (!tick.label || tick.label.length == 0)
continue;
html
.push('<div style="position:absolute;top:' + (this.plotOffset.top + this.tVert(tick.v, axis) - axis.maxLabel.height / 2)
+ 'px;right:0;width:' + (this.plotOffset.right - options.grid.labelMargin) + 'px;text-align:left;'
+ (axis.options.color ? ('color:' + axis.options.color + ';') : '') + '" class="flotr-grid-label">' + tick.label
+ '</div>');
ctx.moveTo(this.plotOffset.left + this.plotWidth - 8, this.plotOffset.top + this.tVert(tick.v, axis));
ctx.lineTo(this.plotOffset.left + this.plotWidth, this.plotOffset.top + this.tVert(tick.v, axis));
}
ctx.stroke();
ctx.restore();
}
html.push('</div>');
this.el.insert(html.join(''));
}
},
/**
* Draws the title and the subtitle
*/
drawTitles : function () {
var html, options = this.options, margin = options.grid.labelMargin, ctx = this.ctx, a = this.axes;
if (!options.HtmlText && this.textEnabled) {
var style = {
size : options.fontSize,
color : options.grid.color,
halign : 'c'
};
// Add subtitle
if (options.subtitle) {
ctx.drawText(options.subtitle, this.plotOffset.left + this.plotWidth / 2, this.titleHeight + this.subtitleHeight - 2, style);
}
style.weight = 1.5;
style.size *= 1.5;
// Add title
if (options.title) {
ctx.drawText(options.title, this.plotOffset.left + this.plotWidth / 2, this.titleHeight - 2, style);
}
style.weight = 1.8;
style.size *= 0.8;
style.adjustAlign = true;
// Add x axis title
if (a.x.options.title && a.x.used) {
style.halign = 'c';
style.valign = 't';
style.angle = Flotr.toRad(a.x.options.titleAngle);
ctx.drawText(a.x.options.title, this.plotOffset.left + this.plotWidth / 2, this.plotOffset.top + a.x.maxLabel.height + this.plotHeight
+ 2 * margin, style);
}
// Add x2 axis title
if (a.x2.options.title && a.x2.used) {
style.halign = 'c';
style.valign = 'b';
style.angle = Flotr.toRad(a.x2.options.titleAngle);
ctx.drawText(a.x2.options.title, this.plotOffset.left + this.plotWidth / 2, this.plotOffset.top - a.x2.maxLabel.height - 2 * margin,
style);
}
// Add y axis title
if (a.y.options.title && a.y.used) {
style.halign = 'r';
style.valign = 'm';
style.angle = Flotr.toRad(a.y.options.titleAngle);
ctx.drawText(a.y.options.title, this.plotOffset.left - a.y.maxLabel.width - 2 * margin, this.plotOffset.top + this.plotHeight / 2,
style);
}
// Add y2 axis title
if (a.y2.options.title && a.y2.used) {
style.halign = 'l';
style.valign = 'm';
style.angle = Flotr.toRad(a.y2.options.titleAngle);
ctx.drawText(a.y2.options.title, this.plotOffset.left + this.plotWidth + a.y2.maxLabel.width + 2 * margin, this.plotOffset.top
+ this.plotHeight / 2, style);
}
} else {
html = [ '<div style="color:' + options.grid.color + ';" class="flotr-titles">' ];
// Add title
if (options.title) {
html.push('<div style="position:absolute;top:0;left:' + this.plotOffset.left
+ 'px;font-size:1em;font-weight:bold;text-align:center;width:' + this.plotWidth + 'px;" class="flotr-title">' + options.title
+ '</div>');
}
// Add subtitle
if (options.subtitle) {
html.push('<div style="position:absolute;top:' + this.titleHeight + 'px;left:' + this.plotOffset.left
+ 'px;font-size:smaller;text-align:center;width:' + this.plotWidth + 'px;" class="flotr-subtitle">' + options.subtitle
+ '</div>');
}
html.push('</div>');
html.push('<div class="flotr-axis-title" style="font-weight:bold;">');
// Add x axis title
if (a.x.options.title && a.x.used) {
html.push('<div style="position:absolute;top:'
+ (this.plotOffset.top + this.plotHeight + options.grid.labelMargin + a.x.titleSize.height) + 'px;left:' + this.plotOffset.left
+ 'px;width:' + this.plotWidth + 'px;text-align:center;" class="flotr-axis-title">' + a.x.options.title + '</div>');
}
// Add x2 axis title
if (a.x2.options.title && a.x2.used) {
html.push('<div style="position:absolute;top:0;left:' + this.plotOffset.left + 'px;width:' + this.plotWidth
+ 'px;text-align:center;" class="flotr-axis-title">' + a.x2.options.title + '</div>');
}
// Add y axis title
if (a.y.options.title && a.y.used) {
html.push('<div style="position:absolute;top:' + (this.plotOffset.top + this.plotHeight / 2 - a.y.titleSize.height / 2)
+ 'px;left:0;text-align:right;" class="flotr-axis-title">' + a.y.options.title + '</div>');
}
// Add y2 axis title
if (a.y2.options.title && a.y2.used) {
html.push('<div style="position:absolute;top:' + (this.plotOffset.top + this.plotHeight / 2 - a.y.titleSize.height / 2)
+ 'px;right:0;text-align:right;" class="flotr-axis-title">' + a.y2.options.title + '</div>');
}
html.push('</div>');
this.el.insert(html.join(''));
}
},
/**
* Actually draws the graph.
*
* @param {Object}
* series - series to draw
*/
drawSeries : function (series) {
series = series || this.series;
var drawn = false;
for ( var type in Flotr._registeredTypes) {
if (series[type] && series[type].show) {
this[Flotr._registeredTypes[type]](series);
drawn = true;
}
}
if (!drawn) {
this[Flotr._registeredTypes[this.options.defaultType]](series);
}
},
plotLine : function (series, offset) {
var ctx = this.ctx, xa = series.xaxis, ya = series.yaxis, tHoz = this.tHoz.bind(this), tVert = this.tVert.bind(this), data = series.data;
if (data.length < 2)
return;
var prevx = tHoz(data[0][0], xa), prevy = tVert(data[0][1], ya) + offset;
ctx.beginPath();
ctx.moveTo(prevx, prevy);
for ( var i = 0; i < data.length - 1; ++i) {
var x1 = data[i][0], y1 = data[i][1], x2 = data[i + 1][0], y2 = data[i + 1][1];
// To allow empty values
if (y1 === null || y2 === null)
continue;
/**
* Clip with ymin.
*/
if (y1 <= y2 && y1 < ya.min) {
/**
* Line segment is outside the drawing area.
*/
if (y2 < ya.min)
continue;
/**
* Compute new intersection point.
*/
x1 = (ya.min - y1) / (y2 - y1) * (x2 - x1) + x1;
y1 = ya.min;
} else if (y2 <= y1 && y2 < ya.min) {
if (y1 < ya.min)
continue;
x2 = (ya.min - y1) / (y2 - y1) * (x2 - x1) + x1;
y2 = ya.min;
}
/**
* Clip with ymax.
*/
if (y1 >= y2 && y1 > ya.max) {
if (y2 > ya.max)
continue;
x1 = (ya.max - y1) / (y2 - y1) * (x2 - x1) + x1;
y1 = ya.max;
} else if (y2 >= y1 && y2 > ya.max) {
if (y1 > ya.max)
continue;
x2 = (ya.max - y1) / (y2 - y1) * (x2 - x1) + x1;
y2 = ya.max;
}
/**
* Clip with xmin.
*/
if (x1 <= x2 && x1 < xa.min) {
if (x2 < xa.min)
continue;
y1 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;
x1 = xa.min;
} else if (x2 <= x1 && x2 < xa.min) {
if (x1 < xa.min)
continue;
y2 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;
x2 = xa.min;
}
/**
* Clip with xmax.
*/
if (x1 >= x2 && x1 > xa.max) {
if (x2 > xa.max)
continue;
y1 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;
x1 = xa.max;
} else if (x2 >= x1 && x2 > xa.max) {
if (x1 > xa.max)
continue;
y2 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;
x2 = xa.max;
}
if (prevx != tHoz(x1, xa) || prevy != tVert(y1, ya) + offset)
ctx.moveTo(tHoz(x1, xa), tVert(y1, ya) + offset);
prevx = tHoz(x2, xa);
prevy = tVert(y2, ya) + offset;
ctx.lineTo(prevx, prevy);
}
ctx.stroke();
},
/**
* Function used to fill
*
* @param {Object}
* data
*/
plotLineArea : function (series, offset) {
var data = series.data;
if (data.length < 2)
return;
var top, lastX = 0, ctx = this.ctx, xa = series.xaxis, ya = series.yaxis, tHoz = this.tHoz.bind(this), tVert = this.tVert.bind(this), bottom = Math
.min(Math.max(0, ya.min), ya.max), first = true;
ctx.beginPath();
for ( var i = 0; i < data.length - 1; ++i) {
var x1 = data[i][0], y1 = data[i][1], x2 = data[i + 1][0], y2 = data[i + 1][1];
if (x1 <= x2 && x1 < xa.min) {
if (x2 < xa.min)
continue;
y1 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;
x1 = xa.min;
} else if (x2 <= x1 && x2 < xa.min) {
if (x1 < xa.min)
continue;
y2 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;
x2 = xa.min;
}
if (x1 >= x2 && x1 > xa.max) {
if (x2 > xa.max)
continue;
y1 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;
x1 = xa.max;
} else if (x2 >= x1 && x2 > xa.max) {
if (x1 > xa.max)
continue;
y2 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;
x2 = xa.max;
}
if (first) {
ctx.moveTo(tHoz(x1, xa), tVert(bottom, ya) + offset);
first = false;
}
/**
* Now check the case where both is outside.
*/
if (y1 >= ya.max && y2 >= ya.max) {
ctx.lineTo(tHoz(x1, xa), tVert(ya.max, ya) + offset);
ctx.lineTo(tHoz(x2, xa), tVert(ya.max, ya) + offset);
continue;
} else if (y1 <= ya.min && y2 <= ya.min) {
ctx.lineTo(tHoz(x1, xa), tVert(ya.min, ya) + offset);
ctx.lineTo(tHoz(x2, xa), tVert(ya.min, ya) + offset);
continue;
}
/**
* Else it's a bit more complicated, there might be two
* rectangles and two triangles we need to fill in; to find
* these keep track of the current x values.
*/
var x1old = x1, x2old = x2;
/**
* And clip the y values, without shortcutting. Clip with
* ymin.
*/
if (y1 <= y2 && y1 < ya.min && y2 >= ya.min) {
x1 = (ya.min - y1) / (y2 - y1) * (x2 - x1) + x1;
y1 = ya.min;
} else if (y2 <= y1 && y2 < ya.min && y1 >= ya.min) {
x2 = (ya.min - y1) / (y2 - y1) * (x2 - x1) + x1;
y2 = ya.min;
}
/**
* Clip with ymax.
*/
if (y1 >= y2 && y1 > ya.max && y2 <= ya.max) {
x1 = (ya.max - y1) / (y2 - y1) * (x2 - x1) + x1;
y1 = ya.max;
} else if (y2 >= y1 && y2 > ya.max && y1 <= ya.max) {
x2 = (ya.max - y1) / (y2 - y1) * (x2 - x1) + x1;
y2 = ya.max;
}
/**
* If the x value was changed we got a rectangle to fill.
*/
if (x1 != x1old) {
top = (y1 <= ya.min) ? top = ya.min : ya.max;
ctx.lineTo(tHoz(x1old, xa), tVert(top, ya) + offset);
ctx.lineTo(tHoz(x1, xa), tVert(top, ya) + offset);
}
/**
* Fill the triangles.
*/
ctx.lineTo(tHoz(x1, xa), tVert(y1, ya) + offset);
ctx.lineTo(tHoz(x2, xa), tVert(y2, ya) + offset);
/**
* Fill the other rectangle if it's there.
*/
if (x2 != x2old) {
top = (y2 <= ya.min) ? ya.min : ya.max;
ctx.lineTo(tHoz(x2old, xa), tVert(top, ya) + offset);
ctx.lineTo(tHoz(x2, xa), tVert(top, ya) + offset);
}
lastX = Math.max(x2, x2old);
}
ctx.lineTo(tHoz(lastX, xa), tVert(bottom, ya) + offset);
ctx.closePath();
ctx.fill();
},
/**
* Function: (private) drawSeriesLines
*
* Function draws lines series in the canvas element.
*
* Parameters: series - Series with options.lines.show = true.
*
* Returns: void
*/
drawSeriesLines : function (series) {
series = series || this.series;
var ctx = this.ctx;
ctx.save();
ctx.translate(this.plotOffset.left, this.plotOffset.top);
ctx.lineJoin = 'round';
var lw = series.lines.lineWidth;
var sw = series.shadowSize;
if (sw > 0) {
ctx.lineWidth = sw / 2;
var offset = lw / 2 + ctx.lineWidth / 2;
ctx.strokeStyle = "rgba(0,0,0,0.1)";
this.plotLine(series, offset + sw / 2);
ctx.strokeStyle = "rgba(0,0,0,0.2)";
this.plotLine(series, offset);
if (series.lines.fill) {
ctx.fillStyle = "rgba(0,0,0,0.05)";
this.plotLineArea(series, offset + sw / 2);
}
}
ctx.lineWidth = lw;
ctx.strokeStyle = series.color;
if (series.lines.fill) {
ctx.fillStyle = series.lines.fillColor != null ? series.lines.fillColor : Flotr.parseColor(series.color).scale(null, null, null,
series.lines.fillOpacity).toString();
this.plotLineArea(series, 0);
}
this.plotLine(series, 0);
ctx.restore();
},
/**
* Function: drawSeriesPoints
*
* Function draws point series in the canvas element.
*
* Parameters: series - Series with options.points.show = true.
*
* Returns: void
*/
drawSeriesPoints : function (series) {
var ctx = this.ctx;
ctx.save();
ctx.translate(this.plotOffset.left, this.plotOffset.top);
var lw = series.lines.lineWidth;
var sw = series.shadowSize;
if (sw > 0) {
ctx.lineWidth = sw / 2;
ctx.strokeStyle = 'rgba(0,0,0,0.1)';
this.plotPointShadows(series, sw / 2 + ctx.lineWidth / 2, series.points.radius);
ctx.strokeStyle = 'rgba(0,0,0,0.2)';
this.plotPointShadows(series, ctx.lineWidth / 2, series.points.radius);
}
ctx.lineWidth = series.points.lineWidth;
ctx.strokeStyle = series.color;
ctx.fillStyle = series.points.fillColor != null ? series.points.fillColor : series.color;
this.plotPoints(series, series.points.radius, series.points.fill);
ctx.restore();
},
plotPoints : function (series, radius, fill) {
var xa = series.xaxis, ya = series.yaxis, ctx = this.ctx, i, data = series.data;
for (i = data.length - 1; i > -1; --i) {
var x = data[i][0], y = data[i][1];
if (x < xa.min || x > xa.max || y < ya.min || y > ya.max)
continue;
ctx.beginPath();
ctx.arc(this.tHoz(x, xa), this.tVert(y, ya), radius, 0, 2 * Math.PI, true);
if (fill)
ctx.fill();
ctx.stroke();
}
},
plotPointShadows : function (series, offset, radius) {
var xa = series.xaxis, ya = series.yaxis, ctx = this.ctx, i, data = series.data;
for (i = data.length - 1; i > -1; --i) {
var x = data[i][0], y = data[i][1];
if (x < xa.min || x > xa.max || y < ya.min || y > ya.max)
continue;
ctx.beginPath();
ctx.arc(this.tHoz(x, xa), this.tVert(y, ya) + offset, radius, 0, Math.PI, false);
ctx.stroke();
}
},
/**
* Function: drawSeriesBars
*
* Function draws bar series in the canvas element.
*
* Parameters: series - Series with options.bars.show = true.
*
* Returns: void
*/
drawSeriesBars : function (series) {
var ctx = this.ctx, bw = series.bars.barWidth, lw = Math.min(series.bars.lineWidth, bw);
ctx.save();
ctx.translate(this.plotOffset.left, this.plotOffset.top);
ctx.lineJoin = 'miter';
/**
* @todo linewidth not interpreted the right way.
*/
ctx.lineWidth = lw;
ctx.strokeStyle = series.color;
this.plotBarsShadows(series, bw, 0, series.bars.fill);
if (series.bars.fill) {
ctx.fillStyle = series.bars.fillColor != null ? series.bars.fillColor : Flotr.parseColor(series.color).scale(null, null, null,
series.bars.fillOpacity).toString();
}
this.plotBars(series, bw, 0, series.bars.fill);
ctx.restore();
},
plotBars : function (series, barWidth, offset, fill) {
var data = series.data;
if (data.length < 1)
return;
var xa = series.xaxis, ya = series.yaxis, ctx = this.ctx, tHoz = this.tHoz.bind(this), tVert = this.tVert.bind(this);
for ( var i = 0; i < data.length; i++) {
var x = data[i][0], y = data[i][1];
var drawLeft = true, drawTop = true, drawRight = true;
// Stacked bars
var stackOffset = 0;
if (series.bars.stacked) {
xa.values.each(function (o, v) {
if (v == x) {
stackOffset = o.stack || 0;
o.stack = stackOffset + y;
}
});
}
// @todo: fix horizontal bars support
// Horizontal bars
if (series.bars.horizontal)
var left = stackOffset, right = x + stackOffset, bottom = y, top = y + barWidth;
else
var left = x, right = x + barWidth, bottom = stackOffset, top = y + stackOffset;
if (right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)
continue;
if (left < xa.min) {
left = xa.min;
drawLeft = false;
}
if (right > xa.max) {
right = xa.max;
if (xa.lastSerie != series && series.bars.horizontal)
drawTop = false;
}
if (bottom < ya.min)
bottom = ya.min;
if (top > ya.max) {
top = ya.max;
if (ya.lastSerie != series && !series.bars.horizontal)
drawTop = false;
}
/**
* Fill the bar.
*/
if (fill) {
ctx.beginPath();
ctx.moveTo(tHoz(left, xa), tVert(bottom, ya) + offset);
ctx.lineTo(tHoz(left, xa), tVert(top, ya) + offset);
ctx.lineTo(tHoz(right, xa), tVert(top, ya) + offset);
ctx.lineTo(tHoz(right, xa), tVert(bottom, ya) + offset);
ctx.fill();
}
/**
* Draw bar outline/border.
*/
if (series.bars.lineWidth != 0 && (drawLeft || drawRight || drawTop)) {
ctx.beginPath();
ctx.moveTo(tHoz(left, xa), tVert(bottom, ya) + offset);
ctx[drawLeft ? 'lineTo' : 'moveTo'](tHoz(left, xa), tVert(top, ya) + offset);
ctx[drawTop ? 'lineTo' : 'moveTo'](tHoz(right, xa), tVert(top, ya) + offset);
ctx[drawRight ? 'lineTo' : 'moveTo'](tHoz(right, xa), tVert(bottom, ya) + offset);
ctx.stroke();
}
}
},
plotBarsShadows : function (series, barWidth, offset) {
var data = series.data;
if (data.length < 1)
return;
var xa = series.xaxis, ya = series.yaxis, ctx = this.ctx, tHoz = this.tHoz.bind(this), tVert = this.tVert.bind(this), sw = this.options.shadowSize;
for ( var i = 0; i < data.length; i++) {
var x = data[i][0], y = data[i][1];
// Stacked bars
var stackOffset = 0;
if (series.bars.stacked) {
xa.values.each(function (o, v) {
if (v == x) {
stackOffset = o.stackShadow || 0;
o.stackShadow = stackOffset + y;
}
});
}
// Horizontal bars
if (series.bars.horizontal)
var left = stackOffset, right = x + stackOffset, bottom = y, top = y + barWidth;
else
var left = x, right = x + barWidth, bottom = stackOffset, top = y + stackOffset;
if (right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)
continue;
if (left < xa.min)
left = xa.min;
if (right > xa.max)
right = xa.max;
if (bottom < ya.min)
bottom = ya.min;
if (top > ya.max)
top = ya.max;
var width = tHoz(right, xa) - tHoz(left, xa) - ((tHoz(right, xa) + sw <= this.plotWidth) ? 0 : sw);
var height = Math.max(0, tVert(bottom, ya) - tVert(top, ya) - ((tVert(bottom, ya) + sw <= this.plotHeight) ? 0 : sw));
ctx.fillStyle = 'rgba(0,0,0,0.05)';
ctx.fillRect(Math.min(tHoz(left, xa) + sw, this.plotWidth), Math.min(tVert(top, ya) + sw, this.plotWidth), width, height);
}
},
/**
* Function: drawSeriesCandles
*
* Function draws candles series in the canvas element.
*
* Parameters: series - Series with options.candles.show = true.
*
* Returns: void
*/
drawSeriesCandles : function (series) {
var ctx = this.ctx, bw = series.candles.candleWidth;
ctx.save();
ctx.translate(this.plotOffset.left, this.plotOffset.top);
ctx.lineJoin = 'miter';
/**
* @todo linewidth not interpreted the right way.
*/
ctx.lineWidth = series.candles.lineWidth;
this.plotCandlesShadows(series, bw / 2);
this.plotCandles(series, bw / 2);
ctx.restore();
},
plotCandles : function (series, offset) {
var data = series.data;
if (data.length < 1)
return;
var xa = series.xaxis, ya = series.yaxis, ctx = this.ctx, tHoz = this.tHoz.bind(this), tVert = this.tVert.bind(this);
for ( var i = 0; i < data.length; i++) {
var d = data[i], x = d[0], open = d[1], high = d[2], low = d[3], close = d[4];
var left = x, right = x + series.candles.candleWidth, bottom = Math.max(ya.min, low), top = Math.min(ya.max, high), bottom2 = Math.max(
ya.min, Math.min(open, close)), top2 = Math.min(ya.max, Math.max(open, close));
if (right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)
continue;
var color = series.candles[open > close ? 'downFillColor' : 'upFillColor'];
/**
* Fill the candle.
*/
if (series.candles.fill && !series.candles.barcharts) {
ctx.fillStyle = Flotr.parseColor(color).scale(null, null, null, series.candles.fillOpacity).toString();
ctx.fillRect(tHoz(left, xa), tVert(top2, ya) + offset, tHoz(right, xa) - tHoz(left, xa), tVert(bottom2, ya) - tVert(top2, ya));
}
/**
* Draw candle outline/border, high, low.
*/
if (series.candles.lineWidth || series.candles.wickLineWidth) {
var x, y, pixelOffset = (series.candles.wickLineWidth % 2) / 2;
x = Math.floor(tHoz((left + right) / 2), xa) + pixelOffset;
ctx.save();
ctx.strokeStyle = color;
ctx.lineWidth = series.candles.wickLineWidth;
ctx.lineCap = 'butt';
if (series.candles.barcharts) {
ctx.beginPath();
ctx.moveTo(x, Math.floor(tVert(top, ya) + offset));
ctx.lineTo(x, Math.floor(tVert(bottom, ya) + offset));
y = Math.floor(tVert(open, ya) + offset) + 0.5;
ctx.moveTo(Math.floor(tHoz(left, xa)) + pixelOffset, y);
ctx.lineTo(x, y);
y = Math.floor(tVert(close, ya) + offset) + 0.5;
ctx.moveTo(Math.floor(tHoz(right, xa)) + pixelOffset, y);
ctx.lineTo(x, y);
} else {
ctx.strokeRect(tHoz(left, xa), tVert(top2, ya) + offset, tHoz(right, xa) - tHoz(left, xa), tVert(bottom2, ya) - tVert(top2, ya));
ctx.beginPath();
ctx.moveTo(x, Math.floor(tVert(top2, ya) + offset));
ctx.lineTo(x, Math.floor(tVert(top, ya) + offset));
ctx.moveTo(x, Math.floor(tVert(bottom2, ya) + offset));
ctx.lineTo(x, Math.floor(tVert(bottom, ya) + offset));
}
ctx.stroke();
ctx.restore();
}
}
},
plotCandlesShadows : function (series, offset) {
var data = series.data;
if (data.length < 1 || series.candles.barcharts)
return;
var xa = series.xaxis, ya = series.yaxis, tHoz = this.tHoz.bind(this), tVert = this.tVert.bind(this), sw = this.options.shadowSize;
for ( var i = 0; i < data.length; i++) {
var d = data[i], x = d[0], open = d[1], high = d[2], low = d[3], close = d[4];
var left = x, right = x + series.candles.candleWidth, bottom = Math.max(ya.min, Math.min(open, close)), top = Math.min(ya.max, Math.max(
open, close));
if (right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)
continue;
var width = tHoz(right, xa) - tHoz(left, xa) - ((tHoz(right, xa) + sw <= this.plotWidth) ? 0 : sw);
var height = Math.max(0, tVert(bottom, ya) - tVert(top, ya) - ((tVert(bottom, ya) + sw <= this.plotHeight) ? 0 : sw));
this.ctx.fillStyle = 'rgba(0,0,0,0.05)';
this.ctx.fillRect(Math.min(tHoz(left, xa) + sw, this.plotWidth), Math.min(tVert(top, ya) + sw, this.plotWidth), width, height);
}
},
/**
* Function: drawSeriesPie
*
* Function draws a pie in the canvas element.
*
* Parameters: series - Series with options.pie.show = true.
*
* Returns: void
*/
drawSeriesPie : function (series) {
if (!this.options.pie.drawn) {
var ctx = this.ctx, options = this.options, lw = series.pie.lineWidth, sw = series.shadowSize, data = series.data, radius = (Math.min(
this.canvasWidth, this.canvasHeight) * series.pie.sizeRatio) / 2, html = [];
var vScale = 1;// Math.cos(series.pie.viewAngle);
var plotTickness = Math.sin(series.pie.viewAngle) * series.pie.spliceThickness / vScale;
var style = {
size : options.fontSize * 1.2,
color : options.grid.color,
weight : 1.5
};
var center = {
x : (this.canvasWidth + this.plotOffset.left) / 2,
y : (this.canvasHeight - this.plotOffset.bottom) / 2
};
// Pie portions
var portions = this.series.collect(function (hash, index) {
if (hash.pie.show)
return {
name : (hash.label || hash.data[0][1]),
value : [ index, hash.data[0][1] ],
explode : hash.pie.explode
};
});
// Sum of the portions' angles
var sum = portions.pluck('value').pluck(1).inject(0, function (acc, n) {
return acc + n;
});
var fraction = 0.0, angle = series.pie.startAngle, value = 0.0;
var slices = portions.collect(function (slice) {
angle += fraction;
value = parseFloat(slice.value[1]); // @warning : won't
// support null
// values !!
fraction = value / sum;
return {
name : slice.name,
fraction : fraction,
x : slice.value[0],
y : value,
explode : slice.explode,
startAngle : 2 * angle * Math.PI,
endAngle : 2 * (angle + fraction) * Math.PI
};
});
ctx.save();
if (sw > 0) {
slices.each(function (slice) {
var bisection = (slice.startAngle + slice.endAngle) / 2;
var xOffset = center.x + Math.cos(bisection) * slice.explode + sw;
var yOffset = center.y + Math.sin(bisection) * slice.explode + sw;
this.plotSlice(xOffset, yOffset, radius, slice.startAngle, slice.endAngle, false, vScale);
ctx.fillStyle = 'rgba(0,0,0,0.1)';
ctx.fill();
}, this);
}
if (options.HtmlText) {
html = [ '<div style="color:' + this.options.grid.color + '" class="flotr-labels">' ];
}
slices.each(function (slice, index) {
var bisection = (slice.startAngle + slice.endAngle) / 2;
var color = options.colors[index];
var xOffset = center.x + Math.cos(bisection) * slice.explode;
var yOffset = center.y + Math.sin(bisection) * slice.explode;
this.plotSlice(xOffset, yOffset, radius, slice.startAngle, slice.endAngle, false, vScale);
if (series.pie.fill) {
ctx.fillStyle = Flotr.parseColor(color).scale(null, null, null, series.pie.fillOpacity).toString();
ctx.fill();
}
ctx.lineWidth = lw;
ctx.strokeStyle = color;
ctx.stroke();
/*
* ctx.save(); ctx.scale(1, vScale);
*
* ctx.moveTo(xOffset, yOffset); ctx.beginPath();
* ctx.lineTo(xOffset, yOffset+plotTickness);
* ctx.lineTo(xOffset+Math.cos(slice.startAngle)*radius,
* yOffset+Math.sin(slice.startAngle)*radius+plotTickness);
* ctx.lineTo(xOffset+Math.cos(slice.startAngle)*radius,
* yOffset+Math.sin(slice.startAngle)*radius);
* ctx.lineTo(xOffset, yOffset); ctx.closePath();
* ctx.fill();ctx.stroke();
*
* ctx.moveTo(xOffset, yOffset); ctx.beginPath();
* ctx.lineTo(xOffset, yOffset+plotTickness);
* ctx.lineTo(xOffset+Math.cos(slice.endAngle)*radius,
* yOffset+Math.sin(slice.endAngle)*radius+plotTickness);
* ctx.lineTo(xOffset+Math.cos(slice.endAngle)*radius,
* yOffset+Math.sin(slice.endAngle)*radius);
* ctx.lineTo(xOffset, yOffset); ctx.closePath();
* ctx.fill();ctx.stroke();
*
* ctx.moveTo(xOffset+Math.cos(slice.startAngle)*radius,
* yOffset+Math.sin(slice.startAngle)*radius);
* ctx.beginPath();
* ctx.lineTo(xOffset+Math.cos(slice.startAngle)*radius,
* yOffset+Math.sin(slice.startAngle)*radius+plotTickness);
* ctx.arc(xOffset, yOffset+plotTickness, radius,
* slice.startAngle, slice.endAngle, false);
* ctx.lineTo(xOffset+Math.cos(slice.endAngle)*radius,
* yOffset+Math.sin(slice.endAngle)*radius);
* ctx.arc(xOffset, yOffset, radius, slice.endAngle,
* slice.startAngle, true); ctx.closePath();
* ctx.fill();ctx.stroke();
*
* ctx.scale(1, 1/vScale); this.plotSlice(xOffset,
* yOffset+plotTickness, radius, slice.startAngle,
* slice.endAngle, false, vScale); ctx.stroke();
* if(series.pie.fill){ ctx.fillStyle =
* Flotr.parseColor(color).scale(null, null, null,
* series.pie.fillOpacity).toString(); ctx.fill(); }
*
* ctx.restore();
*/
var label = options.pie.labelFormatter(slice);
var textAlignRight = (Math.cos(bisection) < 0);
var distX = xOffset + Math.cos(bisection) * (series.pie.explode + radius);
var distY = yOffset + Math.sin(bisection) * (series.pie.explode + radius);
if (slice.fraction && label) {
if (options.HtmlText) {
var divStyle = 'position:absolute;top:' + (distY - 5) + 'px;'; // @todo:
// change
if (textAlignRight) {
divStyle += 'right:' + (this.canvasWidth - distX) + 'px;text-align:right;';
} else {
divStyle += 'left:' + distX + 'px;text-align:left;';
}
html.push('<div style="' + divStyle + '" class="flotr-grid-label">' + label + '</div>');
} else {
style.halign = textAlignRight ? 'r' : 'l';
ctx.drawText(label, distX, distY + style.size / 2, style);
}
}
}, this);
if (options.HtmlText) {
html.push('</div>');
this.el.insert(html.join(''));
}
ctx.restore();
options.pie.drawn = true;
}
},
plotSlice : function (x, y, radius, startAngle, endAngle, fill, vScale) {
var ctx = this.ctx;
vScale = vScale || 1;
ctx.save();
ctx.scale(1, vScale);
ctx.beginPath();
ctx.moveTo(x, y);
ctx.arc(x, y, radius, startAngle, endAngle, fill);
ctx.lineTo(x, y);
ctx.closePath();
ctx.restore();
},
plotPie : function () {
},
/**
* Function: insertLegend
*
* Function adds a legend div to the canvas container or draws it on
* the canvas.
*
* Parameters: none
*
* Returns: void
*/
insertLegend : function () {
if (!this.options.legend.show)
return;
var series = this.series, plotOffset = this.plotOffset, options = this.options, fragments = [], rowStarted = false, ctx = this.ctx, i;
var noLegendItems = series.findAll(function (s) {
return (s.label && !s.hide);
}).size();
if (noLegendItems) {
if (!options.HtmlText && this.textEnabled) {
var style = {
size : options.fontSize * 1.1,
color : options.grid.color
};
// @todo: take css into account
// var dummyDiv = this.el.insert('<div
// class="flotr-legend"
// style="position:absolute;top:-10000px;"></div>');
var p = options.legend.position, m = options.legend.margin, lbw = options.legend.labelBoxWidth, lbh = options.legend.labelBoxHeight, lbm = options.legend.labelBoxMargin, offsetX = plotOffset.left
+ m, offsetY = plotOffset.top + m;
// We calculate the labels' max width
var labelMaxWidth = 0;
for (i = series.length - 1; i > -1; --i) {
if (!series[i].label || series[i].hide)
continue;
var label = options.legend.labelFormatter(series[i].label);
labelMaxWidth = Math.max(labelMaxWidth, ctx.measureText(label, style));
}
var legendWidth = Math.round(lbw + lbm * 3 + labelMaxWidth), legendHeight = Math.round(noLegendItems * (lbm + lbh) + lbm);
if (p.charAt(0) == 's')
offsetY = plotOffset.top + this.plotHeight - (m + legendHeight);
if (p.charAt(1) == 'e')
offsetX = plotOffset.left + this.plotWidth - (m + legendWidth);
// Legend box
var color = Flotr.parseColor(options.legend.backgroundColor || 'rgb(240,240,240)').scale(null, null, null,
options.legend.backgroundOpacity || 0.1).toString();
ctx.fillStyle = color;
ctx.fillRect(offsetX, offsetY, legendWidth, legendHeight);
ctx.strokeStyle = options.legend.labelBoxBorderColor;
ctx.strokeRect(Flotr.toPixel(offsetX), Flotr.toPixel(offsetY), legendWidth, legendHeight);
// Legend labels
var x = offsetX + lbm;
var y = offsetY + lbm;
for (i = 0; i < series.length; i++) {
if (!series[i].label || series[i].hide)
continue;
var label = options.legend.labelFormatter(series[i].label);
ctx.fillStyle = series[i].color;
ctx.fillRect(x, y, lbw - 1, lbh - 1);
ctx.strokeStyle = options.legend.labelBoxBorderColor;
ctx.lineWidth = 1;
ctx.strokeRect(Math.ceil(x) - 1.5, Math.ceil(y) - 1.5, lbw + 2, lbh + 2);
// Legend text
ctx.drawText(label, x + lbw + lbm, y + (lbh + style.size - ctx.fontDescent(style)) / 2, style);
y += lbh + lbm;
}
} else {
for (i = 0; i < series.length; ++i) {
if (!series[i].label || series[i].hide)
continue;
if (i % options.legend.noColumns == 0) {
fragments.push(rowStarted ? '</tr><tr>' : '<tr>');
rowStarted = true;
}
var label = options.legend.labelFormatter(series[i].label);
fragments.push('<td class="flotr-legend-color-box"><div style="border:1px solid ' + options.legend.labelBoxBorderColor
+ ';padding:1px"><div style="width:' + options.legend.labelBoxWidth + 'px;height:' + options.legend.labelBoxHeight
+ 'px;background-color:' + series[i].color + '"></div></div></td>' + '<td class="flotr-legend-label">' + label + '</td>');
}
if (rowStarted)
fragments.push('</tr>');
if (fragments.length > 0) {
var table = '<table style="font-size:smaller;color:' + options.grid.color + '">' + fragments.join("") + '</table>';
if (options.legend.container != null) {
$(options.legend.container).update(table);
} else {
var pos = '';
var p = options.legend.position, m = options.legend.margin;
if (p.charAt(0) == 'n')
pos += 'top:' + (m + plotOffset.top) + 'px;';
else if (p.charAt(0) == 's')
pos += 'bottom:' + (m + plotOffset.bottom) + 'px;';
if (p.charAt(1) == 'e')
pos += 'right:' + (m + plotOffset.right) + 'px;';
else if (p.charAt(1) == 'w')
pos += 'left:' + (m + plotOffset.left) + 'px;';
var div = this.el.insert('<div class="flotr-legend" style="position:absolute;z-index:2;' + pos + '">' + table + '</div>')
.select('div.flotr-legend').first();
if (options.legend.backgroundOpacity != 0.0) {
/**
* Put in the transparent background
* separately to avoid blended labels and
* label boxes.
*/
var c = options.legend.backgroundColor;
if (c == null) {
var tmp = (options.grid.backgroundColor != null) ? options.grid.backgroundColor : Flotr.extractColor(div);
c = Flotr.parseColor(tmp).adjust(null, null, null, 1).toString();
}
this.el.insert(
'<div class="flotr-legend-bg" style="position:absolute;width:' + div.getWidth() + 'px;height:' + div.getHeight()
+ 'px;' + pos + 'background-color:' + c + ';"> </div>').select('div.flotr-legend-bg').first().setStyle({
'opacity' : options.legend.backgroundOpacity
});
}
}
}
}
}
},
/**
* Function: getEventPosition
*
* Calculates the coordinates from a mouse event object.
*
* Parameters: event - Mouse Event object.
*
* Returns: Object with x and y coordinates of the mouse.
*/
getEventPosition : function (event) {
var offset = this.overlay.cumulativeOffset(), rx = (event.pageX - offset.left - this.plotOffset.left), ry = (event.pageY - offset.top - this.plotOffset.top), ax = 0, ay = 0;
if (event.pageX == null && event.clientX != null) {
var de = document.documentElement, b = document.body;
ax = event.clientX + (de && de.scrollLeft || b.scrollLeft || 0);
ay = event.clientY + (de && de.scrollTop || b.scrollTop || 0);
} else {
ax = event.pageX;
ay = event.pageY;
}
return {
x : this.axes.x.min + rx / this.axes.x.scale,
x2 : this.axes.x2.min + rx / this.axes.x2.scale,
y : this.axes.y.max - ry / this.axes.y.scale,
y2 : this.axes.y2.max - ry / this.axes.y2.scale,
relX : rx,
relY : ry,
absX : ax,
absY : ay
};
},
/**
* Function: clickHandler
*
* Handler observes the 'click' event and fires the 'flotr:click'
* event.
*
* Parameters: event - 'click' Event object.
*
* Returns: void
*/
clickHandler : function (event) {
if (this.ignoreClick) {
this.ignoreClick = false;
return;
}
this.el.fire('flotr:click', [ this.getEventPosition(event), this ]);
},
/**
* Function: mouseMoveHandler
*
* Handler observes mouse movement over the graph area. Fires the
* 'flotr:mousemove' event.
*
* Parameters: event - 'mousemove' Event object.
*
* Returns: void
*/
mouseMoveHandler : function (event) {
var pos = this.getEventPosition(event);
this.lastMousePos.pageX = pos.absX;
this.lastMousePos.pageY = pos.absY;
if (this.selectionInterval == null && (this.options.mouse.track || this.series.any(function (s) {
return s.mouse && s.mouse.track;
}))) {
this.hit(pos);
}
this.el.fire('flotr:mousemove', [ event, pos, this ]);
},
/**
* Function: mouseDownHandler
*
* Handler observes the 'mousedown' event.
*
* Parameters: event - 'mousedown' Event object.
*
* Returns: void
*/
mouseDownHandler : function (event) {
if (event.isRightClick()) {
event.stop();
var overlay = this.overlay;
overlay.hide();
function cancelContextMenu () {
overlay.show();
$(document).stopObserving('mousemove', cancelContextMenu);
}
$(document).observe('mousemove', cancelContextMenu);
return;
}
if (!this.options.selection.mode || !event.isLeftClick())
return;
this.setSelectionPos(this.selection.first, event);
if (this.selectionInterval != null) {
clearInterval(this.selectionInterval);
}
this.lastMousePos.pageX = null;
this.selectionInterval = setInterval(this.updateSelection.bind(this), 1000 / this.options.selection.fps);
this.mouseUpHandler = this.mouseUpHandler.bind(this);
$(document).observe('mouseup', this.mouseUpHandler);
},
/**
* Function: (private) fireSelectEvent
*
* Fires the 'flotr:select' event when the user made a selection.
*
* Parameters: none
*
* Returns: void
*/
fireSelectEvent : function () {
var a = this.axes, selection = this.selection, x1 = (selection.first.x <= selection.second.x) ? selection.first.x : selection.second.x, x2 = (selection.first.x <= selection.second.x) ? selection.second.x
: selection.first.x, y1 = (selection.first.y >= selection.second.y) ? selection.first.y : selection.second.y, y2 = (selection.first.y >= selection.second.y) ? selection.second.y
: selection.first.y;
x1 = a.x.min + x1 / a.x.scale;
x2 = a.x.min + x2 / a.x.scale;
y1 = a.y.max - y1 / a.y.scale;
y2 = a.y.max - y2 / a.y.scale;
this.el.fire('flotr:select', [ {
x1 : x1,
y1 : y1,
x2 : x2,
y2 : y2
}, this ]);
},
/**
* Function: (private) mouseUpHandler
*
* Handler observes the mouseup event for the document.
*
* Parameters: event - 'mouseup' Event object.
*
* Returns: void
*/
mouseUpHandler : function (event) {
$(document).stopObserving('mouseup', this.mouseUpHandler);
event.stop();
if (this.selectionInterval != null) {
clearInterval(this.selectionInterval);
this.selectionInterval = null;
}
this.setSelectionPos(this.selection.second, event);
this.clearSelection();
if (this.selectionIsSane()) {
this.drawSelection();
this.fireSelectEvent();
this.ignoreClick = true;
}
},
/**
* Function: setSelectionPos
*
* Calculates the position of the selection.
*
* Parameters: pos - Position object. event - Event object.
*
* Returns: void
*/
setSelectionPos : function (pos, event) {
var options = this.options, offset = $(this.overlay).cumulativeOffset();
if (options.selection.mode.indexOf('x') == -1) {
pos.x = (pos == this.selection.first) ? 0 : this.plotWidth;
} else {
pos.x = event.pageX - offset.left - this.plotOffset.left;
pos.x = Math.min(Math.max(0, pos.x), this.plotWidth);
}
if (options.selection.mode.indexOf('y') == -1) {
pos.y = (pos == this.selection.first) ? 0 : this.plotHeight;
} else {
pos.y = event.pageY - offset.top - this.plotOffset.top;
pos.y = Math.min(Math.max(0, pos.y), this.plotHeight);
}
},
/**
* Function: updateSelection
*
* Updates (draws) the selection box.
*
* Parameters: none
*
* Returns: void
*/
updateSelection : function () {
if (this.lastMousePos.pageX == null)
return;
this.setSelectionPos(this.selection.second, this.lastMousePos);
this.clearSelection();
if (this.selectionIsSane())
this.drawSelection();
},
/**
* Function: clearSelection
*
* Removes the selection box from the overlay canvas.
*
* Parameters: none
*
* Returns: void
*/
clearSelection : function () {
if (this.prevSelection == null)
return;
var prevSelection = this.prevSelection, octx = this.octx, plotOffset = this.plotOffset, x = Math.min(prevSelection.first.x,
prevSelection.second.x), y = Math.min(prevSelection.first.y, prevSelection.second.y), w = Math.abs(prevSelection.second.x
- prevSelection.first.x), h = Math.abs(prevSelection.second.y - prevSelection.first.y);
octx.clearRect(x + plotOffset.left - octx.lineWidth, y + plotOffset.top - octx.lineWidth, w + octx.lineWidth * 2, h + octx.lineWidth * 2);
this.prevSelection = null;
},
/**
* Function: setSelection
*
* Allows the user the manually select an area.
*
* Parameters: area - Object with coordinates to select.
*
* Returns: void
*/
setSelection : function (area) {
var options = this.options, xa = this.axes.x, ya = this.axes.y, vertScale = yaxis.scale, hozScale = xaxis.scale, selX = options.selection.mode
.indexOf('x') != -1, selY = options.selection.mode.indexOf('y') != -1;
this.clearSelection();
this.selection.first.y = selX ? 0 : (ya.max - area.y1) * vertScale;
this.selection.second.y = selX ? this.plotHeight : (ya.max - area.y2) * vertScale;
this.selection.first.x = selY ? 0 : (area.x1 - xa.min) * hozScale;
this.selection.second.x = selY ? this.plotWidth : (area.x2 - xa.min) * hozScale;
this.drawSelection();
this.fireSelectEvent();
},
/**
* Function: (private) drawSelection
*
* Draws the selection box.
*
* Parameters: none
*
* Returns: void
*/
drawSelection : function () {
var prevSelection = this.prevSelection, selection = this.selection, octx = this.octx, options = this.options, plotOffset = this.plotOffset;
if (prevSelection != null && selection.first.x == prevSelection.first.x && selection.first.y == prevSelection.first.y
&& selection.second.x == prevSelection.second.x && selection.second.y == prevSelection.second.y)
return;
octx.strokeStyle = Flotr.parseColor(options.selection.color).scale(null, null, null, 0.8).toString();
octx.lineWidth = 1;
octx.lineJoin = 'round';
octx.fillStyle = Flotr.parseColor(options.selection.color).scale(null, null, null, 0.4).toString();
this.prevSelection = {
first : {
x : selection.first.x,
y : selection.first.y
},
second : {
x : selection.second.x,
y : selection.second.y
}
};
var x = Math.min(selection.first.x, selection.second.x), y = Math.min(selection.first.y, selection.second.y), w = Math.abs(selection.second.x
- selection.first.x), h = Math.abs(selection.second.y - selection.first.y);
octx.fillRect(x + plotOffset.left, y + plotOffset.top, w, h);
octx.strokeRect(x + plotOffset.left, y + plotOffset.top, w, h);
},
/**
* Function: (private) selectionIsSane
*
* Determines whether or not the selection is sane and should be
* drawn.
*
* Parameters: none
*
* Returns: boolean - True when sane, false otherwise.
*/
selectionIsSane : function () {
var selection = this.selection;
return Math.abs(selection.second.x - selection.first.x) >= 5 && Math.abs(selection.second.y - selection.first.y) >= 5;
},
/**
* Function: clearHit
*
* Removes the mouse tracking point from the overlay.
*
* Parameters: none
*
* Returns: void
*/
clearHit : function () {
if (this.prevHit) {
var options = this.options, plotOffset = this.plotOffset, prevHit = this.prevHit;
this.octx.clearRect(this.tHoz(prevHit.x) + plotOffset.left - options.points.radius * 2, this.tVert(prevHit.y) + plotOffset.top
- options.points.radius * 2, options.points.radius * 3 + options.points.lineWidth * 3, options.points.radius * 3
+ options.points.lineWidth * 3);
this.prevHit = null;
}
},
/**
* Function: hit
*
* Retrieves the nearest data point from the mouse cursor. If it's
* within a certain range, draw a point on the overlay canvas and
* display the x and y value of the data.
*
* Parameters: mouse - Object that holds the relative x and y
* coordinates of the cursor.
*
* Returns: void
*/
hit : function (mouse) {
var series = this.series, options = this.options, prevHit = this.prevHit, plotOffset = this.plotOffset, octx = this.octx, data, xsens, ysens,
/**
* Nearest data element.
*/
i, n = {
dist : Number.MAX_VALUE,
x : null,
y : null,
relX : mouse.relX,
relY : mouse.relY,
absX : mouse.absX,
absY : mouse.absY,
mouse : null,
serie : null,
primaryKey : null,
pointTag : null
};
for (i = 0; i < series.length; i++) {
s = series[i];
if (!s.mouse.track)
continue;
data = s.data;
//DA : Augmenter considérablement la sensibilité pour que l'on puisse utiliser les dates.
// xsens = (s.xaxis.scale * s.mouse.sensibility);
// ysens = (s.yaxis.scale * s.mouse.sensibility);
xsens = (s.xaxis.scale * s.mouse.sensibility);
ysens = (s.yaxis.scale * s.mouse.sensibility);
for ( var j = 0, xpow, ypow; j < data.length; j++) {
if (data[j][1] === null)
continue;
xpow = Math.pow(s.xaxis.scale * (data[j][0] - mouse.x), 2);
ypow = Math.pow(s.yaxis.scale * (data[j][1] - mouse.y), 2);
if (xpow < xsens && ypow < ysens && Math.sqrt(xpow + ypow) < n.dist) {
n.dist = Math.sqrt(xpow + ypow);
n.x = data[j][0];
n.y = data[j][1];
n.primaryKey = data[j][2];
n.pointTag = data[j][3];
n.mouse = s.mouse;
n.serie = s;
}
}
}
if (n.mouse && n.mouse.track && !prevHit || (prevHit && (n.x != prevHit.x || n.y != prevHit.y))) {
var mt = this.mouseTrack || this.el.select(".flotr-mouse-value")[0], pos = '', p = options.mouse.position, m = options.mouse.margin, elStyle = 'opacity:0.7;background-color:#000;color:#fff;display:none;position:absolute;padding:2px 8px;-moz-border-radius:4px;border-radius:4px;white-space:nowrap;';
if (!options.mouse.relative) { // absolute to the canvas
if (p.charAt(0) == 'n')
pos += 'top:' + (m + plotOffset.top) + 'px;';
else if (p.charAt(0) == 's')
pos += 'bottom:' + (m + plotOffset.bottom) + 'px;';
if (p.charAt(1) == 'e')
pos += 'right:' + (m + plotOffset.right) + 'px;';
else if (p.charAt(1) == 'w')
pos += 'left:' + (m + plotOffset.left) + 'px;';
} else { // relative to the mouse
if (p.charAt(0) == 'n')
pos += 'bottom:' + (m - plotOffset.top - this.tVert(n.y) + this.canvasHeight) + 'px;';
else if (p.charAt(0) == 's')
pos += 'top:' + (m + plotOffset.top + this.tVert(n.y)) + 'px;';
if (p.charAt(1) == 'e')
pos += 'left:' + (m + plotOffset.left + this.tHoz(n.x)) + 'px;';
else if (p.charAt(1) == 'w')
pos += 'right:' + (m - plotOffset.left - this.tHoz(n.x) + this.canvasWidth) + 'px;';
}
elStyle += pos;
if (!mt) {
this.el.insert('<div class="flotr-mouse-value" style="' + elStyle + '"></div>');
mt = this.mouseTrack = this.el.select('.flotr-mouse-value').first();
} else {
this.mouseTrack = mt.setStyle(elStyle);
}
if (n.x !== null && n.y !== null) {
mt.show();
this.clearHit();
if (n.mouse.lineColor != null) {
octx.save();
octx.translate(plotOffset.left, plotOffset.top);
octx.lineWidth = options.points.lineWidth;
octx.strokeStyle = n.mouse.lineColor;
octx.fillStyle = '#ffffff';
octx.beginPath();
octx.arc(this.tHoz(n.x), this.tVert(n.y), options.mouse.radius, 0, 2 * Math.PI, true);
octx.fill();
octx.stroke();
octx.restore();
}
this.prevHit = n;
var decimals = n.mouse.trackDecimals;
if (decimals == null || decimals < 0)
decimals = 0;
mt.innerHTML = n.pointTag;
// mt.innerHTML = n.mouse.trackFormatter({x:
// n.x.toFixed(decimals), y: n.y.toFixed(decimals)});
mt.fire('flotr:hit', [ n, this ]);
} else if (prevHit) {
mt.hide();
this.clearHit();
}
}
},
saveImage : function (type, fileName, width, height, replaceCanvas) {
var image = null;
switch (type) {
case 'jpeg':
case 'jpg':
image = Canvas2Image.saveAsJPEG(this.canvas, replaceCanvas, width, height);
break;
default:
case 'png':
image = Canvas2Image.saveAsPNG(this.canvas, fileName, replaceCanvas, width, height);
break;
case 'bmp':
image = Canvas2Image.saveAsBMP(this.canvas, replaceCanvas, width, height);
break;
}
if (Object.isElement(image) && replaceCanvas) {
this.restoreCanvas();
this.canvas.hide();
this.overlay.hide();
this.el.insert(image.setStyle({
position : 'absolute'
}));
}
},
restoreCanvas : function () {
this.canvas.show();
this.overlay.show();
this.el.select('img').invoke('remove');
}
});
Flotr.Color = Class.create({
initialize : function (r, g, b, a) {
this.rgba = [ 'r', 'g', 'b', 'a' ];
var x = 4;
while (-1 < --x) {
this[this.rgba[x]] = arguments[x] || ((x == 3) ? 1.0 : 0);
}
this.normalize();
},
adjust : function (rd, gd, bd, ad) {
var x = 4;
while (-1 < --x) {
if (arguments[x] != null)
this[this.rgba[x]] += arguments[x];
}
return this.normalize();
},
clone : function () {
return new Flotr.Color(this.r, this.b, this.g, this.a);
},
limit : function (val, minVal, maxVal) {
return Math.max(Math.min(val, maxVal), minVal);
},
normalize : function () {
var limit = this.limit;
this.r = limit(parseInt(this.r), 0, 255);
this.g = limit(parseInt(this.g), 0, 255);
this.b = limit(parseInt(this.b), 0, 255);
this.a = limit(this.a, 0, 1);
return this;
},
scale : function (rf, gf, bf, af) {
var x = 4;
while (-1 < --x) {
if (arguments[x] != null)
this[this.rgba[x]] *= arguments[x];
}
return this.normalize();
},
distance : function (color) {
if (!color)
return;
color = new Flotr.parseColor(color);
var dist = 0;
var x = 3;
while (-1 < --x) {
dist += Math.abs(this[this.rgba[x]] - color[this.rgba[x]]);
}
return dist;
},
toString : function () {
return (this.a >= 1.0) ? 'rgb(' + [ this.r, this.g, this.b ].join(',') + ')' : 'rgba(' + [ this.r, this.g, this.b, this.a ].join(',') + ')';
}
});
Flotr.Color.lookupColors = {
aqua : [ 0, 255, 255 ],
azure : [ 240, 255, 255 ],
beige : [ 245, 245, 220 ],
black : [ 0, 0, 0 ],
blue : [ 0, 0, 255 ],
brown : [ 165, 42, 42 ],
cyan : [ 0, 255, 255 ],
darkblue : [ 0, 0, 139 ],
darkcyan : [ 0, 139, 139 ],
darkgrey : [ 169, 169, 169 ],
darkgreen : [ 0, 100, 0 ],
darkkhaki : [ 189, 183, 107 ],
darkmagenta : [ 139, 0, 139 ],
darkolivegreen : [ 85, 107, 47 ],
darkorange : [ 255, 140, 0 ],
darkorchid : [ 153, 50, 204 ],
darkred : [ 139, 0, 0 ],
darksalmon : [ 233, 150, 122 ],
darkviolet : [ 148, 0, 211 ],
fuchsia : [ 255, 0, 255 ],
gold : [ 255, 215, 0 ],
green : [ 0, 128, 0 ],
indigo : [ 75, 0, 130 ],
khaki : [ 240, 230, 140 ],
lightblue : [ 173, 216, 230 ],
lightcyan : [ 224, 255, 255 ],
lightgreen : [ 144, 238, 144 ],
lightgrey : [ 211, 211, 211 ],
lightpink : [ 255, 182, 193 ],
lightyellow : [ 255, 255, 224 ],
lime : [ 0, 255, 0 ],
magenta : [ 255, 0, 255 ],
maroon : [ 128, 0, 0 ],
navy : [ 0, 0, 128 ],
olive : [ 128, 128, 0 ],
orange : [ 255, 165, 0 ],
pink : [ 255, 192, 203 ],
purple : [ 128, 0, 128 ],
violet : [ 128, 0, 128 ],
red : [ 255, 0, 0 ],
silver : [ 192, 192, 192 ],
white : [ 255, 255, 255 ],
yellow : [ 255, 255, 0 ]
};
// not used yet
Flotr.Date = {
format : function (d, format) {
if (!d)
return;
var leftPad = function (n) {
n = n.toString();
return n.length == 1 ? "0" + n : n;
};
var r = [];
var escape = false;
for ( var i = 0; i < format.length; ++i) {
var c = format.charAt(i);
if (escape) {
switch (c) {
case 'h':
c = d.getUTCHours().toString();
break;
case 'H':
c = leftPad(d.getUTCHours());
break;
case 'M':
c = leftPad(d.getUTCMinutes());
break;
case 'S':
c = leftPad(d.getUTCSeconds());
break;
case 'd':
c = d.getUTCDate().toString();
break;
case 'm':
c = (d.getUTCMonth() + 1).toString();
break;
case 'y':
c = d.getUTCFullYear().toString();
break;
case 'b':
c = Flotr.Date.monthNames[d.getUTCMonth()];
break;
}
r.push(c);
escape = false;
} else {
if (c == "%")
escape = true;
else
r.push(c);
}
}
return r.join("");
},
timeUnits : {
"second" : 1000,
"minute" : 60 * 1000,
"hour" : 60 * 60 * 1000,
"day" : 24 * 60 * 60 * 1000,
"month" : 30 * 24 * 60 * 60 * 1000,
"year" : 365.2425 * 24 * 60 * 60 * 1000
},
// the allowed tick sizes, after 1 year we use an integer algorithm
spec : [ [ 1, "second" ], [ 2, "second" ], [ 5, "second" ], [ 10, "second" ], [ 30, "second" ], [ 1, "minute" ], [ 2, "minute" ], [ 5, "minute" ],
[ 10, "minute" ], [ 30, "minute" ], [ 1, "hour" ], [ 2, "hour" ], [ 4, "hour" ], [ 8, "hour" ], [ 12, "hour" ], [ 1, "day" ], [ 2, "day" ],
[ 3, "day" ], [ 0.25, "month" ], [ 0.5, "month" ], [ 1, "month" ], [ 2, "month" ], [ 3, "month" ], [ 6, "month" ], [ 1, "year" ] ],
monthNames : [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]
};
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, projectGlobal, commonTreeUtils, showResponse, DEFAULT_PREFERENCES_FOLDER,
document, i18n, $, Flotr, userLogin, SitoolsDesk, sql2ext, loadUrl,
SITOOLS_DATE_FORMAT, SITOOLS_DEFAULT_IHM_DATE_FORMAT, DEFAULT_LIVEGRID_BUFFER_SIZE, WARNING_NB_RECORDS_PLOT*/
/*
* @include "../viewDataDetail/viewDataDetail.js"
* @include "../../sitoolsProject.js"
*/
/**
*
* <a href="https://sourceforge.net/tracker/?func=detail&aid=3313793&group_id=531341&atid=2158259">[3313793]</a><br/>
* 16/06/2011 m.gond {Display the right number of data plotted} <br/>
*
* ExtJS layout for plotting data
*/
Ext.namespace('sitools.user.component');
/**
* @cfg {String} dataUrl the dataset url attachment
* @cfg {} columnModel the dataset's column model
* @cfg {} filters the list of filters to apply (filters from the dataview)
* @cfg {String} selections the selections as a String to add to the URL (selections from the dataview)
* @cfg {String} datasetName the name of the dataset
* @cfg {} formParam list of parameters from a query form
* @cfg {} formMultiDsParams list of parameters from a multidataset query form
* @cfg {String} datasetId the id of the dataset
* @cfg {string} componentType Should be "plot"
* @requires sitools.user.component.viewDataDetail
* @class sitools.user.component.dataPlotter
* @extends Ext.Panel
*/
sitools.user.component.dataPlotter = function (config) {
//sitools.component.users.datasets.dataPlotter = function (config) {
Ext.apply(this, config);
this.dataUrl = config.dataUrl;
this.datasetName = config.datasetName;
this.datasetId = config.datasetId;
/** Variable to know if the plot has been done once */
this.hasPlotted = false;
/** function to get numeric fields */
function getNumericFields(arrayFields) {
var numericFields = [];
var store = new Ext.data.JsonStore({
fields : [{
name : "columnAlias",
type : "string"
}, {
name : "sqlColumnType",
type : "string"
}]
});
Ext.each(arrayFields, function (field) {
if (!Ext.isEmpty(field.sqlColumnType)) {
var extType = sql2ext.get(field.sqlColumnType);
if (extType.match(/^(numeric)+[48]?$/gi) !== null && !field.hidden) {
store.add(new Ext.data.Record(field));
}
if (extType.match(/dateAsString/gi) !== null && !field.hidden) {
store.add(new Ext.data.Record(field));
}
}
}, this);
return store;
}
/** function to get numeric fields */
function getVisibleFields(arrayFields) {
var visibleFields = [];
Ext.each(arrayFields, function (field) {
if (!field.hidden) {
visibleFields.push(field.columnAlias);
}
}, this);
return visibleFields;
}
/**
* Buffer range for display in the bottom bar
*/
this.bufferRange = 300;
/**
* Dataset url for data details
*/
var dataUrl = config.dataUrl;
this.columnModel = config.columnModel;
/** Initial fields list */
var initialFields = getNumericFields(this.columnModel);
/** Point tag field list */
var pointTagFields = getVisibleFields(this.columnModel);
/**
* Whether or not there was a selection
*/
this.isSelection = !Ext.isEmpty(config.selections);
/** Initial data */
// var rawData = config.dataplot.data.items;
/** field for x axis label */
this.titleX = new Ext.form.Field({
fieldLabel : i18n.get('label.plot.form.xlabel'),
anchor : "95%",
name : "titleX",
listeners : {
scope : this,
change : this.handlePlotLayout
}
});
/** field for x axis label */
this.xFormat = null;
/** field for y axis label */
this.titleY = new Ext.form.Field({
fieldLabel : i18n.get('label.plot.form.ylabel'),
anchor : "95%",
name : "titleY",
listeners : {
scope : this,
change : this.handlePlotLayout
}
});
/** field for x axis label */
this.yFormat = null;
/** combobox for x field */
this.comboX = new Ext.form.ComboBox({
store : initialFields,
anchor : "95%",
name : "comboX",
allowBlank : false,
emptyText : i18n.get('label.plot.select.xaxis'),
fieldLabel : i18n.get('label.plot.select.xcolumn'),
selectOnFocus : true,
triggerAction : 'all',
valueField : "columnAlias",
displayField : "columnAlias",
editable : false,
mode : 'local',
listeners : {
scope : this,
select : function (combo, record, index) {
this.titleX.setValue(combo.getValue());
var extType = sql2ext.get(record.get("sqlColumnType"));
if (extType.match(/dateAsString/gi) !== null) {
if (Ext.isEmpty(this.xFormat)) {
this.xFormat = new Ext.form.Field({
fieldLabel : i18n.get('label.plot.form.xFormat'),
anchor : "95%",
name : "xFormat",
value : config.userPreference && config.userPreference.xFormat ? config.userPreference.xFormat : SITOOLS_DEFAULT_IHM_DATE_FORMAT,
listeners : {
scope : this,
change : this.handlePlotLayout
}
});
this.fieldSetX.insert(1, this.xFormat);
}
}
else {
this.fieldSetX.remove(this.xFormat);
this.xFormat = null;
}
this.fieldSetX.doLayout();
},
expand : function (combo) {
combo.store.clearFilter(true);
if (this.comboY.getValue() !== '' && this.comboY.getValue() !== null) {
combo.store.filterBy(function (record, id) {
return record.get('field1') !== this.comboY.getValue();
}, this);
}
}
}
});
/** combo box for y data */
this.comboY = new Ext.form.ComboBox({
store : initialFields,
name : "comboY",
allowBlank : false,
anchor : "95%",
emptyText : i18n.get('label.plot.select.yaxis'),
fieldLabel : i18n.get('label.plot.select.ycolumn'),
selectOnFocus : true,
editable : false,
valueField : "columnAlias",
displayField : "columnAlias",
triggerAction : 'all',
mode : 'local',
listeners : {
scope : this,
select : function (combo, record, index) {
this.titleY.setValue(combo.getValue());
var extType = sql2ext.get(record.get("sqlColumnType"));
if (extType.match(/dateAsString/gi) !== null) {
if (Ext.isEmpty(this.yFormat)) {
this.yFormat = new Ext.form.Field({
fieldLabel : i18n.get('label.plot.form.yFormat'),
anchor : "95%",
name : "yFormat",
value : config.userPreference && config.userPreference.yFormat ? config.userPreference.yFormat : SITOOLS_DEFAULT_IHM_DATE_FORMAT,
listeners : {
scope : this,
change : this.handlePlotLayout
}
});
// if (Ext.isEmpty(xFormat)) {
// this.leftPanel.insert(2, yFormat);
// }
// else {
// this.leftPanel.insert(3, yFormat);
// }
this.fieldSetY.insert(1, this.yFormat);
}
}
else {
this.fieldSetY.remove(this.yFormat);
this.yFormat = null;
}
this.fieldSetY.doLayout();
},
expand : function (combo) {
combo.store.clearFilter(true);
if (this.comboX.getValue() !== '' && this.comboX.getValue() !== null) {
combo.store.filterBy(function (record, id) {
return record.get('field1') !== this.comboX.getValue();
}, this);
}
}
}
});
/** field for x axis label */
this.titlePlot = new Ext.form.Field({
anchor : "95%",
fieldLabel : i18n.get('label.plot.form.title'),
name : "titlePlot",
listeners : {
scope : this,
change : this.handlePlotLayout
}
});
/** field for x axis label */
var numberRecords = new Ext.form.NumberField({
anchor : "95%",
fieldLabel : i18n.get('label.plot.form.nbRecords'),
name : "nbRecords",
value : DEFAULT_LIVEGRID_BUFFER_SIZE,
disabled : this.isSelection,
allowBlank : false
});
/** checkbox for drawing line */
this.checkLine = new Ext.form.Checkbox({
fieldLabel : i18n.get('label.plot.form.drawline'),
name : "checkLine",
scope : this,
listeners : {
scope : this,
check : this.handlePlotLayout
}
});
/** Combo box for tag title */
this.comboTag = new Ext.form.ComboBox({
store : pointTagFields,
name : "this.comboTag",
anchor : "95%",
allowBlank : true,
emptyText : i18n.get('label.plot.select.tag'),
fieldLabel : i18n.get('label.plot.select.tagcolumn'),
selectOnFocus : true,
triggerAction : 'all',
mode : 'local',
scope : this,
listeners : {
scope : this,
select : this.handlePlotLayout
}
});
this.comboXColor = new sitools.widget.colorField({
fieldLabel : i18n.get('label.plot.label.color'),
anchor : "95%",
name : "comboXColor",
value : "#000000",
listeners : {
scope : this,
select : this.handlePlotLayout
}
});
this.comboYColor = new sitools.widget.colorField({
fieldLabel : i18n.get('label.plot.label.color'),
anchor : "95%",
name : "comboYColor",
value : "#000000",
listeners : {
scope : this,
select : this.handlePlotLayout
}
});
this.fieldSetX = new Ext.form.FieldSet({
title : i18n.get('title.plot.xAxis'),
items : [this.comboX, this.titleX, this.comboXColor],
collapsible : true
});
this.fieldSetY = new Ext.form.FieldSet({
title : i18n.get('title.plot.yAxis'),
items : [this.comboY, this.titleY, this.comboYColor],
collapsible : true
});
var urlRecords = config.dataUrl + '/records';
//if there was a selection let's add the selection string to the urlRecords
if (this.isSelection) {
urlRecords += "?1=1&" + config.selections;
}
var sitoolsAttachementForUsers = config.dataUrl;
this.storeData = new sitools.user.component.dataviews.tplView.StoreTplView({
datasetCm : this.columnModel,
urlRecords : urlRecords,
sitoolsAttachementForUsers : sitoolsAttachementForUsers,
userPreference : config.userPreference,
formParams : (!this.isSelection ? config.formParams : undefined),
formMultiDsParams : (!this.isSelection ? config.formMultiDsParams : undefined),
mainView : this,
datasetId : config.datasetId,
isFirstCountDone : false,
autoLoad : false,
filters : config.filters
});
this.storeData.addListener("load", function (store, records, options) {
this.displayPlot(records);
}, this);
this.storeData.on("beforeload", function (store, options) {
//set the nocount param to false.
//before load is called only when a new action (sort, filter) is applied
var noCount;
if (!store.isFirstCountDone) {
options.params.nocount = false;
} else {
options.params.nocount = true;
}
if (!this.isSelection && !Ext.isEmpty(store.filters)) {
var params = store.buildQuery(store.filters.getFilterData());
Ext.apply(options.params, params);
}
this.storeData.storeOptions(options);
}, this);
/** button to draw the plot */
this.drawPlotButton = new Ext.Button({
text : i18n.get('label.plot.draw'),
disabled : true,
listeners : {
scope : this,
click : function (button, e) {
var form = this.leftPanel.getForm();
var pageSize = form.findField("nbRecords").getValue();
if (pageSize > WARNING_NB_RECORDS_PLOT) {
Ext.Msg.show({
title: i18n.get("label.warning"),
msg: String.format(i18n.get("label.plot.toManyRecordsAsked"), pageSize, WARNING_NB_RECORDS_PLOT) ,
buttons: Ext.Msg.YESNO,
icon: Ext.MessageBox.WARNING,
scope : this,
fn : function (buttonId) {
if (buttonId === 'yes') {
this.loadPlot(pageSize);
}
}
});
} else {
this.loadPlot(pageSize);
}
}
}
});
var bbar;
if (this.isSelection) {
bbar = new Ext.Toolbar({
hidden : true,
items : [ '->', {
id : 'plot-tb-text',
xtype : 'tbtext'
// text : 'Displaying ' + bufferSize + ' record' + (bufferSize > 1 ? 's' : '') + ' from ' + (bufferRange[0] + 1) + ' to ' + (bufferRange[1] + 1)
} ]
});
} else {
bbar = new Ext.PagingToolbar({
hidden : true,
store: this.storeData, // grid and PagingToolbar using same store
displayInfo: true,
pageSize: DEFAULT_LIVEGRID_BUFFER_SIZE,
items : []
});
}
/** right panel is the plot place */
this.rightPanel = new Ext.Panel({
id : 'plot-right-panel',
title : i18n.get('title.plot.panel'),
region : 'center',
margins : '2 2 2 1',
scope : this,
listeners : {
scope : this,
bodyresize : function (window, width, height) {
if (this.isVisible() && this.hasPlotted) {
if (!Ext.isEmpty(this.storeData.data)) {
this.displayPlot(this.storeData.data.items);
}
}
},
afterRender : function () {
// create a new loadingMask
this.loadMask = new Ext.LoadMask(this.rightPanel.getEl(), {
msg : i18n.get("label.plot.waitForPlot"),
store : this.storeData
});
}
},
bbar : bbar
});
/** left panel is a form */
this.leftPanel = new Ext.FormPanel({
title : i18n.get('title.plot.form'),
region : 'west',
split : true,
width : 300,
autoScroll : true,
collapsible : true,
margins : '2 1 2 2',
cmargins : '2 2 2 2',
padding : '5',
monitorValid : true,
items : [ this.titlePlot, numberRecords, this.checkLine, this.comboTag, this.fieldSetX, this.fieldSetY],
buttons : [this.drawPlotButton],
listeners : {
scope : this,
clientvalidation : function (panel, valid) {
if (valid && (this.comboX.getValue() !== this.comboY.getValue())) {
this.drawPlotButton.setDisabled(false);
} else {
this.drawPlotButton.setDisabled(true);
}
}
}
});
/** Automatic plot refresh when buffering */
// rightPanel.addListener('buffer',
// function (storage, rowindex, min, total) {
// if (this.isVisible() && this.hasPlotted) {
// rawData = storage.data.items;
// bufferSize = storage.bufferSize;
// bufferRange = storage.bufferRange;
// bbar.findById('plot-tb-text').setText(
// 'Displaying ' + bufferSize + ' record' + (bufferSize > 1 ? 's' : '') + ' from ' + (bufferRange[0] + 1) + ' to ' + (bufferRange[1] + 1));
// var plotConfig = getPlotConfig(columnModel, rawData);
// this.plot = Flotr.draw($(rightPanel.body.id), [ plotConfig.data ], plotConfig.config);
// }
// },
// this
// );
// /** Function to transform log checks in plot styles */
// function scaleTypeFromCheckBox (checkbox) {
// var style = 'linear';
// if (checkbox.getValue()) {
// style = 'logarithmic';
// }
// return style;
// }
/*
* Constructor call
*/
sitools.user.component.dataPlotter.superclass.constructor.call(this, Ext.apply({
id : 'plot-panel',
datasetName : config.datasetName,
layout : 'border',
items : [ this.leftPanel, this.rightPanel ]
// bbar : bbar
}, config));
};
Ext.extend(sitools.user.component.dataPlotter, Ext.Panel, {
/**
* Must be implemented to save window Settings
* @return {}
*/
_getSettings : function () {
return {
datasetName : this.datasetName,
leftPanelValues : this.leftPanel.getForm().getValues(),
preferencesPath : this.preferencesPath,
preferencesFileName : this.preferencesFileName
};
},
/**
* Load the userPreferences...
*/
afterRender : function () {
sitools.user.component.dataPlotter.superclass.afterRender.call(this);
this.el.on("contextmenu", function (e, t, o) {
e.stopEvent();
if (this.hasPlotted) {
var ctxMenu = new Ext.menu.Menu({
items : [{
text : i18n.get('label.plot.savePng'),
scope : this,
handler : function () {
this.plot.saveImage("png", "plotImage");
}
}]
});
ctxMenu.showAt(e.getXY());
// this.plot.saveImage("png");
}
}, this);
if (Ext.isEmpty(this.userPreference)) {
return;
}
var record, idx;
//load the preference a first Time...
this.leftPanel.getForm().loadRecord(new Ext.data.Record(this.userPreference.leftPanelValues));
//fire select to create optional fields...
var comboX = this.leftPanel.find("name", "comboX")[0];
if (!Ext.isEmpty(this.comboX.getValue())) {
idx = this.comboX.getStore().find("columnAlias", this.userPreference.comboX);
record = this.comboX.getStore().getAt(idx);
if (record) {
this.comboX.fireEvent("select", this.comboX, record, idx);
}
}
var comboY = this.leftPanel.find("name", "comboY")[0];
if (!Ext.isEmpty(this.comboY.getValue())) {
idx = this.comboY.getStore().find("columnAlias", this.userPreference.comboY);
record = this.comboY.getStore().getAt(idx);
if (record) {
this.comboY.fireEvent("select", this.comboY, record, idx);
}
}
//reload the preference with all fields...
this.leftPanel.getForm().loadRecord(new Ext.data.Record(this.userPreference));
},
/**
* @private
* Main function to display the plot directly from its data. Without a server call
* @param {Array} records the list records to show in the plot
*/
displayPlot : function (records) {
this.storeData.isFirstCountDone = true;
var plotConfig = this.getPlotConfig(this.columnModel, records);
this.plot = Flotr.draw($(this.rightPanel.body.id), [ plotConfig.data ], plotConfig.config);
$(this.rightPanel.body.id).stopObserving('flotr:click');
$(this.rightPanel.body.id).observe('flotr:click', this.showDataDetail.bindAsEventListener(this));
$(this.rightPanel.body.id).stopObserving('flotr:select');
$(this.rightPanel.body.id).observe('flotr:select', function (evt) {
var area = evt.memo[0];
var options = plotConfig.config;
options.xaxis.min = area.x1;
options.xaxis.max = area.x2;
options.yaxis.min = area.y1;
options.yaxis.max = area.y2;
this.plot = Flotr.draw($(this.id), [ plotConfig.data ], options);
});
this.hasPlotted = true;
if (this.isSelection) {
this.rightPanel.getBottomToolbar().findById('plot-tb-text').setText(String.format(i18n.get("label.plot.displayNbRecords"),
records.length));
}
this.rightPanel.getBottomToolbar().setVisible(true);
this.doLayout();
},
/**
* @private
* Main function to display the plot by getting the data from the server
* @param {int} pageSize the number of records to get
*/
loadPlot : function (pageSize) {
var form = this.leftPanel.getForm();
if (!this.isSelection) {
this.rightPanel.getBottomToolbar().pageSize = pageSize;
}
this.storeData.load({
params : {
start : 0,
limit : pageSize
}
});
},
/**
*
*/
/**
* @private
* Create plot-able dataset from the store
* @param {} columnModel the columnModel of the dataset
* @param {} storeItems the records from the store
* @return the plot-able data
*/
createData : function (columnModel, storeItems) {
var outData = [];
Ext.each(storeItems, function (item) {
var tag = this.comboTag.getValue() !== '' ? item.get(this.comboTag.getValue()) : null;
var colXType = sql2ext.get(this.getColumn(columnModel, this.comboX.getValue()).sqlColumnType);
var colYType = sql2ext.get(this.getColumn(columnModel, this.comboY.getValue()).sqlColumnType);
var xValue, yValue;
switch (colXType) {
case "dateAsString" :
xValue = Date.parseDate(item.get(this.comboX.getValue()), SITOOLS_DATE_FORMAT, true);
if (!Ext.isEmpty(xValue)) {
xValue = xValue.getTime();
}
break;
case "numeric" :
xValue = parseFloat(item.get(this.comboX.getValue()));
break;
default :
xValue = item.get(this.comboX.getValue());
break;
}
switch (colYType) {
case "dateAsString" :
var value = item.get(this.comboY.getValue());
yValue = Date.parseDate(value, SITOOLS_DATE_FORMAT, true);
if (!Ext.isEmpty(yValue)) {
yValue = yValue.getTime();
}
break;
case "numeric" :
yValue = parseFloat(item.get(this.comboY.getValue()));
break;
default :
yValue = item.get(this.comboY.getValue());
break;
}
outData.push([ xValue, yValue, item.id, tag ? tag : item.id ]);
}, this);
return outData;
},
/**
* Get a column from the given columnModel corresponding to the given columnAlias
* @param {} columnModel the list of columns
* @param {} columnAlias the column alias to search for
* @return {} the columnFound or undefined if not found
*/
getColumn : function (columnModel, columnAlias) {
var result;
for (var i = 0; i < columnModel.length; i++) {
if (columnModel[i].columnAlias == columnAlias) {
result = columnModel[i];
}
}
return result;
},
/**
* @private
* Create the config for a plot and add the given data to it
* @param {} columnModel the column model
* @param {} newdata the list of records to plot
* @return {} the config of the plot
*/
getPlotConfig : function (columnModel, newdata) {
var d1 = this.createData(columnModel, newdata);
var yAxisFormat = "Normal";
var colY = this.getColumn(columnModel, this.comboY.getValue());
var colYType = sql2ext.get(colY.sqlColumnType);
var xAxisFormat = "Normal";
var colX = this.getColumn(columnModel, this.comboX.getValue());
var colXType = sql2ext.get(colX.sqlColumnType);
/**
* Formater for the X axis
*/
var colXFormater = function (value) {
if (colXType == "dateAsString") {
var dt = new Date();
dt.setTime(value);
return dt.format(this.xFormat ? this.xFormat.getValue() : SITOOLS_DEFAULT_IHM_DATE_FORMAT);
}
return value;
};
/**
* Formater for the Y axis
*/
var colYFormater = function (value) {
if (colYType == "dateAsString") {
var dt = new Date();
dt.setTime(value);
return dt.format(this.yFormat ? this.yFormat.getValue() : SITOOLS_DEFAULT_IHM_DATE_FORMAT);
}
return value;
}
var plotConfig = {
HtmlText : false,
colors : [ '#00A8F0', '#C0D800', '#cb4b4b', '#4da74d', '#9440ed' ], // =>
// The
// default
// colorscheme.
// When
// there
// are
// > 5
// series,
// additional
// colors
// are
// generated.
title : this.titlePlot.getValue(),
legend : {
show : true, // => setting to true will show the legend, hide
// otherwise
noColumns : 1, // => number of colums in legend table
labelFormatter : null, // => fn: string -> string
labelBoxBorderColor : '#ccc', // => border color for the
// little label boxes
container : null, // => container (as jQuery object) to put
// legend in, null means default on top of
// graph
position : 'ne', // => position of default legend container
// within plot
margin : 5, // => distance from grid edge to default legend
// container within plot
backgroundColor : '#CCCCCC', // => null means auto-detect
backgroundOpacity : 1.0
// => set to 0 to avoid background, set to 1 for a solid background
},
xaxis : {
ticks : null, // => format: either [1, 3] or [[1, 'a'], 3]
noTicks : 5, // => number of ticks for automagically
color : this.comboXColor.getValue() ? this.comboXColor.getValue() : "#000000",
//bind the formater to have the keed the correct scope
tickFormatter : colXFormater.bind(this),
// generated ticks
tickDecimals : null, // => no. of decimals, null means auto
min : null, // => min. value to show, null means set
// automatically
max : null, // => max. value to show, null means set
// automatically
autoscaleMargin : 0, // => margin in % to add if auto-setting
// min/max
title : this.titleX.getValue(),
mode : colXType == "dateAsString" ? "time" : "Normal",
labelsAngle : colXType == "dateAsString" ? 45 : 0,
timeFormat : this.xFormat ? this.xFormat.getValue() : SITOOLS_DATE_FORMAT
// ,
// scale : scaleTypeFromCheckBox(logX)
},
yaxis : {
ticks : null, // => format: either [1, 3] or [[1, 'a'], 3]
color : this.comboYColor.getValue() ? this.comboYColor.getValue() : "#000000",
noTicks : 5, // => number of ticks for automagically
// generated ticks
tickDecimals : null, // => no. of decimals, null means auto
//bind the formater to have the keed the correct scope
tickFormatter : colYFormater.bind(this),
min : null, // => min. value to show, null means set
// automatically
max : null, // => max. value to show, null means set
// automatically
autoscaleMargin : 0, // => margin in % to add if auto-setting
// min/max
title : this.titleY.getValue(),
mode : colYType == "dateAsString" ? "time" : "Normal",
labelsAngle : 0,
timeFormat : SITOOLS_DATE_FORMAT
// ,
// scale : scaleTypeFromCheckBox(logY)
},
y2axis : {
title : ' '
},
points : {
show : true, // => setting to true will show points, false
// will hide
radius : 3, // => point radius (pixels)
lineWidth : 2,
fill : true, // => true to fill the points with a color,
// false for (transparent) no fill
fillColor : '#ffffff' // => fill color
},
lines : {
show : this.checkLine.getValue(), // => setting to true will show
// lines, false will hide
lineWidth : 0.1, // => line width in pixels
fill : false, // => true to fill the area from the line to the
// x axis, false for (transparent) no fill
fillColor : null
// => fill color
},
grid : {
color : '#545454', // => primary color used for outline and
// labels
backgroundColor : '#FFFFFF', // => null for transparent, else
// color
tickColor : '#dddddd', // => color used for the ticks
labelMargin : 3
// => margin in pixels
},
selection : {
mode : 'xy', // => one of null, 'x', 'y' or 'xy'
color : '#B6D9FF', // => selection box color
fps : 10
// => frames-per-second
},
spreadsheet : {
show : false
},
mouse : {
track : true, // => true to track the mouse, no tracking
// otherwise
position : 'se', // => position of the value box (default
// south-east)
margin : 2, // => margin in pixels of the valuebox
color : '#ff3f19', // => line color of points that are drawn
// when mouse comes near a value of a series
trackDecimals : 1, // => decimals for the track values
sensibility : 10 * 1000000000, // => the lower this number, the more
// precise you have to aim to show a value
radius : 3
// => radius of the track point
},
shadowSize : 4
// => size of the 'fake' shadow
};
var out = {
data : d1,
config : plotConfig
};
return out;
},
/**
* Function to show the details of a record
* @param {} evt the event calling the function
*/
showDataDetail : function (evt) {
var idx = encodeURIComponent(evt.memo[1].prevHit.primaryKey);
var jsObj = sitools.user.component.viewDataDetail;
var componentCfg = {
datasetUrl : this.dataUrl,
baseUrl : this.dataUrl + '/records',
datasetId : this.datasetId,
fromWhere : "plot",
url : this.dataUrl + '/records/' + idx,
preferencesPath : "/" + this.datasetName,
preferencesFileName : "dataDetails"
};
var windowConfig = {
id : "simpleDataDetail" + this.datasetId,
title : i18n.get('label.viewDataDetail') + " : " + evt.memo[1].prevHit.primaryKey,
datasetName : this.datasetName,
saveToolbar : false,
type : "simpleDataDetail",
iconCls : "dataDetail"
};
SitoolsDesk.addDesktopWindow(windowConfig, componentCfg, jsObj, true);
},
/**
* Handler to change the plot layout.
* Should be used in a form param event
*/
handlePlotLayout : function () {
if (this.hasPlotted) {
this.displayPlot(this.storeData.data.items);
}
}
});
Ext.reg('sitools.user.component.dataPlotter', sitools.user.component.dataPlotter);
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, getDesktop*/
Ext.ns('sitools.widget');
/**
* A specific window to display preview Images in user desktop.
* @class sitools.widget.WindowImageViewer
* @config {boolean} resizeImage true to resize the image according to the desktop, image ratio is also keeped.
* false to keep the image size with scrollbars if needed. Default to false
* @extends Ext.Window
*/
sitools.widget.WindowImageViewer = Ext.extend(Ext.Window, {
resizeImage : false,
maximizable : true,
modal : true,
minHeight : 0,
minWidth : 0,
initComponent : function () {
// this.renderTo = SitoolsDesk.getDesktop().getDesktopEl();
if (!this.resizeImage) {
this.panel = new Ext.Panel({
bodyCfg : {
tag : 'img',
src : this.src
},
listeners : {
scope : this,
render : function () {
this.panel.body.on('load', this.onImageLoad, this, {
single : true
});
}
}
});
this.items = [this.panel];
this.autoScroll=true;
} else {
this.bodyCfg = {
tag : 'img',
src : this.src
};
}
this.constrain = true;
sitools.widget.WindowImageViewer.superclass.initComponent.apply(this, arguments);
},
onRender : function () {
sitools.widget.WindowImageViewer.superclass.onRender.apply(this, arguments);
if(this.resizeImage){
this.body.on('load', this.onImageLoad, this, {
single : true
});
}
},
/**
* Method called when the image is loaded. It is in charge of resizing the image according to the desktop size
*/
onImageLoad : function () {
var imgTag = Ext.DomQuery.select("div[id='"+this.id+"'] img")[0];
var hi = this.body.dom.offsetHeight;
var wi = this.body.dom.offsetWidth;
var hiImg = imgTag.offsetHeight;
var wiImg = imgTag.offsetWidth;
if (!this.resizeImage) {
this.panel.setSize(wiImg, hiImg);
}
var desktop = getDesktop();
var ww = desktop.getWinWidth();
var hw = desktop.getWinHeight();
var reduce = false;
if (hi > hw) {
wi = wi * hw / hi;
hi = hw;
reduce = true;
}
if (wi > ww) {
hi = hi * ww / wi;
wi = ww;
reduce = true;
}
if (reduce) {
hi *= 0.9;
wi *= 0.9;
}
this.setSize(wi + this.getFrameWidth(), hi + this.getFrameHeight());
// if (Ext.isIE) {
this.center();
// }
},
setSrc : function (src) {
var panel;
if(resizeImage){
panel = this;
}else {
panel = this.panel;
}
panel.body.on('load', this.onImageLoad, this, {
single : true
});
panel.body.dom.style.width = panel.body.dom.style.width = 'auto';
panel.body.dom.src = src;
},
initEvents : function () {
sitools.widget.WindowImageViewer.superclass.initEvents.apply(this, arguments);
if (this.resizer && this.resizeImage) {
this.resizer.preserveRatio = true;
}
}
});
/**
* A specific panel to display preview Images in user desktop.
* @class sitools.widget.WindowImageViewer
* @extends Ext.Window
*/
sitools.widget.PanelImageViewer = Ext.extend(Ext.Panel, {
initComponent : function () {
this.bodyCfg = {
tag : 'img',
src : this.src
};
sitools.widget.PanelImageViewer.superclass.initComponent.apply(this, arguments);
},
onRender : function () {
sitools.widget.PanelImageViewer.superclass.onRender.apply(this, arguments);
this.body.on('load', this.onImageLoad, this, {
single : true
});
},
onImageLoad : function () {
var h = this.getFrameHeight(), w = this.getFrameWidth();
this.setSize(this.body.dom.offsetWidth + w, this.body.dom.offsetHeight + h);
if (Ext.isIE) {
this.center();
}
},
setSrc : function (src) {
this.body.on('load', this.onImageLoad, this, {
single : true
});
this.body.dom.style.width = this.body.dom.style.width = 'auto';
this.body.dom.src = src;
},
initEvents : function () {
sitools.widget.PanelImageViewer.superclass.initEvents.apply(this, arguments);
if (this.resizer) {
this.resizer.preserveRatio = true;
}
},
/**
* Method called when trying to show this component with fixed navigation
*
* @param {sitools.user.component.viewDataDetail} me the dataDetail view
* @param {} config config options
* @returns
*/
showMeInFixedNav : function (me, config) {
me.show();
},
/**
* Method called when trying to show this component with Desktop navigation
*
* @param {sitools.user.component.viewDataDetail} me the dataDetail view
* @param {} config config options
* @returns
*/
showMeInDesktopNav : function (me, config) {
me.show();
}
});
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, ID, i18n, document, showResponse, alertFailure*/
Ext.namespace('sitools.component.version');
sitools.component.version.sitoolsVersion = Ext.extend(Ext.Panel, {
layout : 'fit',
version : null,
initComponent : function () {
this.versionUrl = loadUrl.get('APP_URL') + '/version';
var title = new Ext.form.Label({
html : '<h2>SITools2</h2'
});
var logo = new Ext.form.Label({
html : '<img src='+loadUrl.get('APP_URL')+'/res/images/logo_02_tailleMoyenne.png>'
});
var credits = new Ext.form.Label({
html : '<p>Copyright 2010, 2011, 2012 CNES</p>'
});
var website = new Ext.form.Label({
html : '<a href="http://www.sitools2.sourceforge.net">sitools2.sourceforge.net</>'
});
this.versionLabel = new Ext.form.Label({
});
var panelVersion = new Ext.Panel({
title : i18n.get("label.version"),
layout : 'fit',
padding : 10
});
var panelLicence = new Ext.ux.ManagedIFrame.Panel({
title : i18n.get("label.licence"),
layout : 'fit',
defaultSrc : loadUrl.get('APP_URL') + "/res/licences/gpl-3.0.txt"
});
panelVersion.add([logo, title, this.versionLabel, credits, website]);
this.tabs = new Ext.TabPanel({
activeTab: 0,
items: [ panelVersion, panelLicence]
});
this.items = [this.tabs];
this.listeners = {
scope : this,
resize : function (window) {
var size = window.body.getSize();
this.tabs.setSize(size);
}
};
sitools.component.version.sitoolsVersion.superclass.initComponent.call(this);
},
afterRender : function () {
sitools.component.version.sitoolsVersion.superclass.afterRender.apply(this, arguments);
Ext.Ajax.request({
url : this.versionUrl,
method : 'GET',
scope : this,
success : function (ret) {
var json = Ext.decode(ret.responseText);
if (!json.success) {
Ext.Msg.alert(i18n.get('label.warning'), json.message);
return false;
}
this.version = json.version;
this.versionLabel.setText("<h3>Version : " + this.version + "</h3>", false);
//this.doLayout();
},
failure : alertFailure
});
var size = this.ownerCt.body.getSize();
this.tabs.setSize(size);
}
});
function showVersion () {
var versionHelp = Ext.getCmp('winVersionId');
if (!versionHelp) {
var panelHelp = new sitools.component.version.sitoolsVersion();
versionHelp = new Ext.Window({
title : i18n.get('label.version'),
id : 'winVersionId',
items : [panelHelp],
modal : false,
width : 700,
height : 480,
resizable : false,
modal : true,
buttons : [{
text : i18n.get('label.close'),
handler : function () {
this.ownerCt.ownerCt.close();
}
} ]
});
versionHelp.show();
} else {
versionHelp.show();
}
}
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*
* Ext JS Library 3.2.1
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
/**
* @class Ext.ux.Spinner
* @extends Ext.util.Observable
* Creates a Spinner control utilized by Ext.ux.form.SpinnerField
*/
Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
incrementValue: 1,
alternateIncrementValue: 5,
triggerClass: 'x-form-spinner-trigger',
splitterClass: 'x-form-spinner-splitter',
alternateKey: Ext.EventObject.shiftKey,
defaultValue: 0,
accelerate: false,
constructor: function(config){
Ext.ux.Spinner.superclass.constructor.call(this, config);
Ext.apply(this, config);
this.mimicing = false;
},
init: function(field){
this.field = field;
field.afterMethod('onRender', this.doRender, this);
field.afterMethod('onEnable', this.doEnable, this);
field.afterMethod('onDisable', this.doDisable, this);
field.afterMethod('afterRender', this.doAfterRender, this);
field.afterMethod('onResize', this.doResize, this);
field.afterMethod('onFocus', this.doFocus, this);
field.beforeMethod('onDestroy', this.doDestroy, this);
},
doRender: function(ct, position){
var el = this.el = this.field.getEl();
var f = this.field;
if (!f.wrap) {
f.wrap = this.wrap = el.wrap({
cls: "x-form-field-wrap"
});
}
else {
this.wrap = f.wrap.addClass('x-form-field-wrap');
}
this.trigger = this.wrap.createChild({
tag: "img",
src: Ext.BLANK_IMAGE_URL,
cls: "x-form-trigger " + this.triggerClass
});
if (!f.width) {
this.wrap.setWidth(el.getWidth() + this.trigger.getWidth());
}
this.splitter = this.wrap.createChild({
tag: 'div',
cls: this.splitterClass,
style: 'width:13px; height:2px;'
});
this.splitter.setRight((Ext.isIE) ? 1 : 2).setTop(10).show();
this.proxy = this.trigger.createProxy('', this.splitter, true);
this.proxy.addClass("x-form-spinner-proxy");
this.proxy.setStyle('left', '0px');
this.proxy.setSize(14, 1);
this.proxy.hide();
this.dd = new Ext.dd.DDProxy(this.splitter.dom.id, "SpinnerDrag", {
dragElId: this.proxy.id
});
this.initTrigger();
this.initSpinner();
},
doAfterRender: function(){
var y;
if (Ext.isIE && this.el.getY() != (y = this.trigger.getY())) {
this.el.position();
this.el.setY(y);
}
},
doEnable: function(){
if (this.wrap) {
this.wrap.removeClass(this.field.disabledClass);
}
},
doDisable: function(){
if (this.wrap) {
this.wrap.addClass(this.field.disabledClass);
this.el.removeClass(this.field.disabledClass);
}
},
doResize: function(w, h){
if (typeof w == 'number') {
this.el.setWidth(w - this.trigger.getWidth());
}
this.wrap.setWidth(this.el.getWidth() + this.trigger.getWidth());
},
doFocus: function(){
if (!this.mimicing) {
this.wrap.addClass('x-trigger-wrap-focus');
this.mimicing = true;
Ext.get(Ext.isIE ? document.body : document).on("mousedown", this.mimicBlur, this, {
delay: 10
});
this.el.on('keydown', this.checkTab, this);
}
},
// private
checkTab: function(e){
if (e.getKey() == e.TAB) {
this.triggerBlur();
}
},
// private
mimicBlur: function(e){
if (!this.wrap.contains(e.target) && this.field.validateBlur(e)) {
this.triggerBlur();
}
},
// private
triggerBlur: function(){
this.mimicing = false;
Ext.get(Ext.isIE ? document.body : document).un("mousedown", this.mimicBlur, this);
this.el.un("keydown", this.checkTab, this);
this.field.beforeBlur();
this.wrap.removeClass('x-trigger-wrap-focus');
this.field.onBlur.call(this.field);
},
initTrigger: function(){
this.trigger.addClassOnOver('x-form-trigger-over');
this.trigger.addClassOnClick('x-form-trigger-click');
},
initSpinner: function(){
this.field.addEvents({
'spin': true,
'spinup': true,
'spindown': true
});
this.keyNav = new Ext.KeyNav(this.el, {
"up": function(e){
e.preventDefault();
this.onSpinUp();
},
"down": function(e){
e.preventDefault();
this.onSpinDown();
},
"pageUp": function(e){
e.preventDefault();
this.onSpinUpAlternate();
},
"pageDown": function(e){
e.preventDefault();
this.onSpinDownAlternate();
},
scope: this
});
this.repeater = new Ext.util.ClickRepeater(this.trigger, {
accelerate: this.accelerate
});
this.field.mon(this.repeater, "click", this.onTriggerClick, this, {
preventDefault: true
});
this.field.mon(this.trigger, {
mouseover: this.onMouseOver,
mouseout: this.onMouseOut,
mousemove: this.onMouseMove,
mousedown: this.onMouseDown,
mouseup: this.onMouseUp,
scope: this,
preventDefault: true
});
this.field.mon(this.wrap, "mousewheel", this.handleMouseWheel, this);
this.dd.setXConstraint(0, 0, 10)
this.dd.setYConstraint(1500, 1500, 10);
this.dd.endDrag = this.endDrag.createDelegate(this);
this.dd.startDrag = this.startDrag.createDelegate(this);
this.dd.onDrag = this.onDrag.createDelegate(this);
},
onMouseOver: function(){
if (this.disabled) {
return;
}
var middle = this.getMiddle();
this.tmpHoverClass = (Ext.EventObject.getPageY() < middle) ? 'x-form-spinner-overup' : 'x-form-spinner-overdown';
this.trigger.addClass(this.tmpHoverClass);
},
//private
onMouseOut: function(){
this.trigger.removeClass(this.tmpHoverClass);
},
//private
onMouseMove: function(){
if (this.disabled) {
return;
}
var middle = this.getMiddle();
if (((Ext.EventObject.getPageY() > middle) && this.tmpHoverClass == "x-form-spinner-overup") ||
((Ext.EventObject.getPageY() < middle) && this.tmpHoverClass == "x-form-spinner-overdown")) {
}
},
//private
onMouseDown: function(){
if (this.disabled) {
return;
}
var middle = this.getMiddle();
this.tmpClickClass = (Ext.EventObject.getPageY() < middle) ? 'x-form-spinner-clickup' : 'x-form-spinner-clickdown';
this.trigger.addClass(this.tmpClickClass);
},
//private
onMouseUp: function(){
this.trigger.removeClass(this.tmpClickClass);
},
//private
onTriggerClick: function(){
if (this.disabled || this.el.dom.readOnly) {
return;
}
var middle = this.getMiddle();
var ud = (Ext.EventObject.getPageY() < middle) ? 'Up' : 'Down';
this['onSpin' + ud]();
},
//private
getMiddle: function(){
var t = this.trigger.getTop();
var h = this.trigger.getHeight();
var middle = t + (h / 2);
return middle;
},
//private
//checks if control is allowed to spin
isSpinnable: function(){
if (this.disabled || this.el.dom.readOnly) {
Ext.EventObject.preventDefault(); //prevent scrolling when disabled/readonly
return false;
}
return true;
},
handleMouseWheel: function(e){
//disable scrolling when not focused
if (this.wrap.hasClass('x-trigger-wrap-focus') == false) {
return;
}
var delta = e.getWheelDelta();
if (delta > 0) {
this.onSpinUp();
e.stopEvent();
}
else
if (delta < 0) {
this.onSpinDown();
e.stopEvent();
}
},
//private
startDrag: function(){
this.proxy.show();
this._previousY = Ext.fly(this.dd.getDragEl()).getTop();
},
//private
endDrag: function(){
this.proxy.hide();
},
//private
onDrag: function(){
if (this.disabled) {
return;
}
var y = Ext.fly(this.dd.getDragEl()).getTop();
var ud = '';
if (this._previousY > y) {
ud = 'Up';
} //up
if (this._previousY < y) {
ud = 'Down';
} //down
if (ud != '') {
this['onSpin' + ud]();
}
this._previousY = y;
},
//private
onSpinUp: function(){
if (this.isSpinnable() == false) {
return;
}
if (Ext.EventObject.shiftKey == true) {
this.onSpinUpAlternate();
return;
}
else {
this.spin(false, false);
}
this.field.fireEvent("spin", this);
this.field.fireEvent("spinup", this);
},
//private
onSpinDown: function(){
if (this.isSpinnable() == false) {
return;
}
if (Ext.EventObject.shiftKey == true) {
this.onSpinDownAlternate();
return;
}
else {
this.spin(true, false);
}
this.field.fireEvent("spin", this);
this.field.fireEvent("spindown", this);
},
//private
onSpinUpAlternate: function(){
if (this.isSpinnable() == false) {
return;
}
this.spin(false, true);
this.field.fireEvent("spin", this);
this.field.fireEvent("spinup", this);
},
//private
onSpinDownAlternate: function(){
if (this.isSpinnable() == false) {
return;
}
this.spin(true, true);
this.field.fireEvent("spin", this);
this.field.fireEvent("spindown", this);
},
spin: function(down, alternate){
var v = parseFloat(this.field.getValue());
var incr = (alternate == true) ? this.alternateIncrementValue : this.incrementValue;
(down == true) ? v -= incr : v += incr;
v = (isNaN(v)) ? this.defaultValue : v;
v = this.fixBoundries(v);
this.field.setRawValue(v);
},
fixBoundries: function(value){
var v = value;
if (this.field.minValue != undefined && v < this.field.minValue) {
v = this.field.minValue;
}
if (this.field.maxValue != undefined && v > this.field.maxValue) {
v = this.field.maxValue;
}
return this.fixPrecision(v);
},
// private
fixPrecision: function(value){
var nan = isNaN(value);
if (!this.field.allowDecimals || this.field.decimalPrecision == -1 || nan || !value) {
return nan ? '' : value;
}
return parseFloat(parseFloat(value).toFixed(this.field.decimalPrecision));
},
doDestroy: function(){
if (this.trigger) {
this.trigger.remove();
}
if (this.wrap) {
this.wrap.remove();
delete this.field.wrap;
}
if (this.splitter) {
this.splitter.remove();
}
if (this.dd) {
this.dd.unreg();
this.dd = null;
}
if (this.proxy) {
this.proxy.remove();
}
if (this.repeater) {
this.repeater.purgeListeners();
}
}
});
//backwards compat
Ext.form.Spinner = Ext.ux.Spinner;
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*
* Ext JS Library 3.2.1
* Copyright(c) 2006-2010 Ext JS, Inc.
* licensing@extjs.com
* http://www.extjs.com/license
*/
Ext.ns('Ext.ux.form');
/**
* @class Ext.ux.form.SpinnerField
* @extends Ext.form.NumberField
* Creates a field utilizing Ext.ux.Spinner
* @xtype spinnerfield
*/
Ext.ux.form.SpinnerField = Ext.extend(Ext.form.NumberField, {
actionMode: 'wrap',
deferHeight: true,
autoSize: Ext.emptyFn,
onBlur: Ext.emptyFn,
adjustSize: Ext.BoxComponent.prototype.adjustSize,
constructor: function(config) {
var spinnerConfig = Ext.copyTo({}, config, 'incrementValue,alternateIncrementValue,accelerate,defaultValue,triggerClass,splitterClass');
var spl = this.spinner = new Ext.ux.Spinner(spinnerConfig);
var plugins = config.plugins
? (Ext.isArray(config.plugins)
? config.plugins.push(spl)
: [config.plugins, spl])
: spl;
Ext.ux.form.SpinnerField.superclass.constructor.call(this, Ext.apply(config, {plugins: plugins}));
},
// private
getResizeEl: function(){
return this.wrap;
},
// private
getPositionEl: function(){
return this.wrap;
},
// private
alignErrorIcon: function(){
if (this.wrap) {
this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
}
},
validateBlur: function(){
return true;
}
});
Ext.reg('spinnerfield', Ext.ux.form.SpinnerField);
//backwards compat
Ext.form.SpinnerField = Ext.ux.form.SpinnerField;
/**
* Define a specific DatePicker to offer possibility to choose Hours Minutes and Seconds
* @class Ext.SitoolsDatePicker
* @extends Ext.BoxComponent
*/
Ext.SitoolsDatePicker = Ext.extend(Ext.BoxComponent, {
todayText : 'Today',
/**
* @cfg {String} okText
* The text to display on the ok button (defaults to <code>' OK '</code> to give the user extra clicking room)
*/
okText : ' OK ',
/**
* @cfg {String} cancelText
* The text to display on the cancel button (defaults to <code>'Cancel'</code>)
*/
cancelText : 'Cancel',
/**
* @cfg {Function} handler
* Optional. A function that will handle the select event of this picker.
* The handler is passed the following parameters:<div class="mdetail-params"><ul>
* <li><code>picker</code> : DatePicker<div class="sub-desc">This DatePicker.</div></li>
* <li><code>date</code> : Date<div class="sub-desc">The selected date.</div></li>
* </ul></div>
*/
/**
* @cfg {Object} scope
* The scope (<code><b>this</b></code> reference) in which the <code>{@link #handler}</code>
* function will be called. Defaults to this DatePicker instance.
*/
/**
* @cfg {String} todayTip
* A string used to format the message for displaying in a tooltip over the button that
* selects the current date. Defaults to <code>'{0} (Spacebar)'</code> where
* the <code>{0}</code> token is replaced by today's date.
*/
todayTip : '{0} (Spacebar)',
/**
* @cfg {String} minText
* The error text to display if the minDate validation fails (defaults to <code>'This date is before the minimum date'</code>)
*/
minText : 'This date is before the minimum date',
/**
* @cfg {String} maxText
* The error text to display if the maxDate validation fails (defaults to <code>'This date is after the maximum date'</code>)
*/
maxText : 'This date is after the maximum date',
/**
* @cfg {String} format
* The default date format string which can be overriden for localization support. The format must be
* valid according to {@link Date#parseDate} (defaults to <code>'m/d/y'</code>).
*/
format : 'm/d/y',
/**
* @cfg {String} disabledDaysText
* The tooltip to display when the date falls on a disabled day (defaults to <code>'Disabled'</code>)
*/
disabledDaysText : 'Disabled',
/**
* @cfg {String} disabledDatesText
* The tooltip text to display when the date falls on a disabled date (defaults to <code>'Disabled'</code>)
*/
disabledDatesText : 'Disabled',
/**
* @cfg {Array} monthNames
* An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
*/
monthNames : Date.monthNames,
/**
* @cfg {Array} dayNames
* An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
*/
dayNames : Date.dayNames,
/**
* @cfg {String} nextText
* The next month navigation button tooltip (defaults to <code>'Next Month (Control+Right)'</code>)
*/
nextText : 'Next Month (Control+Right)',
/**
* @cfg {String} prevText
* The previous month navigation button tooltip (defaults to <code>'Previous Month (Control+Left)'</code>)
*/
prevText : 'Previous Month (Control+Left)',
/**
* @cfg {String} monthYearText
* The header month selector tooltip (defaults to <code>'Choose a month (Control+Up/Down to move years)'</code>)
*/
monthYearText : 'Choose a month (Control+Up/Down to move years)',
/**
* @cfg {Number} startDay
* Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
*/
startDay : 0,
/**
* @cfg {Boolean} showToday
* False to hide the footer area containing the Today button and disable the keyboard handler for spacebar
* that selects the current date (defaults to <code>true</code>).
*/
showToday : true,
/**
* @cfg {Boolean} showTime
* False to hide the footer area containing the hour definition
* (defaults to <code>false</code>).
*/
showTime : false,
// private
// Set by other components to stop the picker focus being updated when the value changes.
focusOnSelect: true,
// default value used to initialise each date in the DatePicker
// (note: 12 noon was chosen because it steers well clear of all DST timezone changes)
initHour: 12,
initComponent : function(){
Ext.SitoolsDatePicker.superclass.initComponent.call(this);
this.value = this.value ?
this.value.clearTime(true) : new Date().clearTime();
this.hourValue = this.value ? this.value.getHours() : new Date().getHours();
this.minuteValue = this.value ? this.value.getMinutes() : new Date().getMinutes();
this.secondValue = this.value ? this.value.getSeconds() : new Date().getSeconds();
this.addEvents(
'select'
);
if(this.handler){
this.on('select', this.handler, this.scope || this);
}
this.initDisabledDays();
},
// private
initDisabledDays : function(){
if(!this.disabledDatesRE && this.disabledDates){
var dd = this.disabledDates,
len = dd.length - 1,
re = '(?:';
Ext.each(dd, function(d, i){
re += Ext.isDate(d) ? '^' + Ext.escapeRe(d.dateFormat(this.format)) + '$' : dd[i];
if(i != len){
re += '|';
}
}, this);
this.disabledDatesRE = new RegExp(re + ')');
}
},
/**
* Replaces any existing disabled dates with new values and refreshes the DatePicker.
* @param {Array/RegExp} disabledDates An array of date strings (see the {@link #disabledDates} config
* for details on supported values), or a JavaScript regular expression used to disable a pattern of dates.
*/
setDisabledDates : function(dd){
if(Ext.isArray(dd)){
this.disabledDates = dd;
this.disabledDatesRE = null;
}else{
this.disabledDatesRE = dd;
}
this.initDisabledDays();
this.update(this.value, true);
},
/**
* Replaces any existing disabled days (by index, 0-6) with new values and refreshes the DatePicker.
* @param {Array} disabledDays An array of disabled day indexes. See the {@link #disabledDays} config
* for details on supported values.
*/
setDisabledDays : function(dd){
this.disabledDays = dd;
this.update(this.value, true);
},
/**
* Replaces any existing {@link #minDate} with the new value and refreshes the DatePicker.
* @param {Date} value The minimum date that can be selected
*/
setMinDate : function(dt){
this.minDate = dt;
this.update(this.value, true);
},
/**
* Replaces any existing {@link #maxDate} with the new value and refreshes the DatePicker.
* @param {Date} value The maximum date that can be selected
*/
setMaxDate : function(dt){
this.maxDate = dt;
this.update(this.value, true);
},
/**
* Sets the value of the date field
* @param {Date} value The date to set
*/
setValue : function(value){
this.value = value;
this.update(this.value);
},
/**
* Gets the current selected value of the date field
* @return {Date} The selected date
*/
getValue : function(){
return this.value;
},
// private
focus : function(){
this.update(this.activeDate);
if (this.showTime) {
this.updateTime(this.activeDate);
}
},
// private
updateTime : function (date) {
this.hourField.setValue(date.getHours());
this.minuteField.setValue(date.getMinutes());
this.secondField.setValue(date.getSeconds());
},
// private
onEnable: function(initial){
Ext.SitoolsDatePicker.superclass.onEnable.call(this);
this.doDisabled(false);
this.update(initial ? this.value : this.activeDate);
if(Ext.isIE){
this.el.repaint();
}
},
// private
onDisable : function(){
Ext.SitoolsDatePicker.superclass.onDisable.call(this);
this.doDisabled(true);
if(Ext.isIE && !Ext.isIE8){
/* Really strange problem in IE6/7, when disabled, have to explicitly
* repaint each of the nodes to get them to display correctly, simply
* calling repaint on the main element doesn't appear to be enough.
*/
Ext.each([].concat(this.textNodes, this.el.query('th span')), function(el){
Ext.fly(el).repaint();
});
}
},
// private
doDisabled : function(disabled){
this.keyNav.setDisabled(disabled);
this.prevRepeater.setDisabled(disabled);
this.nextRepeater.setDisabled(disabled);
if(this.showToday){
this.todayKeyListener.setDisabled(disabled);
this.todayBtn.setDisabled(disabled);
}
},
// private
onRender : function(container, position){
var m = [
'<table cellspacing="0">',
'<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'"> </a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'"> </a></td></tr>',
'<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'],
dn = this.dayNames,
i;
for(i = 0; i < 7; i++){
var d = this.startDay+i;
if(d > 6){
d = d-7;
}
m.push('<th><span>', dn[d].substr(0,1), '</span></th>');
}
m[m.length] = '</tr></thead><tbody><tr>';
for(i = 0; i < 42; i++) {
if(i % 7 === 0 && i !== 0){
m[m.length] = '</tr><tr>';
}
m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
}
m.push('</tr></tbody></table></td></tr>',
this.showTime ? '<tr><td colspan="3" class="x-date-time" align="center"></td></tr>' : '',
this.showToday ? '<tr><td colspan="3" class="x-date-bottom" align="center"></td></tr>' : '',
'</table><div class="x-date-mp"></div>');
var el = document.createElement('div');
el.className = 'x-date-picker';
el.innerHTML = m.join('');
container.dom.insertBefore(el, position);
this.el = Ext.get(el);
this.eventEl = Ext.get(el.firstChild);
this.prevRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-left a'), {
handler: this.showPrevMonth,
scope: this,
preventDefault:true,
stopDefault:true
});
this.nextRepeater = new Ext.util.ClickRepeater(this.el.child('td.x-date-right a'), {
handler: this.showNextMonth,
scope: this,
preventDefault:true,
stopDefault:true
});
this.monthPicker = this.el.down('div.x-date-mp');
this.monthPicker.enableDisplayMode('block');
this.keyNav = new Ext.KeyNav(this.eventEl, {
'left' : function(e){
if(e.ctrlKey){
this.showPrevMonth();
}else{
this.update(this.activeDate.add('d', -1));
}
},
'right' : function(e){
if(e.ctrlKey){
this.showNextMonth();
}else{
this.update(this.activeDate.add('d', 1));
}
},
'up' : function(e){
if(e.ctrlKey){
this.showNextYear();
}else{
this.update(this.activeDate.add('d', -7));
}
},
'down' : function(e){
if(e.ctrlKey){
this.showPrevYear();
}else{
this.update(this.activeDate.add('d', 7));
}
},
'pageUp' : function(e){
this.showNextMonth();
},
'pageDown' : function(e){
this.showPrevMonth();
},
'enter' : function(e){
e.stopPropagation();
return true;
},
scope : this
});
//Suppress unselectable option to allow chrome input fields to be modified.
// this.el.unselectable();
this.cells = this.el.select('table.x-date-inner tbody td');
this.textNodes = this.el.query('table.x-date-inner tbody span');
this.mbtn = new Ext.Button({
text: ' ',
tooltip: this.monthYearText,
renderTo: this.el.child('td.x-date-middle', true)
});
this.mbtn.el.child('em').addClass('x-btn-arrow');
if(this.showToday){
this.todayKeyListener = this.eventEl.addKeyListener(Ext.EventObject.SPACE, this.selectToday, this);
var today = (new Date()).dateFormat(this.format);
this.todayBtn = new Ext.Button({
renderTo: this.el.child('td.x-date-bottom', true),
text: String.format(this.todayText, today),
tooltip: String.format(this.todayTip, today),
handler: this.selectToday,
scope: this
});
}
if (this.showTime){
this.hourField = new Ext.form.TextField({
value : this.hourValue,
width : "25"
,
listeners : {
scope : this,
specialkey : function (field, e) {
if (e.getKey() == e.TAB) {
if (e.shiftKey) {
this.secondField.focus();
}
else {
this.minuteField.focus();
}
}
}
}
,
maxLength : 2,
maskRe : /[0-9]/,
disabled : false,
validationEvent : "blur",
validator : function (value) {
var intValue = parseInt(value);
if (!Ext.isEmpty(intValue) && intValue <= 23 && intValue >= 0) {
if (value.length == 1) {
this.setValue("0" + value);
}
return true;
}
else {
return "incorrect Value";
}
}
});
this.minuteField = new Ext.form.TextField({
value : this.minuteValue,
width : "25",
listeners : {
scope : this,
specialkey : function (field, e) {
if (e.getKey() == e.TAB) {
if (e.shiftKey) {
this.hourField.focus();
}
else {
this.secondField.focus();
}
}
}
},
maxLength : 2,
maskRe : /[0-9]/,
validationEvent : "blur",
validator : function (value) {
var intValue = parseInt(value);
if (!Ext.isEmpty(intValue) && intValue <= 59 && intValue >= 0) {
if (value.length == 1) {
this.setValue("0" + value);
}
return true;
}
else {
return "incorrect Value";
}
}
});
this.secondField = new Ext.form.TextField({
value : this.minuteValue,
width : "25",
listeners : {
scope : this,
specialkey : function (field, e) {
if (e.getKey() == e.TAB) {
if (e.shiftKey) {
this.minuteField.focus();
}
else {
this.hourField.focus();
}
}
}
},
maxLength : 2,
maskRe : /[0-9]/,
validationEvent : "blur",
validator : function (value) {
var intValue = parseInt(value);
if (!Ext.isEmpty(intValue) && intValue <= 59 && intValue >= 0) {
if (value.length == 1) {
this.setValue("0" + value);
}
return true;
}
else {
return "incorrect Value";
}
}
});
var sepLabel1 = new Ext.form.DisplayField({
value : ":"
});
var sepLabel2 = new Ext.form.DisplayField({
value : ":"
});
this.timeForm = new Ext.form.FormPanel({
labelWidth : 1,
itemsCls : "sitools-no-margin",
items : [{
xtype : "compositefield",
width : 135,
style : {
padding : "3px"
},
items : [this.hourField, sepLabel1, this.minuteField, sepLabel2, this.secondField]
}],
renderTo : this.el.child('td.x-date-time', true)
});
/**/
}
this.mon(this.eventEl, 'mousewheel', this.handleMouseWheel, this);
this.mon(this.eventEl, 'click', this.handleDateClick, this, {delegate: 'a.x-date-date'});
this.mon(this.mbtn, 'click', this.showMonthPicker, this);
this.onEnable(true);
},
// private
createMonthPicker : function(){
if(!this.monthPicker.dom.firstChild){
var buf = ['<table border="0" cellspacing="0">'];
for(var i = 0; i < 6; i++){
buf.push(
'<tr><td class="x-date-mp-month"><a href="#">', Date.getShortMonthName(i), '</a></td>',
'<td class="x-date-mp-month x-date-mp-sep"><a href="#">', Date.getShortMonthName(i + 6), '</a></td>',
i === 0 ?
'<td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-prev"></a></td><td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-next"></a></td></tr>' :
'<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
);
}
buf.push(
'<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
this.okText,
'</button><button type="button" class="x-date-mp-cancel">',
this.cancelText,
'</button></td></tr>',
'</table>'
);
this.monthPicker.update(buf.join(''));
this.mon(this.monthPicker, 'click', this.onMonthClick, this);
this.mon(this.monthPicker, 'dblclick', this.onMonthDblClick, this);
this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
this.mpYears = this.monthPicker.select('td.x-date-mp-year');
this.mpMonths.each(function(m, a, i){
i += 1;
if((i%2) === 0){
m.dom.xmonth = 5 + Math.round(i * 0.5);
}else{
m.dom.xmonth = Math.round((i-1) * 0.5);
}
});
}
},
// private
showMonthPicker : function(){
if(!this.disabled){
this.createMonthPicker();
var size = this.el.getSize();
this.monthPicker.setSize(size);
this.monthPicker.child('table').setSize(size);
this.mpSelMonth = (this.activeDate || this.value).getMonth();
this.updateMPMonth(this.mpSelMonth);
this.mpSelYear = (this.activeDate || this.value).getFullYear();
this.updateMPYear(this.mpSelYear);
this.monthPicker.slideIn('t', {duration:0.2});
}
},
// private
updateMPYear : function(y){
this.mpyear = y;
var ys = this.mpYears.elements;
for(var i = 1; i <= 10; i++){
var td = ys[i-1], y2;
if((i%2) === 0){
y2 = y + Math.round(i * 0.5);
td.firstChild.innerHTML = y2;
td.xyear = y2;
}else{
y2 = y - (5-Math.round(i * 0.5));
td.firstChild.innerHTML = y2;
td.xyear = y2;
}
this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
}
},
// private
updateMPMonth : function(sm){
this.mpMonths.each(function(m, a, i){
m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
});
},
// private
selectMPMonth : function(m){
},
// private
onMonthClick : function(e, t){
e.stopEvent();
var el = new Ext.Element(t), pn;
if(el.is('button.x-date-mp-cancel')){
this.hideMonthPicker();
}
else if(el.is('button.x-date-mp-ok')){
var d = new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate());
if(d.getMonth() != this.mpSelMonth){
d = new Date(this.mpSelYear, this.mpSelMonth, 1).getLastDateOfMonth();
}
this.update(d);
this.hideMonthPicker();
}
else if((pn = el.up('td.x-date-mp-month', 2))){
this.mpMonths.removeClass('x-date-mp-sel');
pn.addClass('x-date-mp-sel');
this.mpSelMonth = pn.dom.xmonth;
}
else if((pn = el.up('td.x-date-mp-year', 2))){
this.mpYears.removeClass('x-date-mp-sel');
pn.addClass('x-date-mp-sel');
this.mpSelYear = pn.dom.xyear;
}
else if(el.is('a.x-date-mp-prev')){
this.updateMPYear(this.mpyear-10);
}
else if(el.is('a.x-date-mp-next')){
this.updateMPYear(this.mpyear+10);
}
},
// private
onMonthDblClick : function(e, t){
e.stopEvent();
var el = new Ext.Element(t), pn;
if((pn = el.up('td.x-date-mp-month', 2))){
this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
this.hideMonthPicker();
}
else if((pn = el.up('td.x-date-mp-year', 2))){
this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
this.hideMonthPicker();
}
},
// private
hideMonthPicker : function(disableAnim){
if(this.monthPicker){
if(disableAnim === true){
this.monthPicker.hide();
}else{
this.monthPicker.slideOut('t', {duration:0.2});
}
}
},
// private
showPrevMonth : function(e){
this.update(this.activeDate.add('mo', -1));
},
// private
showNextMonth : function(e){
this.update(this.activeDate.add('mo', 1));
},
// private
showPrevYear : function(){
this.update(this.activeDate.add('y', -1));
},
// private
showNextYear : function(){
this.update(this.activeDate.add('y', 1));
},
// private
handleMouseWheel : function(e){
e.stopEvent();
if(!this.disabled){
var delta = e.getWheelDelta();
if(delta > 0){
this.showPrevMonth();
} else if(delta < 0){
this.showNextMonth();
}
}
},
// private
handleDateClick : function(e, t){
e.stopEvent();
if(!this.disabled && t.dateValue && !Ext.fly(t.parentNode).hasClass('x-date-disabled')){
this.cancelFocus = this.focusOnSelect === false;
var date = new Date(t.dateValue);
if (this.showTime) {
date = date.add(Date.HOUR, this.hourField.getValue());
date = date.add(Date.MINUTE, this.minuteField.getValue());
date = date.add(Date.SECOND, this.secondField.getValue());
if (!this.hourField.isValid() || !this.minuteField.isValid() || !this.secondField.isValid()) {
return;
}
}
this.setValue(date);
delete this.cancelFocus;
this.fireEvent('select', this, this.value);
}
},
// private
selectToday : function(){
if(this.todayBtn && !this.todayBtn.disabled){
var dateNow = new Date();
this.setValue(dateNow);
if (this.showTime) {
this.hourField.setValue(dateNow.getHours());
this.minuteField.setValue(dateNow.getMinutes());
this.secondField.setValue(dateNow.getSeconds());
}
this.fireEvent('select', this, this.value);
}
},
// private
update : function(date, forceRefresh){
if(this.rendered){
if (!Ext.isDate(date)) {
date = new Date();
}
var vd = this.activeDate, vis = this.isVisible();
var dateWithoutTime = new Date(date.getTime());
dateWithoutTime.setHours(0);
dateWithoutTime.setMinutes(0);
dateWithoutTime.setMilliseconds(0);
dateWithoutTime.setSeconds(0);
this.activeDate = date;
if(!forceRefresh && vd && this.el){
var t = dateWithoutTime.getTime();
if(vd.getMonth() == dateWithoutTime.getMonth() && vd.getFullYear() == dateWithoutTime.getFullYear()){
this.cells.removeClass('x-date-selected');
this.cells.each(function(c){
if(c.dom.firstChild.dateValue == t){
c.addClass('x-date-selected');
if(vis && !this.cancelFocus){
Ext.fly(c.dom.firstChild).focus(50);
}
return false;
}
}, this);
return;
}
}
var days = date.getDaysInMonth(),
firstOfMonth = date.getFirstDateOfMonth(),
startingPos = firstOfMonth.getDay()-this.startDay;
if(startingPos < 0){
startingPos += 7;
}
days += startingPos;
var pm = date.add('mo', -1),
prevStart = pm.getDaysInMonth()-startingPos,
cells = this.cells.elements,
textEls = this.textNodes,
d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart, this.initHour));
d.setHours(pm.getHours());
d.setMinutes(pm.getMinutes());
d.setSeconds(pm.getSeconds());
today = new Date().getTime(),
sel = date.clearTime(true).getTime(),
min = this.minDate ? this.minDate.clearTime(true) : Number.NEGATIVE_INFINITY,
max = this.maxDate ? this.maxDate.clearTime(true) : Number.POSITIVE_INFINITY,
ddMatch = this.disabledDatesRE,
ddText = this.disabledDatesText,
ddays = this.disabledDays ? this.disabledDays.join('') : false,
ddaysText = this.disabledDaysText,
format = this.format;
if(this.showToday){
var td = new Date().clearTime(),
disable = (td < min || td > max ||
(ddMatch && format && ddMatch.test(td.dateFormat(format))) ||
(ddays && ddays.indexOf(td.getDay()) != -1));
if(!this.disabled){
this.todayBtn.setDisabled(disable);
this.todayKeyListener[disable ? 'disable' : 'enable']();
}
}
var setCellClass = function(cal, cell){
cell.title = '';
var t = d.clearTime(true).getTime();
cell.firstChild.dateValue = t;
if(t == today){
cell.className += ' x-date-today';
cell.title = cal.todayText;
}
if(t == sel){
cell.className += ' x-date-selected';
if(vis){
Ext.fly(cell.firstChild).focus(50);
}
}
if(t < min) {
cell.className = ' x-date-disabled';
cell.title = cal.minText;
return;
}
if(t > max) {
cell.className = ' x-date-disabled';
cell.title = cal.maxText;
return;
}
if(ddays){
if(ddays.indexOf(d.getDay()) != -1){
cell.title = ddaysText;
cell.className = ' x-date-disabled';
}
}
if(ddMatch && format){
var fvalue = d.dateFormat(format);
if(ddMatch.test(fvalue)){
cell.title = ddText.replace('%0', fvalue);
cell.className = ' x-date-disabled';
}
}
};
var i = 0;
for(; i < startingPos; i++) {
textEls[i].innerHTML = (++prevStart);
d.setDate(d.getDate()+1);
cells[i].className = 'x-date-prevday';
setCellClass(this, cells[i]);
}
for(; i < days; i++){
var intDay = i - startingPos + 1;
textEls[i].innerHTML = (intDay);
d.setDate(d.getDate()+1);
cells[i].className = 'x-date-active';
setCellClass(this, cells[i]);
}
var extraDays = 0;
for(; i < 42; i++) {
textEls[i].innerHTML = (++extraDays);
d.setDate(d.getDate()+1);
cells[i].className = 'x-date-nextday';
setCellClass(this, cells[i]);
}
this.mbtn.setText(this.monthNames[date.getMonth()] + ' ' + date.getFullYear());
if(!this.internalRender){
var main = this.el.dom.firstChild,
w = main.offsetWidth;
this.el.setWidth(w + this.el.getBorderWidth('lr'));
Ext.fly(main).setWidth(w);
this.internalRender = true;
if(Ext.isOpera && !this.secondPass){
main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + 'px';
this.secondPass = true;
this.update.defer(10, this, [date]);
}
}
}
},
// private
beforeDestroy : function() {
if(this.rendered){
Ext.destroy(
this.keyNav,
this.monthPicker,
this.eventEl,
this.mbtn,
this.nextRepeater,
this.prevRepeater,
this.cells.el,
this.todayBtn
);
delete this.textNodes;
delete this.cells.elements;
}
}
});
Ext.reg('datepicker', Ext.SitoolsDatePicker);
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*
* Ext JS Library 3.3.1
* Copyright(c) 2006-2010 Sencha Inc.
* licensing@sencha.com
* http://www.sencha.com/license
*/
Ext.ns('Ext.ux.form');
/**
* @class Ext.ux.form.FileUploadField
* @extends Ext.form.TextField
* Creates a file upload field.
* @xtype fileuploadfield
*/
Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
/**
* @cfg {String} buttonText The button text to display on the upload button (defaults to
* 'Browse...'). Note that if you supply a value for {@link #buttonCfg}, the buttonCfg.text
* value will be used instead if available.
*/
buttonText: 'Browse...',
/**
* @cfg {Boolean} buttonOnly True to display the file upload field as a button with no visible
* text field (defaults to false). If true, all inherited TextField members will still be available.
*/
buttonOnly: false,
/**
* @cfg {Number} buttonOffset The number of pixels of space reserved between the button and the text field
* (defaults to 3). Note that this only applies if {@link #buttonOnly} = false.
*/
buttonOffset: 3,
/**
* @cfg {Object} buttonCfg A standard {@link Ext.Button} config object.
*/
// private
readOnly: true,
/**
* @hide
* @method autoSize
*/
autoSize: Ext.emptyFn,
// private
initComponent: function(){
Ext.ux.form.FileUploadField.superclass.initComponent.call(this);
this.addEvents(
/**
* @event fileselected
* Fires when the underlying file input field's value has changed from the user
* selecting a new file from the system file selection dialog.
* @param {Ext.ux.form.FileUploadField} this
* @param {String} value The file value returned by the underlying file input field
*/
'fileselected'
);
},
// private
onRender : function(ct, position){
Ext.ux.form.FileUploadField.superclass.onRender.call(this, ct, position);
this.wrap = this.el.wrap({cls:'x-form-field-wrap x-form-file-wrap'});
this.el.addClass('x-form-file-text');
this.el.dom.removeAttribute('name');
this.createFileInput();
var btnCfg = Ext.applyIf(this.buttonCfg || {}, {
text: this.buttonText
});
this.button = new Ext.Button(Ext.apply(btnCfg, {
renderTo: this.wrap,
cls: 'x-form-file-btn' + (btnCfg.iconCls ? ' x-btn-icon' : '')
}));
if(this.buttonOnly){
this.el.hide();
this.wrap.setWidth(this.button.getEl().getWidth());
}
this.bindListeners();
this.resizeEl = this.positionEl = this.wrap;
},
bindListeners: function(){
this.fileInput.on({
scope: this,
mouseenter: function() {
this.button.addClass(['x-btn-over','x-btn-focus'])
},
mouseleave: function(){
this.button.removeClass(['x-btn-over','x-btn-focus','x-btn-click'])
},
mousedown: function(){
this.button.addClass('x-btn-click')
},
mouseup: function(){
this.button.removeClass(['x-btn-over','x-btn-focus','x-btn-click'])
},
change: function(){
var v = this.fileInput.dom.value;
this.setValue(v);
this.fireEvent('fileselected', this, v);
}
});
},
createFileInput : function() {
this.fileInput = this.wrap.createChild({
id: this.getFileInputId(),
name: this.name||this.getId(),
cls: 'x-form-file',
tag: 'input',
type: 'file',
size: 1
});
},
reset : function(){
this.fileInput.remove();
this.createFileInput();
this.bindListeners();
Ext.ux.form.FileUploadField.superclass.reset.call(this);
},
// private
getFileInputId: function(){
return this.id + '-file';
},
// private
onResize : function(w, h){
Ext.ux.form.FileUploadField.superclass.onResize.call(this, w, h);
this.wrap.setWidth(w);
if(!this.buttonOnly){
var w = this.wrap.getWidth() - this.button.getEl().getWidth() - this.buttonOffset;
this.el.setWidth(w);
}
},
// private
onDestroy: function(){
Ext.ux.form.FileUploadField.superclass.onDestroy.call(this);
Ext.destroy(this.fileInput, this.button, this.wrap);
},
onDisable: function(){
Ext.ux.form.FileUploadField.superclass.onDisable.call(this);
this.doDisable(true);
},
onEnable: function(){
Ext.ux.form.FileUploadField.superclass.onEnable.call(this);
this.doDisable(false);
},
// private
doDisable: function(disabled){
this.fileInput.dom.disabled = disabled;
this.button.setDisabled(disabled);
},
// private
preFocus : Ext.emptyFn,
// private
alignErrorIcon : function(){
this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
}
});
Ext.reg('fileuploadfield', Ext.ux.form.FileUploadField);
// backwards compat
Ext.form.FileUploadField = Ext.ux.form.FileUploadField;
/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools*/
/*
* @include "desktop/desktop.js"
*/
var SitoolsDesk = new sitools.user.desktop.App();
SitoolsDesk.initDesktopApplication();/***************************************
* Copyright 2011, 2012 CNES - CENTRE NATIONAL d'ETUDES SPATIALES
*
* This file is part of SITools2.
*
* SITools2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SITools2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SITools2. If not, see <http://www.gnu.org/licenses/>.
***************************************/
/*global Ext, sitools, ID, i18n, document, showResponse, alertFailure, LOCALE, ImageChooser,
showHelp, loadUrl, ColumnRendererEnum*/
Ext.namespace('sitools.admin.datasets.columnRenderer');
/**
* List of constants
* @type sitools.admin.datasets.columnRenderer.columnRenderEnum
*/
sitools.admin.datasets.columnRenderer.behaviorEnum = {
/**
* URL_LOCAL constant
* @static
* @type String
*/
URL_LOCAL : "localUrl",
/**
* URL_EXT_NEW_TAB constant
* @static
* @type String
*/
URL_EXT_NEW_TAB : "extUrlNewTab",
/**
* URL_EXT_DESKTOP constant
* @static
* @type String
*/
URL_EXT_DESKTOP : "extUrlDesktop",
/**
* IMAGE_NO_THUMB constant
* @static
* @type String
*/
IMAGE_NO_THUMB : "ImgNoThumb",
/**
* IMAGE_THUMB_FROM_IMAGE constant
* @static
* @type String
*/
IMAGE_THUMB_FROM_IMAGE : "ImgAutoThumb",
/**
* IMAGE_FROM_SQL constant
* @static
* @type String
*/
IMAGE_FROM_SQL : "ImgThumbSQL",
/**
* DATASET_LINK constant
* @static
* @type String
*/
DATASET_LINK : "datasetLink",
/**
* DATASET_ICON_LINK constant
* @static
* @type String
*/
DATASET_ICON_LINK : "datasetIconLink",
/**
* NO_CLIENT_ACCESS constant
* @static
* @type String
*/
NO_CLIENT_ACCESS : "noClientAccess",
getColumnRendererCategoryFromBehavior : function (behavior) {
var category;
switch (behavior) {
case ColumnRendererEnum.URL_LOCAL:
case ColumnRendererEnum.URL_EXT_NEW_TAB:
case ColumnRendererEnum.URL_EXT_DESKTOP:
category = "URL";
break;
case ColumnRendererEnum.IMAGE_NO_THUMB:
case ColumnRendererEnum.IMAGE_THUMB_FROM_IMAGE:
case ColumnRendererEnum.IMAGE_FROM_SQL:
category = "Image";
break;
case ColumnRendererEnum.DATASET_LINK:
case ColumnRendererEnum.DATASET_ICON_LINK:
category = "DataSetLink";
break;
case ColumnRendererEnum.NO_CLIENT_ACCESS:
category = "Other";
break;
default :
category = "";
break;
}
return category;
},
/**
* According to a given column Renderer, return true if the column should be displayed as an image
* @param {Object} cr the Column Renderer
* @return {Boolean} true when displaying an image, false otherwise.
*/
isDisplayingImage : function (cr) {
var result = false;
switch (cr.behavior) {
case ColumnRendererEnum.IMAGE_THUMB_FROM_IMAGE:
case ColumnRendererEnum.IMAGE_FROM_SQL:
case ColumnRendererEnum.DATASET_ICON_LINK:
result = true;
break;
case ColumnRendererEnum.URL_LOCAL:
case ColumnRendererEnum.URL_EXT_NEW_TAB:
case ColumnRendererEnum.URL_EXT_DESKTOP:
if (cr.type == "Image")
result = true;
break;
}
return result;
}
};
var ColumnRendererEnum = sitools.admin.datasets.columnRenderer.behaviorEnum;