Created
February 21, 2009 09:12
-
-
Save daqing/67964 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * BBCode.js - javascript BBCode module by Zhang Qingcheng <kinch.zhang@gmail.com> | |
| * | |
| * usage: | |
| * | |
| * 1. load this module | |
| * <script type="text/javascript" src="<?php echo get_domain_name_by_app('js', true);?>/c/BBCode.js"></script> | |
| * | |
| * 2. get an instance to use it | |
| * <script type="text/javascript"> | |
| * var bbcode = new BBCode(); | |
| * | |
| * if (! bbcode.isValid(bbcode)) | |
| * { | |
| * alert('bbcode is invalid!'); | |
| * | |
| * return false; | |
| * } | |
| * </script> | |
| * | |
| */ | |
| (function(){ | |
| var BBCode = window.BBCode = function() {} | |
| BBCode.prototype = { | |
| /** | |
| * check if the given bbcode is valid | |
| * | |
| * @param String bbcode | |
| * @returns Boolean true/false | |
| * @description this function returns true if the given bbcode in well-formed | |
| */ | |
| 'isValid' : function(content) { | |
| /* | |
| * 检查一段内容中包含的UBB的格式是否正确 | |
| * | |
| */ | |
| if (content.length == 0) | |
| return false; | |
| var stack = []; | |
| var depth = 0; | |
| var errors = 0; | |
| var unmatched = 0; | |
| var options = { | |
| 'b' : 'no_arg', | |
| 'i' : 'no_arg', | |
| 'u' : 'no_arg', | |
| 'url' : 'opt_arg', | |
| 'img' : 'no_arg', | |
| 'swf' : 'no_arg', | |
| 'wmv' : 'no_arg', | |
| 'rm' : 'no_arg', | |
| 'media' : 'arg', | |
| 'size' : 'arg', | |
| 'quote' : 'no_arg', | |
| 'list' : 'opt_arg', | |
| 'color' : 'arg', | |
| 'dstaic' : 'no_arg', | |
| 'attach' : 'no_arg', | |
| 'align' : 'arg', | |
| 'p' : 'no_arg', | |
| 'font': 'arg', | |
| 'color' : 'arg', | |
| 'table' : 'opt_arg', | |
| 'tr' : 'opt_arg', | |
| 'td' : 'opt_arg', | |
| 'desc' : 'no_arg', | |
| 'hide' : 'no_arg', | |
| 'fly' : 'no_arg', | |
| 'code' : 'no_arg', | |
| 'email' : 'no_arg', | |
| '*': 'opt_arg', | |
| 'tempfile': 'no_arg' | |
| }; | |
| var strictRule = ['img', 'swf', 'wmv', 'media', 'rm', 'dstatic', 'email']; | |
| // strip faces and br if any | |
| if (content.indexOf('[face_') != -1) | |
| content = content.replace(/\[face_[0-9]+\]/g, ''); | |
| if (content.indexOf('[br]') != -1) | |
| content = content.replace(/\[br\]/g, ''); | |
| parseBBCode(content); | |
| console.info('all errer count: ' + errors); | |
| return (errors == 0) && (unmatched == 0); | |
| function in_array(needle, haystack, isStrict) | |
| { | |
| var found = false, key; | |
| for (key in haystack) { | |
| if ((isStrict && haystack[key] === needle) | |
| || | |
| (!isStrict && haystack[key] == needle) | |
| ) | |
| { | |
| found = true; | |
| break; | |
| } | |
| } | |
| return found; | |
| } | |
| function hasQuotes(str) | |
| { | |
| return (str.indexOf('"') != -1) || | |
| (str.indexOf("'") != -1); | |
| } | |
| function checkParam(param) | |
| { | |
| console.log('checking param: -> ' + param); | |
| if ((param[0] == '"' || param[0] == "'")) | |
| { | |
| var last = param.length - 1; | |
| if (param[0] != param[last]) | |
| { | |
| console.log('quote not match: (' + param[0]); | |
| return 1; | |
| } | |
| else if (hasQuotes(param.substring(1, last - 1))) | |
| { | |
| console.log('extra quotes found'); | |
| return 1; | |
| } | |
| } | |
| else if (hasQuotes(param)) | |
| { | |
| return 1; | |
| } | |
| return 0; | |
| } | |
| function parseBBCode(content) | |
| { | |
| if (content.length == 0) | |
| return true; | |
| if (depth < 1000) | |
| depth++; | |
| else | |
| throw "Max depth of 1000 recursion reached"; | |
| var head = content.indexOf('['); | |
| var tail = content.indexOf(']'); | |
| if ( head == -1 && tail == -1) | |
| // no bbcode | |
| return true; | |
| if ((head == -1 && tail > -1) || | |
| (head > -1 && tail == -1) || | |
| (head > -1 && tail > -1 && head > tail) | |
| ) | |
| { | |
| errors++; | |
| console.info('error count: ' + errors + '::head and tail not match'); | |
| return; | |
| } | |
| tag = content.substring(head + 1, tail); | |
| if (tag.length == 0) { | |
| errors++; | |
| console.info('error count: ' + errors + '::empty tag'); | |
| return; | |
| } | |
| if (tag[0] != '/') { | |
| // open tag | |
| console.info('enter opening tag: ' + tag); | |
| // check paramters | |
| var pos = tag.indexOf('='); | |
| if (pos == -1) { | |
| if (!options[tag]) { | |
| // invalid tag | |
| errors++; | |
| console.info('error count: ' + errors + '::invalid tag name -> ' + tag); | |
| return; | |
| } | |
| if (options[tag] == 'arg') { | |
| errors++; | |
| console.info('error count: ' + errors + '::tag -> ' + tag_name + ' should have arg'); | |
| return; | |
| } | |
| stack.push(tag); | |
| } else { | |
| var tag_name = tag.substring(0, pos); | |
| if (!options[tag_name]) { | |
| // invalid tag | |
| errors++; | |
| console.info('error count: ' + errors + '::invalid tag name -> ' + tag_name); | |
| return; | |
| } | |
| if (options[tag_name] == 'no_arg') { | |
| errors++; | |
| console.info('error count: ' + errors + '::tag -> ' + tag_name + ' should have no arg'); | |
| return; | |
| } | |
| errors += checkParam(tag.substring(pos + 1)); | |
| if (errors > 0) | |
| return; | |
| stack.push(tag_name); | |
| } | |
| unmatched ++; | |
| console.info('unmatch count: ' + unmatched); | |
| } else { | |
| // close tag | |
| tag_name = tag.substring(1); | |
| if (!options[tag_name]) { | |
| // invalid tag | |
| errors++; | |
| console.info('error count: ' + errors + '::invalid tag name or empty tag -> ' + tag_name); | |
| return; | |
| } | |
| console.info('enter close tag: ' + tag); | |
| unmatched --; | |
| console.info('unmatch count: ' + unmatched); | |
| if (stack.length == 0) { | |
| errors++; | |
| console.info('error count: ' + errors + '::stack is empty, too many close tag'); | |
| return; | |
| } | |
| // check if the open tag and closing tag is match | |
| open = stack.pop(); | |
| if (open != tag_name) | |
| { | |
| if (in_array(open, strictRule, true) || in_array(tag_name, strictRule, true)) | |
| { | |
| errors++; | |
| console.info('error count: ' + errors + '::have strict tag but not match -> open=' + open + ' and close=' + tag_name); | |
| return; | |
| } | |
| } | |
| } | |
| parseBBCode(content.substring(tail + 1)); | |
| } | |
| } | |
| } | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment