You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6516 lines
215 KiB
6516 lines
215 KiB
/*
|
|
http://www.JSON.org/json2.js
|
|
2011-02-23
|
|
|
|
Public Domain.
|
|
|
|
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
|
|
|
See http://www.JSON.org/js.html
|
|
|
|
|
|
This code should be minified before deployment.
|
|
See http://javascript.crockford.com/jsmin.html
|
|
|
|
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
|
|
NOT CONTROL.
|
|
|
|
|
|
This file creates a global JSON object containing two methods: stringify
|
|
and parse.
|
|
|
|
JSON.stringify(value, replacer, space)
|
|
value any JavaScript value, usually an object or array.
|
|
|
|
replacer an optional parameter that determines how object
|
|
values are stringified for objects. It can be a
|
|
function or an array of strings.
|
|
|
|
space an optional parameter that specifies the indentation
|
|
of nested structures. If it is omitted, the text will
|
|
be packed without extra whitespace. If it is a number,
|
|
it will specify the number of spaces to indent at each
|
|
level. If it is a string (such as '\t' or ' '),
|
|
it contains the characters used to indent at each level.
|
|
|
|
This method produces a JSON text from a JavaScript value.
|
|
|
|
When an object value is found, if the object contains a toJSON
|
|
method, its toJSON method will be called and the result will be
|
|
stringified. A toJSON method does not serialize: it returns the
|
|
value represented by the name/value pair that should be serialized,
|
|
or undefined if nothing should be serialized. The toJSON method
|
|
will be passed the key associated with the value, and this will be
|
|
bound to the value
|
|
|
|
For example, this would serialize Dates as ISO strings.
|
|
|
|
Date.prototype.toJSON = function (key) {
|
|
function f(n) {
|
|
// Format integers to have at least two digits.
|
|
return n < 10 ? '0' + n : n;
|
|
}
|
|
|
|
return this.getUTCFullYear() + '-' +
|
|
f(this.getUTCMonth() + 1) + '-' +
|
|
f(this.getUTCDate()) + 'T' +
|
|
f(this.getUTCHours()) + ':' +
|
|
f(this.getUTCMinutes()) + ':' +
|
|
f(this.getUTCSeconds()) + 'Z';
|
|
};
|
|
|
|
You can provide an optional replacer method. It will be passed the
|
|
key and value of each member, with this bound to the containing
|
|
object. The value that is returned from your method will be
|
|
serialized. If your method returns undefined, then the member will
|
|
be excluded from the serialization.
|
|
|
|
If the replacer parameter is an array of strings, then it will be
|
|
used to select the members to be serialized. It filters the results
|
|
such that only members with keys listed in the replacer array are
|
|
stringified.
|
|
|
|
Values that do not have JSON representations, such as undefined or
|
|
functions, will not be serialized. Such values in objects will be
|
|
dropped; in arrays they will be replaced with null. You can use
|
|
a replacer function to replace those with JSON values.
|
|
JSON.stringify(undefined) returns undefined.
|
|
|
|
The optional space parameter produces a stringification of the
|
|
value that is filled with line breaks and indentation to make it
|
|
easier to read.
|
|
|
|
If the space parameter is a non-empty string, then that string will
|
|
be used for indentation. If the space parameter is a number, then
|
|
the indentation will be that many spaces.
|
|
|
|
Example:
|
|
|
|
text = JSON.stringify(['e', {pluribus: 'unum'}]);
|
|
// text is '["e",{"pluribus":"unum"}]'
|
|
|
|
|
|
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
|
|
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
|
|
|
|
text = JSON.stringify([new Date()], function (key, value) {
|
|
return this[key] instanceof Date ?
|
|
'Date(' + this[key] + ')' : value;
|
|
});
|
|
// text is '["Date(---current time---)"]'
|
|
|
|
|
|
JSON.parse(text, reviver)
|
|
This method parses a JSON text to produce an object or array.
|
|
It can throw a SyntaxError exception.
|
|
|
|
The optional reviver parameter is a function that can filter and
|
|
transform the results. It receives each of the keys and values,
|
|
and its return value is used instead of the original value.
|
|
If it returns what it received, then the structure is not modified.
|
|
If it returns undefined then the member is deleted.
|
|
|
|
Example:
|
|
|
|
// Parse the text. Values that look like ISO date strings will
|
|
// be converted to Date objects.
|
|
|
|
myData = JSON.parse(text, function (key, value) {
|
|
var a;
|
|
if (typeof value === 'string') {
|
|
a =
|
|
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
|
|
if (a) {
|
|
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
|
|
+a[5], +a[6]));
|
|
}
|
|
}
|
|
return value;
|
|
});
|
|
|
|
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
|
|
var d;
|
|
if (typeof value === 'string' &&
|
|
value.slice(0, 5) === 'Date(' &&
|
|
value.slice(-1) === ')') {
|
|
d = new Date(value.slice(5, -1));
|
|
if (d) {
|
|
return d;
|
|
}
|
|
}
|
|
return value;
|
|
});
|
|
|
|
|
|
This is a reference implementation. You are free to copy, modify, or
|
|
redistribute.
|
|
*/
|
|
|
|
/*jslint evil: true, strict: false, regexp: false */
|
|
|
|
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
|
|
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
|
|
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
|
|
lastIndex, length, parse, prototype, push, replace, slice, stringify,
|
|
test, toJSON, toString, valueOf
|
|
*/
|
|
|
|
|
|
// Create a JSON object only if one does not already exist. We create the
|
|
// methods in a closure to avoid creating global variables.
|
|
|
|
var JSON;
|
|
if (!JSON) {
|
|
JSON = {};
|
|
}
|
|
|
|
(function () {
|
|
"use strict";
|
|
|
|
function f(n) {
|
|
// Format integers to have at least two digits.
|
|
return n < 10 ? '0' + n : n;
|
|
}
|
|
|
|
if (typeof Date.prototype.toJSON !== 'function') {
|
|
|
|
Date.prototype.toJSON = function (key) {
|
|
|
|
return isFinite(this.valueOf()) ?
|
|
this.getUTCFullYear() + '-' +
|
|
f(this.getUTCMonth() + 1) + '-' +
|
|
f(this.getUTCDate()) + 'T' +
|
|
f(this.getUTCHours()) + ':' +
|
|
f(this.getUTCMinutes()) + ':' +
|
|
f(this.getUTCSeconds()) + 'Z' : null;
|
|
};
|
|
|
|
String.prototype.toJSON =
|
|
Number.prototype.toJSON =
|
|
Boolean.prototype.toJSON = function (key) {
|
|
return this.valueOf();
|
|
};
|
|
}
|
|
|
|
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
|
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
|
gap,
|
|
indent,
|
|
meta = { // table of character substitutions
|
|
'\b': '\\b',
|
|
'\t': '\\t',
|
|
'\n': '\\n',
|
|
'\f': '\\f',
|
|
'\r': '\\r',
|
|
'"' : '\\"',
|
|
'\\': '\\\\'
|
|
},
|
|
rep;
|
|
|
|
|
|
function quote(string) {
|
|
|
|
// If the string contains no control characters, no quote characters, and no
|
|
// backslash characters, then we can safely slap some quotes around it.
|
|
// Otherwise we must also replace the offending characters with safe escape
|
|
// sequences.
|
|
|
|
escapable.lastIndex = 0;
|
|
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
|
|
var c = meta[a];
|
|
return typeof c === 'string' ? c :
|
|
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
|
}) + '"' : '"' + string + '"';
|
|
}
|
|
|
|
|
|
function str(key, holder) {
|
|
|
|
// Produce a string from holder[key].
|
|
|
|
var i, // The loop counter.
|
|
k, // The member key.
|
|
v, // The member value.
|
|
length,
|
|
mind = gap,
|
|
partial,
|
|
value = holder[key];
|
|
|
|
// If the value has a toJSON method, call it to obtain a replacement value.
|
|
|
|
if (value && typeof value === 'object' &&
|
|
typeof value.toJSON === 'function') {
|
|
value = value.toJSON(key);
|
|
}
|
|
|
|
// If we were called with a replacer function, then call the replacer to
|
|
// obtain a replacement value.
|
|
|
|
if (typeof rep === 'function') {
|
|
value = rep.call(holder, key, value);
|
|
}
|
|
|
|
// What happens next depends on the value's type.
|
|
|
|
switch (typeof value) {
|
|
case 'string':
|
|
return quote(value);
|
|
|
|
case 'number':
|
|
|
|
// JSON numbers must be finite. Encode non-finite numbers as null.
|
|
|
|
return isFinite(value) ? String(value) : 'null';
|
|
|
|
case 'boolean':
|
|
case 'null':
|
|
|
|
// If the value is a boolean or null, convert it to a string. Note:
|
|
// typeof null does not produce 'null'. The case is included here in
|
|
// the remote chance that this gets fixed someday.
|
|
|
|
return String(value);
|
|
|
|
// If the type is 'object', we might be dealing with an object or an array or
|
|
// null.
|
|
|
|
case 'object':
|
|
|
|
// Due to a specification blunder in ECMAScript, typeof null is 'object',
|
|
// so watch out for that case.
|
|
|
|
if (!value) {
|
|
return 'null';
|
|
}
|
|
|
|
// Make an array to hold the partial results of stringifying this object value.
|
|
|
|
gap += indent;
|
|
partial = [];
|
|
|
|
// Is the value an array?
|
|
|
|
if (Object.prototype.toString.apply(value) === '[object Array]') {
|
|
|
|
// The value is an array. Stringify every element. Use null as a placeholder
|
|
// for non-JSON values.
|
|
|
|
length = value.length;
|
|
for (i = 0; i < length; i += 1) {
|
|
partial[i] = str(i, value) || 'null';
|
|
}
|
|
|
|
// Join all of the elements together, separated with commas, and wrap them in
|
|
// brackets.
|
|
|
|
v = partial.length === 0 ? '[]' : gap ?
|
|
'[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
|
|
'[' + partial.join(',') + ']';
|
|
gap = mind;
|
|
return v;
|
|
}
|
|
|
|
// If the replacer is an array, use it to select the members to be stringified.
|
|
|
|
if (rep && typeof rep === 'object') {
|
|
length = rep.length;
|
|
for (i = 0; i < length; i += 1) {
|
|
if (typeof rep[i] === 'string') {
|
|
k = rep[i];
|
|
v = str(k, value);
|
|
if (v) {
|
|
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
|
|
// Otherwise, iterate through all of the keys in the object.
|
|
|
|
for (k in value) {
|
|
if (Object.prototype.hasOwnProperty.call(value, k)) {
|
|
v = str(k, value);
|
|
if (v) {
|
|
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Join all of the member texts together, separated with commas,
|
|
// and wrap them in braces.
|
|
|
|
v = partial.length === 0 ? '{}' : gap ?
|
|
'{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
|
|
'{' + partial.join(',') + '}';
|
|
gap = mind;
|
|
return v;
|
|
}
|
|
}
|
|
|
|
// If the JSON object does not yet have a stringify method, give it one.
|
|
|
|
if (typeof JSON.stringify !== 'function') {
|
|
JSON.stringify = function (value, replacer, space) {
|
|
|
|
// The stringify method takes a value and an optional replacer, and an optional
|
|
// space parameter, and returns a JSON text. The replacer can be a function
|
|
// that can replace values, or an array of strings that will select the keys.
|
|
// A default replacer method can be provided. Use of the space parameter can
|
|
// produce text that is more easily readable.
|
|
|
|
var i;
|
|
gap = '';
|
|
indent = '';
|
|
|
|
// If the space parameter is a number, make an indent string containing that
|
|
// many spaces.
|
|
|
|
if (typeof space === 'number') {
|
|
for (i = 0; i < space; i += 1) {
|
|
indent += ' ';
|
|
}
|
|
|
|
// If the space parameter is a string, it will be used as the indent string.
|
|
|
|
} else if (typeof space === 'string') {
|
|
indent = space;
|
|
}
|
|
|
|
// If there is a replacer, it must be a function or an array.
|
|
// Otherwise, throw an error.
|
|
|
|
rep = replacer;
|
|
if (replacer && typeof replacer !== 'function' &&
|
|
(typeof replacer !== 'object' ||
|
|
typeof replacer.length !== 'number')) {
|
|
throw new Error('JSON.stringify');
|
|
}
|
|
|
|
// Make a fake root object containing our value under the key of ''.
|
|
// Return the result of stringifying the value.
|
|
|
|
return str('', {'': value});
|
|
};
|
|
}
|
|
|
|
|
|
// If the JSON object does not yet have a parse method, give it one.
|
|
|
|
if (typeof JSON.parse !== 'function') {
|
|
JSON.parse = function (text, reviver) {
|
|
|
|
// The parse method takes a text and an optional reviver function, and returns
|
|
// a JavaScript value if the text is a valid JSON text.
|
|
|
|
var j;
|
|
|
|
function walk(holder, key) {
|
|
|
|
// The walk method is used to recursively walk the resulting structure so
|
|
// that modifications can be made.
|
|
|
|
var k, v, value = holder[key];
|
|
if (value && typeof value === 'object') {
|
|
for (k in value) {
|
|
if (Object.prototype.hasOwnProperty.call(value, k)) {
|
|
v = walk(value, k);
|
|
if (v !== undefined) {
|
|
value[k] = v;
|
|
} else {
|
|
delete value[k];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return reviver.call(holder, key, value);
|
|
}
|
|
|
|
|
|
// Parsing happens in four stages. In the first stage, we replace certain
|
|
// Unicode characters with escape sequences. JavaScript handles many characters
|
|
// incorrectly, either silently deleting them, or treating them as line endings.
|
|
|
|
text = String(text);
|
|
cx.lastIndex = 0;
|
|
if (cx.test(text)) {
|
|
text = text.replace(cx, function (a) {
|
|
return '\\u' +
|
|
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
|
});
|
|
}
|
|
|
|
// In the second stage, we run the text against regular expressions that look
|
|
// for non-JSON patterns. We are especially concerned with '()' and 'new'
|
|
// because they can cause invocation, and '=' because it can cause mutation.
|
|
// But just to be safe, we want to reject all unexpected forms.
|
|
|
|
// We split the second stage into 4 regexp operations in order to work around
|
|
// crippling inefficiencies in IE's and Safari's regexp engines. First we
|
|
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
|
|
// replace all simple value tokens with ']' characters. Third, we delete all
|
|
// open brackets that follow a colon or comma or that begin the text. Finally,
|
|
// we look to see that the remaining characters are only whitespace or ']' or
|
|
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
|
|
|
|
if (/^[\],:{}\s]*$/
|
|
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
|
|
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
|
|
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
|
|
|
|
// In the third stage we use the eval function to compile the text into a
|
|
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
|
|
// in JavaScript: it can begin a block or an object literal. We wrap the text
|
|
// in parens to eliminate the ambiguity.
|
|
|
|
j = eval('(' + text + ')');
|
|
|
|
// In the optional fourth stage, we recursively walk the new structure, passing
|
|
// each name/value pair to a reviver function for possible transformation.
|
|
|
|
return typeof reviver === 'function' ?
|
|
walk({'': j}, '') : j;
|
|
}
|
|
|
|
// If the text is not JSON parseable, then a SyntaxError is thrown.
|
|
|
|
throw new SyntaxError('JSON.parse');
|
|
};
|
|
}
|
|
}());
|
|
/**
|
|
*
|
|
* 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;
|
|
}
|
|
|
|
};
|
|
// FineUI应用程序域
|
|
var F = function (cmpName) {
|
|
return Ext.getCmp(cmpName);
|
|
};
|
|
|
|
// 标识这个页面是由 FineUI 创建的
|
|
F.fineui = '6.0.2';
|
|
|
|
F.target = function (target) {
|
|
return F.util.getTargetWindow(target);
|
|
};
|
|
|
|
F.alert = function () {
|
|
F.util.alert.apply(window, arguments);
|
|
};
|
|
|
|
F.f_init = function () {
|
|
F.util.init.apply(window, arguments);
|
|
};
|
|
|
|
F.load = function () {
|
|
F.util.load.apply(window, arguments);
|
|
};
|
|
|
|
F.ready = function () {
|
|
F.util.ready.apply(window, arguments);
|
|
};
|
|
|
|
F.ajaxReady = function () {
|
|
F.util.ajaxReady.apply(window, arguments);
|
|
};
|
|
|
|
F.beforeAjax = function () {
|
|
F.util.beforeAjax.apply(window, arguments);
|
|
};
|
|
F.beforeAjaxSuccess = function () {
|
|
F.util.beforeAjaxSuccess.apply(window, arguments);
|
|
};
|
|
|
|
|
|
F.stop = function () {
|
|
var event = arguments.callee.caller.arguments[0] || window.event;
|
|
F.util.stopEventPropagation(event);
|
|
};
|
|
|
|
F.confirm = function () {
|
|
F.util.confirm.apply(null, arguments);
|
|
};
|
|
|
|
F.toggle = function (el, className) {
|
|
Ext.get(el).toggleCls(className);
|
|
};
|
|
|
|
F.fieldValue = function (cmp) {
|
|
return F.util.getFormFieldValue(cmp);
|
|
};
|
|
|
|
F.getHidden = function () {
|
|
return F.util.getHiddenFieldValue.apply(window, arguments);
|
|
};
|
|
F.setHidden = function () {
|
|
return F.util.setHiddenFieldValue.apply(window, arguments);
|
|
};
|
|
|
|
F.addCSS = function () {
|
|
F.util.addCSS.apply(window, arguments);
|
|
};
|
|
|
|
F.initTreeTabStrip = function () {
|
|
F.util.initTreeTabStrip.apply(window, arguments);
|
|
};
|
|
|
|
|
|
F.addMainTab = function () {
|
|
F.util.addMainTab.apply(window, arguments);
|
|
};
|
|
|
|
F.getActiveWindow = function () {
|
|
return F.wnd.getActiveWindow.apply(window, arguments);
|
|
};
|
|
|
|
F.isEOBJ = function (value) {
|
|
return F.util.isObjectEmpty(value);
|
|
};
|
|
|
|
F.defer = function (fn, miliseconds, scope) {
|
|
if (scope) {
|
|
return window.setTimeout(function () {
|
|
fn.apply(scope);
|
|
}, miliseconds);
|
|
} else {
|
|
return window.setTimeout(fn, miliseconds);
|
|
}
|
|
};
|
|
|
|
// 创建客户端控件,标识这是一个FineUI服务器端创建的控件
|
|
F.ui = F.create = function () {
|
|
var cmp = Ext.create.apply(window, arguments);
|
|
|
|
// 是个UI组件(排除 Ext.data.ArrayStore...)
|
|
if (cmp instanceof Ext.Component) {
|
|
cmp.fineui = true;
|
|
}
|
|
|
|
return cmp;
|
|
};
|
|
|
|
// 记录最后一个控件的序号
|
|
F.f_objectIndex = 0;
|
|
|
|
|
|
// 为了兼容保留函数签名:F.customEvent
|
|
F.f_customEvent = F.customEvent = function (argument, validate) {
|
|
//var pmv = F.f_pagemanager.validate;
|
|
//if (validate && pmv) {
|
|
// if (!F.util.validForms(pmv.forms, pmv.target, pmv.messagebox)) {
|
|
// return false;
|
|
// }
|
|
//}
|
|
//__doPostBack(F.f_pagemanager.name, argument);
|
|
|
|
var enableAjax;
|
|
if (typeof (argument) === 'boolean') {
|
|
enableAjax = argument;
|
|
argument = validate;
|
|
validate = arguments[2];
|
|
}
|
|
|
|
var pmv = F.f_pagemanager.validate;
|
|
if (validate && pmv) {
|
|
if (!F.util.validateForms(pmv.forms, pmv.target, pmv.messagebox)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (typeof (enableAjax) === 'boolean') {
|
|
__doPostBack(enableAjax, F.f_pagemanager.name, argument);
|
|
} else {
|
|
__doPostBack(F.f_pagemanager.name, argument);
|
|
}
|
|
};
|
|
|
|
|
|
// 更新EventValidation的值
|
|
F.f_eventValidation = function (newValue) {
|
|
F.setHidden("__EVENTVALIDATION", newValue);
|
|
};
|
|
|
|
F.f_state = function (cmp, state, statev) {
|
|
F.util.setFState(cmp, state, statev);
|
|
};
|
|
|
|
// 为了兼容保留函数签名:F.enable
|
|
F.f_enable = F.enable = function (id) {
|
|
F.util.enableSubmitControl(id);
|
|
};
|
|
|
|
// 为了兼容保留函数签名:F.disable
|
|
F.f_disable = F.disable = function (id) {
|
|
F.util.disableSubmitControl(id);
|
|
};
|
|
|
|
// 更新ViewState的值
|
|
F.f_viewState = function (viewStateBeforeAJAX, newValue, startIndex) {
|
|
var viewStateHiddenFiledId = '__VIEWSTATE';
|
|
|
|
var oldValue = F.getHidden(viewStateHiddenFiledId);
|
|
var viewStateChanged = false;
|
|
if (oldValue !== viewStateBeforeAJAX) {
|
|
viewStateChanged = true;
|
|
}
|
|
|
|
if (typeof (newValue) === 'undefined') {
|
|
// AJAX过程中ViewState值没变化
|
|
if (viewStateChanged) {
|
|
F.setHidden(viewStateHiddenFiledId, viewStateBeforeAJAX);
|
|
}
|
|
} else {
|
|
// AJAX过程中ViewState值有变化
|
|
if (typeof (startIndex) === 'number' && startIndex > 0) {
|
|
// 只返回startIndex之后的内容
|
|
if (viewStateChanged) {
|
|
// 无法处理!
|
|
return false;
|
|
} else {
|
|
F.setHidden(viewStateHiddenFiledId, oldValue.substr(0, startIndex) + newValue);
|
|
}
|
|
} else {
|
|
// 返回完整的ViewState
|
|
F.setHidden(viewStateHiddenFiledId, newValue);
|
|
}
|
|
}
|
|
|
|
// 更新成功!
|
|
return true;
|
|
};
|
|
|
|
// cookie('theme');
|
|
// cookie('theme', 'gray');
|
|
// cookie('theme', 'gray', { 'expires': 3 });
|
|
// expires: 天
|
|
// 新增 或者 修改Cookie
|
|
F.cookie = function (key, value, options) {
|
|
if (typeof (value) === 'undefined') {
|
|
var cookies = document.cookie ? document.cookie.split('; ') : [];
|
|
var result = key ? '' : {};
|
|
Ext.Array.each(cookies, function (cookie, index) {
|
|
var parts = cookie.split('=');
|
|
var partName = decodeURIComponent(Ext.String.trim(parts[0]));
|
|
var partValue = decodeURIComponent(Ext.String.trim(parts[1]));
|
|
|
|
if (key) {
|
|
if (key === partName) {
|
|
result = partValue;
|
|
return false;
|
|
}
|
|
} else {
|
|
result[partName] = partValue;
|
|
}
|
|
});
|
|
return result;
|
|
} else {
|
|
// Set cookie
|
|
options = Ext.apply(options || {}, {
|
|
path: '/'
|
|
});
|
|
|
|
var expTime;
|
|
if (typeof (options.expires) === 'number') {
|
|
expTime = new Date();
|
|
expTime.setTime(expTime.getTime() + options.expires * 24 * 60 * 60 * 1000);
|
|
}
|
|
|
|
document.cookie = [
|
|
encodeURIComponent(key), '=', encodeURIComponent(value),
|
|
options.expires ? '; expires=' + expTime.toUTCString() : '',
|
|
options.path ? '; path=' + options.path : '',
|
|
options.domain ? '; domain=' + options.domain : '',
|
|
options.secure ? '; secure' : ''
|
|
].join('');
|
|
}
|
|
};
|
|
|
|
// 删除Cookie
|
|
F.removeCookie = function (key, options) {
|
|
options = Ext.apply(options || {}, {
|
|
path: '/',
|
|
'expires': -1
|
|
});
|
|
|
|
F.cookie(key, '', options);
|
|
};
|
|
|
|
|
|
// 能否访问 iframe 中的 window.F 对象
|
|
F.canAccess = function (iframeWnd) {
|
|
|
|
// 访问 iframeWnd.F 时,可能出现错误 Blocked a frame with origin "http://fineui.com/" from accessing a cross-origin frame.
|
|
// Blocked:这个问题出现在 http://fineui.com/ 页面加载一个 http://baidu.com/ 的 iframe 页面
|
|
try {
|
|
iframeWnd.F;
|
|
iframeWnd.window;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
|
|
if (!iframeWnd.F || !iframeWnd.window) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
|
|
Ext.onReady(function () {
|
|
|
|
// 加延迟,以保证在 zh_CN 中通过 Ext.onReady 注册的脚本先执行(其中对 Ext.Date 进行了初始化)
|
|
window.setTimeout(function () {
|
|
F.util.triggerLoad();
|
|
F.util.triggerReady();
|
|
F.util.hidePageLoading();
|
|
}, 0);
|
|
|
|
});
|
|
|
|
(function () {
|
|
|
|
// 遍历定义了 renderTo 属性的对象
|
|
// callback: 'return false' to prevent loop continue
|
|
function resolveRenderToObj(callback) {
|
|
Ext.ComponentManager.each(function (key, cmp) {
|
|
if (cmp.isXType && cmp.renderTo) {
|
|
|
|
var result = callback.apply(cmp, [cmp]);
|
|
if (result === false) {
|
|
return false; // break
|
|
}
|
|
|
|
}
|
|
});
|
|
}
|
|
|
|
function isUND(value) {
|
|
return typeof (value) === 'undefined' || value === null;
|
|
}
|
|
|
|
/*
|
|
// 能否访问 iframe 中的 window.F 对象
|
|
function canIFrameWindowAccessed(iframeWnd) {
|
|
|
|
// 访问 iframeWnd.F 时,可能出现错误 Blocked a frame with origin "http://fineui.com/" from accessing a cross-origin frame.
|
|
// Blocked:这个问题出现在 http://fineui.com/ 页面加载一个 http://baidu.com/ 的 iframe 页面
|
|
try {
|
|
iframeWnd.F;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
|
|
if (!iframeWnd.F) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
*/
|
|
|
|
|
|
// FineUI常用函数域(Utility)
|
|
F.util = {
|
|
|
|
alertTitle: "Alert Dialog",
|
|
confirmTitle: "Confirm Dialog",
|
|
//formAlertMsg: "Please provide valid value for {0}!",
|
|
formAlertTitle: "Form Invalid",
|
|
loading: "Loading...",
|
|
|
|
// 下拉列表的模板
|
|
ddlTPL: '<tpl for="."><div class="x-boundlist-item<tpl if="!enabled"> x-boundlist-item-disabled</tpl>">{prefix}{text}</div></tpl>',
|
|
|
|
// 初始化
|
|
init: function (options) { // msgTarget, labelWidth, labelSeparator, blankImageUrl, enableAjaxLoading, ajaxLoadingType, enableAjax, themeName, formChangeConfirm) {
|
|
|
|
Ext.apply(F, options, {
|
|
language: 'zh_CN',
|
|
msgTarget: 'side',
|
|
labelWidth: 100,
|
|
labelSeparator: ':',
|
|
//blankImageUrl: '',
|
|
enableAjaxLoading: true,
|
|
ajaxLoadingType: 'default',
|
|
enableAjax: true,
|
|
theme: 'neptune',
|
|
formChangeConfirm: false,
|
|
ajaxTimeout: 120,
|
|
fstateValidation: false
|
|
});
|
|
|
|
|
|
// Ext.QuickTips.init(true); 在原生的IE7(非IE8下的IE7模式)会有问题
|
|
// 表现为iframe中的页面出现滚动条时,页面上的所有按钮都不能点击了。
|
|
// 测试例子在:aspnet/test.aspx
|
|
//Ext.QuickTips.init(false);
|
|
Ext.tip.QuickTipManager.init();
|
|
|
|
F.ajax.hookPostBack();
|
|
|
|
//F.global_enable_ajax = F.enableAjax;
|
|
//F.global_enable_ajax_loading = F.enableAjaxLoading;
|
|
//F.global_ajax_loading_type = F.ajaxLoadingType;
|
|
|
|
// 添加Ajax Loading提示节点
|
|
F.ajaxLoadingDefault = Ext.get(F.util.appendLoadingNode());
|
|
/*
|
|
F.ajaxLoadingMask = Ext.create('Ext.LoadMask', Ext.getBody(), {
|
|
hidden: true,
|
|
msg: F.util.loading
|
|
});
|
|
*/
|
|
|
|
|
|
//F.form_upload_file = false;
|
|
//F.global_disable_ajax = false;
|
|
//F.x_window_manager = new Ext.WindowManager();
|
|
//F.x_window_manager.zseed = 6000;
|
|
|
|
F.util.setHiddenFieldValue('F_CHANGED', 'false');
|
|
document.forms[0].autocomplete = 'off';
|
|
|
|
Ext.getBody().addCls('f-body');
|
|
|
|
Ext.Ajax.setTimeout(F.ajaxTimeout * 1000);
|
|
|
|
// 向document.body添加主题类
|
|
if (F.theme) {
|
|
Ext.getBody().addCls('f-theme-' + F.theme);
|
|
}
|
|
|
|
if (Ext.form.field) {
|
|
var fieldPro = Ext.form.field.Base.prototype;
|
|
fieldPro.msgTarget = F.msgTarget;
|
|
fieldPro.labelWidth = F.labelWidth;
|
|
fieldPro.labelSeparator = F.labelSeparator;
|
|
fieldPro.autoFitErrors = true;
|
|
}
|
|
if (Ext.form.CheckboxGroup) {
|
|
var checkboxgroupPro = Ext.form.CheckboxGroup.prototype;
|
|
checkboxgroupPro.msgTarget = F.msgTarget;
|
|
checkboxgroupPro.labelWidth = F.labelWidth;
|
|
checkboxgroupPro.labelSeparator = F.labelSeparator;
|
|
checkboxgroupPro.autoFitErrors = true;
|
|
}
|
|
|
|
F.beforeunloadCheck = true;
|
|
// 启用表单改变确认对话框
|
|
if (F.formChangeConfirm) {
|
|
// 下面这个方法在 Chrome、 Firefox下无效
|
|
//Ext.EventManager.on(window, 'beforeunload', function (event) {
|
|
window.onbeforeunload = function () {
|
|
// 允许关闭页面前提示,并且表单改变
|
|
if (F.beforeunloadCheck && F.util.formChanged()) {
|
|
return F.wnd.formChangeConfirmMsg;
|
|
}
|
|
};
|
|
}
|
|
|
|
//if (enableBigFont) {
|
|
// Ext.getBody().addCls('bigfont');
|
|
//}
|
|
|
|
/*
|
|
// IE6&7不支持,IE8以上支持"data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="
|
|
if (Ext.isIE6 || Ext.isIE7) {
|
|
Ext.BLANK_IMAGE_URL = F.blankImageUrl;
|
|
}
|
|
*/
|
|
|
|
// Submit
|
|
F.ready(function () {
|
|
if (F.submitbutton) {
|
|
Ext.ComponentManager.each(function (key, cmp) {
|
|
if (cmp.isXType && cmp.renderTo) {
|
|
if (cmp.isXType('tooltip')) {
|
|
return true; // continue
|
|
}
|
|
|
|
if (cmp.isXType('panel') || cmp.isXType('formviewport')) {
|
|
F.util.registerPanelEnterKey(cmp);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// 为了防止【页面中只有一个input[type=text],则回车会提交表单】的问题,现在页面上创建一个input[type=text]的空元素
|
|
//F.util.appendFormNode('<input type="text" class="f-input-text-hidden">');
|
|
Ext.DomHelper.insertFirst(document.forms[0], '<input type="text" class="f-input-text-hidden">');
|
|
|
|
},
|
|
|
|
_readyList: [],
|
|
_ajaxReadyList: [],
|
|
_beforeAjaxList: [],
|
|
_beforeAjaxSuccessList: [],
|
|
_loadList: [],
|
|
|
|
ready: function (callback) {
|
|
F.util._readyList.push(callback);
|
|
},
|
|
triggerReady: function () {
|
|
Ext.Array.each(F.util._readyList, function (item, index) {
|
|
item.apply(window);
|
|
});
|
|
},
|
|
|
|
|
|
ajaxReady: function (callback) {
|
|
F.util._ajaxReadyList.push(callback);
|
|
},
|
|
triggerAjaxReady: function () {
|
|
Ext.Array.each(F.util._ajaxReadyList, function (item, index) {
|
|
item.apply(window);
|
|
});
|
|
},
|
|
|
|
beforeAjax: function (callback) {
|
|
F.util._beforeAjaxList.push(callback);
|
|
},
|
|
triggerBeforeAjax: function () {
|
|
var result = true, args = arguments;
|
|
Ext.Array.each(F.util._beforeAjaxList, function (item, index) {
|
|
if (item.apply(window, args) === false) {
|
|
result = false;
|
|
}
|
|
});
|
|
return result;
|
|
},
|
|
|
|
beforeAjaxSuccess: function (callback) {
|
|
F.util._beforeAjaxSuccessList.push(callback);
|
|
},
|
|
triggerBeforeAjaxSuccess: function () {
|
|
var result = true, args = arguments;
|
|
Ext.Array.each(F.util._beforeAjaxSuccessList, function (item, index) {
|
|
if (item.apply(window, args) === false) {
|
|
result = false;
|
|
}
|
|
});
|
|
return result;
|
|
},
|
|
|
|
|
|
load: function (callback) {
|
|
F.util._loadList.push(callback);
|
|
},
|
|
triggerLoad: function () {
|
|
Ext.Array.each(F.util._loadList, function (item, index) {
|
|
item.apply(window);
|
|
});
|
|
},
|
|
|
|
setFState: function (cmp, state, statev) {
|
|
if (!cmp) {
|
|
return;
|
|
}
|
|
|
|
// 如果不存在,则初始化为空对象
|
|
if (!cmp['f_state']) {
|
|
cmp['f_state'] = {};
|
|
}
|
|
|
|
var oldValue, newValue, el;
|
|
// 如果state中包含CssClass,也就是在服务器端修改了CssClass属性,则需要首先删除原来的CssClass属性。
|
|
if (typeof (state['CssClass']) !== 'undefined') {
|
|
newValue = state['CssClass'];
|
|
oldValue = cmp['f_state']['CssClass'];
|
|
if (!oldValue) {
|
|
oldValue = cmp.initialConfig.cls;
|
|
}
|
|
el = cmp.el;
|
|
el.removeCls(oldValue);
|
|
el.addCls(newValue);
|
|
}
|
|
|
|
//if (typeof (state['FormItemClass']) !== 'undefined') {
|
|
// newValue = state['FormItemClass'];
|
|
// oldValue = cmp['f_state']['FormItemClass'];
|
|
// if (!oldValue) {
|
|
// oldValue = cmp.initialConfig.itemCls;
|
|
// }
|
|
// // Search for max 10 depth.
|
|
// el = cmp.el.findParent('.x-form-item', 10, true);
|
|
// el.removeCls(oldValue);
|
|
// el.addCls(newValue);
|
|
//}
|
|
|
|
// 注意:f_state是更新属性(可能只更新其中一个属性),而非覆盖属性
|
|
Ext.apply(cmp['f_state'], state);
|
|
if (F.fstateValidation && statev) {
|
|
// 注意:f_state_v是覆盖
|
|
cmp.f_state_v = statev;
|
|
}
|
|
},
|
|
|
|
stopEventPropagation: function (event) {
|
|
event = event || window.event;
|
|
if (typeof (event.cancelBubble) === 'boolean') {
|
|
event.cancelBubble = true;
|
|
} else {
|
|
event.stopPropagation();
|
|
}
|
|
},
|
|
|
|
// 绑定函数的上下文
|
|
bind: function (fn, scope) {
|
|
return function () {
|
|
return fn.apply(scope, arguments);
|
|
};
|
|
},
|
|
|
|
// 在页面上查找id为findId的节点,替换成replaceHtml
|
|
replace: function (findId, replaceHtml) {
|
|
// 在findId外面添加一个DIV层,然后更新此wrapper的InnerHTML
|
|
var findedControl = Ext.get(findId);
|
|
if (findedControl) {
|
|
var wrapper = findedControl.wrap().update(replaceHtml);
|
|
// 将新增的节点移到wrapper上面
|
|
wrapper.first().insertBefore(wrapper);
|
|
// 然后删除wrapper
|
|
wrapper.remove();
|
|
}
|
|
},
|
|
|
|
// 隐藏PageLoading节点
|
|
hidePageLoading: function () {
|
|
/*
|
|
if (fadeOut) {
|
|
Ext.get("loading").remove();
|
|
Ext.get("loading-mask").fadeOut({ remove: true });
|
|
}
|
|
else {
|
|
Ext.get("loading").remove();
|
|
Ext.get("loading-mask").remove();
|
|
}
|
|
*/
|
|
|
|
Ext.get("f_loading").hide();
|
|
Ext.get("f_loading_mask").hide();
|
|
},
|
|
|
|
|
|
// 去掉字符串中的html标签
|
|
stripHtmlTags: function (str) {
|
|
return str.replace(/<[^>]*>/g, "");
|
|
},
|
|
|
|
|
|
|
|
|
|
// 向页面添加Loading...节点
|
|
appendLoadingNode: function () {
|
|
return F.util.appendFormNode({ tag: 'div', id: 'f_ajax_loading', cls: 'f-ajax-loading', html: F.util.loading });
|
|
},
|
|
|
|
// 向页面的 form 节点最后添加新的节点
|
|
appendFormNode: function (htmlOrObj) {
|
|
return Ext.DomHelper.append(document.forms[0], htmlOrObj);
|
|
},
|
|
|
|
// 向页面添加一个隐藏字段,如果已经存在则更新值
|
|
setHiddenFieldValue: function (fieldId, fieldValue) {
|
|
var itemNode = Ext.get(fieldId);
|
|
if (!itemNode) {
|
|
// Ext.DomHelper.append 有问题,例如下面这个例子得到的结果是错的;变通一下,先插入节点,在设置节点的值。
|
|
// Ext.DomHelper.append(document.forms[0], { tag: "input", type: "hidden", value: '{"X_Items":[["Value1","可选项1",1],["Value2","可选项2(不可选择)",0],["Value3","可选项3(不可选择)",0],["Value4","可选项4",1],["Value5","可选项5",1],["Value6","可选项6",1],["Value7","可选择项7",1],["Value8","可选择项8",1],["Value9","可选择项9",1]],"SelectedValue":"Value1"}'});
|
|
// 上面的这个字符串,在IETest的IE8模式下会变成:
|
|
// {"DropDownList1":{"X_Items":[["Value1","\u9009\u9879 1",1],["Value2","\u9009\u9879 2\uff08\u4e0d\u53ef\u9009\u62e9\uff09",0],["Value3","\u9009\u9879 3\uff08\u4e0d\u53ef\u9009\u62e9\uff09",0],["Value4","\u9009\u9879 4",1],["Value5","\u9009\u9879 5",1],["Value6","\u9009\u9879 6",1],["Value7","\u9009\u9879 7",1],["Value8","\u9009\u9879 8",1],["Value9","\u9009\u9879 9",1]],"SelectedValue":"Value1"}}
|
|
|
|
F.util.appendFormNode({ tag: "input", type: "hidden", id: fieldId, name: fieldId });
|
|
Ext.get(fieldId).dom.value = fieldValue;
|
|
}
|
|
else {
|
|
itemNode.dom.value = fieldValue;
|
|
}
|
|
},
|
|
// 从表单中删除隐藏字段
|
|
removeHiddenField: function (fieldId) {
|
|
var itemNode = Ext.get(fieldId);
|
|
if (itemNode) {
|
|
itemNode.remove();
|
|
}
|
|
},
|
|
// 获取页面中一个隐藏字段的值
|
|
getHiddenFieldValue: function (fieldId) {
|
|
var itemNode = Ext.get(fieldId);
|
|
if (itemNode) {
|
|
return itemNode.getValue();
|
|
}
|
|
return null;
|
|
},
|
|
|
|
// 禁用提交按钮(在回发之前禁用以防止重复提交)
|
|
disableSubmitControl: function (controlClientID) {
|
|
F(controlClientID).disable();
|
|
// extjs v6.0需要,如果禁用按钮,则会查找页面上第一个可以获取焦点的元素,并使其获得焦点(对于面板而言,就是右上角的折叠按钮)
|
|
Ext.query('.f-input-text-hidden')[0].focus();
|
|
F.util.setHiddenFieldValue('F_TARGET', controlClientID);
|
|
},
|
|
// 启用提交按钮(在回发之后启用提交按钮)
|
|
enableSubmitControl: function (controlClientID) {
|
|
F(controlClientID).enable();
|
|
// extjs v6.0需要,启用按钮并不会使其获取焦点,必须手工调用
|
|
F(controlClientID).focus();
|
|
F.util.setHiddenFieldValue('F_TARGET', '');
|
|
},
|
|
|
|
|
|
|
|
/*
|
|
// 更新ViewState的值
|
|
updateViewState: function (newValue, startIndex, gzipped) {
|
|
if (typeof (startIndex) === 'boolean') {
|
|
gzipped = startIndex;
|
|
startIndex = -1;
|
|
}
|
|
|
|
var viewStateHiddenFiledID = "__VIEWSTATE";
|
|
if (gzipped) {
|
|
viewStateHiddenFiledID = "__VIEWSTATE_GZ";
|
|
}
|
|
|
|
var oldValue = F.util.getHiddenFieldValue(viewStateHiddenFiledID);
|
|
if (Ext.type(startIndex) == "number" && startIndex > 0) {
|
|
if (startIndex < oldValue.length) {
|
|
oldValue = oldValue.substr(0, startIndex);
|
|
}
|
|
} else {
|
|
// Added on 2011-5-2, this is a horrible mistake.
|
|
oldValue = '';
|
|
}
|
|
F.util.setHiddenFieldValue(viewStateHiddenFiledID, oldValue + newValue);
|
|
},
|
|
|
|
// 更新EventValidation的值
|
|
updateEventValidation: function (newValue) {
|
|
F.util.setHiddenFieldValue("__EVENTVALIDATION", newValue);
|
|
},
|
|
*/
|
|
|
|
// 设置页面状态是否改变
|
|
setPageStateChanged: function (changed) {
|
|
var pageState = Ext.get("F_CHANGED");
|
|
if (pageState) {
|
|
pageState.dom.value = changed;
|
|
}
|
|
},
|
|
|
|
// 页面状态是否改变
|
|
isPageStateChanged: function () {
|
|
var pageState = Ext.get("F_CHANGED");
|
|
if (pageState && pageState.getValue() == "true") {
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
|
|
// 阻止页面关闭(页面中iframe内的表单已改变,或者页面中iframe定义了beforeunload)
|
|
preventPageClose: function (el) {
|
|
var me = this;
|
|
|
|
// 是否阻止关闭
|
|
var preventClose = false;
|
|
|
|
var iframeEls;
|
|
if (el) {
|
|
iframeEls = el.select('iframe');
|
|
} else {
|
|
iframeEls = Ext.select('iframe');
|
|
}
|
|
|
|
iframeEls.each(function (iframeEl) {
|
|
var iframeWnd = iframeEl.dom.contentWindow;
|
|
|
|
if (!F.canAccess(iframeWnd)) {
|
|
return true; // continue
|
|
}
|
|
|
|
if (iframeWnd && iframeWnd.F) {
|
|
var iframeF = iframeWnd.F;
|
|
|
|
// 启用表单改变确认对话框 并且 表单已改变
|
|
if (iframeF.formChangeConfirm && iframeF.util.formChanged()) {
|
|
// 阻止关闭当前面板
|
|
if (!window.confirm(F.wnd.formChangeConfirmMsg)) {
|
|
preventClose = true;
|
|
return false; // break
|
|
} else {
|
|
// 没有阻止,不要在触发 $(window).beforeunload 事件了
|
|
iframeF.beforeunloadCheck = false;
|
|
}
|
|
}
|
|
|
|
/*
|
|
// 是否自定义了 beforeunload 事件
|
|
var beforeunloadCallbacks = iframeF.util._fjs_getEvent('beforeunload');
|
|
if (beforeunloadCallbacks) {
|
|
for (var i = 0, count = beforeunloadCallbacks.length; i < count; i++) {
|
|
var beforeunloadCallback = beforeunloadCallbacks[i];
|
|
|
|
var confirmMsg = beforeunloadCallback.apply(iframeWnd);
|
|
if (confirmMsg) {
|
|
// 阻止关闭当前面板
|
|
if (!window.confirm(confirmMsg)) {
|
|
preventClose = true;
|
|
return false; // break
|
|
} else {
|
|
// 没有阻止,不要在触发 $(window).beforeunload 事件了
|
|
iframeF.beforeunloadCheck = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
// 子页面是否阻止关闭
|
|
var childrenPreventClose = iframeF.util.preventPageClose();
|
|
if (childrenPreventClose) {
|
|
|
|
// 被子页面阻止了,则恢复父页面的 beforeunloadCheck 标识
|
|
iframeF.beforeunloadCheck = true;
|
|
|
|
preventClose = true;
|
|
return false; // break
|
|
}
|
|
}
|
|
|
|
});
|
|
|
|
return preventClose;
|
|
},
|
|
|
|
// 页面中表单字段是否改变
|
|
formChanged: function () {
|
|
var changed = false;
|
|
resolveRenderToObj(function (obj) {
|
|
if (obj.isXType('container') && obj.f_isDirty()) {
|
|
changed = true;
|
|
return false; // break
|
|
}
|
|
});
|
|
|
|
return changed;
|
|
},
|
|
|
|
trim: function (source) {
|
|
return Ext.String.trim(source);
|
|
},
|
|
|
|
|
|
// 验证多个表单,返回数组[是否验证通过,第一个不通过的表单字段]
|
|
validForms: function (forms, targetName, showBox) {
|
|
var util = F.util;
|
|
var target = util.getTargetWindow(targetName);
|
|
var valid = true;
|
|
var firstInvalidField = null;
|
|
for (var i = 0; i < forms.length; i++) {
|
|
var result = F(forms[i]).f_isValid();
|
|
if (!result[0]) {
|
|
valid = false;
|
|
if (firstInvalidField == null) {
|
|
firstInvalidField = result[1];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!valid) {
|
|
if (showBox) {
|
|
// var alertMsg = Ext.String.format(F.util.formAlertMsg, firstInvalidField.fieldLabel);
|
|
|
|
var fieldLabel = util.trim(util.stripHtmlTags(firstInvalidField.fieldLabel));
|
|
// 去除后面的*
|
|
if (fieldLabel.charAt(fieldLabel.length - 1) === '*') {
|
|
fieldLabel = fieldLabel.substr(0, fieldLabel.length - 1);
|
|
}
|
|
var activeError = util.trim(util.stripHtmlTags(firstInvalidField.activeError));
|
|
|
|
var alertMsg = '<div class="f-messagebox-errorfield">' + fieldLabel + '</div><div class="f-messagebox-errormsg">' + activeError + '</div>';
|
|
|
|
target.F.util.alert(alertMsg, util.formAlertTitle, Ext.MessageBox.INFO, function () {
|
|
// 第一次验证失败的字段获取焦点(选中文本,延迟执行)
|
|
firstInvalidField.focus(true, 200);
|
|
});
|
|
} else {
|
|
firstInvalidField.focus(true, 200);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
return true;
|
|
},
|
|
|
|
|
|
// 判断隐藏字段值(数组)是否包含value
|
|
isHiddenFieldContains: function (domId, testValue) {
|
|
testValue += "";
|
|
var domValue = Ext.get(domId).dom.value;
|
|
if (domValue === "") {
|
|
//console.log(domId);
|
|
return false;
|
|
}
|
|
else {
|
|
var sourceArray = domValue.split(",");
|
|
return Ext.Array.indexOf(sourceArray, testValue) >= 0 ? true : false;
|
|
}
|
|
},
|
|
|
|
|
|
// 将一个字符添加到字符列表中,将2添加到[5,3,4]
|
|
addValueToHiddenField: function (domId, addValue) {
|
|
addValue += "";
|
|
var domValue = Ext.get(domId).dom.value;
|
|
if (domValue == "") {
|
|
Ext.get(domId).dom.value = addValue + "";
|
|
}
|
|
else {
|
|
var sourceArray = domValue.split(",");
|
|
if (Ext.Array.indexOf(sourceArray, addValue) < 0) {
|
|
sourceArray.push(addValue);
|
|
Ext.get(domId).dom.value = sourceArray.join(",");
|
|
}
|
|
}
|
|
},
|
|
|
|
|
|
// 从字符列表中移除一个字符,将2从dom的值"5,3,4,2"移除
|
|
removeValueFromHiddenField: function (domId, addValue) {
|
|
addValue += "";
|
|
var domValue = Ext.get(domId).dom.value;
|
|
if (domValue != "") {
|
|
var sourceArray = domValue.split(",");
|
|
if (Ext.Array.indexOf(sourceArray, addValue) >= 0) {
|
|
sourceArray = sourceArray.remove(addValue);
|
|
Ext.get(domId).dom.value = sourceArray.join(",");
|
|
}
|
|
}
|
|
},
|
|
|
|
|
|
// 取得隐藏字段的值
|
|
getHiddenFieldValue: function (fieldId) {
|
|
var itemNode = Ext.get(fieldId);
|
|
if (!itemNode) {
|
|
return "";
|
|
}
|
|
else {
|
|
return itemNode.dom.value;
|
|
}
|
|
},
|
|
|
|
|
|
// 取得表单字段的值
|
|
getFormFieldValue: function (cmp) {
|
|
if (typeof (cmp) === 'string') {
|
|
cmp = F(cmp);
|
|
}
|
|
var value = cmp.getValue();
|
|
if (cmp.isXType('displayfield')) {
|
|
value = value.replace(/<\/?span[^>]*>/ig, '');
|
|
}
|
|
return value;
|
|
},
|
|
|
|
|
|
// 由target获取window对象
|
|
getTargetWindow: function (target) {
|
|
var wnd = window;
|
|
if (target === '_self') {
|
|
wnd = window;
|
|
} else if (target === '_parent') {
|
|
wnd = parent;
|
|
} else if (target === '_top') {
|
|
wnd = top;
|
|
}
|
|
return wnd;
|
|
},
|
|
|
|
|
|
// 预加载图片
|
|
preloadImages: function (images) {
|
|
var imageInstance = [];
|
|
for (var i = 0; i < images.length; i++) {
|
|
imageInstance[i] = new Image();
|
|
imageInstance[i].src = images[i];
|
|
}
|
|
},
|
|
|
|
hasCSS: function (id) {
|
|
return !!Ext.get(id);
|
|
},
|
|
|
|
addCSS: function (id, content, isCSSFile) {
|
|
|
|
// 如果此节点已经存在,则先删除此节点
|
|
var node = Ext.get(id);
|
|
if (node) {
|
|
Ext.removeNode(node.dom);
|
|
}
|
|
|
|
/*
|
|
var ss1;
|
|
|
|
if (isCSSFile) {
|
|
ss1 = document.createElement('link');
|
|
ss1.setAttribute('type', 'text/css');
|
|
ss1.setAttribute('rel', 'stylesheet');
|
|
ss1.setAttribute('id', id);
|
|
ss1.setAttribute('href', content);
|
|
} else {
|
|
// Tricks From: http://www.phpied.com/dynamic-script-and-style-elements-in-ie/
|
|
ss1 = document.createElement("style");
|
|
ss1.setAttribute("type", "text/css");
|
|
ss1.setAttribute("id", id);
|
|
if (ss1.styleSheet) { // IE
|
|
ss1.styleSheet.cssText = content;
|
|
} else { // the world
|
|
var tt1 = document.createTextNode(content);
|
|
ss1.appendChild(tt1);
|
|
}
|
|
}
|
|
|
|
var hh1 = document.getElementsByTagName("head")[0];
|
|
hh1.appendChild(ss1);
|
|
*/
|
|
|
|
var ss1;
|
|
var hh1 = document.getElementsByTagName('head')[0];
|
|
if (isCSSFile) {
|
|
ss1 = document.createElement('link');
|
|
//ss1.setAttribute('type', 'text/css');
|
|
ss1.setAttribute('rel', 'stylesheet');
|
|
ss1.setAttribute('id', id);
|
|
ss1.setAttribute('href', content);
|
|
hh1.appendChild(ss1);
|
|
} else {
|
|
// Tricks From: http://www.phpied.com/dynamic-script-and-style-elements-in-ie/
|
|
ss1 = document.createElement('style');
|
|
//ss1.setAttribute('type', 'text/css');
|
|
ss1.setAttribute('id', id);
|
|
// Update: note that it's important for IE that you append the style to the head *before* setting its content. Otherwise IE678 will *crash* is the css string contains an @import.
|
|
hh1.appendChild(ss1);
|
|
if (ss1.styleSheet) { // IE
|
|
ss1.styleSheet.cssText = content;
|
|
} else { // the world
|
|
var tt1 = document.createTextNode(content);
|
|
ss1.appendChild(tt1);
|
|
}
|
|
}
|
|
|
|
},
|
|
|
|
/*
|
|
// 在启用AJAX的情况下,使所有的Asp.net的提交按钮(type="submit")不要响应默认的submit行为,而是自定义的AJAX
|
|
makeAspnetSubmitButtonAjax: function (buttonId) {
|
|
|
|
// 低版本IE浏览器不允许使用JS修改input标签的type属性,导致此函数无效
|
|
function resetButton(button) {
|
|
button.set({ "type": "button" });
|
|
button.addListener("click", function (event, el) {
|
|
__doPostBack(el.getAttribute("name"), "");
|
|
event.stopEvent();
|
|
});
|
|
}
|
|
|
|
if (typeof (buttonId) === "undefined") {
|
|
Ext.Array.each(Ext.DomQuery.select("input[type=submit]"), function (item, index) {
|
|
resetButton(Ext.get(item));
|
|
});
|
|
} else {
|
|
var button = Ext.get(buttonId);
|
|
if (button.getAttribute("type") === "submit") {
|
|
resetButton(button);
|
|
}
|
|
}
|
|
|
|
},
|
|
|
|
*/
|
|
|
|
htmlEncode: function (str) {
|
|
var div = document.createElement("div");
|
|
div.appendChild(document.createTextNode(str));
|
|
return div.innerHTML;
|
|
},
|
|
|
|
htmlDecode: function (str) {
|
|
var div = document.createElement("div");
|
|
div.innerHTML = str;
|
|
return div.innerHTML;
|
|
},
|
|
|
|
|
|
// Whether a object is empty (With no property) or not.
|
|
// 可以使用 Ext.Object.isEmpty
|
|
isObjectEmpty: function (obj) {
|
|
for (var prop in obj) {
|
|
if (obj.hasOwnProperty(prop)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
|
|
// Convert an array to object.
|
|
// ['Text', 'Icon'] -> {'Text':true, 'Icon': true}
|
|
arrayToObject: function (arr) {
|
|
var obj = {};
|
|
Ext.Array.each(arr, function (item, index) {
|
|
obj[item] = true;
|
|
});
|
|
return obj;
|
|
},
|
|
|
|
hideScrollbar: function () {
|
|
if (Ext.isIE) {
|
|
window.document.body.scroll = 'no';
|
|
} else {
|
|
window.document.body.style.overflow = 'hidden';
|
|
}
|
|
},
|
|
|
|
|
|
// 动态添加一个标签页
|
|
// mainTabStrip: 选项卡实例
|
|
// id: 选项卡ID
|
|
// iframeUrl: 选项卡IFrame地址
|
|
// title: 选项卡标题
|
|
// icon: 选项卡图标
|
|
// createToolbar: 创建选项卡前的回调函数(接受tabConfig参数)
|
|
// refreshWhenExist: 添加选项卡时,如果选项卡已经存在,是否刷新内部IFrame
|
|
addMainTab: function (mainTabStrip, tabOptions) {
|
|
|
|
/*
|
|
// 兼容 addMainTab(mainTabStrip, treeNode, createToolbar, refreshWhenExist) 调用方式
|
|
if (typeof (id) !== 'string') {
|
|
refreshWhenExist = text;
|
|
createToolbar = url;
|
|
url = id.data.href;
|
|
icon = id.data.icon;
|
|
text = id.data.text;
|
|
|
|
id = id.getId();
|
|
}
|
|
*/
|
|
|
|
// 兼容之前的写法
|
|
if (typeof (tabOptions) === 'string') {
|
|
tabOptions = {
|
|
id: arguments[1],
|
|
iframeUrl: arguments[2],
|
|
title: arguments[3],
|
|
icon: arguments[4],
|
|
createToolbar: arguments[5],
|
|
refreshWhenExist: arguments[6]
|
|
};
|
|
} else if (typeof (tabOptions) === 'object' && tabOptions.data) {
|
|
var paramTreeNode = tabOptions;
|
|
tabOptions = {
|
|
id: paramTreeNode.getId(),
|
|
iframeUrl: paramTreeNode.data.href,
|
|
title: paramTreeNode.data.text,
|
|
icon: paramTreeNode.data.icon,
|
|
createToolbar: arguments[2],
|
|
refreshWhenExist: arguments[3]
|
|
};
|
|
}
|
|
|
|
//var href = node.attributes.href;
|
|
if (tabOptions.icon) {
|
|
var iconId = tabOptions.icon.replace(/\W/ig, '_');
|
|
if (!F.util.hasCSS(iconId)) {
|
|
var iconCss = [];
|
|
iconCss.push('.');
|
|
iconCss.push(iconId);
|
|
iconCss.push('{background-image:url("');
|
|
iconCss.push(tabOptions.icon);
|
|
iconCss.push('")}');
|
|
F.util.addCSS(iconId, iconCss.join(''));
|
|
}
|
|
}
|
|
// 动态添加一个带工具栏的标签页
|
|
//tabId = 'dynamic_added_tab' + id.replace('__', '-');
|
|
var currentTab = mainTabStrip.getTab(tabOptions.id);
|
|
if (!currentTab) {
|
|
var tabConfig = {
|
|
'id': tabOptions.id,
|
|
'url': tabOptions.iframeUrl,
|
|
'title': tabOptions.title,
|
|
'closable': true,
|
|
'bodyStyle': 'padding:0px;'
|
|
};
|
|
if (tabOptions.icon) {
|
|
tabConfig['iconCls'] = iconId;
|
|
}
|
|
|
|
if (tabOptions.createToolbar) {
|
|
var addTabCallbackResult = tabOptions.createToolbar.apply(window, [tabConfig]);
|
|
// 兼容之前的方法,函数返回值如果不为空,则将返回值作为顶部工具条实例
|
|
if (addTabCallbackResult) {
|
|
tabConfig['tbar'] = addTabCallbackResult;
|
|
}
|
|
}
|
|
mainTabStrip.addTab(tabConfig);
|
|
} else {
|
|
mainTabStrip.setActiveTab(currentTab);
|
|
currentTab.setTitle(tabOptions.title);
|
|
if (tabOptions.icon) {
|
|
currentTab.setIconCls(iconId);
|
|
}
|
|
if (tabOptions.refreshWhenExist) {
|
|
var iframeNode = currentTab.body.query('iframe')[0];
|
|
if (iframeNode) {
|
|
if (tabOptions.iframeUrl) {
|
|
iframeNode.contentWindow.location.href = tabOptions.iframeUrl;
|
|
} else {
|
|
iframeNode.contentWindow.location.reload();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
},
|
|
|
|
// 初始化左侧树(或者手风琴+树)与右侧选项卡控件的交互
|
|
// treeMenu: 主框架中的树控件实例,或者内嵌树控件的手风琴控件实例
|
|
// mainTabStrip: 选项卡实例
|
|
// createToolbar: 创建选项卡前的回调函数(接受tabConfig参数)
|
|
// updateHash: 切换Tab时,是否更新地址栏Hash值
|
|
// refreshWhenExist: 添加选项卡时,如果选项卡已经存在,是否刷新内部IFrame
|
|
// refreshWhenTabChange: 切换选项卡时,是否刷新内部IFrame
|
|
// hashWindow:需要更新Hash值的窗口对象,默认为当前window
|
|
// maxTabCount: 最大允许打开的选项卡数量
|
|
// maxTabMessage: 超过最大允许打开选项卡数量时的提示信息
|
|
initTreeTabStrip: function (treeMenu, mainTabStrip, createToolbar,
|
|
updateHash, refreshWhenExist, refreshWhenTabChange, hashWindow, maxTabCount, maxTabMessage) {
|
|
|
|
// 如果传入的对象 - (treeMenu, mainTabStrip, options)
|
|
if (createToolbar && typeof (createToolbar) === 'object') {
|
|
maxTabCount = createToolbar.maxTabCount;
|
|
maxTabMessage = createToolbar.maxTabMessage;
|
|
hashWindow = createToolbar.hashWindow;
|
|
refreshWhenTabChange = createToolbar.refreshWhenTabChange;
|
|
refreshWhenExist = createToolbar.refreshWhenExist;
|
|
updateHash = createToolbar.updateHash;
|
|
// 放到最后
|
|
createToolbar = createToolbar.createToolbar;
|
|
} else {
|
|
// 处理忽略 createToolbar 参数的情况
|
|
if (typeof (createToolbar) === 'boolean') {
|
|
maxTabMessage = maxTabCount;
|
|
maxTabCount = hashWindow;
|
|
hashWindow = refreshWhenTabChange;
|
|
refreshWhenTabChange = refreshWhenExist;
|
|
refreshWhenExist = updateHash;
|
|
updateHash = createToolbar;
|
|
createToolbar = undefined;
|
|
}
|
|
}
|
|
|
|
if (!hashWindow) {
|
|
hashWindow = window;
|
|
}
|
|
|
|
// 默认值
|
|
if (isUND(refreshWhenTabChange)) {
|
|
refreshWhenTabChange = false;
|
|
}
|
|
if (isUND(refreshWhenExist)) {
|
|
refreshWhenExist = false;
|
|
}
|
|
if (isUND(updateHash)) {
|
|
updateHash = true;
|
|
}
|
|
|
|
|
|
// 注册树的节点点击事件
|
|
function registerTreeClickEvent(treeInstance) {
|
|
|
|
// https://www.sencha.com/forum/showthread.php?286719-preventDefault-does-not-work-on-IE10-IE11
|
|
// https://www.sencha.com/forum/showthread.php?303907
|
|
// https://www.sencha.com/blog/delegated-events-and-gestures-in-ext-js-5/
|
|
treeInstance.el.on({
|
|
click: function (event) {
|
|
},
|
|
delegate: 'a.x-tree-node-text',
|
|
translate: false,
|
|
stopEvent: true
|
|
});
|
|
|
|
|
|
treeInstance.on('itemclick', function (view, record, item, index, event) {
|
|
var href = record.data.href;
|
|
// 不管当前节点是否子节点,只要有 href 属性,都需要打开一个新Tab
|
|
if (href) {
|
|
|
|
// 定义了 maxTabCount,并且当前打开的选项卡已经达到最大值了
|
|
if (!isUND(maxTabCount) && mainTabStrip.items.length >= maxTabCount) {
|
|
F.alert(maxTabMessage);
|
|
return;
|
|
}
|
|
|
|
// 阻止事件传播
|
|
event.stopEvent();
|
|
|
|
if (updateHash) {
|
|
// 修改地址栏
|
|
hashWindow.location.hash = '#' + href;
|
|
}
|
|
|
|
// 新增Tab节点
|
|
F.util.addMainTab(mainTabStrip, record, createToolbar, refreshWhenExist);
|
|
}
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
// treeMenu可能是Accordion或者Tree
|
|
if (treeMenu.getXType() === 'panel') {
|
|
treeMenu.items.each(function (item) {
|
|
var tree = item.items.getAt(0);
|
|
if (tree && tree.getXType() === 'treepanel') {
|
|
registerTreeClickEvent(tree);
|
|
}
|
|
});
|
|
} else if (treeMenu.getXType() === 'treepanel') {
|
|
registerTreeClickEvent(treeMenu);
|
|
}
|
|
|
|
// 切换主窗口的Tab
|
|
mainTabStrip.on('tabchange', function (tabStrip, tab) {
|
|
var tabHash = '#' + (tab.url || '');
|
|
|
|
// 只有当浏览器地址栏的Hash值和将要改变的不一样时,才进行如下两步处理:
|
|
// 1. 更新地址栏Hash值
|
|
// 2. 刷新Tab内的IFrame
|
|
if (tabHash !== hashWindow.location.hash) {
|
|
|
|
if (updateHash) {
|
|
hashWindow.location.hash = tabHash;
|
|
}
|
|
|
|
if (refreshWhenTabChange) {
|
|
var iframeNode = tab.body.query('iframe')[0];
|
|
if (iframeNode) {
|
|
var currentLocationHref = iframeNode.contentWindow.location.href;
|
|
if (/^http(s?):\/\//.test(currentLocationHref)) {
|
|
iframeNode.contentWindow.location.reload();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
});
|
|
|
|
|
|
// 页面第一次加载时,根据URL地址在主窗口加载页面
|
|
var HASH = hashWindow.location.hash.substr(1);
|
|
if (HASH) {
|
|
var FOUND = false;
|
|
|
|
function initTreeMenu(treeInstance, node) {
|
|
var i, currentNode, nodes, node, path;
|
|
if (!FOUND && node.hasChildNodes()) {
|
|
nodes = node.childNodes;
|
|
for (i = 0; i < nodes.length; i++) {
|
|
currentNode = nodes[i];
|
|
if (currentNode.isLeaf()) {
|
|
if (currentNode.data.href === HASH) {
|
|
path = currentNode.getPath();
|
|
treeInstance.expandPath(path); //node.expand();
|
|
treeInstance.selectPath(path); // currentNode.select();
|
|
F.util.addMainTab(mainTabStrip, currentNode, createToolbar);
|
|
FOUND = true;
|
|
return;
|
|
}
|
|
} else {
|
|
arguments.callee(treeInstance, currentNode);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (treeMenu.getXType() === 'panel') {
|
|
treeMenu.items.each(function (item) {
|
|
var tree = item.items.getAt(0);
|
|
if (tree && tree.getXType() === 'treepanel') {
|
|
initTreeMenu(tree, tree.getRootNode());
|
|
|
|
// 找到树节点
|
|
if (FOUND) {
|
|
item.expand();
|
|
return false;
|
|
}
|
|
}
|
|
});
|
|
} else if (treeMenu.getXType() === 'treepanel') {
|
|
initTreeMenu(treeMenu, treeMenu.getRootNode());
|
|
}
|
|
}
|
|
|
|
},
|
|
|
|
// 复选框分组处理
|
|
resolveCheckBoxGroup: function (name, xstateContainer, isradiogroup) {
|
|
var items = [], i, count, xitem, xitemvalue, xitems, xselectedarray, xselected, xchecked, xitemname;
|
|
|
|
xitems = xstateContainer.F_Items;
|
|
xselectedarray = xstateContainer.SelectedValueArray;
|
|
xselected = xstateContainer.SelectedValue;
|
|
|
|
if (xitems && xitems.length > 0) {
|
|
for (i = 0, count = xitems.length; i < count; i++) {
|
|
xitem = xitems[i];
|
|
xitemvalue = xitem[1];
|
|
xchecked = false;
|
|
if (!isradiogroup) {
|
|
// xselectedarray 可能是undefined, [], ["value1", "value2"]
|
|
if (xselectedarray) {
|
|
xchecked = (Ext.Array.indexOf(xselectedarray, xitemvalue) >= 0) ? true : false;
|
|
}
|
|
xitemname = name + '_' + i;
|
|
} else {
|
|
xchecked = (xselected === xitemvalue) ? true : false;
|
|
xitemname = name;
|
|
}
|
|
items.push({
|
|
'inputValue': xitemvalue,
|
|
'boxLabel': xitem[0],
|
|
'name': xitemname,
|
|
'checked': xchecked
|
|
});
|
|
}
|
|
}
|
|
/*
|
|
else {
|
|
items.push({
|
|
'inputValue': "tobedeleted",
|
|
'boxLabel': " ",
|
|
'name': "tobedeleted"
|
|
});
|
|
}
|
|
*/
|
|
return items;
|
|
|
|
},
|
|
|
|
// 防止在短时间内,同一GroupName的单选框触发两次事件
|
|
// 用于 MenuCheckBox 和 RadioButton
|
|
checkGroupLastTime: function (groupName) {
|
|
var checkName = groupName + '_lastupdatetime';
|
|
var checkValue = F.util[checkName];
|
|
F.util[checkName] = new Date();
|
|
if (typeof (checkValue) === 'undefined') {
|
|
return true;
|
|
} else {
|
|
if ((new Date() - checkValue) < 100) {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
},
|
|
|
|
// 对话框图标
|
|
getMessageBoxIcon: function (iconShortName) {
|
|
var icon = iconShortName || Ext.MessageBox.WARNING;
|
|
if (iconShortName === 'info') {
|
|
icon = Ext.MessageBox.INFO;
|
|
} else if (iconShortName === 'warning') {
|
|
icon = Ext.MessageBox.WARNING;
|
|
} else if (iconShortName === 'question') {
|
|
icon = Ext.MessageBox.QUESTION;
|
|
} else if (iconShortName === 'error') {
|
|
icon = Ext.MessageBox.ERROR;
|
|
}
|
|
return icon;
|
|
},
|
|
|
|
// 弹出Alert对话框
|
|
alert: function (target, message, title, messageIcon, ok) { // 老的顺序:msg, title, icon, okscript
|
|
var args = [].slice.call(arguments, 0);
|
|
|
|
var options = args[0];
|
|
if (typeof (options) === 'string') {
|
|
if (!/^_self|_parent|_top$/.test(args[0])) {
|
|
args.splice(0, 0, '_self');
|
|
}
|
|
options = {
|
|
target: args[0],
|
|
message: args[1],
|
|
title: args[2],
|
|
messageIcon: args[3],
|
|
ok: args[4]
|
|
};
|
|
}
|
|
|
|
var wnd = F.util.getTargetWindow(options.target);
|
|
if (!F.canAccess(wnd)) {
|
|
return; // return
|
|
}
|
|
|
|
var icon = Ext.MessageBox.INFO;
|
|
if (options.messageIcon) {
|
|
icon = F.util.getMessageBoxIcon(options.messageIcon);
|
|
}
|
|
|
|
wnd.Ext.MessageBox.show({
|
|
cls: options.cls || '',
|
|
title: options.title || F.util.alertTitle,
|
|
msg: options.message,
|
|
buttons: Ext.MessageBox.OK,
|
|
icon: icon,
|
|
fn: function (buttonId) {
|
|
if (buttonId === "ok") {
|
|
if (typeof (options.ok) === "function") {
|
|
options.ok.call(window);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
},
|
|
|
|
|
|
|
|
// 确认对话框
|
|
confirm: function (target, message, title, messageIcon, ok, cancel) { // 老的顺序:targetName, title, msg, okScript, cancelScript, iconShortName)
|
|
|
|
var args = [].slice.call(arguments, 0); //$.makeArray(arguments);
|
|
|
|
var options = args[0];
|
|
if (typeof (options) === 'string') {
|
|
if (!/^_self|_parent|_top$/.test(args[0])) {
|
|
args.splice(0, 0, '_self');
|
|
}
|
|
options = {
|
|
target: args[0],
|
|
message: args[1],
|
|
title: args[2],
|
|
messageIcon: args[3],
|
|
ok: args[4],
|
|
cancel: args[5]
|
|
};
|
|
}
|
|
|
|
|
|
var wnd = F.util.getTargetWindow(options.target);
|
|
if (!F.canAccess(wnd)) {
|
|
return; // return
|
|
}
|
|
|
|
var icon = F.util.getMessageBoxIcon(options.messageIcon);
|
|
wnd.Ext.MessageBox.show({
|
|
cls: options.cls || '',
|
|
title: options.title || F.util.confirmTitle,
|
|
msg: options.message,
|
|
buttons: Ext.MessageBox.OKCANCEL,
|
|
icon: icon,
|
|
fn: function (btn) {
|
|
if (btn == 'cancel') {
|
|
if (options.cancel) {
|
|
if (typeof (options.cancel) === 'string') {
|
|
new Function(options.cancel)();
|
|
} else {
|
|
options.cancel.apply(wnd);
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
if (options.ok) {
|
|
if (typeof (options.ok) === 'string') {
|
|
new Function(options.ok)();
|
|
} else {
|
|
options.ok.apply(wnd);
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
},
|
|
|
|
|
|
|
|
summaryRenderer: function (gridId) {
|
|
return function (value, summaryData, dataIndex) {
|
|
var summary = F(gridId).f_state['SummaryData'];
|
|
if (summary) {
|
|
var summaryValue = summary[dataIndex];
|
|
if (typeof (summaryValue) !== 'undefined') {
|
|
return summaryValue;
|
|
}
|
|
}
|
|
return '';
|
|
};
|
|
},
|
|
|
|
// 表单字段内按回车键触发提交按钮
|
|
registerPanelEnterKey: function (panel) {
|
|
if (F.submitbutton) {
|
|
F.create('Ext.util.KeyNav', panel.el, {
|
|
enter: function (e) {
|
|
var el = Ext.Element.getActiveElement();
|
|
if (el.type !== 'textarea') {
|
|
F(F.submitbutton).el.dom.click();
|
|
}
|
|
},
|
|
scope: panel
|
|
});
|
|
}
|
|
},
|
|
|
|
reset: function () {
|
|
Ext.ComponentManager.each(function (key, cmp) {
|
|
if (cmp.isXType && cmp.isXType('panel') && cmp.renderTo) {
|
|
cmp.f_reset();
|
|
}
|
|
});
|
|
},
|
|
|
|
|
|
isDate: function (value) {
|
|
return Object.prototype.toString.call(value) === '[object Date]';
|
|
},
|
|
|
|
resolveGridDateToString: function (fields, fieldName, fieldValue) {
|
|
var i, fieldConfig, result = fieldValue;
|
|
for (i = 0, count = fields.length; i < count; i++) {
|
|
fieldConfig = fields[i];
|
|
if (fieldConfig.name === fieldName && fieldConfig.type === 'date' && fieldConfig.dateFormat) {
|
|
result = Ext.util.Format.date(fieldValue, fieldConfig.dateFormat);
|
|
}
|
|
}
|
|
return result;
|
|
},
|
|
|
|
|
|
|
|
|
|
noop: function () { }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
})();
|
|
(function () {
|
|
|
|
// 正在进行中的AJAX请求个数
|
|
var __ajaxUnderwayCount = 0;
|
|
|
|
F.ajax = {
|
|
|
|
timeoutErrorMsg: "Request timeout, please refresh the page and try again!",
|
|
errorMsg: "Error! {0} ({1})",
|
|
errorWindow: null,
|
|
|
|
hookPostBack: function () {
|
|
if (typeof (__doPostBack) != 'undefined') {
|
|
__doPostBack = f__doPostBack;
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
function enableAjax() {
|
|
if (typeof (F.controlEnableAjax) === 'undefined') {
|
|
return F.enableAjax;
|
|
}
|
|
return F.controlEnableAjax;
|
|
}
|
|
|
|
function enableAjaxLoading() {
|
|
if (typeof (F.controlEnableAjaxLoading) === 'undefined') {
|
|
return F.enableAjaxLoading;
|
|
}
|
|
return F.controlEnableAjaxLoading;
|
|
}
|
|
|
|
function ajaxLoadingType() {
|
|
if (typeof (F.controlAjaxLoadingType) === 'undefined') {
|
|
return F.ajaxLoadingType;
|
|
}
|
|
return F.controlAjaxLoadingType;
|
|
}
|
|
|
|
|
|
function f__doPostBack_internal() {
|
|
//if (typeof (F.util.beforeAjaxPostBackScript) === 'function') {
|
|
// F.util.beforeAjaxPostBackScript();
|
|
//}
|
|
|
|
// 如果显式返回false,则阻止AJAX回发
|
|
if(F.util.triggerBeforeAjax() === false) {
|
|
return;
|
|
}
|
|
|
|
|
|
// Ext.encode will convert Chinese characters. Ext.encode({a:"你好"}) => '{"a":"\u4f60\u597d"}'
|
|
// We will include the official JSON object from http://json.org/
|
|
// 现在还是用的 Ext.encode,在 IETester的 IE8下 JSON.stringify 生成的中文是\u9009\u9879形式。
|
|
//F.util.setHiddenFieldValue('F_STATE', encodeURIComponent(JSON.stringify(getFState())));
|
|
|
|
var fstate = Ext.encode(getFState());
|
|
if (Ext.isIE6 || Ext.isIE7) {
|
|
F.util.setHiddenFieldValue('F_STATE_URI', 'true');
|
|
fstate = encodeURIComponent(fstate);
|
|
} else {
|
|
fstate = Base64.encode(fstate);
|
|
}
|
|
F.util.setHiddenFieldValue('F_STATE', fstate);
|
|
|
|
//F.util.setHiddenFieldValue('F_STATE', encodeURIComponent(Ext.encode(getFState())));
|
|
if (!enableAjax()) {
|
|
// 当前请求结束后必须重置 F.controlEnableAjax
|
|
F.controlEnableAjax = undefined;
|
|
F.util.setHiddenFieldValue('F_AJAX', 'false');
|
|
theForm.submit();
|
|
} else {
|
|
// 当前请求结束后必须重置 F.controlEnableAjax
|
|
F.controlEnableAjax = undefined;
|
|
F.util.setHiddenFieldValue('F_AJAX', 'true');
|
|
var url = document.location.href;
|
|
var urlHashIndex = url.indexOf('#');
|
|
if (urlHashIndex >= 0) {
|
|
url = url.substring(0, urlHashIndex);
|
|
}
|
|
|
|
var viewStateBeforeAJAX = F.util.getHiddenFieldValue('__VIEWSTATE');
|
|
var disabledButtonIdBeforeAJAX = F.getHidden('F_TARGET');
|
|
|
|
function processEnd() {
|
|
//隐藏正在加载提示
|
|
ajaxStop();
|
|
}
|
|
|
|
function ajaxSuccess(data, viewStateBeforeAJAX) {
|
|
|
|
// 如果显式返回false,则阻止AJAX回发
|
|
if (F.util.triggerBeforeAjaxSuccess(data) === false) {
|
|
processEnd();
|
|
return;
|
|
}
|
|
|
|
try {
|
|
new Function('__VIEWSTATE', data)(viewStateBeforeAJAX);
|
|
|
|
// 有可能响应返回后即关闭本窗体
|
|
if (F && F.util) {
|
|
F.util.triggerAjaxReady();
|
|
}
|
|
} catch (e) {
|
|
|
|
// 重新抛出异常
|
|
throw e;
|
|
|
|
} finally {
|
|
|
|
processEnd();
|
|
}
|
|
|
|
}
|
|
|
|
ajaxStart();
|
|
|
|
|
|
// 判断是否有文件上传
|
|
var isFileUpload = !!Ext.get(theForm).query('input[type=file]').length;
|
|
|
|
Ext.Ajax.request({
|
|
form: theForm.id,
|
|
url: url,
|
|
isUpload: isFileUpload, //F.form_upload_file,
|
|
//params: serializeForm(theForm) + '&X_AJAX=true',
|
|
success: function (data) {
|
|
var scripts = data.responseText;
|
|
|
|
if (scripts && isFileUpload) {
|
|
// 文件上传时,输出内容经过encodeURIComponent编码(在ResponseFilter中的Close函数中)
|
|
//scripts = scripts.replace(/<\/?pre[^>]*>/ig, '');
|
|
scripts = decodeURIComponent(scripts);
|
|
}
|
|
|
|
// 启用AJAX发起时禁用的按钮
|
|
if (disabledButtonIdBeforeAJAX) {
|
|
F.enable(disabledButtonIdBeforeAJAX);
|
|
}
|
|
|
|
// 因为这里调用后(可能会关闭当前页面),extjs还有代码要执行(Ext.callback...),所以这里要延迟一下,等 extjs 代码执行完毕后再执行这里代码
|
|
window.setTimeout(function () {
|
|
ajaxSuccess(scripts, viewStateBeforeAJAX);
|
|
}, 0);
|
|
},
|
|
failure: function (data) {
|
|
//var lastDisabledButtonId = F.util.getHiddenFieldValue('F_TARGET');
|
|
if (disabledButtonIdBeforeAJAX) {
|
|
F.enable(disabledButtonIdBeforeAJAX);
|
|
}
|
|
|
|
processEnd(); // v6.0.0:失败也要做清理工作
|
|
createErrorWindow(data);
|
|
},
|
|
callback: function (options, success, response) {
|
|
// AJAX结束时需要清空此字段,否则下一次的type=submit提交(ASP.NET回发方式之一)会被误认为是AJAX提交
|
|
if (F && F.util) {
|
|
F.util.setHiddenFieldValue('F_AJAX', 'false');
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
// 如果启用 Ajax,则所有对 __doPostBack 的调用都会到这里来
|
|
function f__doPostBack(eventTarget, eventArgument) {
|
|
var enableAjax;
|
|
if (typeof (eventTarget) === 'boolean') {
|
|
enableAjax = eventTarget;
|
|
eventTarget = eventArgument;
|
|
eventArgument = arguments[2];
|
|
}
|
|
|
|
// 回发页面之前延时 100 毫秒,确保页面上的操作完成(比如选中复选框的动作)
|
|
window.setTimeout(function () {
|
|
|
|
// theForm variable will always exist, because we invoke the GetPostBackEventReference in PageManager.
|
|
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
|
|
theForm.__EVENTTARGET.value = eventTarget;
|
|
theForm.__EVENTARGUMENT.value = eventArgument;
|
|
|
|
// 设置当前请求是否为AJAX请求
|
|
if (typeof (enableAjax) === 'boolean') {
|
|
F.controlEnableAjax = enableAjax;
|
|
}
|
|
|
|
f__doPostBack_internal();
|
|
}
|
|
}, 100);
|
|
}
|
|
|
|
|
|
function writeContentToIFrame(iframe, content) {
|
|
// http://stackoverflow.com/questions/1477547/getelementbyid-contentdocument-error-in-ie
|
|
// contentWindow is always there.
|
|
if (iframe) {
|
|
var doc = iframe.contentWindow.document;
|
|
if (doc) {
|
|
doc.open();
|
|
doc.write(content);
|
|
doc.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
// 创建出错窗口
|
|
function createErrorWindow(data) {
|
|
// 如果是请求超时错误,则弹出简单提醒对话框
|
|
if (data.isTimeout) {
|
|
F.util.alert(F.ajax.timeoutErrorMsg);
|
|
return;
|
|
}
|
|
|
|
// 如果响应正文为空,则弹出简单提醒对话框
|
|
if (!data.responseText) {
|
|
F.util.alert(Ext.String.format(F.ajax.errorMsg, data.statusText, data.status));
|
|
return;
|
|
}
|
|
|
|
if (!F.ajax.errorWindow) {
|
|
F.ajax.errorWindow = F.create('Ext.window.Window', {
|
|
id: "FINEUI_ERROR",
|
|
renderTo: window.body,
|
|
width: 550,
|
|
height: 350,
|
|
border: true,
|
|
animCollapse: true,
|
|
collapsible: false,
|
|
collapsed: false,
|
|
closeAction: "hide",
|
|
plain: false,
|
|
modal: true,
|
|
draggable: true,
|
|
minimizable: false,
|
|
minHeight: 100,
|
|
minWidth: 200,
|
|
resizable: true,
|
|
maximizable: true,
|
|
closable: true
|
|
});
|
|
}
|
|
|
|
F.ajax.errorWindow.show();
|
|
F.ajax.errorWindow.body.dom.innerHTML = F.wnd.createIFrameHtml('about:blank', 'FINEUI_ERROR');
|
|
F.ajax.errorWindow.setTitle(Ext.String.format(F.ajax.errorMsg, data.statusText, data.status));
|
|
writeContentToIFrame(F.ajax.errorWindow.body.query('iframe')[0], data.responseText);
|
|
}
|
|
|
|
// 序列化表单为 URL 编码字符串,除去 <input type="submit" /> 的按钮
|
|
var extjsSerializeForm = Ext.Element.serializeForm;
|
|
Ext.Element.serializeForm = function (form) {
|
|
var el, originalStr = extjsSerializeForm(form);
|
|
for (var i = 0; i < form.elements.length; i++) {
|
|
el = form.elements[i];
|
|
if (el.type === 'submit') {
|
|
var submitStr = encodeURIComponent(el.name) + '=' + encodeURIComponent(el.value);
|
|
if (originalStr.indexOf(submitStr) == 0) {
|
|
originalStr = originalStr.replace(submitStr, '');
|
|
} else {
|
|
originalStr = originalStr.replace('&' + submitStr, '');
|
|
}
|
|
}
|
|
}
|
|
return originalStr;
|
|
};
|
|
|
|
|
|
function getFState() {
|
|
var state = {};
|
|
Ext.ComponentManager.each(function (key, cmp) {
|
|
// 只处理FineUI服务器端生成的控件(f_state表明这个控件对应一个服务器端控件)
|
|
if (cmp.fineui && cmp.f_state) {
|
|
resolveCmpHiddenFields(cmp);
|
|
|
|
var fstate = cmp['f_state'];
|
|
if (fstate && !F.isEOBJ(fstate)) {
|
|
if (F.fstateValidation) {
|
|
// 如果验证信息不存在,则不添加f_state
|
|
var fstatev = cmp['f_state_v'];
|
|
if (fstatev) {
|
|
state[cmp.id] = [fstate, fstatev];
|
|
}
|
|
} else {
|
|
state[cmp.id] = fstate;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
if (cmp.isXType) {
|
|
var fstate = cmp['f_state'];
|
|
if (fstate && Ext.isObject(fstate)) {
|
|
var cmpState = getFStateViaCmp(cmp, fstate);
|
|
if (!F.util.isObjectEmpty(cmpState)) {
|
|
state[cmp.id] = cmpState;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
});
|
|
return state;
|
|
}
|
|
|
|
//F.ajax.getFState = getFState;
|
|
|
|
// 设置控件相关隐藏字段的值
|
|
function resolveCmpHiddenFields(cmp) {
|
|
//var state = {};
|
|
//Ext.apply(state, fstate);
|
|
|
|
function saveInHiddenField(property, currentValue) {
|
|
// Save this client-changed property in a form hidden field.
|
|
F.util.setHiddenFieldValue(cmp.id + '_' + property, currentValue);
|
|
}
|
|
function removeHiddenField(property) {
|
|
F.util.removeHiddenField(cmp.id + '_' + property);
|
|
}
|
|
|
|
/*
|
|
// 如果存在Gzip压缩的属性,就删除原来的属性
|
|
function resolveGZProperty(property) {
|
|
var gzProperty = property + '_GZ';
|
|
if (state[gzProperty]) {
|
|
delete state[property];
|
|
} else {
|
|
delete state[gzProperty];
|
|
}
|
|
}
|
|
*/
|
|
|
|
|
|
// 有些属性可以在客户端改变,因此需要在每个请求之前计算
|
|
if (cmp.isXType('menucheckitem')) {
|
|
saveInHiddenField('Checked', cmp.checked);
|
|
}
|
|
|
|
if (cmp.isXType('checkbox')) {
|
|
// 包含RadioButton
|
|
saveInHiddenField('Checked', cmp.getValue());
|
|
}
|
|
|
|
if (cmp.isXType('checkboxgroup')) {
|
|
var selected = cmp.f_getSelectedValues();
|
|
if (selected.length > 0) {
|
|
saveInHiddenField('SelectedValueArray', selected.join(','));
|
|
} else {
|
|
removeHiddenField('SelectedValueArray');
|
|
}
|
|
}
|
|
|
|
if (cmp.isXType('panel') || cmp.isXType('fieldset')) {
|
|
saveInHiddenField('Collapsed', cmp.f_isCollapsed());
|
|
}
|
|
|
|
if (cmp.isXType('datepicker')) {
|
|
saveInHiddenField('SelectedDate', Ext.Date.format(cmp.getValue(), cmp.initialConfig.format));
|
|
}
|
|
|
|
if (cmp.isXType('button')) {
|
|
if (cmp.initialConfig.enableToggle) {
|
|
saveInHiddenField('Pressed', cmp.pressed);
|
|
}
|
|
}
|
|
|
|
if (cmp.isXType('grid')) {
|
|
|
|
// 启用分页
|
|
if (cmp.f_paging) {
|
|
var pagingBar = cmp.f_getPaging();
|
|
saveInHiddenField('PageIndex', pagingBar.f_pageIndex);
|
|
}
|
|
|
|
// 启用排序
|
|
if (cmp.f_sorting) {
|
|
var gridSorter = cmp.getStore().sorters.get(0);
|
|
|
|
// 如果启用排序,但是默认没有排序,则可能 gridSorter 不存在
|
|
if (gridSorter) {
|
|
saveInHiddenField('SortField', gridSorter.property);
|
|
saveInHiddenField('SortDirection', gridSorter.direction);
|
|
}
|
|
}
|
|
|
|
|
|
//if (cmp.getPlugin(cmp.id + '_celledit')) {
|
|
if(cmp.f_cellEditing) {
|
|
// 可编辑单元格的表格
|
|
// 选中单元格
|
|
//saveInHiddenField('SelectedCell', cmp.f_getSelectedCell().join(','));
|
|
|
|
// 选中单元格
|
|
var selectedCell = cmp.f_getSelectedCell();
|
|
if (selectedCell && selectedCell.length) {
|
|
saveInHiddenField('SelectedCell', JSON.stringify(selectedCell));
|
|
} else {
|
|
removeHiddenField('SelectedCell');
|
|
}
|
|
|
|
//// 新增行
|
|
//var newAddedRows = cmp.f_getNewAddedRows();
|
|
//if (newAddedRows.length > 0) {
|
|
// saveInHiddenField('NewAddedRows', newAddedRows.join(','));
|
|
//} else {
|
|
// removeHiddenField('NewAddedRows');
|
|
//}
|
|
|
|
// 修改的数据
|
|
var modifiedData = cmp.f_getModifiedData();
|
|
if (modifiedData.length > 0) {
|
|
saveInHiddenField('ModifiedData', Ext.encode(modifiedData));
|
|
} else {
|
|
removeHiddenField('ModifiedData');
|
|
}
|
|
|
|
/*
|
|
// 删除的行索引列表
|
|
var deletedRows = cmp.f_getDeletedRows();
|
|
if (deletedRows.length > 0) {
|
|
saveInHiddenField('DeletedRows', deletedRows.join(','));
|
|
} else {
|
|
removeHiddenField('DeletedRows');
|
|
}
|
|
*/
|
|
|
|
} else {
|
|
// 普通的表格
|
|
// 选中行索引列表
|
|
//saveInHiddenField('SelectedRowIndexArray', cmp.f_getSelectedRows().join(','));
|
|
// 选中行标识符列表
|
|
var selectedRows = cmp.f_getSelectedRows();
|
|
if (selectedRows && selectedRows.length) {
|
|
saveInHiddenField('SelectedRows', JSON.stringify(selectedRows));
|
|
} else {
|
|
removeHiddenField('SelectedRows');
|
|
}
|
|
}
|
|
|
|
|
|
// 隐藏的列索引列表
|
|
var gridHiddenColumns = cmp.f_getHiddenColumns();
|
|
if (gridHiddenColumns.length > 0) {
|
|
saveInHiddenField('HiddenColumns', gridHiddenColumns.join(','));
|
|
} else {
|
|
removeHiddenField('HiddenColumns');
|
|
}
|
|
|
|
// 目前States仅用于CheckBoxField
|
|
var gridStates = cmp.f_getStates();
|
|
if (gridStates.length > 0) {
|
|
saveInHiddenField('States', Ext.encode(gridStates));
|
|
} else {
|
|
removeHiddenField('States');
|
|
}
|
|
|
|
//// 如果存在 GZIPPED 的属性,就用 GZIPPED 属性
|
|
//resolveGZProperty('F_Rows');
|
|
}
|
|
|
|
//if (cmp.isXType('combo') || cmp.isXType('checkboxgroup') || cmp.isXType('radiogroup')) {
|
|
|
|
// // 如果存在 GZIPPED 的属性,就用 GZIPPED 属性
|
|
// resolveGZProperty('F_Items');
|
|
//}
|
|
|
|
if (cmp.isXType('field')) {
|
|
|
|
//// 如果存在 GZIPPED 的属性,就用 GZIPPED 属性
|
|
//resolveGZProperty('Text');
|
|
}
|
|
|
|
if (cmp.isXType('treepanel')) {
|
|
saveInHiddenField('ExpandedNodes', cmp.f_getExpandedNodes(cmp.getRootNode().childNodes).join(','));
|
|
saveInHiddenField('CheckedNodes', cmp.f_getCheckedNodes().join(','));
|
|
saveInHiddenField('SelectedNodeIDArray', cmp.f_getSelectedNodes().join(','));
|
|
|
|
//// 如果存在 GZIPPED 的属性,就用 GZIPPED 属性
|
|
//resolveGZProperty('F_Nodes');
|
|
}
|
|
|
|
if (cmp.isXType('tabpanel')) {
|
|
saveInHiddenField('ActiveTabIndex', cmp.f_getActiveTabIndex());
|
|
}
|
|
|
|
if (cmp.isXType('panel') && cmp.getLayout().type === 'accordion') {
|
|
saveInHiddenField('ActivePaneIndex', cmp.f_getActiveIndex());
|
|
}
|
|
|
|
if (cmp['f_type'] && cmp['f_type'] === 'tab') {
|
|
saveInHiddenField('Hidden', cmp.tab.isHidden());
|
|
}
|
|
|
|
//return state;
|
|
}
|
|
|
|
|
|
function showMaskAjaxLoading() {
|
|
|
|
var loadingMaskNode = Ext.get('f_ajax_loading_mask_mask');
|
|
var loadingNode = Ext.get('f_ajax_loading_mask');
|
|
// 如果还没有创建,则创建节点
|
|
if (!loadingNode) {
|
|
|
|
var loadingMaskHtml = '<div id="f_ajax_loading_mask_mask" class="f-loading-mask"></div>'
|
|
+ '<div id="f_ajax_loading_mask" class="f-loading"><div class="f-loading-img"><img src="' + F.loadingImage + '"/></div></div>';
|
|
|
|
Ext.DomHelper.append(Ext.getBody(), loadingMaskHtml);
|
|
|
|
|
|
loadingMaskNode = Ext.get('f_ajax_loading_mask_mask');
|
|
loadingNode = Ext.get('f_ajax_loading_mask');
|
|
}
|
|
|
|
|
|
loadingMaskNode.show();
|
|
loadingNode.show();
|
|
}
|
|
|
|
|
|
function hideMaskAjaxLoading() {
|
|
Ext.get('f_ajax_loading_mask_mask').hide();
|
|
Ext.get('f_ajax_loading_mask').hide();
|
|
}
|
|
|
|
// 显示“正在载入...”的提示信息
|
|
function _showAjaxLoading(ajaxLoadingType) {
|
|
// 延迟后,要再次检查当前有 AJAX 正在进行,才显示提示信息
|
|
if (__ajaxUnderwayCount > 0) {
|
|
|
|
if (ajaxLoadingType === "default") {
|
|
F.ajaxLoadingDefault.setStyle('left', (Ext.getBody().getWidth() - F.ajaxLoadingDefault.getWidth()) / 2 + 'px');
|
|
F.ajaxLoadingDefault.show();
|
|
} else {
|
|
//F.ajaxLoadingMask.show();
|
|
//Ext.getBody().mask(F.util.loading);
|
|
showMaskAjaxLoading();
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// 隐藏“正在载入...”的提示信息
|
|
function _hideAjaxLoading(ajaxLoadingType) {
|
|
if (__ajaxUnderwayCount === 0) {
|
|
|
|
if (ajaxLoadingType === "default") {
|
|
F.ajaxLoadingDefault.hide();
|
|
} else {
|
|
//F.ajaxLoadingMask.hide();
|
|
//Ext.getBody().unmask();
|
|
hideMaskAjaxLoading();
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
function ajaxStart() {
|
|
|
|
// 计数加一
|
|
__ajaxUnderwayCount++;
|
|
|
|
// 仅在第一个 AJAX 发起时,延迟显示提示信息
|
|
if (__ajaxUnderwayCount !== 1) {
|
|
return;
|
|
}
|
|
|
|
if (!enableAjaxLoading()) {
|
|
// Do nothing
|
|
} else {
|
|
Ext.defer(_showAjaxLoading, 50, window, [ajaxLoadingType()]);
|
|
}
|
|
|
|
}
|
|
|
|
function ajaxStop() {
|
|
// 计数减一
|
|
__ajaxUnderwayCount--;
|
|
if (__ajaxUnderwayCount < 0) {
|
|
__ajaxUnderwayCount = 0;
|
|
}
|
|
|
|
if (!enableAjaxLoading()) {
|
|
// ...
|
|
} else {
|
|
Ext.defer(_hideAjaxLoading, 0, window, [ajaxLoadingType()]);
|
|
}
|
|
|
|
if (__ajaxUnderwayCount === 0) {
|
|
F.controlEnableAjaxLoading = undefined;
|
|
F.controlAjaxLoadingType = undefined;
|
|
}
|
|
}
|
|
|
|
/*
|
|
// 当前 Ajax 的并发请求数
|
|
//var _requestCount = 0;
|
|
var _ajaxStarted = false;
|
|
|
|
// 发起 Ajax 请求之前事件处理
|
|
Ext.Ajax.on('beforerequest', function (conn, options) {
|
|
//_requestCount++;
|
|
|
|
_ajaxStarted = true;
|
|
ajaxStart();
|
|
});
|
|
|
|
// Ajax 请求结束
|
|
Ext.Ajax.on('requestcomplete', function (conn, options) {
|
|
//_requestCount--;
|
|
_ajaxStarted = false;
|
|
|
|
});
|
|
|
|
// Ajax 请求发生异常
|
|
Ext.Ajax.on('requestexception', function (conn, options) {
|
|
//_requestCount--;
|
|
_ajaxStarted = false;
|
|
|
|
|
|
});
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
// // 不适用于所有Extjs控件(比如Toolbar中放置按钮,这个按钮就没有ownerCt对象)
|
|
// // 更新一个Javascript对象
|
|
// updateObject: function(obj, newObjFunction, renderImmediately) {
|
|
// var id = obj.id;
|
|
// if (Ext.type(renderImmediately) == 'boolean' && !renderImmediately) {
|
|
|
|
// // 1.取得父容器
|
|
// var owner = obj.ownerCt;
|
|
// // 2.本控件在父容器的位置
|
|
// var insertIndex = owner.items.indexOf(obj);
|
|
// // 3.从父容器中销毁此控件
|
|
// owner.remove(obj);
|
|
// // 4.创建新的控件
|
|
// newObjFunction();
|
|
// // 5.将新的控件添加到删除的位置
|
|
// owner.insert(insertIndex, Ext.getCmp(id));
|
|
// // 6.父容器重新布局
|
|
// owner.doLayout();
|
|
|
|
// }
|
|
// else {
|
|
|
|
// // 1.销毁此控件
|
|
// obj.destroy();
|
|
// // 2.新建此控件
|
|
// newObjFunction();
|
|
// }
|
|
// }
|
|
|
|
})();
|
|
|
|
(function () {
|
|
|
|
// 计算黄金分割点的位置
|
|
// bodySize : 整个页面的Body的大小
|
|
// windowSize : 窗口的大小
|
|
function _calculateGoldenPosition(bodySize, windowSize) {
|
|
var top = (bodySize.height - (bodySize.height / 1.618)) - windowSize.height / 2;
|
|
if (top < 0) {
|
|
top = 0;
|
|
}
|
|
var left = (bodySize.width - windowSize.width) / 2;
|
|
if (left < 0) {
|
|
left = 0;
|
|
}
|
|
return { left: left, top: top };
|
|
}
|
|
|
|
// 计算中间的位置
|
|
// bodySize : 整个页面的Body的大小
|
|
// windowSize : 窗口的大小
|
|
function _calculateCenterPosition(bodySize, windowSize) {
|
|
var top = (bodySize.height - windowSize.height) / 2;
|
|
if (top < 0) {
|
|
top = 0;
|
|
}
|
|
var left = (bodySize.width - windowSize.width) / 2;
|
|
if (left < 0) {
|
|
left = 0;
|
|
}
|
|
return { left: left, top: top };
|
|
}
|
|
|
|
|
|
|
|
// 创建IFrame节点片段
|
|
function _createIFrameHtml(iframeUrl, iframeName) {
|
|
return '<iframe frameborder="0" style="overflow:auto;height:100%;width:100%;" name="' + iframeName + '" src="' + iframeUrl + '"></iframe>';
|
|
}
|
|
|
|
// 获取窗体的外部容器
|
|
function _getWrapperNode(panel) {
|
|
return Ext.get(panel.el.findParentNode('.f-window-wrapper'));
|
|
}
|
|
|
|
// FineUI窗口域(Window)
|
|
F.wnd = {
|
|
|
|
closeButtonTooltip: "Close this window",
|
|
formChangeConfirmMsg: "Current form has been modified, abandon changes?",
|
|
|
|
createIFrameHtml: function (iframeUrl, iframeName) {
|
|
return _createIFrameHtml(iframeUrl, iframeName);
|
|
},
|
|
|
|
// 窗体定义:Original Panel / Ghost Panel
|
|
|
|
// 显示一个弹出窗体
|
|
// 在 panel 实例中,定义了几个自定义属性,用于标示此实例的状态(在PanelBase中定义)
|
|
// 属性 - f_iframe/f_iframe_url/f_iframe_name/f_iframe_loaded
|
|
// panel : 当前弹出的窗体(Ext-Window)
|
|
// iframeUrl : 弹出窗体中包含的IFrame的地址
|
|
// windowTitle : 弹出窗体的标题
|
|
// left/top : 弹出窗体的左上角坐标(如果为空字符串,则使用中间位置或黄金分隔位置)
|
|
// isGoldenSection : 弹出窗体位于页面的黄金分隔位置
|
|
// hiddenHiddenFieldID : 隐藏表单字段记录此窗体是否弹出,也页面回发时保持状态用
|
|
show: function (panel, iframeUrl, windowTitle, left, top, isGoldenSection, hiddenHiddenFieldID, width, height) {
|
|
var target = F.util.getTargetWindow(panel.f_property_target);
|
|
var guid = panel.f_property_guid;
|
|
|
|
// 当前页面在IFrame中(window.frameElement 存在) - 这个判断有问题
|
|
// ----如果外部页面是 http://a.com/ 而内部页面是 http://b.com/ 在 b.com 内弹出窗体时, window.frameElement 就会出现拒绝访问
|
|
|
|
// parent != window - 当前窗体不是顶层窗体
|
|
// target !== window - 并且当前窗体不是需要弹出的位置(target)
|
|
if (parent != window && target !== window) {
|
|
|
|
if (!target.F[guid]) {
|
|
// 父窗口中已经创建了这个Ext-Window对象
|
|
var wrapper = guid + '_wrapper';
|
|
if (!target.Ext.get(wrapper)) {
|
|
target.F.util.appendFormNode('<div class="f-window-wrapper" id="' + wrapper + '"></div>');
|
|
} else {
|
|
target.Ext.get(wrapper).dom.innerHTML = '';
|
|
}
|
|
// Ext.apply 的第三个参数是default obejct
|
|
var config = Ext.apply({}, {
|
|
renderTo: wrapper,
|
|
id: guid,
|
|
f_property_window: window,
|
|
f_property_ext_window: panel
|
|
}, panel.initialConfig);
|
|
delete config.f_state;
|
|
delete config.items;
|
|
delete config.listeners;
|
|
|
|
|
|
// 在父页面中创建一个Ext-Window的幻影(拷贝)
|
|
//target.F[guid] = target.Ext.create('Ext.window.Window', config);
|
|
target.F.wnd.createGhostWindow(config);
|
|
}
|
|
panel = target.F[guid];
|
|
}
|
|
|
|
|
|
|
|
if (iframeUrl !== '') {
|
|
F.wnd.updateIFrameNode(panel, iframeUrl);
|
|
}
|
|
if (windowTitle != '') {
|
|
panel.setTitle(windowTitle);
|
|
}
|
|
|
|
|
|
if (typeof(width) === 'number' && width) {
|
|
panel.setWidth(width);
|
|
}
|
|
|
|
if (typeof(height) === 'number' && height) {
|
|
panel.setHeight(height);
|
|
}
|
|
|
|
|
|
Ext.get(hiddenHiddenFieldID).dom.value = 'false';
|
|
panel.show();
|
|
|
|
if (left !== '' && top !== '') {
|
|
panel.setPosition(parseInt(left, 10), parseInt(top, 10));
|
|
} else {
|
|
var bodySize = target.window.Ext.getBody().getViewSize();
|
|
var panelSize = panel.getSize(), leftTop;
|
|
if (isGoldenSection) {
|
|
leftTop = _calculateGoldenPosition(bodySize, panelSize);
|
|
} else {
|
|
leftTop = _calculateCenterPosition(bodySize, panelSize);
|
|
//panel.alignTo(target.Ext.getBody(), "c-c");
|
|
}
|
|
panel.setPosition(leftTop.left, leftTop.top);
|
|
}
|
|
|
|
F.wnd.fixMaximize(panel);
|
|
|
|
},
|
|
|
|
createGhostWindow: function (config) {
|
|
|
|
var ghostWnd = F.create('Ext.window.Window', config);
|
|
ghostWnd.on('beforeclose', function () {
|
|
|
|
// 如果原始窗体所在的页面存在,则触发原始窗体的 beforeclose 事件
|
|
if (F.canAccess(config.f_property_window)) {
|
|
config.f_property_ext_window.fireEvent('beforeclose', config.f_property_ext_window);
|
|
|
|
return false;
|
|
}
|
|
|
|
// 如果原始窗体已经被关闭,则不拦截 beforeclose 事件,会简单的关闭窗体
|
|
|
|
});
|
|
|
|
|
|
ghostWnd.on('maximize', function () {
|
|
|
|
/*
|
|
// 如果原始窗体所在的页面存在,则触发原始窗体的 maximize 事件
|
|
if (F.canAccess(config.f_property_window)) {
|
|
config.f_property_ext_window.fireEvent('maximize', config.f_property_ext_window);
|
|
} else {
|
|
F.wnd.fixMaximize(ghostWnd);
|
|
}
|
|
*/
|
|
|
|
F.wnd.fixMaximize(ghostWnd);
|
|
|
|
});
|
|
|
|
|
|
F[config.id] = ghostWnd;
|
|
},
|
|
|
|
|
|
// 获取Ghost Panel实例
|
|
getGhostPanel: function (panel, targetName, guid) {
|
|
if (typeof (targetName) === 'undefined') {
|
|
targetName = panel.f_property_target;
|
|
}
|
|
if (typeof (guid) === 'undefined') {
|
|
guid = panel.f_property_guid;
|
|
}
|
|
var target = F.util.getTargetWindow(targetName);
|
|
if (parent != window && target !== window) {
|
|
// 从父页面中查找幻影Ext-Window对象
|
|
panel = target.F[guid];
|
|
}
|
|
return panel;
|
|
},
|
|
|
|
// 隐藏Ext-Window(比如用户点击了关闭按钮)
|
|
hide: function (panel, enableIFrame, hiddenHiddenFieldID) {
|
|
var panel = F.wnd.getGhostPanel(panel);
|
|
|
|
// 如果返回 false,则说明隐藏操作被阻止了
|
|
if (panel.hide() !== false) {
|
|
|
|
// 修改当前页面中记录弹出窗口弹出状态的隐藏表单字段
|
|
Ext.get(hiddenHiddenFieldID).dom.value = 'true';
|
|
// 如果启用IFrame,则清空IFrame的内容,防止下次打开时显示残影
|
|
if (enableIFrame) {
|
|
// 如果不加延迟,IE下AJAX会出错,因为在success中已经把当前窗体关闭后,而后面还要继续使用本页面上相关对象
|
|
window.setTimeout(function () {
|
|
panel['f_iframe_loaded'] = false;
|
|
panel.update("");
|
|
}, 100);
|
|
}
|
|
|
|
}
|
|
},
|
|
|
|
// 最大化
|
|
maximize: function (panel) {
|
|
var panel = F.wnd.getGhostPanel(panel);
|
|
panel.maximize();
|
|
|
|
F.wnd.fixMaximize(panel);
|
|
},
|
|
|
|
// 最小化
|
|
minimize: function (panel) {
|
|
var panel = F.wnd.getGhostPanel(panel);
|
|
panel.minimize();
|
|
},
|
|
|
|
// 恢复窗体大小
|
|
restore: function (panel) {
|
|
var panel = F.wnd.getGhostPanel(panel);
|
|
panel.restore();
|
|
},
|
|
|
|
// 这是 Extjs 的一个 bug,如果 Window 控件不是渲染在 document.body 中,则 maximize 函数并不能真正的最大化
|
|
// 现在的 Window 控件时渲染在 from 表单里面的一个 DIV 中的
|
|
fixMaximize: function (panel) {
|
|
if (panel.maximized) {
|
|
var target = F.util.getTargetWindow(panel.f_property_target);
|
|
var bodySize = target.window.Ext.getBody().getViewSize();
|
|
panel.setSize(bodySize.width, bodySize.height);
|
|
// 不要忘记左上角坐标
|
|
panel.setPosition(0, 0);
|
|
}
|
|
},
|
|
|
|
// 创建或更新IFrame节点,同时更新panel实例中的自定义属性值
|
|
updateIFrameNode: function (panel, iframeUrl) {
|
|
var iframeUrlChanged = false;
|
|
panel = F.wnd.getGhostPanel(panel);
|
|
// 如果此Panel中包含有IFrame
|
|
if (panel && panel['f_iframe']) {
|
|
if (iframeUrl && panel['f_iframe_url'] !== iframeUrl) {
|
|
panel['f_iframe_url'] = iframeUrl;
|
|
iframeUrlChanged = true;
|
|
}
|
|
// 如果此Panel中包含的IFrame还没有加载
|
|
if (!panel['f_iframe_loaded']) {
|
|
window.setTimeout(function () {
|
|
// 如果此Panel已经创建完毕,但有时Panel可能是延迟创建的(比如TabStrip中的Tab,只有点击这个Tab时才创建Tab的内容)
|
|
panel['f_iframe_loaded'] = true;
|
|
panel.update(_createIFrameHtml(panel['f_iframe_url'], panel['f_iframe_name']));
|
|
}, 0);
|
|
}
|
|
else {
|
|
if (iframeUrlChanged) {
|
|
panel.body.query('iframe')[0].src = panel['f_iframe_url'];
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
|
|
// 处理表单中有任何字段发生变化时,关闭当前窗口时的提示
|
|
confirmModified: function (closeFn) {
|
|
if (F.util.isPageStateChanged()) {
|
|
F.util.confirm('_self', F.wnd.formModifiedConfirmTitle, F.wnd.formChangeConfirmMsg, function () {
|
|
closeFn.apply(window, arguments);
|
|
});
|
|
} else {
|
|
closeFn.apply(window, arguments);
|
|
}
|
|
},
|
|
|
|
|
|
// Ext-Window中IFrame里页面中的表单发生变化时弹出确认消息
|
|
iframeModifiedConfirm: function (panel, closeFn) {
|
|
// 这个页面所在的Window对象
|
|
var pageWindow = F.wnd.getIFrameWindowObject(panel);
|
|
// 如果弹出的页面没能正常加载(比如说网络暂时连接中断)
|
|
// 则直接关闭弹出的Ext-Window,而不会去检查页面表单变化,因为页面对象不存在
|
|
if (pageWindow.F) {
|
|
pageWindow.F.wnd.confirmModified(closeFn);
|
|
}
|
|
else {
|
|
panel.f_hide();
|
|
}
|
|
},
|
|
|
|
// 取得Ghost Panel所在页面window对象
|
|
getIFrameWindowObject: function (panel) {
|
|
// 当前页面在IFrame中(也即时 window.frameElement 存在)
|
|
// 此Ext-Window需要在父窗口中弹出
|
|
/*
|
|
if (window.frameElement && panel['f_property_show_in_parent']) {
|
|
panel = parent.F[panel['f_property_guid']];
|
|
}
|
|
*/
|
|
panel = F.wnd.getGhostPanel(panel);
|
|
var iframeNode = Ext.query('iframe', panel.body.dom);
|
|
if (iframeNode.length === 0) {
|
|
// 当前panel(Ext-Window)不包含iframe
|
|
return window;
|
|
}
|
|
else {
|
|
return iframeNode[0].contentWindow;
|
|
}
|
|
},
|
|
|
|
// 返回当前活动Window组件对象(浏览器窗口对象通过F.wnd.getActiveWindow().window获取)
|
|
getActiveWindow: function (justParentWindow) {
|
|
|
|
// Ext.WindowManager.getActive();有可能返回一个弹出对话框
|
|
function getActiveFineUIWindow(wnd) {
|
|
var result = wnd.Ext.WindowManager.getActive();
|
|
|
|
// 如果弹出的窗体不是 FineUI.Window 生成的窗体(有可能是Alert、Notify),则需要从排序列表中找
|
|
if (result && !result.f_property_guid) {
|
|
wnd.Ext.WindowManager.eachTopDown(function (cmp) {
|
|
if (cmp.f_property_guid) {
|
|
result = cmp;
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
var activeWindow = parent.window;
|
|
var activeExtWindow = getActiveFineUIWindow(activeWindow);
|
|
|
|
if (activeExtWindow) {
|
|
if (activeExtWindow.f_property_window && !justParentWindow) {
|
|
activeWindow = activeExtWindow.f_property_window;
|
|
activeExtWindow = activeExtWindow.f_property_ext_window;
|
|
}
|
|
activeExtWindow.window = activeWindow;
|
|
}
|
|
return activeExtWindow;
|
|
},
|
|
|
|
|
|
// 向弹出此Ext-Window的页面写入值
|
|
writeBackValue: function () {
|
|
var aw = F.wnd.getActiveWindow();
|
|
if (F.canAccess(aw.window)) {
|
|
var controlIds = aw.f_property_save_state_control_client_ids;
|
|
var controlCount = Math.min(controlIds.length, arguments.length);
|
|
for (var i = 0; i < controlCount; i++) {
|
|
aw.window.Ext.getCmp(controlIds[i]).setValue(arguments[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
function hideActiveWindow(type, param) {
|
|
var aw = F.getActiveWindow();
|
|
if (aw) {
|
|
if (F.canAccess(aw.window)) {
|
|
if (type === 'hide') {
|
|
aw.f_hide();
|
|
} else if (type === 'hiderefresh') {
|
|
aw.f_hide_refresh();
|
|
} else if (type === 'hidepostback') {
|
|
aw.f_hide_postback.call(aw, param)
|
|
} else if (type === 'hideexecutescript') {
|
|
aw.f_hide_executescript.call(aw, param)
|
|
}
|
|
} else {
|
|
var parentAW = F.getActiveWindow(true);
|
|
parentAW.hide();
|
|
}
|
|
}
|
|
}
|
|
|
|
// 当前激活窗体
|
|
F.activeWnd = {
|
|
|
|
hide: function () {
|
|
hideActiveWindow('hide');
|
|
},
|
|
|
|
hideRefresh: function () {
|
|
hideActiveWindow('hiderefresh');
|
|
},
|
|
|
|
hidePostBack: function (param) {
|
|
hideActiveWindow('hidepostback', param);
|
|
},
|
|
|
|
hideExecuteScript: function (param) {
|
|
hideActiveWindow('hideexecutescript', param);
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
})();
|
|
|
|
F.originalComponentHide = Ext.Component.prototype.hide;
|
|
Ext.override(Ext.Component, {
|
|
|
|
// override
|
|
hide: function () {
|
|
var me = this;
|
|
|
|
if (me.tab && me.tab.isXType('tab')) {
|
|
// tabpanel 单独处理
|
|
} else {
|
|
// 除了 tabpanel 的其他面板
|
|
if (me.body) {
|
|
// 检查当前组件内的表单是否改变(包含组件内 iframe 页面,递归查找所有 iframe)
|
|
if (F.util.preventPageClose(me.body)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return F.originalComponentHide.apply(me, arguments);
|
|
},
|
|
|
|
f_setDisabled: function () {
|
|
this.setDisabled(!this.f_state['Enabled']);
|
|
},
|
|
|
|
f_setVisible: function () {
|
|
this.setVisible(!this.f_state['Hidden']);
|
|
},
|
|
|
|
f_setWidth: function () {
|
|
this.setWidth(this.f_state['Width']);
|
|
},
|
|
|
|
f_setHeight: function () {
|
|
this.setHeight(this.f_state['Height']);
|
|
},
|
|
|
|
|
|
// Extjs v6.0: doLayout method has been removed. Use updateLayout instead.
|
|
doLayout: function (params) {
|
|
this.updateLayout(params);
|
|
}
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
// 1. tabpanel 单独处理,选项卡右上角的关闭按钮
|
|
F.originalTabBarCloseTab = Ext.tab.Bar.prototype.closeTab;
|
|
Ext.override(Ext.tab.Bar, {
|
|
// override
|
|
closeTab: function (toClose) {
|
|
var me = this, card = toClose.card;
|
|
|
|
if (card.body) {
|
|
// 检查当前组件内的表单是否改变(包含组件内 iframe 页面,递归查找所有 iframe)
|
|
if (F.util.preventPageClose(card.body)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return F.originalTabBarCloseTab.apply(me, arguments);
|
|
}
|
|
|
|
});
|
|
|
|
// 2. tabpanel 单独处理,选项卡的右键菜单
|
|
F.originalTabPanelRemove = Ext.tab.Panel.prototype.remove;
|
|
Ext.override(Ext.tab.Panel, {
|
|
|
|
// override
|
|
remove: function (comp) {
|
|
var me = this, c = me.getComponent(comp);
|
|
|
|
if (c && c.body) {
|
|
// 检查当前组件内的表单是否改变(包含组件内 iframe 页面,递归查找所有 iframe)
|
|
if (F.util.preventPageClose(c.body)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return F.originalTabPanelRemove.apply(me, arguments);
|
|
}
|
|
|
|
});
|
|
|
|
|
|
// 验证一个表单是否有效,会递归查询表单中每个字段
|
|
// 如果表单隐藏或者字段隐藏,则不进行有效性校验
|
|
Ext.override(Ext.container.Container, {
|
|
|
|
f_isValid: function () {
|
|
var valid = true;
|
|
var firstInvalidField = null;
|
|
if (!this.hidden) {
|
|
this.items.each(function (f) {
|
|
if (!f.hidden) {
|
|
if (f.isXType('field') || f.isXType('checkboxgroup')) {
|
|
if (!f.validate()) {
|
|
valid = false;
|
|
if (firstInvalidField == null) {
|
|
firstInvalidField = f;
|
|
}
|
|
}
|
|
} else if (f.isXType('container') && f.items.length) {
|
|
var validResult = f.f_isValid();
|
|
if (!validResult[0]) {
|
|
valid = false;
|
|
if (firstInvalidField == null) {
|
|
firstInvalidField = validResult[1];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
return [valid, firstInvalidField];
|
|
},
|
|
|
|
f_reset: function () {
|
|
var me = this;
|
|
if (me.items && me.items.length) {
|
|
me.items.each(function (item) {
|
|
if (item.isXType('field')) {
|
|
item.reset();
|
|
} else if (item.isXType('container') && item.items.length) {
|
|
item.f_reset();
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
// 当前面板内的表单字段是否改变
|
|
f_isDirty: function () {
|
|
var me = this, dirty = false;
|
|
|
|
if (me.items && me.items.length) {
|
|
me.items.each(function (item) {
|
|
if (item.isXType('field')) {
|
|
if (item.isDirty()) {
|
|
dirty = true;
|
|
return false;
|
|
}
|
|
} else if (item.isXType('container') && item.items.length) {
|
|
if (item.f_isDirty()) {
|
|
dirty = true;
|
|
return false;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
return dirty;
|
|
},
|
|
|
|
|
|
// 当前面板内的表单字段
|
|
f_clearDirty: function () {
|
|
var me = this;
|
|
|
|
if (me.items && me.items.length) {
|
|
me.items.each(function (item) {
|
|
if (item.isXType('field')) {
|
|
item.resetOriginalValue();
|
|
} else if (item.isXType('container') && item.items.length) {
|
|
item.f_clearDirty()
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
});
|
|
|
|
//F.originalPanelClose = Ext.panel.Panel.prototype.close;
|
|
|
|
Ext.override(Ext.panel.Panel, {
|
|
|
|
//// override
|
|
//close: function () {
|
|
|
|
// // 检查当前组件内的表单是否改变(包含组件内 iframe 页面,递归查找所有 iframe)
|
|
// if (F.util.preventPageClose(this.body)) {
|
|
// return false;
|
|
// }
|
|
|
|
|
|
// return F.originalPanelClose.apply(this, arguments);
|
|
//},
|
|
|
|
|
|
f_setCollapse: function () {
|
|
var collapsed = this.f_state['Collapsed'];
|
|
if (collapsed) {
|
|
this.collapse();
|
|
} else {
|
|
this.expand();
|
|
}
|
|
},
|
|
|
|
f_isCollapsed: function () {
|
|
/*
|
|
var collapsed = false;
|
|
var state = this.getState();
|
|
if (state && state.collapsed) {
|
|
collapsed = true;
|
|
}
|
|
return collapsed;
|
|
*/
|
|
return !!this.getCollapsed();
|
|
},
|
|
|
|
f_setTitle: function () {
|
|
this.setTitle(this.f_state['Title']);
|
|
},
|
|
|
|
f_getActiveIndex: function () {
|
|
var activeIndex = -1;
|
|
this.items.each(function (item, index) {
|
|
if (item.f_isCollapsed && !item.f_isCollapsed()) {
|
|
activeIndex = index;
|
|
return false;
|
|
}
|
|
});
|
|
return activeIndex;
|
|
}
|
|
|
|
|
|
});
|
|
|
|
Ext.override(Ext.form.FieldSet, {
|
|
f_setCollapse: function () {
|
|
var collapsed = this.f_state['Collapsed'];
|
|
if (collapsed) {
|
|
this.collapse();
|
|
} else {
|
|
this.expand();
|
|
}
|
|
},
|
|
|
|
f_isCollapsed: function () {
|
|
/*
|
|
var collapsed = false;
|
|
var state = this.getState();
|
|
if (state && state.collapsed) {
|
|
collapsed = true;
|
|
}
|
|
return collapsed;
|
|
*/
|
|
return !!this.getCollapsed();
|
|
},
|
|
|
|
f_setTitle: function () {
|
|
this.setTitle(this.f_state['Title']);
|
|
}
|
|
|
|
});
|
|
|
|
if (Ext.menu.CheckItem) {
|
|
Ext.override(Ext.menu.CheckItem, {
|
|
|
|
f_setChecked: function () {
|
|
this.setChecked(this.f_state['Checked'], true);
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
if (Ext.form.field.Base) {
|
|
Ext.override(Ext.form.field.Base, {
|
|
|
|
// Add functionality to Field's initComponent to enable the change event to bubble
|
|
/*
|
|
initComponent: Ext.form.Field.prototype.initComponent.createSequence(function () {
|
|
this.enableBubble('change');
|
|
}),
|
|
*/
|
|
|
|
/* 这会导致在文本输入框中按回车键,无法触发type=submit的表单回发事件
|
|
listeners: {
|
|
specialkey: function (field, e) {
|
|
if (e.getKey() == e.ENTER) {
|
|
e.stopEvent();
|
|
}
|
|
}
|
|
},
|
|
*/
|
|
|
|
/*
|
|
// When show or hide the field, also hide the label.
|
|
hide: function () {
|
|
Ext.form.Field.superclass.hide.call(this);
|
|
//this.callOverridden();
|
|
|
|
//var label = Ext.get(this.el.findParent('div[class=x-form-item]')).first('label[for=' + this.id + ']');
|
|
var labelAndField = this.el.findParentNode('div[class*=x-form-item]', 10, true);
|
|
if (labelAndField) {
|
|
if (this.hideMode == 'display') {
|
|
labelAndField.setVisibilityMode(Ext.Element.DISPLAY);
|
|
} else {
|
|
labelAndField.setVisibilityMode(Ext.Element.VISIBILITY);
|
|
}
|
|
labelAndField.hide();
|
|
}
|
|
},
|
|
|
|
show: function () {
|
|
Ext.form.Field.superclass.show.call(this);
|
|
//this.callOverridden();
|
|
|
|
//var label = Ext.get(this.el.findParent('div[class=x-form-item]')).first('label[for=' + this.id + ']');
|
|
var labelAndField = this.el.findParentNode('div[class*=x-form-item]', 10, true);
|
|
if (labelAndField) {
|
|
if (this.hideMode == 'display') {
|
|
labelAndField.setVisibilityMode(Ext.Element.DISPLAY);
|
|
} else {
|
|
labelAndField.setVisibilityMode(Ext.Element.VISIBILITY);
|
|
}
|
|
labelAndField.show();
|
|
}
|
|
},
|
|
*/
|
|
|
|
f_setValue: function (value) {
|
|
if (typeof (value) === 'undefined') {
|
|
value = this.f_state['Text'];
|
|
}
|
|
this.setValue(value);
|
|
},
|
|
|
|
f_setLabel: function (text) {
|
|
/*
|
|
if (this.label && this.label.update) {
|
|
this.label.update(text || this.f_state['Label']);
|
|
}
|
|
*/
|
|
var text = text || this.f_state['Label'];
|
|
if (this.setFieldLabel) {
|
|
this.setFieldLabel(text);
|
|
}
|
|
},
|
|
|
|
f_setReadOnly: function (readonly) {
|
|
var me = this;
|
|
|
|
if (typeof (readonly) === 'undefined') {
|
|
readonly = me.f_state['Readonly'];
|
|
}
|
|
|
|
if (me.setReadOnly) {
|
|
me.setReadOnly(readonly);
|
|
}
|
|
|
|
if (readonly) {
|
|
me.el.addCls('f-readonly');
|
|
} else {
|
|
me.el.removeCls('f-readonly');
|
|
}
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
|
|
Ext.override(Ext.form.field.Trigger, {
|
|
|
|
showTrigger: function () {
|
|
this.setTriggerVisible(1, true);
|
|
},
|
|
showTrigger1: function () {
|
|
this.setTriggerVisible(1, true);
|
|
},
|
|
showTrigger2: function () {
|
|
this.setTriggerVisible(2, true);
|
|
},
|
|
|
|
hideTrigger: function () {
|
|
this.setTriggerVisible(1, false);
|
|
},
|
|
hideTrigger1: function () {
|
|
this.setTriggerVisible(1, false);
|
|
},
|
|
hideTrigger2: function () {
|
|
this.setTriggerVisible(2, false);
|
|
},
|
|
|
|
setTriggerVisible: function (triggerNumber, visible) {
|
|
this.triggerCell.item(triggerNumber - 1).setDisplayed(visible);
|
|
}
|
|
|
|
});
|
|
|
|
if (Ext.form.Label) {
|
|
Ext.override(Ext.form.Label, {
|
|
|
|
f_setReadOnly: function (readonly) {
|
|
var me = this;
|
|
|
|
if (typeof (readonly) === 'undefined') {
|
|
readonly = me.f_state['Readonly'];
|
|
}
|
|
|
|
if (me.setReadOnly) {
|
|
me.setReadOnly(readonly);
|
|
}
|
|
|
|
if (readonly) {
|
|
me.el.addCls('f-readonly');
|
|
} else {
|
|
me.el.removeCls('f-readonly');
|
|
}
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Ext.form.CheckboxGroup) {
|
|
Ext.override(Ext.form.CheckboxGroup, {
|
|
|
|
f_setReadOnly: function (readonly) {
|
|
var me = this;
|
|
|
|
if (typeof (readonly) === 'undefined') {
|
|
readonly = me.f_state['Readonly'];
|
|
}
|
|
|
|
if (me.setReadOnly) {
|
|
me.setReadOnly(readonly);
|
|
}
|
|
|
|
if (readonly) {
|
|
me.el.addCls('f-readonly');
|
|
} else {
|
|
me.el.removeCls('f-readonly');
|
|
}
|
|
},
|
|
|
|
f_reloadData: function (name, isradiogroup) {
|
|
var container = this.ownerCt;
|
|
var newConfig = Ext.apply(this.initialConfig, {
|
|
"f_state": this.f_state,
|
|
"f_state_v": this.f_state_v,
|
|
"items": F.util.resolveCheckBoxGroup(name, this.f_state, isradiogroup)
|
|
});
|
|
|
|
if (container) {
|
|
var originalIndex = container.items.indexOf(this);
|
|
container.remove(this, true);
|
|
|
|
if (isradiogroup) {
|
|
container.insert(originalIndex, F.create('Ext.form.RadioGroup', newConfig));
|
|
} else {
|
|
container.insert(originalIndex, F.create('Ext.form.CheckboxGroup', newConfig));
|
|
}
|
|
|
|
container.doLayout();
|
|
} else {
|
|
this.destroy();
|
|
if (isradiogroup) {
|
|
F.create('Ext.form.RadioGroup', newConfig);
|
|
} else {
|
|
F.create('Ext.form.CheckboxGroup', newConfig);
|
|
}
|
|
|
|
}
|
|
},
|
|
|
|
/*
|
|
f_toBeDeleted: function () {
|
|
var tobedeleted = this.items.items[0];
|
|
if (tobedeleted && tobedeleted.inputValue === 'tobedeleted') {
|
|
tobedeleted.destroy();
|
|
this.items.remove(tobedeleted);
|
|
}
|
|
},
|
|
*/
|
|
|
|
// 选中项
|
|
f_setValue: function (values) {
|
|
// valueArray:["value1", "value2", "value3"]
|
|
var values = values || this.f_state['SelectedValueArray'];
|
|
|
|
var selectedObj = {};
|
|
this.items.each(function (item) {
|
|
var itemSelected = false;
|
|
if (Ext.Array.indexOf(values, item.inputValue) >= 0) {
|
|
itemSelected = true;
|
|
}
|
|
selectedObj[item.name] = itemSelected;
|
|
});
|
|
|
|
this.setValue(selectedObj);
|
|
},
|
|
|
|
// 返回 ["value1", "value2", "value3"]
|
|
f_getSelectedValues: function () {
|
|
var selectedValues = [];
|
|
var values = this.getValue();
|
|
Ext.Object.each(values, function (key, value) {
|
|
selectedValues.push(value);
|
|
});
|
|
return selectedValues;
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
|
|
|
|
if (Ext.form.field.Time) {
|
|
Ext.override(Ext.form.field.Time, {
|
|
|
|
// Time 继承自 ComboBox,这个函数被覆盖了,因此需要重新定义
|
|
f_setValue: function (value) {
|
|
if (typeof (value) === 'undefined') {
|
|
value = this.f_state['Text'];
|
|
}
|
|
this.setValue(value);
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
|
|
if (Ext.form.field.HtmlEditor) {
|
|
Ext.override(Ext.form.field.HtmlEditor, {
|
|
|
|
f_setValue: function (text) {
|
|
if (typeof (text) === 'undefined') {
|
|
text = this.f_state['Text'];
|
|
}
|
|
this.setValue(text);
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
|
|
if (Ext.form.field.Checkbox) {
|
|
Ext.override(Ext.form.field.Checkbox, {
|
|
|
|
f_setValue: function () {
|
|
this.setValue(this.f_state['Checked']);
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
|
|
if (Ext.form.RadioGroup) {
|
|
Ext.override(Ext.form.RadioGroup, {
|
|
|
|
f_setValue: function (value) {
|
|
value = value || this.f_state['SelectedValue'];
|
|
var selectedObj = {};
|
|
selectedObj[this.name] = value;
|
|
this.setValue(selectedObj);
|
|
//Ext.form.CheckboxGroup.prototype.f_setValue.apply(this, [value]);
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
|
|
if (Ext.form.field.ComboBox) {
|
|
Ext.override(Ext.form.field.ComboBox, {
|
|
// Load data from local cache.
|
|
// mode: "local",
|
|
// triggerAction: "all",
|
|
displayField: "text",
|
|
valueField: "value",
|
|
//tpl: "<tpl for=\".\"><div class=\"x-combo-list-item <tpl if=\"!enabled\">x-combo-list-item-disable</tpl>\">{prefix}{text}</div></tpl>",
|
|
|
|
// These variables are in the Ext.form.ComboBox.prototype, therefore all instance will refer to the same store instance.
|
|
//store: new Ext.data.ArrayStore({ fields: ['value', 'text', 'enabled', 'prefix'] }),
|
|
|
|
f_setValue: function (value) {
|
|
// value 可以是空字符串
|
|
if (typeof (value) === 'undefined') {
|
|
var stateSelectedValueArray = this.f_state['SelectedValueArray'];
|
|
if (this.multiSelect) {
|
|
value = stateSelectedValueArray;
|
|
} else {
|
|
value = stateSelectedValueArray[0];
|
|
}
|
|
}
|
|
this.setValue(value);
|
|
},
|
|
|
|
f_loadData: function (data) {
|
|
data = data || this.f_state['F_Items'];
|
|
if (data) {
|
|
this.store.loadData(F.simulateTree.transform(data));
|
|
}
|
|
},
|
|
|
|
|
|
f_getTextByValue: function (value, data) {
|
|
data = data || this.f_state['F_Items'];
|
|
value += ''; // 把Value转换为字符串
|
|
for (var i = 0, count = data.length; i < count; i++) {
|
|
var item = data[i];
|
|
if (item[0] === value) {
|
|
return item[1];
|
|
}
|
|
}
|
|
return '';
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
|
|
if (Ext.button.Button) {
|
|
Ext.override(Ext.button.Button, {
|
|
|
|
f_setTooltip: function () {
|
|
this.setTooltip(this.f_state['ToolTip']);
|
|
},
|
|
|
|
f_toggle: function () {
|
|
this.toggle(this.f_state['Pressed']);
|
|
},
|
|
|
|
f_setText: function () {
|
|
this.setText(this.f_state['Text']);
|
|
}
|
|
|
|
|
|
});
|
|
}
|
|
|
|
|
|
|
|
if (Ext.grid.column.RowNumberer) {
|
|
|
|
F.originalRowNumbererRenderer = Ext.grid.column.RowNumberer.prototype.defaultRenderer;
|
|
Ext.override(Ext.grid.column.RowNumberer, {
|
|
|
|
defaultRenderer: function () {
|
|
|
|
var number = F.originalRowNumbererRenderer.apply(this, arguments);
|
|
|
|
if (this.f_paging) {
|
|
var pagingBar = F(this.f_paging_grid).f_getPaging();
|
|
if (pagingBar) {
|
|
number += pagingBar.f_pageIndex * pagingBar.f_pageSize;
|
|
}
|
|
}
|
|
|
|
return number;
|
|
}
|
|
});
|
|
|
|
}
|
|
|
|
|
|
if (Ext.grid.Panel) {
|
|
Ext.override(Ext.grid.Panel, {
|
|
|
|
f_getData: function () {
|
|
var $this = this, rows = this.f_state['F_Rows'];
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
var tpls = this.f_getTpls(this.f_tpls);
|
|
|
|
// 将Grid1_ctl37与对应的outHTML放在哈希表中
|
|
var tplsHash = {};
|
|
var e = document.createElement('div');
|
|
e.innerHTML = tpls;
|
|
Ext.Array.each(e.childNodes, function (item, index) {
|
|
tplsHash[item.id] = item.outerHTML.replace(/\r?\n\s*/ig, '');
|
|
});
|
|
|
|
/*
|
|
// 将服务器返回的字符串转换为实际的JavaScript类型
|
|
function resolveActualDataItem(fieldValue, fieldIndex) {
|
|
var fieldType = $this.f_fields[fieldIndex].type;
|
|
if (fieldType) {
|
|
if (fieldType === 'date') {
|
|
fieldValue = new Date(fieldValue);
|
|
} else if (fieldType === 'boolean') {
|
|
if (fieldValue == 'true' || fieldValue == '1') {
|
|
fieldValue = true;
|
|
} else {
|
|
fieldValue = false;
|
|
}
|
|
} else if (fieldType === 'float') {
|
|
fieldValue = parseFloat(fieldValue);
|
|
} else if (fieldType === 'int') {
|
|
fieldValue = parseInt(fieldValue, 10);
|
|
}
|
|
}
|
|
return fieldValue;
|
|
}
|
|
*/
|
|
|
|
// 不要改变 F_Rows.Values 的原始数据,因为这个值会被POST到后台
|
|
/*
|
|
var newdata = [], newdataitem;
|
|
Ext.Array.each(data, function (row, rowIndex) {
|
|
newdataitem = [];
|
|
Ext.Array.each(row, function (item, index) {
|
|
if (typeof (item) === 'string' && item.substr(0, 7) === "#@TPL@#") {
|
|
var clientId = $this.id + '_' + item.substr(7);
|
|
newdataitem.push('<div id="' + clientId + '_container">' + tplsHash[clientId] + '</div>');
|
|
} else {
|
|
//newdataitem.push(resolveActualDataItem(item, index));
|
|
newdataitem.push(item);
|
|
}
|
|
});
|
|
newdata.push(newdataitem);
|
|
});
|
|
*/
|
|
|
|
var newdata = [];
|
|
Ext.Array.each(rows, function (row, rowIndex) {
|
|
var newdataitem = [];
|
|
|
|
// row['f0'] -> Values
|
|
|
|
// [v6.0.1]修正DataKeyNames值是小数(比如9.80),则页面回发时会出现F_STATE验证出错的问题(Fire-8910)。
|
|
var rowf0 = row['f0'];
|
|
if(typeof(rowf0) === 'string') {
|
|
rowf0 = JSON.parse(rowf0);
|
|
}
|
|
|
|
Ext.Array.each(rowf0, function (item, cellIndex) {
|
|
var newcellvalue = item;
|
|
if (typeof (item) === 'string' && item.substr(0, 7) === "#@TPL@#") {
|
|
var clientId = $this.id + '_' + item.substr(7);
|
|
newcellvalue = '<div id="' + clientId + '_container">' + tplsHash[clientId] + '</div>';
|
|
}
|
|
|
|
newdataitem.push(newcellvalue);
|
|
});
|
|
|
|
// idProperty
|
|
var rowId = row['f6'];
|
|
if (typeof (rowId) === 'undefined') {
|
|
// 如果未定义 id,要生成一个 id,用来记录选中的行(否则在行调整顺序后,选中的行就乱了)
|
|
rowId = 'fineui_row_' + rowIndex;
|
|
}
|
|
newdataitem.push(rowId);
|
|
|
|
|
|
newdata.push(newdataitem);
|
|
});
|
|
//////////////////////////////////////////////////
|
|
|
|
return newdata;
|
|
},
|
|
|
|
f_getTpls: function (paramTpls) {
|
|
var tpls;
|
|
if (typeof (paramTpls) !== 'undefined') {
|
|
// 1. 如果Tpls存在于函数参数中
|
|
tpls = paramTpls;
|
|
this['data-last-tpls'] = tpls;
|
|
} else {
|
|
var tplsNode = Ext.get(this.id + '_tpls');
|
|
if (tplsNode) {
|
|
// 2. 如果Tpls存在于页面节点中
|
|
tpls = tplsNode.dom.innerHTML;
|
|
// 获取模板列的内容之后,必须要删除原有的节点,因为会在表格中创建完全相同的新节点
|
|
tplsNode.remove();
|
|
|
|
// 将模板列内容保存到表格实例中
|
|
this['data-last-tpls'] = tpls;
|
|
} else {
|
|
// 3. 从缓存中读取
|
|
// 从表格实例中读取模板列内容
|
|
tpls = this['data-last-tpls'];
|
|
}
|
|
}
|
|
|
|
return tpls;
|
|
},
|
|
|
|
|
|
f_updateTpls: function (tpls) {
|
|
tpls = this.f_getTpls(tpls);
|
|
|
|
var e = document.createElement('div');
|
|
e.innerHTML = tpls;
|
|
Ext.Array.each(e.childNodes, function (item, index) {
|
|
var nodeId = item.id;
|
|
var tplContainer = Ext.get(nodeId + '_container');
|
|
|
|
// 对于内存分页,模板列的内容可能还没有渲染到页面中
|
|
if (tplContainer) {
|
|
tplContainer.dom.innerHTML = item.outerHTML;
|
|
}
|
|
});
|
|
},
|
|
|
|
f_getPaging: function () {
|
|
var toolbar = this.getDockedItems('toolbar[dock="bottom"][xtype="simplepagingtoolbar"]');
|
|
return toolbar.length ? toolbar[0] : undefined;
|
|
},
|
|
|
|
f_loadData: function () {
|
|
var datas = this.f_getData();
|
|
var pagingBar = this.f_getPaging();
|
|
if (pagingBar) {
|
|
var pagingDatas = [];
|
|
if (pagingBar.f_databasePaging) {
|
|
pagingDatas = datas;
|
|
} else {
|
|
for (var i = pagingBar.f_startRowIndex; i <= pagingBar.f_endRowIndex; i++) {
|
|
pagingDatas.push(datas[i]);
|
|
}
|
|
}
|
|
datas = pagingDatas;
|
|
}
|
|
|
|
|
|
var store = this.getStore();
|
|
|
|
// 已经设置 Ext.data.Store 的 pruneModifiedRecords ,在重新加载数据时都会清除所有已经改变的数据
|
|
// 所以无需 rejectChanges
|
|
// 拒绝之前对表格的编辑,因为接下来就要重新加载数据
|
|
//store.rejectChanges();
|
|
|
|
// 重新加载数据前清空之前的改变
|
|
//this.f_newAddedRows = [];
|
|
//this.f_deletedRows = [];
|
|
|
|
store.loadData(datas);
|
|
|
|
|
|
if (this.f_cellEditing) {
|
|
this.f_cellEditing.cancelEdit();
|
|
store.commitChanges();
|
|
this.f_initRecordIDs();
|
|
}
|
|
},
|
|
|
|
// 初始化所有记录的ID列表
|
|
f_initRecordIDs: function () {
|
|
var $this = this;
|
|
this.f_recordIDs = [];
|
|
this.getStore().each(function (record, index) {
|
|
$this.f_recordIDs.push(record.id);
|
|
});
|
|
},
|
|
|
|
// 展开所有的行扩展列
|
|
f_expandAllRows: function () {
|
|
var expander = this.getPlugin(this.id + '_rowexpander');
|
|
if (expander) {
|
|
var store = this.getStore();
|
|
for (var i = 0, count = store.getCount() ; i < count; i++) {
|
|
var record = store.getAt(i);
|
|
if (!expander.recordsExpanded[record.internalId]) {
|
|
expander.toggleRow(i, record);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
// 隐藏所有的行扩展列
|
|
f_collapseAllRows: function () {
|
|
var expander = this.getPlugin(this.id + '_rowexpander');
|
|
if (expander) {
|
|
var store = this.getStore();
|
|
for (var i = 0, count = store.getCount() ; i < count; i++) {
|
|
var record = store.getAt(i);
|
|
if (expander.recordsExpanded[record.internalId]) {
|
|
expander.toggleRow(i, record);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
// http://evilcroco.name/2010/10/making-extjs-grid-content-selectable/
|
|
// IE下允许选中表格中的文本
|
|
/*
|
|
f_enableTextSelection: function () {
|
|
var elems = Ext.DomQuery.select("div[unselectable=on]", this.el.dom);
|
|
for (var i = 0, len = elems.length; i < len; i++) {
|
|
Ext.get(elems[i]).set({ 'unselectable': 'off' }).removeCls('x-unselectable');
|
|
}
|
|
},
|
|
*/
|
|
|
|
// 获取选中的行数,或者单元格数(单元格编辑模式)
|
|
f_getSelectedCount: function () {
|
|
var selectedCount = 0;
|
|
var sm = this.getSelectionModel();
|
|
if (sm.hasSelection()) {
|
|
if (sm.getCount) {
|
|
selectedCount = sm.getCount();
|
|
} else {
|
|
// 单元格编辑模式,只可能选中一个单元格
|
|
selectedCount = 1;
|
|
}
|
|
}
|
|
return selectedCount;
|
|
},
|
|
|
|
|
|
f_clearSelections: function () {
|
|
var me = this;
|
|
var sm = me.getSelectionModel();
|
|
|
|
sm.deselectAll(true);
|
|
},
|
|
|
|
// 选中某些行
|
|
f_selectRows: function (rows) {
|
|
var me = this;
|
|
rows = rows || me.f_state['SelectedRowIDArray'] || [];
|
|
|
|
var sm = me.getSelectionModel();
|
|
var store = me.getStore();
|
|
|
|
// 如果传入 rows=[],则需要先清空全部选中行
|
|
sm.deselectAll(true);
|
|
if (rows.length) {
|
|
Ext.Array.each(rows, function (row, index) {
|
|
// select( records, [keepExisting], [suppressEvent] )
|
|
// 有可能存在指定的行找不到的情况
|
|
var rowInstance = store.getById(row);
|
|
if (rowInstance) {
|
|
sm.select(rowInstance, true, true);
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
// 选中全部行
|
|
f_selectAllRows: function () {
|
|
var sm = this.getSelectionModel();
|
|
if (sm.selectAll) {
|
|
sm.selectAll(true);
|
|
}
|
|
},
|
|
|
|
// 获取选中的行
|
|
f_getSelectedRows: function () {
|
|
var me = this, selectedRows = [];
|
|
|
|
var sm = me.getSelectionModel();
|
|
if (sm.getSelection) {
|
|
var selection = sm.getSelection();
|
|
var store = me.getStore();
|
|
|
|
Ext.Array.each(selection, function (record, index) {
|
|
// 晕倒:新增行的 record.getId() 居然为 undedined,没办法!
|
|
selectedRows.push(record.getId());
|
|
});
|
|
}
|
|
|
|
return selectedRows;
|
|
},
|
|
|
|
|
|
// 选中单元格(AllowCellEditing)
|
|
f_selectCell: function (rowId, columnId) {
|
|
var me = this;
|
|
|
|
var cell = rowId;
|
|
if (typeof (cell) === 'undefined') {
|
|
cell = me.f_state['SelectedCell'] || [];
|
|
} else if (!Ext.isArray(cell)) {
|
|
cell = [rowId, columnId];
|
|
}
|
|
|
|
if (cell && cell.length === 2) {
|
|
// 支持[行索引,列索引],也支持[行Id,列Id]
|
|
var row = cell[0];
|
|
var column = cell[1];
|
|
|
|
// 如果未定义,则直接返回
|
|
if (!row || !column) {
|
|
return;
|
|
}
|
|
|
|
if (typeof (row) === 'string') {
|
|
row = me.f_getRow(row);
|
|
}
|
|
|
|
if (typeof (column) === 'string') {
|
|
column = me.f_getColumn(column);
|
|
}
|
|
|
|
var sm = me.getSelectionModel();
|
|
sm.setCurrentPosition({
|
|
row: row,
|
|
column: column
|
|
});
|
|
}
|
|
},
|
|
|
|
// 获取选中的单元格(AllowCellEditing)
|
|
f_getSelectedCell: function () {
|
|
var me = this, selectedCell = [], currentPos;
|
|
var sm = me.getSelectionModel();
|
|
if (sm.getCurrentPosition) {
|
|
currentPos = sm.getCurrentPosition();
|
|
if (currentPos) {
|
|
selectedCell = [currentPos.record.getId(), currentPos.columnHeader.id];
|
|
}
|
|
}
|
|
return selectedCell;
|
|
},
|
|
|
|
|
|
// 获取隐藏列的名称列表
|
|
f_getHiddenColumns: function () {
|
|
var hiddens = [], columns = this.f_getColumns();
|
|
Ext.Array.each(columns, function (column, index) {
|
|
var columnId = column.id;
|
|
|
|
// 行扩展列需要单独处理,id属性不是 expander
|
|
if (!column.dataIndex && column.innerCls && column.innerCls.indexOf('row-expander') > 0) {
|
|
columnId = 'expander';
|
|
|
|
}
|
|
|
|
if (column.isHidden()) {
|
|
hiddens.push(columnId);
|
|
}
|
|
});
|
|
return hiddens;
|
|
},
|
|
|
|
// 隐藏需要隐藏的列,显示不需要隐藏的列
|
|
f_updateColumnsHiddenStatus: function (hiddens) {
|
|
hiddens = hiddens || this.f_state['HiddenColumns'] || [];
|
|
var columns = this.f_getColumns();
|
|
Ext.Array.each(columns, function (column, index) {
|
|
var columnId = column.id;
|
|
|
|
// 行扩展列需要单独处理,id属性不是 expander
|
|
if (!column.dataIndex && column.innerCls && column.innerCls.indexOf('row-expander') > 0) {
|
|
columnId = 'expander';
|
|
}
|
|
|
|
if (Ext.Array.indexOf(hiddens, columnId) !== -1) {
|
|
column.setVisible(false);
|
|
} else {
|
|
column.setVisible(true);
|
|
}
|
|
});
|
|
},
|
|
|
|
// 初始化排序列头
|
|
f_initSortHeaders: function () {
|
|
var gridEl = Ext.get(this.id), columns = this.f_getColumns();
|
|
|
|
// 为所有可排序列添加手型光标
|
|
Ext.Array.each(columns, function (item, index) {
|
|
if (item['sortable']) {
|
|
Ext.get(item.id).addCls('cursor-pointer');
|
|
}
|
|
});
|
|
},
|
|
|
|
// 设置表格标题栏的排序图标
|
|
f_setSortIcon: function (sortColumnID, sortDirection) {
|
|
var gridEl = Ext.get(this.id), columns = this.f_getColumns(), headers = gridEl.select('.x-column-header');
|
|
|
|
// 清空所有可排序列的排序箭头
|
|
headers.removeCls(['x-column-header-sort-DESC', 'x-column-header-sort-ASC']);
|
|
|
|
// 为所有可排序列添加手型光标
|
|
Ext.Array.each(columns, function (item, index) {
|
|
if (item['sortable']) {
|
|
Ext.get(item.id).addCls('cursor-pointer');
|
|
}
|
|
});
|
|
|
|
// 设置当前列的排序箭头
|
|
if (sortColumnID) {
|
|
Ext.get(sortColumnID).addCls('x-column-header-sort-' + sortDirection.toUpperCase());
|
|
}
|
|
|
|
},
|
|
|
|
// 获取表格列
|
|
f_getColumns: function () {
|
|
/*
|
|
var columns = [];
|
|
var configColumns = this.getColumnModel().config;
|
|
Ext.Array.each(configColumns, function (item, index) {
|
|
// expander也属于表格列的一种类型,否则设置f_setSortIcon会出错
|
|
if (item.id !== 'numberer' && item.id !== 'checker') { // && item.id !== 'expander'
|
|
columns.push(item);
|
|
}
|
|
});
|
|
*/
|
|
|
|
// columns 属性不包含行扩展列
|
|
//return this.columns;
|
|
|
|
// this.columnManager.columns 返回相同内容
|
|
return this.headerCt.getGridColumns();
|
|
},
|
|
|
|
// 这个方法用不到了,现在对States的更新会导致Values的改变,进而促使表格的重新加载
|
|
/*
|
|
f_setRowStates: function (states) {
|
|
var gridEl = Ext.get(this.id), columns = this.f_getColumns(), states = states || this.f_state['f_states'] || [];
|
|
|
|
function setCheckBoxStates(columnIndex, stateColumnIndex) {
|
|
var checkboxRows = gridEl.select('.x-grid-body .x-grid-item .x-grid-td-' + columns[columnIndex].id + ' .f-grid-checkbox');
|
|
checkboxRows.each(function (row, rows, index) {
|
|
if (states[index][stateColumnIndex]) {
|
|
if (row.hasCls('box-grid-checkbox-unchecked-disabled')) {
|
|
row.removeCls('box-grid-checkbox-unchecked-disabled');
|
|
} else {
|
|
row.removeCls('box-grid-checkbox-unchecked');
|
|
}
|
|
} else {
|
|
if (row.hasCls('box-grid-checkbox-disabled')) {
|
|
row.addCls('box-grid-checkbox-unchecked-disabled')
|
|
} else {
|
|
row.addCls('box-grid-checkbox-unchecked')
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
var stateColumnIndex = 0;
|
|
Ext.Array.each(columns, function (column, index) {
|
|
if (column['f_persistState']) {
|
|
if (column['f_persistStateType'] === 'checkbox') {
|
|
setCheckBoxStates(index, stateColumnIndex);
|
|
stateColumnIndex++;
|
|
}
|
|
}
|
|
});
|
|
},
|
|
*/
|
|
|
|
// 获取列状态(目前只有CheckBoxField用到)
|
|
f_getStates: function () {
|
|
var gridEl = Ext.get(this.id), columns = this.f_getColumns(), states = [];
|
|
|
|
function getCheckBoxStates(columnIndex) {
|
|
var checkboxRows = gridEl.select('.x-grid-item .x-grid-cell-' + columns[columnIndex].id + ' .f-grid-checkbox');
|
|
var columnStates = [];
|
|
checkboxRows.each(function (row, index) {
|
|
if (row.hasCls('unchecked')) {
|
|
columnStates.push(false);
|
|
} else {
|
|
columnStates.push(true);
|
|
}
|
|
});
|
|
return columnStates;
|
|
}
|
|
|
|
Ext.Array.each(columns, function (column, index) {
|
|
if (column['f_persistState']) {
|
|
if (column['f_persistStateType'] === 'checkbox') {
|
|
states.push(getCheckBoxStates(index));
|
|
}
|
|
}
|
|
});
|
|
|
|
// 把列状态列表转换为行状态列表,与后台数据保持一致
|
|
var i, resolvedStates = [], rowState, rowCount;
|
|
if (states.length > 0) {
|
|
rowCount = states[0].length;
|
|
for (i = 0; i < rowCount; i++) {
|
|
rowState = [];
|
|
Ext.Array.each(states, function (state, index) {
|
|
rowState.push(state[i]);
|
|
});
|
|
resolvedStates.push(rowState);
|
|
}
|
|
}
|
|
|
|
return resolvedStates;
|
|
},
|
|
|
|
// 提交客户端改变
|
|
f_commitChanges: function () {
|
|
|
|
if (this.f_cellEditing) {
|
|
this.f_cellEditing.cancelEdit();
|
|
this.getStore().commitChanges();
|
|
this.f_initRecordIDs();
|
|
}
|
|
|
|
},
|
|
|
|
|
|
// 仅内部使用(f_deleteSelectedRows)
|
|
f_getSelectedRowsIndex: function () {
|
|
var selectedRows = [];
|
|
var sm = this.getSelectionModel();
|
|
if (sm.getSelection) {
|
|
var selection = sm.getSelection();
|
|
var store = this.getStore();
|
|
|
|
Ext.Array.each(selection, function (record, index) {
|
|
selectedRows.push(store.indexOf(record));
|
|
});
|
|
}
|
|
|
|
return selectedRows;
|
|
},
|
|
|
|
// 仅内部使用(f_deleteSelectedRows)
|
|
f_getSelectedCellIndex: function () {
|
|
var selectedCell = [], currentPos;
|
|
var sm = this.getSelectionModel();
|
|
if (sm.getCurrentPosition) {
|
|
currentPos = sm.getCurrentPosition();
|
|
if (currentPos) {
|
|
selectedCell = [currentPos.row, currentPos.columnHeader.f_columnIndex];
|
|
}
|
|
}
|
|
return selectedCell;
|
|
},
|
|
|
|
// 从Store中删除选中的行(或者单元格)
|
|
f_deleteSelectedRows: function () {
|
|
var $this = this;
|
|
var store = this.getStore();
|
|
|
|
var sm = this.getSelectionModel();
|
|
if (sm.getSelection) {
|
|
var rows = this.f_getSelectedRowsIndex();
|
|
Ext.Array.each(rows, function (rowIndex, index) {
|
|
store.removeAt(rowIndex);
|
|
});
|
|
} else if (sm.getSelectedCell) {
|
|
var selectedCell = this.f_getSelectedCellIndex();
|
|
if (selectedCell.length) {
|
|
store.removeAt(selectedCell[0]);
|
|
}
|
|
}
|
|
},
|
|
|
|
f_generateNewId: function () {
|
|
var newid = 'fineui_' + F.f_objectIndex;
|
|
|
|
F.f_objectIndex++;
|
|
|
|
return newid;
|
|
},
|
|
|
|
// 添加一条新纪录
|
|
f_addNewRecord: function (defaultObj, appendToEnd, editColumnId) {
|
|
var me = this, store = me.getStore();
|
|
var newRecord = defaultObj; //new Ext.data.Model(defaultObj);
|
|
|
|
|
|
// 如果设置了 id,则 extjs 认为这不是一个 phantom(幻影),而是一个真实存在的数据,rejectChanges 就不能去除这条数据了
|
|
/*
|
|
// 自动生成ID
|
|
if(typeof(newRecord.__id) === 'undefined') {
|
|
newRecord.__id = me.f_generateNewId();
|
|
}
|
|
*/
|
|
|
|
// 清空当前选中的单元格
|
|
me.getSelectionModel().setCurrentPosition();
|
|
|
|
|
|
// 取消正在编辑
|
|
me.f_cellEditing.cancelEdit();
|
|
|
|
|
|
|
|
var newAddedRecords;
|
|
//var rowIndex = 0;
|
|
if (appendToEnd) {
|
|
newAddedRecords = store.add(newRecord);
|
|
//rowIndex = store.getCount() - 1;
|
|
} else {
|
|
newAddedRecords = store.insert(0, newRecord);
|
|
//rowIndex = 0;
|
|
}
|
|
|
|
var newAddedRecord = newAddedRecords[0];
|
|
|
|
|
|
// phantom: True when the record does not yet exist in a server-side database (see setDirty). Any record which has a real database pk set as its id property is NOT a phantom -- it's real.
|
|
// 如果设置了 id 属性,则 extjs 认为这不是一个 phantom(幻影),而是一个真实存在的数据,然后通过 getStore().getModifiedRecords() 就得不到这条记录了。
|
|
// 所以需要设置 setDirty
|
|
//newAddedRecord.setDirty(true);
|
|
|
|
var column;
|
|
if (typeof (editColumnId) === 'undefined') {
|
|
column = me.f_firstEditableColumn();
|
|
} else {
|
|
column = me.f_getColumn(editColumnId);
|
|
}
|
|
|
|
me.f_cellEditing.startEdit(newAddedRecord, column);
|
|
},
|
|
|
|
|
|
f_startEdit: function (rowId, columnId) {
|
|
var me = this;
|
|
|
|
me.f_cellEditing.startEdit(me.f_getRow(rowId), me.f_getColumn(columnId));
|
|
},
|
|
|
|
//// 获取新增的行索引(在修改后的列表中)
|
|
//f_getNewAddedRows: function () {
|
|
// var $this = this;
|
|
// var newAddedRows = [];
|
|
// this.getStore().each(function (record, index) {
|
|
// if (Ext.Array.indexOf($this.f_recordIDs, record.id) < 0) {
|
|
// newAddedRows.push(index);
|
|
// }
|
|
// });
|
|
// return newAddedRows;
|
|
//},
|
|
|
|
/*
|
|
// 获取删除的行索引(在原始的列表中)
|
|
f_getDeletedRows: function () {
|
|
var me = this, currentRecordIDs = [], deletedRows = [];
|
|
me.getStore().each(function (record, index) {
|
|
currentRecordIDs.push(record.id);
|
|
});
|
|
|
|
// 快速判断是否存在行被删除的情况
|
|
if (currentRecordIDs.join('') === me.f_recordIDs.join('')) {
|
|
return []; // 没有行被删除
|
|
}
|
|
|
|
|
|
// 内存分页,特殊处理
|
|
var originalIndexPlus = 0;
|
|
var pagingBar = me.f_getPaging();
|
|
if (pagingBar && !pagingBar.f_databasePaging) {
|
|
originalIndexPlus = pagingBar.f_pageIndex * pagingBar.f_pageSize;
|
|
}
|
|
|
|
|
|
Ext.Array.each(me.f_recordIDs, function (recordID, index) {
|
|
if (Ext.Array.indexOf(currentRecordIDs, recordID) < 0) {
|
|
//deletedRows.push(index + originalIndexPlus);
|
|
deletedRows.push({
|
|
index: -1,
|
|
originalIndex: index + originalIndexPlus,
|
|
id: recordID,
|
|
status: 'deleted'
|
|
});
|
|
}
|
|
});
|
|
return deletedRows;
|
|
},
|
|
*/
|
|
|
|
f_firstEditableColumn: function () {
|
|
var me = this, columns = me.f_getColumns();
|
|
|
|
for (var i = 0, count = columns.length; i < count; i++) {
|
|
var column = columns[i];
|
|
if (me.f_columnEditable(column)) {
|
|
return column;
|
|
}
|
|
}
|
|
|
|
return undefined;
|
|
},
|
|
|
|
f_columnEditable: function (columnID) {
|
|
var me = this, columns = me.f_getColumns();
|
|
|
|
var column = columnID;
|
|
if (typeof (columnID) === 'string') {
|
|
column = me.f_getColumn(column);
|
|
}
|
|
|
|
if (column && column.f_editable) {
|
|
return true;
|
|
/*
|
|
if((column.getEditor && column.getEditor()) || column.xtype === 'checkcolumn') {
|
|
return true;
|
|
}
|
|
*/
|
|
}
|
|
|
|
return false;
|
|
},
|
|
|
|
|
|
f_getColumn: function (columnID) {
|
|
var me = this, columns = me.f_getColumns();
|
|
|
|
for (var i = 0, count = columns.length; i < count; i++) {
|
|
var column = columns[i];
|
|
if (column.id === columnID) {
|
|
return column;
|
|
}
|
|
}
|
|
return undefined;
|
|
},
|
|
|
|
f_getRow: function (rowId) {
|
|
var me = this, store = me.getStore();
|
|
return store.getById(rowId);
|
|
},
|
|
|
|
f_getCellValue: function (rowId, columnId) {
|
|
var me = this;
|
|
|
|
var row = me.f_getRow(rowId);
|
|
if (row && row.data) {
|
|
return row.data[columnId];
|
|
}
|
|
|
|
return undefined;
|
|
},
|
|
|
|
f_updateCellValue: function (rowId, columnId, newvalue) {
|
|
var me = this;
|
|
|
|
var row = me.f_getRow(rowId);
|
|
if (row && row.set) {
|
|
row.set(columnId, newvalue);
|
|
}
|
|
},
|
|
|
|
|
|
/*
|
|
// 获取用户修改的单元格值
|
|
f_getModifiedData: function () {
|
|
var me = this, i, j, count, columns = this.f_getColumns();
|
|
|
|
// 内存分页,特殊处理
|
|
var originalIndexPlus = 0;
|
|
var pagingBar = me.f_getPaging();
|
|
if (pagingBar && !pagingBar.f_databasePaging) {
|
|
originalIndexPlus = pagingBar.f_pageIndex * pagingBar.f_pageSize;
|
|
}
|
|
|
|
var modifiedRows = [];
|
|
var store = this.getStore();
|
|
var modifiedRecords = store.getModifiedRecords();
|
|
var rowIndex, rowData, newData, modifiedRecord, recordID, rowIndexOriginal;
|
|
for (i = 0, count = modifiedRecords.length; i < count; i++) {
|
|
modifiedRecord = modifiedRecords[i];
|
|
recordID = modifiedRecord.id;
|
|
rowIndex = store.indexOf(modifiedRecord);
|
|
rowData = modifiedRecord.data;
|
|
if (rowIndex < 0) {
|
|
continue;
|
|
}
|
|
|
|
// 本行数据在原始数据集合中的行索引
|
|
rowIndexOriginal = Ext.Array.indexOf(this.f_recordIDs, recordID);
|
|
if (rowIndexOriginal < 0) {
|
|
var newRowData = {};
|
|
// 删除那些不能编辑的列
|
|
for (var columnID in rowData) {
|
|
if (this.f_columnEditable(columnID)) {
|
|
//delete rowData[columnID];
|
|
var rowDataColumn = rowData[columnID];
|
|
// 如果是日期对象,则转化为字符串
|
|
if (F.util.isDate(rowDataColumn)) {
|
|
rowDataColumn = F.util.resolveGridDateToString(me.f_fields, columnID, rowDataColumn);
|
|
}
|
|
newRowData[columnID] = rowDataColumn;
|
|
}
|
|
}
|
|
// 新增数据行
|
|
modifiedRows.push([rowIndex, -1, newRowData]);
|
|
} else {
|
|
var rowModifiedObj = {};
|
|
for (var columnID in modifiedRecord.modified) {
|
|
if (this.f_columnEditable(columnID)) {
|
|
newData = rowData[columnID];
|
|
// 如果是日期对象,则转化为字符串
|
|
if (F.util.isDate(newData)) {
|
|
newData = F.util.resolveGridDateToString(me.f_fields, columnID, newData);
|
|
}
|
|
rowModifiedObj[columnID] = newData;
|
|
}
|
|
}
|
|
// 修改现有数据行
|
|
modifiedRows.push([rowIndex, rowIndexOriginal + originalIndexPlus, rowModifiedObj]);
|
|
}
|
|
}
|
|
|
|
// 结果按照 rowIndex 升序排序
|
|
return modifiedRows.sort(function (a, b) { return a[0] - b[0]; });
|
|
},
|
|
*/
|
|
|
|
// 获取用户修改的单元格值
|
|
f_getModifiedData: function () {
|
|
var me = this, i, j, count, columns = me.f_getColumns();
|
|
|
|
// 内存分页,特殊处理
|
|
var originalIndexPlus = 0;
|
|
var pagingBar = me.f_getPaging();
|
|
if (pagingBar && !pagingBar.f_databasePaging) {
|
|
originalIndexPlus = pagingBar.f_pageIndex * pagingBar.f_pageSize;
|
|
}
|
|
|
|
var modifiedRows = [];
|
|
var store = me.getStore();
|
|
var modifiedRecords = store.getModifiedRecords();
|
|
for (i = 0, count = modifiedRecords.length; i < count; i++) {
|
|
var modifiedRecord = modifiedRecords[i];
|
|
var recordID = modifiedRecord.id;
|
|
var rowId = modifiedRecord.getId(); // getId() is not the same as id property
|
|
var rowIndex = store.indexOf(modifiedRecord);
|
|
var rowData = modifiedRecord.data;
|
|
if (rowIndex < 0) {
|
|
continue;
|
|
}
|
|
|
|
// 本行数据在原始数据集合中的行索引
|
|
var rowIndexOriginal = Ext.Array.indexOf(me.f_recordIDs, recordID);
|
|
if (rowIndexOriginal < 0) {
|
|
var newRowData = {};
|
|
//for (var columnID in rowData) {
|
|
Ext.Object.each(rowData, function (columnID, value) {
|
|
//if (me.f_columnEditable(columnID)) {
|
|
//delete rowData[columnID];
|
|
var column = me.f_getColumn(columnID);
|
|
if (column && (column.f_columnType === 'rendercheckfield' || column.f_columnType === 'renderfield')) {
|
|
var newData = rowData[columnID];
|
|
// 如果是日期对象,则转化为字符串
|
|
if (F.util.isDate(newData)) {
|
|
newData = F.util.resolveGridDateToString(me.f_fields, columnID, newData);
|
|
}
|
|
newRowData[columnID] = newData;
|
|
}
|
|
//}
|
|
});
|
|
// 新增数据行
|
|
//modifiedRows.push([rowIndex, -1, newRowData]);
|
|
modifiedRows.push({
|
|
index: rowIndex,
|
|
originalIndex: -1,
|
|
id: rowId,
|
|
values: newRowData,
|
|
status: 'newadded'
|
|
});
|
|
} else {
|
|
var rowModifiedObj = {};
|
|
Ext.Object.each(modifiedRecord.modified, function (columnID, value) {
|
|
//for (var columnID in modifiedRecord.modified) {
|
|
// 不删除非可编辑列,比如[总成绩(不可编辑)]列不可编辑,但是可以通过代码更改
|
|
//if (me.f_columnEditable(columnID)) {
|
|
var newData = rowData[columnID];
|
|
// 如果是日期对象,则转化为字符串
|
|
if (F.util.isDate(newData)) {
|
|
newData = F.util.resolveGridDateToString(me.f_fields, columnID, newData);
|
|
}
|
|
rowModifiedObj[columnID] = newData;
|
|
//}
|
|
});
|
|
// 修改现有数据行
|
|
//modifiedRows.push([rowIndex, rowIndexOriginal + originalIndexPlus, rowModifiedObj]);
|
|
modifiedRows.push({
|
|
index: rowIndex,
|
|
originalIndex: rowIndexOriginal + originalIndexPlus,
|
|
id: rowId,
|
|
values: rowModifiedObj,
|
|
status: 'modified'
|
|
});
|
|
}
|
|
}
|
|
|
|
// 删除的行
|
|
//modifiedRows = modifiedRows.concat(me.f_getDeletedRows());
|
|
var removedRecords = store.getRemovedRecords();
|
|
Ext.Array.each(removedRecords, function (record, index) {
|
|
var recordOriginalIndex = Ext.Array.indexOf(me.f_recordIDs, record.id);
|
|
modifiedRows.push({
|
|
index: -1,
|
|
originalIndex: recordOriginalIndex + originalIndexPlus,
|
|
id: record.getId(),
|
|
status: 'deleted'
|
|
});
|
|
});
|
|
|
|
// 结果按照 originalIndex 升序排序
|
|
return modifiedRows.sort(function (a, b) { return a.originalIndex - b.originalIndex; });
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
|
|
if (Ext.tree.Panel) {
|
|
Ext.override(Ext.tree.Panel, {
|
|
|
|
f_loadData: function () {
|
|
var datas = this.f_state['F_Nodes'];
|
|
var nodes = this.f_tranformData(datas);
|
|
var root = this.getRootNode();
|
|
if (root) {
|
|
root.removeAll();
|
|
}
|
|
this.setRootNode({
|
|
//id: this.id + '_root',
|
|
expanded: true,
|
|
children: nodes
|
|
});
|
|
},
|
|
|
|
f_tranformData: function (datas) {
|
|
var that = this, i = 0, nodes = [];
|
|
for (i = 0; i < datas.length; i++) {
|
|
var data = datas[i], node = {};
|
|
|
|
// 0 - Text
|
|
// 1 - Leaf
|
|
// 2 - NodeID
|
|
// 3 - Enabled
|
|
// 4 - EnableCheckBox
|
|
// 5 - Checked
|
|
// 6 - Expanded
|
|
// 7 - NavigateUrl
|
|
// 8 - Target
|
|
// 9 - href
|
|
// 10 - Icon
|
|
// 11 - IconUrl
|
|
// 12 - iconUrl
|
|
// 13 - ToolTip
|
|
// 14 - OnClientClick
|
|
// 15 - EnableClickEvent
|
|
// 16 - CommandName
|
|
// 17 - CommandArgument
|
|
|
|
// 18 - EnableCheckEvent
|
|
// 19 - EnableExpandEvent
|
|
// 20 - EnableCollapseEvent
|
|
|
|
// 21 - CssClass
|
|
|
|
// 22 - Nodes
|
|
node.text = data[0];
|
|
node.leaf = !!data[1];
|
|
node.id = data[2];
|
|
node.disabled = !data[3];
|
|
if (!!data[4]) {
|
|
// node.checked === undefined, no checkbox
|
|
node.checked = !!data[5];
|
|
}
|
|
if (!data[1]) {
|
|
node.expanded = !!data[6];
|
|
}
|
|
if (data[9]) {
|
|
node.href = data[9];
|
|
node.hrefTarget = data[8];
|
|
}
|
|
if (data[12]) {
|
|
node.icon = data[12];
|
|
}
|
|
node.qtip = data[13];
|
|
|
|
if (data[14]) {
|
|
node.f_clientclick = data[14];
|
|
}
|
|
node.f_enableclickevent = !!data[15];
|
|
node.f_commandname = data[16];
|
|
node.f_commandargument = data[17];
|
|
|
|
node.f_enablecheckevent = !!data[18];
|
|
|
|
node.f_enableexpandevent = !!data[19];
|
|
node.f_enablecollapseevent = !!data[20];
|
|
|
|
if (data[21]) {
|
|
node.cls = data[21];
|
|
}
|
|
|
|
if (data[22] && data[22].length > 0) {
|
|
node.children = that.f_tranformData(data[22]);
|
|
}
|
|
|
|
nodes.push(node);
|
|
}
|
|
return nodes;
|
|
},
|
|
|
|
f_getExpandedNodes: function (nodes) {
|
|
var i = 0, that = this, expandedNodes = [];
|
|
|
|
for (; i < nodes.length; i++) {
|
|
var node = nodes[i];
|
|
if (node.isExpanded()) {
|
|
expandedNodes.push(node.getId());
|
|
}
|
|
if (node.hasChildNodes()) {
|
|
expandedNodes = expandedNodes.concat(that.f_getExpandedNodes(node.childNodes));
|
|
}
|
|
}
|
|
|
|
return expandedNodes;
|
|
},
|
|
|
|
f_getCheckedNodes: function () {
|
|
var checkedIDs = [], checkedArray = this.getChecked();
|
|
Ext.Array.each(checkedArray, function (node, index) {
|
|
checkedIDs.push(node.getId());
|
|
});
|
|
return checkedIDs;
|
|
},
|
|
|
|
f_getSelectedNodes: function () {
|
|
var selectedNodeIDs = [];
|
|
var sm = this.getSelectionModel();
|
|
if (sm.getSelection) {
|
|
var selection = sm.getSelection();
|
|
|
|
Ext.Array.each(selection, function (node, index) {
|
|
selectedNodeIDs.push(node.getId());
|
|
});
|
|
}
|
|
|
|
return selectedNodeIDs;
|
|
},
|
|
|
|
f_selectNodes: function () {
|
|
var nodeIDs = this.f_state['SelectedNodeIDArray'] || [];
|
|
var model = this.getSelectionModel(), store = this.getStore(), nodes = [], node;
|
|
Ext.Array.each(nodeIDs, function (nodeID, index) {
|
|
node = store.getNodeById(nodeID);
|
|
if (node) {
|
|
nodes.push(node);
|
|
}
|
|
});
|
|
model.deselectAll(true);
|
|
model.select(nodes);
|
|
}
|
|
|
|
|
|
});
|
|
}
|
|
|
|
|
|
if (Ext.PagingToolbar) {
|
|
// We don't use this Class in current version.
|
|
Ext.override(Ext.PagingToolbar, {
|
|
|
|
f_hideRefresh: function () {
|
|
var index = this.items.indexOf(this.refresh);
|
|
this.items.get(index - 1).hide();
|
|
this.refresh.hide();
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
|
|
if (Ext.tab.Panel) {
|
|
Ext.override(Ext.tab.Panel, {
|
|
|
|
f_autoPostBackTabsContains: function (tabId) {
|
|
var tabs = this.f_state['F_AutoPostBackTabs'];
|
|
return tabs.indexOf(tabId) !== -1;
|
|
},
|
|
|
|
f_setActiveTab: function () {
|
|
var tabIndex = this.f_state['ActiveTabIndex'];
|
|
this.setActiveTab(tabIndex);
|
|
},
|
|
|
|
f_getActiveTabIndex: function () {
|
|
return this.items.indexOf(this.getActiveTab());
|
|
},
|
|
|
|
/*
|
|
activateNextTab: function (c) {
|
|
if (c == this.activeTab) {
|
|
var next = this.stack.next();
|
|
if (next) {
|
|
this.setActiveTab(next);
|
|
}
|
|
if (next = this.items.find(function (t) { return t.tabEl.style.display !== 'none'; })) {
|
|
// Find the first visible tab and set it active tab.
|
|
this.setActiveTab(next);
|
|
} else {
|
|
this.setActiveTab(null);
|
|
}
|
|
}
|
|
},
|
|
*/
|
|
|
|
hideTab: function (tabId) {
|
|
var tab = F(tabId).tab;
|
|
if (tab) {
|
|
tab.hide();
|
|
}
|
|
},
|
|
|
|
showTab: function (tabId) {
|
|
var tab = F(tabId).tab;
|
|
if (tab) {
|
|
tab.show();
|
|
}
|
|
},
|
|
|
|
addTab: function (id, url, title, closable) {
|
|
var options = {
|
|
'cls': 'f-tab'
|
|
}, tab;
|
|
if (typeof (id) === 'string') {
|
|
Ext.apply(options, {
|
|
'id': id,
|
|
'title': title,
|
|
'closable': closable,
|
|
'url': url
|
|
});
|
|
} else {
|
|
// 如果id不是字符串,则id为对象并且只有一个参数
|
|
Ext.apply(options, id);
|
|
}
|
|
|
|
tab = this.getTab(options.id);
|
|
if (!tab) {
|
|
Ext.apply(options, {
|
|
'f_dynamic_added_tab': true,
|
|
'html': '<iframe id="' + options.id + '" name="' + options.id + '" src="' + options.url + '" frameborder="0" style="height:100%;width:100%;overflow:auto;"\></iframe\>'
|
|
});
|
|
tab = this.add(options);
|
|
}
|
|
|
|
this.setActiveTab(tab);
|
|
|
|
return tab;
|
|
},
|
|
|
|
getTab: function (tabId) {
|
|
return F(tabId);
|
|
},
|
|
|
|
removeTab: function (tabId) {
|
|
this.remove(tabId);
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
if (Ext.WindowManager) {
|
|
|
|
Ext.override(Ext.WindowManager, {
|
|
|
|
// 确保窗体的遮罩层覆盖整个窗口
|
|
getMaskBox: function () {
|
|
this.mask.maskTarget = Ext.getBody();
|
|
return this.callParent(arguments);
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
if (Ext.window.Window) {
|
|
|
|
Ext.override(Ext.window.Window, {
|
|
/*
|
|
hide: function () {
|
|
this.callParent(arguments);
|
|
if (this.modal) {
|
|
Ext.select('.x-mask').setStyle({ top: 0, left: 0, width: '100%', height: '100%' });
|
|
}
|
|
},
|
|
|
|
show: function(){
|
|
this.callParent(arguments);
|
|
if (this.modal) {
|
|
Ext.select('.x-mask').setStyle({ top: 0, left: 0, width: '100%', height: '100%' });
|
|
}
|
|
},
|
|
*/
|
|
|
|
// @private
|
|
onWindowResize: function () {
|
|
var me = this;
|
|
if (me.maximized) {
|
|
// 改变浏览器大小可以自动调整窗体控件的大小(窗体控件最大化时)
|
|
F.wnd.fixMaximize(me);
|
|
} else {
|
|
me.callParent();
|
|
}
|
|
},
|
|
|
|
/*
|
|
bof_hide: function () {
|
|
this.f_hide();
|
|
},
|
|
bof_hide_refresh: function () {
|
|
this.f_hide_refresh();
|
|
},
|
|
bof_hide_postback: function (argument) {
|
|
this.f_hide_postback(argument);
|
|
},
|
|
bof_show: function (iframeUrl, windowTitle) {
|
|
this.f_show(iframeUrl, windowTitle);
|
|
},
|
|
*/
|
|
|
|
f_setWidth: function () {
|
|
var panel = F.wnd.getGhostPanel(this);
|
|
panel.setWidth(this.f_state['Width']);
|
|
},
|
|
|
|
f_setHeight: function () {
|
|
var panel = F.wnd.getGhostPanel(this);
|
|
panel.setHeight(this.f_state['Height']);
|
|
},
|
|
|
|
f_setTitle: function () {
|
|
var panel = F.wnd.getGhostPanel(this);
|
|
panel.setTitle(this.f_state['Title']);
|
|
},
|
|
|
|
f_hide: function () {
|
|
F.wnd.hide(this, this.f_iframe, this.id + '_Hidden');
|
|
},
|
|
f_hide_refresh: function () {
|
|
this.f_hide();
|
|
window.location.reload();
|
|
},
|
|
f_hide_postback: function (argument) {
|
|
var me = this;
|
|
me.f_hide();
|
|
|
|
if (me.f_property_enable_ajax === false) {
|
|
F.controlEnableAjax = false;
|
|
}
|
|
|
|
// 如果argument为undefined,则传入 __doPostBack 的 argument 应该为空字符串
|
|
argument = argument || '';
|
|
__doPostBack(me.name, 'Close$' + argument);
|
|
},
|
|
f_hide_executescript: function (scripts) {
|
|
var me = this;
|
|
me.f_hide();
|
|
|
|
if (scripts) {
|
|
with (window) {
|
|
new Function(scripts)();
|
|
}
|
|
}
|
|
},
|
|
f_show: function (iframeUrl, windowTitle, width, height) {
|
|
var me = this;
|
|
if (typeof (iframeUrl) === 'undefined') {
|
|
iframeUrl = me.f_iframe_url;
|
|
}
|
|
if (typeof (windowTitle) === 'undefined') {
|
|
windowTitle = me.title;
|
|
}
|
|
F.wnd.show(me, iframeUrl, windowTitle, me.f_property_left, me.f_property_top, me.f_property_position, me.id + '_Hidden', width, height);
|
|
},
|
|
|
|
f_maximize: function () {
|
|
F.wnd.maximize(this);
|
|
},
|
|
f_minimize: function () {
|
|
F.wnd.minimize(this);
|
|
},
|
|
f_restore: function () {
|
|
F.wnd.restore(this);
|
|
}
|
|
|
|
|
|
|
|
});
|
|
}
|
|
|
|
|
|
|
|
if (Ext.grid.plugin.RowExpander) {
|
|
Ext.override(Ext.grid.plugin.RowExpander, {
|
|
|
|
// 将行扩展列的 td CSS类改为 x-grid-cell-row-expander
|
|
getHeaderConfig: function () {
|
|
var config = this.callParent(arguments);
|
|
config.tdCls = Ext.baseCSSPrefix + 'grid-cell-row-expander';
|
|
return config;
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
// 修正IE7下,窗口出现滚动条时,点击Window控件标题栏有时node为null的问题
|
|
/*
|
|
if (Ext.dd.DragDrop) {
|
|
F.originalIsValidHandleChild = Ext.dd.DragDrop.prototype.isValidHandleChild;
|
|
Ext.dd.DragDrop.prototype.isValidHandleChild = function (node) {
|
|
if (!node || !node.nodeName) {
|
|
return false;
|
|
}
|
|
return F.originalIsValidHandleChild.apply(this, [node]);
|
|
};
|
|
}
|
|
*/
|
|
|
|
|
|
// 修正在IE下,Grid的模版列中出现文本输入框或者下拉列表时,第一次不能选中的问题
|
|
// 已经有网友发现这个问题:http://www.sencha.com/forum/archive/index.php/t-49653.html
|
|
// This is what caused my self-rendered-Html-Elements to "flicker" as described in my other thread.
|
|
// The Dropdown receives the Click, opens and stays open for the Millisecond until
|
|
// Ext calls back and gives focus to the Cell, causing my Drop-Down to close again.
|
|
/*
|
|
if (Ext.grid.GridPanel) {
|
|
Ext.grid.GridView.prototype.focusCell = function (row, col, hscroll) {
|
|
this.syncFocusEl(this.ensureVisible(row, col, hscroll));
|
|
|
|
var focusEl = this.focusEl;
|
|
|
|
focusEl.focus();
|
|
};
|
|
}
|
|
*/
|
|
|
|
// 修正Chrome下多表头样式错位
|
|
// 增加 !Ext.isChrome 的判断,在Chrome下DIV的宽度不包括边框的宽度
|
|
/*
|
|
if (Ext.ux.grid && Ext.ux.grid.ColumnHeaderGroup) {
|
|
Ext.ux.grid.ColumnHeaderGroup.prototype.getGroupStyle = function (group, gcol) {
|
|
var width = 0, hidden = true;
|
|
for (var i = gcol, len = gcol + group.colspan; i < len; i++) {
|
|
if (!this.cm.isHidden(i)) {
|
|
var cw = this.cm.getColumnWidth(i);
|
|
if (typeof cw == 'number') {
|
|
width += cw;
|
|
}
|
|
hidden = false;
|
|
}
|
|
}
|
|
return {
|
|
width: (Ext.isBorderBox || (Ext.isWebKit && !Ext.isSafari2 && !Ext.isChrome) ? width : Math.max(width - this.borderWidth, 0)) + 'px',
|
|
hidden: hidden
|
|
};
|
|
};
|
|
}
|
|
*/
|
|
|
|
|
|
// enableTextSelection: true --> Uncaught TypeError: Cannot call method 'getVisibleIndex' of undefined
|
|
// https://www.sencha.com/forum/showthread.php?265507-Uncaught-TypeError-Cannot-call-method-getVisibleIndex-of-undefined.-Upgrade-issues
|
|
Ext.override(Ext.selection.CellModel, {
|
|
|
|
onMouseDown: function (view, cell, cellIndex, record, row, recordIndex, e) {
|
|
|
|
// Added - Change cellIndex value
|
|
if (view.enableTextSelection && cellIndex === -1) {
|
|
cellIndex = cell.cellIndex;
|
|
}
|
|
|
|
// Record index will be -1 if the clicked record is a metadata record and not selectable
|
|
if (recordIndex !== -1) {
|
|
this.setCurrentPosition({
|
|
view: view,
|
|
row: row,
|
|
column: cellIndex
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
(function () {
|
|
|
|
// 修正IE7/IE8下Date.parse('2015-10-01')出错的问题
|
|
// http://jibbering.com/faq/#parseDate
|
|
function parseISO8601(dateStr) {
|
|
var isoExp = /(\d{2,4})-(\d\d?)-(\d\d?)/,
|
|
date = new Date(NaN), month,
|
|
parts = isoExp.exec(dateStr);
|
|
|
|
if (parts) {
|
|
month = +parts[2];
|
|
date.setFullYear(parts[1], month - 1, parts[3]);
|
|
if (month != date.getMonth() + 1) {
|
|
date.setTime(NaN);
|
|
}
|
|
}
|
|
return date;
|
|
}
|
|
|
|
var originalParse = Date.parse;
|
|
Date.parse = function (dateStr) {
|
|
var date = originalParse(dateStr);
|
|
if (isNaN(date)) {
|
|
date = parseISO8601(dateStr);
|
|
}
|
|
return date;
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Ext.form.field.ComboBox) {
|
|
var originalComboSetValue = Ext.form.field.ComboBox.prototype.setValue;
|
|
Ext.form.field.ComboBox.prototype.setValue = function (value, doSelect) {
|
|
// value可能是数字(可编辑单元格,列的FieldType可能是Int)
|
|
if (typeof (value) === 'number' || typeof (value) === 'boolean') {
|
|
value += '';
|
|
}
|
|
return originalComboSetValue.apply(this, [value, doSelect]);
|
|
};
|
|
}
|
|
|
|
|
|
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(function() {
|
|
|
|
function getParentIndex(levels, level, index) {
|
|
if (level > 0) {
|
|
for (var i = index - 1; i >= 0; i--) {
|
|
if (levels[i] == level - 1) {
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
function hasLittleBrother(levels, level, index) {
|
|
if (index < levels.length - 1) {
|
|
for (var i = index + 1; i < levels.length; i++) {
|
|
if (levels[i] == level) {
|
|
return true;
|
|
} else if (levels[i] < level) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function getParentTempData(tempdatas, tempdata, prefixIndex) {
|
|
for (var i = 0; i < prefixIndex - 1; i++) {
|
|
tempdata = tempdatas[tempdata.parentIndex];
|
|
}
|
|
return tempdata;
|
|
}
|
|
|
|
function getPrefixInner(tempdatas, tempdata, prefixIndex) {
|
|
// If level = 3, then prefixIndex array will be: [3, 2, 1]
|
|
// prefixIndex === 1 will always present the nearest prefix next to the Text.
|
|
if (prefixIndex === 1) {
|
|
if (tempdata.littleBrother) {
|
|
return '<div class="x-elbow"></div>';
|
|
}
|
|
else {
|
|
return '<div class="x-elbow-end"></div>';
|
|
}
|
|
} else {
|
|
var parentdata = getParentTempData(tempdatas, tempdata, prefixIndex);
|
|
if (parentdata.littleBrother) {
|
|
return '<div class="x-elbow-line"></div>';
|
|
}
|
|
else {
|
|
return '<div class="x-elbow-empty"></div>';
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
function getPrefix(tempdatas, index) {
|
|
var tempdata = tempdatas[index];
|
|
var level = tempdata.level;
|
|
var prefix = [];
|
|
for (var i = level; i > 0; i--) {
|
|
prefix.push(getPrefixInner(tempdatas, tempdata, i));
|
|
}
|
|
return prefix.join('');
|
|
}
|
|
|
|
F.simulateTree = {
|
|
|
|
transform: function(datas) {
|
|
if (!datas.length || datas[0].length < 4) {
|
|
return datas;
|
|
}
|
|
|
|
//// store: new Ext.data.ArrayStore({ fields: ['value', 'text', 'enabled', 'prefix'] })
|
|
//// Sample data:
|
|
//[
|
|
// ["0", "jQuery", 0, 0],
|
|
// ["1", "Core", 0, 1],
|
|
// ["2", "Selectors", 0, 1],
|
|
// ["3", "Basic Filters", 1, 2],
|
|
// ["4", "Content Filters", 1, 2],
|
|
// ["41", "Contains", 1, 3],
|
|
// ["5", "Attribute Filters", 1, 2],
|
|
// ["6", "Traversing", 1, 1],
|
|
// ["7", "Filtering", 1, 2],
|
|
// ["8", "Finding", 1, 2],
|
|
// ["9", "Events", 0, 1],
|
|
// ["10", "Page Load", 1, 2],
|
|
// ["11", "Event Handling", 1, 2],
|
|
// ["12", "Interaction Helpers", 1, 2],
|
|
// ["13", "Ajax", 1, 1]
|
|
//]
|
|
var levels = [];
|
|
Ext.Array.each(datas, function (data, index) {
|
|
levels.push(data[3]);
|
|
});
|
|
|
|
var tempdatas = [];
|
|
Ext.Array.each(levels, function (level, index) {
|
|
tempdatas.push({
|
|
'level': level,
|
|
'parentIndex': getParentIndex(levels, level, index),
|
|
'littleBrother': hasLittleBrother(levels, level, index)
|
|
});
|
|
});
|
|
|
|
var newdatas = [];
|
|
Ext.Array.each(datas, function (data, index) {
|
|
newdatas.push([data[0], data[1], data[2], getPrefix(tempdatas, index)]);
|
|
});
|
|
return newdatas;
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
})();
|
|
(function () {
|
|
|
|
var ExtF = Ext.util.Format;
|
|
|
|
F.format = {
|
|
|
|
capitalize: ExtF.capitalize,
|
|
|
|
dateRenderer: ExtF.dateRenderer,
|
|
|
|
ellipsisRenderer: function (length) {
|
|
return function (value) {
|
|
return ExtF.ellipsis(value, length, false);
|
|
};
|
|
},
|
|
|
|
fileSize: ExtF.fileSize,
|
|
|
|
htmlEncode: ExtF.htmlEncode,
|
|
|
|
htmlDecode: ExtF.htmlDecode,
|
|
|
|
lowercase: ExtF.lowercase,
|
|
|
|
uppercase: ExtF.uppercase,
|
|
|
|
nl2br: ExtF.nl2br,
|
|
|
|
//number: ExtF.numberRenderer,
|
|
|
|
stripScripts: ExtF.stripScripts,
|
|
|
|
stripTags: ExtF.stripTags,
|
|
|
|
trim: ExtF.trim
|
|
|
|
//usMoney: ExtF.usMoney
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
})();
|
|
Ext.define('Ext.ux.FormViewport', {
|
|
extend: 'Ext.container.Container',
|
|
alias: 'widget.formviewport',
|
|
|
|
isViewport: true,
|
|
|
|
ariaRole: 'application',
|
|
|
|
preserveElOnDestroy: true,
|
|
|
|
viewportCls: Ext.baseCSSPrefix + 'viewport',
|
|
|
|
initComponent: function () {
|
|
var me = this,
|
|
html = document.body.parentNode,
|
|
el = me.el = Ext.getBody();
|
|
|
|
/////��ʼ �ĵ�һ/////////////////////////////
|
|
el = me.el = Ext.get(me.renderTo);
|
|
var body = Ext.getBody();
|
|
/////���� �ĵ�һ/////////////////////////////
|
|
|
|
|
|
// Get the DOM disruption over with before the Viewport renders and begins a layout
|
|
Ext.getScrollbarSize();
|
|
|
|
// Clear any dimensions, we will size later on
|
|
me.width = me.height = undefined;
|
|
|
|
me.callParent(arguments);
|
|
Ext.fly(html).addCls(me.viewportCls);
|
|
if (me.autoScroll) {
|
|
Ext.fly(html).setStyle(me.getOverflowStyle());
|
|
delete me.autoScroll;
|
|
}
|
|
el.setHeight = el.setWidth = Ext.emptyFn;
|
|
el.dom.scroll = 'no';
|
|
me.allowDomMove = false;
|
|
me.renderTo = me.el;
|
|
|
|
},
|
|
|
|
// override here to prevent an extraneous warning
|
|
applyTargetCls: function (targetCls) {
|
|
this.el.addCls(targetCls);
|
|
},
|
|
|
|
onRender: function () {
|
|
var me = this;
|
|
|
|
me.callParent(arguments);
|
|
|
|
// Important to start life as the proper size (to avoid extra layouts)
|
|
// But after render so that the size is not stamped into the body
|
|
me.width = Ext.Element.getViewportWidth();
|
|
me.height = Ext.Element.getViewportHeight();
|
|
},
|
|
|
|
afterFirstLayout: function () {
|
|
var me = this;
|
|
|
|
me.callParent(arguments);
|
|
setTimeout(function () {
|
|
Ext.EventManager.onWindowResize(me.fireResize, me);
|
|
}, 1);
|
|
},
|
|
|
|
fireResize: function (width, height) {
|
|
// In IE we can get resize events that have our current size, so we ignore them
|
|
// to avoid the useless layout...
|
|
if (width != this.width || height != this.height) {
|
|
this.setSize(width, height);
|
|
}
|
|
},
|
|
|
|
initHierarchyState: function (hierarchyState) {
|
|
this.callParent([this.hierarchyState = Ext.rootHierarchyState]);
|
|
},
|
|
|
|
beforeDestroy: function () {
|
|
var me = this;
|
|
|
|
me.removeUIFromElement();
|
|
me.el.removeCls(me.baseCls);
|
|
Ext.fly(document.body.parentNode).removeCls(me.viewportCls);
|
|
me.callParent();
|
|
}
|
|
|
|
});
|
|
|
|
|
|
Ext.define('Ext.ux.SimplePagingToolbar', {
|
|
extend: 'Ext.toolbar.Paging',
|
|
alias: 'widget.simplepagingtoolbar',
|
|
|
|
cls: 'x-toolbar-paging',
|
|
|
|
// Override parent
|
|
initComponent: function () {
|
|
var me = this;
|
|
|
|
me.store = Ext.Object.merge({}, me.store, {
|
|
getCount: function () {
|
|
return me.f_recordCount;
|
|
},
|
|
currentPage: me.f_pageIndex + 1
|
|
});
|
|
|
|
me.callParent();
|
|
},
|
|
|
|
// Override parent
|
|
getPagingItems: function() {
|
|
var items = this.callParent();
|
|
// Remove refresh and separator items.
|
|
return items.slice(0, items.length - 2);
|
|
},
|
|
|
|
// Override parent
|
|
getPageData: function () {
|
|
var fromRecord = 0, toRecord = 0;
|
|
if (this.f_databasePaging) {
|
|
fromRecord = (this.f_pageIndex * this.f_pageSize) + 1;
|
|
toRecord = fromRecord + this.f_pageSize - 1;
|
|
} else {
|
|
fromRecord = this.f_startRowIndex + 1;
|
|
toRecord = this.f_endRowIndex + 1;
|
|
}
|
|
if (toRecord > this.f_recordCount) {
|
|
toRecord = this.f_recordCount;
|
|
}
|
|
|
|
return {
|
|
total: this.f_recordCount,
|
|
currentPage: this.f_pageIndex + 1,
|
|
pageCount: this.f_pageCount <= 0 ? 1 : this.f_pageCount,
|
|
fromRecord: fromRecord,
|
|
toRecord: toRecord
|
|
};
|
|
},
|
|
|
|
f_update: function (configs) {
|
|
var me = this;
|
|
Ext.Object.merge(me, configs);
|
|
me.store.currentPage = me.f_pageIndex + 1;
|
|
|
|
|
|
// �Ƿ����˷�ҳ������Ҫ���¼��� f_startRowIndex �� f_endRowIndex
|
|
if (!me.f_databasePaging) {
|
|
var startRowIndex = me.f_pageSize * me.f_pageIndex;
|
|
var endRowIndex = (me.f_pageIndex + 1) * me.f_pageSize - 1;
|
|
if(endRowIndex > me.f_recordCount - 1) {
|
|
endRowIndex = me.f_recordCount - 1;
|
|
}
|
|
|
|
me.f_startRowIndex = startRowIndex;
|
|
me.f_endRowIndex = endRowIndex;
|
|
}
|
|
|
|
// v6.0.3������������ҳ��Ϣ������ʾ����ȷ��9097��
|
|
// onLoad����������getPageData�����õ�f_startRowIndex, f_endRowIndex��������Ҫ����ִ��onLoad
|
|
me.onLoad();
|
|
|
|
}
|
|
|
|
});
|
|
// feature idea to enable Ajax loading and then the content
|
|
// cache would actually make sense. Should we dictate that they use
|
|
// data or support raw html as well?
|
|
|
|
/**
|
|
* 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.
|
|
*
|
|
* **Note:** The {@link Ext.grid.plugin.RowExpander rowexpander} plugin and the rowbody
|
|
* feature are exclusive and cannot both be set on the same grid / tree.
|
|
*/
|
|
Ext.define('Ext.grid.plugin.RowExpander', {
|
|
extend: 'Ext.plugin.Abstract',
|
|
lockableScope: 'top',
|
|
|
|
requires: [
|
|
'Ext.grid.feature.RowBody'
|
|
],
|
|
|
|
alias: 'plugin.rowexpander',
|
|
|
|
/**
|
|
* @cfg {Number} [columnWidth=24]
|
|
* The width of the row expander column which contains the [+]/[-] icons to toggle row expansion.
|
|
*/
|
|
columnWidth: 24,
|
|
|
|
/**
|
|
* @cfg {Ext.XTemplate} rowBodyTpl
|
|
* An XTemplate which, when passed a record data object, produces HTML for the expanded row content.
|
|
*
|
|
* Note that if this plugin is applied to a lockable grid, the rowBodyTpl applies to the normal (unlocked) side.
|
|
* See {@link #lockedTpl}
|
|
*
|
|
*/
|
|
rowBodyTpl: null,
|
|
|
|
/**
|
|
* @cfg {Ext.XTemplate} [lockedTpl]
|
|
* An XTemplate which, when passed a record data object, produces HTML for the expanded row content *on the locked side of a lockable grid*.
|
|
*/
|
|
lockedTpl: null,
|
|
|
|
/**
|
|
* @cfg {Boolean} expandOnEnter
|
|
* This config is no longer supported. The Enter key initiated the grid's actinoable mode.
|
|
*/
|
|
|
|
/**
|
|
* @cfg {Boolean} expandOnDblClick
|
|
* `true` to toggle a row between expanded/collapsed when double clicked
|
|
* (defaults to `true`).
|
|
*/
|
|
expandOnDblClick: true,
|
|
|
|
/**
|
|
* @cfg {Boolean} selectRowOnExpand
|
|
* `true` to select a row when clicking on the expander icon
|
|
* (defaults to `false`).
|
|
*/
|
|
selectRowOnExpand: false,
|
|
|
|
/**
|
|
* @cfg {Boolean} scrollIntoViewOnExpand
|
|
* @since 6.2.0
|
|
* `true` to ensure that the full row expander body is visible when clicking on the expander icon
|
|
* (defaults to `true`)
|
|
*/
|
|
scrollIntoViewOnExpand: true,
|
|
|
|
/**
|
|
* @cfg {Number}
|
|
* The width of the Row Expander column header
|
|
*/
|
|
headerWidth: 24,
|
|
|
|
/**
|
|
* @cfg {Boolean} [bodyBefore=false]
|
|
* Configure as `true` to put the row expander body *before* the data row.
|
|
*
|
|
*/
|
|
bodyBefore: false,
|
|
|
|
rowBodyTrSelector: '.' + Ext.baseCSSPrefix + 'grid-rowbody-tr',
|
|
rowBodyHiddenCls: Ext.baseCSSPrefix + 'grid-row-body-hidden',
|
|
rowCollapsedCls: Ext.baseCSSPrefix + 'grid-row-collapsed',
|
|
|
|
addCollapsedCls: {
|
|
fn: function(out, values, parent) {
|
|
var me = this.rowExpander;
|
|
if (!me.recordsExpanded[values.record.internalId]) {
|
|
values.itemClasses.push(me.rowCollapsedCls);
|
|
}
|
|
this.nextTpl.applyOut(values, out, parent);
|
|
},
|
|
|
|
syncRowHeights: function(lockedItem, normalItem) {
|
|
this.rowExpander.syncRowHeights(lockedItem, normalItem);
|
|
},
|
|
|
|
// We need a high priority to get in ahead of the outerRowTpl
|
|
// so we can setup row data
|
|
priority: 20000
|
|
},
|
|
|
|
/**
|
|
* @event expandbody
|
|
* **Fired through the grid's View**
|
|
* @param {HTMLElement} rowNode The <tr> element which owns the expanded row.
|
|
* @param {Ext.data.Model} record The record providing the data.
|
|
* @param {HTMLElement} expandRow The <tr> element containing the expanded data.
|
|
*/
|
|
/**
|
|
* @event collapsebody
|
|
* **Fired through the grid's View.**
|
|
* @param {HTMLElement} rowNode The <tr> element which owns the expanded row.
|
|
* @param {Ext.data.Model} record The record providing the data.
|
|
* @param {HTMLElement} expandRow The <tr> element containing the expanded data.
|
|
*/
|
|
|
|
setCmp: function(grid) {
|
|
var me = this,
|
|
features;
|
|
|
|
me.callParent(arguments);
|
|
|
|
// Keep track of which record internalIds are expanded.
|
|
me.recordsExpanded = {};
|
|
// <debug>
|
|
if (!me.rowBodyTpl) {
|
|
Ext.raise("The 'rowBodyTpl' config is required and is not defined.");
|
|
}
|
|
// </debug>
|
|
|
|
me.rowBodyTpl = Ext.XTemplate.getTpl(me, 'rowBodyTpl');
|
|
features = me.getFeatureConfig(grid);
|
|
|
|
if (grid.features) {
|
|
grid.features = Ext.Array.push(features, grid.features);
|
|
} else {
|
|
grid.features = features;
|
|
}
|
|
// NOTE: features have to be added before init (before Table.initComponent)
|
|
},
|
|
|
|
/**
|
|
* @protected
|
|
* @return {Array} And array of Features or Feature config objects.
|
|
* Returns the array of Feature configurations needed to make the RowExpander work.
|
|
* May be overridden in a subclass to modify the returned array.
|
|
*/
|
|
getFeatureConfig: function(grid) {
|
|
var me = this,
|
|
features = [],
|
|
featuresCfg = {
|
|
ftype: 'rowbody',
|
|
rowExpander: me,
|
|
rowIdCls: me.rowIdCls,
|
|
bodyBefore: me.bodyBefore,
|
|
recordsExpanded: me.recordsExpanded,
|
|
rowBodyHiddenCls: me.rowBodyHiddenCls,
|
|
rowCollapsedCls: me.rowCollapsedCls,
|
|
setupRowData: me.getRowBodyFeatureData,
|
|
setup: me.setup
|
|
};
|
|
|
|
features.push(Ext.apply({
|
|
lockableScope: 'normal',
|
|
getRowBodyContents: me.getRowBodyContentsFn(me.rowBodyTpl)
|
|
}, featuresCfg));
|
|
|
|
// Locked side will need a copy to keep the two DOM structures symmetrical.
|
|
// A lockedTpl config is available to create content in locked side.
|
|
// The enableLocking flag is set early in Ext.panel.Table#initComponent if any columns are locked.
|
|
if (grid.enableLocking) {
|
|
features.push(Ext.apply({
|
|
lockableScope: 'locked',
|
|
getRowBodyContents: me.lockedTpl ? me.getRowBodyContentsFn(me.lockedTpl) : function() {return '';}
|
|
}, featuresCfg));
|
|
}
|
|
|
|
return features;
|
|
},
|
|
|
|
getRowBodyContentsFn: function(rowBodyTpl) {
|
|
var me = this;
|
|
return function (rowValues) {
|
|
rowBodyTpl.owner = me;
|
|
return rowBodyTpl.applyTemplate(rowValues.record.getData());
|
|
};
|
|
},
|
|
|
|
init: function(grid) {
|
|
var me = this,
|
|
// Plugin attaches to topmost grid if lockable
|
|
ownerLockable = grid.lockable && grid,
|
|
view, lockedView, normalView;
|
|
|
|
if (ownerLockable) {
|
|
me.lockedGrid = ownerLockable.lockedGrid;
|
|
me.normalGrid = ownerLockable.normalGrid;
|
|
lockedView = me.lockedView = me.lockedGrid.getView();
|
|
normalView = me.normalView = me.normalGrid.getView();
|
|
}
|
|
|
|
me.callParent(arguments);
|
|
me.grid = grid;
|
|
view = me.view = grid.getView();
|
|
|
|
// Bind to view for key and mouse events
|
|
me.bindView(view);
|
|
|
|
// If the owning grid is lockable, ensure the collapsed class is applied to the locked side by adding
|
|
// a row processor to both views.
|
|
if (ownerLockable) {
|
|
me.addExpander(me.lockedGrid.headerCt.items.getCount() ? me.lockedGrid : me.normalGrid);
|
|
|
|
// Add row processor which adds collapsed class.
|
|
// Ensure tpl and view can access this plugin via a "rowExpander" property.
|
|
lockedView.addRowTpl(me.addCollapsedCls).rowExpander =
|
|
normalView.addRowTpl(me.addCollapsedCls).rowExpander =
|
|
lockedView.rowExpander =
|
|
normalView.rowExpander = me;
|
|
|
|
// If our client grid part of a lockable grid, we listen to its ownerLockable's processcolumns
|
|
ownerLockable.mon(ownerLockable, {
|
|
processcolumns: me.onLockableProcessColumns,
|
|
lockcolumn: me.onColumnLock,
|
|
unlockcolumn: me.onColumnUnlock,
|
|
scope: me
|
|
});
|
|
}
|
|
// Add row processor which adds collapsed class
|
|
else {
|
|
// Ensure tpl and view can access this plugin
|
|
view.addRowTpl(me.addCollapsedCls).rowExpander =
|
|
view.rowExpander = me;
|
|
me.addExpander(grid);
|
|
grid.on('beforereconfigure', me.beforeReconfigure, me);
|
|
}
|
|
},
|
|
|
|
onItemAdd: function(newRecords, startIndex, newItems) {
|
|
var me = this,
|
|
ownerLockable = me.grid.lockable,
|
|
len = newItems.length,
|
|
record,
|
|
i;
|
|
|
|
// If any added items are expanded, we will need a syncRowHeights call on next layout
|
|
for (i = 0; i < len; i++) {
|
|
record = newRecords[i];
|
|
if (!record.isNonData && me.recordsExpanded[record.internalId]) {
|
|
ownerLockable && (me.grid.syncRowHeightOnNextLayout = true);
|
|
return;
|
|
}
|
|
}
|
|
},
|
|
|
|
beforeReconfigure: function(grid, store, columns, oldStore, oldColumns) {
|
|
var me = this;
|
|
|
|
if (me.viewListeners) {
|
|
me.viewListeners.destroy();
|
|
}
|
|
|
|
if (columns) {
|
|
me.expanderColumn = new Ext.grid.Column(me.getHeaderConfig());
|
|
columns.unshift(me.expanderColumn);
|
|
}
|
|
|
|
},
|
|
|
|
onLockableProcessColumns: function(lockable, lockedHeaders, normalHeaders) {
|
|
this.addExpander(lockedHeaders.length ? lockable.lockedGrid : lockable.normalGrid);
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* Inject the expander column into the correct grid.
|
|
*
|
|
* If we are expanding the normal side of a lockable grid, poke the column into the locked side if the locked side has columns
|
|
*/
|
|
addExpander: function(expanderGrid) {
|
|
var me = this,
|
|
selModel = expanderGrid.getSelectionModel(),
|
|
checkBoxPosition = selModel.injectCheckbox;
|
|
|
|
me.expanderColumn = expanderGrid.headerCt.insert(0, me.getHeaderConfig());
|
|
|
|
// If a CheckboxModel, and it's position is 0, it must now go at position one because this
|
|
// cell always gets in at position zero, and spans 2 columns.
|
|
if (checkBoxPosition === 0 || checkBoxPosition === 'first') {
|
|
checkBoxPosition = 1;
|
|
}
|
|
selModel.injectCheckbox = checkBoxPosition;
|
|
},
|
|
|
|
getRowBodyFeatureData: function(record, idx, rowValues) {
|
|
var me = this;
|
|
|
|
me.self.prototype.setupRowData.apply(me, arguments);
|
|
|
|
rowValues.rowBody = me.getRowBodyContents(rowValues);
|
|
rowValues.rowBodyCls = me.recordsExpanded[record.internalId] ? '' : me.rowBodyHiddenCls;
|
|
},
|
|
|
|
bindView: function(view) {
|
|
var me = this,
|
|
listeners = {
|
|
itemkeydown: me.onKeyDown,
|
|
scope: me
|
|
};
|
|
|
|
if (me.expandOnDblClick) {
|
|
listeners.itemdblclick = me.onDblClick;
|
|
}
|
|
if (me.grid.lockable) {
|
|
listeners.itemadd = me.onItemAdd;
|
|
}
|
|
view.on(listeners);
|
|
},
|
|
|
|
onKeyDown: function(view, record, row, rowIdx, e) {
|
|
var me = this,
|
|
key = e.getKey(),
|
|
pos = view.getNavigationModel().getPosition(),
|
|
isCollapsed;
|
|
|
|
if (pos) {
|
|
row = Ext.fly(row);
|
|
isCollapsed = row.hasCls(me.rowCollapsedCls);
|
|
|
|
// + key on collapsed or - key on expanded
|
|
if (((key === 107 || (key === 187 && e.shiftKey)) && isCollapsed) || ((key === 109 || key === 189) && !isCollapsed)) {
|
|
me.toggleRow(rowIdx, record);
|
|
}
|
|
}
|
|
},
|
|
|
|
onDblClick: function(view, record, row, rowIdx, e) {
|
|
this.toggleRow(rowIdx, record);
|
|
},
|
|
|
|
toggleRow: function(rowIdx, record) {
|
|
var me = this,
|
|
// If we are handling a lockable assembly,
|
|
// handle the normal view first
|
|
view = me.normalView || me.view,
|
|
fireView = view,
|
|
rowNode = view.getNode(rowIdx),
|
|
normalRow = Ext.fly(rowNode),
|
|
lockedRow,
|
|
nextBd = normalRow.down(me.rowBodyTrSelector, true),
|
|
wasCollapsed = normalRow.hasCls(me.rowCollapsedCls),
|
|
addOrRemoveCls = wasCollapsed ? 'removeCls' : 'addCls',
|
|
ownerLockable = me.grid.lockable && me.grid,
|
|
componentLayoutCounter;
|
|
|
|
normalRow[addOrRemoveCls](me.rowCollapsedCls);
|
|
Ext.fly(nextBd)[addOrRemoveCls](me.rowBodyHiddenCls);
|
|
me.recordsExpanded[record.internalId] = wasCollapsed;
|
|
|
|
Ext.suspendLayouts();
|
|
|
|
// Sync the collapsed/hidden classes on the locked side
|
|
if (ownerLockable) {
|
|
componentLayoutCounter = ownerLockable.componentLayoutCounter;
|
|
|
|
// It's the top level grid's LockingView that does the firing when there's a lockable assembly involved.
|
|
fireView = ownerLockable.getView();
|
|
|
|
// Only attempt to toggle lockable side if it is visible.
|
|
if (me.lockedGrid.isVisible()) {
|
|
|
|
view = me.lockedView;
|
|
|
|
// The other side must be thrown into the layout matrix so that
|
|
// row height syncing can be done. If it is collapsed but floated,
|
|
// it will not automatically be added to the layout when the top
|
|
// level grid layout calculates its layout children.
|
|
view.lockingPartner.updateLayout();
|
|
|
|
// Process the locked side.
|
|
lockedRow = Ext.fly(view.getNode(rowIdx));
|
|
// Just because the grid is locked, doesn't mean we'll necessarily have a locked row.
|
|
if (lockedRow) {
|
|
lockedRow[addOrRemoveCls](me.rowCollapsedCls);
|
|
|
|
// If there is a template for expander content in the locked side, toggle that side too
|
|
nextBd = lockedRow.down(me.rowBodyTrSelector, true);
|
|
Ext.fly(nextBd)[addOrRemoveCls](me.rowBodyHiddenCls);
|
|
}
|
|
}
|
|
// We're going to need a layout run to synchronize row heights
|
|
ownerLockable.syncRowHeightOnNextLayout = true;
|
|
}
|
|
|
|
fireView.fireEvent(wasCollapsed ? 'expandbody' : 'collapsebody', rowNode, record, nextBd);
|
|
view.refreshSize(true);
|
|
|
|
Ext.resumeLayouts(true);
|
|
|
|
if (me.scrollIntoViewOnExpand && wasCollapsed) {
|
|
me.grid.ensureVisible(rowIdx);
|
|
}
|
|
|
|
// The two sides are layout roots. The top grid will not have layed out.
|
|
// We must postprocess it now.
|
|
if (ownerLockable && ownerLockable.componentLayoutCounter === componentLayoutCounter) {
|
|
ownerLockable.syncLockableLayout();
|
|
}
|
|
},
|
|
|
|
// Called from TableLayout.finishedLayout
|
|
syncRowHeights: function(lockedItem, normalItem) {
|
|
var me = this,
|
|
lockedBd = Ext.fly(lockedItem).down(me.rowBodyTrSelector),
|
|
normalBd = Ext.fly(normalItem).down(me.rowBodyTrSelector),
|
|
lockedHeight,
|
|
normalHeight;
|
|
|
|
// If expanded, we have to ensure expander row heights are synched
|
|
if (normalBd.isVisible()) {
|
|
|
|
// If heights are different, expand the smallest one
|
|
if ((lockedHeight = lockedBd.getHeight()) !== (normalHeight = normalBd.getHeight())) {
|
|
if (lockedHeight > normalHeight) {
|
|
normalBd.setHeight(lockedHeight);
|
|
} else {
|
|
lockedBd.setHeight(normalHeight);
|
|
}
|
|
}
|
|
}
|
|
// When not expanded we do not control the heights
|
|
else {
|
|
lockedBd.dom.style.height = normalBd.dom.style.height = '';
|
|
}
|
|
},
|
|
|
|
onColumnUnlock: function(lockable, column) {
|
|
var me = this,
|
|
lockedColumns;
|
|
|
|
lockable = lockable || me.grid;
|
|
lockedColumns = lockable.lockedGrid.visibleColumnManager.getColumns();
|
|
|
|
// User has unlocked all columns and left only the expander column in the locked side.
|
|
if (lockedColumns.length === 1) {
|
|
lockable.normalGrid.removeCls(Ext.baseCSSPrefix + 'grid-hide-row-expander-spacer');
|
|
lockable.lockedGrid.addCls(Ext.baseCSSPrefix + 'grid-hide-row-expander-spacer');
|
|
if (lockedColumns[0] === me.expanderColumn) {
|
|
lockable.unlock(me.expanderColumn);
|
|
} else {
|
|
lockable.lock(me.expanderColumn, 0);
|
|
}
|
|
}
|
|
},
|
|
|
|
onColumnLock: function(lockable, column) {
|
|
var me = this,
|
|
lockedColumns;
|
|
|
|
lockable = lockable || me.grid;
|
|
lockedColumns = me.lockedGrid.visibleColumnManager.getColumns();
|
|
|
|
// This is the first column to move into the locked side.
|
|
// The expander column must follow it.
|
|
if (lockedColumns.length === 1) {
|
|
me.lockedGrid.headerCt.insert(0, me.expanderColumn);
|
|
lockable.normalGrid.addCls(Ext.baseCSSPrefix + 'grid-hide-row-expander-spacer');
|
|
lockable.lockedGrid.removeCls(Ext.baseCSSPrefix + 'grid-hide-row-expander-spacer');
|
|
}
|
|
},
|
|
|
|
getHeaderConfig: function() {
|
|
var me = this,
|
|
lockable = me.grid.lockable && me.grid;
|
|
|
|
return {
|
|
width: me.headerWidth,
|
|
ignoreExport: true,
|
|
lockable: false,
|
|
autoLock: true,
|
|
sortable: false,
|
|
resizable: false,
|
|
draggable: false,
|
|
hideable: false,
|
|
menuDisabled: true,
|
|
tdCls: Ext.baseCSSPrefix + 'grid-cell-special',
|
|
innerCls: Ext.baseCSSPrefix + 'grid-cell-inner-row-expander',
|
|
renderer: function() {
|
|
return '<div class="' + Ext.baseCSSPrefix + 'grid-row-expander" role="presentation" tabIndex="0"></div>';
|
|
},
|
|
processEvent: function(type, view, cell, rowIndex, cellIndex, e, record) {
|
|
var isTouch = e.pointerType === 'touch',
|
|
isExpanderClick = !!e.getTarget('.' + Ext.baseCSSPrefix + 'grid-row-expander');
|
|
|
|
if ((type === "click" && isExpanderClick) || (type === 'keydown' && e.getKey() === e.SPACE)) {
|
|
|
|
// Focus the cell on real touch tap.
|
|
// This is because the toggleRow saves and restores focus
|
|
// which may be elsewhere than clicked on causing a scroll jump.
|
|
if (isTouch) {
|
|
cell.focus();
|
|
}
|
|
me.toggleRow(rowIndex, record, e);
|
|
e.stopSelection = !me.selectRowOnExpand;
|
|
} else if (e.type === 'mousedown' && !isTouch && isExpanderClick) {
|
|
e.preventDefault();
|
|
}
|
|
},
|
|
|
|
// This column always migrates to the locked side if the locked side is visible.
|
|
// It has to report this correctly so that editors can position things correctly
|
|
isLocked: function() {
|
|
return lockable && (lockable.lockedGrid.isVisible() || this.locked);
|
|
},
|
|
|
|
// In an editor, this shows nothing.
|
|
editRenderer: function() {
|
|
return ' ';
|
|
}
|
|
};
|
|
}
|
|
});
|
|
/**
|
|
* @deprecated
|
|
* Ext.ux.RowExpander has been promoted to the core framework. Use
|
|
* {@link Ext.grid.plugin.RowExpander} instead. Ext.ux.RowExpander is now just an empty
|
|
* stub that extends Ext.grid.plugin.RowExpander for backward compatibility reasons.
|
|
*/
|
|
Ext.define('Ext.ux.RowExpander', {
|
|
extend: 'Ext.grid.plugin.RowExpander'
|
|
});/**
|
|
* Plugin for adding a close context menu to tabs. Note that the menu respects
|
|
* the closable configuration on the tab. As such, commands like remove others
|
|
* and remove all will not remove items that are not closable.
|
|
*/
|
|
Ext.define('Ext.ux.TabCloseMenu', {
|
|
extend: 'Ext.plugin.Abstract',
|
|
|
|
alias: 'plugin.tabclosemenu',
|
|
|
|
mixins: {
|
|
observable: 'Ext.util.Observable'
|
|
},
|
|
|
|
/**
|
|
* @cfg {String} closeTabText
|
|
* The text for closing the current tab.
|
|
*/
|
|
closeTabText: 'Close Tab',
|
|
|
|
/**
|
|
* @cfg {Boolean} showCloseOthers
|
|
* Indicates whether to show the 'Close Others' option.
|
|
*/
|
|
showCloseOthers: true,
|
|
|
|
/**
|
|
* @cfg {String} closeOthersTabsText
|
|
* The text for closing all tabs except the current one.
|
|
*/
|
|
closeOthersTabsText: 'Close Other Tabs',
|
|
|
|
/**
|
|
* @cfg {Boolean} showCloseAll
|
|
* Indicates whether to show the 'Close All' option.
|
|
*/
|
|
showCloseAll: true,
|
|
|
|
/**
|
|
* @cfg {String} closeAllTabsText
|
|
* The text for closing all tabs.
|
|
*/
|
|
closeAllTabsText: 'Close All Tabs',
|
|
|
|
/**
|
|
* @cfg {Array} extraItemsHead
|
|
* An array of additional context menu items to add to the front of the context menu.
|
|
*/
|
|
extraItemsHead: null,
|
|
|
|
/**
|
|
* @cfg {Array} extraItemsTail
|
|
* An array of additional context menu items to add to the end of the context menu.
|
|
*/
|
|
extraItemsTail: null,
|
|
|
|
//public
|
|
constructor: function (config) {
|
|
this.callParent([config]);
|
|
this.mixins.observable.constructor.call(this, config);
|
|
},
|
|
|
|
init : function(tabpanel){
|
|
this.tabPanel = tabpanel;
|
|
this.tabBar = tabpanel.down("tabbar");
|
|
|
|
this.mon(this.tabPanel, {
|
|
scope: this,
|
|
afterlayout: this.onAfterLayout,
|
|
single: true
|
|
});
|
|
},
|
|
|
|
onAfterLayout: function() {
|
|
this.mon(this.tabBar.el, {
|
|
scope: this,
|
|
contextmenu: this.onContextMenu,
|
|
delegate: '.x-tab'
|
|
});
|
|
},
|
|
|
|
destroy: function() {
|
|
Ext.destroy(this.menu);
|
|
this.callParent();
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
onContextMenu : function(event, target){
|
|
var me = this,
|
|
menu = me.createMenu(),
|
|
disableAll = true,
|
|
disableOthers = true,
|
|
tab = me.tabBar.getChildByElement(target),
|
|
index = me.tabBar.items.indexOf(tab);
|
|
|
|
me.item = me.tabPanel.getComponent(index);
|
|
menu.child('#close').setDisabled(!me.item.closable);
|
|
|
|
if (me.showCloseAll || me.showCloseOthers) {
|
|
me.tabPanel.items.each(function(item) {
|
|
if (item.closable) {
|
|
disableAll = false;
|
|
if (item !== me.item) {
|
|
disableOthers = false;
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
|
|
if (me.showCloseAll) {
|
|
menu.child('#closeAll').setDisabled(disableAll);
|
|
}
|
|
|
|
if (me.showCloseOthers) {
|
|
menu.child('#closeOthers').setDisabled(disableOthers);
|
|
}
|
|
}
|
|
|
|
event.preventDefault();
|
|
me.fireEvent('beforemenu', menu, me.item, me);
|
|
|
|
menu.showAt(event.getXY());
|
|
},
|
|
|
|
createMenu : function() {
|
|
var me = this;
|
|
|
|
if (!me.menu) {
|
|
var items = [{
|
|
itemId: 'close',
|
|
text: me.closeTabText,
|
|
scope: me,
|
|
handler: me.onClose
|
|
}];
|
|
|
|
if (me.showCloseAll || me.showCloseOthers) {
|
|
items.push('-');
|
|
}
|
|
|
|
if (me.showCloseOthers) {
|
|
items.push({
|
|
itemId: 'closeOthers',
|
|
text: me.closeOthersTabsText,
|
|
scope: me,
|
|
handler: me.onCloseOthers
|
|
});
|
|
}
|
|
|
|
if (me.showCloseAll) {
|
|
items.push({
|
|
itemId: 'closeAll',
|
|
text: me.closeAllTabsText,
|
|
scope: me,
|
|
handler: me.onCloseAll
|
|
});
|
|
}
|
|
|
|
if (me.extraItemsHead) {
|
|
items = me.extraItemsHead.concat(items);
|
|
}
|
|
|
|
if (me.extraItemsTail) {
|
|
items = items.concat(me.extraItemsTail);
|
|
}
|
|
|
|
me.menu = Ext.create('Ext.menu.Menu', {
|
|
items: items,
|
|
listeners: {
|
|
hide: me.onHideMenu,
|
|
scope: me
|
|
}
|
|
});
|
|
}
|
|
|
|
return me.menu;
|
|
},
|
|
|
|
onHideMenu: function () {
|
|
var me = this;
|
|
me.fireEvent('aftermenu', me.menu, me);
|
|
},
|
|
|
|
onClose : function(){
|
|
this.tabPanel.remove(this.item);
|
|
},
|
|
|
|
onCloseOthers : function(){
|
|
this.doClose(true);
|
|
},
|
|
|
|
onCloseAll : function(){
|
|
this.doClose(false);
|
|
},
|
|
|
|
doClose : function(excludeActive){
|
|
var items = [];
|
|
|
|
this.tabPanel.items.each(function(item){
|
|
if(item.closable){
|
|
if(!excludeActive || item !== this.item){
|
|
items.push(item);
|
|
}
|
|
}
|
|
}, this);
|
|
|
|
Ext.suspendLayouts();
|
|
Ext.Array.forEach(items, function(item){
|
|
this.tabPanel.remove(item);
|
|
}, this);
|
|
Ext.resumeLayouts(true);
|
|
}
|
|
});
|
|
|