-
I'd like a few opinions on the sidebar thingy... I'm posting in the public topic willingly, BTW.
Here's a small screenshot of the Warm skin. I've modified it to put the sidebar on the left of the *page*, as opposed to the left of the *content area* (i.e. surrounded by footer, header and nav.)
I just figured that forcing a sidebar onto users wasn't too big a deal (as it helps separate the main content from the asides, really, that's what it's all about), but forcing a sidebar layout onto themers wasn't as cool. It's not too hard to force the sidebar to show on the *right*, but then I thought, what if the themer wants a layout where the sidebar is outside of the header area? I think it's doable but it's hard. And most likely will require creating a new theme just for that aspect. Themes are harder to maintain than skins, so I tried to figure out a solution and it struck me that the layer system is either too simple, or too complicated.
The current layer structure makes the order of calling templates functions as such:
- template_html_above
- template_body_above
- template_header
- template_menu
- template_linktree
- template_sidebar_above
- "sidebar" sub-templates
- template_sidebar_below
- template_main_above
- "top" sub-templates
- "main" sub-templates (i.e. main content)
- template_main_below
- template_footer
- template_body_below
- template_html_below
In order to have the sidebar shown next to the rest of the page, I'd have to move the sidebar layer out of this loop. Although I'm not too scared at the idea of 'hacking' into the system for the good cause, I'm just wondering if there isn't a smooth way to do it.
Could we consider doing something like a 'skeleton' for the template functions...?
For instance, a $context['skeleton'] array of arrays, that pretty much holds the template structure. We already have similar things with the $context['sub_template'] variable, but it only holds the main content area structure.
I added a skin variable called <sidebar> and a theme variable called $settings['sidebar_position'], they both do the same thing: tell Wedge whether the skin wants the sidebar to be outside the flow, or next to the content. By default it's next to the content. So, right now, in template_body_above(), I just have two occurrences of this:
if ($settings['sidebar_position'] === 'left_page')
template_sidebar();
(The other being 'left_content', of course, and positioned in the correct place. And template_sidebar is a function defined in Subs.php that basically calls sidebar_above, the sidebar sub-templates, and sidebar_below.)
Although it works, I can't help feeling this is 'wrong'. Plus, it will force the skin to redefine the 'sidebar' and 'content' blocks, because in the default skin, they're linked together. Not a big deal of course, but what I probably don't like here, is that a themer can't simply switch between two sidebar positions through a single variable being set -- they'll also need to redefine the actual HTML content to match it... Not only that, but I'm not even sure it's not going to break stuff. I have the sidebar + content stuck inside an 'edge' div that serves as display:table and is also used by the onresize sidebar toggler. If I remove it, the toggler will stop working, but the 'edge' div is closed at the end of the 'content' block... And there's no 'block' for the entire page that shows on the right of the sidebar when in left_page mode. Meaning, the 'edge' div never gets closed properly just by redefining the blocks.
I can't really think of a way to get out of this loop of complicated crap. And I definitely don't want to live another week like last week, where a simple remark ("allow embedding in sentences doesn't work") led into a nightmare with a complete overhaul of the auto-embedding code. In the end I'm happy with it (the feature finally works as expected and the actual logic of the embedding process is a bit better), but... I'm just not ready to jump straight back into another nightmare, see.
Posted: September 6th, 2011, 11:15 AM
Update -- I thought it didn't validate, but it does. The magic of nesting sort of fixed itself actually: the edge div closer is still in the same place (after the main content block), but this time it's seen as a closer for the wedge id, not edge. It should be totally broken because the wedge div is not even behaving like a table cell, but... bah. I guess these can be fixed in Warm/index.css anyway.
Still, I don't like hacks... :^^;:
I could actually allow skin.xml files to hold PHP code -- such as a template_body_above_override() function allowing for new sidebar layouts -- but it also mean eval. And, uhh... Let's just say I'd rather do without evals.
Posted: September 6th, 2011, 11:45 AM
Lol... A modified sidebar location will freeze IE9 (100% CPU). But not IE7 or IE8, mind you! :lol:
Nice bug. Sasuga Maikurosofuto da na...
-
Okay... The "too long, didn't read" version then:
Is anyone interested in having themes where the sidebar is to the left of the page and the header, rather than to the left of the content (and thus below the header and above the footer)?
If yes, would you be willing to have a 'hackish' (and a bit ugly) way of doing that in the default theme (i.e. within a new skin, which is much easier to maintain in the long run), or would you rather create a new theme for this kind of detail?
-
Hahahaha, just as I finally get round to posting, you've beaten me to it!
Yeah, eval is an evil beast at the best of times.
I like the notion of having the sidebar outside of the content and encapsulating the overall page in the manner demonstrated.
Hmm. I think I'd prefer it not to be an entirely new theme if possible, such that if it can be done inside a skin, that would seem to me to be preferable, ugliness aside. But I'm no themer, I don't make themes, so my view on the mechanics of it are mostly irrelevant.
-
Well, in the case of Wedge, the actual subtemplate list is an array as well, such that multiple sub templates can exist.
There are already pages where this happens; on the board index, for example, each item of the info center is a separate template that's added to the sidebar template list.
I don't recall anywhere else I split the templates up, but that's mostly just down to not having gotten round to it.
In other news, I made use of this multiple list facility in WedgeDesk earlier today to add a new item to the end of the unread/unreadreplies page without having to fake it up as a template layer as SimpleDesk had to, so it can definitely be done.
-
Changing the layout should only be useful for the sidebar, I suppose. I mean, I don't see any possible reasons for someone wanting to show the footer at the beginning or the header at the right of the page... :P
Although I suppose one could want to make a three-column layout where the header or footer is the third column. That doesn't make much sense to me, but never underestimate the power of craziness, sometimes it leads to innovation... :P
Doing a skeleton really is something I'd like to do at this point. I considered it for the first time a few months ago when I built upon the layer system. I just found it... A bit too complicated for my taste, and at the time I didn't even consider some alternative solutions for the implementation that make sense to me only after working through the mess that is the template layer system. (Although it has to be said that when used correctly, layers do things that a skeleton could hardly do.)
For instance... Imagine a skeleton saying basically, "header, sidebar, content, footer". If I want to add data to the footer through the skeleton, I can't. I'll have to do it above it or below it, considering that 'footer' includes its own wrap code (<div></div>). With a layer system, we "only" need to do something like "header_above header_content header_below sidebar_above sidebar_content sidebar_below content_above content_content content_below footer_above footer_content footer_below". Now I can easily add my code in "footer_content" without fear of breaking it.
Of course, a logical solution is to make way for template hooks in strategic positions like these, so I'm not too worried, and would actually, at this point, be more interesting in getting rid of layers and manually adding hooks in the skeleton, or rather in the related functions (content, sidebar, etc.)
If anything, it's probably easier to understand for anyone having a first look at index.template.php... A function called skeleton(), with some HTML and some {calls} like this, followed with a series of functions sharing the same name, really makes a lot of sense...
Then again, how do we do that without eval()?
We can't do echo '...' because then we'll need to capture the buffer at ob_sessrewrite time and call the functions one at a time there -- and I'm pretty sure it'd break many things because some items expect to be called before ob_sessrewrite is done, eh.
We can do return '...' then, and analyze the code. We echo the thing as it goes, but we stop on each {, extract the following string, make sure it's a valid function, and we call it. Then we discard the following } and we resume the templating process...
I like that idea. What do you think of it?
Plus, it makes it much easier to change the template layout in skins, really. We can very simply put that code into a <skeleton><![CDATA[<html>]]></skeleton> and replace the code we got from skeleton()...
We can do something like this to begin with, and then determine whether we need to keep the template layer code around.
Posted: September 6th, 2011, 04:58 PM
Oh, in other news (© Pete), I renamed template_header() and template_footer() to start_output() and finish_output()... I don't know about you, but I always found these two functions to have VERY misleading names. Especially when you consider that template_footer() never was there to show a footer at all... Just to finish the layers in reverse order. :^^;:
-
Then again, how do we do that without eval()?
Variable functions are a truly wonderful thing. :P
$skeleton = "header, sidebar, content, footer";
$list = explode(',', $skeleton);
foreach ($list as $item)
{
$item = trim($item);
$item();
}
It's faster than eval though naturally not as fast as calling the function directly, but you don't really have a lot of choice at this point, and it would go through the normal template execution flow anyway, meaning that the buffer process is essentially unchanged, since to a degree this is how template layers themselves work.
The one thing that seems critical to me is that the list of items can be manipulated, and ideally more easily than fudging around with a string; that's one thing I like about the current setup is that you can add new items cleanly to an existing content area.I renamed template_header() and template_footer() to start_output() and finish_output()
Works for me.
-
Variable functions are a truly wonderful thing. :P
...And, quoting myself:
"extract the following string, make sure it's a valid function, and we call it."
:whistle:$skeleton = "header, sidebar, content, footer";
I was thinking about something closer to the templating system like, REAL html with custom tags in it... :^^;:
The only 'trick' is that it couldn't have any PHP in it, really. We're only talking about the main structure, not overriding anything else...The one thing that seems critical to me is that the list of items can be manipulated, and ideally more easily than fudging around with a string; that's one thing I like about the current setup is that you can add new items cleanly to an existing content area.
Maybe something like this..
<layer:header>
<menu>
<linktree>
<layer:main>
<layer:sidebar>
<footer>
I don't know... Something that basically tells Wedge whether to start a layer or a sub-template at that point. Or it could simply recognize whether <footer> is stand-alone function, or a layer... Etc.
-
"extract the following string, make sure it's a valid function, and we call it.
Yes... but it absolutely does not require eval at all ;)
I thought the whole point was that the skeleton would dictate which parts to call and in what order, nor intermixing the order with the content therein...I don't know... Something that basically tells Wedge whether to start a layer or a sub-template at that point. Or it could simply recognize whether <footer> is stand-alone function, or a layer... Etc.
How is that different to now, then? A layer is an array in the template list, a standalone function is a string item.
-
Yes... but it absolutely does not require eval at all ;)
Never said it did :pI thought the whole point was that the skeleton would dictate which parts to call and in what order, nor intermixing the order with the content therein...
Yep... But it has to have some content in it, which is where it gets bitchy.
So, as an example, here's the code from the body layer's 'above' section...
function template_body_above()
{
global $settings;
if ($settings['sidebar_position'] === 'left_page')
template_sidebar();
echo '
<div id="wedge">', !empty($settings['forum_width']) ? '<div id="wrapper" style="width: ' . $settings['forum_width'] . '">' : '';
// Show the header area.
template_header();
// Show the menu here, according to the menu sub-template.
template_menu();
// Show the navigation tree.
theme_linktree();
// The main content should go here.
echo '
<div id="content"><div class="frame">';
if ($settings['sidebar_position'] === 'left_content')
template_sidebar();
}
Please look at <div id=content>... Where exactly would you put that in a skeleton situation? In what function, exactly? If we can get rid of it, does it mean we're getting rid of the body layer as well? What of the wedge div, do we have to create a new template_* function just for this call...?
-
*ahem*
Then again, how do we do that without eval()?
That's just me being facetious at this point because I don't think there is a good way to do it that doesn't involve either eval, or using fun functions everywhere.
There is where you're getting into semantics. As far as I'm concerned, #content is used to represent the content, and thus it encapsulates all of it. Surely, then, the ideal place is the layer that surrounds the page content, which would be the body layer?
I see what you're getting at, and you're probably right. As I said, a lot of this stuff is mostly hypothetical from my perspective; I don't make themes, I only know how I'd want to interact with things as a modder, and do so in a way that doesn't foul up themes.
-
Okay... Busy IRL, but the more I think about it, the more it strikes me as relatively simple.
To hell with template layers as such.
A template system should have this kind of structure, which can *easily* be replicated in a pseudo-XML file, and thus overridden through skin.xml:
$templates = array(
'html' => array(
'body' => array(
'header' => 'header',
'menu' => 'menu',
'nav' => 'linktree',
'wrapper' => array(
'sidebar' => array(
'rss' => 'rss_feed',
),
'top' => array(
'subtemplate1' => 'subtemplate1',
),
'main' => array(
'content' => 'subtemplate1',
),
),
'footer' => array(
'sub1' => 'wedge_credits',
'sub2' => 'my_mod_credits',
),
),
),
);
Or (sidebar in the left side)
$templates = array(
'html' => array(
'body' => array(
'wrapper' => array(
'sidebar' => array(
'rss_feed',
),
'header',
'menu',
'linktree',
'top' => array(
'subtemplate1',
),
'main' => array(
'content',
),
'footer' => array(
'wedge_credits',
'my_mod_credits',
),
),
),
),
);
And there you go...
The idea, as you can see, is that a layer is just an array. Multiple nested arrays means multiple layers. If we go through the layers recursively, each time we meet an array, we take its key, and then test for "template_KEY_above", if there, we call it. Then we go through the array and call its subtemplates (I added random keys and values, which we use can be discussed, and the other can be used for something else), until we meet an array etc, and then when the loop is over, we just test for "template_KEY_below", and if there, we call it...
You can easily add sub-templates to any of the systems by calling a custom insert function we'll provide -- said function will simply look recursively for the 'layer' we want, and add the stuff there, or it could even add a subtemplate before or after another, etc...
It's a bit harder to remove layers for this but again -- it's just an array, it's easily to manipulate. We can have a function for that, too, we can basically keep the structure inside a layer while removing said layer. We can remove everything and just rebuild a barebones template with hideChrome(), etc...
This way, we can also easily add layers that aren't in the theme. We can also add layers in the theme that have no above and below functions -- we can leave it up to a mod to add them... (Although they could also use the override hook for that. I don't think I implemented it for layers, though...)
Anyway. It's a whole new world to me, suddenly... And quite exciting. I really like the idea of having a basic structure that can be modified by a skin. All extra layers and subtemplates added by mods and such should add their stuff relative to the existing skeleton -- e.g. if they want to add a sidebar subtemplate, they'll just call a function that searches for the 'sidebar' array and then adds their subtemplate entry to it.
What do you think, guys...?
Posted: September 6th, 2011, 08:07 PM
(Edited to differentiate between the two sidebar layouts. The wrapper layer is just that extra div which is made into a table and allows us to have a sidebar that behaves like a table cell i.e. it takes the entire height...)
-
Great. I'll try to implement that tonight or tomorrow. :)
Mod compatibility with what? SMF? Well, it won't be the first rewrite they'll have to go through... ;)
-
No, the long standing question of themes and mods being compatible.
For the record, file edits are going to be supported and with no less functionality than on SMF (I.e. Install on custom themes, as well as updating custom themes later on if you install mods) but the preferred method will be hooks simply because it's cleaner and more likely to be compatible.
-
I'd tend to say, 'screw mods if they're not gonna behave'... :P
I'm doing my best to ensure they'll have an easier time, so they'd better not piss me off :niark:
Okay, in template_footer() (now finish_output(), although it may be going away at some point), I have this:
* - Theme dirs and paths are re-established from the master values (as opposed to being modified through any other page)
It's in your comment, Pete.
So, are you sure this is what the code does? I'd tend to say yes, but... What's the point, really?
I mean, why would a mod modify the theme URL right in the middle of the page? Did SMF implement that after they noticed the variable being abused?
Apart from that... It's a little buggy, but my implementation seems to work fine, at least on regular pages.
SMF added tons of hacks to the layer system. I'm gonna have to trust them and include them in my own, but... meh.
The rest will come tomorrow...
-
I mean, why would a mod modify the theme URL right in the middle of the page? Did SMF implement that after they noticed the variable being abused?
Oh... ooh, I looked at this again. The code is a little bit different to how it was when I documented it - it's now much clearer as to what it's doing, as opposed to my creative interpretation back then (a year ago!)
If a theme indicates that the default images should be used, and that the theme is indicating that it uses the default templates, reset the theme dirs to the master default directory. I don't recall a theme ever setting it, however, not even the default theme. I see no reason, really, why that actually needs to remain.
Mind you, there is some creative variable abuse inside SMF, like $scripturl, which can actually be redefined after creation depending on circumstance, so don't take it for granted that it is what you will expect it to be...
-
I'd just tend to have this philosophy: don't waste CPU cycles fixing crap made by badly coded mods or themes.
Btw I also tend to forget to update your documentation when I remove stuff hehe. For instance it referred to include_after_template which doesn't even exist anymore so I removed it ;)
I guess that, somehow, the tempting system could use a diet. Like so many other things you already did!
Posted: September 7th, 2011, 09:23 AM
Btw - use default images AND templates? That's skin territory to me ;)
-
I never got the idea behind using default theme for images..
I don't know, I thought new themes used default images by default... (i.e. if no images folder was found, the default images folder was used.) Isn't that the case...?no themes use it, and not many use the based-on option either. Whats important is that the fallback tempaltes are self-contained, so if a custom theme rewrites everything in index.tempalte, possibly display.tempalte, the others would still work.
Yeah, unless they broke the main template of course... In which case they'll see soon enough, anyway.In the beginning I argued sepatating styles, or at least use alot of common classes. Both was worked out to be one-file-fits all and maybe 10% classes, the rest is id styles.
The early Curves (the ones you made) were pretty light on the CSS. Like, 4 times less... Although it's a nice idea to make everything skinnable, the SMF team put too much emphasis on the "everything", and less on the "skinnable", because as it is now, it's a real mess to navigate through the CSS and find what you want to change. Which is one of the reasons why I went for the pre-parser, which at least allows for shorter code and more logical nesting. Unfortunately I don't have the time to rewrite ALL of the css... There are many places where, frankly, common classes would make more sense to use -- if only in the admin area, because no one in their right mind would reskin this anyway...
Heck, even the actual common classes (windowbg*, clear_*, float*...) didn't get used all of the time.Wasting a lot of good styles on things designers seldom change anyway, making working with index.css a nightmare really.. Its like it was all - or nothing lol.
Absolutely.
I'd tend to say -- feel free to simplify the Wedge CSS, reapply things to the HTML and not always the CSS... You can always submit a patch and I'll happily look through it :) I'm all for the simplification of code -- I just can't do it alone because I have more things to do and they're not all layout-related.
Okay, my progress on this...
- Wine is working. Some subtemplates won't show, because I haven't yet converted the 'sub_template'/'template_layers' code to use the array.
- The skeleton override is working. The skeleton is rewritten to fit my HTML tags. Here's the code I put into Warm's skin.xml:
<!--
Layout skeleton. The following uses pseudo-HTML to represent the final array.
- use <tags></tags> to define layers (i.e. a function
called as a wrapper around other functions)
- use <self closing tags /> to define sub-templates
Overrides the theme's $context['skeleton'] variable.
-->
<skeleton>
<html>
<body>
<wrapper>
<sidebar>
<sidebar_feed />
</sidebar>
<header />
<menu />
<linktree />
<top></top>
<main>
<content />
</main>
<footer />
</wrapper>
</body>
</html>
</skeleton>
As you can see, it's dead simple... Feel free to suggest any improvements, in case I missed anything. (The indentations are only there for clarity. Obviously they're not needed...)
Also, the rendering for this rewritten skeleton is buggy. It still uses the other one... Uh.
And the db_debug_junk is output at the beginning instead of the end, meaning the body tag closer isn't output at this point. Well, it's probably the kind of bug I'll spend an hour on, until I find out that I made a tiny mistake at one point and spend another hour cursing at myself... :lol:
Posted: September 7th, 2011, 06:35 PM
:edit: db_debug_junk issue fixed...
-
I don't know, I thought new themes used default images by default... (i.e. if no images folder was found, the default images folder was used.) Isn't that the case...?
No, it isn't. A new theme as created by the admin panel is a copy of all folders from the theme's directory, plus index.template.php.
OK, idiot question time, because I'm not seeing how the one thing that is quite important to me is covered.
I see there is the sidebar_feed item inside the sidebar. How do I go about adding a new item in sidebar, preferably doing it before sidebar_feed, and doing it dynamically because I don't want it every page?
-
OK, idiot question time, because I'm not seeing how the one thing that is quite important to me is covered.
I see there is the sidebar_feed item inside the sidebar. How do I go about adding a new item in sidebar, preferably doing it before sidebar_feed, and doing it dynamically because I don't want it every page?
This isn't done for now but I don't see where it's going to be a problem.
The skeleton array is generated right from loadTheme(), so basically everything you add to it later (via loadSubTemplate) will be added to the array by Wedge. It'll be transparent...
I can also add a removeSubTemplate() function.
I'll also add something like loadLayer(), although I don't exactly know how it'll work... (i.e. where do we position it?)
BTW, I just found out that there's a slight miscalculation in my project.
The skin.xml override is loaded through wedge_cache_css, which itself is loaded through theme_base_css, which itself is called "at the last possible minute"... Although this works quite well for all of the overrides it has (html blocks, etc.), rebuilding the skeleton at that time will delete all of the existing subtemplates.
Hmm...
Don't really know how to fix that -- except by loading the CSS files twice: once early on for the skeleton override, and once at the last minute for block overrides. Yikes.... :-/
Any idea? I'll take a cigarette break.
-
Okay, I've done it -- split wedge_cache_css into two functions. The first one is called in loadTheme() and will build the correct list of CSS folders for use in skins (i.e. it will discard any parent folders if it meets a replace-type skin), and will retrieve the options for the current skin. The second one, wedge_cache_css, will go through the folder list built by the former function, and will build the actual CSS file. Performance-wise, it should be exactly the same as before, except that it's cleaner, and that it allows me to override the skeleton right after loading it from the theme. (Hmm, come to think of it... I should probably load the theme's skeleton after the skin's skeleton, to save on processing time... :lol:)
I'd have hoped this would make it easier to merge add_css_file with wedge_cache_css (their code is VERY similar), but it probably won't be possible, because each one has optimizations that the other couldn't use... I still have hope, though :P
Anyway... 'Done'.
Warm is running the modified skeleton, it has the sidebar on the left, but the rest of the content is crammed onto two vertical columns if the main content doesn't take much space (actually, it looks funny.) I guess I'll have to encase all of the content (and header, and footer) into their own div. Well, the structure isn't too great... I should probably add more layers, so that pretty much every block is encased within a special div that I can then manipulate as I wish.
That, or I actually allow adding functions within a file in the skin... Something like 'Custom.template.php', which would be loaded by Wedge at loadTheme time, and would contain overrides, i.e. "template_body_above_override". If such an override exists, Wedge won't run the original function. Of course, then, it's getting closer in spirit to a full-fledged new theme, and I don't know if I'm ready to make that big a jump...
Still got plenty left to do. Hopefully I'll be finished by tomorrow night... I'd really rather not spend too much time on this. I guess I can fix Warm later -- definitely not a priority (heck, I can simply remove the <skeleton> entry in skin.xml just to fix it for now...)
-
Sounds like a very awesome amount of functionality and very, very flexible too :)
Can't wait to actually see it to play with.
-
I don't know if it's going to amount for new functionality, but it'll sure make more sense IMHO... *And* it'll make for easier debugging if you can't figure out why your block won't show up.
print_r($context['skeleton']);
Done... :lol:
Of course, adding ?debug or ;debug to the URL is also a nice solution. (I did it yesterday to debug the new stuff. I have no idea why it's not exactly a documented feature...)
-
I have no idea why it's not exactly a documented feature...
I don't know that either, but to be fair it's only really useful for themers and people that create template layers. Which means it's useful to themers and the dozen or so modders who ever bothered to investigate SMF and found it useful, which means Daniel15, various portal authors, me, you and anyone else who really, really put time in.
I sort of wondered about adding it to the debugging menu, but I figure it's convenient enough there. Or, alternatively, add it to $db_show_debug. If you're already using that, your layout's shot to hell anyway with masses more data than normal, why not go for the full house and do it then too?
-
I'm hoping to have this on SVN by tonight...
Most of the stuff is working now. I'm having more issues though, so I'll just mention them here.
- seems like having a page sent in XML will crash everything. I've only seen this quickly, it seemed to me but it seems like XML will bypass many things in loadTheme() or something... (And it makes sense, since this codepath will generate its entire 'HTML' from scratch.)
Pete, any memories about this?
- I'm working on a "loadLayer()" function, similar to loadSubTemplate()... I'd like for it to be logical in its execution and settings. When exactly do we want to add a layer, and what for? Generally it's because we want to add something around the code being executed. The main issue I'm having here is that if it means adding a layer to the 'main' layer, any subsequent layers added will become parents of the earlier added layers. It's not a big problem to me but I don't think SMF does it in that direction... (Does it?)
Also, I'm having fun (ah ah... not exactly) trying to figure out how to quickly rename an array key. It's easy enough when your array doesn't need to preserve order... But when you start having to use array_splice when this one doesn't work with associative arrays and doesn't even preserve key names, meh... I guess I'll have to do my own routine that rebuilds an array from scratch. Ah ah, fun, as I said...
And these are my two current issues :P
Posted: September 8th, 2011, 01:58 PM
Okay, renaming keys was easy enough, surprisingly... And fast.
However now I'm wondering what's best. By default, layers are added to the 'main' layer (you can choose your target layer, otherwise it's not cool.)
Should they be added *inside* the layer, or *outside* it? i.e. adding a <layer2> to <main> in <layer1><main><output /></main></layer1> should result in what...?
<layer1>
<main>
<layer2></layer2>
<output />
</main>
</layer1>
<layer1>
<main>
<layer2>
<output />
</layer2>
</main>
</layer1>
<layer1>
<layer2>
<main>
<output />
</main>
</layer2>
</layer1>
Of course I can include an option to do any of the three, but I'm sure there's going to be at least one option that never gets used... And we're bound to find people complaining they can't add an empty layer at the *end* of an existing layer... :lol:
Oh well, maybe it's not very important... I mean, adding a layer to the end manually can be done very easily: $context['layers']['main']['my_layer'] = array();
And at the beginning, my first guess would be to do something like: $context['layers']['main'] = array('my_layer' => array()) + $context['layers']['main'];
(And yes, I suppose I can add wrappers for these, too...)
-
I sort of wondered about adding it to the debugging menu, but I figure it's convenient enough there. Or, alternatively, add it to $db_show_debug. If you're already using that, your layout's shot to hell anyway with masses more data than normal, why not go for the full house and do it then too?
It's not shot to hell... It only adds below the end of the body. If it was shot to hell, I'd be out fixing it... :lol:
No, don't touch $db_show_debug, I always have it enabled, even if I don't use it, while ?debug would kill my layouts... :^^;:
Posted: September 8th, 2011, 02:18 PM
Layers are a really under-developed feature of SMF.
I actually didn't understand anything about layers and sub-templates before I started working on Wedge... Yikes.
Which is one of the reasons I thought that skeletons could sound more logical to newbie modders and themers.The theme should have the last word(I know, I am repeating myself lol) so even if x layers are added in, it can still look good.
How would you see them have the 'last word'?
Adding a function somewhere at the end that allows for the theme to check for integrity...? :^^;:
Oh, which makes me think -- there is technically nothing that prevents me from doing all layer/sub-template operations directly on the pseudo-HTML that I provide in $context['skeleton']. I only converted it to an array to make it more 'logical' for parsing by users, but if I add enough wrapper functions, I can do everything myself with regular expressions...
I don't know what's best for this. I'm currently sticking to the array solution, but I guess it's not going to take a long time to rework everything into using a HTML string if needed.And no mod would ever take control over it in such a way it does in SMF now, it should not have to. A portal needs sidebars? in SMF: wrap everything else, or possibly just the content into a table..voila. But problem comes when the theme doesn't know about the sidebars, and puts for example absolute positioned items on the sides..a nice way to add embelishments around the content. But now it is separated from that crafted background around the content, by 2 big bars...
Well, I don't really have a suggestion on how to fix this (plus, Pete seems to have the problem in WedgeDesk itself ;))
Do you have anything...?
Multiplying the number of layers, maybe? And putting your positioned stuff in one of the top-level ones, and hoping that mods will only built upon lower-level layers?If the theme had KNOWN there would be layers that could want to add themselves on the sides, it would have made some changes for that.
But, doesn't SMF already allow themes to know that...? It's all in $context['template_layers'] AFAIK...? And it's easy than Wedge, because template_layers is a single-dimensional string, basically a set of Matryoshka dolls that can easily be analyzed, while Wedge now has a more complex multi-level structure. So I don't know that my thing will be 'the' solution at all for this kind of issue...
I'm all ears though, if you have any suggestion, however little it is. I'm not building this system for myself but for themers -- no, not themers -- for *designers*. To give complete freedom on the layout, which usually isn't possible without redoing a new theme, i.e. getting into compatibility problems.Sadly this is just things that theme designers worry about, and not many of them either, at least not for SMF. So it will most likely never win any motions to be added. Wedge looks to be heading in a good direction though.
I may not be a 'designer', but I'm a good listener when it comes to feature implementations, you should have suggested this kind of change long ago ;)
-
I've only seen this quickly, it seemed to me but it seems like XML will bypass many things in loadTheme() or something...
loadTheme should always be called, at least. But if $_REQUEST['xml'] is defined, hideChrome() is called, the Xml template is loaded, and the rest of the pure theme stuff (most importantly, loading any required templates and initialising template layers) doesn't happen.
After that, it sets up jQuery, and looks for the init subtemplate in a theme, sorts out blocks, then just wanders off on other stuff like dealing with scheduled and imperative queues, the mail queue and stuff like that, nothing that should be a problem here.
Anything in the error log?any subsequent layers added will become parents of the earlier added layers. It's not a big problem to me but I don't think SMF does it in that direction... (Does it?)
No, any subsequent layers are children of the existing layer. Thus if you add a new layer to the default, you get html_before, body_before, newlayer_before, main, newlayer_after etc.When exactly do we want to add a layer, and what for? Generally it's because we want to add something around the code being executed.
Yes, but we don't always want to layer things, which is where it gets complicated. The way I'd envisage using it normally is to have some content, encapsulated in markup (either a block or some other container) and inject that into the existing structure, which wouldn't necessarily constitute a layer.
The really important use is to be able to inject content into the sidebar, which notionally requires adding to the list of templates to be called by the sidebar layer, rather than creating new layers.Also, I'm having fun (ah ah... not exactly) trying to figure out how to quickly rename an array key.
There isn't a particularly quick way of doing it, to the best of my knowledge. All the methods for accessing arrays (even more exotic options like array_replace in 5.3) are for dealing with the values not the keys.
What about something like:
$keys = array_keys($original_array);
$values = array_values($original_array);
foreach ($keys as $key => $value)
if ($value == $key_to_find)
{
$keys[$key] = $key_to_replace;
break;
}
$new_array = array_combine($keys, $values);
I don't know how efficient that'd be versus building a new array from scratch as a product of regular iteration of the original array, but that's the approach that occurs to me, anyway.Okay, renaming keys was easy enough, surprisingly... And fast.
Oh, you already did it, heh.Of course I can include an option to do any of the three, but I'm sure there's going to be at least one option that never gets used... And we're bound to find people complaining they can't add an empty layer at the *end* of an existing layer...
The facility would be useful, even if it ends up being underused, though adding a template to the end of a layer is significantly more important in the long run.
You and I are actually in agreement, though it might not look like it. You're right, it should need all 4 options, which are effectively: outside, inside, before-item, after-item.
In your examples, the first is before-item (it's before <output />), inside, outside (all considered relative to main), and the only item that's lacking is after-item, because positioning of templates is potentially quite important.
Remember: forcing everything to be actual layers is potentially a headache and one I don't want to repeat. See, if you provide the ability to place content with those 4 options, it doesn't matter if it's a layer or a self contained item.
The same logic should cover for adding <extra-content /> after <output />, the only difference is that extra-content isn't an array signifying a layer but a self contained item, right?No, don't touch $db_show_debug, I always have it enabled, even if I don't use it, while ?debug would kill my layouts...
Fair call, I do the same :lol: Like I said, I was only considering it being part of db_show_debug, but it really should be in the debug menu (and I'd probably remove it from URLs and sessions otherwise if it were a modSetting)but I guess it's not going to take a long time to rework everything into using a HTML string if needed.
Please please please leave it as an array. It can be built from a pseudo markup string in the skin file but it really should be an array internally because it's much faster to inject items into an array than it is to use string munging.Well, I don't really have a suggestion on how to fix this (plus, Pete seems to have the problem in WedgeDesk
This is where themes and mods are always going to have problems, because there is no possible way that you can expect everything to work in a meaningful manner, there just isn't.
What we can do, however, is be intelligent about it. The default theme has a sidebar. I have no problem with the theme indicating through some kind of variable that it provides a sidebar. Then WedgeDesk can check to see if a sidebar is given, and if it is, use it, otherwise I can reimplement the sidebar type bits that I had before (as in if the theme doesn't provide for one, I can)
Then you get more clever, because if/when a portal comes along, it can look at that too - if the theme provides a sidebar, make use of it, but if not, the portal can create one. It'll take a bit of co-operation to make it work but instead of going it alone as much as historically happened, I see no reason why we can't be a bit smarter about it.So I don't know that my thing will be 'the' solution at all for this kind of issue...
From my standpoint, I think it is, because it provides the core with the facility to let designers be a lot more free - and it's not like it's some mythical resource.
All the time it's supported and there are add-ons using it rather than hacking templates about, it'll be an improvement. Sure there are going to be incompatibilities but that's a fact of life: it's going to happen that some things just don't play nicely. This, however, will really minimise that being a problem, IMO.But, doesn't SMF already allow themes to know that...?
Themes dictate what layers they want used, which is typically html and body. They're the ones calling the shots, it's not like there is default skeleton in place that they can make use of - or totally ignore in favour of their own, and that's it.
It's not like there's any kind of structure to it, other than a fairly limited approach, but even that isn't used that much. By making it more powerful, and proceeding to actually *use* that power a lot more, I think we'll see more and more examples of it.
But ultimately it's going to rely on a certain set of contractual obligations - like I mentioned above with the 'supports sidebar' concept. Themes are going to need to indicate if they provide these things or not, and if not, mods that want to use them will need to do something else to accommodate it (or risk the outfall of incompatibility), and that's something that's just going to have to happen. We can't (and, IMO, shouldn't) dictate that every theme has to support a sidebar, it's not realistic to expect that.
-
Thursday, September 8, 2011. Paris time, 22:41.
The friggin' new layer system friggin' works in both Wine and Warm.
Oh yeah! :eheh:
It just keeps failing in XML but I think I'll commit it and look into this tomorrow, unless Pete finds a fix before me. (Hint, hint! :P) (And yes, I can simply avoid running this code for XML but I'd like to know where I made a mistake, if any...)
Posted: September 8th, 2011, 10:42 PM
(Hoping I can complete the changelog before I go to bed... It's really huge. Some of the files underwent a lot of changes, notably Load.php, Subs.php, Subs-Cache.php and the index template... I've done about two thirds of it.)
-
like portal A adds a "left" sidebar, ad mod B adds also a "left" panel but really want it the far left
And this is immediately where control at some level has to be asserted.
If you don't provide some modicum of control, you end up with the current mess where templates are trying to work around each other, to the point that you might as well not bother trying to do anything even remotely complex and just plump for sticking to the standard because anything else won't play nicely.
I spent a surprising amount of time debugging SD's layers interacting with the portals for just this reason.
If two things compete for the far left, what determines who wins?
-
Skeleton = structure not position.
It's only a helper it won't do the cooking for you :)
Positioning is up to CSS. I'll commit on a few minutes. Bloc, I suggest you look into the new system and determine if you think something can be done with it. I'll accept any patches, algorithms or suggestions. With pleasure.
Posted: September 9th, 2011, 12:34 AM
It's up :)
Hopefully it'll work for both of you, Pete and Bjorn... Take your time to study it but make sure to feel your first feeling about it!
I'll try and update the demo site this week-end... I guess I'm going to have to release it to the public anyway. Ahhhh, and I'm still not using AeMe for avatars and attachments... The agony, I always postpone this big chunk!
-
Ahhhh, and I'm still not using AeMe for avatars and attachments... The agony, I always postpone this big chunk!
It's a huge job, no doubt, but I suspect it almost depends on the permissions system being upgraded to a degree.
Before worrying about implementation, nail down the exact details of how it's supposed to work, where avatars and attachments should be stored (one folder for each, multiple folders?), how that should be referenced in the code (new album, mythical album 0 or something else?) and stuff like that.
It's a complex job and it has consequences that are far reaching, so best to look at that first before touching the code, IMO.
-
I suspect you want mods to do all the work lol..but why? Let the admin+theme do all that.
Two words: WordPress Widgets. That is essentially how they work. And what a mind fuck that is. You end up with themes having to state what widgets they support and vice versa.
There has to be a middle ground, of reasonably rigid definition, that both sides can reasonably expect to be present. Turning it on one side so that one side has all the power, it hamstrings the potential of the other.
SMF put too much power in the modder's hands, what you're suggesting removes most of the power they would actually have. I want a middle ground where I can write code that I have a reasonable expectation of being supported the way I want it to be, not some vague notion of support.
Also, if anything, it's actually making life a lot harder for themers to do anything creative. Because I guarantee you that if themers are given totally free reign, people will have trouble using add-ons because they just won't work as expected. Take a look at WordPress sometime and how many people really do have trouble with Widgets - and how many themes actively state what they support for just that reason: because they give an awful lot of flexibility to the themer and little to the modder in any real sense.
Having some semblance of structure ensures that both sides have a reasonable expectation of things working.
-
How about we assign a left:right:bottom:top var to layer names in skeletons? Only one per direction per skeleton.
<main_wrap:left>
Would mean "if a mod asks to add a subtemplate to the left, use this layer." like a shortcut!
We could have more directions or even other hints, as separated by commas.
And loadSubtemplate('tempy', array('left', 'hello')) would mean add a subtemp to the left-hinted layer, and fallback to the hello layer if not found.
Heck. I can even have a global fallback to the main layer or whatever!
What a smart idea :eheh:
-
you describe something I don't want either
Ah, see, I was describing what I saw from what you were saying: a setup that is surely a path to hell and back. Joomla, WP, Drupal (to a lesser degree) all have these problems.The theme would HAVE to give it back to make it work.
Then the theme doesn't have final control, does it? It has a reasonable contract to fulfill, which is the state of play that we were approaching anyway.where some themes support 4 spots, others 25 lol.
That's the scenario I want to avoid and one that your suggestion didn't seem to exclude from happening, if anything it seemed to encourage it, since leaving it up to the theme means that themers are going to do bizarre things like disallow certain areas because their design doesn't support it.Would mean "if a mod asks to add a subtemplate to the left, use this layer." like a shortcut!
I like that.
-
So, Bjorn, what do you think about the latest changes to Wedge...? The skeleton in general I know you like, but how about the semantic pseudo-elements?
It's only there as a canvas. Ideally, designers should tell me what the list of pseudo-elements would be eventually -- i.e. whatever helps a designer make a semantically solid theme.
Just watched Tucker & Dale vs. Evil... What a fun movie :lol:
-
Before worrying about implementation, nail down the exact details of how it's supposed to work, where avatars and attachments should be stored (one folder for each, multiple folders?),
Oh, it's already been nailed on for a while... First time an avatar is created, an album is silently created, using /media/avatars/ as its target folder. Same for attachments, with /media/files/. The folders are already in my local copy but I just noticed they're not in SVN...
Anyway-- they'll behave like normal albums, i.e. new sub-folders created after a sub-folder is full. The idea is that whatever the obfuscation setting is, thumbnails will always be visible to everyone, because it'd be stupid to expect a web server to take dozens of extra PHP connections just for these. (Or maybe we could put a dummy avatar if user doesn't have the right to view them... Anyway, this kind of thing is done via Load.php anyway, not through the usual AeMe codepath.)
Other than that... I don't see any biggie.how that should be referenced in the code (new album, mythical album 0 or something else?) and stuff like that.
No, it can't be album 0 because we need different albums for avatars and files. It's easier internally to help people choose their avatar from an existing pool. (They can always move their files to the avatar album later if they want to use them as avatars...)It's a complex job and it has consequences that are far reaching, so best to look at that first before touching the code, IMO.
I don't think it has that many consequences. The main consequence is that many, MANY functions and settings will have to go, and that's probably the part I'm a bit scared to screw up...
Other than that, I don't think there would be any reason to use different album settings for avatars and files, compared to other albums. It's just... easier to apply the same settings to everything. The only difference being that Wedge will directly retrieve avatars from the media table.
Oh, and I'm also not looking forward to dealing with the Attachment feature in post pages... I mean, I like the 'simplicity' of it, and I'd like to do something between our current popup and the current attachment solution for that.
-
Oh, and I'm also not looking forward to dealing with the Attachment feature in post pages... I mean, I like the 'simplicity' of it, and I'd like to do something between our current popup and the current attachment solution for that.
Hmm, yes, that is an interesting point. The current solution is 'nice', it's straight forward, it's elegant, but it doesn't allow for adding more complex data to the attachment like the popup would.
What about perhaps enhancing that with an async solution, to have the file uploaded there and then, with the option to open the file in the media area for editing?
The stuff around attachments is pretty complex, but not for the obvious reason: it's not that it just uploads stuff and does error handling, but that it has a complicated habit of stashing stuff in session. Specifically that if you upload a file or two while posting but there's an error, the files are preserved in the temporary folder, with the details for them (for renaming/moving to the actual attachments folder) in session.
I spent a surprising amount of time figuring it out for SimpleDesk, because it is pretty complicated to get it right, but that might be a good place to start because it breaks the process down into stages unlike Post2.php which doesn't (and you can see the stuff that I had to write to bridge to SMF's own functions, which I think will help make the logic slightly easier to follow)
Though of course, if the file's sent asynchronously, that stops being a problem anyway.
-
Okay, just keep me posted :) I feel like the current implementation is a work in progress, even though it's probably fully functional and 95% done -- but I'm sure there are ways it can be made more helpful to designers. :)
Posted: September 9th, 2011, 03:12 PM
Missed that post...Hmm, yes, that is an interesting point. The current solution is 'nice', it's straight forward, it's elegant, but it doesn't allow for adding more complex data to the attachment like the popup would.
It can be done through Ajax, really... Like, I'm simply selecting the file, then if the File API is supported, it starts uploading it and adds a box somewhere, where I can enter data. Then I also add another file input to upload something else. (Adding it above the rest, so I can upload several files without having to scroll...)
(Heck, the good thing with the file API is that IIRC it also allows for multiple file selection... It needs to be implemented, too.)The stuff around attachments is pretty complex, but not for the obvious reason: it's not that it just uploads stuff and does error handling, but that it has a complicated habit of stashing stuff in session. Specifically that if you upload a file or two while posting but there's an error, the files are preserved in the temporary folder, with the details for them (for renaming/moving to the actual attachments folder) in session.
Hmm, didn't know that...
Well, I guess this is the kind of thing that would have to go, unless we implement it into the media area.
Posted: September 9th, 2011, 03:16 PM
(Split and moved to a non-blog area.)
-
Hmm, didn't know that...
Well, I guess this is the kind of thing that would have to go, unless we implement it into the media area.
It's not well known unless you ever had a reason to dabble in the attachments code.
Doing it asynchronously one way or another would definitely remove the need for that code in its entirety (and would simplify WedgeDesk too)
I'd certainly prefer the UI aspect of asynch uploads (AJAX, Flash, whatever)
-
I'm just not sure about this for now -- I want it to be done, but I'm a bit rusty when it comes to managing uploads... Been a couple of years since I last jumped into media code!
-
Bloc. Looked into this yet? ;)
-
Okay, I'll still need opinions on something...
This is from the default skeleton:
<wrapper>
<header />
<menu />
<linktree />
<content_wrap>
<sidebar_wrap>
<sidebar:side></sidebar>
</sidebar_wrap>
<offside_wrap>
<main_wrap>
<top:top></top>
<main:main>
<main />
</main>
</main_wrap>
</offside_wrap>
</content_wrap>
<footer />
</wrapper>
Alternatively, I've added header_wrap and footer_wrap layers:
<wrapper>
<header_wrap>
<header />
<menu />
<linktree />
</header_wrap>
<content_wrap>
<sidebar_wrap>
<sidebar:side></sidebar>
</sidebar_wrap>
<offside_wrap>
<main_wrap>
<top:top></top>
<main:main>
<main />
</main>
</main_wrap>
</offside_wrap>
</content_wrap>
<footer_wrap>
<footer />
</footer_wrap>
</wrapper>
These layers are unused, but the second version ensures that no single layer holds a combination of layers and blocks. Meaning that a layer can only hold either one or more layers, or one or more blocks.
The code that is currently in SVN allows for layers to have both layers and blocks. The good point is that it gives flexibility to themers. The bad point is that once you start mixing these together, it might lead into unexpected results -- which I can control through code, but I'm wondering whether it's best to leave freedom to themers, or force them to put blocks away from layers. However, the solution of putting everything into layers may not be better actually.
Right now I'm only seeing ONE potential problem with layer/block mixes, and it is when using the default setting for loadBlock, i.e. replace existing blocks in a layer with the new one.
- In the second version, it'll be all good, because all I'll be doing is replace the contents of the parent layer. BUT... If a layer is found within the parent layer though, what do I do? Create a new layer and insert the block in it? What name do I give it?
- In the first version though, if I want to insert a block in <content_wrap>, what do I do? Do I remove all of the existing child layers and child blocks? Do I delete only the child blocks? If yes, should I insert the block in place of the first one (which will be removed), or after the last layer? -- Of course, it's likely that if someone tries to replace blocks in such a non-trivial layer, they made a mistake. However, if I just want to add a block to <content_wrap>, it's easy enough, I don't have to create a dummy layer for it.
What do you think would be best, then...?
-
The code that is currently in SVN allows for layers to have both layers and blocks.
Surely, the contents of main_wrap has both a block and a layer in it?
I honestly wouldn't make replace the default; if someone does want to replace the entire contents of a layer, fine, but don't make that the default state of play. (And if they do want to replace, discard the entire contents of that layer and be done with it)
Instead, I'd suggest append should be the default of the day, if someone adds to a layer, the typical behaviour is going to be to add it to the end of the layer. If they can add it arbitrarily inside the layer (before all, before/after a given node) that's important, but at the end should be the default.
If in doubt, think about the typical DOM methods exposed in jQuery as the sorts of operations people do actually want to do: replaceWith, before, after, prepend, append, and wrap. The same operations would typically be desirable for managing blocks and layers - which really aren't any different to DOM manipulation.
-
BTW, last commit has a tiny issue in that it inverts the boolean values for $where, which won't matter since I planned to rewrite that anyway (done.)
The code that is currently in SVN allows for layers to have both layers and blocks.
Surely, the contents of main_wrap has both a block and a layer in it?
Nope... main_wrap has two layers in it. The 'top' layer is empty by default. <top></top> defines an empty layer, while <top /> defines a block.
Maybe I should reconsider the way I'm doing it, though...? Maybe not use pseudo-HTML, but something else? Or use a <layer:mylayer:side,left> and <block:myblock> instead of <layer> and <block />?I honestly wouldn't make replace the default;
Because of the main layer, yes it should be :)
loadBlock() is called over 300 times in the entire codebase. loadBlock with a $where parameter (i.e. "don't replace, do something else") is called less than 20 times...
I could limit loadBlock() to the main layer though, and have addBlock() and removeBlock() functions that are for other situations. (But then I'd probably have to change loadLayer(), too... ;))if someone does want to replace the entire contents of a layer, fine, but don't make that the default state of play. (And if they do want to replace, discard the entire contents of that layer and be done with it)
What if they 'simply' want to discard the blocks in the layer and keep the child layers?
Hmm... Yeah, I can already hear you say, "who would do that anyway" ;)Instead, I'd suggest append should be the default of the day, if someone adds to a layer, the typical behaviour is going to be to add it to the end of the layer.
But doing that in the main layer will break it. For instance, if you go to the Change Skin page, and disable the replacement of blocks, loadBlock() will add the 'pick' block to the lot, so it will call both 'main' and 'pick', which in turns will generate errors because it'll start to show the Admin Theme area... ;)If in doubt, think about the typical DOM methods exposed in jQuery as the sorts of operations people do actually want to do: replaceWith, before, after, prepend, append, and wrap.
Yeah, jQuery probably got it right... ;)
-
Ah, I got the terminology slightly off then.
Regarding replace vs append, there's one fairly good reason why I'd suggest it should be append: mods.
Sure, themers and the core code will typically do replace, because they don't have to care about the consequences nearly as much - they're setting the canvas that mods will later work with.
WedgeDesk used the old subtemplate insertion code, to add subtemplates and so on e.g. to the sidebar, and not once did it do a replace, it was always doing appends.
That said, if the core code does 300 vs 20, then it should probably stand and modders will just have to use it the way I've used it thus far :lol:What if they 'simply' want to discard the blocks in the layer and keep the child layers?
Hmm... Yeah, I can already hear you say, "who would do that anyway"
I can think of reasons why you might.But doing that in the main layer will break it. For instance, if you go to the Change Skin page, and disable the replacement of blocks, loadBlock() will add the 'pick' block to the lot, so it will call both 'main' and 'pick', which in turns will generate errors because it'll start to show the Admin Theme area...
Argh, yes, I can see the problem.Yeah, jQuery probably got it right...
Well, remember that unlike the DOM specification, jQuery was built by and for people who actually *use* the DOM. So the spec says that insertBefore, insert-as-last and removeChild are enough, but the real world needs to use replace, before, after, etc. (And yes, there should have been a remove operation on that list)
-
Regarding replace vs append, there's one fairly good reason why I'd suggest it should be append: mods.
I know, I know...
What I could do: loadBlock will do a replace when called on ':main', and an add when called on anything else. Would that be reasonable, or would it confuse users?
If we end up changing all of Wedge's loadBlock calls to specify 'replace', modders may also be confused, I don't know... I mean, I think most of the loadBlock() calls, even from within mods, will be made on ':main'...That said, if the core code does 300 vs 20, then it should probably stand and modders will just have to use it the way I've used it thus far :lol:
Just as I did...
Ah well.What if they 'simply' want to discard the blocks in the layer and keep the child layers?
Hmm... Yeah, I can already hear you say, "who would do that anyway"
I can think of reasons why you might.
Then it gets complicated, eh.
Of course, mods could still potentially modify $context['template_layers'] directly by themselves. It's not like the array is locked once we get out of loadBlock and loadLayer...
Oh my, I realize I'm getting confused by my own implementation. Not by the basics of it, but by whether or not I should allow mixing layers and blocks together, etc... :-/
I don't even remember my original question :lol:
-
re: rev 996...
loadBlock() can now add blocks before or after a specified layer *or* a specified block.
I decided, at least for now, to allow both kinds of objects as the target, without specifying their type. My code is rather simplish, and it will fail if you attempt to load before or after the 'html' layer (which actually makes sense... :lol:), but I just don't know if it's "all right" to mix the two types together at this point.
I mean... If I do it for 'before' and 'after', why couldn't a modder look for a block by its *semantic hint*?
Only, hints are for layers only. But it makes sense to have them for blocks as well. Maybe I'm going too far... Or maybe I just shouldn't use hints in the first place because it complicates things...?
I'd really, really appreciate to have Bloc's feedback as of now. I'm sure there are both problems and solutions I didn't think about...
Posted: September 12th, 2011, 10:52 PM
Also -- should I add a 'rename' type of addition? i.e. take an existing block and rename it to the new block... It's effectively the equivalent of 'replace' in loadLayer() (except for blocks, of course), but I don't want to make it too complex either...
And what about removeBlock() and removeLayer() functions? Would they be helpful at all?
Posted: September 12th, 2011, 10:56 PM
Bump!
Posted: September 13th, 2011, 09:37 AM
Bump again...
Also, I'm having trouble with XML and WAP2.
Codebase wasn't too solid to begin with. In SMF, if you look closely at the code, even if you're in XML mode, the software will still load a lot of useless things... For instance, in PM mode, it will still load the menu code even though there's nothing to show. Even in loadTheme(), it loads tons of things related to regular theming, even after it was determined that the index template won't be needed (and thus the theme won't be useful.)
Now, the 'funny' thing in Wedge is that I had overlooked that, and thus XML and WAP2 were calling hideChrome() before the layers were actually defined. Ah ah, good times...
Anyway, now I've fixed some of it but I still have a long way to do. Can you spell "all day long"? Can you believe I started this morning by actually looking into avatar code and a firm decision to implement it today? :lol:
-
Hmm, I'm debugging loadBlock() because I ran into what I perceive to be a bug. What I'm trying to do is load a block below 'main' in Post. It works if I specify the default layer, but not if I select the actual block itself.
I found out why I couldn't select a block to add after. It seems that the main block isn't found when loadBlock steps through the layers.
-
Can you print_r($context['skeleton_array']) and print_r($context['layers']) for me before you run the function...? Thanks.
-
It might help to know what calls are placed in case there's something wrong (and also SVN rev)
-
I'll get those in a few. It;s r1030.
-
Alright...
-
Bump for the above.
Also, is the feed block totally driven by the skeleton now rather than late-injected into the sidebar as it used to be? It just occurs to me that some of the things I want to do may well rely on the feed block of the sidebar for positioning/ordering.
-
Oh... For John, not me :P
Also, is the feed block totally driven by the skeleton now rather than late-injected into the sidebar as it used to be?
It's still injected later.
The reasoning behind this is that we want to have the block at the very bottom of the sidebar. We could call it through sidebar_below(), though...It just occurs to me that some of the things I want to do may well rely on the feed block of the sidebar for positioning/ordering.
Before feed block: that's how it behaves...
After feed block: any reason for wanting that...?
-
No, I wasn't thinking of 'after feeds' but I could conceive of wanting things below all other content and thus 'above' feeds, and if late injected, it occurred to me that I couldn't necessarily rely on 'above feeds' for that.
-
No, but you can rely on asking for it to be 'last', because feeds will be injected last...
Of course, we could also have two streams in each direction:
loadBlock('my_block', 'sidebar') would add a block in the normal direction.
loadBlock('my_block', 'sidebar', 'from_end') would add a block in the opposite direction.
So we'd just need to call loadBlock('sidebar_feeds', 'sidebar', 'from_end') ASAP, and then all 'from_end' calls will put the block above feeds. Of course, normal direction will mean it's always added between the current 'normal' position and the 'from_end' position.
-
Yea, I had forgotten that.
That could be good, though I'm a little concerned that we're providing too many variations on a theme - though if we can find valid uses where it would achieve the job better than manual juggling or non-obvious uses (like the above example), then we can run with that too.
-
So what do I do?
-
Would adding the streams provide something that currently can't be done without a lot of work? If not, don't change it.
-
In the case of the sidebar I guess yeah?
-
In the case of the sidebar, new elements are either going to be before or after existing elements, I just didn't immediately realise that 'before feeds' meant 'last in queue', since I don't really imagine anything adding itself after the feeds block...
Given that, is it worth the extra hassle?
-
Hassle? For me? Are you kidding, template skeleton is my best idea since wecss and is even funnier to work on ;)
I'm just at a loss when it comes to turning the stuff into an object but I'm sure it'll be a good thing eventually. At least for readability.
-
Heh, I know what you mean!
Objectifying the template skeleton... hmm.
Well, let's say it's wetpl. What does wetpl need to know or keep control of that nothing else should be controlling or dealing with? Seems to me that it needs to be aware of the context vars attached to the skeleton.
So that means we have a class and it has its own variables that are internal. Since we don't want to allow access to any old routine, it'd be a private variable of the class.
We'd then create a function for querying the skeleton, whose purpose, essentially, is to just return that variable. (This is known as a getter, or accessor, method)
Then you'd create functions under the class that essentially do what loadBlock does now, but there's the difference that instead of having to modify $context, when you're inside the function, you also get $this, allowing you to refer to the internal variable(s).
Really, it'd still be basically the same as loadBlock now, except that it would belong solely to wetpl and it would be able to modify the private variables to prevent anything else touching or breaking them, because you're forcing any changes to go through the methods you've given everything else to use.
-
Well, let's say it's wetpl.
wetem! :PWhat does wetpl need to know or keep control of that nothing else should be controlling or dealing with? Seems to me that it needs to be aware of the context vars attached to the skeleton.
Well, I don't see any reason to have $context['layers'] and $context['skeleton_array'] outside of the object...
As for $context['skeleton'], it can easily be modified to call an object setter instead.Really, it'd still be basically the same as loadBlock now, except that it would belong solely to wetpl and it would be able to modify the private variables to prevent anything else touching or breaking them, because you're forcing any changes to go through the methods you've given everything else to use.
That was your main point for turning it into an object, yes.
And I don't mind doing it one way or the other. ;)
Okay, I haven't added that 'from_end' code yet, because that would probably require renaming the other entries...
Like:
add add block(s) at the end of the layer <layer> <other /> <blocks /> </layer>
first add block(s) at the beginning of the layer <layer> <blocks /> <other /> </layer>
-
Well, not only is it cleaner and 'safer', it is more semantic because you never have to worry about what a random loadBlock function is doing to global variables and it can't be tampered with accidentally by the same.
I'm fine with doing it either way, but if it is going to become wetem, it should be done sooner rather than later, since the last thing I want to have to do is get a publicly-usable release out, ship some add-ons, and have to rejig everything heavily after.
-
Yeah, whatever name, but "wetem" is pronounceable in French at least :p
"weske", maybe...? :^^;:
-
The name isn't critically important, the idea behind it is. wetem is fine with me, weske reminds me of Hesk which I'd rather not be reminded of, thanks. Ugly ugly ugly.
-
OK, I think I found a limitation in the template skeleton, unless I'm missing something fairly big.
For my first plugin, I tackled a simple version of the 'users online today' functionality. Nothing clever, just literally getting all the visitors since midnight (subject to visibility)
Now, adding the template layer to the info_center layer is straightforward enough, but I can't place it before a given block inside that layer; ideally I'd place it after info_center->info_center_usersonline, but I can't see a way of doing that.
Also, I'm thinking it might be useful to add a boolean return to loadBlock and its friends, in case we attempt to load but it isn't there - e.g. if the info_center->info_center_usersonline block doesn't exist, we would be able to detect that and display it somewhere else, or do something else with it at least.
-
loadBlock('my_block', 'info_center_useronline', 'after');
As the documentation says, 'before' and 'after' both accept either a layer or block name, unlike other options which require a layer name.
Boolean? Well, I thought that providing fallbacks would make more sense... (?)
-
loadBlock('my_block', 'info_center_useronline', 'after');
Doesn't work, it just does nothing (this was the very first thing I tried). info_center_usersonline isn't a layer, it's a block. The code only works on adding a block after a layer, not adding a block to the same layer to which the specified block is in.
See the opening to loadBlock: it converts the target (info_center_usersonline) into an array and attempts to match that to $context['layers'], which if it found it, it would put it in $to, but it doesn't find it (because it's not a layer) and promptly returns.
Providing a fallback is fine, assuming it actually wants to do that. It might decide that if the desired place can't be done, it doesn't want to do a fallback - or, slightly more irritatingly, let's take something I considered for WedgeDesk. WD has a two column layout for the main ticket display, some of which I pushed into the sidebar - but if the sidebar doesn't exist, I'd be wanting to create a new template layer to hold things in. (Though, I guess, I could test for the sidebar before trying to add that block in the first place, but my point is: I might want to do other things rather than just having a direct fallback.)
-
Will fix ASAP then.
Last time I tested, it worked. I probably broke it during one of my numerous code changes last month.
Posted: October 2nd, 2011, 06:49 PM
Okay, gotta go, will commit a fix later...
I'm not sure how to deal with it though. I should probably just skip the original test if we're in before or after mode...
-
OK, so now I'm playing with it again, and either I'm missing something or it's still buggy. Right now it could just as easily be me, I'm not feeling 100% (it's gone midnight, the heating's off and yet I'm running a temperature to the point where I'm sweating :/)
Anyway, here's the deal. I'm hacking together a crude Share Topic plugin. Provides links to the FB like button, the Tweet button and the Google +1 button, at a topic level. It's also gotten me to create a new item at the top level for the admin panel where I've found a bug, too.
Now, because I like compartmentalising and easy-extension later, I put each of the three link buttons into their own mini template, and bind them into a custom layer that I add dynamically. For the sidebar it's just not a problem at all to do this, and it works just great adding my new layer as lastchild to the sidebar layer.
It's a bit more problematic adding it into the display template. Now, I seem to recall there being a discussion about mixing layers and blocks, and I was of the understanding that I could essentially create a layout like this:
default layer
block
block
layer
block
block
end layer
block
end default layer
So there's me trying to add it into the template skeleton with:
loadLayer('flitter_topic', 'title_upper', 'before');
To me, this should include the layer into the flow before the title_upper (where the upper title/nav links are, after the report-sent and draft-saved blocks occur), but it doesn't do anything.
Now, it may be that it's not supposed to be used that way, and I have it wrong. Or it may be that it's got a bug. At this stage I'm not particularly fussed which it is, because I can make it all work with:
loadLayer('flitter_topic', 'default', 'firstchild');
It's not exactly the same but for the vast majority of the time, it's close enough. And of course I could easily enough rewrite it to use a block there which should work (haven't retested that yet) But I thought I'd clarify what it was supposed to do before I looked at changing it.
-
It's not a bug, actually... It's as designed. loadLayer() is not supposed to be able to add layers relative to blocks, only to layers.
However, I'm aware that loadBlock() can do it for both blocks and layers, so it only makes sense to allow the same level of creativity for loadLayer(), so I'll look into it.
I'm also looking into, maybe fusing both functions into a 'load' function (wetem::load?) that will take care of inserting a block, layer or array of blocks and layers into a specific position.
I think it'd probably make sense to have something like this...
wetem::load(
array(
'layer' => array(),
'layer2' => array(
'block',
),
'block2',
),
'default',
'add'
);
What do you think...?
The only 'issue' is that I'll have to analyze the array to create a new 'proper' array that looks like what's actually in use in the skeleton array:
array(
'layer' => array(),
'layer2' => array(
'block' => 1,
),
'block2' => 1,
)
i.e. flip block items (and these only), but recursively... (Added benefit: can possibly add some kind of sanitization later on.)
Or I could change the skeleton code to actually do it the other way around, hence removing the need to flip anything... (But no sanitization, of course.)
What do you think?
Posted: October 10th, 2011, 09:07 AM
PS: the use of wetem::load would also imply we couldn't load a layer by just specifying a string, it would have to be array('layer' => array()), but we could either add aliases to that, or simply rely on the fact that no one ever adds a layer without also specifying at least a sub-block at the same time...
-
Ah, so it was me misinterpreting, my bad.
I always thought of layers as being essentially blocks that contain other blocks; there's no real special layer-only behaviour that doesn't logically also apply to blocks, with the exception of being a parent. So yeah, a single fused function would be pretty neat.
I'd also suggest that it is done using flipping and is done that way to allow for sanitisation, though that's just my gut instinct, there's no real reason to insist on it (much as there wasn't much need to sanitise what went into the old template_layers setup)PS: the use of wetem::load would also imply we couldn't load a layer by just specifying a string, it would have to be array('layer' => array()), but we could either add aliases to that, or simply rely on the fact that no one ever adds a layer without also specifying at least a sub-block at the same time...
I'm good with it being an empty array. I'd rather not enforce there being a sub-block defined by necessity.
-
Ah, so it was me misinterpreting, my bad.
I should be apologizing for making the system not very logical when it comes to this... There is absolutely no valid reason for allowing blocks to be added relative to blocks and layers, but be more restrictive about layers.I always thought of layers as being essentially blocks that contain other blocks; there's no real special layer-only behaviour that doesn't logically also apply to blocks, with the exception of being a parent. So yeah, a single fused function would be pretty neat.
Yep. I think it simply goes to show that my concept of template skeleton, while innovative, was a bit restrained by my earlier conception of how SMF's template system was working, i.e. layers were "the big thing" and subtemplates were more casual. The skeleton's target was precisely to allow for layers to become as casual as the rest, but I just didn't realize I was separating layers from blocks simply by having them in a different function.
Somehow, then, it makes sense to declare them as an array in wetem::load() because it shows anyone reading the code that this is a container for blocks.I'd also suggest that it is done using flipping and is done that way to allow for sanitisation, though that's just my gut instinct, there's no real reason to insist on it (much as there wasn't much need to sanitise what went into the old template_layers setup)
It's not a big function, it can always be changed later.
Oh my, if only I could do it myself... I mean, put the template code into an object...
Heck, I'll just look at the other objects and give it a try. The skeleton is so dying to be an object...PS: the use of wetem::load would also imply we couldn't load a layer by just specifying a string, it would have to be array('layer' => array()), but we could either add aliases to that, or simply rely on the fact that no one ever adds a layer without also specifying at least a sub-block at the same time...
Actually loadLayer is only used 10 times, and half the time it's used for loading a block in it immediately after, but the rest of the time it's used to add a parent layer to the default layer, when building the template for a specific feature. I forgot about that... But it's still no big deal, and we could always add a wetem::layer() shortcut.
-
I should be apologizing for making the system not very logical when it comes to this... There is absolutely no valid reason for allowing blocks to be added relative to blocks and layers, but be more restrictive about layers.
I didn't discover it either until I started to use it, because I saw layers as this immutable concept...Yep. I think it simply goes to show that my concept of template skeleton, while innovative, was a bit restrained by my earlier conception of how SMF's template system was working, i.e. layers were "the big thing" and subtemplates were more casual.
I actually thought the same to start with, and somewhere I managed to forget that, probably around the time I realised that from a plugin author's POV, there's no difference, and that a layer is semantically a block that can contain other blocks.Oh my, if only I could do it myself... I mean, put the template code into an object...
Heck, I'll just look at the other objects and give it a try. The skeleton is so dying to be an object...
Look at wesql, it's really similar structurally in this case. There's private variables (much like the template skeleton itself should be as only wetem needs to deal with it), the setup stuff and then public functions.
-
I actually thought the same to start with, and somewhere I managed to forget that, probably around the time I realised that from a plugin author's POV, there's no difference, and that a layer is semantically a block that can contain other blocks.
Yeah...
Actually, we could even get rid of '_before' and '_after' and use '_above' and '_below' instead for block overrides, considering that they're just like a layer, too... (Only layers don't have a central function to call.)
Or the other way around-- rename _above and _below to _before and _after.
What's nice with our layers is that they don't even require _above and _below, meaning layers can just be used as a way to put a bit more structure to the skeleton, e.g. make it easy to add a block at the end of a thematic series of blocks, without having to know the names of the blocks (e.g. if they're added conditionally.)Look at wesql, it's really similar structurally in this case. There's private variables (much like the template skeleton itself should be as only wetem needs to deal with it), the setup stuff and then public functions.
Yeah, I'm looking into it... Working on it.
I'm a bit rusty (or the other way around -- a virgin) when it comes to object building. I did build wecss but it was based upon another object, and I did have trouble with it. Someone remind me -- when should I use self::function and when should I use wetem::function, inside the wetem object? Is any of the two faster, or is it just about scope (i.e. if I use one it'll crash, if I use the other it'll work)?
Are there any noticeable performance penalties in calling these functions? e.g. a recursive function... If I called it a hundred times, would it make sense to optimize the way it's called?
-
Actually, we could even get rid of '_before' and '_after' and use '_above' and '_below' instead for block overrides, considering that they're just like a layer, too... (Only layers don't have a central function to call.)
Or the other way around-- rename _above and _below to _before and _after.
I'm thinking before and after would be nicer, generally. It's more descriptive of what's going on (though above and below is too, just it seems more accurate to say before/after)Someone remind me -- when should I use self::function and when should I use wetem::function, inside the wetem object? Is any of the two faster, or is it just about scope (i.e. if I use one it'll crash, if I use the other it'll work)?
I seem to recall a speed difference when I set up wesql, which is IIRC partly why I ended up making them all static functions even though they don't need to be - I seem to remember that if it's non static but still called through wetem:: it'll have to call the setup function in order to have the instance returned. I would imagine self:: would avoid the same overhead.
If it's in a loop, it's always best to test which is fastest, but I don't recall anything huge involved.
-
I'm thinking before and after would be nicer, generally. It's more descriptive of what's going on (though above and below is too, just it seems more accurate to say before/after)
I think it's more accurate too -- probably because _above and _below imply spatial positioning, when these functions could possibly not output anything, or even _above could output a floated div that shows up below the layer, things like that...I seem to recall a speed difference when I set up wesql, which is IIRC partly why I ended up making them all static functions even though they don't need to be - I seem to remember that if it's non static but still called through wetem:: it'll have to call the setup function in order to have the instance returned. I would imagine self:: would avoid the same overhead.
All of the functions are static right now.
Okay, I'll just go ahead and finish a working version, and then I'll commit, and I'll let you 'fix' whatever doesn't work...
Hell, I love being finally able to remove the skeleton_ namespace from all functions... :P
What I don't like as much, though, is replacing $context['layers'] with self::$layers. It's shorter, but Notepad2 shows it in plain black and dark blue, instead of 'layers' being shown in limegreen (because it's a string), so it suddenly becomes harder to spot any layer manipulation in the code... Meh. (And before you ask -- one of Notepad2's issues is that it doesn't allow to add a custom color for a regex-delimited string like "self::\$\w+"...)
-
What I don't like as much, though, is replacing $context['layers'] with self::$layers
But the only layers manipulation using wetem::$layers should be inside wetem (and it should be a private variable for this reason) - all the other stuff should be wetem:: calls outside it... though I guess the main places it's used are in Subs-Template currently...
Nope, haven't got a good answer for that one, sorry.
-
It's not a biggie anyway...
Okay, took me less than an hour to make the transition. Tested on Display.php, after a couple of minutes of debugging it worked flawlessly. :)
self:: can be used anywhere inside the class, I didn't have to rely on wetem::, the only bugs I had were with my build() rewrite where I was trying to avoid using adding a secondary (private) function for it, in the end I did that and it did the skeleton parsing correctly.
Working on converting all loadBlocks and then I'll commit...
PS: and yes, self::$layers is private, of course. That's the whole point of the object :)
-
If it works properly, it's probably correctly written ;)
-
Was busy IRL.
I'm working on converting the templates.
Interestingly, I never noticed but the media codepath (the one that returns an image, similar to dlattach) goes through the entire process and loads even the menu code...
I reckon it should be skipped. Load.php has a $simpleActions array that holds items that don't need a template, but maybe I should instead use the same path as action=dlattach, i.e. skip the code when dlattach skips it. Ultimately I'd like to get rid of most media path calls though, but for now I think it's necessary to lighten it.
Now, I was looking at the index.php file and found this. It's used in a similar fashion in Wedge but here's the SMF code:
// Attachments don't require the entire theme to be loaded.
if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'dlattach' && (!empty($modSettings['allow_guestAccess']) && $user_info['is_guest']))
detectBrowser();
// Load the current theme. (note that ?theme=1 will also work, may be used for guest theming.)
else
loadTheme();
Now... It basically says, "skip loading the theme for dlattach, ONLY if the user is a guest and guest access is enabled.
What's with the guest thing? dlattach will never use theme data AFAIK, so it would make sense to skip loadTheme for everything... What do you think of this?
-
I think it's to do with falling back in the event of error. If guest access is off, the theme will be needed. If it's a guest, there's a possibility it'll need the guest to log in (remember: access to attachments is not provided to guests by default)
I'm not sure why else you'd need that, though.
Yes, media should be lightened, which is why I was in favour of pushing serving items into something like dlattach - there's really no need to invoke the entire media action (and all the theme loading) just for serving files.
-
I think it's to do with falling back in the event of error. If guest access is off, the theme will be needed.
Technically, since the item will be called half the time through an img tag, whether you have the theme or not is irrelevant here, since all you'll get is a broken image... As for downloads, Wedge can simply return a "file not found" error or something, without any theme around it. Just plain text...If it's a guest, there's a possibility it'll need the guest to log in (remember: access to attachments is not provided to guests by default)
The code as I posted/spotted above will precisely not load the theme code for guests.. (?)I'm not sure why else you'd need that, though.
It's quite obscure to me.Yes, media should be lightened, which is why I was in favour of pushing serving items into something like dlattach - there's really no need to invoke the entire media action (and all the theme loading) just for serving files.
I'll leave it at that for now...
Okay, I'm starting manually converting the stuff but I suspect I'll do a commit that will break Wedge. Just for sanity reasons -- first committing the main code change, and then committing the fixes to make the whole thing work.
In the meantime, I was thinking, maybe we shouldn't call the block loading code 'load' but use 'add' instead... Because that's precisely what it does. Except for the default layer, I know... :lol:
Well, I suppose (?) I could introduce a few shortcuts, like wetem::add(..., '') would actually call wetem::load(..., '', 'add'). Does that make any sense...?
-
Technically, since the item will be called half the time through an img tag, whether you have the theme or not is irrelevant here, since all you'll get is a broken image... As for downloads, Wedge can simply return a "file not found" error or something, without any theme around it. Just plain text...
True enough!The code as I posted/spotted above will precisely not load the theme code for guests.. (?)
Oh, my bad. I was just trying to go through the circumstances in which you might want to but there aren't really any.Okay, I'm starting manually converting the stuff but I suspect I'll do a commit that will break Wedge. Just for sanity reasons -- first committing the main code change, and then committing the fixes to make the whole thing work.
Works for me. I'm not in the middle of anything that will be broken if I sync, so I can readily wait until you're done before updating.In the meantime, I was thinking, maybe we shouldn't call the block loading code 'load' but use 'add' instead... Because that's precisely what it does. Except for the default layer, I know...
Well, technically it is still adding, even if there wasn't anything to add to before. It's essentially the same as saying x += y but dealing with the case of empty(x) first... no?
To me, calling it 'add' would make more sense.
-
Oh, my bad. I was just trying to go through the circumstances in which you might want to but there aren't really any.
So, you agree we should be doing even less work for dlattach at this point...?Works for me. I'm not in the middle of anything that will be broken if I sync, so I can readily wait until you're done before updating.
Well turns out I didn't leave it broken for long (a few minutes). I just split the stuff so I didn't have to mix 'proper changes' with 'site-wide search & replace changes' in the same commit. That way, you can check out my changes while skipping a specific commit so you don't have to go through a long list of boring changes...
I'll do the same if/when I rename the load() method.
Oh, BTW, I've found out why I find it a bit ugly...
loadLanguage()
loadTemplate()
loadBlock()
We have a lot of these together. Now it's like:
loadLanguage()
loadTemplate()
wetem::load()
Meh... It's like I broke the pattern :PIn the meantime, I was thinking, maybe we shouldn't call the block loading code 'load' but use 'add' instead... Because that's precisely what it does. Except for the default layer, I know...
Well, technically it is still adding, even if there wasn't anything to add to before. It's essentially the same as saying x += y but dealing with the case of empty(x) first... no?
Hmm no...
I'll think about all of that when I have a moment to resume my work.
In the meantime, feel free to look at my object code and improve it (i.e. anything related to object optimization, not template manipulation, which I'll deal with later to merge the block and layer loading code.)To me, calling it 'add' would make more sense.
It definitely makes more sense. Except for the default layer but shhh ;)
-
So, you agree we should be doing even less work for dlattach at this point...?
However you slice it, for something whose purpose is solely to authenticate the user, then serve a file, we should be doing absolutely as little as possible.
If SSI were slimmer I'd suggest dropping dlattach and using an external file instead. Thing is, SSI sets up a whole bunch of stuff like loadTheme calls :/Meh... It's like I broke the pattern
I have been wondering about a System class that handles stuff like loading sources and templates, which would give:
wesys::loadTemplate()
wesys::loadSource()
but it's too long, need to shorten it down! :PIn the meantime, feel free to look at my object code and improve it (i.e. anything related to object optimization, not template manipulation, which I'll deal with later to merge the block and layer loading code.)
I will when I've had my fun with SVG images. I've never done SVG before, it's quite interesting to just play with.It definitely makes more sense. Except for the default layer but shhh
How is it different? You're still adding to a list, except the list was totally empty beforehand.
-
However you slice it, for something whose purpose is solely to authenticate the user, then serve a file, we should be doing absolutely as little as possible.
So... Who adds it to their to-do? :PI have been wondering about a System class that handles stuff like loading sources and templates, which would give:
wesys::loadTemplate()
wesys::loadSource()
wesys is still a cool name... ;)
It's better than 'wetem', but it doesn't indicate what it's for.
I'm wondering whether execBlock() should be in wetem.
I tried moving it to a private method, but then I remembered that Load.php and other files will use it to run specific functions from template files, such as template_init(), so I made it public, but then it doesn't have much of a point being in the object... Except for being called through self::exec in the render method.
I try having as little data as possible in the object that is not directly related to outputting non-template data. I've been wondering about while_we_re_here(), for example...
I've already sorted out the functions to push everything public to the beginning of the object, and everything private to the end. Seems cleaner to me that way, although on the other hand it also separates some functions from their twins, like render() is no longer followed by render_recursive(). I don't think it's that big a problem, as I'm not going to keep developing wetem forever... After a while, it'll be solid enough that no one will even bother to look at the code.
Oh, and I also turned the static variables into private, and the wetem class to final. I don't see any reason to inherit it... Might as well protect it entirely. If in the future a use is found in inheriting from wetem, then we can always remove the final keyword.How is it different? You're still adding to a list, except the list was totally empty beforehand.
But in the case of default, the list is never empty, is it..? It has the 'main' block by default in it...
-
So... Who adds it to their to-do?
Well, refitting the API is on my todo list for the murky future... but for now, neither of us. There are bigger fish to fry - though it's certainly relevant in the integration of Aeva for attachments.I tried moving it to a private method, but then I remembered that Load.php and other files will use it to run specific functions from template files, such as template_init(), so I made it public, but then it doesn't have much of a point being in the object... Except for being called through self::exec in the render method.
Except for the small detail that if it's not part of the object, it won't have access to the object's variables. Does it need access to the block list for any reason, for example?I try having as little data as possible in the object that is not directly related to outputting non-template data. I've been wondering about while_we_re_here(), for example...
That's the general idea; stuff that the object doesn't *need*, it shouldn't *have*.But in the case of default, the list is never empty, is it..? It has the 'main' block by default in it...
But you're still adding to it, right?
Perhaps a better verb would be 'merge', which covers both adding and replacing...
-
So... Who adds it to their to-do?
Well, refitting the API is on my todo list for the murky future... but for now, neither of us. There are bigger fish to fry - though it's certainly relevant in the integration of Aeva for attachments.
I'm still so wary of Aeva's bundling...
I mean, today I was thinking again about the comment system for AeMe and wondering whether we should beef it up, make it smaller (in UI at least), or simply integrate it into wedge_messages... Then I was wondering, is it necessary to implement floating topics before we can use wedge_messages to store posts that don't belong in a topic...? And then I thought, do we really need to put all 'floating topics' (i.e. topics, profile comments, media comments...) inside the topic table? Can't we just deal with these in the messages table, have a special 'wedge' field in wedge_messages that allows us to store a message origin, whether a topic, profile or media, I don't know, when I start thinking like that, I start to lose myself in thought...
Last week I was spending an afternoon with a friend who needed my help to configure .htaccess and .htpasswd features on her portfolio website. We spent about 3 hours on it, and in the end she commented to Milady, "I don't know how he does it. With all the music, and with his focus switching from one thing to another every other second..."
But, well, I did it :P And yes I'm probably a bit ADD.
Which brings me back to, ah, these annoying floating topics... I think I should just rename this to 'floating messages' and give up on the idea of storing the type in the topic table, and rather have it in the message table, with a proper index.
(I give you 5 minutes before you tell me it's the worst idea I had this week :P)Except for the small detail that if it's not part of the object, it won't have access to the object's variables. Does it need access to the block list for any reason, for example?
Nope, it doesn't... Which is why I didn't push it into the object to begin with. It already has the block's name at this point, so it simply needs to call template_blockname().But in the case of default, the list is never empty, is it..? It has the 'main' block by default in it...
But you're still adding to it, right?
Nope... load('block', 'default') will replace the 'main' block. load('block', 'sidebar') will add to the current blocks.
I think we already went through that... :P
-
Which brings me back to, ah, these annoying floating topics... I think I should just rename this to 'floating messages' and give up on the idea of storing the type in the topic table, and rather have it in the message table, with a proper index.
It's not the worst idea you had this week. I'm not sure what is, but this wasn't it.
No, essentially what is needed is adding something to the topic - not the message - to define where it is. That takes care of content management internally.
All you do, much like I talked about for media items, is convert the board id into half of two columns: you have 'topic type' and 'topic context'; the type refers to board, or media item or whatever, and context is the board id or album id.
Displaying that content is another matter entirely, because then it comes down purely to presentation how you want to display it - since you'd realistically never use the same layout everywhere. The layout for posts (be they forum or blog posts) wouldn't be the same as in the PM area, wouldn't be the same as comments in media items, and whatever else (I certainly wouldn't reuse the same layout for WD, I'd keep closer to WD's original layout)
To sum up, it is exactly what you're talking about, but tied to the topic, not the individual message. A given message lives in a given topic. It's the topic which forms a collection of messages that you need to deal with putting an origin into.Nope, it doesn't... Which is why I didn't push it into the object to begin with. It already has the block's name at this point, so it simply needs to call template_blockname().
Then it doesn't really need to belong to the class, though there's no reason why it *can't*. It is sort of between the two, go with whatever makes more sense.Nope... load('block', 'default') will replace the 'main' block. load('block', 'sidebar') will add to the current blocks.
I think we already went through that...
So you're merging then? :P Consider array_merge. It replaces elements in the first source with those from the second, and is quite content to add things on the end as well under the right circumstances...
-
It's not the worst idea you had this week. I'm not sure what is, but this wasn't it.
I think I should feel offended... :lol:No, essentially what is needed is adding something to the topic - not the message - to define where it is. That takes care of content management internally.
Then that's exactly the original definition of floating topics...All you do, much like I talked about for media items, is convert the board id into half of two columns: you have 'topic type' and 'topic context'; the type refers to board, or media item or whatever, and context is the board id or album id.
Which also means we can't have both a topic ID of #1 and an album ID of #1. Or we have to ditch the id_topic key in favor of an (id_topic, board_type) key. Which I'm not sure would be as fast...?Displaying that content is another matter entirely,
Definitely. I was still referring simply to the storing of data itself.Then it doesn't really need to belong to the class, though there's no reason why it *can't*. It is sort of between the two, go with whatever makes more sense.
A shorter wetem is what I'm looking at for now.Nope... load('block', 'default') will replace the 'main' block. load('block', 'sidebar') will add to the current blocks.
I think we already went through that...
So you're merging then? :P Consider array_merge. It replaces elements in the first source with those from the second, and is quite content to add things on the end as well under the right circumstances...
Don't confuse me... :whistle:
I'm already confused enough with the merging (ahah) of ::load and ::layer... And actually I shouldn't do it, really. I think.
Take an example...
::load(array('layer' => array('block')), 'default', 'replace')
Okay, what do you do with this...?
- loadBlock() would do this: take the 'default' layer, empty it, except for its child layers. Then add the contents of the array to it. i.e. we would have <wrapper><default><layer><block /></layer></default></wrapper>.
- loadLayer() would do this: take the 'default' layer, and REPLACE it with the 'layer' layer. We would have this: <wrapper><layer></layer></wrapper>.
So, I went ahead and added a 'rename' value for ::load() not to get confused, but what to do in our example, where I'm providing contents for the layer? Should I also empty out the original layer and add data to it? Or should I just rename the layer, and don't bother with the provided contents...?
So much fun for me...
I guess I'll just keep the ::layer method for easy addition of container layers, like used to be done in SMF.
And I'll consider calls to ::load to be, well... Just a series of blocks.
-
I think I should feel offended... :lol:
Nope, wasn't meant as one. There simply haven't been any bad ideas.Then that's exactly the original definition of floating topics...
Yup, hehe ;)Or we have to ditch the id_topic key in favor of an (id_topic, board_type) key. Which I'm not sure would be as fast...?
You'd make id_topic remain the PK, then have a unique index on source_type, source_id. It'd be comparable to now, and should be faster under some circumstances.Definitely. I was still referring simply to the storing of data itself.
*nods*A shorter wetem is what I'm looking at for now.
Works for me.Don't confuse me... :whistle:
Heh. Well, just seems to me that add (or better, merge) is the right verb to describe the operation being carried out.::load(array('layer' => array('block')), 'default', 'replace')
Okay, what do you do with this...?
This says to me to replace the current contents of default with a new layer (with that new block in it)
The rename is a good idea.I guess I'll just keep the ::layer method for easy addition of container layers, like used to be done in SMF.
And I'll consider calls to ::load to be, well... Just a series of blocks.
Works for me.
-
Nope, wasn't meant as one. There simply haven't been any bad ideas.
You can always try, but you'll have a hard time trying to offend me, given that I'm convinced that whenever you criticize me, it's because I deserve it, not because you want to offend me ;)You'd make id_topic remain the PK,
...which, again, means we can't have both a topic=1.0 and a media album with ID #1. Creating a first album when topic=1.0 already exists will set the album ID to 2. And that's precisely one of the major blockers for me...Heh. Well, just seems to me that add (or better, merge) is the right verb to describe the operation being carried out.
Right now I'm staying at ::load(), waiting for feedback.::load(array('layer' => array('block')), 'default', 'replace')
Okay, what do you do with this...?
This says to me to replace the current contents of default with a new layer (with that new block in it)
Exactly... Except if you replace $blocks with array('layer' => array('block'), 'block2'), it's exactly the same except that we want to add another block right after the layer... So, technically, should Wedge behave completely differently (i.e. replace the contents of the layer rather than the layer itself) just because I added a block to the list...?
Working on replacing _above and _below with _before and _after... It's quite odd. Oh, and there's an even stranger one -- Reports.php has both a 'print' layer and a 'print' block. UH!
-
...which, again, means we can't have both a topic=1.0 and a media album with ID #1. Creating a first album when topic=1.0 already exists will set the album ID to 2. And that's precisely one of the major blockers for me...
Wait, what?
The boards and albums table will be left alone, because they're foreign keys to the source-type/source-id item.
If you create a board, and an album, they're both id 1 in their respective tables.
The first topic to be created is topic id 1 (source type: board, source id 1, as it's in board 1). Then we upload a media item... it's media item 1 (in album 1), but it consumes topic id 2 (source type: album, source id 1)
You can define multiple types of index on a typical; topic own id has to be the primary key because it's auto-increment and that ensures uniqueness for the topic itself (so you don't end up with multiple topic id 1 cases)
-
...which, again, means we can't have both a topic=1.0 and a media album with ID #1. Creating a first album when topic=1.0 already exists will set the album ID to 2. And that's precisely one of the major blockers for me...
Wait, what?
The boards and albums table will be left alone, because they're foreign keys to the source-type/source-id item.
But if id_topic is the primary index, then it's unique as well, isn't it..? So we can't hold two different items with id_topic = 1 in the topic table... (Can we?)The first topic to be created is topic id 1 (source type: board, source id 1, as it's in board 1). Then we upload a media item... it's media item 1 (in album 1), but it consumes topic id 2 (source type: album, source id 1)
Then we can't have a topic=2.0... Same problem. No?
Or do you mean to store the actual topic IDs in a different place than {db_prefix}topics...?
(Also, FWIW, I've updated the demo site to the latest SVN... Except I haven't updated the database, so it's bound to crash on the missing items.)
-
But if id_topic is the primary index, then it's unique as well, isn't it..? So we can't hold two different items with id_topic = 1 in the topic table... (Can we?)
No, that's because it's auto increment and thus unique.Then we can't have a topic=2.0... Same problem. No?
Or do you mean to store the actual topic IDs in a different place than {db_prefix}topics...?
Same problem. Might as well scratch the idea of floating topics since it cannot be implemented in a way that to be able to have contiguous user visible topics without making it over complicated (by having the user visible id be separate and disconnected from the physical id, because you then have to get into the realms of transactions to ensure that the id you use for insertion is actually the next id and hasn't been stepped on in the time between querying for last-used id and the row insertion...)
If the choice is between having separate tables or juggling ids, I'll take separate tables every time.
-
Hmm. And if we only created dummy topic Ids each time a comment is posted on a profile or album or item?
we could associate these dummy Ids with the real element Id in a new table... Dunno.
-
Hmm. And if we only created dummy topic Ids each time a comment is posted on a profile or album or item?
we could associate these dummy Ids with the real element Id in a new table... Dunno.
Which is juggling ids, which is more work, requires transactions to achieve reliably, and complicates matters.
-
Profile comments and Media comments = less used, less likely to have lots of items, less likely to be a pain in the ass to maintain, IMHO.
-
Totally unrelated (again)... Would post in the 'These two bytes won't matter to you' topic, but I have a post to answer over there and if I post this, I'll forget about the other one ;)
I tried running minification processes on inline JavaScript. I took the media homepage as an example.
Running nothing: about .08s to execute the page
Running JSMin on the whole page: about 0.17s
Running Packer on the whole page: about 0.38s
Additionally, Packer tends to crash the page in some situations...
So JSMin is definitely the winner here.
However, it still doubles the time needed to generate the page... Which would be fine if it saved a lot of data, but it isn't the case.
Full page: 33759 bytes
Compressed: 32107 bytes
So it saves about 1.6kb...
Which is reduced to about 400 bytes after zipping the files.
About 4% saved on the full size.
I'm not exactly sure it's worth it... Sure, it's good for bandwidth (that's 400 bytes saved on *each* page load), but if it makes page generation twice more expensive... Not sure it's worth it.
Does anyone know of a PHP script that can compress JavaScript on the fly VERY quickly? And I mean, VERY?
I don't mind if it isn't optimized for size... I need something that optimizes for speed!
-
Does anyone know of a PHP script that can compress JavaScript on the fly VERY quickly? And I mean, VERY?
I don't mind if it isn't optimized for size... I need something that optimizes for speed!
I don't think there is one. Packing JS is not normally a JIT type process, it's done in batch and pushed out once done. Even the likes of JSMin and Packer are not designed for JIT and not really in the manner in which Wedge uses them (which is about the closest to JIT I think you're going to get)
-
I'm just pretty sure there's a way to minify these with little overhead even at the cost of limited gains.
-
Question: what happens to the size of the file before and after with gzip?
I remember someone doing a test to shorten $scripturl to just 'index.php' instead of prepending it with $boardurl, and finding the gzipped difference was only 200 bytes. I wonder if something similar would be the case here.
I also wonder whether it wouldn't be worthwhile stripping \s{2,} from the buffer while we're at it (since bbcode/posted code is not subject to that limitation, as it's injected with nbsp entities during preparse)
-
There's something still up with this, even with the latest changes.
So, I want to add a block to the info_center layer, before the statistics (info_center_statistics is the target block I want to insert before)
So, naturally, I'm thinking the call should be:
wetem::load('birthdays_info_center', 'info_center_statistics', 'before');
This promptly causes it to get very upset and throw the skeleton error. Oddly it only renders a very limited set of the page (it renders the everything except the <body> tag in the source HTML, so I get the headers, <head> and closing </html>)
More interestingly, I get:http://smf/wedge/index.php
2: Invalid argument supplied for foreach()
File: C:/Dev/public_html/smf_test/wedge/Sources/Subs-Template.php
Line: 1440
in the error log. Line 1440 is the foreach in wetem::render_recursive that performs the iteration through the skeleton and either calls render_recursive again or execBlock. Logical, I guess, if the template structure is broken and that what it's being fed isn't an array.
You want to debug or want me to do it?
-
I'll look into it... I'm busy IRL and I have a commit coming up once I have time to deal with it (the <we:scripturl> changes.)
BTW, I'm not thrilled having <we:scripturl> inside tags. Like <a href="<we:scripturl>">, I find that ugly... Isn't there any other 'realistic' character that gets turned into entities inside posts? Can't think of anything for now...
-
There's no real hurry, just that it's something that needs to be fixed prior to release.
Isn't there any other 'realistic' character that gets turned into entities inside posts
The only guaranteed ones are <, > and & - plus apostrophes and quote marks if we leave ENT_QUOTES in (as opposed to ENT_COMPAT)
It is a bit ugly, but I don't really see an alternative, other than leaving everything how it is currently.
-
Hmm yeah, <> remains best here...
How about something like <SCRIPT>? In uppercase... It's likelier to be sent as a placeholder tag, than a <we:> which is mainly for themers (being used in macros and all...)
-
Anything like that will work and yes, it would be better than using <we:*> for that. But I suggest not using <script> for the obvious confusion reason...
-
Well, obviously yes :P Although it would never come to mind (mine at least) to use uppercase in HTML... :lol:
Hmm... Why not simply <URL>? It's an acronym so it 'makes sense' in uppercase. And I don't believe we need to have $boardurl much, so it's unlikely we'll be having a <URL> for $boardurl in the future...
Posted: October 13th, 2011, 09:23 PM
Oops, latest we:scripturl commits breaks Wedge... Sorry, didn't test earlier ;)
It's due to the way macros are parsed. I'll have to fix that, too, in addition to the other bugs you mentioned...
Posted: October 13th, 2011, 09:27 PM
(This is fixed by just using anything non-<we:>, BTW...)
-
Using <URL> is fine with me :)
-
Good then.
-
So... The problem was within reindex(), more specifically self::$layers = array() was actually emptying self::$skeleton in the process.
This should NOT, I repeat this should NOT have happened, ever... Because an array of references, when erased, will not erase its referenced data, only the 'link' to the referenced data. (An easy way to create a memory hole since if you have no other reference to it, it's lost and not regained...)
I tried many solutions, I tried unsetting the data part by part, at best it didn't work, at worst (90% of the time) it actually crashed my server...
So I decided to let it do it, and simply save self::$skeleton ($transit = self::$skeleton) and reset it right after erasing the layer list.
And... It didn't work either (i.e. the $transit variable was also emptied after the self::$layers line). I was starting to go crazy because self::$skeleton is just a plain regular array, not an array of references, but I tried to 'simply' get it as raw data (through unserialize(serialize())), and this time it worked. :)
Really... I don't wanna know why it works this way.
Heck, yeah I'd love to know... But I already wasted a lot of time on this, and I suspect investigating would only waste even more time. And I'd rather waste my time playing RPGs than determining why PHP is buggy... :P
Please confirm that it's fixed on your side.
-
I'll test it shortly, but now you got me curious as to why.
Remember though that iterating a loop will the key iterator and last value hanging around until it falls out of scope at which point it's GC'd. Smells like one of those references is lingering.
-
I'll test it shortly, but now you got me curious as to why.
I fixed it 'quickly' because I'd already tried and failed to fix the same problem last week or so, when I'd mistakenly removed an ampersand from within reindex_recursive() (in the foreach). Turned out that ampersand was vital... :P
Anyway, if you find a faster solution, please be my guest! But don't waste too much time on it...Remember though that iterating a loop will the key iterator and last value hanging around until it falls out of scope at which point it's GC'd. Smells like one of those references is lingering.
Have no idea what you're talking about...... :whistle:
-
Have no idea what you're talking about......
foreach ($array as $k => &$v)
$k and $v are still set after the loop finishes, and $v is still a reference. Normally it isn't too much of a problem because it's within only the scope of the current function, which means at the end of the function, it's going to fall out of scope and becomes available for the garbage collector to free up.
If $v happens to be a reference to something that might remain in scope after the function ends, it might still be GC'd, but then you garbage collect something that wasn't supposed to be, and boom, segfault.
References are voodoo when you put then inside recursion. They're powerful but dangerous if you're not careful.
-
If it throws away a reference it shouldn't be throwing way the original. Unset isn't the same as setting the reference to zero pr something. That'd be a php bug.
-
I know, but there are times the GC is a little enthusiastic about housekeeping of references.
-
Confirmed the bug is fixed, I can now add template blocks before others as expected :)
-
Hmm, I think I found another bug, this time in wetem::layer. Just want to confirm I'm using it correctly or not as the case may be.
This one's from WedgeDesk.
wetem::load(
array(
'shd_post_nojs',
'post_navigation',
'preview',
'ticket_info',
'ticket_subjectbox',
'ticket_meta',
'ticket_postbox',
'ticket_footer',
'ticket_pageend',
'ticket_proxy_js',
),
'default',
'replace'
);
if (!empty($context['ticket_form']['do_replies']))
{
wetem::layer('ticket_replies', 'ticket_pageend', 'before');
wetem::load('ticket_do_replies', 'ticket_replies', 'add');
}
It's a long story as to why that's a replace up in the first load call, but that's what it has to be for the time being until I fix other things. This is based against r1142, but I have something to add in a moment about r1143.
Anyway, my understanding is that I can dynamically create a layer through wetem::layer and have it positioned where I want in the list, and I want to add it dynamically based on a variable that I know to exist and be set correctly. Except that although the if() is executed, wetem::layer never adds ticket_replies as a layer before ticket_pageend, and do-replies is never added to the list.
I know I can work around it by declaring the layer up front in the main load call and then dynamically removing it if the relevant variable is empty, but that seems clumsy to me.
Also, r1143 will break any instance of array_insert; all places it was called (e.g. the template skeleton) relied on it modifying $array by reference but now it's returning a value - and wetem (amongst other places) isn't picking that up. I'll fix it tomorrow if you don't get to it first.
-
Okay, a few things....
- The post above: is it still valid? I suspect so, but I never quite understood what was wrong with the code... Maybe you could dig into it again? Thank you.
- I'm not too happy with the welay object. I renamed it to wetemItem because, well, it can also hold a block, and I decided to drop the jQuery naming conventions, so I re-renamed 'append' to 'add', and 'prepend' to 'first'. Also, I renamed 'wrap' to 'outer'.
- I decided that considering there are NOT a lot of places in Wedge where we could use method chaining anyway, weitemItem will only be there 'for the show', but not actually used if we can do otherwise.
- I renamed wetem::load() to wetem::op() (operations), made it private, and added a ::load() that does the 'replace' thing. Also added ::add() and other public static stations. Given that 95% of the use of wetem is to load a full block into the default layer, I think there's no need to bother in the first place.
- I'm considering inverting the order of parameters.
wetem::add('sidebar', 'block1') would add this block to the sidebar.
wetem::load(array('block1', 'block2')) would load (not add) these blocks to the default layer.
This would allow to keep the simple syntax of the majority of calls (wetem::load('block')), while making all functions behave in a logical way -- I think it really makes more sense to have the target name first, and then whatever we want to add to it. And even more when it comes to wetem::rename('current_layer', 'new_name').
However, this MAY sound complicated or illogical to many people.
Of course, people could 'simply' do wetem::get('sidebar')->add('block1') for similar results, and with the added benefit of specifying the target layer first. I'm just... Not sure which is best right now.
Any opinions on all of this...?
-
- The post above: is it still valid? I suspect so, but I never quite understood what was wrong with the code... Maybe you could dig into it again? Thank you.
That was the point. The code should have worked but it didn't work as expected, in that the layer that (as far as I was concerned) should have been created, just wasn't being created.- I decided that considering there are NOT a lot of places in Wedge where we could use method chaining anyway, weitemItem will only be there 'for the show', but not actually used if we can do otherwise.
This was something that bugged me. I saw it was cool but I couldn't quite envisage where it would be beneficial over anything else we were really doing at the time.- I renamed wetem::load() to wetem::op() (operations), made it private, and added a ::load() that does the 'replace' thing. Also added ::add() and other public static stations. Given that 95% of the use of wetem is to load a full block into the default layer, I think there's no need to bother in the first place.
95% of *Wedge's* use might be that. But that means, yay, I get to fix every plugin I've written thus far that adds a block, because they all use load to add to the layers, though it would logically be better to use an add method.- I'm considering inverting the order of parameters.
wetem::add('sidebar', 'block1') would add this block to the sidebar.
wetem::load(array('block1', 'block2')) would load (not add) these blocks to the default layer.
Makes sense.However, this MAY sound complicated or illogical to many people.
As long as it's documented and there are examples, it seems to make sense...Of course, people could 'simply' do wetem::get('sidebar')->add('block1') for similar results, and with the added benefit of specifying the target layer first. I'm just... Not sure which is best right now.
I don't think the chaining really adds anything here.
-
That was the point. The code should have worked but it didn't work as expected, in that the layer that (as far as I was concerned) should have been created, just wasn't being created.
Does it work if you don't execute the ::load() before it? Do you remember...?This was something that bugged me. I saw it was cool but I couldn't quite envisage where it would be beneficial over anything else we were really doing at the time.
The main point was me learning more about singletons and non-static methods, I guess... :lol:95% of *Wedge's* use might be that. But that means, yay, I get to fix every plugin I've written thus far that adds a block, because they all use load to add to the layers, though it would logically be better to use an add method.
Hmm... 'Oops'?
I could ensure ::load stays public, but I have a feeling that you would want to 'give the right example' and rewrite your code to use :add anyway. It's relatively fast to update, though...Well, it's easy to understand when one of the params is an array, but if it's not, it could lead to misunderstandings... Was it wetem::add('side', 'sidebar') or wetem::add('sidebar', 'side') already?Of course, people could 'simply' do wetem::get('sidebar')->add('block1') for similar results, and with the added benefit of specifying the target layer first. I'm just... Not sure which is best right now.
I don't think the chaining really adds anything here.
My documentation for wetemItem has this:
wetem::get('sidebar_dummy')->parent()->rename('sidebar2')->inner('inside_sidebar');
:lol:
Well, I guess it's mostly interesting for the parent() function at this point. And readability.
-
This one's damn funny...
wetem::load('profile_top', array('top', 'default'));
Any n00b might think, 'load the top and default blocks into the profile_top layer'... When it's actually the other way around ;)
Anyway, that one reminds me that I can't even use is_array() to determine the position of $blocks in the param list... :P
Posted: November 23rd, 2011, 11:25 PM
I've converted all templates manually in about 10 minutes. So it should be doable... Just do a regex search on ::load[^)]+$ and ::load.*,
It should be enough to catch all 'special cases'...
Bed time, and Subs-Template.php is not finished yet, so I'll commit tomorrow.
-
Bump! For previous page.
-
Does it work if you don't execute the ::load() before it? Do you remember...?
Didn't try it, because the whole point was to add a layer dynamically after the rest of the stuff had been created. To me, having a caveat that says 'you can only create new layers before resetting the default layer contents' is a bit banal.Hmm... 'Oops'?
I could ensure ::load stays public, but I have a feeling that you would want to 'give the right example' and rewrite your code to use :add anyway. It's relatively fast to update, though...
That's partly why I'm enthusiastic about building plugins, so that there are 'best practice' examples to work with. Besides, it does seem more logical to have add as a separate method because it does define what it's doing.
(I don't really mind updating my plugins. It's the curse of writing plugins this early, really.)Well, it's easy to understand when one of the params is an array, but if it's not, it could lead to misunderstandings... Was it wetem::add('side', 'sidebar') or wetem::add('sidebar', 'side') already?
Yeah...My documentation for wetemItem has this:
wetem::get('sidebar_dummy')->parent()->rename('sidebar2')->inner('inside_sidebar');
That's the sort of case that chaining really allows for - which is an improvement over the equivalent unchained methodology. Just that for most uses in the core, and most plugin uses, chaining doesn't bring anything huge.
-
Didn't try it, because the whole point was to add a layer dynamically after the rest of the stuff had been created. To me, having a caveat that says 'you can only create new layers before resetting the default layer contents' is a bit banal.
Yeah, sure...
I'll take some time to look into this. Maybe it's "fixed" in the new code already, I don't know... (I mean, I found and fixed a bug with 'load(before)'.)That's partly why I'm enthusiastic about building plugins, so that there are 'best practice' examples to work with. Besides, it does seem more logical to have add as a separate method because it does define what it's doing.
Yep... I think we discussed it in the early days of wetem, but I forgot to think further about it...(I don't really mind updating my plugins. It's the curse of writing plugins this early, really.)
And besides, it's not going to be as annoying as my own work on the rewrite itself... Believe me, I had to double-check the entire friggin' code at least 10 times today... :^^;:
Too bad I deleted my test suite for wetem. I had to write a new one from scratch, and because it's annoying, I barely tested half the use cases I had before... Meh, it should work. And if it doesn't... It's an alpha anyway :PWell, it's easy to understand when one of the params is an array, but if it's not, it could lead to misunderstandings... Was it wetem::add('side', 'sidebar') or wetem::add('sidebar', 'side') already?
Yeah...
I was thinking, the only reason we need an array for layer lists is to provide for fallbacks... Why not do an explode(',', $target) in ::load()? That way, we can provide 'sidebar,top,default' or even 'sidebar,top,' (empty last string) for the target...
Also, was thinking at this point we may wanna split wetem into its own class file... It's 22KB. Splitting it into another file, however, adds about 5ms of processing time on my local server, even if it's just that -- the process of taking one file and splitting it in two, and including both files from within Subs.php. There aren't a lot of connections between Subs-Template and Class-Template (or whatever we'd call it), just a few here and there, so it might be justified.
:edit: Hey! We both have 7777 posts each... LUCKY! :P
-
Bump, again....... :whistle:
Been holding myself from committing the changes mentioned in the last paragraphs because I'm not sure we want that.
-
Yeah, sure...
I'll take some time to look into this. Maybe it's "fixed" in the new code already, I don't know... (I mean, I found and fixed a bug with 'load(before)'.)
I haven't had chance to try it but it's certainly something that needs investigation. You know, you could always try writing a plugin :whistle:Yep... I think we discussed it in the early days of wetem, but I forgot to think further about it...
No worries; I fully expected to be the one who would discover such fun things when writing plugins. It's a good way of debugging things, incidentally.And besides, it's not going to be as annoying as my own work on the rewrite itself... Believe me, I had to double-check the entire friggin' code at least 10 times today...
*nods* This is also why I'm slack about updating my plugins until things settle down. I still, as it happens, have one plugin that uses loadBlock() from before wetem even existed.I was thinking, the only reason we need an array for layer lists is to provide for fallbacks... Why not do an explode(',', $target) in ::load()? That way, we can provide 'sidebar,top,default' or even 'sidebar,top,' (empty last string) for the target...
That's workable. The thing is, whenever doing anything like this, two sets of circumstances need to be borne in mind: firstly, how Wedge itself uses these, and secondly how plugins and themes will use it (but mostly plugins).
Wedge's use is almost entirely just dropping complete lists of templates into layers, but plugins may well want to insert individual things into layers, may want fallbacks, may want to do other things. To be honest, if I'm looking to insert into the sidebar and falling back to the default layer, I really won't want to do it like that, because the styling will be all wrong. I'll want to have separate templates for that job.
Consider any of the sidebar blocks that we have currently. Would they look right, style-wise, if simply dropped into the default layer? A few might get away with it but generally it'll look bad.Also, was thinking at this point we may wanna split wetem into its own class file... It's 22KB. Splitting it into another file, however, adds about 5ms of processing time on my local server, even if it's just that -- the process of taking one file and splitting it in two, and including both files from within Subs.php. There aren't a lot of connections between Subs-Template and Class-Template (or whatever we'd call it), just a few here and there, so it might be justified.
Yeah, it's something to bear in mind. However, while there is little connection, it's going to be called together and used together ultimately, so there's little point in splitting it.
-
I haven't had chance to try it but it's certainly something that needs investigation. You know, you could always try writing a plugin :whistle:
I don't know, I would first like to hone my skills on OOP... I have a feeling that I need to fully grasp the meaning of cooperation between different elements of a program, before I even consider doing a plugin. Aeva Media was kind of a hard task to manage -- not because of the technicalities of a SMF add-on (Dragooon managed most of it really), but because it required thinking in two ways: the SMF way of doing things, and my way of doing things. With Wedge, the problem is no longer there because I'm doing things my way (and they're close enough to your way that we don't often get dragged into endless discussions about whether something should be done this or that way), but I need to have a feel of how to *allow* others to plug into my mind and my way of doing things -- and I think it's necessary for me to broaden my technique for that.
On a very, very slightly related topic, but it's something I wanted to discuss anyway and I couldn't bother to open a new topic... I finally watched Atlas Shrugged this morning. The movie. I had an interest in Ayn Rand's works because I'm very much interested in null-A logic, which has arguably (and thankfully) nothing to do with objectivism, but she was into null-A as well, so I thought maybe she had something interesting to say. I was not utterly convinced by The Fountainhead, as I found the main character to be mostly selfish and actually too far removed from the contributions to society that he's supposed to be making -- I'm not sure that ambition plays a huge role in your life after you're past your 20/30's. I know it's not in my book right now. But I still liked the idea of a philosophy of doing your own thing and not letting others get in the way. However, with Atlas Shrugged, I think I've finally understood what it's all about... It's an American thing.
From what I understand, Republicans and Democrats are not exactly the same as Right and Left wings in Europe. It's mostly a federal thing, so Republicans have 'laissez-faire', and Democrats represent the government as a means to control wealth in the US, in a way that could lead them to be accused of communism, or as they like to say, socialism. Atlas Shrugged, at least the movie, shows this in a way that reminded me of the current economy crisis in Europe: the wealthier European states, like France and Germany, don't want to 'chip in' for Greece. So, in that respect, we actually have a European leadership that chose the 'Democrat' way of doing things, while the people wants 'laissez-faire'. There's a similar trend in Belgium where the Flemish half of the country doesn't want to pay for the failing economy of the French speaking part -- even though a century ago, the French speaking Belgians were doing the exact same thing for their weak Flemish neighbors.
All in all -- I have a feeling that this is what it's about: when you ask someone to help someone else who's been less lucky, are you being charitable or selfish? It's interesting that in the movie, the 'good guys' are the ones who, as they clearly say themselves, 'are only interested in making money'. I'm not falling for that. The Reardon guy is clearly a geek who only has interest in success and discovery, not in getting paid for that. Now it'd be interesting to see how much that applies to financial institutions... They don't really create things, they only bet on other people's success or failure. That's not innovation to me. I'm not exactly sure why I should be supporting them...
Well, just wanna say that I'm not falling for either side of the issue, but at least I have a better understanding of the divide between Americans (and, let's say it, Europeans now.)
And on my current matters: what are we demonstrating by doing what we're doing? We're not doing it for money, we're not doing it for glory... We're doing it because we feel it has to be done. Because we want to innovate in our field. How would we react if we ended up making Wedge a huge success, and someone demanded of us that we be 'fair' to the competition or something? I don't know, because I think I'm being fair right now -- I'm certainly not trying to make money off anyone, or take market shares, or anything like that.
I think that's it... I think that innovation is not systematically something that should be monetized for the sake of being monetized. What one wants is to keep living doing something that makes them happy. This requires money, so often the two gets mixed together, but it doesn't have to. I think that's probably one of the big flaws in objectivism as I'm seeing it. Unless, of course, I totally misunderstood the concept... :^^;:*nods* This is also why I'm slack about updating my plugins until things settle down. I still, as it happens, have one plugin that uses loadBlock() from before wetem even existed.
Could be worse... Could be loadSubTemplate() :PThat's workable. The thing is, whenever doing anything like this, two sets of circumstances need to be borne in mind: firstly, how Wedge itself uses these, and secondly how plugins and themes will use it (but mostly plugins).
Wedge doesn't use it that much. I think there are only a couple of places where multiple target layers are provided (probably when it comes to the menus, which are added to the 'top' layer?). Still, it makes sense to allow plugin authors to make sure their data is shown. I'll give you a quick example: let's say I want to show data in the sidebar at all times. However, Wedge doesn't guarantee me that I'll be able to access the sidebar at all times (another plugin may want to delete it to make room for something else), so I may want to give up on most data I'm showing, but if there's something particularly critical to show, I could just as well create my own layer inside the footer or something, NOT fill it with anything, and only provide it as a fallback for my critical data. Wedge won't budge if it doesn't find any code associated to layers you create. (Just check out Warm's recent indenazi changes -- I added a fake <indent> layer to cancel any indentation changes made by its parent layer. I think it's pretty neat.)
That's one thing among others...
Of course, we could also do it differently, like, instead of providing 'sidebar,fallback', the plugin author could use '!sidebar' or something, where the '!' would be seen by Wedge as a sign that the layer needs to be created if it's not there. It would force me to record all traces of previously deleted layers, though, but it's doable.Wedge's use is almost entirely just dropping complete lists of templates into layers, but plugins may well want to insert individual things into layers, may want fallbacks, may want to do other things. To be honest, if I'm looking to insert into the sidebar and falling back to the default layer, I really won't want to do it like that, because the styling will be all wrong.
I'm not sure about that. You could very well prepare for this particular case by adding some CSS to adapt the styling for your data inside the fallback layer.Consider any of the sidebar blocks that we have currently. Would they look right, style-wise, if simply dropped into the default layer? A few might get away with it but generally it'll look bad.
I still have plans to make the sidebar look good horizontally... :P I need to turn the blocks into inline-blocks for that.Yeah, it's something to bear in mind. However, while there is little connection, it's going to be called together and used together ultimately, so there's little point in splitting it.
The main point is having all important objects into their own file, for easing editing. Some class files are only called from within one point in the source code (such as Class-CSS or Class-SFTP), so we might argue that they should be stored in the same file... (Well, they're not ALWAYS loaded though, so it's best to keep them apart, sorry for the poor analogy.)
-
:/ I don't have much to say on anything other than the following. I think it doesn't help that both of us (my partner and me) are both under the weather today, feeling rubbish and ill.
And on my current matters: what are we demonstrating by doing what we're doing? We're not doing it for money, we're not doing it for glory... We're doing it because we feel it has to be done. Because we want to innovate in our field. How would we react if we ended up making Wedge a huge success, and someone demanded of us that we be 'fair' to the competition or something? I don't know, because I think I'm being fair right now -- I'm certainly not trying to make money off anyone, or take market shares, or anything like that.
We are demonstrating that the way things are is not ideal and that there is an alternative. Only recently I saw someone asking on sm.org for 'a way of working out what order mods needed to be installed in so they work properly'. Apart from the vast number of permutations that are generated out of this, it's also entirely the wrong way to go. Instead of playing triage on file edit related matters, people should be looking at ways to change the problem entirely.I think that's it... I think that innovation is not systematically something that should be monetized for the sake of being monetized. What one wants is to keep living doing something that makes them happy. This requires money, so often the two gets mixed together, but it doesn't have to. I think that's probably one of the big flaws in objectivism as I'm seeing it. Unless, of course, I totally misunderstood the concept...
You haven't misunderstood anything. If you're curious about how others view what is fundamentally the same concept, look up Maslow's Hierarchy of Needs. It describes virtually the same thing, but from an economist's point of view.
Once people have enough money to make sure their basic needs are met, they're generally pretty good but once their higher, not-necessarily-financial needs are met, they're even happier. I know I turned down a promotion at my former career once because while it would have made me more money, it would have meant longer hours and more stress.I still have plans to make the sidebar look good horizontally..,
Not quite the same thing. Making the sidebar look good horizontally isn't the same challenge. I'm talking about having the sidebar stuff be moved wholesale out of the sidebar and into the default layer. The main header is likely to be wrong (as it should probably be elevated from a we:title to we:cat, or we:title2 to we:title depending on circumstance), for example.I'm not sure about that. You could very well prepare for this particular case by adding some CSS to adapt the styling for your data inside the fallback layer.
But that's the thing - see above. If a plugin wants to use the sidebar but the sidebar's not available, just changing the CSS isn't enough, the markup is likely to be different too. If a plugin wants to create its own layer, fine, but even then it's still probably going to be using its own different markup.
What has to happen is either the fallback needs to allow an author to specify an alternative function to call as well the fallback layer.
Or, and this is why I asked for a return value in the method that adds a block in, the plugin can attempt to add to the sidebar, and if that fails, it can do something else.
That's assuming, of course, that the sidebar is removed by something with highest priority and everything else is done with lower priority but that's not something we can readily do much about... short of plugins having some flag to indicate that they manipulate, require, or disable the sidebar but that's another can of worms I don't want to get into.The main point is having all important objects into their own file, for easing editing. Some class files are only called from within one point in the source code (such as Class-CSS or Class-SFTP), so we might argue that they should be stored in the same file...
Class-SFTP and Class-FTP could be called from different points in the code, but Class-CSS can't (it's invoked early on, no?)
-
:/ I don't have much to say on anything other than the following. I think it doesn't help that both of us (my partner and me) are both under the weather today, feeling rubbish and ill.
Ah, my girlfriend too... :^^;:We are demonstrating that the way things are is not ideal and that there is an alternative.
Well, we didn't need to 'demonstrate' that things were not ideal. But people don't generally expect free software to live up to commercial software. It takes crazy people like us, or Unknown back in the day, to do just that ;)You haven't misunderstood anything. If you're curious about how others view what is fundamentally the same concept, look up Maslow's Hierarchy of Needs. It describes virtually the same thing, but from an economist's point of view.
I'll take note of that.Once people have enough money to make sure their basic needs are met, they're generally pretty good but once their higher, not-necessarily-financial needs are met, they're even happier. I know I turned down a promotion at my former career once because while it would have made me more money, it would have meant longer hours and more stress.
I turned down so many things because of that, I understand perfectly... Well, actually I wouldn't be working on Wedge today if I hadn't suddenly started turning down *everything* back in September 2006. It felt like a dull life always working for other people to make money off my stuff... Even if I did make a decent share, too. Anyway...Not quite the same thing. Making the sidebar look good horizontally isn't the same challenge. I'm talking about having the sidebar stuff be moved wholesale out of the sidebar and into the default layer.
And again, I'm positive that showing a sidebar block inside the default layer can work if done properly.Or, and this is why I asked for a return value in the method that adds a block in, the plugin can attempt to add to the sidebar, and if that fails, it can do something else.
Well, it makes sense... wetem actually had this, but I realized when looking through my code that I'd 'stopped' doing it at some point, so the wetem::op() stuff was actually returning a value to no use, because it's a private method and the public methods that called it didn't return its value in turn.
Okay, so I removed my new code for comma-separated strings, if only because the whole thing was only used ONCE, after checking thoroughly (it's in Profile.php). The code was this, at the beginning of find():
// Turn 'sidebar,top,' into array('sidebar', 'top', '')
if (!is_array($targets))
$targets = explode(',', $targets);
Nothing big, really... But in the end, I felt a bit uncomfortable doing an unneeded explode() on every single wetem method call.Class-SFTP and Class-FTP could be called from different points in the code, but Class-CSS can't (it's invoked early on, no?)
It's only invoked when Wedge actually needs to cache a CSS file. Otherwise it's not run at all, that is, 99% of the time...
-
Well, we didn't need to 'demonstrate' that things were not ideal. But people don't generally expect free software to live up to commercial software. It takes crazy people like us, or Unknown back in the day, to do just that
Even if people do make free software that's better than the paid competition, it's still not going to be acknowledged on the same level simply because it's not paid.I turned down so many things because of that, I understand perfectly... Well, actually I wouldn't be working on Wedge today if I hadn't suddenly started turning down *everything* back in September 2006. It felt like a dull life always working for other people to make money off my stuff... Even if I did make a decent share, too. Anyway...
*nods* You enjoy doing things for you, and like me the money is a side issue.And again, I'm positive that showing a sidebar block inside the default layer can work if done properly.
If it's a top level layer in the sidebar (e.g. the info center as a whole) it can work just fine as a child of the default layer. The we:title is thematically consistent with we:cat, and it won't look particularly wrong.
But that's top level categories only and they might be expecting a ~220px wide column and do complicated things with floats and wrapping and so on that won't work on a bigger scale.
In that case, the compromise is to allow for both; if the developer knows in advance that it's going to work OK falling back to default, let them specify it, but if not, have the return value to accommodate it (which means they can dynamically do their own thing if they choose)It's only invoked when Wedge actually needs to cache a CSS file. Otherwise it's not run at all, that is, 99% of the time...
Hmm. You know, we could solve some of this problem intelligently by setting up an autoloader function.
-
An auto-loader..?
Anyway, that's not gonna solve the 'semantics' of a Class-Template file at any rate ;)
-
An autoloader is a routine that automatically loads classes that currently don't exist and does so automatically. You give it a routine by which it can load a given class based on the class you call for and it'll automatically load it for you if it doesn't currently exist.
Having something like that can help encourage code to be broken up based on whether it's needed or not.
-
Do you have examples of this?
-
For example, if we were to rename Class-Editor.php to Class-wedit, we wouldn't ever need to put a loadSource call in for it again. We could just refer to wedit, and if the class hasn't been already loaded, PHP can load it for us.
Stops you worrying so much about cross-dependencies by encouraging you to split things up and have them loaded on demand.
Mind you, I find it interesting that the general policy of Zend is to break things down to an atomic level; Zend stuff and stuff written to Zend standards generates a *lot* of small files. (xenForo has many 1-2KB source files for example)
-
Hmm, the only way it could work for me in terms in file naming would be to have a Class or Classes folder with files named 'wedit.php' and such in it.
I'm not sure it'd be beneficial in the long run, though. For example in terms of ease of update (if you do it via FTP.)
Would like to get more opinions...
-
Hmm, the only way it could work for me in terms in file naming would be to have a Class or Classes folder with files named 'wedit.php' and such in it.
Here's the thing. When the autoload is invoked, you get to provide a function that dictates how it should load the relevant class, so you can set it up how you like. I'm more just throwing it out there really to see whether it might be useful in cases like this.
-
Would it hurt performance?