<commit_before>'use strict';

if (typeof GJS === "undefined") {
    var GJS = {};
}

/**
 * Bitmap font that uses a simple ISO-8859-1 monospace grid sprite sheet.
 * @param {Object} options Constructor options.
 * @constructor
 */
GJS.MonospaceBitmapFont = function(options) {
    var defaults = {
        spriteSrc: 'bitmapfont-tiny.png',
        characterHeight: 6,
        characterWidth: 4,
        charactersPerRow: undefined,
        color: undefined,
        closerKerningCharacters: [], // list of characters to kern closer when in pairs. for example: ['i', 'l']
        kerningAmount: 1
    };
    objectUtil.initWithDefaults(this, defaults, options);
    if (this.color !== undefined) {
        this.sprite = new GJS.Sprite(this.spriteSrc, GJS.Sprite.turnSolidColored(this.color));
    } else {
        this.sprite = new GJS.Sprite(this.spriteSrc);
    }
};

/**
 * Draw a single character.
 * @param {CanvasRenderingContext2D} ctx Context to draw to.
 * @param {string} A single-character string to draw.
 */
GJS.MonospaceBitmapFont.prototype.drawCharacter = function(ctx, character) {
    if (this.sprite.loaded) {
        if (this.charactersPerRow === undefined) {
            this.charactersPerRow = this.sprite.width / this.characterWidth;
        }
        var code = character.charCodeAt(0);
        var row = Math.floor(code / this.charactersPerRow);
        var col = code - (row * this.charactersPerRow);
        ctx.drawImage(this.sprite.img,
                      col * this.characterWidth, row * this.characterHeight,
                      this.characterWidth, this.characterHeight,
                      0, 0,
                      this.characterWidth, this.characterHeight);
    }
};

/**
 * Draw a string of text. The "textAlign" property of the canvas context affects its placement.
 * @param {CanvasRenderingContext2D} ctx Context to draw to.
 * @param {string} string String to draw.
 * @param {number} x Horizontal coordinate.
 * @param {number} y Vertical coordinate.
 */
GJS.MonospaceBitmapFont.prototype.drawText = function(ctx, string, x, y) {
    var drawnWidth = string.length * this.characterWidth;
    var kerningActive = this.closerKerningCharacters.length > 0 && this.kerningAmount != 0;
    var prevCharacterNarrow = false;
    if (kerningActive) {
        for (var i = 0; i < string.length; ++i) {
            if (this.closerKerningCharacters.indexOf(string[i]) >= 0) {
                if (prevCharacterNarrow) {
                    drawnWidth -= this.kerningAmount;
                }
                prevCharacterNarrow = true;
            } else {
                prevCharacterNarrow = false;
            }
        }
    }

    var baselineTranslate = 0; // Default for top and hanging
    if (ctx.textBaseline == 'bottom' || ctx.textBaseline == 'alphabetic' || ctx.textBaseline == 'ideographic') {
        baselineTranslate = -this.characterHeight;
    } else if (ctx.textBaseline == 'middle') {
        baselineTranslate = Math.floor(-this.characterHeight * 0.5);
    }
    var alignTranslate = 0;
    if (ctx.textAlign == 'center') {
        alignTranslate = -Math.floor(drawnWidth * 0.5);
    } else if (ctx.textAlign == 'right') {
        alignTranslate = -Math.floor(drawnWidth);
    }
    ctx.save();
    ctx.translate(x + alignTranslate, y + baselineTranslate);
    for (var i = 0; i < string.length; ++i) {
        this.drawCharacter(ctx, string[i]);
        if (kerningActive) {
            if (this.closerKerningCharacters.indexOf(string[i]) >= 0 && i + 1 < string.length &&
                this.closerKerningCharacters.indexOf(string[i + 1]) >= 0) {
                ctx.translate(this.characterWidth - this.kerningAmount, 0);
            } else {
                ctx.translate(this.characterWidth, 0);
            }

        } else {
            ctx.translate(this.characterWidth, 0);
        }
    }
    ctx.restore();
};

/**
 * Draw a string of text split in several rows. The "textAlign" property of the canvas context affects its placement.
 * The text is split at spaces.
 * @param {CanvasRenderingContext2D} ctx Context to draw to.
 * @param {string} textToRender String to draw.
 * @param {number} x Horizontal coordinate.
 * @param {number} y Vertical coordinate of the top row.
 * @param {number} maxRowLength Maximum length of row in characters.
 * @param {number} rowHeight Row height in coordinates.
 */
GJS.MonospaceBitmapFont.prototype.drawTextInRows = function(ctx, textToRender, x, y, maxRowLength, rowHeight) {
    var renderedRows = textToRender;
    if (!(renderedRows instanceof Array)) {
        if (maxRowLength < 0) {
            renderedRows = [textToRender];
        } else {
            renderedRows = [];
            var rowStartIndex = 0;
            var spaceIndex = textToRender.indexOf(' ');
            while (textToRender.length - rowStartIndex > maxRowLength) {
                var prevSpaceIndex = spaceIndex;
                while (spaceIndex - rowStartIndex < maxRowLength && spaceIndex !== -1) {
                    prevSpaceIndex = spaceIndex;
                    spaceIndex = textToRender.indexOf(' ', prevSpaceIndex + 1);
                }
                renderedRows.push(textToRender.substring(rowStartIndex, prevSpaceIndex));
                rowStartIndex = prevSpaceIndex + 1;
            }
            renderedRows.push(textToRender.substring(rowStartIndex));
        }
    }
    for (var i = 0; i < renderedRows.length; ++i) {
        this.drawText(ctx, renderedRows[i], x, y + i * rowHeight);
    }
};
<commit_msg>Add getNumberOfRows to MonospaceBitmapFont<commit_after>'use strict';

if (typeof GJS === "undefined") {
    var GJS = {};
}

/**
 * Bitmap font that uses a simple ISO-8859-1 monospace grid sprite sheet.
 * @param {Object} options Constructor options.
 * @constructor
 */
GJS.MonospaceBitmapFont = function(options) {
    var defaults = {
        spriteSrc: 'bitmapfont-tiny.png',
        characterHeight: 6,
        characterWidth: 4,
        charactersPerRow: undefined,
        color: undefined,
        closerKerningCharacters: [], // list of characters to kern closer when in pairs. for example: ['i', 'l']
        kerningAmount: 1
    };
    objectUtil.initWithDefaults(this, defaults, options);
    if (this.color !== undefined) {
        this.sprite = new GJS.Sprite(this.spriteSrc, GJS.Sprite.turnSolidColored(this.color));
    } else {
        this.sprite = new GJS.Sprite(this.spriteSrc);
    }
};

/**
 * Draw a single character.
 * @param {CanvasRenderingContext2D} ctx Context to draw to.
 * @param {string} A single-character string to draw.
 */
GJS.MonospaceBitmapFont.prototype.drawCharacter = function(ctx, character) {
    if (this.sprite.loaded) {
        if (this.charactersPerRow === undefined) {
            this.charactersPerRow = this.sprite.width / this.characterWidth;
        }
        var code = character.charCodeAt(0);
        var row = Math.floor(code / this.charactersPerRow);
        var col = code - (row * this.charactersPerRow);
        ctx.drawImage(this.sprite.img,
                      col * this.characterWidth, row * this.characterHeight,
                      this.characterWidth, this.characterHeight,
                      0, 0,
                      this.characterWidth, this.characterHeight);
    }
};

/**
 * Draw a string of text. The "textAlign" property of the canvas context affects its placement.
 * @param {CanvasRenderingContext2D} ctx Context to draw to.
 * @param {string} string String to draw.
 * @param {number} x Horizontal coordinate.
 * @param {number} y Vertical coordinate.
 */
GJS.MonospaceBitmapFont.prototype.drawText = function(ctx, string, x, y) {
    var drawnWidth = string.length * this.characterWidth;
    var kerningActive = this.closerKerningCharacters.length > 0 && this.kerningAmount != 0;
    var prevCharacterNarrow = false;
    if (kerningActive) {
        for (var i = 0; i < string.length; ++i) {
            if (this.closerKerningCharacters.indexOf(string[i]) >= 0) {
                if (prevCharacterNarrow) {
                    drawnWidth -= this.kerningAmount;
                }
                prevCharacterNarrow = true;
            } else {
                prevCharacterNarrow = false;
            }
        }
    }

    var baselineTranslate = 0; // Default for top and hanging
    if (ctx.textBaseline == 'bottom' || ctx.textBaseline == 'alphabetic' || ctx.textBaseline == 'ideographic') {
        baselineTranslate = -this.characterHeight;
    } else if (ctx.textBaseline == 'middle') {
        baselineTranslate = Math.floor(-this.characterHeight * 0.5);
    }
    var alignTranslate = 0;
    if (ctx.textAlign == 'center') {
        alignTranslate = -Math.floor(drawnWidth * 0.5);
    } else if (ctx.textAlign == 'right') {
        alignTranslate = -Math.floor(drawnWidth);
    }
    ctx.save();
    ctx.translate(x + alignTranslate, y + baselineTranslate);
    for (var i = 0; i < string.length; ++i) {
        this.drawCharacter(ctx, string[i]);
        if (kerningActive) {
            if (this.closerKerningCharacters.indexOf(string[i]) >= 0 && i + 1 < string.length &&
                this.closerKerningCharacters.indexOf(string[i + 1]) >= 0) {
                ctx.translate(this.characterWidth - this.kerningAmount, 0);
            } else {
                ctx.translate(this.characterWidth, 0);
            }

        } else {
            ctx.translate(this.characterWidth, 0);
        }
    }
    ctx.restore();
};

/**
 * Draw a string of text split in several rows. The "textAlign" property of the canvas context affects its placement.
 * The text is split at spaces.
 * @param {CanvasRenderingContext2D} ctx Context to draw to.
 * @param {string} textToRender String to draw.
 * @param {number} x Horizontal coordinate.
 * @param {number} y Vertical coordinate of the top row.
 * @param {number} maxRowLength Maximum length of row in characters.
 * @param {number} rowHeight Row height in coordinates.
 */
GJS.MonospaceBitmapFont.prototype.drawTextInRows = function(ctx, textToRender, x, y, maxRowLength, rowHeight) {
    var renderedRows = this._splitRows(textToRender, maxRowLength);
    for (var i = 0; i < renderedRows.length; ++i) {
        this.drawText(ctx, renderedRows[i], x, y + i * rowHeight);
    }
};

/**
 * @param {string} textToRender String to draw.
 * @param {number} maxRowLength Maximum length of row in characters.
 * @return {number} Number of rows that would get drawn if drawTextInRows is called with the same arguments.
 */
GJS.MonospaceBitmapFont.prototype.getNumberOfRows = function(textToRender, maxRowLength) {
    return this._splitRows(textToRender, maxRowLength).length;
};

/**
 * Split text into rows. The text is split at spaces.
 * @param {string} textToRender String to draw.
 * @param {number} maxRowLength Maximum length of row in characters.
 * @protected
 */
GJS.MonospaceBitmapFont.prototype._splitRows = function(textToRender, maxRowLength) {
    var renderedRows = textToRender;
    if (!(renderedRows instanceof Array)) {
        if (maxRowLength < 0) {
            renderedRows = [textToRender];
        } else {
            renderedRows = [];
            var rowStartIndex = 0;
            var spaceIndex = textToRender.indexOf(' ');
            while (textToRender.length - rowStartIndex > maxRowLength) {
                var prevSpaceIndex = spaceIndex;
                while (spaceIndex - rowStartIndex < maxRowLength && spaceIndex !== -1) {
                    prevSpaceIndex = spaceIndex;
                    spaceIndex = textToRender.indexOf(' ', prevSpaceIndex + 1);
                }
                renderedRows.push(textToRender.substring(rowStartIndex, prevSpaceIndex));
                rowStartIndex = prevSpaceIndex + 1;
            }
            renderedRows.push(textToRender.substring(rowStartIndex));
        }
    }
    return renderedRows;
};
<|endoftext|>


<commit_before>Markup = {
	parse: function(text) {
		if (text) {
			var t = new Date();
			// Create the root tag as a container for all the other bits
			var rootTag = MarkupTag.create('root');
			var start = 0, end = 0;
			// Current tag:
			var tag = rootTag;
			while (start != -1) {
				start = text.indexOf('<', end);
				if (start > end)
					tag.parts.push(text.substring(end, start));
				if (start >= 0) {
					end = text.indexOf('>', start) + 1;
					if (end <= start) {
						// Non-closed tag:
						tag.parts.push(text.substring(start));
						break;
					}
					var open = text.charAt(start + 1) != '/';
					if (open) {
						// Opening tag
						// Pass current tag as parent
						tag = MarkupTag.create(text.substring(start + 1, end - 1), tag);
					} else {
						// Closing tag
						var name = text.substring(start + 2, end - 1), openTag = tag;
						// Walk up hierarchy until we find closing tag:
						while(openTag && openTag.name != name)
							openTag = openTag.parent;
						if (openTag && openTag != rootTag) {
							// Activate parent tag
						 	tag = openTag.parent;
							tag.parts.push(openTag);
						}
					}
				}
			}
			if (end > start)
				rootTag.parts.push(text.substring(end));
			app.log("TIME " + (new Date() - t));
			return rootTag;
		}
		return null;
	},

	render: function(text, param) {
		var tag = Markup.parse(text);
		return tag && tag.render(param) || '';
	}
};

MarkupTag = Base.extend(new function() {
	// Private function to parse tag definitions (everything wihtout the trailing '<' & '>')
	// This is used both when creating a tag object from a tag string and when parsing
	// _attributes definitions, in which case collectAttributes is set to true
	// and the method collects different information, see bellow.
	function parseDefinition(str, collectAttributes) {
		var name = null, list = [], attribute = null, attributes = {};
		for (var match; match = /(\w+)=|("(?:[^"\\]*(?:\\"|\\)?)*")|(\S+)/g.exec(str);) {
			if (match[1]) { // attribute name
				attribute = match[1];
			} else { // string or value
				// Eval strings (match[2]) here is safe, due to regex above it is always a string
				var value = match[2] ? eval(match[2]) : match[3];
				if (collectAttributes) {
					// When collecting _attributes, use list array to store them
					if (!attribute) // attribute with no default value
						list.push({ name: value });
					else
						list.push({ name: attribute, defaultValue: value });
				} else {
					// Normal tag parsing:
					// Find tag name, and store attributes (named) and arguments (unnamed)
					if (!name) { // The first value is the tag name
						name = value;
					} else if (attribute) { // named attribute
						attributes[attribute] = value;
					} else { // unnamed argument
						list.push(value);
					}
				}
				// Reset attribute name again
				attribute = null;
			}
		}
		if (collectAttributes) {
			// Scan backwards to see wether further attributes define defaults.
			// This is needed to stop looping through attributes early once
			// no more defaults are available and unnamed arguments are used up.
			// See MarkupTag#create
			var defaultsFollow = false;
			for (var i = list.length - 1; i >= 0; i--) {
				list[i].defaultsFollow = defaultsFollow;
				defaultsFollow = defaultsFollow || list[i].defaultValue !== undefined;
			}
			return list;
		} else {
			// Normal tag parsing.
			// Return name, unnamed arguments and named attributes for further
			// scanning in MarkupTag.create, if the tag defines _attributes.
			return {
				name: name,
				arguments: list,
				attributes: attributes
			};
		}
	}

	var tags = {};

	return {
		render: function(content, param, encoder) {
			// Define in subclasses
		},

		/*
		cleanUp: function(param) {
			// Define only if tag needs to clean up something in param
			// This is only called once per used tag type, not for each tag!
		}
		*/

		renderChildren: function(param, encoder, cleanUps) {
			var buffer = new Array(this.parts.length);
			for (var i = 0, l = this.parts.length; i < l; i++) {
				var part = this.parts[i];
				if (part.render) {
					// This is a tag, render its children first into one content string
					var content = part.renderChildren(param, encoder, cleanUps);
					// Now render the tag itself and place it in the resulting buffer
					buffer[i] = part.render(content, param, encoder)
					// If the object defines the cleanUp function,
					// collect it now:
					if (part.cleanUp)
						cleanUps[part.name] = part;
				} else {
					// A simple string. Just encode it
					buffer[i] = encoder(this.parts[i]);
				}
			}
			return buffer.join('');
		},

		toString: function() {
			return '<' + this.definition + '>';
		},

		statics: {
			extend: function(src) {
				// Parse _attributes definition through the same tag parsing mechanism
				// parseDefinition contains special logic to produce an info object
				// for attribute / argument parsing further down in MarkupTag.create
				var attributes = src._attributes && parseDefinition(src._attributes, true);
				return src._tags.split(',').each(function(tag) {
					// Store attributes information and a reference to prototype in tags
					tags[tag] = {
						attributes: attributes,
						proto: this.prototype
					};
				}, this.base(src));
			},

			create: function(definition, parent) {
				// Parse tag definition for attributes (named) and arguments (unnamed).
				var def = definition == 'root' ? { name: 'root' } : parseDefinition(definition);
				// Render any undefined tag through the UndefinedTag.
				var obj = tags[def.name] || tags['undefined'];
				if (obj.attributes) {
					// If _attributes were defined, use the info object produced
					// by parseDefinition in MarkupTag.extend now to scan through
					// defined named attributes and unnamed arguments,
					// and use default values if available.
					var index = 0;
					for (var i = 0, l = obj.attributes.length; i < l; i++) {
						var attrib = obj.attributes[i];
						// If the tag does not define this predefined attribute,
						// either take its value from the unnamed arguments,
						// and increase index, or use its default value.
						if (def.attributes[attrib.name] === undefined) {
							def.attributes[attrib.name] = index < def.arguments.length
								? def.arguments[index++]
								: attrib.defaultValue; // Use default value if running out of unnamed args
						}
						// If the _attributes definition does not contain any more defaults
						// and we are running out of unnamed arguments, we might as well
						// drop out of the loop since there won't be anything to be done.
						if (!attrib.defaultsFollow && index >= def.arguments.length)
							break;
					}
					// Cut away consumed unnamed arguments
					if (index > 0)
						def.arguments.splice(0, index);
				}
				// Instead of using the empty tag initializers that are a bit
				// slow through bootstrap's #initalize support, produce a pure
				// js object and then set its __proto__ field on Rhino,
				// to speed things up.
				// This hack works on Rhino but not on every browser.
				// On Browsers, you would do this instead:
				// var tag = new obj.proto();
				var tag = {};
				tag.__proto__ = obj.proto;
				// This part stays the same:
				tag.name = def.name;
				tag.attributes = def.attributes;
				tag.arguments = def.arguments;
				tag.parent = parent;
				tag.definition = definition;
				tag.parts = [];
				// Setup children list, and previous / next references
				tag.children = [];
				if (parent) {
					var siblings = parent.children;
					tag.previous = siblings[siblings.length - 1];
					if (tag.previous)
						tag.previous.next = tag;
					siblings.push(tag);
				}
				return tag;
			}
		}
	}
});

// The RootTag is there to contain all other markup tags and content parts and
// is produced internally in and returned by Markup.parse. Call render on it
// to render the parsed Markup tree.
RootTag = MarkupTag.extend({
	_tags: 'root',

	// The RootTag's render function is different as it is used to render the whole tree
	// and does not receive content or encoder as parameters.
	render: function(param) {
		if (!param)
			param = {};
		// Determine encoder to be used, default is not encoding anything:
		var encoder = param.encoding && global['encode' + param.encoding.capitalize()]
			|| function(val) { return val };
		// Keep tag objects that need to clean up something in the end. This is
		// only used for resource rendering in Scriptographer right now.
		var cleanUps = {};
		var str = this.renderChildren(param, encoder, cleanUps);
		// See if we need to do some clean up now:
		for (var name in cleanUps)
			cleanUps[name].cleanUp(param);
		return str;
	}
});

