Skip to content

Instantly share code, notes, and snippets.

@mrlannigan
Created May 11, 2015 19:58
Show Gist options
  • Save mrlannigan/65a6ee5c2dfd384df40e to your computer and use it in GitHub Desktop.
Save mrlannigan/65a6ee5c2dfd384df40e to your computer and use it in GitHub Desktop.
(function (exports) {
var shortCodeRegex = /\{\{\s*(.+?)\}\}/g,
hasWhitespaceRegex = /\s+/;
/**
* @param {string} input - Parsed string
* @param {object} [context] - context object defining shortcodes
* @param {object} [callContext] - call context for any functions called within any shortcode replacement
*
* Supported Inputs:
* {{Count_ForSale_Total}}
* {{Count_ForSale_Total test="argument"}}
* {{Test_Func test="argument" nice="dude" }}
*
* Not Supported Inputs:
* {{Count_ForSale_Total test=arguments}}
*/
exports.replace = function doShortCodeReplace(input, context, callContext) {
callContext = callContext || this;
return input.replace(shortCodeRegex, function (wholeMatch, shortCode, index) {
var result,
typeofResult,
codeArguments,
codeKey,
tmpCodeArguments,
matchedCodeArguments,
argumentsRegex,
hasWhitespace;
hasWhitespace = hasWhitespaceRegex.test(shortCode);
// test for no whitespace before checking context hash
if (!hasWhitespace) {
// grab value from keyed hash
result = context[shortCode];
typeofResult = typeof result;
// check if valid
if (typeofResult === 'undefined') {
return '{{! Invalid Shortcode : "' + shortCode + '" }}';
}
// short-circuit processing, no need to continue if not a function
if (typeofResult !== 'function') {
return result;
}
} else {
// if whitespace exists, start processing for arguments
result = shortCode;
}
// check if has arguments
if (hasWhitespace) {
argumentsRegex = /(\S+)=["']?((?:.(?!["']?\s+(?:\S+)=|[$"']))+.)["']?/g;
result = result.split(' ');
codeKey = result.shift();
tmpCodeArguments = result.join(' ');
// grab value from keyed hash
result = context[codeKey];
typeofResult = typeof result;
if (typeofResult !== 'function') {
return result;
}
codeArguments = {};
while ((matchedCodeArguments = argumentsRegex.exec(tmpCodeArguments)) != null) {
codeArguments[matchedCodeArguments[1]] = matchedCodeArguments[2];
}
if (Object.keys(codeArguments).length < 1) {
return '{{! Invalid Shortcode : "' + shortCode + '" : Invalid arguments format given (no matches) }}';
}
return safeFunctionCall(result, callContext, codeArguments);
}
return result;
});
}
/**
Pass through function to safely call function and not disqualifying from compilation
**/
function safeFunctionCall(func, context, options) {
try {
return func.call(context, options);
} catch (err) {
var _toString = err.toString;
err.toString = function () {
return '{{! ' + _toString.call(err) + ' }}';
}
return err;
}
}
})(exports);
/***** EXAMPLE *****/
var context = {
Count_ForSale_Total: 123456,
Count_ForRent_Total: 9876,
Test_Func: function (options) {
return 'Test Function: ' + JSON.stringify(options);
}
};
console.log(exports.replace('{{ Count_ForSale_Total}} For Sale Homes and {{Test_Func test="dude" neat="oh" sweet="man" }} For Rent Homes', context));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment