[component] YiiML

[size="5"]YiiML[/size]

[size="3"]Wrapper and extension for peml[/size]

http://erudit.es/YiiML

Inspired by haml/sass/less and all those goodies, I’ve written a parser that’s powerful enough to represent all the views in my current project. So I’m posting this to see if people would be interested in me improving this extension to have more needed shortcuts and control structures.

The core parser is in its own project at http://erudit.es/peml, which contains reference material for the default syntax.

The component is able to be used without changing all your view files into the new format, please see the install docs on the YiiML site for details.

Nice!

What’s the difference between this and phpHaml http://phphaml.sourceforge.net/ ?

I’m focusing a bit more on markup extensibility over simply implementing haml. Haml is really nice, why I’m emulating it in part, but it’s really quite focused on views, and keeping logic inside helpers/controllers (haml doesn’t provide any direct flow control from what I see?) whereas I’m trying to give enough power for it to stand on its own a bit. Also having flow control show up in the indentation looks great to me.

I’m currently cleaning up how commands are handled, so you’ll be able to just inherit from a pemlCommand, configure the options, and override the processing you need to do, so the commands are more modular and don’t rely on inheritance from the pemlCore.

As a simple example of sweetening the markup, I added in a couple of minutes a :ganalytics command that takes a trailing ID and inserts the google analytics tag. (:ganalytics ID-BLAHBLAH-0). Yeah this could have gone into the base controller as a method, but then you’re liable for clutter to accomodate something general to markup.

Idea is to get a baseline which approximates haml, then add sugar on top. (I know at least in my current project, there are a few structural schemes repeated a lot for panels, and being able to tidy some of that into a command is lovely).

thanks, we needed this …

–iM

Quick module release now that peml is feeling a little more stable.

I know there are some things missing such as cache and clip, but if you need them, just look at pemlYiiCL.php and you should be able to work out how to add it, perhaps with some help from the extension docs: http://erudit.es/peml/extend.php

hello,

OK, I downloaded the component and I’ve been playing with it, on general it works fine so far …

1.- Have you used it with Widgets? (where can I find documentation for that, if you have one)

2.- The yiic shell seems to be broken, unless I turn off the viewRenderer I get errors ( output: http://pastii.com.ar/101 )

I saw the permission denied errors, but I have them set to 777 and still getting the error :confused:

ideas?

thanks,

–iM

I’ve put a couple of YiiCL commands in for widgets, so:


.yiiml


:widget application.components.search


:widget application.components.search

  autocomplete : true


output php


<?php $this->widget("application.components.search"); ?>


<?php $this->widget("application.components.search", array(

  "autocomplete" => true,

)); ?>

and similarly inside a :php block (though will then skip the <?php ?>)

There’s a bit more at http://erudit.es/YiiML/reference.php

I’ve not used the yiic shell with it installed, though seems strange as the writing logic I’ve used is the same as the builtin CPradoViewRenderer. I’ll try and get that tested, though issue is I just have a windows box for my development. Could you see if the Prado renderer gives the same error? If all else fails I guess you need to disable it in the config when using yiic until sorted.

I’m working on a few new bits (have basic output filters done, for inline-php within blocks and autolinking and the like) and just updating YiiCL with some more commands for clips/caching. Busy week for me though so may be a little while before I finish that.

hello,

no rush, it’s a great tool! I’m trying to use the Zii CGridView widget with it - http://www.yiiframework.com/doc/api/CGridView

I’ll let you know how that goes …

I didn’t use yiic a lot in the past, but i’m trying to put together a little tutorial, and I’d like to put your YiiML component/class in it - (to kill more birds with one stone). and I use heavily the yiic tool there (scaffolding and whatnot)

thanks,

keep up the good work!

–iM

oh, btw - is there a color-scheme for this (HAML) out there? (i’m using NetBeans), because it doesn’t really fit in the HTML or the PHP schemes …

thanks,

–iM

Ah, cool, sounds great. :)

I’ve not any experience with Netbeans for PHP (I guess I should try it again, as I’ve been using it for Java work). I’ve tried a haml highlighter with the editor I do but, but unfortunately the differences seem to be quite key with regards to highlighting (markedly the lack of % at the start of tags) so it only highlights the div elements.

I think once I get the syntax a little more stable I’ll have a go at modifying a haml highlight for it and seeing what changes are actually needed.

One bug that’s been tripping me up a little btw: It’s not properly ignoring tags it doesn’t recognise if they appear to start a block.

so:


script

  jQuery.etc(

    var stuff

  );

is getting oddly transformed to:


<script>

  >.etc

    var stuff

  );

</script>


script

  jQuery.etc(

  var stuff

  );

Is fine though. Will try and get a fix on the repo. (and yeah, I should make a :script tha doesn’t treat its insides like html :P)

hello,

alrighty - my code for this particular widget looks like this now:




:php

    $this->widget('zii.widgets.CListView', array(

        'dataProvider'=>$dataProvider,

        'itemView'=>'_view',

    ));



so in order to use the Zii Widgets, as you can see above, I have to declare an itemView (without an extension). I dug through the CWidget core code and found out, that is looking for a .php extension, unless I specify a new extension in the config/main.php file, just like this …




...

'fileExtension' => '.yiiml',

...



so I did that, but then I had to overwrite every single view file from .php to .yiiml.

Oh, and one last thing … while I was overwriting the template files, if you look into the login.php (view file in the site folder) there is a form declaration at the bottom of the file:




<?php

$form = new CForm(array(

    'elements'=>array(

        'username'=>array(

            'type'=>'text',

            'maxlength'=>32,

        ),

        'password'=>array(

            'type'=>'password',

            'maxlength'=>32,

        ),

        'rememberMe'=>array(

            'type'=>'checkbox',

        )

    ),


    'buttons'=>array(

        'login'=>array(

            'type'=>'submit',

            'label'=>'Login',

        ),

    ),

), $model);

?>



this array kills Yiiml for some reason (it says, invalid &lt; character or something like that), i had to comment it out - weird.

ok, that’s my 2 cent here :)

–iM




:widget zii.widgets.CListView

    dataProvider : $dataProvider

    itemView : _view



Should work here. One thing you may have already changed is the indentation that it expects, by default it’s a double space.

Aha, this can be fixed for user created widgets by adding a new Widget class as a component, and extending your widgets from that instead, then adding:


<?php

class Widget extends CWidget {

  

	public function getViewFile($viewName)

	{

		if(($renderer=Yii::app()->getViewRenderer())!==null)

			$extension=$renderer->fileExtension;

		else

			$extension='.php';

		if(strpos($viewName,'.')) // a path alias

			$viewFile=Yii::getPathOfAlias($viewName).$extension;

		else

			$viewFile=$this->getViewPath().DIRECTORY_SEPARATOR.$viewName.$extension;

		return Yii::app()->findLocalizedFile($viewFile);

	}

  

}

?>

Of course You can’t really do that with a built-in Widget though. These are mainly workarounds as Yii is designed to work with one kind of view at a time, and there are a few file-exists checks before it gets to the ViewRenderer. I could change the default extension of the ViewRenderer to .yiiml but then the reverse problem is true. Might ticket (or see if I can code myself) a system that allows multiple viewRenderers based on file extension.

Ahh, I’d not actually seen that kind of definition used for a CForm, interesting. It should work if you place it all inside a :php like so:




:php

    $form = new CForm(array(

        'elements'=>array(

            'username'=>array(

                'type'=>'text',

                'maxlength'=>32,

            ),


            snip

  

        ),

    ), $model);



Though you’d have difficulty using the :form command if you wanted, which is expecting one built using CHtml:: lines.

I love the idea of YiiML (and how the codes looks!), but without proper indentation in the final code, it’s a bitch to debug.

Test site:

layouts/main.yiiml




:doctype xhtml 1.0 strict

html

	head

		meta(http-equiv:Content-Type ` content:text/html; charset=UTF-<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/cool.gif' class='bbc_emoticon' alt='8)' />

		title= app()->name

	body

		.container

			.page

				.header

					.banner

						h1 a(href:./)

							span YiiML test

						span Description

					:php

						$menuItems = array(

							array('id' => 'work', 	'label' => 'Werk', 		'url' => array('work/index')),

							array('id' => 'contact','label' => 'Contact', 	'mailto' => 'mail@example.nl'),

							array('id' => 'cv', 	'label' => 'CV', 		'url' => array('cv/index'))

						)

					:widget application.components.MainMenu

						id : 'nav-main'

						items : $menuItems

				.content

					= $content



MainMenu widget .yiiml




ul.navigation(id:=$id)

	:foreach $items as $item

		li(id:=$item['id'].($item['active'] ? ' active' : ''))

			:if !empty($item['url'])

				a(href:=$item['url'])

					span= $item['label']

			:elseif !empty($item['mailto'])

				a(href:='mailto:'.$item['mailto'])

					span= $item['label']

			span.comment

				span= $item['comment']



index.yiiml




.classname

	a.awesome(href:http://google.com ` data-external:true)

		span Go Google Go!