// Special tag to render undefined tag names unmodified.
// UndefinedTag#render can be overridden and is handling the rendering of all the undefined tags.
UndefinedTag = MarkupTag.extend({
	_tags: 'undefined',

	render: function(content, param, encoder) {
		return encoder('<' + this.definition + '>')	+ content + encoder('</' + this.name + '>');
	}
});

NodeTag = MarkupTag.extend({
	_tags: 'node',
	_attributes: 'id',

	render: function(content) {
		var id = this.attributes.id;
		if (!id) {
			id = content;
			content = null;
		}
		var node = HopObject.get(id);
		if (node)
			return node.renderLink(content);
	}
});

CodeTag = MarkupTag.extend({
	_tags: 'code',

	render: function(content) {
		return '
' + content.replaceAll('
', '') + '
';
	}
});

ResourceTag = MarkupTag.extend({
	_tags: 'resource',

	getResource: function(name, param) {
		if (!param.resourceLookup) {
			param.resourceLookup = {};
			if (param.resources) {
				for (var i = 0; i < param.resources.length; i++) {
					var resource = param.resources[i]
					param.resourceLookup[resource.name] = { resource: resource, index: i };
				}
			}
		}
		var entry = param.resourceLookup[name];
		if (entry) {
			// Mark as used. Scriptographer extends ResourceTag to remove
			// these in cleanUp
			entry.used = true;
			return entry.resource;
		}
	},

	cleanUp: function(param) {
		if (param.removeUsedResources && param.resources) {
			// Remove the resources that have been flaged 'used'
			for (var i = param.resources.length - 1; i >= 0; i--)
				if (param.resourceLookup[param.resources[i].name].used)
					param.resources.splice(i, 1);
		}
		delete param.resourceLookup;
	},

	// Defined outside render() so it can be overridden by applications.
	renderIcon: function(resource, param) {
		// TODO: pass param, and define small as smallIcon or iconSmall ?
		return resource.renderIcon({ small: true });
	},

	render: function(content, param) {
		var resource = this.getResource(content, param);
		if (resource)
			return this.renderIcon(resource, param);
	}
});

ImageTag = ResourceTag.extend({
	_tags: 'img',

	// Defined outside render() so it can be overridden by applications.
	renderImage: function(picture, param) {
		return picture.renderImage(param);
	},

	render: function(content, param) {
		if (!/^http/.test(content)) {
			var resource = this.getResource(content, param);
			if (resource && resource instanceof Picture)
				return this.renderImage(resource, param);
		} else {
			return '';
		}
	}
});

HtmlTag = MarkupTag.extend({
	_tags: 'i,b,strong,s,strike',

	render: function(content) {
		return '<' + this.definition + (content != null
				? '>' + content + '</' + this.name + '>'
				: '>');
	}
});

BoldTag = MarkupTag.extend({
	_tags: 'bold',

	render: function(content) {
		return '' + content + '';
	}
});

UrlTag = MarkupTag.extend({
	_tags: 'url',
	_attributes: 'url',

	render: function(content, param) {
		var url = this.attributes.url || content;
		var title = content || url;
		var str = '' + title + '';
		return str;
	}
});

QuoteTag = MarkupTag.extend({
	_tags: 'quote',
	_attributes: 'name',

	render: function(content) {
		return '
' + (this.attributes.name
			? this.attributes.name + ' wrote:'
			: 'Quote:')
			+ '

' + content + '
';
	}
});

ListTag = MarkupTag.extend({
	_tags: 'list',

	render: function(content) {
		return '
' + content + '
';
	}
});
<commit_msg>Removed benchmark log commands.<commit_after>Markup = {
	parse: function(text) {
		if (text) {
			// Create the root tag as a container for all the other bits
			var rootTag = MarkupTag.create('root');
			var start = 0, end = 0;
			// Current tag:
			var tag = rootTag;
			while (start != -1) {
				start = text.indexOf('<', end);
				if (start > end)
					tag.parts.push(text.substring(end, start));
				if (start >= 0) {
					end = text.indexOf('>', start) + 1;
					if (end <= start) {
						// Non-closed tag:
						tag.parts.push(text.substring(start));
						break;
					}
					var open = text.charAt(start + 1) != '/';
					if (open) {
						// Opening tag
						// Pass current tag as parent
						tag = MarkupTag.create(text.substring(start + 1, end - 1), tag);
					} else {
						// Closing tag
						var name = text.substring(start + 2, end - 1), openTag = tag;
						// Walk up hierarchy until we find closing tag:
						while(openTag && openTag.name != name)
							openTag = openTag.parent;
						if (openTag && openTag != rootTag) {
							// Activate parent tag
						 	tag = openTag.parent;
							tag.parts.push(openTag);
						}
					}
				}
			}
			if (end > start)
				rootTag.parts.push(text.substring(end));
			return rootTag;
		}
		return null;
	},

	render: function(text, param) {
		var tag = Markup.parse(text);
		return tag && tag.render(param) || '';
	}
};

MarkupTag = Base.extend(new function() {
	// Private function to parse tag definitions (everything wihtout the trailing '<' & '>')
	// This is used both when creating a tag object from a tag string and when parsing
	// _attributes definitions, in which case collectAttributes is set to true
	// and the method collects different information, see bellow.
	function parseDefinition(str, collectAttributes) {
		var name = null, list = [], attribute = null, attributes = {};
		for (var match; match = /(\w+)=|("(?:[^"\\]*(?:\\"|\\)?)*")|(\S+)/g.exec(str);) {
			if (match[1]) { // attribute name
				attribute = match[1];
			} else { // string or value
				// Eval strings (match[2]) here is safe, due to regex above it is always a string
				var value = match[2] ? eval(match[2]) : match[3];
				if (collectAttributes) {
					// When collecting _attributes, use list array to store them
					if (!attribute) // attribute with no default value
						list.push({ name: value });
					else
						list.push({ name: attribute, defaultValue: value });
				} else {
					// Normal tag parsing:
					// Find tag name, and store attributes (named) and arguments (unnamed)
					if (!name) { // The first value is the tag name
						name = value;
					} else if (attribute) { // named attribute
						attributes[attribute] = value;
					} else { // unnamed argument
						list.push(value);
					}
				}
				// Reset attribute name again
				attribute = null;
			}
		}
		if (collectAttributes) {
			// Scan backwards to see wether further attributes define defaults.
			// This is needed to stop looping through attributes early once
			// no more defaults are available and unnamed arguments are used up.
			// See MarkupTag#create
			var defaultsFollow = false;
			for (var i = list.length - 1; i >= 0; i--) {
				list[i].defaultsFollow = defaultsFollow;
				defaultsFollow = defaultsFollow || list[i].defaultValue !== undefined;
			}
			return list;
		} else {
			// Normal tag parsing.
			// Return name, unnamed arguments and named attributes for further
			// scanning in MarkupTag.create, if the tag defines _attributes.
			return {
				name: name,
				arguments: list,
				attributes: attributes
			};
		}
	}

	var tags = {};

	return {
		render: function(content, param, encoder) {
			// Define in subclasses
		},

		/*
		cleanUp: function(param) {
			// Define only if tag needs to clean up something in param
			// This is only called once per used tag type, not for each tag!
		}
		*/

		renderChildren: function(param, encoder, cleanUps) {
			var buffer = new Array(this.parts.length);
			for (var i = 0, l = this.parts.length; i < l; i++) {
				var part = this.parts[i];
				if (part.render) {
					// This is a tag, render its children first into one content string
					var content = part.renderChildren(param, encoder, cleanUps);
					// Now render the tag itself and place it in the resulting buffer
					buffer[i] = part.render(content, param, encoder)
					// If the object defines the cleanUp function,
					// collect it now:
					if (part.cleanUp)
						cleanUps[part.name] = part;
				} else {
					// A simple string. Just encode it
					buffer[i] = encoder(this.parts[i]);
				}
			}
			return buffer.join('');
		},

		toString: function() {
			return '<' + this.definition + '>';
		},

		statics: {
			extend: function(src) {
				// Parse _attributes definition through the same tag parsing mechanism
				// parseDefinition contains special logic to produce an info object
				// for attribute / argument parsing further down in MarkupTag.create
				var attributes = src._attributes && parseDefinition(src._attributes, true);
				return src._tags.split(',').each(function(tag) {
					// Store attributes information and a reference to prototype in tags
					tags[tag] = {
						attributes: attributes,
						proto: this.prototype
					};
				}, this.base(src));
			},

			create: function(definition, parent) {
				// Parse tag definition for attributes (named) and arguments (unnamed).
				var def = definition == 'root' ? { name: 'root' } : parseDefinition(definition);
				// Render any undefined tag through the UndefinedTag.
				var obj = tags[def.name] || tags['undefined'];
				if (obj.attributes) {
					// If _attributes were defined, use the info object produced
					// by parseDefinition in MarkupTag.extend now to scan through
					// defined named attributes and unnamed arguments,
					// and use default values if available.
					var index = 0;
					for (var i = 0, l = obj.attributes.length; i < l; i++) {
						var attrib = obj.attributes[i];
						// If the tag does not define this predefined attribute,
						// either take its value from the unnamed arguments,
						// and increase index, or use its default value.
						if (def.attributes[attrib.name] === undefined) {
							def.attributes[attrib.name] = index < def.arguments.length
								? def.arguments[index++]
								: attrib.defaultValue; // Use default value if running out of unnamed args
						}
						// If the _attributes definition does not contain any more defaults
						// and we are running out of unnamed arguments, we might as well
						// drop out of the loop since there won't be anything to be done.
						if (!attrib.defaultsFollow && index >= def.arguments.length)
							break;
					}
					// Cut away consumed unnamed arguments
					if (index > 0)
						def.arguments.splice(0, index);
				}
				// Instead of using the empty tag initializers that are a bit
				// slow through bootstrap's #initalize support, produce a pure
				// js object and then set its __proto__ field on Rhino,
				// to speed things up.
				// This hack works on Rhino but not on every browser.
				// On Browsers, you would do this instead:
				// var tag = new obj.proto();
				var tag = {};
				tag.__proto__ = obj.proto;
				// This part stays the same:
				tag.name = def.name;
				tag.attributes = def.attributes;
				tag.arguments = def.arguments;
				tag.parent = parent;
				tag.definition = definition;
				tag.parts = [];
				// Setup children list, and previous / next references
				tag.children = [];
				if (parent) {
					var siblings = parent.children;
					tag.previous = siblings[siblings.length - 1];
					if (tag.previous)
						tag.previous.next = tag;
					siblings.push(tag);
				}
				return tag;
			}
		}
	}
});

