I think a very nice addition to reptags would be to be able to make the parametric.
Here is what i mean

i want to create an image reptag (ok.. we have one.. but its for the example)

img id="idname" src="somepath" alt="altname" .

It would be nice to have $imagetag(idname,somepath,altname) = img id="%arg1" src="%arg2" alt = "%arg3" (omitted < tags for profound reasons)

Or even better to have default values $imagetag(idname=id1,somepath=here,altname='name')

Would it be easy to have smthg like that?

CommentFileSizeAuthor
#7 tabletags_placeholder.patch665 bytesprofix898

Comments

profix898’s picture

Not sure I got you right, but as I understand it you are requesting something like this:
You want to type $tag(arg1=abc, arg2=def)$ and reptag should replace that with <tag arg1="abc" arg2="def" />. Is that right? If so, it should be easy to implement, but it opens a security hole unless you have a whitelist of allowed tags.

buffos’s picture

let me put an example more abstract

Lets define $sometag(arg1,arg2) = Hi. My name is %arg1 and my age is %arg2

The = sign i put was for default values we sometimes put in functions if arguments are omitted.
so for example if i define the tag as

$sometag(arg1="tom", arg2="19") = Hi. My name is %arg1 and my age is %arg2
if i write
$sometag(nick,25) it will output-> Hi. My name is nick and my age is 25
if i just write
$sometag it will output -> Hi. My name is tom and my age is 19
which are the default values.

I hope this example is simpler.

Why would it introduce a security hole. ?

profix898’s picture

Do you mean this functionality to be generic, i.e. $mytag... is translated directly into the output? Or do you think about a .tags module, where you 'define' these tags explicitly? In the first case the user could type any tag, even if he/she doesnt have the rights to do so. In the second case that wont be a problem.

buffos’s picture

It does not matter if its a sitewide tag or a special module tag (if i really understood your question)

Now when the reptag finds the $sometag$ it replaces it with the defined text.
What i was suggesting is making it a step ahead. replace the text and if i find a place holder %arg for example replace it with the first argument, if i find a second %arg replace it with the second argument and so on.

For example

sometag(arg1,arg2,arg3) = sometext %arg and sometext %arg and even more text.

Now if i type $sometag$ it will output--> sometext %arg and sometext %arg and even more text.
if the module makes a second pass and replaced the first %arg with arg1 the second %arg with arg2 and the third %arg with arg3.

it would really be helpfull.

buffos’s picture

Correction

"Now if i type $sometag$ it will output--> sometext %arg and sometext %arg and even more text.

BUT IF i type $sometage(arg1,arg2,arg3)$ then if the module makes a second pass and replaced the first %arg with arg1 the second %arg with arg2 and the third %arg with arg3.

it would really be helpfull.

profix898’s picture

There is a difference between sidewide/user tags and module tags for your feature request:
As module tags are processed after sidewide/user tags is it also possible to include module tags (like {DATE}, ...) in the replacement text for sidewide/user tags. For example:
Say you have a sidewide tag defined as follows $WELCOME$ => 'Hi {USERNAME}! Welcome to ...'. Because {USERNAME} is a tag from system.tags, the final output will be Hi UserX! Welcome to ....

BUT IF i type $sometag(arg1,arg2,arg3)$ then if the module makes a second pass and replaced the first %arg with arg1 the second %arg with arg2 and the third %arg with arg3.

There are two possible solutions for this case:

  1. Process table tags twice. You could have $SOMETAG$ => 'This text contains a $PLACEHOLDER$'. In the second pass $PLACEHOLDER$ could be replaced with a second table tag named $PLACEHOLDER$. You would however need to define the placeholder tags separately. Thats almost trivial to implement because the only change is to process table tags twice.
  2. Introduce a special syntax like $SOMETAG(...)$ that allows to specify placeholder replacements directly as part of the tag. Problematic because you would need special 'reserved' characters - '(' and ')' in this example - to recognize the syntax. You would also need to make the tag field much larger in the db and the UI and you would need an extra complex UI to be able to specify default values for your placeholders.
profix898’s picture

Status: Active » Needs review
StatusFileSize
new665 bytes