Results in:




<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html>

	<head>

		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

		<title>YiiML Test</title>

	</head>

	<body>

		<div class="container">

			<div class="page">

				<div class="header">

					<div class="banner">

						<h1>

							<a href="./">

								<span>YiiML test</span>

							</a>

						</h1>

						<span>Description</span>

					</div>

										<ul class="navigation" id="nav-main">

			<li id="work">

							<a href="/Yiiml/work/index">

					<span>Werk</span>

				</a>

						<span class="comment">

				<span>Comment 123</span>

			</span>

		</li>

			<li id="contact">

							<a href="mailto:mail@example.nl">

					<span>Contact</span>

				</a>

						<span class="comment">

				<span>Comment 456</span>

			</span>

		</li>

			<li id="cv">

							<a href="/Yiiml/cv/index">

					<span>CV</span>

				</a>

						<span class="comment">

				<span></span>

			</span>

		</li>

	</ul>				</div>

				<div class="content">

					<div class="classname">

	<a class="awesome" href="http://google.com" data-external="true">

		<span>Go Google Go!</span>

	</a>

</div>				</div>

			</div>

		</div>

	</body>

</html>



As you can see, indentation is makes the code unreadable.

Also, it would be nice to not have to use indentations in some cases.

No idea how, but sometimes it just nice to put code on one line (when using a, span, and li for example)




ul.menu

	li > a.item > span Text1

	li > a.item > span Text2

	li > a.item > span Text3



Instead of:




ul.menu

	li

		a.item

			span Text1

	li

		a.item

			span Text2

	li

		a.item

			span Text3



Ah yes, some of my tagging needs to add a space after the php tags otherwise php eats the lineending, giving a doubled up indentation for the next line. It’s a little hit and miss, I’ll try and test a little more thoroughly on getting the output nice.

Recursive tags were on my list of things to implement as well, I was thinking the syntax of +, but I like the > notation you’ve got there so I’ll probably roll with that.

Sorry for lack of maintenance, heading towards end of term for me here and my own projects taken a swing towards the javascript side so haven’t been able to incidentally work on peml.

I’ll try and get a 0.2 done with:

[list=1]

[*]Output Filters

[*]Better output formatting

[*]Better input format checkings

[*]recursive tag definitions

[*]some extra commands for YiiCL (clips and caches mainly I think)

[/list]

As well as hopefully a little more documentation on extending yourself.

Edit

Just noticed, could be your preference for wrapping in spans, but some code such as:




:if !empty($item['url'])

  a(href:=$item['url'])

    span= $item['label']

:elseif !empty($item['mailto'])

  a(href:='mailto:'.$item['mailto'])

    span= $item['label']

span.comment

  span= $item['comment']



could be rewritten as:




:if !empty($item['url'])

  a=(href:=$item['url']) $item['label']

:elseif !empty($item['mailto'])

  a=(href:='mailto:'.$item['mailto']) $item['label']

span.comment= $item['comment']



I admit the placement of the = isn’t ideal right now when combined with attributes, I may rework it while I do the recursive stuff to be after, like so:




:if !empty($item['url'])

  a(href:=$item['url']) = $item['label']



I use the spans because I can then hide the text and use a background: url(’’) in css to style the element without losing the ability for screenreaders to navigate.

Don’t use <img alt=“same text as in span”> because of the limited hover/active states etc.

I also have the same "script" bug you had some post back btw.




script

	document.addEvent('domready', function(){


	});



results in:




<script>

	document.addEvent('domready', function(){


	});

</script>






script

	document.addEvent('domready', function(){

		alert('test');

	});



results in:




<script>

	>('domready', function(){

		alert('test');

	</document>

	});

</script>



Ah yes, thought there was probably a reason, just making sure. :)

Yeah, the script/block bug itself needs fixing, but I may also add a :script or :javascript command that wraps the content in a CDATA (and will also avoid any accidental tag expansion within the script block).

Will you still be able to use php echo’s inside the script block?

I usually use some minor echoing like "var data = <?= json_encode($array) ?>"

Yeah that’ll work, it just means peml will leave the insides alone rather than trying to check for tags/commands, so the php tags will end up in the final file that’s run.

@Chris Spencer

You may be interested in this ticket (in the next Yii release) which I think is applicable to YiiML as well as my Haml and Sass extension.

Yii will now fall back to a PHP view if the view renderer’s view file is not available which saves having to override CCcontroller::resolveViewFile() and making extensions using a view renderer “drop-ins”. The view renderer still needs to check what it’s got so it knows what to do with it.