I just invented PSEUDO Query!
var objects = $.pquery([
'##pquery##', // Initialize as PSEUDO Query Object
[document.body, 'css', [{'background-color':'#f00'}], 'append',
['##pquery##', // Helps distinguish array needing parsing from array of arguments
'<div />', 'text', 'LOL!']
],
['textarea', 'css', ['background-color', '#0f0']]
]);
...Is equivalent to:
var objects = [
$(document.body).css({background-color: '#f00'}).append($('<div />').text('LOL!')),
$('textarea').css('background-color', '#0f0')
];
Example image (got spam blocked for too low of reputation):
http://i.stack.imgur.com/IoSgi.png
The point?
The point of this is in no way for added readability, but rather to provide a means to execute jQuery via PHP outputted JSON through Ajax. I believe this is going to make possible a nicely structured, and well defined output class for PHP, with very little code.
Ultimately, my goal is to have all clients long polling the server, to accept new Javascript and commands at any given moment. I plan to use jQuery for exactly what it is, as a framework, and extend any common commands/routines directly to it as extensions. Eventually I'll revise the structure to support $.method()
calls, without having to have a selector. I might need some ideas for the best way to go about that, without causing problems.
What are the advantages? added 2/21/2012 2:00pm
- Easy PHP output
- Strictly governed remote script execution
What are some concerns with this? updated 2/21/2012 2:00pm
I wanted to avoid it, but I think I'm going to have to eval the Ajax array, for setting callback functions. Or I'll just pass it to a new <script />
element, and delete it after parse. Another option is to add some method to detect function structures, and pass the quoted code through new Function
. The last option I can think of, is to only allow predefined functions, which I've already extended to jQuery. I've heard it is bad to pass Javascript through through JSON, however I feel it is necessary if I'm going to be constructing new objects with bound events. I also feel that maybe this whole thing may be a little redundant if I'm going to just eval the code, but there's still the factor of easy output with PHP, which makes me want to continue with this extension. Basically, I'm not sure what the best way to handle my JSON would be. Should I accept text only, or allow Javascript in the mix and evaluate the array into a variable?
This is the area that I could really use the most advice and opinions about.
Another concern I realized is the need for a PHP compatible way to output unquoted Javascript variables, from PHP arrays to json_encode($array);
. This likely isn't very easily possible, and would demean the value of this extension, which is supposed to define a simple protocol to make PHP output much easier and very efficient.
Can you help me?
Any structural/general ideas or concerns about this? Or possibly some suggestions to just scrap the whole thing, and start with a different approach to the madness?
The code added 2/21/12 2:00pm
I'm not a big fan of comments, and since this post is more a question on what the best possible structure would be, to avoid issues and maintain functionality, I didn't think it would be necessary to post the code to the actual extension. Due to popular demand(lol?), here is the code for the actual pQuery extension:
(function ($, undefined) {
function object_type (o) { // To replace typeof
var type = Object.prototype.toString.call(o); // Returns [object "instanceof"], etc
return type.substring(8, --type.length); // Removes [object ...] and returns value
}
var header; // Scope-global header var set in $.pquery
function pquery (query) { // Parse a single array
var selector = query.shift(), // Expects selector to be in front at this point
_selector_type = object_type(selector),
$selector = ( // Set as a jQuery options
_selector_type == 'Array'
? $.apply(window, selector) // Multiple values for jQuery() is valid
: $.call(window, selector) // Single selector value
);
// Consider adding a statement to return if $selector.length is less than one
while (query.length > 0) { // Loop through rest of query
var method = query.shift() || '', // Expects a method to be in front at this point
_method_type = object_type(method),
args = query.shift() || [], // Expects arguments to be in front at this point
_args_type = object_type(args);
if (_method_type != 'String') { // Name of method should always be a string
console.log("Method: %o\nArguments: %o\nError: %s", method, args, "pQuery expects all methods to be a string");
/* Dump is a seperate information class of mine
dump.log('Uncaught exception', ["Method: %o\nArguments: %o\nError: %s", method, args, "pQuery expects all methods to be a string"]);
dump.out('Uncaught exception', true);
*/
return; // Array is out of sync
}
if (object_type($selector[method]) == 'Function') { // Check to make sure requested method exists
if (_args_type != 'Array') { // Arguments should always be an array
console.warn('Argument type "%s" should be an array for method "%s"', _args_type, method);
args = new Array(args); // Convert to array expected by apply
}
else if (args[0] === header) // Header helps us distinguish pQuery arrays from argument arrays
args = $.pquery(args); // If first argument matches the header, we parse it as pQuery
try {
$selector[method].apply($selector, args); // Call the methods
}
catch (e) {
console.log("Method: %s\nArguments: %o\nError: %s", method, args, e.message); //Show the errors
/*
dump.log('Caught exception', ["Method: %s\nArguments: %o\nError: %s", method, args, e.message]);
dump.out('Caught exception', true);
*/
}
}
else console.warn('Method "%s" does not exist', method); // Allows moving to next method, instead of returning
}
return $selector; // Return a single jQuery object
}
$.pquery = function (subject, pheader) { // Accept array and a custom header
var _subject_type = object_type(subject),
buffer = []; // Output array
header = (
object_type(pheader) == 'String'
? pheader // Custome header string
: '##pquery##' // Default header string
);
if (_subject_type == 'Array') { // Query structure is defined by array
if (subject.shift() !== header) { // Not a valide pQuery array
console.log("Header: %o\nError: %s", header, "The first value of a valid pQuery array should be a header value");
/*
dump.log('Uncaught exception', ["Header: %o\nError: %s", header, "The first value of a valid pQuery array should be a header value"]);
dump.out('Uncaught exception', true);
*/
return;
}
var _form_type = object_type(subject[0]),
__form_type = object_type(subject[1]);
// The follow statements trys to distinguish an array of arrays from an array of values
if (_form_type == 'Array' && (__form_type == 'Array' || __form_type == 'Undefined')) { // Array or arrays, probably multiple queries
$.each(subject, function (i, query) {
buffer.push(pquery(query)); // Push single jQuery object onto return array
});
}
else if ((_form_type == 'String' || _form_type == 'Array') && __form_type != 'Array') // Array of values, probably a single query
buffer = pquery(subject); // Sets return array to a single jQuery object
else {
console.log("Method: %o\nArguments: %o\nError: %s", method, args, "pQuery expects an array of arrays, or an array beginning with a selector");
/*
dump.log('Uncaught exception', ["Method: %o\nArguments: %o\nError: %s", method, args, "pQuery expects an array of arrays, or an array beginning with a selector"]);
dump.out('Uncaught exception', true);
*/
};
}
else throw "pQuery expects an array";
console.log(buffer);
return buffer;
}
})(jQuery);