// The RootTag is there to contain all other markup tags and content parts and
// is produced internally in and returned by Markup.parse. Call render on it
// to render the parsed Markup tree.
RootTag = MarkupTag.extend({
	_tags: 'root',

	// The RootTag's render function is different as it is used to render the whole tree
	// and does not receive content or encoder as parameters.
	render: function(param) {
		if (!param)
			param = {};
		// Determine encoder to be used, default is not encoding anything:
		var encoder = param.encoding && global['encode' + param.encoding.capitalize()]
			|| function(val) { return val };
		// Keep tag objects that need to clean up something in the end. This is
		// only used for resource rendering in Scriptographer right now.
		var cleanUps = {};
		var str = this.renderChildren(param, encoder, cleanUps);
		// See if we need to do some clean up now:
		for (var name in cleanUps)
			cleanUps[name].cleanUp(param);
		return str;
	}
});

// Special tag to render undefined tag names unmodified.
// UndefinedTag#render can be overridden and is handling the rendering of all the undefined tags.
UndefinedTag = MarkupTag.extend({
	_tags: 'undefined',

	render: function(content, param, encoder) {
		return encoder('<' + this.definition + '>')	+ content + encoder('</' + this.name + '>');
	}
});

NodeTag = MarkupTag.extend({
	_tags: 'node',
	_attributes: 'id',

	render: function(content) {
		var id = this.attributes.id;
		if (!id) {
			id = content;
			content = null;
		}
		var node = HopObject.get(id);
		if (node)
			return node.renderLink(content);
	}
});

CodeTag = MarkupTag.extend({
	_tags: 'code',

	render: function(content) {
		return '
' + content.replaceAll('
', '') + '
';
	}
});

ResourceTag = MarkupTag.extend({
	_tags: 'resource',

	getResource: function(name, param) {
		if (!param.resourceLookup) {
			param.resourceLookup = {};
			if (param.resources) {
				for (var i = 0; i < param.resources.length; i++) {
					var resource = param.resources[i]
					param.resourceLookup[resource.name] = { resource: resource, index: i };
				}
			}
		}
		var entry = param.resourceLookup[name];
		if (entry) {
			// Mark as used. Scriptographer extends ResourceTag to remove
			// these in cleanUp
			entry.used = true;
			return entry.resource;
		}
	},

	cleanUp: function(param) {
		if (param.removeUsedResources && param.resources) {
			// Remove the resources that have been flaged 'used'
			for (var i = param.resources.length - 1; i >= 0; i--)
				if (param.resourceLookup[param.resources[i].name].used)
					param.resources.splice(i, 1);
		}
		delete param.resourceLookup;
	},

	// Defined outside render() so it can be overridden by applications.
	renderIcon: function(resource, param) {
		// TODO: pass param, and define small as smallIcon or iconSmall ?
		return resource.renderIcon({ small: true });
	},

	render: function(content, param) {
		var resource = this.getResource(content, param);
		if (resource)
			return this.renderIcon(resource, param);
	}
});

ImageTag = ResourceTag.extend({
	_tags: 'img',

	// Defined outside render() so it can be overridden by applications.
	renderImage: function(picture, param) {
		return picture.renderImage(param);
	},

	render: function(content, param) {
		if (!/^http/.test(content)) {
			var resource = this.getResource(content, param);
			if (resource && resource instanceof Picture)
				return this.renderImage(resource, param);
		} else {
			return '';
		}
	}
});

HtmlTag = MarkupTag.extend({
	_tags: 'i,b,strong,s,strike',

	render: function(content) {
		return '<' + this.definition + (content != null
				? '>' + content + '</' + this.name + '>'
				: '>');
	}
});

BoldTag = MarkupTag.extend({
	_tags: 'bold',

	render: function(content) {
		return '' + content + '';
	}
});

UrlTag = MarkupTag.extend({
	_tags: 'url',
	_attributes: 'url',

	render: function(content, param) {
		var url = this.attributes.url || content;
		var title = content || url;
		var str = '' + title + '';
		return str;
	}
});

QuoteTag = MarkupTag.extend({
	_tags: 'quote',
	_attributes: 'name',

	render: function(content) {
		return '
' + (this.attributes.name
			? this.attributes.name + ' wrote:'
			: 'Quote:')
			+ '

' + content + '
';
	}
});

ListTag = MarkupTag.extend({
	_tags: 'list',

	render: function(content) {
		return '
' + content + '
';
	}
});
<|endoftext|>


<commit_before>/*
 * grunt-font-sampler
 * https://github.com/pedrocorreia/font-sampler
 *
 * Copyright (c) 2014 Pedro Correia
 * Licensed under the MIT license.
 */

'use strict';

var chalk = require('chalk');

module.exports = function(grunt) {

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks

  grunt.registerMultiTask('font_sampler', 'The best Grunt plugin ever.', function() {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      fontname: 'Ink-Icons',
      charmap: 'glyphs.json',
      dest: 'dist/sample.html',
      sizes: [16,18,20,22,24,26,28,30,32,34,36,38,40],
      stylesheets: ["http://cdn.ink.sapo.pt/3.0.2/css/ink.min.css","/css/ink-icons.css"]
    });

    var json = grunt.file.readJSON(options.charmap);
    var chars = json.chars;

    var sampler = grunt.file.read('doc-head.html');

    options.stylesheets.forEach(function(css){
        sampler += '<link rel="stylesheet" type="text/css" href="'+css+'">\n';
    });

    // create sizes css
    sampler += '\n';

    sampler += grunt.file.read('doc-body.html');

    options.sizes.forEach(function(size){
        sampler += '
\n';
        sampler += '
'+ size +'px
\n';
        chars.forEach(function(glyph){
            sampler += '\n';
        });
        sampler += '
\n';
    });

    sampler += grunt.file.read('doc-end.html');

    grunt.file.write(options.dest, sampler);

    grunt.log.writeln('File ' + chalk.cyan(options.dest) + ' created.');

    // // Iterate over all specified file groups.
    // this.files.forEach(function(f) {
    //   // Concat specified files.
    //   var src = f.src.filter(function(filepath) {
    //     // Warn on and remove invalid source files (if nonull was set).
    //     if (!grunt.file.exists(filepath)) {
    //       grunt.log.warn('Source file "' + filepath + '" not found.');
    //       return false;
    //     } else {
    //       return true;
    //     }
    //   }).map(function(filepath) {
    //     // Read file source.
    //     return grunt.file.read(filepath);
    //   }).join(grunt.util.normalizelf(options.separator));
    //
    //   // Handle options.
    //   src += options.punctuation;
    //
    //   // Write the destination file.
    //   grunt.file.write(f.dest, src);
    //
    //   // Print a success message.
    //   grunt.log.writeln('File "' + f.dest + '" created.');
    // });
  });

};
<commit_msg>minor tweaks.<commit_after>/*
 * grunt-font-sampler
 * https://github.com/pedrocorreia/font-sampler
 *
 * Copyright (c) 2014 Pedro Correia
 * Licensed under the MIT license.
 */

'use strict';

var chalk = require('chalk');

module.exports = function(grunt) {

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks

  grunt.registerMultiTask('font_sampler', 'The best Grunt plugin ever.', function() {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      fontname: 'Ink-Icons',
      charmap: 'glyphs.json',
      dest: 'dist/sample.html',
      sizes: [16,18,20,22,24,26,28,30,32,34,36,38,40],
      stylesheets: ["http://cdn.ink.sapo.pt/3.0.2/css/ink.min.css","/css/ink-icons.css"]
    });

    var json = grunt.file.readJSON(options.charmap);
    var chars = json.chars;

    var sampler = grunt.file.read('doc-head.html');

    options.stylesheets.forEach(function(css){
        sampler += '<link rel="stylesheet" type="text/css" href="'+css+'">\n';
    });

    // create sizes css
    sampler += '\n';

    sampler += grunt.file.read('doc-body.html');

    options.sizes.forEach(function(size){
        sampler += '
\n';
        sampler += '
'+ size +'px
\n';
        chars.forEach(function(glyph){
            sampler += '\n';
        });
        sampler += '
\n';
    });

    sampler += grunt.file.read('doc-end.html');

    grunt.file.write(options.dest, sampler);

    grunt.log.writeln('File ' + chalk.cyan(options.dest) + ' created.');

    // // Iterate over all specified file groups.
    // this.files.forEach(function(f) {
    //   // Concat specified files.
    //   var src = f.src.filter(function(filepath) {
    //     // Warn on and remove invalid source files (if nonull was set).
    //     if (!grunt.file.exists(filepath)) {
    //       grunt.log.warn('Source file "' + filepath + '" not found.');
    //       return false;
    //     } else {
    //       return true;
    //     }
    //   }).map(function(filepath) {
    //     // Read file source.
    //     return grunt.file.read(filepath);
    //   }).join(grunt.util.normalizelf(options.separator));
    //
    //   // Handle options.
    //   src += options.punctuation;
    //
    //   // Write the destination file.
    //   grunt.file.write(f.dest, src);
    //
    //   // Print a success message.
    //   grunt.log.writeln('File "' + f.dest + '" created.');
    // });
  });

};
<|endoftext|>


<commit_before>var Display = {
  add_message: function(text, className) {
    var time_html = '\#{time}'.interpolate({ time: this.dateText() });
    $('messages').insert({ bottom: '
' + time_html + ' ' + text + '
' });
    this.scrollMessagesToTop();
  },

  message: function(message) {
    var text = '\#{user} \#{message}';
    text = text.interpolate({ room: message['room'], user: this.truncateName(message['user']), message: this.decorateMessage(message['message']) });
    this.add_message(text, 'message');
  },

  messages: function(messages) {
    messages.each(function(json) {
     this[json['display']](json[json['display']]);
    }.bind(this));
  },

  scrollMessagesToTop: function() {
    $('messages').scrollTop = $('messages').scrollHeight;
  },

  zeroPad: function(value, length) {
    value = value.toString();
    if (value.length >= length) {
      return value;
    } else {
      return this.zeroPad('0' + value, length);
    }
  },

  dateText: function() {
    var d = new Date;
    return this.zeroPad(d.getHours(), 2) + ':' + this.zeroPad(d.getMinutes(), 2);
  },

  truncateName: function(text) {
    return text.truncate(10);
  },

  extractURLs: function(text) {
    return text.match(/(http:\/\/[^\s]*)/g);
  },

  decorateMessage: function(text) {
    try {
      var links = this.extractURLs(text);

      if (links) {
        links.each(function(url) {
          if (url.match(/(jp?g|png|gif)/i)) {
            text = text.replace(url, ''.interpolate({ url: url, image: url }));
          } else {
            text = text.replace(url, '\#{link_name}'.interpolate({ url: url, link_name: url}));
          }
        });
      }
    } catch (exception) {
      console.log(exception);
    }
    return text;
  },

  names: function(names) {
    $('names').innerHTML = '';
    names.each(function(name) {
      $('names').insert({ bottom: '
' + this.truncateName(name) + '
' });
    }.bind(this));
  },

  join: function(join) {
    $('room-name').innerHTML = join['room'];
  },

  join_notice: function(join) {
    $('names').insert({ bottom: '
' + this.truncateName(join['user']) + '
' });
    this.add_message(join['user'] + ' has joined the room', 'server');
  },

  remove_user: function(name) {
    $$('#names li').each(function(element) { if (element.innerHTML == name) element.remove(); });
  },

  part_notice: function(part) {
    this.remove_user(part['user']);
    this.add_message(part['user'] + ' has left the room', 'server');
  },

  quit_notice: function(quit) {
    this.remove_user(quit['user']);
    this.add_message(quit['user'] + ' has quit', 'server');
  }
};

function displayMessages(text) {
  var json_set = text.evalJSON(true);
  if (json_set.length == 0) {
    return;
  }
  json_set.each(function(json) {
    Display[json['display']](json[json['display']]);
  });
}

function updateMessages() {
  new Ajax.Request('/messages', {
    method: 'get',
    parameters: { time: new Date().getTime() },
    onSuccess: function(transport) {
      displayMessages(transport.responseText);
    }
  });
}

function adaptSizes() {
  var windowSize = document.viewport.getDimensions();
  $('messages').setStyle({ width: windowSize.width - 220 + 'px' });
  $('messages').setStyle({ height: windowSize.height - 100 + 'px' });
  $('message').setStyle({ width: windowSize.width - 290 + 'px' });
  Display.scrollMessagesToTop();
}

document.observe('dom:loaded', function() {
  if ($('room') && window.location.hash) {
    $('room').value = window.location.hash;
  }

  if ($('post_message')) {
    adaptSizes();

    Event.observe(window, 'resize', function() {
      adaptSizes();
    });

    new Ajax.Request('/names', {
      method: 'get',
      parameters: { time: new Date().getTime() },
      onFailure: function() { alert('Error connecting'); },
      onSuccess: function(transport) {
        updateMessages();

        new Ajax.Request('/lastlog', {
          method: 'get',
          parameters: { time: new Date().getTime() },
          onSuccess: function() {
            new PeriodicalExecuter(updateMessages, 3);
          },
          onFailure: function() { alert('Error connecting'); }
        });
      }
    });

    $('message').activate();
    $('post_message').observe('submit', function(e) {
      var element = Event.element(e);
      var message = $('message').value;
      $('message').value = '';
      new Ajax.Request('/message', {
        method: 'post',
        parameters: { 'message': message },
        onSuccess: function(transport) {
        }
      });

      Event.stop(e);
    });

    Event.observe(window, 'unload', function() {
      new Ajax.Request('/quit');
    });
  }

  if ($('sign-on')) {
    $('name').activate();
  }
});

<commit_msg>The load order in the previous update was reversed: the lastlog should be downloaded and then the /names list (http client)<commit_after>var Display = {
  add_message: function(text, className) {
    var time_html = '\#{time}'.interpolate({ time: this.dateText() });
    $('messages').insert({ bottom: '
' + time_html + ' ' + text + '
' });
    this.scrollMessagesToTop();
  },

  message: function(message) {
    var text = '\#{user} \#{message}';
    text = text.interpolate({ room: message['room'], user: this.truncateName(message['user']), message: this.decorateMessage(message['message']) });
    this.add_message(text, 'message');
  },

  messages: function(messages) {
    messages.each(function(json) {
     this[json['display']](json[json['display']]);
    }.bind(this));
  },

  scrollMessagesToTop: function() {
    $('messages').scrollTop = $('messages').scrollHeight;
  },

  zeroPad: function(value, length) {
    value = value.toString();
    if (value.length >= length) {
      return value;
    } else {
      return this.zeroPad('0' + value, length);
    }
  },

  dateText: function() {
    var d = new Date;
    return this.zeroPad(d.getHours(), 2) + ':' + this.zeroPad(d.getMinutes(), 2);
  },

  truncateName: function(text) {
    return text.truncate(10);
  },

  extractURLs: function(text) {
    return text.match(/(http:\/\/[^\s]*)/g);
  },

  decorateMessage: function(text) {
    try {
      var links = this.extractURLs(text);

      if (links) {
        links.each(function(url) {
          if (url.match(/(jp?g|png|gif)/i)) {
            text = text.replace(url, ''.interpolate({ url: url, image: url }));
          } else {
            text = text.replace(url, '\#{link_name}'.interpolate({ url: url, link_name: url}));
          }
        });
      }
    } catch (exception) {
      console.log(exception);
    }
    return text;
  },

  names: function(names) {
    $('names').innerHTML = '';
    names.each(function(name) {
      $('names').insert({ bottom: '
' + this.truncateName(name) + '
' });
    }.bind(this));
  },

  join: function(join) {
    $('room-name').innerHTML = join['room'];
  },

  join_notice: function(join) {
    $('names').insert({ bottom: '
' + this.truncateName(join['user']) + '
' });
    this.add_message(join['user'] + ' has joined the room', 'server');
  },

  remove_user: function(name) {
    $$('#names li').each(function(element) { if (element.innerHTML == name) element.remove(); });
  },

  part_notice: function(part) {
    this.remove_user(part['user']);
    this.add_message(part['user'] + ' has left the room', 'server');
  },

  quit_notice: function(quit) {
    this.remove_user(quit['user']);
    this.add_message(quit['user'] + ' has quit', 'server');
  }
};

function displayMessages(text) {
  var json_set = text.evalJSON(true);
  if (json_set.length == 0) {
    return;
  }
  json_set.each(function(json) {
    Display[json['display']](json[json['display']]);
  });
}

function updateMessages() {
  new Ajax.Request('/messages', {
    method: 'get',
    parameters: { time: new Date().getTime() },
    onSuccess: function(transport) {
      displayMessages(transport.responseText);
    }
  });
}

function adaptSizes() {
  var windowSize = document.viewport.getDimensions();
  $('messages').setStyle({ width: windowSize.width - 220 + 'px' });
  $('messages').setStyle({ height: windowSize.height - 100 + 'px' });
  $('message').setStyle({ width: windowSize.width - 290 + 'px' });
  Display.scrollMessagesToTop();
}

document.observe('dom:loaded', function() {
  if ($('room') && window.location.hash) {
    $('room').value = window.location.hash;
  }

  if ($('post_message')) {
    adaptSizes();

    Event.observe(window, 'resize', function() {
      adaptSizes();
    });

    new Ajax.Request('/lastlog', {
      method: 'get',
      parameters: { time: new Date().getTime() },
      onFailure: function() { alert('Error connecting'); },
      onSuccess: function(transport) {
        updateMessages();

        new Ajax.Request('/names', {
          method: 'get',
          parameters: { time: new Date().getTime() },
          onSuccess: function() {
            new PeriodicalExecuter(updateMessages, 3);
          },
          onFailure: function() { alert('Error connecting'); }
        });
      }
    });

    $('message').activate();
    $('post_message').observe('submit', function(e) {
      var element = Event.element(e);
      var message = $('message').value;
      $('message').value = '';
      new Ajax.Request('/message', {
        method: 'post',
        parameters: { 'message': message },
        onSuccess: function(transport) {
        }
      });

      Event.stop(e);
    });

    Event.observe(window, 'unload', function() {
      new Ajax.Request('/quit');
    });
  }

  if ($('sign-on')) {
    $('name').activate();
  }
});

<|endoftext|>


<commit_before>module.exports = function(grunt) {
    "use strict";
    // Please see the grunt documentation for more information regarding task and
    // helper creation: https://github.com/gruntjs/grunt/blob/master/docs/toc.md
    // ==========================================================================
    // TASKS
    // ==========================================================================
    grunt.task.registerMultiTask('jsbeautifier', 'jsbeautifier.org for grunt', function() {

        var beautify = require('js-beautify').js_beautify;
        var params = this.options();
        var fileCount = 0;

        if (this.filesSrc) {
            grunt.verbose.writeln('Beautifing using filesSrc with ' + this.filesSrc.length.toString().cyan + ' files...');
            this.filesSrc.forEach(function(src) {
                if (grunt.file.isDir(src)) {
                    return;
                }

                var result = grunt.file.read(src);
                grunt.verbose.write('Beautifing ' + src.cyan + '...');
                result = beautify(result, params);
                result += '\n';
                grunt.verbose.ok();
                grunt.file.write(src, result);
                fileCount++;
            });
        }
        grunt.log.write('Beautified ' + fileCount.toString().cyan + ' files...');
        grunt.log.ok();
    });
};
<commit_msg>No longer re-writes unchanged files.<commit_after>module.exports = function(grunt) {
    "use strict";
    // Please see the grunt documentation for more information regarding task and
    // helper creation: https://github.com/gruntjs/grunt/blob/master/docs/toc.md
    // ==========================================================================
    // TASKS
    // ==========================================================================
    grunt.task.registerMultiTask('jsbeautifier', 'jsbeautifier.org for grunt', function() {

        var beautify = require('js-beautify').js_beautify;
        var params = this.options();
        var fileCount = 0;
        var changedFileCount = 0;

        if (this.filesSrc) {
            grunt.verbose.writeln('Beautifing using filesSrc with ' + this.filesSrc.length.toString().cyan + ' files...');
            this.filesSrc.forEach(function(src) {
                if (grunt.file.isDir(src)) {
                    return;
                }

                var original = grunt.file.read(src);
                grunt.verbose.write('Beautifing ' + src.cyan + '...');
                var result = beautify(original, params);
                result += '\n';
                grunt.verbose.ok();
                if (original !== result) {
                    grunt.file.write(src, result);
                    changedFileCount++;
                }
                fileCount++;
            });
        }
        grunt.log.write('Beautified ' + fileCount.toString().cyan + ' files, changed ' + changedFileCount.toString().cyan + ' files...');
        grunt.log.ok();
    });
};
<|endoftext|>


<commit_before>$(function () {
    'use strict';

    function initTables() {
        var cardView = false;

        if ($(window).width() < 640) {
            cardView = true;
        }

        $('#table, #column, #event, #method, #localization').bootstrapTable('destroy');

        $('#table').bootstrapTable({
            cardView: cardView,
            columns: [
                {field: 'name', title: 'Name', align: 'center', width: 60, sortable: true},
                {field: 'type', title: 'Type', align: 'center', width: 60},
                {field: 'description', title: 'Description', width: 400},
                {field: 'default', title: 'Default', align: '', width: 180}
            ],
            data: [
                {
                    name: 'bootstrapVersion',
                    type: 'Number',
                    description: 'Bootstrap version.',
                    'default': '3'
                },
                {
                    name: 'classes',
                    type: 'String',
                    description: 'The class name of table.',
                    'default': 'table table-hover'
                },
                {
                    name: 'height',
                    type: 'Number',
                    description: 'The height of table.',
                    'default': 'undefined'
                },
                {
                    name: 'undefinedText',
                    type: 'String',
                    description: 'Defines the default undefined text.',
                    'default': '-'
                },
                {
                    name: 'striped',
                    type: 'Boolean',
                    description: 'True to stripe the rows.',
                    'default': 'false'
                },
                {
                    name: 'sortName',
                    type: 'String',
                    description: 'Defines which column can be sorted.',
                    'default': 'undefined'
                },
                {
                    name: 'sortOrder',
                    type: 'String',
                    description: 'Defines the column sort order, can only be "asc" or "desc".',
                    'default': 'asc'
                },
                {
                    name: 'columns',
                    type: 'Array',
                    description: 'The table columns config object, see column properties for more details.',
                    'default': '[]'
                },
                {
                    name: 'data',
                    type: 'Array',
                    description: 'The data to be loaded.',
                    'default': '[]'
                },
                {
                    name: 'method',
                    type: 'String',
                    description: 'The method type to request remote data.',
                    'default': 'get'
                },
                {
                    name: 'url',
                    type: 'String',
                    description: 'A URL to request data from remote site.',
                    'default': 'undefined'
                },
                {
                    name: 'contentType',
                    type: 'String',
                    description: 'The contentType of request remote data.',
                    'default': 'application/json'
                },
                {
                    name: 'queryParams',
                    type: 'Function',
                    description: 'When request remote data, sending additional parameters by format the queryParams, the parameters object contains:
pageSize, pageNumber, searchText, sortName, sortOrder.',
                    'default': 'function(params) {
return {};
}'
                },
                {
                    name: 'pagination',
                    type: 'Boolean',
                    description: 'True to show a pagination toolbar on datagrid bottom.',
                    'default': 'false'
                },
                {
                    name: 'sidePagination',
                    type: 'String',
                    description: 'Defines the side pagination of table, can only be "client" or "server".',
                    'default': 'client'
                },
                {
                    name: 'totalRows',
                    type: 'Number',
                    description: 'Defines the total rows of table, you need to set this option when the sidePagination option is set to "server".',
                    'default': 0
                },
                {
                    name: 'pageNumber',
                    type: 'Number',
                    description: 'When set pagination property, initialize the page number.',
                    'default': 1
                },
                {
                    name: 'pageSize',
                    type: 'Number',
                    description: 'When set pagination property, initialize the page size.',
                    'default': 10
                },
                {
                    name: 'pageList',
                    type: 'Array',
                    description: 'When set pagination property, initialize the page size selecting list.',
                    'default': '[10, 25, 50, 100]'
                },
                {
                    name: 'search',
                    type: 'Boolean',
                    description: 'Enable the search input.',
                    'default': 'false'
                },
                {
                    name: 'selectItemName',
                    type: 'String',
                    description: 'The name of radio or checkbox input.',
                    'default': 'btSelectItem'
                },
                {
                    name: 'showHeader',
                    type: 'Boolean',
                    description: 'False to hide the table header.',
                    'default': 'true'
                },
                {
                    name: 'showColumns',
                    type: 'Boolean',
                    description: 'True to show the columns drop down list.',
                    'default': 'false'
                },
                {
                    name: 'idField',
                    type: 'String',
                    description: 'Indicate which field is an identity field.',
                    'default': 'undefined'
                },
                {
                    name: 'cardView',
                    type: 'Boolean',
                    description: 'True to show card view table, for example mobile view.',
                    'default': 'false'
                },
                {
                    name: 'clickToSelect',
                    type: 'Boolean',
                    description: 'True to select checkbox or radiobox when click rows.',
                    'default': 'false'
                },
                {
                    name: 'singleSelect',
                    type: 'Boolean',
                    description: 'True to allow checkbox selecting only one row.',
                    'default': 'false'
                },
                {
                    name: 'toolbar',
                    type: 'String',
                    description: 'A jQuery selector that indicate the toolbar, for example:
#toolbar, .toolbar.',
                    'default': 'undefined'
                },
                {
                    name: 'rowStyle',
                    type: 'Function',
                    description: 'The row formatter function, take two parameters:
row: the row record data.
index: the row index.
Support classes or css, code example:
{
classes: "red",
css: {background: "red", color: "white"}
}',
                    'default': '{}'
                }
            ]
        });
        $('#column').bootstrapTable({
            cardView: cardView,
            columns: [
                {field: 'name', title: 'Name', align: 'center', valign: 'middle', width: 60, sortable: true},
                {field: 'type', title: 'Type', align: 'center', valign: 'middle', width: 60},
                {field: 'description', title: 'Description', width: 400},
                {field: 'default', title: 'Default', align: 'right', valign: 'middle', width: 180}
            ],
            data: [
                {
                    name: 'radio',
                    type: 'Boolean',
                    description: 'True to show a radio. The radio column has fixed width.',
                    'default': 'false'
                },
                {
                    name: 'checkbox',
                    type: 'Boolean',
                    description: 'True to show a checkbox. The checkbox column has fixed width.',
                    'default': 'false'
                },
                {
                    name: 'field',
                    type: 'String',
                    description: 'The column field name.',
                    'default': 'undefined'
                },
                {
                    name: 'title',
                    type: 'String',
                    description: 'The column title text.',
                    'default': 'undefined'
                },
                {
                    name: 'align',
                    type: 'String',
                    description: 'Indicate how to align the column data. "left", "right", "center" can be used.',
                    'default': 'undefined'},
                {
                    name: 'valign',
                    type: 'String',
                    description: 'Indicate how to align the cell data. "top", "middle", "bottom" can be used.',
                    'default': 'undefined'
                },
                {
                    name: 'width',
                    type: 'Number',
                    description: 'The width of column. If not defined, the width will auto expand to fit its contents.',
                    'default': 'undefined'},
                {
                    name: 'sortable',
                    type: 'Boolean',
                    description: 'True to allow the column can be sorted.',
                    'default': 'false'
                },
                {
                    name: 'order',
                    type: 'String',
                    description: 'The default sort order, can only be "asc" or "desc".',
                    'default': 'asc'
                },
                {
                    name: 'visible',
                    type: 'Boolean',
                    description: 'True to visible the columns item.',
                    'default': 'true'
                },
                {
                    name: 'formatter',
                    type: 'Function',
                    description: 'The cell formatter function, take two parameters:
value: the field value.
row: the row record data.
index: the row index.',
                    'default': 'undefined'
                },
                {
                    name: 'sorter',
                    type: 'Function',
                    description: 'The custom field sort function that used to do local sorting, take two parameters:
a: the first field value.
 b: the second field value.',
                    'default': 'undefined'
                }
            ]
        });
        $('#event').bootstrapTable({
            cardView: cardView,
            columns: [
                {field: 'name', title: 'Option Event', align: 'center', valign: 'middle', width: 100, sortable: true},
                {field: 'event', title: 'jQuery Event', align: 'center', valign: 'middle', width: 100, sortable: true},
                {field: 'parameter', title: 'Parameter', align: 'center', valign: 'middle', width: 100, sortable: true},
                {field: 'description', title: 'Description', width: 400, sortable: true}
            ],
            data: [
                {
                    name: 'onAll',
                    event: 'all.bs.table',
                    parameter: 'name, args',
                    description: 'Fires when all events trigger, the parameters contains:
name: the event name,
args: the event data.'
                },
                {
                    name: 'onClickRow',
                    event: 'click-row.bs.table',
                    parameter: 'row, $element',
                    description: 'Fires when user click a row, the parameters contains:
row: the record corresponding to the clicked row,
$element: the tr element.'
                },
                {
                    name: 'onDblClickRow',
                    event: 'dbl-click-row.bs.table',
                    parameter: 'row, $element',
                    description: 'Fires when user click a row, the parameters contains:
row: the record corresponding to the clicked row,
$element: the tr element.'
                },
                {
                    name: 'onSort',
                    event: 'sort.bs.table',
                    parameter: 'name, order',
                    description: 'Fires when user sort a column, the parameters contains:
name: the sort column field name
order: the sort column order.'
                },
                {
                    name: 'onCheck',
                    event: 'check.bs.table',
                    parameter: 'row',
                    description: 'Fires when user check a row, the parameters contains:
row: the record corresponding to the clicked row.'
                },
                {
                    name: 'onUncheck',
                    event: 'uncheck.bs.table',
                    parameter: 'row',
                    description: 'Fires when user uncheck a row, the parameters contains:
row: the record corresponding to the clicked row.'
                },
                {
                    name: 'onCheckAll',
                    event: 'check-all.bs.table',
                    parameter: 'none',
                    description: 'Fires when user check all rows.'
                },
                {
                    name: 'onUncheckAll',
                    event: 'uncheck-all.bs.table',
                    parameter: 'none',
                    description: 'Fires when user uncheck all rows.'
                },
                {
                    name: 'onLoadSuccess',
                    event: 'load-success.bs.table',
                    parameter: 'data',
                    description: 'Fires when remote data is loaded successfully.'
                },
                {
                    name: 'onLoadError',
                    event: 'load-error.bs.table',
                    parameter: 'status',
                    description: 'Fires when some errors occur to load remote data.'
                },
                {
                    name: 'onBeforeLoad',
                    event: 'before-load.bs.table',
                    parameter: 'res',
                    description: 'Fires before a request is made to load data.'
                }
            ],
            onClickRow: function (row) {
                console.log('onClickRow', row);
            },
            onSort: function (name, order) {
                console.log('onSort', name, order);
            },
            onCheck: function(row) {
                console.log('onCheck', row);
            },
            onUncheck: function(row) {
                console.log('onUncheck', row);
            },
            onCheckAll: function() {
                console.log('onCheckAll');
            },
            onUncheckAll: function() {
                console.log('onUncheckAll');
            }
        });
        $('#method').bootstrapTable({
            cardView: cardView,
            columns: [
                {field: 'name', title: 'Name', align: 'center', valign: 'middle', width: 100},
                {field: 'parameter', title: 'Parameter', align: 'center', valign: 'middle', width: 100},
                {field: 'description', title: 'Description', width: 400}
            ]
        }).bootstrapTable('load', [
                {name: 'getSelections', parameter: 'none', description: 'Return all selected rows, when no record selected, am empty array will return.'},
                {name: 'load', parameter: 'data', description: 'Load the data to table.'}
            ]).bootstrapTable('append', [
                {name: 'append', parameter: 'data', description: 'Append the data to table.'},
                {name: 'mergeCells', parameter: 'options', description: 'Merge some cells to one cell, the options contains following properties:'},
                {name: 'mergeCells', parameter: 'options', description: 'index: the row index.'},
                {name: 'mergeCells', parameter: 'options', description: 'field: the field name.'},
                {name: 'mergeCells', parameter: 'options', description: 'rowspan: the rowspan count to be merged.'},
                {name: 'mergeCells', parameter: 'options', description: 'colspan: the colspan count to be merged.'},
                {name: 'refresh', parameter: 'none', description: 'Refresh the remote server data.'},
                {name: 'showLoading', parameter: 'none', description: 'Show loading status.'},
                {name: 'hideLoading', parameter: 'none', description: 'Hide loading status.'},
                {name: 'checkAll', parameter: 'none', description: 'Check all current page rows.'},
                {name: 'uncheckAll', parameter: 'none', description: 'Uncheck all current page rows.'},
                {name: 'resetView', parameter: 'none', description: 'Reset the bootstrap table view, like display error when init the table with display: none.'},
                {name: 'destroy', parameter: 'none', description: 'Destroy the bootstrap table.'}
            ]).bootstrapTable('mergeCells', {
                index: 3,
                field: 'name',
                rowspan: 5
            }).bootstrapTable('mergeCells', {
                index: 3,
                field: 'parameter',
                rowspan: 5
            });

        $('#localization').bootstrapTable({
            cardView: cardView,
            columns: [
                {field: 'name', title: 'Name', align: 'center', valign: 'middle', width: 100},
                {field: 'parameter', title: 'Parameter', align: 'center', valign: 'middle', width: 100},
                {field: 'default', title: 'Default', align: 'center', valign: 'middle', width: 200}
            ],
            data: [{
                name: 'formatLoadingMessage',
                parameter: '-',
                'default': 'Loading, please wait…'
            }, {
                name: 'formatRecordsPerPage',
                parameter: 'pageNumber',
                'default': '%s records per page'
            }, {
                name: 'formatShowingRows',
                parameter: 'pageFrom, pageTo, totalRows',
                'default': 'Showing %s to %s of %s rows'
            }, {
                name: 'formatSearch',
                parameter: '-',
                'default': 'Search'
            }, {
                name: 'formatNoMatches',
                parameter: '-',
                'default': 'No matching records found'
            }]
        });
    }

    var $window = $(window);
    var $body = $(document.body);

    var navHeight = $('.navbar').outerHeight(true) + 10;

    $body.scrollspy({
        target: '.bs-sidebar',
        offset: navHeight
    });

    $window.on('load', function () {
        $body.scrollspy('refresh')
    });

    $window.on('resize', function() {
        initTables();
    });

    // affix
    setTimeout(function () {
        var $sideBar = $('.bs-sidebar');

        $sideBar.affix({
            offset: {
                top: function () {
                    var offsetTop = $sideBar.offset().top;
                    var sideBarMargin = parseInt($sideBar.children(0).css('margin-top'), 10);
                    var navOuterHeight = $('.bs-docs-nav').height();

                    return (this.top = offsetTop - navOuterHeight - sideBarMargin);
                },
                bottom: function () {
                    return (this.bottom = $('.bs-footer').outerHeight(true));
                }
            }
        });
    }, 100);

    initTables();
});<commit_msg>Update docs.<commit_after>$(function () {
    'use strict';

    function initTables() {
        var cardView = false;

        if ($(window).width() < 640) {
            cardView = true;
        }

        $('#table, #column, #event, #method, #localization').bootstrapTable('destroy');

        $('#table').bootstrapTable({
            cardView: cardView,
            columns: [
                {field: 'name', title: 'Name', align: 'center', width: 60, sortable: true},
                {field: 'type', title: 'Type', align: 'center', width: 60},
                {field: 'description', title: 'Description', width: 400},
                {field: 'default', title: 'Default', align: '', width: 180}
            ],
            data: [
                {
                    name: 'bootstrapVersion',
                    type: 'Number',
                    description: 'Bootstrap version.',
                    'default': '3'
                },
                {
                    name: 'classes',
                    type: 'String',
                    description: 'The class name of table.',
                    'default': 'table table-hover'
                },
                {
                    name: 'height',
                    type: 'Number',
                    description: 'The height of table.',
                    'default': 'undefined'
                },
                {
                    name: 'undefinedText',
                    type: 'String',
                    description: 'Defines the default undefined text.',
                    'default': '-'
                },
                {
                    name: 'striped',
                    type: 'Boolean',
                    description: 'True to stripe the rows.',
                    'default': 'false'
                },
                {
                    name: 'sortName',
                    type: 'String',
                    description: 'Defines which column can be sorted.',
                    'default': 'undefined'
                },
                {
                    name: 'sortOrder',
                    type: 'String',
                    description: 'Defines the column sort order, can only be "asc" or "desc".',
                    'default': 'asc'
                },
                {
                    name: 'columns',
                    type: 'Array',
                    description: 'The table columns config object, see column properties for more details.',
                    'default': '[]'
                },
                {
                    name: 'data',
                    type: 'Array',
                    description: 'The data to be loaded.',
                    'default': '[]'
                },
                {
                    name: 'method',
                    type: 'String',
                    description: 'The method type to request remote data.',
                    'default': 'get'
                },
                {
                    name: 'url',
                    type: 'String',
                    description: 'A URL to request data from remote site.',
                    'default': 'undefined'
                },
                {
                    name: 'contentType',
                    type: 'String',
                    description: 'The contentType of request remote data.',
                    'default': 'application/json'
                },
                {
                    name: 'queryParams',
                    type: 'Function',
                    description: 'When request remote data, sending additional parameters by format the queryParams, the parameters object contains:
pageSize, pageNumber, searchText, sortName, sortOrder.',
                    'default': 'function(params) {
return {};
}'
                },
                {
                    name: 'pagination',
                    type: 'Boolean',
                    description: 'True to show a pagination toolbar on datagrid bottom.',
                    'default': 'false'
                },
                {
                    name: 'sidePagination',
                    type: 'String',
                    description: 'Defines the side pagination of table, can only be "client" or "server".',
                    'default': 'client'
                },
                {
                    name: 'totalRows',
                    type: 'Number',
                    description: 'Defines the total rows of table, you need to set this option when the sidePagination option is set to "server".',
                    'default': 0
                },
                {
                    name: 'pageNumber',
                    type: 'Number',
                    description: 'When set pagination property, initialize the page number.',
                    'default': 1
                },
                {
                    name: 'pageSize',
                    type: 'Number',
                    description: 'When set pagination property, initialize the page size.',
                    'default': 10
                },
                {
                    name: 'pageList',
                    type: 'Array',
                    description: 'When set pagination property, initialize the page size selecting list.',
                    'default': '[10, 25, 50, 100]'
                },
                {
                    name: 'search',
                    type: 'Boolean',
                    description: 'Enable the search input.',
                    'default': 'false'
                },
                {
                    name: 'selectItemName',
                    type: 'String',
                    description: 'The name of radio or checkbox input.',
                    'default': 'btSelectItem'
                },
                {
                    name: 'showHeader',
                    type: 'Boolean',
                    description: 'False to hide the table header.',
                    'default': 'true'
                },
                {
                    name: 'showColumns',
                    type: 'Boolean',
                    description: 'True to show the columns drop down list.',
                    'default': 'false'
                },
                {
                    name: 'idField',
                    type: 'String',
                    description: 'Indicate which field is an identity field.',
                    'default': 'undefined'
                },
                {
                    name: 'cardView',
                    type: 'Boolean',
                    description: 'True to show card view table, for example mobile view.',
                    'default': 'false'
                },
                {
                    name: 'clickToSelect',
                    type: 'Boolean',
                    description: 'True to select checkbox or radiobox when click rows.',
                    'default': 'false'
                },
                {
                    name: 'singleSelect',
                    type: 'Boolean',
                    description: 'True to allow checkbox selecting only one row.',
                    'default': 'false'
                },
                {
                    name: 'toolbar',
                    type: 'String',
                    description: 'A jQuery selector that indicate the toolbar, for example:
#toolbar, .toolbar.',
                    'default': 'undefined'
                },
                {
                    name: 'rowStyle',
                    type: 'Function',
                    description: 'The row formatter function, take two parameters:
row: the row record data.
index: the row index.
Support classes or css, code example:

return {
    classes: "red",
    css: {background: "red", color: "white"}
}
',
                    'default': '{}'
                }
            ]
        });
        $('#column').bootstrapTable({
            cardView: cardView,
            columns: [
                {field: 'name', title: 'Name', align: 'center', valign: 'middle', width: 60, sortable: true},
                {field: 'type', title: 'Type', align: 'center', valign: 'middle', width: 60},
                {field: 'description', title: 'Description', width: 400},
                {field: 'default', title: 'Default', align: 'right', valign: 'middle', width: 180}
            ],
            data: [
                {
                    name: 'radio',
                    type: 'Boolean',
                    description: 'True to show a radio. The radio column has fixed width.',
                    'default': 'false'
                },
                {
                    name: 'checkbox',
                    type: 'Boolean',
                    description: 'True to show a checkbox. The checkbox column has fixed width.',
                    'default': 'false'
                },
                {
                    name: 'field',
                    type: 'String',
                    description: 'The column field name.',
                    'default': 'undefined'
                },
                {
                    name: 'title',
                    type: 'String',
                    description: 'The column title text.',
                    'default': 'undefined'
                },
                {
                    name: 'align',
                    type: 'String',
                    description: 'Indicate how to align the column data. "left", "right", "center" can be used.',
                    'default': 'undefined'},
                {
                    name: 'valign',
                    type: 'String',
                    description: 'Indicate how to align the cell data. "top", "middle", "bottom" can be used.',
                    'default': 'undefined'
                },
                {
                    name: 'width',
                    type: 'Number',
                    description: 'The width of column. If not defined, the width will auto expand to fit its contents.',
                    'default': 'undefined'},
                {
                    name: 'sortable',
                    type: 'Boolean',
                    description: 'True to allow the column can be sorted.',
                    'default': 'false'
                },
                {
                    name: 'order',
                    type: 'String',
                    description: 'The default sort order, can only be "asc" or "desc".',
                    'default': 'asc'
                },
                {
                    name: 'visible',
                    type: 'Boolean',
                    description: 'True to visible the columns item.',
                    'default': 'true'
                },
                {
                    name: 'formatter',
                    type: 'Function',
                    description: 'The cell formatter function, take two parameters:
value: the field value.
row: the row record data.
index: the row index.',
                    'default': 'undefined'
                },
                {
                    name: 'sorter',
                    type: 'Function',
                    description: 'The custom field sort function that used to do local sorting, take two parameters:
a: the first field value.
 b: the second field value.',
                    'default': 'undefined'
                }
            ]
        });
        $('#event').bootstrapTable({
            cardView: cardView,
            columns: [
                {field: 'name', title: 'Option Event', align: 'center', valign: 'middle', width: 100, sortable: true},
                {field: 'event', title: 'jQuery Event', align: 'center', valign: 'middle', width: 100, sortable: true},
                {field: 'parameter', title: 'Parameter', align: 'center', valign: 'middle', width: 100, sortable: true},
                {field: 'description', title: 'Description', width: 400, sortable: true}
            ],
            data: [
                {
                    name: 'onAll',
                    event: 'all.bs.table',
                    parameter: 'name, args',
                    description: 'Fires when all events trigger, the parameters contains:
name: the event name,
args: the event data.'
                },
                {
                    name: 'onClickRow',
                    event: 'click-row.bs.table',
                    parameter: 'row, $element',
                    description: 'Fires when user click a row, the parameters contains:
row: the record corresponding to the clicked row,
$element: the tr element.'
                },
                {
                    name: 'onDblClickRow',
                    event: 'dbl-click-row.bs.table',
                    parameter: 'row, $element',
                    description: 'Fires when user click a row, the parameters contains:
row: the record corresponding to the clicked row,
$element: the tr element.'
                },
                {
                    name: 'onSort',
                    event: 'sort.bs.table',
                    parameter: 'name, order',
                    description: 'Fires when user sort a column, the parameters contains:
name: the sort column field name
order: the sort column order.'
                },
                {
                    name: 'onCheck',
                    event: 'check.bs.table',
                    parameter: 'row',
                    description: 'Fires when user check a row, the parameters contains:
row: the record corresponding to the clicked row.'
                },
                {
                    name: 'onUncheck',
                    event: 'uncheck.bs.table',
                    parameter: 'row',
                    description: 'Fires when user uncheck a row, the parameters contains:
row: the record corresponding to the clicked row.'
                },
                {
                    name: 'onCheckAll',
                    event: 'check-all.bs.table',
                    parameter: 'none',
                    description: 'Fires when user check all rows.'
                },
                {
                    name: 'onUncheckAll',
                    event: 'uncheck-all.bs.table',
                    parameter: 'none',
                    description: 'Fires when user uncheck all rows.'
                },
                {
                    name: 'onLoadSuccess',
                    event: 'load-success.bs.table',
                    parameter: 'data',
                    description: 'Fires when remote data is loaded successfully.'
                },
                {
                    name: 'onLoadError',
                    event: 'load-error.bs.table',
                    parameter: 'status',
                    description: 'Fires when some errors occur to load remote data.'
                },
                {
                    name: 'onBeforeLoad',
                    event: 'before-load.bs.table',
                    parameter: 'res',
                    description: 'Fires before a request is made to load data.'
                }
            ],
            onClickRow: function (row) {
                console.log('onClickRow', row);
            },
            onSort: function (name, order) {
                console.log('onSort', name, order);
            },
            onCheck: function(row) {
                console.log('onCheck', row);
            },
            onUncheck: function(row) {
                console.log('onUncheck', row);
            },
            onCheckAll: function() {
                console.log('onCheckAll');
            },
            onUncheckAll: function() {
                console.log('onUncheckAll');
            }
        });
        $('#method').bootstrapTable({
            cardView: cardView,
            columns: [
                {field: 'name', title: 'Name', align: 'center', valign: 'middle', width: 100},
                {field: 'parameter', title: 'Parameter', align: 'center', valign: 'middle', width: 100},
                {field: 'description', title: 'Description', width: 400}
            ]
        }).bootstrapTable('load', [
                {name: 'getSelections', parameter: 'none', description: 'Return all selected rows, when no record selected, am empty array will return.'},
                {name: 'load', parameter: 'data', description: 'Load the data to table.'}
            ]).bootstrapTable('append', [
                {name: 'append', parameter: 'data', description: 'Append the data to table.'},
                {name: 'mergeCells', parameter: 'options', description: 'Merge some cells to one cell, the options contains following properties:'},
                {name: 'mergeCells', parameter: 'options', description: 'index: the row index.'},
                {name: 'mergeCells', parameter: 'options', description: 'field: the field name.'},
                {name: 'mergeCells', parameter: 'options', description: 'rowspan: the rowspan count to be merged.'},
                {name: 'mergeCells', parameter: 'options', description: 'colspan: the colspan count to be merged.'},
                {name: 'refresh', parameter: 'none', description: 'Refresh the remote server data.'},
                {name: 'showLoading', parameter: 'none', description: 'Show loading status.'},
                {name: 'hideLoading', parameter: 'none', description: 'Hide loading status.'},
                {name: 'checkAll', parameter: 'none', description: 'Check all current page rows.'},
                {name: 'uncheckAll', parameter: 'none', description: 'Uncheck all current page rows.'},
                {name: 'resetView', parameter: 'none', description: 'Reset the bootstrap table view, like display error when init the table with display: none.'},
                {name: 'destroy', parameter: 'none', description: 'Destroy the bootstrap table.'}
            ]).bootstrapTable('mergeCells', {
                index: 3,
                field: 'name',
                rowspan: 5
            }).bootstrapTable('mergeCells', {
                index: 3,
                field: 'parameter',
                rowspan: 5
            });

        $('#localization').bootstrapTable({
            cardView: cardView,
            columns: [
                {field: 'name', title: 'Name', align: 'center', valign: 'middle', width: 100},
                {field: 'parameter', title: 'Parameter', align: 'center', valign: 'middle', width: 100},
                {field: 'default', title: 'Default', align: 'center', valign: 'middle', width: 200}
            ],
            data: [{
                name: 'formatLoadingMessage',
                parameter: '-',
                'default': 'Loading, please wait…'
            }, {
                name: 'formatRecordsPerPage',
                parameter: 'pageNumber',
                'default': '%s records per page'
            }, {
                name: 'formatShowingRows',
                parameter: 'pageFrom, pageTo, totalRows',
                'default': 'Showing %s to %s of %s rows'
            }, {
                name: 'formatSearch',
                parameter: '-',
                'default': 'Search'
            }, {
                name: 'formatNoMatches',
                parameter: '-',
                'default': 'No matching records found'
            }]
        });
    }

    var $window = $(window);
    var $body = $(document.body);

    var navHeight = $('.navbar').outerHeight(true) + 10;

    $body.scrollspy({
        target: '.bs-sidebar',
        offset: navHeight
    });

    $window.on('load', function () {
        $body.scrollspy('refresh')
    });

    $window.on('resize', function() {
        initTables();
    });

    // affix
    setTimeout(function () {
        var $sideBar = $('.bs-sidebar');

        $sideBar.affix({
            offset: {
                top: function () {
                    var offsetTop = $sideBar.offset().top;
                    var sideBarMargin = parseInt($sideBar.children(0).css('margin-top'), 10);
                    var navOuterHeight = $('.bs-docs-nav').height();

                    return (this.top = offsetTop - navOuterHeight - sideBarMargin);
                },
                bottom: function () {
                    return (this.bottom = $('.bs-footer').outerHeight(true));
                }
            }
        });
    }, 100);

    initTables();
});<|endoftext|>