Trivial patch for solution #1.

buffos’s picture

Case 1 is highly problematic. The reason it deprives the essense of the parametric approach, the dynamic nature

Case 2 would be nice (if it is possible) I think ( beeing reserved is not so important) . You can always use { or [ or [[ or $$ or what ever you like to signal start and end of place holding.

If it cannot be done .. no prob :)

profix898’s picture

It is possible in .tags modules already, but for table tags I think approach #2 adds too much complexity. We could think about placeholder arguments as part of the tag definition, but at least a UI to specify default values is overly complex IMO.

buffos’s picture

if the problem its UI you dont need something new.
In the existing UI

LEFT you define tag right the reptag

sometag hi i am %arg and my age is %arg

TILL HERE nothing new.

The only thing that needs to change is parsing . Let me place it in althorithmic steps.
LET the calling reptag be

$sometag(nick,34)$

1) If inside the $ $ there is no ( and ) then use the normal procedure and just output the text
2) if the are () then create an array of the values as args[] = {nick,34} in our case (its just splitting the string when comma occurs)
3) then to the output text (which is currently "hi i am %arg and my age is %arg")
do the following :replace the first instance of %arg with args[0] the second instance of %args with args[1]
4) output the newly create string.

Very simple string manipulation i think and you dont need to change a bit of the UI.

profix898’s picture

Status: Needs review » Needs work

Aha :) I got you wrong about the defaults. Sorry! But I think we should extend the syntax a little then ...

DEFINITION
tag: $SOMETAG{arg1=abc,arg2=def}$
replacement: 'This text contains %arg1 and %arg2.'

OUTPUT
... $SOMETAG$ ... results in ... This text contains abc and def.
... $SOMETAG{xyz}$ ... results in ... This text contains xyz and def.
... $SOMETAG{,xyz}$ ... results in ... This text contains abc and xyz.
... $SOMETAG{klm,mno}$ ... results in ... This text contains klm and mno.

What do you think?
We should also keep in mind that the tag definition can be quite vast, e.g. $THISISMYTAG{arg1='Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt', arg2= ... }. Thats why I originally expected a different UI to specify the defaults.

buffos’s picture

Bullseye.

Although defaults are not a must. Just an extra feature of arguments.
So if you skip default values you dont need ANYTHING new in the definition

$SOMETAG$ will just do for definition

and then $SOMETAGE(a1,a2,a3,a4,a5)$ {it does not matter how many arguments} because the procedure is just the same

1) split the string a1,a2,a3,a4,a5 with delimiter , and create array args
2) currentargument=0;position=0;
2) while (position = findnext(outputtext,"%arg",position))
{ replace(outputtext,"%arg",args[currentargument++],position) //just replace in the string outputtext the string %arg with the argument stored in the array args and its the currentargument , and the starting position of the %arg string is position
}//endwhile

ofcourse functions are schematic but the procedure is as simple as that (unfortunatelly i dont code in php :)

So if you leave defaults out, the procedure is really easy i think.
Dont you agree?

profix898’s picture

The major difference between #11 and #12 is that in #11 you have keyed arguments (like %arg1, %arg2, ...) while in #12 there are identical arguments replaced in order of appearance. And I'm not really convinced this being a good solution. Do you have any real world use cases or examples for this functionality? I somehow think that keyed arguments are a) more Drupal-like (see %-variables for mails and stuff) and b) much easier to extend in the future. They are c) also better from the usability point of view because you dont need to worry about order. If you - for example - reword your replacement text with #12 you would also need to edit every node containing the tag to preserve the order the arguments appear.

I can write you a patch for #12, but I dont think I will implement un-keyed dynamic arguments in reptag (unless you convince me ;)). One solution that I could agree on is to introduce #11 without the defaults and think about a nice way to handle/specify default values in D6 (where the UI is completely reworked). For now (D5) we would have:

DEFINITION
tag: $SOMETAG{arg1,arg2}$
replacement: 'This text contains %arg1 and %arg2.'
OUTPUT
... $SOMETAG{arg1=abc,arg2=def}$ ... results in ... This text contains abc and def.

