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.
410 lines
16 KiB
410 lines
16 KiB
/**
|
|
* @typedef {object} JQPropertyGridOptions
|
|
* @property {object} meta - A metadata object describing the obj properties
|
|
*/
|
|
|
|
/* jshint -W089 */
|
|
(function ($) {// jscs:ignore requireNamedUnassignedFunctions
|
|
var OTHER_GROUP_NAME = 'Other';
|
|
var GET_VALS_FUNC_KEY = 'pg.getValues';
|
|
var HIDDEN_GROUP = 'hidden_group';
|
|
var NOT_SAVE_GROUP = 'not_save_group';
|
|
var pgIdSequence = 0;
|
|
|
|
/**
|
|
* Generates the property grid
|
|
* @param {object} obj - The object whose properties we want to display //要显示的对象
|
|
* @param {JQPropertyGridOptions} options - Options object for the component //组件的选项对象
|
|
*/
|
|
$.fn.jqPropertyGrid = function (obj, options) {
|
|
// Check if the user called the 'get' function (to get the values back from the grid).
|
|
//检查用户是否呼叫了'get' 函数,,从表格中读取数据
|
|
if (typeof obj === 'string' && obj === 'get') { //如果第一个参数是字符串类型,并且字面值='get'
|
|
if (typeof this.data(GET_VALS_FUNC_KEY) === 'function') { //如果GET_VALS_FUNC_KEY是函数类型
|
|
return this.data(GET_VALS_FUNC_KEY)(); //调用这个函数
|
|
}
|
|
|
|
return null; //否则返回null
|
|
} else if (typeof obj === 'string') { //字符类型返回错误信息
|
|
console.error('jqPropertyGrid got invalid option:', obj);
|
|
return;
|
|
} else if (typeof obj !== 'object' || obj === null) { //不是对象返回错误误信息
|
|
console.error('jqPropertyGrid must get an object in order to initialize the grid.');
|
|
return;
|
|
}
|
|
|
|
// Normalize options
|
|
options = options && typeof options === 'object' ? options : {}; //如果options不是对象,则返回一个空对象
|
|
options.meta = options.meta && typeof options.meta === 'object' ? options.meta : {};//判断 options.met是不是对象,不是对象返回空对象
|
|
|
|
// 以下为创建属性网格操作
|
|
var meta = options.meta; //描述对象属性的元数据
|
|
var propertyRowsHTML = {OTHER_GROUP_NAME: ''}; //属性列表的HTML代码
|
|
var groupsHeaderRowHTML = {}; //组的标记头
|
|
var postCreateInitFuncs = []; //创建初始化函数?
|
|
var getValueFuncs = {}; //获取值
|
|
var pgId = 'pg' + (pgIdSequence++); //生成属性网格内部使用的id
|
|
var customTypes = options.customTypes || {}; //默认类型为object
|
|
|
|
var currGroup; //当前属性组?
|
|
for (var prop in obj) {
|
|
// Skip if this is not a direct property, a function, or its meta says it's non browsable
|
|
//obj是要显示对象,flow_node对象,如果obj没有这个属性,或者这个属性是个函数,或者这个属性的元数据不存在或可见性为false ,以上不在属性网格显示
|
|
if (!obj.hasOwnProperty(prop) || typeof obj[prop] === 'function' || (meta[prop] && meta[prop].browsable === false)) {
|
|
continue;
|
|
}
|
|
|
|
// Check what is the group of the current property or use the default 'Other' group
|
|
//检查当前属性是否有元数据,没有则归到OTHER组
|
|
currGroup = (meta[prop] && meta[prop].group) || OTHER_GROUP_NAME;
|
|
|
|
// If this is the first time we run into this group create the group row
|
|
//如果是第一次向这个组里添加组元素执行以下代码,如果这个组不是Other组,且为空,获取这个组
|
|
if (currGroup !== OTHER_GROUP_NAME && currGroup !== NOT_SAVE_GROUP && !groupsHeaderRowHTML[currGroup]) {
|
|
groupsHeaderRowHTML[currGroup] = getGroupHeaderRowHtml(currGroup);
|
|
}
|
|
if (currGroup == 'HIDDEN_GROUP') {
|
|
groupsHeaderRowHTML[currGroup] = getGroupHeaderRowHtml(currGroup);
|
|
}
|
|
|
|
// Initialize the group cells html 初始化这个组成员html
|
|
propertyRowsHTML[currGroup] = propertyRowsHTML[currGroup] || '';
|
|
|
|
// 添加html代码当前单元格
|
|
// console.log(prop+":"+ obj[prop]);
|
|
propertyRowsHTML[currGroup] += getPropertyRowHtml(pgId, prop, obj[prop], meta[prop], postCreateInitFuncs, getValueFuncs, customTypes, currGroup);
|
|
}
|
|
|
|
//以下生成表格
|
|
var innerHTML = '<table class="pgTable">';
|
|
for (var group in groupsHeaderRowHTML) {
|
|
// Add the group row 组列
|
|
innerHTML += groupsHeaderRowHTML[group];
|
|
// Add the group cells 组单元格
|
|
innerHTML += propertyRowsHTML[group];
|
|
}
|
|
|
|
//添加Other组
|
|
if (propertyRowsHTML[OTHER_GROUP_NAME]) {
|
|
innerHTML += getGroupHeaderRowHtml(OTHER_GROUP_NAME);
|
|
innerHTML += propertyRowsHTML[OTHER_GROUP_NAME];
|
|
}
|
|
|
|
// 闭合table标签
|
|
innerHTML += '</table>';
|
|
this.html(innerHTML);
|
|
/* $("pgTextArea").cleditor({
|
|
width: 240, // height not including margins, borders or padding
|
|
controls: // controls to add to the toolbar
|
|
"bold italic underline strikethrough | font size " +
|
|
"style | color highlight removeformat | "
|
|
}).change(function(){
|
|
$('input[id^="pg"]').trigger("keyup");
|
|
});*/
|
|
$("textarea").change(function () {
|
|
$('input[id^="pg"]').trigger("keyup");
|
|
|
|
});
|
|
// Call the post init functions
|
|
for (var i = 0; i < postCreateInitFuncs.length; ++i) {
|
|
if (typeof postCreateInitFuncs[i] === 'function') {
|
|
postCreateInitFuncs[i]();
|
|
// just in case make sure we are not holding any reference to the functions
|
|
postCreateInitFuncs[i] = null;
|
|
}
|
|
}
|
|
|
|
// Create a function that will return tha values back from the property grid
|
|
var getValues = function () {
|
|
var result = {};
|
|
for (var prop in getValueFuncs) {
|
|
if (typeof getValueFuncs[prop] !== 'function') {
|
|
continue;
|
|
}
|
|
|
|
result[prop] = getValueFuncs[prop]();
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
this.data(GET_VALS_FUNC_KEY, getValues);
|
|
};
|
|
|
|
/**
|
|
*获取分组头部信息的html文档
|
|
* @param {string} displayName - The group display name
|
|
*/
|
|
function getGroupHeaderRowHtml(displayName) {
|
|
if (displayName != 'hidden_group') {
|
|
return '<table class="pgSubTable" ><tr class="pgGroupRow"><td class="pgGroupHeadCell" ><a href="#" onclick="hidde_pgRow(this)">-</a></td><td colspan="2" class="pgGroupCell">' + displayName + '</td></tr>';
|
|
|
|
} else {
|
|
return '<table class="pgSubTable"><tr class="pgGroupRow" style="display:none"><td class="pgGroupHeadCell" ><a href="#" onclick="hidde_pgRow(this)">-</a></td><td colspan="2" class="pgGroupCell" style="display:none">' + displayName + '</td></tr>';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Gets the html of a specific property row
|
|
* @param {string} pgId - The property-grid id being rendered
|
|
* @param {string} name - The property name
|
|
* @param {*} value - The current property value
|
|
* @param {object} meta - A metadata object describing this property
|
|
* @param {function[]} [postCreateInitFuncs] - An array to fill with functions to run after the grid was created
|
|
* @param {object.<string, function>} [getValueFuncs] - A dictionary where the key is the property name and the value is a function to retrieve the propery selected value
|
|
* @param {object} customTypes - an object describing additionnal types renderers
|
|
*/
|
|
function getPropertyRowHtml(pgId, name, value, meta, postCreateInitFuncs, getValueFuncs, customTypes, currGroup) {
|
|
if (!name) {
|
|
return '';
|
|
}
|
|
|
|
meta = meta || {};
|
|
// We use the name in the meta if available
|
|
var displayName = meta.name || name;
|
|
var type = meta.type || '';
|
|
var elemId = pgId + name;
|
|
|
|
var valueHTML;
|
|
|
|
// check if type is registered in customTypes
|
|
var isCustomType = false;
|
|
for (var customType in customTypes) {
|
|
if (type === customType) {
|
|
isCustomType = customTypes[customType];
|
|
}
|
|
}
|
|
|
|
// If value was handled by custom type
|
|
if (isCustomType !== false) {
|
|
valueHTML = isCustomType.html(elemId, name, value, meta);
|
|
if (getValueFuncs) {
|
|
if (isCustomType.hasOwnProperty('makeValueFn')) {
|
|
getValueFuncs[name] = isCustomType.makeValueFn(elemId, name, value, meta);
|
|
} else if (isCustomType.hasOwnProperty('valueFn')) {
|
|
getValueFuncs[name] = isCustomType.valueFn;
|
|
} else {
|
|
getValueFuncs[name] = function () {
|
|
return $('#' + elemId).val();
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
// If boolean create checkbox
|
|
else if (type === 'boolean' || (type === '' && typeof value === 'boolean')) {
|
|
valueHTML = '<input type="checkbox" id="' + elemId + '" value="' + name + '"' + (value ? ' checked' : '') + ' />';
|
|
if (getValueFuncs) {
|
|
getValueFuncs[name] = function () {
|
|
return $('#' + elemId).prop('checked');
|
|
};
|
|
}
|
|
|
|
// If options create drop-down list
|
|
} else if (type === 'options' && Array.isArray(meta.options)) {
|
|
valueHTML = getSelectOptionHtml(elemId, value, meta.options);
|
|
if (getValueFuncs) {
|
|
getValueFuncs[name] = function () {
|
|
return $('#' + elemId).val();
|
|
};
|
|
}
|
|
|
|
// If number and a jqueryUI spinner is loaded use it
|
|
} else if (typeof $.fn.spinner === 'function' && (type === 'number' || (type === '' && typeof value === 'number'))) {
|
|
valueHTML = '<input type="text" id="' + elemId + '" value="' + value + '" style="width:50px" />';
|
|
if (postCreateInitFuncs) {
|
|
postCreateInitFuncs.push(initSpinner(elemId, meta.options));
|
|
}
|
|
|
|
if (getValueFuncs) {
|
|
getValueFuncs[name] = function () {
|
|
return $('#' + elemId).spinner('value');
|
|
};
|
|
}
|
|
|
|
// If color and we have the spectrum color picker use it
|
|
} else if (type === 'color' && typeof $.fn.spectrum === 'function') {
|
|
valueHTML = '<input type="text" id="' + elemId + '" />';
|
|
if (postCreateInitFuncs) {
|
|
postCreateInitFuncs.push(initColorPicker(elemId, value, meta.options));
|
|
}
|
|
|
|
if (getValueFuncs) {
|
|
getValueFuncs[name] = function () {
|
|
return $('#' + elemId).spectrum('get').toHexString();
|
|
};
|
|
}
|
|
|
|
// If label (for read-only)
|
|
} else if (type === 'label') {
|
|
if (typeof meta.description === 'string' && meta.description) {
|
|
valueHTML = '<label for="' + elemId + '" title="' + meta.description + '">' + value + '</label>';
|
|
} else {
|
|
valueHTML = '<label for="' + elemId + '">' + value + '</label>';
|
|
}
|
|
|
|
// If hidden_Item (for read-only)
|
|
} else if (currGroup == 'hidden_group') {
|
|
valueHTML = '<input type="text" style="display:none" id="' + elemId + '" value="' + value + '"></input>';
|
|
|
|
if (getValueFuncs) {
|
|
getValueFuncs[name] = function () {
|
|
return value
|
|
};
|
|
}
|
|
} else if (type == 'text_area') {
|
|
|
|
|
|
valueHTML = '<textarea id="' + elemId + '" class="pgTextArea" rows="10" cols=22 style="resize:none" >' + value + '</textarea >';
|
|
|
|
if (getValueFuncs) {
|
|
getValueFuncs[name] = function () {
|
|
return $('#' + elemId).val();
|
|
};
|
|
}
|
|
} else {
|
|
whensetassigner = "";
|
|
if (elemId.indexOf('assigner') >= 0) {
|
|
whensetassigner = "readyonly"
|
|
}
|
|
|
|
valueHTML = '<input type="text" ' + whensetassigner + ' id="' + elemId + '" value="' + value + '" />';
|
|
if (getValueFuncs) {
|
|
getValueFuncs[name] = function () {
|
|
// if (elemId.indexOf('assigner') >= 0) {
|
|
// return $('#' + elemId).val();
|
|
|
|
|
|
// }else{
|
|
return $('#' + elemId).val();
|
|
// }
|
|
|
|
};
|
|
}
|
|
}
|
|
|
|
if (typeof meta.description === 'string' && meta.description &&
|
|
(typeof meta.showHelp === 'undefined' || meta.showHelp)) {
|
|
displayName += '<span class="pgTooltip" title="' + meta.description + '">[?]</span>';
|
|
}
|
|
if (currGroup == 'hidden_group') {
|
|
return '<tr class="pgRow" style="display:none" ><td class="td_head" ></td>' +
|
|
'<td class="pgCell" style="display:none" >' + displayName + '</td>' +
|
|
'<td class="pgCell" style="display:none" >' + valueHTML + '</td></tr>';
|
|
} else {
|
|
return '<tr class="pgRow"><td class="td_head"></td>' +
|
|
'<td class="pgCell">' + displayName + '</td>' +
|
|
'<td class="pgCell">' + valueHTML + '</td></tr>';
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Gets a select-option (dropdown) html
|
|
* @param {string} id - The select element id
|
|
* @param {string} [selectedValue] - The current selected value
|
|
* @param {*[]} options - An array of option. An element can be an object with value/text pairs, or just a string which is both the value and text
|
|
* @returns {string} The select element html
|
|
*/
|
|
function getSelectOptionHtml(id, selectedValue, options) {
|
|
id = id || '';
|
|
console.log('1');
|
|
console.log(selectedValue);
|
|
selectedValue = selectedValue || '';
|
|
options = options || [];
|
|
|
|
var html = '<select';
|
|
if (id) {
|
|
html += ' id="' + id + '"';
|
|
}
|
|
|
|
html += ' >';
|
|
|
|
var text;
|
|
var value;
|
|
for (var i = 0; i < options.length; i++) {
|
|
value = typeof options[i] === 'object' ? options[i].value : options[i];
|
|
text = typeof options[i] === 'object' ? options[i].text : options[i];
|
|
|
|
html += '<option value="' + value + '"' + (selectedValue === value ? ' selected>' : '>');
|
|
html += text + '</option>';
|
|
}
|
|
|
|
html += '</select>';
|
|
return html;
|
|
}
|
|
|
|
/**
|
|
* Gets an init function to a number textbox
|
|
* @param {string} id - The number textbox id
|
|
* @param {object} [options] - The spinner options
|
|
* @returns {function}
|
|
*/
|
|
function initSpinner(id, options) {
|
|
if (!id) {
|
|
return null;
|
|
}
|
|
// Copy the options so we won't change the user "copy"
|
|
var opts = {};
|
|
$.extend(opts, options);
|
|
|
|
// Add a handler to the change event to verify the min/max (only if not provided by the user)
|
|
opts.change = typeof opts.change === 'undefined' ? onSpinnerChange : opts.change;
|
|
|
|
return function onSpinnerInit() {
|
|
$('#' + id).spinner(opts);
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Gets an init function to a color textbox
|
|
* @param {string} id - The color textbox id
|
|
* @param {string} [color] - The current color (e.g #000000)
|
|
* @param {object} [options] - The color picker options
|
|
* @returns {function}
|
|
*/
|
|
function initColorPicker(id, color, options) {
|
|
if (!id) {
|
|
return null;
|
|
}
|
|
|
|
var opts = {};
|
|
$.extend(opts, options);
|
|
if (typeof color === 'string') {
|
|
opts.color = color;
|
|
}
|
|
|
|
return function onColorPickerInit() {
|
|
$('#' + id).spectrum(opts);
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Handler for the spinner change event
|
|
*/
|
|
function onSpinnerChange() {
|
|
var $spinner = $(this);
|
|
var value = $spinner.spinner('value');
|
|
|
|
// If the value is null and the real value in the textbox is string we empty the textbox
|
|
if (value === null && typeof $spinner.val() === 'string') {
|
|
$spinner.val('');
|
|
return;
|
|
}
|
|
|
|
// Now check that the number is in the min/max range.
|
|
var min = $spinner.spinner('option', 'min');
|
|
var max = $spinner.spinner('option', 'max');
|
|
if (typeof min === 'number' && this.value < min) {
|
|
this.value = min;
|
|
return;
|
|
}
|
|
|
|
if (typeof max === 'number' && this.value > max) {
|
|
this.value = max;
|
|
}
|
|
}
|
|
|
|
})(window.$);
|
|
|