Tobiasz Cudnik

Posts Tagged ‘html’

Can CSS stylesheets be applied on the server-side ?

In Ideas, QueryTemplates, Workflow on 27.01.2009 at 3:23

The question is: can CSS stylesheet be applied in the server-side ? And if yes, would would be the purpose ? I should say yes, they can and i would explain how and why. So what for are stylesheets ? “Applying cascading styles onto the DOM” may be the answer. But i would focus more on that why actually stylesheets are used for such purpose?

  • Because they are clean ?
  • Because CSS selectors do so much job, that besides them only really needed things are simple properties with obligatory number of arguments ?
  • Because cascading inheritance is just right for the DOM ?
  • CSS selector are simply benefiting from DOM structure’s nature

So first thing which needs to be implemented on the server is the DOM. When we already got it, so we can query it thou selector, that’s the first half. Now the properties. What could be the property on the server ? border-color ? Rather not. Do we need to style the DOM on the server ? Is it shown anywhere ? Not right now. On the server, page’s DOM is being build. Typically by various ways of string concatenation.

So if we need to build a DOM and same time we can query it with selectors, then the style’s properties should build / modify it’s structure. For example, show some articles or blog posts on the page. So here is pure CSS parser-validable code with some proposed server properties.

.section.articles ul > li {
  /* loop "articles" variable as "article" using "num" as index
  after that remove all other-than-first LIs */
  loop-one: articles num article;

  /* apply filter method on next variable output */
  vars-filter: htmlentities;

  /* use "article" fields and populate them inside nodes
  matched by ".a-%k" where %k is field name, eg .a-title */
  vars-to-selector: articles var(articleFields) null ".a-%k";

  /* example custom method to adding class for 1st loop node using index "num" */
  add-class-to-first: num custom-class;
}
/* show .comments node if variable articleComments is true */
.comments {
  if-var: articleComments;
}
/* bubbled event */
.section.articles:inserted {
  /* another custom method */
  /* null means 0 arguments */
  strip-tables: null;
}

So what have we done here ?

  1. We simply build articles loop which prints it’s contents into proper child nodes automagically. It could have 3 fields or 345, but line in CSS is only one.
  2. We’ve also used a custom method do add class basing on the loop position.
  3. Comments presentance is conditional.
  4. One Mutation Event is used. Hidden in :insert pseudoclass, really named DOMNodeInserted will apply on all new nodes which matches prior selector and were just inserted into the DOM structure.
  5. Each unspecified event defaults to :load.

All properties should be simply methods which applies something on all matched nodes. Sound familiar ? That’s exactly what many of jQuery methods are doing. Take a look:

.section.articles {
  remove-class: section;
  attr: rel section;
  /* all css properties can be used
  but will result in inline "style" attributes */
  css: padding 2px;
}
/* this rule applies to all load-time nodes
and the new one too */
.change-me,
.change-me:inserted {
  text: "changed innerText";
  prepend: "
<div>changed</div>
";
  remove-class: change-me;
  /* reallocation, interesting... */
  insert-into: ".content";
  /* passing some data to forward ? */
  data: some-flag "some value for developer";
}

All from above properties are jQuery methods. Possibilities are huge. But let’s stick with simple things right now. How would it benefit ? Who will write those server-css-sheets ? I should say…

Read the rest of this entry »

QueryTemplates – template’s logic and markup in one file

In QueryTemplates, phpQuery on 25.01.2009 at 15:41

Using latest phpQuery revisions you can easily keep template’s markup and logic in one place with 2 extra lines of code. This heavily breaks the general concept, but it may be useful in some cases. Idea is based on support for callbacks as template sources. First you start dumping markup with 1 line.

<?php ob_start(); ?>

After that the markup goes

<html>
  <body>
<div>Hello world</div>
</body>
</html>

And at the end there is whole logic. $markup is dumped using new CallbackReturnValue, which takes a variable as parameter. When callback is called it just returns it.

<?php
require('../src/QueryTemplates.php');
$markup = new CallbackReturnValue(ob_get_clean());
require template('test')->parse($markup)
	->find('div')
		->text('Hello template!')
;

This approach could also be used for getting markup with requestAction in CakePHP views.

Test cases for websites using phpQuery and SimpleTest

In Ideas, phpQuery on 13.01.2009 at 23:09

Using phpQuery and some UnitTest framework (SimpleTest in this example) you can automatically test web page for presentence of specific part and it’s position. Set of such tests can save a lot of time during website development and after that even more.

Not only you can do simple tests like “are articles visible” but using WebBrowser plugin you can test whole process, let’s say a user registration. Example of such test i would like to present. This test will include following steps:

  1. Enter main page and follow the registration link
  2. Fill registration form and submit it
  3. Check if result is expected

Like i sad before, SimpleTest is framework of choice, but it doesn’t matter so much. What’s important:

  • WebBrowser needs callbacks
  • Callbacks should be declared as functions (for PHP < 5.3)
  • Inside callbacks, $this variable is unavailable
  • First step of the test should check if last step has succeeded

Full code below:

require('simpletest/autorun.php');
require('phpQuery/phpQuery.php');