buffos’s picture

actually keyed or not args is the same. I thought it would be a little bit easier to program non keyed args and much FASTER because replacement requires only ONE pass (as each time you encounter an %arg you trigger a replacement). The keyed replacement is slower as you require to pass the output string as many times as the number of arguments to find %argN.

Just that. Actually there is not difference in the result. In the unkeyed solution order is defined by occurence of %arg. In the keyed order is defined by naming convention.

The final result is the same but i think unkeyed is way much faster to parse and replace (did i convince you? xexe.)

profix898’s picture

The final result is the same but i think unkeyed is way much faster to parse and replace

So you are fine with keyed arguments in principle, right? I dont think the unkeyed way is faster but slower. In unkeyed case you need a loop to iterate over the %arg positions and replace every %arg with an argument in order of appearance (as you said: while (position = findnext(outputtext,"%arg",position))). With keyed arguments however order doesnt matter and you can replace all arguments at once with a single call to str_replace().

buffos’s picture

It seems that keyed are faster but in fact they are not.
Let me tell you why.

What a find_replace(sourcestring,findstring,replacestring) function does is search through an array (string = array of chars) to find an instrance of findstring
This is LINEAR procedure. Let me discribe a worst case senario.

Let as have a string of N characters where N is big. And we have to replace K strings that are ALL at the end of the source string ( i mean "blablabla.... %arg1 %arg2...)
The search function will find the arg1 after searching all characters before arg1 . The same applies to arg2 and so on.
So the search function will have to traverse the array of chars N*K times appox (where K is the number of arguments)

In the unkeyed way you the search will just be N times (because the last search provides the position the %arg placeholder was found)

If N is big and K increases we have a huge difference in implementation times.

In the keyed version the overload is just hidden under the search function.

I dont know if i explained it it well

profix898’s picture

I didnt benchmark any of these cases, but in my experience its faster to use str_replace(), which is available as function in php with optimized code (C/C++ or stg), than to write a loop in php syntax iterating over the elements. Also your K is quite small (max 10-20) unless you specify really many arguments. All in all I dont think you will ever notice a difference between both implementations at all. The str_ functions are much faster than their regexp counterparts, that are used in reptag to support sophisticated expressions.

The questions are:
1. Do we need what you requested/suggested here
2. Whats the safest way (in respect to usability and extensibility) to implement it

buffos’s picture

May i provide some simple example.

the image tag (which exist in a module ofcourse but its an easy example)
You would not need to write a module to post an image. Just define a tag as
$IMAGE(path,size,title) for example.. and you have your image

I for example use it to embed a chess game viewer in a post. How?
To embedd it i just need to copy paste a certain code + the body of the chess game. So my solution now is to create TWO TAGS
a $STARTTAG$ and and $ENDTAG$. They simple hold the code that must be place on the body of the post and are SPLITTED at the place the gamescore (moves) must be inserted. So the user writes $STARTTAG$chessmoves....$ENDTAG$ and its working perfectly.

So i am simulating an ONE parameter TAG. TAG(chessmoves). If i want to simulate 2 parameters i have to manually create 3 tags and so on.

I can list so many examples.

I let my users use the tags but ofcourse i never allow them to create tags (for security reasons)

profix898’s picture

Status: Needs work » Patch (to be ported)

I have added support for parametric reptags to the 6.x version of the module. Marking 'patch (to be ported)' as a reminder to think about the 5.x version as well.

profix898’s picture

Status: Patch (to be ported) » Fixed

Done.

Anonymous’s picture

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for two weeks with no activity.

summit’s picture

Component: Code » RepTag .tags module
Category: feature » support
Status: Closed (fixed) » Active

Hi, just installed the latest drupal 5.* dev version. Couldn't find the parametric tags...
Thanks a lot for going into this!

greetings,
Martijn

buffos’s picture

Just download the latest dev install and then go to your admin section at reptags settings page and look under Expert settings.
You have to enable parametric tags.
It works fine by the way (i have not tested for default arguments) but parametric tags are GREAT

avpaderno’s picture

Status: Active » Fixed
Anonymous’s picture

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for two weeks with no activity.