Jump to content

ryan

Administrators
  • Posts

    17,240
  • Joined

  • Days Won

    1,703

Everything posted by ryan

  1. Beautiful site Martin! Nicely done! Love the transparency on the trees, and the trees as a concept for your company name as well. You really have a fantastic portfolio here too. Thanks for posting this.
  2. I can post one on Tuesday when I'm back in my office. I'm just on mobile till then.
  3. No doubt we'll build this auto-publish or auto-unpublish as a module this hooks into LazyCron. When built, it will most likely be a core module, but one that's disabled by default.
  4. In order to drag-move a page to another branch, you have to open that branch first (even if it has no children). Opening that branch is a matter of just clicking on the page. You know a branch is opened when you can see it's 'edit | view', etc. links. I think it would be nice to have it auto-open a branch when you hover over it for a couple of seconds, but that's beyond my current JS skill level.
  5. This options are primarily for guiding the direction of newly created pages. They don't affect pages already in the system. So when you choose "require this parent" that means "require this parent when creating a page that uses this template".
  6. You are right I think this coming week will be it. It would be this weekend, but it's a long weekend (with Labor Day tomorrow) and I'm not getting any computer time. But I think we should be ready by the end of the week.
  7. I'm on a cell phone so some of your code example isn't coming through but put your publish_date selector in here: $notes = $pages->get("/notes/")->children("template=notes, sort=-publish_date, publish_date<$today");
  8. Absolutely--You could definitely use a custom date field for this. And if you don't want them showing in foreach, then just specify a date range in your selector: $today = time(); foreach($page->children("date<$today") { ... }
  9. If you need to select a lot of pages, you are right that it's cumbersome. But I had to design this field to maximize the simplicity with my clients. So the instant feedback of closing the list, showing you what was added and letting you sort right there was the preferable compromise. At least for the needs of the clients I work with. Eventually we'll make the behavior configurable where you can tailor it more to the needs of fields where you might have a lot to select.
  10. Currently there isn't a way to change the published 'created' date, short of changing it directly in the SQL. PW only sets this field the first time a page is saved, and then doesn't include it in any future saves. Though I could certainly change that. But if you are working this weekend, here's how you could do it with SQL: <?php $page = $pages->get("/page/you/want/to/change/"); $time = strtotime("2011-04-23"); // or whatever date you want wire('db')->query("UPDATE pages SET created=$time WHERE id={$page->id}");
  11. Actually we do need something like HTTP_X_FIELDNAME. Maybe not for this specific instance with file uploads… but in order for PW to support saving any field via ajax, it needs to know what it is ahead of time. Otherwise there would be no way to detect something like an unchecked checkbox. By that I mean that when you submit a form with nothing but an unchecked checkbox, the $_POST would be an empty array, no reference to the checkbox. So something like HTTP_X_FIELDNAME is actually quite a good idea, and necessary if dealing with individually POSTed fields within a form. The only thing I wonder about is: what is the advantage of using a header as opposed to a regular POST var for this? Might it be simpler for it just to be another POST var rather than a header (for simpler ajax with jQuery)? Something like a POST var called "_fieldName" that's a string with a field name or "_fieldNames" that's an array holding one or more field names. I only mention this because I don't yet know how to send headers like HTTP_X_FIELDNAME with regular jQuery, so am just looking for the most straightforward solution. Sounds good to me. That looks similar to what it already does. Currently this is what it returns: { "error":false, "message":"Saved page '1' field 'images'" } Whenever PW sees it's an ajax request, it just returns a JSON of any messages that you would usually see in the admin. That's how it gets error alerts to the PageList ajax, for example. What would you think about using the same format that's already there, but just adding a 'filename' field to it, like in your example? Like this: { "error":false, "message":"Saved page '1' field 'images'", "filename": "filename.jpg" } and { "error":true, "message":"Please no more photos of your cats.", "filename": "filename.jpg" } I also noticed when testing that I get this message from Firebug in Firefox 6 whenever the ajax upload code executes. It doesn't seem to matter or affect anything, but just wanted to mention it in case it makes any sense to you: Use of File.fileName is deprecated. To upgrade your code, use standard properties or use the DOM FileReader object. For more help https://developer.mozilla.org/en/DOM/FileReader
  12. getFieldValue isn't hookable and won't be. It's used internally by the Page class, and not part of the external API. There is a little overhead with every hooked function, and getFieldValue is one that sees so much activity that making it hookable would potentially reduce performance. What I'll do instead is add a new hook that only gets called when $page->get(fieldName) or $page->fieldName is returning a null. That will enable us to achieve the same thing without adding much, if any overhead. We'll likely call the hook 'getUnknownFieldValue'. When a module hooks into that function, it'll get the opportunity to supply a value for a $page->fieldName call that would have otherwise returned null. For instance, if your page didn't have a 'body' field, and you called $page->body, it would return null. But in your case, you want it to potentially translate 'body' to 'body_fr' or 'body_en' or something like that, so that's where this hook would come into play. You could have a call for $page->body return the contents of $page->body_en rather than null. Also want to note that there isn't currently a hook like this. It's something that I need to add, but it will be easy to do. Of course– There won't be any change in syntax.
  13. Good news, I got all the AjaxUpload stuff out of ProcessPageEdit and everything working with WireUpload, so now the AjaxUpload files get routed through there instead. It basically saves it in a temporary dir like PHP does with regular uploads, then creates a new $_FILES var cloning what would be in the PHP one during a regular upload. That way, not much code had to change in WireUpload and it's backwards compatible with regular uploads. It runs through all the same filename and extension validation and sanitization before getting moved to the destination dir and sent back to InputfieldFile. One thing I realized though is that we need some way to send a success (or error) response with the actual resulting filename back to InputfieldFile.js AjaxUpload. WireUpload sanitizes filenames, makes them lowercase, removes non ascii characters and so forth, so it may have changed the filename or thrown an error that ultimately needs to be output by InputfieldFile.js. I hope to get time this weekend to experiment with it more, but so far everything seems to be working great. I'm still adding a little more validation (for file size) but will post updated files once I've got that going, hopefully sometime this weekend. Thanks for all your work in getting this going. I can't wait to get this officially committed to the 2.1 source.
  14. Thanks for this update! Your InputfieldFile.module doesn't have this commit in it (below), so I combined your updates into the latest version and it's attached to this message. https://github.com/ryancramerdesign/P21/commit/0a7db81eab8ac3b601ace0871d1722449941857a InputfieldFile.module
  15. It's definitely not for everything. There are plenty of things we need to define custom styles for. I try to keep them all part of the admin theme for the most part, but of course those have to be general purpose, non-specific stuff. It gets tricky when you get down to modules with specific needs, especially with regards to color. One way I've been avoiding the issue lately is to use opacity. For instance, if I want something to be a little de-emphasized, I might add an "opacity: 0.5;" to the stylesheet, so that it'll continue to be de-emphasized (with the right colors) regardless of the admin theme. Not sure if this is the best approach or not... but it seems to work. Ultimately we may want to add more styles to theme stylesheets to cover more needs. Or could standardize on some style framework that compliments jQuery UI and takes a broader role. I appreciate any suggestions you have in this area. Good to know. I rarely had to deal with "undefined" before jQuery 1.6, but now it seems 1.6 likes to return undefined for everything it didn't before, so I suppose I'm getting to know non-jQuery javascript a little better now. Can you describe more or point me to a good link? I'm not sure I understand about the HTTP_X_FIELDNAME. I use 'ugly but unique' mostly for selecting in javascript or styling things that are completely unique to the module. Everywhere else the jQuery UI styles are probably better, but of course they don't cover everything. Perhaps we can collaborate on PW's common CSS framework to cover all the stuff that jQuery UI doesn't.
  16. That's a good idea and I don't think there would be any worries about performance or overhead. But since there may be different approaches for multi language support, I'd probably want to delegate it to a module rather than make translation assumptions with field names. So we could add a new hook to the Page class that is called when an unknown property is accessed (a hook called when the return value is going to be null). Then a module could hook into it to see if it can translate it to another field. Using your example, the hook would get called when the unknown field "body" is accessed. The hook would check to see if the page has a "body_$lang" field (where $lang might be "en or "fr", etc), and return it if it does. Of course, that sort of thing could very easily become and endless recursion loop, so PW would prevent that.
  17. Pete, I work on several travel-based web sites as well and they keep me in business. Good to hear you are working on these types of sites too–it's nice to have a peer in the industry! Perhaps we should collaborate on one of these projects someday. There seems to be an overabundance of work in this area, it's enjoyable work, and a lot of good people. Not specific to travel industry, but my experience has been that most sites that have a large inventory of constantly changing stuff in any industry are providing a means to share and mirror their data. Most often, they are using verbose XML feeds (well beyond something like RSS), and letting their vendors or affiliates pull data off of them. The type of data sharing I was describing in the other thread is really no different, and I would say that PW lends itself especially well to both sharing and pulling data. PW also makes it easy to go far beyond just providing a feed and instead providing a true web service that can be queried. It really is fun to do. I've done this on a few sites, and seen other sites do it too, so it's not a secret or anything. However, it does cross into a territory of getting logic involved in style, so not a best practice for those that like to just swap in new stylesheets to completely change a design. Lets use a fictional example where you want to display a wide horizontal row of 3 square photos and another vertical row of square thumbnails, 2 per row. For landscape orientation photos that have the resolution, you want to double the width to maximize the space. You'd treat the big horizontal row and the vertical thumbnails as two separate things, though might use the same code (in a function) to handle either. In either case, you need to know the total width of the row in pixels so you know how much room you have to work with. Then you'll keep a counter on the width of each photo so you'll know when you've filled the space. You'll also look for opportunities to maximize the photo width. Treat the following as pseudocode because it's typed in the browser and not tested: <?php $pixelsMax = 900; // max pixels we're allowed to use $pixels = 0; // counter of current used pixels $w1 = 300; // target regular size image width $w2 = 600; // target double size image width $h1 = 300; // target height $skipped = array(); // images skipped due to being too small, can be displayed elsewhere $out = ''; // where we'll store our markup while(1) { // if there's no more room for a small photo, then break if($pixels + $w1 > $pixelsMax) break; // shift off the first image $image = $page->images->shift(); // no image? then stop if(!$image) break; // get it's width and height $w = $image->width; $h = $image->height; // if the image isn't big enough, then save it and skip it if($w < $w1 || $h < $h1) { $skipped[] = $image; continue; } // get the current image width/height $w = $image->width(); $h = $image->height(); // see if there's room for a double-wide // and also if the image has a wide-landscape orientation if(($pixels + $w2 <= $pixelsMax) && ($w / $h >= 1.5)) { $newWidth = $w2; // double-wide } else { $newWidth = $w1; // square } // make the image the size we need it $newImage = $image->size($newWidth, $h1); // add to our width counter $pixels += $newWidth; // make the markup $out .= "<a href='{$image->url}'><img src='{$newImage->url}' alt='{$image->description}' width='$newWidth' height='$newHeight' /></a>"; } // stuff the unused images back to the page // so they can be used for the vertical thumbnails foreach(array_reverse($skipped) as $image) { $page->images->prepend($image); } This is all typed in the browser and untested, so there may be errors, but hopefully it at least works as pseudocode. If it were real code, we'd want it in a function too. Now the vertical thumbnails part would work in a similar manner. You could use the above as a function for each row of thumbnails, but may prefer to make something more efficient custom to the need.
  18. Antti, I've been going through the code line by line just to see how everything works so that I can be of more help here. The code looks beautiful, you did an awesome job with putting this together. I've only made it through the InputfieldFile part so far and here are some comments/questions for core integration: In this line, I'm wondering about the css('color', 'white') because that may or may not be compatible with whatever UI theme is being used? progressBarValue.addClass("ui-state-default").css('color','white').html("<span>100% complete</span>"); Also on the line above, what do you think about replacing the word "complete" with a ui-icon-check or a ui-icon-circle-check, just so there's one less thing to translate in languages? Since this line is in the JS, it made me realize I probably need to make ProcessPageEdit so that you can post right to "./". Otherwise, the HTML5 upload will be harder to make use of outside of the PageEdit (for example, the new CSV import module has a file upload, and so having the JS post to /fields/ isn't portable). This is my fault of course, and I'm working on an alternative so that you can post to "./" rather than "./fields/" and will keep you up to date. xhr.open("POST", "./fields/?id=" + page_id, true); I was wondering about class names like "over" and "complete", and if it might be generic enough to conflict with some other future 3rd party module or customization that someone is using. If these are part of jQuery UI's built-in progress bar classes, then there's nothing we can do about it, so skip the next paragraph. Otherwise, here's a thought about class names created by modules: When it comes to the core, it might seem overly verbose, but I mostly try to use really specific names so that there's no possibility it could ever conflict with someone else's stuff. I figure I'll leave the short/simple names for non-core stuff. For instance, lets say someone builds their own new Fieldtype and they use class names like "over", "on" and so forth. If they don't scope them down far enough in their stylesheet, the "over" one could potentially affect the HTML5 upload styles. Like, lets say they had this in their stylesheet: .over { position: absolute; top: 0; left: 0; } Granted, that's their problem not ours, and you've properly scoped your styles in the CSS. But it's also one of those things that is easy enough to prevent with specificity. Examples might be: InputfieldFileHTML5Over and InputfieldFileHTML5Complete … verbose and ugly, I know. But I just wanted to mention this and you decide whether it's worth it. I don't know my way around JS near as well as PHP, so had a question on this line: if (typeof files !== "undefined") { If I recall correctly, I usually see it like this (constant rather than string): if (typeof files !== undefined) { Does it work either way? On the following lines in the stylesheet, I'm wondering about theme conflicts when someone swaps in a new jQuery UI theme. Specifically wondering if any might work better as jQuery UI interaction states or interaction cues classes (http://jqueryui.com/docs/Theming/API) rather than defining specific colors. Also should mention that I'm occasionally defining some specific colors in some of the module-specific code in PW as well, but am trying to move away from it for better compatibility with new admin themes. .InputfieldFileUpload .dropHere { ... color: #777; } .complete { background: green !important; } .AjaxUpload .ui-progressbar-value { ... color: black; } .ui-widget-content.over { border-color: rgb(135, 167, 27); background: rgba(90, 200, 27, 0.1); }
  19. $page->filesManager->path - doesn't return anything, it should be: $page->filesManager->path() - this works Sorry about this, I think I posted an example using 'path' rather than 'path()' earlier by mistake. The function version was required here. I say 'was', because I just updated the class to also support the non-function version too, so will commit that soon.
  20. Actually, I wasn't even thinking of TinyMCE, but you are right that would be an option. What I was thinking of was a shared assets page, and I use them on a lot of sites already. Language-specific pages could pull from those shared assets like any other page, i.e. <?php $masthead = $pages->get("/tools/shared/masthead/")->images->getRandom(1); $alt = array( 'en' => 'Masthead', 'de' => 'Impressum' ); $lang = $page->rootParent->name; echo "<img src='{$masthead->url}' alt='$alt[$lang]' />";
  21. For security reasons, PW forces a "403 forbidden" if someone tries to directly access any PHP files in the /site/templates/ dir, as well as several other locations in PW's file system. So it's best not to put any PHP files that you need to directly access in any of ProcessWire's directories, because there's a good chance it'll block access to them. Here are a few alternatives: Option 1. Place your sendemail (and optionally phpmailer include) files somewhere outside of PW's directories. For instance, maybe you could create a dir called /form/ off your web root and place them in there. Then set your form to: action='/forms/sendemail.php' Option 2. Use your sendemail.php as a ProcessWire template. Create a page using that template, and make your form post to that page. Option 3. (the one that I use most often) Make your form post to the same page that it's on (i.e. action='./'). When you see one of your POST vars present, include your form processing script. i.e. <?php if($input->post->submit) { // process contact form include("./includes/sendemail.php"); } else { // output contact form }
  22. $page->created …will give you the unix timestamp, or you can use PHP to format it however you want: <?php echo date("F j, Y, g:i a", $page->created); // October 10, 1974, 11:28 pm http://www.php.net/manual/en/function.date.php
  23. PW's page cloning supports images/files too. I suppose it just depends when the cloning takes place as to whether the images are duplicated there. You never really know if an image is going to need to be language specific or not, though it's description (alt tag) would be. I tend to think it's best to follow a path of more duplication here rather than trying to squeeze out some efficiency benefits in less duplication. Either way, any kind of image or file mirroring would seem more like a luxury than a requirement, in my opinion. If I were building a multi-language site, I would probably keep some pages for shared assets (outside of the language trees) and pull shared images from there when necessary. I'd reserve the on-page image and file fields for language specific stuff, not to be cloned across trees. @Pete: Technically it's not different than any other web service for sharing content, except that it's a little more custom and deals with larger sets of data. This particular one is specific to a company intranet, so there aren't public examples I can link to. I won't get into the unique parts since it's not my own site, but can describe the general ideas common to most web services of this kind. The master server has a REST-based web service, which I just built with a template and assigned it to a page. That web service lets you query PW with selectors and it responds with JSON results containing all page data. The other web servers query the web service from a cron job calling PW's API from PHP command line scripts. They look for pages that have changed since the last query, and re-populate all the page's fields with the data parsed from the JSON. It mirrors all fieldtypes including files and page references, as well as child pages. It determines if something has been deleted by it's lack of presence in the JSON feed. If there's a page on one of the servers with a master_id that no longer appears in the feed, it moves the page to the trash and ultimately deletes it. This system deals with tens of thousands of pages, so it doesn't all happen in one request. Let me know if I can answer any more specific questions about it. Though maybe we should switch to another topic so we don't hijack this thread.
  24. What you are describing is similar to PW1, where you would set the field's label/description information individually on a per template basis. I think there are two sides to it. First off, it's very worthwhile to be able to have one page say "Press Release Headline" in one template and another say "Full Name", but have them both refer to the same field (be that 'title', or some other field). But the flip side is that you end up with less consistency and familiarity between templates. From a developers perspective, it's also more challenging to connect fields on the front end with your usage of them in the API in your templates. Still, the pros outweigh the cons, and especially so if it reduces the number of fields you need to accomplish your site's goals. So rest assured, I totally agree with the value of it and we'll have this at some point as a module. But I've considered it more of a luxury than a requirement, so it's coming but I haven't yet penned a date to it.
  25. Not sure if this all applicable, but I'll mention it because I think it gets into the two issues you mentioned. You may already be doing something like this. But I'll type it out just in case any of it is worthwhile. I do some cross-site syncing where pages from one PW site are duplicated on other PW sites and then mirrored every hour. The sites have different structures, so the mirrored pages have to remember where they came from. This is accomplished by maintaining a 'master_id' (integer) field on every page. That field contains the ID of the page at the originating site. So even if the page is moved in the structure, it continues to be mirrored since it's master_id will never change. If I want a given page to stop mirroring, then I just set it's master_id to 0. Perhaps in your case, keeping a master_id field containing the ID of the page it was duplicated from would ensure that it could continue to be synced regardless of where it gets moved to in the future. Since synced pages would be sharing the same template as the master, they would both have a master_id field. So one way to differentiate the master from the others would be to use a signed ID… they both have the same number, but the master has a positive and the other(s) have negative number (master_id * -1). Canceling the mirroring at either end would just mean setting it to 0. Any templates you want to mirror you would add a master_id field to in Setup > Templates. Your $pages->save() hook would monitor pages that have this field and populate it when creating a page. Likewise, they would create the corresponding page(s) (with the negative master_id) as child(ren) of any other pages that had a master_id equal to the saved page's parent_id * -1. If you didn't want the parent to be mirroring, but you wanted its children to mirror, then the master parent would have a master_id of 0, and the other corresponding parents would have a master_id of the master parent's ID * -1. I think that the default would be that any page created that has a master_id field in it's template would be assumed to be mirrored until you set it to 0. I may not understand the full scope of your needs, so correct me if I'm wrong… but wouldn't this sort of approach be a simple solution to the two issues you mentioned?
×
×
  • Create New...