class CustomerTest extends UnitTestCase {
	public static $_this;
	public static $registration = array(
		'username' => null,
		'success' => false
	);
	function testRegistration() {
		self::$_this = $this;
		phpQuery::browserGet('http://localhost/tested-site/',
			array('CustomerTest', '_testRegistrationLink')
		);
		$this->assertTrue(
			self::$registration['success'], "Registration unsuccessful"
		);
	}
	function _testRegistrationLink($browser) {
		$registrationLink = null;
		$browser->find('a:contains(rejestracja)')
			->WebBrowser(array('CustomerTest', '_testRegistrationForm'))
			->toReference($registrationLink)
				// jump to _testRegistrationForm
				->click();
		self::$_this->assertTrue(
			$registrationLink->length, "Registration link missing"
		);
	}
	function _testRegistrationForm($browser) {
		$registrationForm = null;
		$username = md5(microtime());
		$browser['.customers.form form']
			->toReference($registrationForm)
			->WebBrowser(array('CustomerTest', '_testRegistrationResult'))
			->find('input[name*=login]')->val($username)->end()
			->find('input[name*=email]')->val($username.'@test.com')->end()
			// jump to _testRegistrationResult
			->submit();
		self::$_this->assertTrue(
			$registrationForm->length, "Registration form missing"
		);
		self::$registration['username'] = $username;
	}
	function _testRegistrationResult($browser) {
		$loginForm = $browser->find('h2:text(Logowanie)');
		self::$_this->assertTrue($loginForm->length, "Login form missing");
		if ($loginForm->length)
			self::$registration['success'] = true;
	}
}

WebBrowser doesn’t support AJAX, so not all sites can be tested like this (although you can do it with AHAH after some work), but cookies and HTTP authentication should satisfy most needs.

Of course that’s noting new, projects accomplishing similar goal exist quite time now, eg jWebUnit, but neither of them have jQuery under the hood  ;)

QueryTemplates finally released

In QueryTemplates, plainTemplates on 03.12.2008 at 16:47

I’ve finally managed to release QueryTemplates, a pure HTML templating engine i’ve been working past months. There’re extensive examples which should allow anyone to easily understand the idea. Previously posted Pure HTML templates theory sums up some thoughts about this templating pattern. You can read more about new library on the wiki and there’s also an official blog. Feel free to post feedback.

Pure HTML templates theory

In Ideas on 19.11.2008 at 23:51

In this post i would like to sum up my thought about using pure HTML files as fully functional templates. I’ve examined this pattern for about a year and i have to say it creates real order in application structure and lifecycle.

What means “pure” ?

  • Pure like plain, nothing else than HTML
  • Fully validable
  • Readable in any browser
  • Editable in any HTML editor

Read the rest of this entry »

phpQuery edits it’s own wiki

In phpQuery on 05.10.2008 at 3:05

phpQuery can connect to Google Code’s wiki editing form, authorize itself, replace page contents and finally submit the form.

// declare main variable
$pq = null;
// create dummy document as start point
phpQuery::newDocument('
<div>')
// authorize your google account
	->script('google_login')
// redirect authorized XHR component to googlecode's wiki form
	->location('http://code.google.com/p/phpquery/w/edit/test')
// save result as $pq, althought we could continue the chain
// but it would break in case of error...
		->toReference($pq);
if ($pq) {
// read about CallbackReference later in this post...
	$pq->WebBrowser(new CallbackReference($pq))
		->find('textarea:first')
			->val('lorem ipsum')
			->parents('form')
// first submit is Preview, so fire up second
				->find(':submit:eq(1)')
// triggering submit event thought input[type=submit]:click
// is a way to choose which submit is send
					->click();
	if ($pq) {
// print without  tags
		print $pq->script('safe_print');
	}
}

You can notice hot new feature – new CallbackReference($pq). Such callback sets first callback parameter to passed variable, by reference. Such pattern works with all methods accepting callbacks. Thanks to that, we can use if statements instead of function callbacks. In above example, CallbackReference object is called when click event is triggered.

Presented code snippet makes use of new Script plugin, particularly google_login.

Now it can be combined with automated XML documentation to wiki script, but this maybe for jQuery 1.3

Web Scraping with cli version of phpquery piped with sed

In Web Scraping, phpQuery on 05.10.2008 at 3:05

I’ve done what i was thinking about for some time. Terminal-firendly phpQuery CLI interface. Took about 10 minutes of coding… Works like this:

phpquery http://code.google.com/p/phpquery/downloads/list --find '.vt.col_4 a:first' --contents

This will return number of downloads latest phpQuery release file. Notice there is no need to quote url in any way. I was very happy with this so i’ve added callback support in text() and htmlOuter() methods, like so:

phpquery http://code.google.com/p/phpquery/downloads/list --find '.vt.col_4 a:first' --text strip_tags trim

When i had all stuff working, i’ve used it straight away to scrap forums and categories lists from old IPB v1.x. I’ve piped phpQuery result with sed, filtering final output.

// Fetch categories
./phpquery http://forum.wiadomosc.info/ --find '.maintitle a' | sed -r 's/^.*?c=([0-9]+).+?>(.+?)]*>([^<]*)<.*$/1: // 2/g'