tag:blogger.com,1999:blog-971777451443786272024-02-19T04:26:51.982-05:00(Programming) Notes to selfDonna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.comBlogger29125tag:blogger.com,1999:blog-97177745144378627.post-85244599318542352602014-12-11T11:12:00.000-05:002014-12-11T11:12:42.234-05:00Symfony site localization based on domain name <p><strong>Problem: I want to localize my site based on the domain name.</strong></p>
<p>Symfony strongly suggests that you use paths (like '/en' or '/fr') after the domain name to determine what the locale should be. This is ideal for a site with only one domain name, but for a site that has a different one for each localization, it's unnecessary. You should be able to determine the language based on the domain.</p>
<p><strong>Solution: Use an event listener.</strong></p>
<p>With an event listener, you can catch the request, parse the domain name, and set the locale appropriately. For this blog's purposes, let's say that a site has www.endomain.com for its English site and www.frdomain for its French site.</p>
<p>Create this folder/file in your bundle: EventListener/LocaleListener.php. Inside, put this:</p>
<pre>
namespace My\CustomBundle\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class LocaleListener
{
public function setLocale(GetResponseEvent $event)
{
if (strstr(strtolower($_SERVER['HTTP_HOST']), strtolower('frdomain')))
{
$request = $event->getRequest();
$request->setLocale('fr');
}
}
}
</pre>
<p>If the HTTP_HOST contains the string 'frdomain', then set the locale to 'fr'.</p>
<p>Now register the listener in your bundle's services.yml file (it should be in Resources/config/). Inside, put this: </p>
<pre>
services:
my_custom.language.kernel_request_listener:
class: My\CustomBundle\EventListener\LocaleListener
tags:
- { name: kernel.event_listener, event: kernel.request, method: setLocale }
</pre>
<p>Now every time a request is sent to Symfony, this listener runs first and sets the locale to 'fr' if it detects 'frdomain' in HTTP_HOST. Otherwise, it keeps the default locale (in this case, it's en).</p>
<p>That should work! Happy coding!</p>
Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-55169581993987241402014-01-13T12:59:00.000-05:002014-01-13T13:07:10.981-05:00Symfony, internalization/localization, and 404 pages<h3>Background</h3>
<p>Given 1) the Symfony framework and 2) the need for localization, one shouldn't be surprised that there's a package that takes care of that already (somewhat): <a target=_blank href="http://jmsyst.com/bundles/JMSI18nRoutingBundle">JMSI18nRoutingBundle</a>. It works so that in your config.yml, you can specify the default locale, the locales that your site works with, and what the domain names are for each locale. I guess I'm not using this bundle correctly, though, because although my config.yml file looks like this:</p>
<pre>
jms_i18n_routing:
default_locale: %locale%
locales: [en, fr]
strategy: custom
hosts:
en: www.englishVersion.com
fr: www.frenchVersion.com
<strong>redirect_to_host: true</strong>
</pre>
<p>
typing in the French locale into the address bar redirects to the English site. (And if you happen to have an inkling of what I'm doing wrong, do let me know!)
</p>
<p>This necessitates the extra steps of 1) creating a separate /fr path that serves up French content and 2) configuring .htaccess to redirect www.frenchVersion.com to that path.</p>
<h3>The Problem</h3>
<p>Given that 1) www.frenchVersion.com originally serves up English content and 2) needs coaxing in .htaccess to <em>redirect</em>, I hit the problem of English 404 pages appearing under the French domain. Ie., www.frenchVersion.com/path-does-not-exist will serve up the English 404 message. </p>
<h3>The Solutions</h3>
<h3>The halfway solution - detect the language in the template</h3>
<p>In my custom 404 page (in project_root\app\Resources\TwigBundle\views\Exception\error404.html.twig), I included an if-statement that checked the domain name and then set the variable <kbd>lang</kbd> appropriately.</p>
<pre>
{% set lang = ('frenchVersion' in app.request.getHost()) ? 'fr' : 'en' %}
<p class="copy">{{ 'projname.error404.copy' | trans({}, "messages", lang) }}</p>
</pre>
<p>This solution only worked halfway, though. While the 404 message <em>was</em> in French, the surrounding layout.html.twig was still in English.
<h3>Full solution - create a listener for any exceptions thrown</h3>
<p>With the guidance of <a target=_blank href="http://stackoverflow.com/questions/17243426/change-locale-symfony-2-3">this Stackoverflow answer</a>, I was able to check for the domain name before anything was rendered <em>when an exception is thrown</em>. This is a two-file (or two-part) solution. First, you create a LanguageListener in projectroot\src\GenericName\SpecificNameBundle\EventListener. Code it like:</p>
<pre>
namespace GenericName\SpecificNameBundle\EventListener;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class LanguageListener
{
public function setLocale(GetResponseEvent $event)
{
if (strstr($_SERVER['HTTP_HOST'], 'frenchVersion'))
{
$request = $event->getRequest();
$request->setLocale('fr');
}
}
}
</pre>
<p>And then in projectroot\src\GenericName\SpecificNameBundle\Resources\config\services.yml: </p>
<pre>
services:
# ...
genericname.language.kernel_request_listener:
class: GenericName\SpecificNameBundle\EventListener\LanguageListener
tags:
- { name: kernel.event_listener, event: kernel.exception, method: setLocale }
</pre>
<p>And there you go! Even your layout should be rendered using the correct locale. Go try it out! Happy coding!</p>Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-63429582521849509132013-11-08T10:02:00.003-05:002013-11-08T10:06:43.717-05:00Using Symfony's routing.yml file for different host names I like extensions, but when they crap out on you, you're kind of a sitting duck. So rather than rely on them, I figured I might as well learn to handle multiple domain names the extension-free way. Did you know this is now available in Symfony? <a href="http://symfony.com/doc/current/components/routing/hostname_pattern.html">How to match a route based on the host.</a><br />
I needed a language toggle for my website, so that when a user is on the English site, the link to the French is available, and vice versa. Between routing.yml, parameters.yml, and config.yml, I was able to create a decent (but still "wordy") toggle for the pages I needed. (And as I type this, I realize that the correct way might be annotations instead. I'll look into that in a bit.)<br />
<b>Step 1: parameters.yml (in app/config/)</b><br />
This is the only file that will contain the domain names in English and French. Ergo, all other config files will pull from this file. Specify keys like “domain_locale_en” and “domain_locale_fr” to hold the domain names of your English and French sites.<br />
<pre>domain_locale_en: www.programmingnotestoself.com
domain_locale_fr: www.notesdeprogrammationalauto.com </pre>
<b>Step 2: config.yml (in app/config/)</b><br />
This is the file where you’ll make the domain names available to the Twig (template) files. Modify the twig section.<br />
<pre>twig:
# ...
globals:
domain_en: %domain_locale_en%
domain_fr: %domain_locale_fr%</pre>
If you ever need to print out the domain in a link, for example, you can just do this:<br />
<pre>< a href="%domain_en%">English blog< /a></pre>
(If you try to include "http://" in parameters.yml, you’re going to get a surprise. At least, I did… I ended up in the default Symfony welcome page.)<br />
<b>Step 3: routing.yml (in app/config/)</b><br />
This is the part that I’m sure can use a little more polishing, so if you have suggestions, please let me know. But, anyway, given that I now have two domain names for the root, I can code routing.yml like this:<br />
<pre>en_root:
path: /
host: %domain_locale_en%
defaults: { _controller: BlogPostsBundle:Default:index }
fr_root:
path: /
host: %domain_locale_fr%
defaults: { _controller: BlogPostsBundle:Default:index }</pre>
So, yes, whether it detects www.programmingnotestoself.com or www.notesdeprogrammationalauto.com, it’ll go to the same controller. Ugly, no?<br />
<b>The not-so-fun part</b><br />
Because of this hack, all the other pages and routes in my site need to be registered twice in the routing file. For example, www.programmingnotestoself.com/help and www.notesdeprogrammationalauto.com/aide lead to the same page, but Symfony needs to know that. This is how they look like in my routing.yml file:<br />
<pre>_help:
pattern: /help
host: %domain_locale_en%
defaults: { _controller: BlogPostsBundle:Default:help }
_aide:
pattern: /aide
host: %domain_locale_fr%
defaults: { _controller: BlogPostsBundle:Default:help }</pre>
Notice <code>host:</code>? This restricts the path to that particular domain name. So www.programmingnotestoself.com/aide is totally legit, but try www.programmingnotestoself.com/aide and it’ll fail. But if you take out <code>host:</code>, you can totally do a crossover (the latter link). As for what locale will be served up, it’ll be whatever the domain name’s locale is.<br />
<b>The cute part</b><br />
I didn’t know you could force Twig to translate a string to a particular locale!<br />
Assume that the controller for this page passed on variable $lang as either 'fr' or 'en' and $lang_name as 'English' or 'Français':<br />
<pre>{% if lang == 'en' %}
< a href="http://{{domain_fr}}/{{ 'help'|trans(locale='fr')}}>{{lang_name}}< /a>
{% else %}
< a href="http://{{domain_en}}/{{ 'help'|trans(locale='en')}}>{{lang_name}}< /a>
{% endif %}</pre>
If you’re on the English site, force 'help' to be translated to the French string, and do similar if you’re on the French site.<br />
Happy coding!Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-76970551407519849582013-10-03T13:18:00.000-04:002013-10-03T13:18:06.002-04:00My new best friend<pre>
error_reporting(E_ALL);
ini_set('display_errors', '1');
</pre>
<div>Like most programmers, I do var_dumps and echo's... But when all else fails--this.</div>Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-90520429893880126922013-09-17T22:01:00.000-04:002013-09-24T21:43:57.436-04:00Symfony 2 symblog tutorial errors<div>
It seems that the Symfony 2 tutorial ("Symblog") is a little out of date. While going through it, I stumbled on some unexpected behaviour. There were exceptions getting thrown when the tutorial made no mention of them. This could be due to several behaviours being deprecated since 2.1; I was using 2.3.4.</div>
<br />
<div>
So without further ado...</div>
<br />
<div>
The errors and their fixes as you work through the tutorial</div>
<br />
<div>
1) When creating a controller method for the Contact page,
<code>$form->bind($this->bindRequest($request)</code> resulted in:</div>
<br />
<div>
<b>FatalErrorException: Error: Call to undefined method Symfony\Component\Form\Form::bindRequest() in /path/to/root/src/Blogger/BlogBundle/Controller/</b><b>PageController.php line 31</b>
</div>
<br />
<div>
I poked around at code that I already knew worked and found this alternative:</div>
<div>
<code>$form->bind($this->getRequest());</code>
</div>
<br />
<div>
2) While editing src/Blogger/BlogBundle/Entity/EnquiryType.php, adding this line
<code>
$metadata->addPropertyConstraint('body', new MaxLength(50));</code> in static function loadValidatorMetadata(ClassMetadata $metadata) resulted in an exception:</div>
<br />
<div>
<b>FatalErrorException: Error: Class 'Symfony\Component\Validator\Constraints\MaxLength' not found in /path/to/root/src/Blogger/BlogBundle/Entity/Enquiry.php line xx</b></div>
<br />
<div>
I read elsewhere that MaxLength and MinLength are deprecated since Symfony 2.1, so you're better off declaring the above line as</div>
<div>
<code>$metadata->addPropertyConstraint('subject', new Length(array('max' => 50)));</code>
</div>
<br />
<div>
Just make sure to add this to the top of the class: <b>use Symfony\Component\Validator\Constraints\Length;</b></div>
<br />
<div>
3)When told to add the following lines to src/Blogger/BlogBundle/Resources/config/config.yml</div>
<br />
<div>
<code>
parameters:
blogger_blog.comments.latest_comment_limit: 10
</code></div>
<div>
You will instead get an error along the lines of <b>blogger_blog.comments.latest_comment_limit must be defined</b>. Now, the solution is to either do <a href="http://symfony.com/doc/current/cookbook/bundles/extension.html">this tutorial (http://symfony.com/doc/current/cookbook/bundles/extension.html)</a>, or do the shortcut, which I did (because lazy).
</div>
<br />
<div>
4) While trying to enable Assetic for BloggerBlogBundle, you are instructed to put it in <b>app/config/config.yml</b>. However, it doesn't take effect. Instead all sidebar.css-ing disappeared. This is because you should have put BloggerBlogBundle in <b>app/config/config_dev.yml</b>.<br />
<br /></div>
<div>
5) <b>Yui Compressor jar file not found</b> - Make sure that 1) you've put the jar file in app/Resources/java and that 2) the name of that jar file is the same as in config_dev.yml.
</div>
<br/>
<div>If there will be more, I will update this post. Happy coding!</div>Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-90309725452277753392013-07-20T21:29:00.000-04:002013-07-20T21:32:47.665-04:00Symfony 1.4 error: Class 'BaseFormDoctrine' not found in (projectpath)/BaseAuthorForm.class.phpBlogging because I thought this error was funny!<br />
<br />
Currently, I'm playing around with Symfony 1.4 (for particular reasons). I've gotten to the part where I can now generate modules so that CRUD forms will be auto-created for me. When I executed this command:<br />
<br />
<b><span style="font-family: "Courier New",Courier,monospace;">php symfony doctrine:generate-module --with-show --non-verbose-templates frontend author Author</span></b><br />
<br />
I got this error:<br />
<br />
<br />
<br />
<b>PHP Fatal error: Class 'BaseFormDoctrine' not found in (pathto project)/lib/plugins/sfDoctrinePlugin/test/functional/fixtures/lib/form/doctrine/base/BaseAuthorForm.class.php on line 14.</b><br />
<br />
<br />
<br />
<br />
I searched around because I'm completely new to Symfony and am under a deadline. (Spending the weekend on this. Sigh...) Heard that there's a file called<b> config_autoload.yml.php</b> in <b>cache/frontend/dev/config</b> that maps out what file the key "BaseFormDoctrine" leads to. As it turned out, it led to lib/plugins/sfDoctrinePlugin/data/generator/sfDoctrineForm/default/template/sfDoctrineFormBaseTemplate.php.<br />
<br />
So I looked at it. And guess what! The opening php tag in the file didn't begin with "<?php". It began with "[?php".<br />
<br />
Changed that square bracket to "<" and I was back on the road.<br />
<br />Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-79702563702545308472013-06-17T16:53:00.003-04:002013-06-17T16:53:28.007-04:00Ruby on Rails (on Windows) - "ruby_check_sizeof_voidp is negative"Today I installed Ruby on Rails on my Windows machine, but had to jump through a few hoops to get it done. The biggest stumbling block was that whenever I got down to executing "<span style="font-family: "Courier New",Courier,monospace;">rails new myapp</span>", I got a long error that started with<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">C:/Ruby193/bin/ruby.exe extconf.rb<br />creating Makefile<br /><br />make<br />generating generator-i386-mingw32.def<br />compiling generator.c<br />In file included from c:/Ruby193/include/ruby-1.9.1/ruby.h:32:0,<br /> from ../fbuffer/fbuffer.h:5,<br /> from generator.c:1:<br />c:/Ruby193/include/ruby-1.9.1/ruby/ruby.h:109:14: error: size of array 'ruby_check_sizeof_voidp' is negative<br />In file included from c:/Ruby193/include/ruby-1.9.1/ruby.h:32:0,<br /> from ../fbuffer/fbuffer.h:5,<br /> from generator.c:1:</span><br />
<br />
and ended with<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">make: *** [generator.o] Error 1</span><br />
<br />
and some version of the message "<i>make sure the json gem was installed correctly</i>" and "<i>log errors will be stored at C:\Ruby193\lib\ruby\gems\1.9.1\gems\json-1.8.0\ext\json\ext\generator\gem_make.out</i>".<br />
<br />
So I tried "<span style="font-family: "Courier New",Courier,monospace;">gem install json -v '1.8.0'</span>" (sometimes with "<span style="font-family: "Courier New",Courier,monospace;">--platform=ruby</span>") but I still received errors. Then I actually looked at gem_make.out and sow the following line: "<span style="font-family: "Courier New",Courier,monospace;">c:/Ruby193/include/ruby-1.9.1/ruby/ruby.h:109:14: error: size of array 'ruby_check_sizeof_voidp' is negative</span>".<br />
<br />
Cue this <a href="http://stackoverflow.com/questions/15537191/why-does-installing-ruby-on-rails-generate-error-size-of-array-ruby-check-size">StackOverflow post</a>, and I realized that I did <i>not</i> install the correct Devkit. I so wanted to work with the latest release of everything that I ignored the "Which Development Kit?" section of <a href="http://rubyinstaller.org/downloads/">this Ruby Installer for Windows page</a>.<br />
<br />
I reinstalled Devkit (following the instructions <a href="https://github.com/oneclick/rubyinstaller/wiki/Development-Kit">here</a>) and actually created my new web app. Now, I have Ruby 1.9.3 working with Rails 3.2.13 and the <strong>tdm-32-4.5.2 </strong>version of DevKit installed.<strong><br /></strong>Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com2tag:blogger.com,1999:blog-97177745144378627.post-37526871238948828742013-05-30T14:49:00.000-04:002013-05-30T14:49:06.954-04:00So... what are you supposed to do, really?You know what would be really nice?<br />
<br />
If a website promoting some product that purports to make my programming life easier would state what problem it solves. I don't mind searching for more information on a product and looking up word combinations I've never seen before, but, really, something like this would be nice: "Hey, remember when you tried to scale your app and you spent, like, a week wrangling everything into place? This product will let you do that in less time!"<br />
<br />
/end_rantDonna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-89352977521929675962013-04-28T22:40:00.000-04:002013-04-28T22:40:15.389-04:00jQuery UI (1.9.2) dialog box did not have an image for its close buttonThe title is pretty self-explanatory, but let me demonstrate. This was the dialog box that caused me a few hours of pain on Thursday and Friday:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsUL9ATgpALHqiy0xOqKD1Dnoa5Feuytb6g9GvUXRJAcXXMyNuOGxWRoe2Zo3Ovc2xZ1KK5roc89oWBI5Vq-ze41XcudrObwifHLLY9W8Uymczyx7ajyQaJSzD76PaRA4kxtaWgjUefJ8/s1600/no-button-image.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsUL9ATgpALHqiy0xOqKD1Dnoa5Feuytb6g9GvUXRJAcXXMyNuOGxWRoe2Zo3Ovc2xZ1KK5roc89oWBI5Vq-ze41XcudrObwifHLLY9W8Uymczyx7ajyQaJSzD76PaRA4kxtaWgjUefJ8/s1600/no-button-image.jpg" height="166" width="320" /></a></div>
<br />
Notice the "Hide" button? It's because I was so frustrated with the close button that I originally planned to make the contents of the dialog appear on the webpage itself, with an option for the user to hide on show the contents (with tacky buttons, imo).<br />
<br />
Anyway, I thought at first that maybe I did not have the image file for this jQuery-UI theme. I did. Perhaps they were not being loaded properly. They were. Then I remembered that a few months ago, I was working on another website with a working dialog box, so I took a look at and the code behind it.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-yA6UBMI5NxTVVwOGY5rWeB3ZNSxoHIAns9TifXD-tVCCj4w8uuQNOx0lEY4USLaaojrEh-rfrH43hjKPmGstKUTPJQp4pdNr3So9V0gh3yDhqy226z2dI9X6BJAfOgMuscl3LaBjfus/s1600/comparison+button.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-yA6UBMI5NxTVVwOGY5rWeB3ZNSxoHIAns9TifXD-tVCCj4w8uuQNOx0lEY4USLaaojrEh-rfrH43hjKPmGstKUTPJQp4pdNr3So9V0gh3yDhqy226z2dI9X6BJAfOgMuscl3LaBjfus/s1600/comparison+button.jpg" height="149" width="320" /></a></div>
<br />
The button was a span element! So I took a look at the old, working jQuery-UI file and the 1.9.2 version and guess what I found out: the new one uses the button element.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhesUA0Y0hIZ0Ni7EDyWoKnqpdm_FHwKJM6JYzgyi3htyoQ1k1lo_7_E3lWaU_gbG6Q_hy7tfL8IQflR4iY3bevd7rYcnc6PgdT0lUWyFO8gaH1HmD4-TF_qQSTX4EWrLZMdq2XJkusq8A/s1600/no-button-image-code.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhesUA0Y0hIZ0Ni7EDyWoKnqpdm_FHwKJM6JYzgyi3htyoQ1k1lo_7_E3lWaU_gbG6Q_hy7tfL8IQflR4iY3bevd7rYcnc6PgdT0lUWyFO8gaH1HmD4-TF_qQSTX4EWrLZMdq2XJkusq8A/s1600/no-button-image-code.jpg" height="178" width="320" /></a></div>
<br />
(I searched for "ui-dialog-titlebar-close" in the JS file to see where the button would be created and assigned that class.)<br />
<br />
How to fix? Good ol' copy and paste.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTdI4g9tIHjCjVQ3Vn-pMG5I3_o2APbh1CbWT-hCny4j28u2BLxRzip18Cxv9lPSLwzmukGoH0LW8CPRruh9kYFry7NYpj22lPtCU5XYLtL3pzzyk77FxZ7IpC0EQj7Z_U5H66-iMBm9I/s1600/hacked-jquery-ui.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTdI4g9tIHjCjVQ3Vn-pMG5I3_o2APbh1CbWT-hCny4j28u2BLxRzip18Cxv9lPSLwzmukGoH0LW8CPRruh9kYFry7NYpj22lPtCU5XYLtL3pzzyk77FxZ7IpC0EQj7Z_U5H66-iMBm9I/s1600/hacked-jquery-ui.jpg" height="129" width="320" /></a></div>
<br />
<br />
<br />
<br />
By replacing the button element with the span element, I finally got an image for my dialog box close button, except it wasn't quite correct.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSKcz8xgFtUknvwVw42PhgbJCowFsXKXZiW22th_ENrNktPaybY9ltTxIpgbqtUA-S-xLLPzEJuHe981S-Ddvm4qcyuTSUP-SnjFwYQXjQlSQ44HUbAwqjRWBJTrSlbf0BaN4NkVI-oGE/s1600/hacked-button-off-center.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSKcz8xgFtUknvwVw42PhgbJCowFsXKXZiW22th_ENrNktPaybY9ltTxIpgbqtUA-S-xLLPzEJuHe981S-Ddvm4qcyuTSUP-SnjFwYQXjQlSQ44HUbAwqjRWBJTrSlbf0BaN4NkVI-oGE/s1600/hacked-button-off-center.jpg" height="177" width="320" /></a></div>
<br />
<br />
If you've downloaded and unzipped a jQuery-UI theme, you'll know that the all the icons for jQuery-UI stuffs (like calendar arrows and dropdown triangles) are just in one file.<br />
<br />
In the above photo, notice how you can see the edges of the icons next to the "x" in the png file. This was an exciting find for me (!!) because I always wondered why the icons weren't stored as images by themselves.<br />
<br />
So on Friday I learned that jQuery-UI selects its icons from one PNG file through margin, width, and height attributes. (Go try it out on Firebug!) I adjusted these attributes and ended up with a properly centred "x" icon.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiceL5qTSlGR928iF_YvQ0ja7opKg2p_CI-woVC-y8sYbUJhAztvCWqRO_chBPlm0ZcZaRMviv5XbJCh7LsCCECri8crV4uwUIzCo5C-gHBu9fQz3kcW3IBJEaUGcS1mp-4qc114R_ZJX4/s1600/hacked-button-centered.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiceL5qTSlGR928iF_YvQ0ja7opKg2p_CI-woVC-y8sYbUJhAztvCWqRO_chBPlm0ZcZaRMviv5XbJCh7LsCCECri8crV4uwUIzCo5C-gHBu9fQz3kcW3IBJEaUGcS1mp-4qc114R_ZJX4/s1600/hacked-button-centered.jpg" height="183" width="320" /></a></div>
<br />
A better look at the fixed up CSS:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgAHSAT80oUyT-7f1Tn9dQ5qfpIdd3ZWL2lfddAd4k1i_aUphhZFUY6LmrS2eYcZ8gdSaoebOtrDEDGmNNlUA8uz5rIFn-YqdkUq8cCjufXy-rE3KY7GdhePHFywP0qCUH1dt_xWehc_s/s1600/fixed-jquery-css.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgAHSAT80oUyT-7f1Tn9dQ5qfpIdd3ZWL2lfddAd4k1i_aUphhZFUY6LmrS2eYcZ8gdSaoebOtrDEDGmNNlUA8uz5rIFn-YqdkUq8cCjufXy-rE3KY7GdhePHFywP0qCUH1dt_xWehc_s/s1600/fixed-jquery-css.jpg" height="143" width="320" /></a></div>
<br />
I'm not actually sure if there was an easier way to fix my close button image problem. I'm sure changing to an older version of jQuery-UI would've been the correct approach, but, to be honest, a lot of things have been breaking left, right, and center depending on what version of jQuery I've loaded, and I didn't want to take the risk with this one.<br />
<br />
Hope this helps somebody out there. Happy coding!<br />
<br />
Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com1tag:blogger.com,1999:blog-97177745144378627.post-27625952480064077822013-04-06T11:29:00.003-04:002013-04-06T11:29:56.556-04:00Passing a PHP array to a Javascript Ajax callRecently, I found myself making an Ajax call to a PHP function and needing more than just one piece of data back from it.<br />
<br />
For those who don't know, a PHP function can "return" data to an Ajax call by echoing the data out. So, for example, given this Ajax call:<br />
<br />
<pre> $.ajax({
type: "POST",
url: 'http://www.domainname.com/module/controller/insert',
data: { name: 'Donna Oberes', address: 'The Universe' }
}).done(function(msg) {});
</pre>
<br />
And given a function that inserts data into the database, returning/echoing data would look like:<br />
<br />
<pre> public function insert($name, $address)
{
$new_id = </pre>
<pre> $this->people_model->insert(array('name' => $name, 'address' => $address));
// Return the ID by echoing
echo $new_id;
}
</pre>
<br />
The calling Ajax function will 'catch' <span style="font-family: "Courier New",Courier,monospace;">$new_id</span> with the variable msg and do whatever it wants with it.<br />
<br />
But how about if I need more than just the new_id? Say, for example, I need the new id and a nicely formatted date of when this new id was created. I have to return these through an array, but the key is to return the array json_encoded. So I should do this: <br />
<br />
<pre>
public function insert($name, $address)
{
$new_id = </pre>
<pre> $this->people_model->insert(array('name' => $name, 'address' => $address));
$data = array('id' => $id, 'date' => 'April 6, 2013');
echo json_encode($data).
}
</pre>
<br />
And then in the ajax call that catches the printout, <span style="font-family: "Courier New",Courier,monospace;">msg</span> will catch the array, but the array has to go through $.parseJSON so that it's usable as a JavaScript array. <br />
<br />
<pre> $.ajax({
type: "POST",
url: 'http://domainname.com/module/controller/insert',
data: { name: 'Donna Oberes', address: 'The Universe' }
}).done(function(msg) {
var obj = $.parseJSON(msg);
// Print out
$('#student_list').append("New student ID " + obj.id + " added on " + obj.date);
});
</pre>
Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-20071380292192461962013-03-21T22:00:00.001-04:002013-03-21T22:00:27.855-04:00CodeIgniter-Bonfire and ImagesHere is simple code for displaying images in an MVC framework like CodeIgniter-Bonfire. This entry assumes that one already has an understanding of how such a framework works.<br />
<br />
<b>The Database Table</b><br />
<br />
Ideally, your database table would contain the following columns with the following types: id (int(11)), title (varchar(255)), mimetype (varchar(255)), filesize (int(11)), content (longblob). <br />
<br />
The id, title, and filesize columns are self-explanatory. The mimetype is information you need later on for rendering the photo and can be obtained as you're uploading the photo. (The filesize is also something you can get when you're uploading the photo.) The content is the image itself in a binary format.<br />
<br />
<b>The View</b><br />
<br />
At the very least, the view will have a form with one input element of type file so that you can upload the photo. Once you submit the form, you can validate the file size and the extension.<br />
<br />
Sample form:<span style="font-family: "Courier New",Courier,monospace;"><br /><br />< form action="http://some.website.com/images/create" enctype="multipart/form-data"> < /form> <br /><br />< input id="file" name="file" type="file" /><br /><br />< input name="save" type="submit" value="Upload" /></span><br/><br/>The enctype must be 'multipart/form-data.' Otherwise, the $_FILES variable will not be created when you submit the form. $_FILES will contain all the file information you need. If the input box is named 'file', you can get the uploaded file's size through $_FILES['file']['size']. <br />
<br />
Sample controller:<br />
<pre>class images extends Front_Controller
{
public function create()
{
if ($_FILES['file']['size'] > 0)
{
// Get the file info
$name = $_FILES['file']['name'];
$size = $_FILES['file']['size'];
$type = $_FILES['file']['type'];
$tmpname = $_FILES['file']['tmp_name'];
// Grab the contents of the photo
$fp = fopen($tmpname, 'r');
$content = fread($fp, filesize($tmpname));
fclose($fp);
// Load your model, if your constructor doesn't
//do it for you
$this->load->model('images/Images_model',
'images_model');
$data['title'] = $name;
$data['mimetype'] = $type;
$data['filesize'] = $size;
$data['content'] = $content;
// Save the image
$insert_id = $this->images_model->insert($data);
// Now go print out a success message if $insert_id
// is an integer,or an error message if it's false
}
}
}</pre>
<br />
<b>Displaying the image </b><br />
<b> </b><br />
When you want to display the image, the img tag's src should point to another function in your images controller. This function retrieves the images' content from the databases and prints it out with the appropriate headers.<br />
<br />
Sample view<br />
<br />
<pre>Here is a photo: <br/>
< img src="http://some.website.com/images/fetch/8"
alt='a picture' /></pre>
<br />
The controller function will look like the following (put this below the create() function):
<pre>
public function fetch($id)
{
$this->load->model('images/Images_model',
'images_model');
$image = $this->images_model->find($id);
ob_clean();
header("Content-type: ".$image->mimetype);
echo $photo->content;
}
</pre>
<br/>
And that's it! The image will be echoed out to the browser as an actual image (as opposed to the garbage it looks like in the database) because of the Content-type. Your browser knows how to interpret the following data.Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-74214978602256370092013-01-29T12:24:00.002-05:002013-01-29T12:24:42.887-05:00Codeigniter Bonfire error: "Cannot redeclare function in a view file"Well, that was annoying.<br />
<br />
<b>Background</b><br />
<br />
I'm working with Codeigniter-Bonfire to create a web application. CI-Bonfire is an MVC framework that lets you put views within views by calling modules::run('path/to/controller/function', $arg).<br />
<br />
<b>Error</b><br />
<br />
I kept getting this error whenever I tried to call modules::run on a function that I know works.<br />
<br />
Fatal error: Cannot redeclare function_name() (previously declared in /path/to/view_file.php:2) in /path/to/view_file.php on line 15.<br />
<br />
Line 2 in view_file.php is where I declare the function. Line 15 is where the function ends. I know this error comes up because I'm using view_file.php twice somehow and that's why the function is getting redeclared. But where??<br />
<br />
Back to the controller I go and I noticed that I forgot a simple else statement.<br />
<br />
In CI-Bonfire, you can print out a view either by itself (using the standard base_url/module/controller/function/args path) or by calling $this->load->view('view_folder/view_file', $args_array) in the controller if you've set some variable to true.<br />
<br />
My rendering function looked like this:<br />
<br />
if ($hmvc)<br />
$this->load->view('view_folder/view_file', $args_array);<br />
Template::render();<br />
<br />
But it should've looked like this: <br />
<br />
if ($hmvc)<br />
$this->load->view('view_folder/view_file', $args_array);<br />
else <br />
Template::render(); <br />
<br />
Phew!Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-23869619038375533052012-11-20T10:14:00.000-05:002012-11-20T10:15:19.565-05:00Using jQuery .on() rather than .onClick on dynamically generated buttonsLast week, I was beating my head over why the .click() event wasn't working with a dynamically generated button. My setup was that the buttons were given the class 'do_this' and the javascript looked like: <br />
<br />
<code>
$('.do_this').click(function(){ /* insert code here */ }; </code><br />
<br />
At first I thought maybe it was because the code wasn't inside $(document).ready(), so I put it inside one. Didn't work. Then I tried assigning the attribute and value 'onClick="runThisFunction()"' to the button instead. Still no go. (I also thought maybe I should define the Javascript functions after the buttons were generated, so I did just that. I'm not sure why it didn't work, though. It could be because the JS that rendered the buttons happened through a .post call.)
<br />
<br />
Then my co-worker pointed me to the <a href="http://api.jquery.com/on/">jQuery .on()</a> method. Surprise, surprise: it worked! The code looks like this now: <br />
<br />
<code>
$(document).on("click", '.add_contact', function(event) { /* insert code here */ });</code><br />
<br />
The jQuery documentation goes on to explain why .on() works and none of my previous attempts did:
<br />
<blockquote>
Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time. By picking an element that is guaranteed to be present at the time the delegated event handler is attached, you can use delegated events to avoid the need to frequently attach and remove event handlers. This element could be the container element of a view in a Model-View-Controller design, for example, or document if the event handler wants to monitor all bubbling events in the document. The document element is available in the head of the document before loading any other HTML, so it is safe to attach events there without waiting for the document to be ready.
</blockquote>
See? I put everything inside <code>document</code> so the class was already rendered when the Javascript bound the class to the <code>click</code> event.<br />
<br />
So with that in mind, happy coding!Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-16607039031124933722012-10-13T21:57:00.002-04:002012-10-13T21:57:36.350-04:00Bringing up a jQuery dialogue before going to a controllerCurrently, I'm using CodeIgniter/Bonfire for a website that does your basic CRUD operations. One of the functionalities the user wanted was a confirmation dialogue that the user really wanted to delete an item, which corresponds to an entry in the database. My problem was that, while I knew how to bring up jquery dialogue boxes, I wasn't sure how to redirect the dialogue to the controller that would actually delete that item from the database. My solution was to use the "id" attribute of my delete button.
<br />
<br />
While iterating through the items returned from the table, print out the
name of the item and a delete button beside it. The delete button is really an
anchor tag styled to look like a button.<br />
<br />
<div style="font-family: "Courier New",Courier,monospace;">
< a class='btn delete' id='".site_url()."modulename/controllername/function_name/{$item->id}'>Delete< /a></div>
<br />
Notice that I didn't use the href attribute. What I would've put in href, I instead put in id. If I hadn't, I wouldn't be able to call the jquery dialogue because the page would instead go to the href link.<br />
<br />
Whenever this anchor tag is clicked, this piece of javascript would be run:<br />
<br />
<pre>$('a.delete').click(function() {
var dest = $(this).attr('id');
$('#confirm_delete').css("display", "block").dialog({
height: 150,
width: 350,
modal: true,
buttons:
{
Yes: function(){
window.location = dest;
},
No: function(){
$(this).dialog('close');
}}}).dialog('open');});
</pre>
<br />
<br />
It's basic jquery, but the key is the assignment of the anchor tag's id attribute. The above code says: when an anchor tag with class 'delete' is clicked, grab that anchor tag's ID attribute and store it in variable "dest". Then look for an html element with the id "confirm_delete" and display it in a dialogue with the following height, width, and buttons: Yes and No.
<br />
<br />
Just so you know, the div with id = confirm_delete is somewhere on the page with this code:
<br />
<br />
<pre>< div id="confirm_delete" style="display: none;"
title="Remove item">
Are you sure you want to remove this item?
</ div>
</pre>
<br />
If the user clicks on the "Yes" button, then the user will be redirected to the controller that will actually delete the item. If he chooses "No", then the dialogue just closes.
<br />
<br />Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-30864113694397807782012-07-09T23:13:00.002-04:002012-07-09T23:13:26.003-04:00Uploading a custom header image to the twentyeleven theme in WordpressThis is more of a note to myself. <br />
<br />
Right now, I am tasked with customizing the twentyeleven theme into another theme , and it involves turning off the rotating header images. After unsuccessfully doing a walkthrough of the associated code (that begins in header.php with a call to header_image()), I found the functions.php file under wp-content/themes/<themename>. In the twentyeleven_setup() function, I found a call to register_default_headers, which takes in an associative array. I only need one header image, so I deleted all but one key-value pair, renamed the key to something that made sense, and pointed the 'url' key to the photo filename. Now, although I haven't deleted any of the other header images from the directory structure, the code will only pick up the one header image I registered.</themename>Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-90390860236765501822012-03-28T14:53:00.000-04:002012-03-28T14:53:00.149-04:00Self-note: error concerning NetFx40_IIS_schema_update.xmlSo a while ago, while trying to restart IIS, I got an annoying error that said C:\Windows\System32\inetsrv\config\schema\NetFx40_IIS_schema_update.xml wasn't a well-formed xml file. Fine. I checked it, and it was indeed malformed--it contained only nulls.<br />
<br />
Fix this by deleting the goshdarn file.Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com2tag:blogger.com,1999:blog-97177745144378627.post-88904946501584835342011-10-18T17:12:00.016-04:002011-10-26T18:23:49.491-04:00Getting Thunderbird to work with distribution.iniThe bug I'm working on is the <span id="summary_alias_container"><span id="short_desc_nonedit_display"><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=458454">ability to customize vanilla Thunderbird with a group of settings (through distribution.ini)</a>. For those who do not know, Thunderbird is Mozilla's open source mail client. (Mozilla = makers of Firefox). I'm far from done. This entry is a culmination of what I have learned so far.<br /><br /><span style="font-weight: bold;">Checkout the repo</span><br /><br />I am working with Fedora, so I use yum. I followed the build and configure instructions from <a href="https://developer.mozilla.org/en/Build_Documentation">here</a>. In a nutshell, here are the steps to cloning the comm-central </span></span><span id="summary_alias_container"><span id="short_desc_nonedit_display">(Thunderbird)</span></span><span id="summary_alias_container"><span id="short_desc_nonedit_display"> repo:<br /><br />1)<span style="font-weight: bold;font-family:lucida grande;" > </span><span style="font-weight: bold;font-family:courier new;" >yum install mercurial</span> - to get Mercurial, a version control tool.<br /><br />2) Create a file called ".hgrc" in your home directory and put these in it:</span></span><br /><br /><span style="font-family:courier new;">[ui]</span><br /><span style="font-family:courier new;">username=</span><span style="font-style: italic;font-family:courier new;" >Firstname Lastname </span><my.email@address.com><br /><span style="font-family:courier new;">merge=internal:merge</span><br /><br /><span style="font-family:courier new;">[diff]</span><br /><span style="font-family:courier new;">git=1</span><br /><span style="font-family:courier new;">showfunc=1</span><br /><span style="font-family:courier new;">unified=8</span><br /><br /><span style="font-family:courier new;">[defaults]</span><br /><span style="font-family:courier new;">commit=-v</span><br /><span id="summary_alias_container"><span id="short_desc_nonedit_display"><br />Note: Obviously, replace Firstname, Lastname, and my.email... with your information.<br /><br />3) Make sure you're in the directory that you want to put the repo in (for example, your home dir) then checkout the repo<span style="font-family:lucida grande;">:<span style="font-weight: bold;"><br />hg clone</span></span></span></span><span style="font-weight: bold;font-family:lucida grande;" > http://hg.mozilla.org/comm-central/ src-thunderbird<br /><br /></span><span style="font-family:lucida grande;">So now you should have a "src-thunderbird" folder in your current directory.<br /><br /><span style="font-weight: bold;">Building Thunderbird</span><br /><br />1) Go to your src-thunderbird directory (<span style="font-weight: bold;">cd src-thunderbird</span>).<br /><br />2) Create a .mozconfig file. (I use vi, so <span style="font-weight: bold;">vi .mozconfig</span>). This file will contain your build configurations for Thunderbird. The contents of mine are:<br /><br /><span style="font-family:courier new;">mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-tbdebug</span><br /><br /><span style="font-family:courier new;">ac_add_options --enable-application=mail</span><br /><br /><span style="font-family:courier new;">ac_add_options --enable-debug </span><br /><br /><span style="font-family:courier new;">ac_add_options --disable-optimize</span><br /><br />"obj-tbdebug" is the directory where all my object files will end up (you can change what you call yours). I will refer to this as <span style="font-weight: bold;">objdir</span>, from now on. The second line says, build me Thunderbird. The third line is because I need debugging printouts. The fourth line I just threw in for good measure. You can read more about configuration options <a href="https://developer.mozilla.org/en/Configuring_Build_Options">here</a>.<br /><br />3) Build Thunderbird! "<span style="font-weight: bold;">make -f client.mk build</span>" (while still in src-thunderbird). This step will take a while (more than a half hour in my case).<br /><br />4) Once the build is done, run Thunderbird with <span style="font-weight: bold;">./objdir/mozilla/dist/bin/thunderbird</span>. Since we configured this build with the debug option, you will see a lot of printouts at your terminal.<br /><br /><span style="font-weight: bold;">Updating the repository </span><br /><br />Make sure you're in the src-thunderbird directory. On the terminal, execute <span style="font-weight: bold;">python client.py checkout</span>. Re-build again.<br /><span style="font-weight: bold;"><br /><br />Modifying the source files<br /></span><br />The source files are everything outside your src-thunderbird file. Everything in it are your object files. When you modify your source files, you need to re-create your object files. You can run <span style="font-weight: bold;">make -f client.mk build </span>again (in your src-thunderbird dir), and it won't take as long as the first time.<br /><br />If you <span style="font-style: italic;">changed files in only one directory</span>, you can re-make only that directory. For example, if you changed files only in ~/src-thunderbird/mail/components, run <span style="font-weight: bold;">make -C objdir/mail/components</span>.<br /><br /><span style="font-weight: bold;">Getting distribution.ini working</span><br /><br />1) This is a <a href="https://bug458454.bugzilla.mozilla.org/attachment.cgi?id=341685">sample distribution.ini</a>. This file must be placed in objdir/mozilla/dist/bin/distribution.<br /><br />2) Add "distribution.js \" to the EXTRA_JS_MODULES section of Makefile.in (which resides in ~/src-thunderbird/mail/base/modules).<br /><br />3) distribution.js should be in ~/src-thunderbird/mail/base/modules. I copied and modified the <a href="http://mxr.mozilla.org/mozilla-central/source/browser/components/distribution.js">Firefox version</a>. (Code referring to bookmarks and livemarks were ripped out.) I also changed the name of the object it exported to something like TBDistCustomizer.<br /><br />(Note: JS modules have EXPORTED_SYMBOLS at the start of the file. This is as opposed to components files (which are also JS), which do not.)<br /><br />4) </span></my.email@address.com><span style="font-family:lucida grande;">cd to objdir/mail/base/modules and type "<span style="font-weight: bold;">make</span>".</span><my.email@address.com><span style="font-family:lucida grande;"><br /><br />5) Modify mailGlue.js (in ~/src-thunderbird/mail/components) so that:<br /><br />(a) It would import distribution.js (<span style="font-weight: bold;">Components.utils.import("resource:///modules/distribution.js");</span>); and<br /><br />(b) it would create an instance of TBDistCustomizer. This intance can now be used to call the code in distribution.js that actually changes prefs (applyPrefDefaults).<br /><br /><strike><span style="font-weight: bold;">Hitting the brick wall</span><br /><span style="font-weight: bold;"><br /></span>So now I've come to the point where preferences set in distribution.ini <span style="font-style: italic;">are </span>being set in Thunderbird, but there is a catch: some prefs are set properly, while others are duplicated. For example, mail.phishing.detection.enabled is set correctly, but something like network.cookie.lifetimePolicy instead becomes duplicated, with one version having the default and the other having the value that was set in distribution.ini.<br /><br />I am still trying to figure out why this is so...</strike><br /><br /><span style="font-weight: bold;">Climbing the brick wall</span><br /><br />The problem was that distribution.ini doesn't like spaces around the "=" sign. <span style="font-family:courier new;">network.cookie.lifetimePolicy = 1 </span>should be <span style="font-family:courier new;">network.cookie.lifetimePolicy=1</span>.<br /><br /></span></my.email@address.com><span style="font-family:lucida grande;"><span style="font-weight: bold;">Thanks to...</span><br /><br />The MailDev team at Mozilla! In particular Standard8 and sid0 for helping me get started.</span>Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-13623679854748120202011-06-15T12:57:00.002-04:002011-06-15T13:00:27.594-04:00Mozilla XPComHere is the link to a list of <span style="font-weight: bold;">ALL</span> the XPCOM contract ID's/components and interfaces are: http://www.oxymoronical.com/experiments/xpcomref/<br /><br />I am currently working on creating an addon that will always take settings from Internet Explorer and set the same prefs for Firefox. Still in the research stages, tho.Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-48699346631584983952011-05-24T21:19:00.002-04:002011-05-24T21:24:34.840-04:00SHUTDOWN ABORTI feel powerful executing the above command as a sysadmin 3=) While practicing on my own database for DBA625, I happened to close a session after thinking that zenit has once again frozen. As it turns out, closing session doesn't necessarily end all processes in my database. When I tried logging on again, I got this:<br /><br /><code><br />SQL> connect sys as sysdba<br />Enter password:<br />Connected to an idle instance.<br />SQL> startup<br />ORA-01012: not logged on<br />SQL> startup mount;<br />ORA-01012: not logged on<br /></code><br />After some googling and deciding that I do not want to mess with resetting memory sizes, I came across "SHUTDOWN ABORT;" and it fixed all my problems.<br /><br /><code><br />SQL> SHUTDOWN ABORT<br />ORACLE instance shut down.<br />SQL> STARTUP<br />ORACLE instance started.<br /><br />Total System Global Area 631914496 bytes<br />Fixed Size 1338364 bytes<br />Variable Size 440402948 bytes<br />Database Buffers 184549376 bytes<br />Redo Buffers 5623808 bytes<br />Database mounted.<br />Database opened.<br /></code>Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-59635700728237224412011-04-07T17:04:00.009-04:002011-04-08T14:30:25.378-04:00Lessons in creating Firefox Enterprise<span style="font-weight: bold;">Firefox Enterprise</span><br /><br />For the past 6 months, I have been at <a href="http://zenit.senecac.on.ca/wiki/index.php/Main_Page">CDOT</a> as Mike Hoye's cronie, and along with <a href="http://scottdowne.wordpress.com/">scott</a> and <a href="http://annasob.wordpress.com/">annasob</a>, I have been working towards creating an enterprise version of Mozilla's Firefox. <a href="http://bespokeio.com/">Bespoke IO</a>, mhoye's company, will be selling the software that lets administrators customize Firefox and produces the MSI that makes deployment across a network easier. It will also be offering Sync services. If you are not familiar with that, <a href="http://www.mozilla.com/en-US/mobile/sync/">Sync</a> lets you store your browsing history in a server--your own or Mozilla's--so that you can you can access your browsing history, passwords, and bookmarks across several different devices. <a href="http://exple.tive.org/blarg/?p=2621">I will leave the elevator pitch for the boss.</a><br /><br />As far as I know, an enterprise version of Firefox conflicts with Mozilla's philosophies about freedom on the web. (To illustrate what "freedom on the web" means, an example: if a user wants to watch a video on YouTube, s/he should just be able to click on a link and the video will play instead of being told that s/he needs a plugin.) That is why Mozilla has not produced the product themselves, and an opportunity for my co-op position was available.<a href="http://exple.tive.org/blarg/?p=2621"></a><br /><br />Since Mozilla is open source, it was a matter of taking the existing <a href="http://byob.mozilla.com/en-US">Build Your Own Browser</a> code and customizing it (with a lot of guidance from kev and lorchard!). The first screenshot is what our BYOB was near the beginning of the project. The first thing I added was the Homepage tab. The second screenshot is what the latest version looks like. The administrator can now choose to lock some things, like the homepage, proxy settings, and which updates are allowed.<br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtw8LY9Vtlyor0gyBNdfuwGzjjjiroavBwJ_rdM0cnTm7xxo1fEsJnuB0BTb_zkTzkdGHGlIPH26IvZP0RyiXkEG9wLSXStfVwgHjfHmY3glhe7D3cGWEf6Ky21F0mPFl7SDlX25LfDqM/s1600/beginning.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 348px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtw8LY9Vtlyor0gyBNdfuwGzjjjiroavBwJ_rdM0cnTm7xxo1fEsJnuB0BTb_zkTzkdGHGlIPH26IvZP0RyiXkEG9wLSXStfVwgHjfHmY3glhe7D3cGWEf6Ky21F0mPFl7SDlX25LfDqM/s400/beginning.jpg" alt="" id="BLOGGER_PHOTO_ID_5593277970985088018" border="0" /></a><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvRyoD77OLvcnIHWkOgOZSwNv3Abk4CL3oGO7Q3VJh-j-Sfj5EXEK46HrZZQV37mnxwaslQuN5OwPjcA6cu1wBs-RhYtXFsewZJW7uvUj16uegBROMV88S8X9NuIrPyAauRP9E11fzGD8/s1600/later.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvRyoD77OLvcnIHWkOgOZSwNv3Abk4CL3oGO7Q3VJh-j-Sfj5EXEK46HrZZQV37mnxwaslQuN5OwPjcA6cu1wBs-RhYtXFsewZJW7uvUj16uegBROMV88S8X9NuIrPyAauRP9E11fzGD8/s400/later.jpg" alt="" id="BLOGGER_PHOTO_ID_5593278049326336146" border="0" /></a><br /><br /><span style="font-weight: bold;">Wading through code</span><br /><br />It was a mess :s As mhoye put it, he threw me under a bus. Although the framework BYOB was built on was documented (<a href="http://kohanaframework.org/">Kohana</a>), for me, there was no way to actually understand what was happening in BYOB unless I did a million printouts and walkthroughs. I realized only much later that the code was exactly what they taught Seneca students in the SYS courses. You have your views, controllers, and models, and then the database.<br /><br />mhoye had me started on letting an admin choose what the homepage was. <span style="font-style: italic;">Where do I begin? </span>My coding bff since then has been the Multi-file Search option in Textwrangler. I searched for all instances of General, then Locales, then Collections in the hopes that I could trace what happened whenever these words popped up. The problem was that General was useless and Locales was coded differently from little prefs like homepage and proxy settings.<br /><br />Luckily, kev and lorchard were kind enough to point me in the right direction. But then, it was like giving me a clue as opposed to telling me exactly what to do, which was better in the end. Teach a man how to fish and all that.<br /><br />Since then, I have gotten to know BYOB really well, but I still learn something everyday, whether it's coding in PHP or bits of Firefox itself. (I dabble in Python every other month, too, but I avoid that part of the code as much as possible.) So far, I can lock down the homepage, proxy settings, and updates. End users cannot change them. Administrators can also add certificates and specify what server they want to use with Sync (if they want it to be used at all).<br /><br /><span style="font-weight: bold;">Challenges</span><br /><br />Mozilla's goal is to give the user the best web experience possible; mine is to cramp the user's style <span style="font-style: italic;">just a little bit</span>.<br /><br />The last great roadblock I had was both a coding problem and a Firefox issue: how do I get BYOB to upload certificates and then add them to the list of certificates in Firefox right from the beginning?<br /><br />The frustrating thing about coding with Kohana was that I didn't grasp the idea of routes right away. There is a special file in the framework that says, if your url is like this: http://myapp.com/fnName/randomText/moreRandom/, then you should be accessing the first file with function fnName in it (there could be more than one!), and pass it the "*[Rr]andom*" arguments.<br /><br />I also came up with what I believe to be a rather inelegant solution to adding certificates to Firefox... only to find out that unless I find a way to make the certificate window read-only/disappear, a user can delete any certificate in it. That's problem # 2.<br /><br />Problem # 1 is bookmarks. Adding bookmarks to a Firefox build was something that Moz's BYOB already did, but how do I lock those bookmarks so that users can't delete them? I know of <a href="http://kb.mozillazine.org/Places.sqlite">places.sqlite</a>, <a href="http://kb.mozillazine.org/Bookmarks.html">bookmarks.html</a>,and the <a href="http://kb.mozillazine.org/Bookmarkbackups_folder">bookmarkbackups folder</a>... But how do I fiddle with those three so that my bookmarks can't be deleted? Right now, I can create a file with json-formatted bookmarks data in it and name it so that Firefox will always load those bookmarks when the browser starts. But that prevents any bookmarks the user will add from loading. Not very user-friendly.<br /><br />Problem # 3 is preventing the user from deleting addons. Right now, addons are locked so that a user can disable them, but not delete them. From the reading I've done, there is a file called userChrome.css that I can write myself; it prevents the addon manager from appearing at all. I could insert that file into the depths of the Firefox application directory. Is there a better way?<br /><br /><span style="font-weight: bold;">What's next?</span><br /><br />Sometime in the summer semester, I believe mhoye is looking for beta testers, so a deadline is tentatively set. My goal for the next week is to leave some good documentation (so that I don't curse myself when I come back from the semester break) and get the bookmarks locked. Still not sure what to do... If you have any answers, please share :DDonna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-32823766926307216462010-10-07T15:32:00.011-04:002010-10-07T17:41:22.097-04:00Game programming with open source toolsRemember trying to create games with Flash? No? Neither do I. I couldn't be bothered to pay for the tools I needed. But that's okay because it's now possible to code games for the web using free tools like <a href="http://processingjs.org/">Processing.js</a> and <a href="http://www.c3dl.org/">C3DL</a>. You don't have to pay $$$ to be the game programmer you want to be. You just need a bit of patience and dedication.<br /><br /><a href="http://zenit.senecac.on.ca/wiki/index.php/Level_Up:_An_OpenWeb_Game_Jam">Level Up: An OpenWeb Game Jam</a> is a tutorial/hack session happening right before the <a href="http://fsoss.senecac.on.ca/2010/">Free Software and Open Source Symposium (FSOSS)</a> 2010 on October 27 at the Seneca@York. Think of it as a one-day sprint of learning new languages. In the morning, you attend the tutorials and the in the afternoon you get to try out what you've learned. Yes, you get to code your own game!<br /><br />When you really think about it, why learn a new language by yourself when you can have fun, socialize (network, maybe?), and learn with others?<br /><br />* * *<br />Some html5 games that you can while away time with:<br /><a href="http://yvoschaap.com/chainrxnadvanced/">Chain Reaction - Advanced - http://yvoschaap.com/chainrxnadvanced/</a><br /><a href="http://html5games.com/">HTML5 Games - http://html5games.com/</a>Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-35965593485960888602010-09-28T18:29:00.035-04:002010-10-06T12:43:07.939-04:00Getting tweets to fade onto the screenOver the past two weeks, I got to know <a href="http://www.json.org/">JSON</a> and the <a href="http://apiwiki.twitter.com/">Twitter API</a> well enough to write a <a href="http://matrix.senecac.on.ca/%7Edaoberes/fadeTweets/fadeTweets4.html">fun little function</a> that lets tweets fade into the screen. It is my contribution to the demo that Scott and Anna are presenting at the Open Video Conference. (It was modified in the final version.)<br /><br /><span style="font-weight: bold;">Things to get out of the way:</span><br /><br />1) "Closure" in Javascript. According to two explanations (<a href="http://www.hunlock.com/blogs/Closing_The_Book_On_Javascript_Closures">Patrick Hunlock</a> and <a href="http://www.javascriptkit.com/javatutors/closures.shtml">Javascript Kit</a>), a closure is a variable that continues to exist outside of the function that created it.<br /><br />2) You can assign a function to a variable! Eg.<br /><pre>var doSomething = function() {<br />alert("You are perusing Donna's blog");<br />/* And whatever else you want to do in this function */<br />}<br /></pre>What it is useful for, as explained in <a href="http://www.permadi.com/tutorial/jsFunc/index.html">permadi.com</a>, is adding functions as a property of an object (see Example D2A in the webpage).<br /><br /><span style="font-weight: bold;">JSON</span><br /><br />To get started, I had to look up what a JSON object is and how to get a JSON object from websites like Twitter. JSON is javascript object notation. All it does is contain data. At its most basic form, a JSON object has a key-value pair (like ({"name" : "donna oberes"}) ); other times, it can be an array of key-value pairs, like this:<br />("students" : {("name" : "donna oberes", "program" : "cpa"), ("name" : "john doe", "program" : "cns")}). .<br /><span style="display: block;" id="formatbar_Buttons"><span class="" style="display: block;" id="formatbar_CreateLink" title="Link"><img src="http://www.blogger.com/img/blank.gif" alt="Link" class="gl_link" border="0" /></span></span><br /><span style="font-weight: bold;">Twitter API</span><br /><br />A <a href="http://dev.twitter.com/doc/get/search">part of the Twitter API</a> describes the link that will bring up a JSON object containing tweets and other information related to it. For example, http://twitter.com/status/user_timeline/daoberes.json?count=15&callback=? will bring up a JSON object containing all the tweets that a person has made and all related information, like the date and the tweet ID. Something like <a href="http://search.twitter.com/search.json?q=%23happy&callback=?">http://search.twitter.com/search.json?q=%23happy&callback=?</a> will bring up all the tweets with the hashtag "#happy" and other info such as the tweeter's ID, the tweet itself, the date, the user's avatar, etc. If you click on the last link (Google Chrome displays the data on the browser), you'll notice that the object has a key called "results" and that its value is an array of objects and other key-value pairs (look at the bottom!). To get it formatted, go to <a href="http://www.jsbeautifier.org/">jsbeautifier.org</a>.<br /><br /><span style="font-weight: bold;">jQuery</span><br /><br />How did I put all of this together? Through good ol' Javascript and <a href="http://jquery.com/">jQuery</a>. According to the website, "jQuery is a fast and concise JavaScript Library that simplifies HTML document traversing, event handling, animating, and Ajax interactions for rapid web development." It <span style="font-style: italic;">did</span> make my life a lot easier.<br /><br />The functions that I used from the library are<a href="http://docs.jquery.com/GetJSON"> .getJSON ()</a>, <a href="http://api.jquery.com/css/">.css</a> (the 2nd overloaded function), <a href="http://api.jquery.com/fadeIn/">$.fadeIn()</a>, and <a href="http://api.jquery.com/fadeTo/">.fadeTo</a>.<br /><br />.getJSON returns the results of the query in JSON format and then lets you specify exactly what you want done with the returned data with the optional callback parameter. This is what I did:<br /><pre><br />$.getJSON('http://search.twitter.com/search.json?q=%23' + searchTerm + '&callback=?',<br />null, function(data) {<br />datalength = 4;<br /><br />/* Store tweets and twitter user images in a JSON object */<br />tweets = []; //declare array of tweets;<br /><br />//Declare a JSON object<br />jsonTweets = [];<br /><br />//Iterate through JSON object and push Twitter pictures and tweets<br />// onto another JSON object<br /> for (i = 0; i < datalength; i++) {<br /> if (data.results[i].text) {<br /> jsonTweets.push({ "tweetPic" : data.results[i].profile_image_url,<br /> "tweet" : data.results[i].text,<br /> "twitterId" : data.results[i].from_user,<br /> "id" : data.results[i].id });<br /> }<br /> }<br /> nextTweetOrNone();<br />});<br /></pre><br /><br /><span style="font-weight: bold;">How the function worked</span><br /><br />After asking the user to enter a hashtag they would like to print to the screen, the function calls the .getJSON function ( $.getJSON('http://search.twitter.com/search.json?q=%23' + tag + '&callback=?', null, function(data) { ... }); ) and processes the JSON object as a whole and takes out of it anything I would need later on.<br /><br />nextTweetOrNone() is going to check if the array I just created still has any elements in it. I am going to start popping elements out of it in the next function, and then I will call nextTweetOrNone() again to keep checking if there are still elements I can print out.<br /><br />I used the<a href="http://www.w3schools.com/js/js_timing.asp"> setTimeout()</a> function so that all my tweets would not fade into the screen all at once. setTimeOut() calls printTweet.<br /><br />printTweet first pops an element from the end of the array. Then it creates a span element that will contain two inner span elements, one for the twitter user's picture and one for the tweet. Later in the function, I use <a href="http://www.w3schools.com/DOM/met_element_appendchild.asp">.appendChild()</a> to actually make the outer span tag contain the two inner span tags.<br /><br />The tweets are to appear in random colours, depending on the mood typed in. The "sad" tag will appear in mostly blue colours, "angry" in red, and "happy" in all ranges. I specified the 10 colours that each of the tags will appear in and used the Math.random() function to get a random number between 1 and 10.<br /><br />I then used the .css function to specify the appearance of the span tags that I created. (This is where the random font colour of the text is set, amongst other things.)<br /><br />And then the fun part! I used .fadeIn to specify how long the tweets should take to appear on the page. And then I used .fadeTo to reduce the tweet's opacity!<br /><br />Try it out! Happy coding!Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-41850673233387545412010-09-10T15:18:00.001-04:002010-09-10T15:24:41.283-04:00Started @ CDOTThis fall, I am a "Student Research Assistant" at <a href="http://zenit.senecac.on.ca/wiki/index.php/Main_Page">CDOT</a>. It's a wikkid title because it sounds like it belongs to a university student. However, as one of the administrators explained it, we are not researching for the sake of knowledge--we are researching for the sake of a final product.<div><br /></div><div>The first thing I did was set up my workstation. Sounds easy enough, but when you throw in a MAC OS (which I'd never worked with before), it's new*2.</div><div><br /></div><div>Some things I learned:</div><div><br /></div><div><b><span class="Apple-style-span">sudo su</span></b></div><div><b><span class="Apple-style-span"><br /></span></b></div><div>1) I should've set up my account on this computer under the admin account in the first place.</div><div><br /></div><div>2) I utilized the <span class="Apple-style-span">sudo su</span> command while setting up my <a href="http://github.com/">github</a> account (as outlined in <a href="http://annasob.wordpress.com/2010/05/13/installing-git-on-max-os/">Anna's blog</a>). (github is a version control system.) <a href="http://www.sudo.ws/sudo/sudo.man.html"><span class="Apple-style-span">sudo</span></a> is a command that lets you execute commands as a super user.</div><div><br /></div><div>Since everything was done at the command line, as user donna, I was prompted for a password every now and then and then inevitably told that "donna is not a sudoer" (or something like that). The fix was to beat the cl to the punch and just type in <span class="Apple-style-span">sudo su</span> and then type in the admin password, and off I went.<br /><br />(Must mention that even while under Admin account, I had to <span class="Apple-style-span">sudo su</span> in order to access other user's accounts).</div><div><br /></div><div><b>github</b></div><div><br /></div><div>As I already said, github is a version control system. In one of my classes, <a href="http://zenit.senecac.on.ca/wiki/index.php/OOP344">OOP344</a>, I used Tortoise SVN, and that was fine because it had GUI. Since Anna's instructions were on the command line, that's how I worked, too. It was frustrating =\<br /></div><div><br /></div><div>After cloning the repos that I was going to be working with, I created a local and a remote branch (again, instructions are in <a href="http://annasob.wordpress.com/2009/10/18/adding-new-code-to-your-github-repository/">Anna's blog</a>), but I stumbled a bit. Things I learned:</div><div><br /></div><div>1) When branching, make sure you are in the directory that contains the cloned repo. So when you clone popcorn (one of the repos I will be working with) like this:<br /><br /><span style="font-family: 'courier new'; ">git clone git://github.com/mozilla/popcorn-js.git popcornDonna</span><br /><br />follow with <span style="font-family: 'courier new'; ">cd popcornDonna</span>, then create the branch (<span style="font-family: 'courier new'; ">git branch firstBranch</span>).<br /></div><div><br /></div><div>2) As Anna says in her blog, some errors that result in creating a remote branch (using the <span class="Apple-style-span">git push</span> command) are fixable by editing the config file. She is referring to the .git/config file.</div><div><br /></div><div>How to find the file: make sure you are in the folder that contains the repo you cloned (in my example, the folder is popcornDonna). Then type <span class="Apple-style-span">ls -a</span> . One of the results should be .git. Change directory to .git (<span class="Apple-style-span">cd .git</span>). Type <span class="Apple-style-span">ls </span><span class="Apple-style-span">and</span> you should see the config file. Edit it.</div><div><br /></div><div>So far so good, tho. Just going to be reading up on Popcorn and learning some JS for the time being.</div>Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-66669668648747702322010-07-18T17:06:00.003-04:002010-07-18T17:18:26.405-04:00Game development club at SenecaDid you know there's a game programming club at Seneca? Check out the <a href="http://gamedev.dkxy.net/">unofficial website</a>.<br /><br />Actually, the club is in its neonatal stages. The founding students still have not found a faculty advisor and, from what I can gather, they are trying to get the Arts and Animation faculty in on it too. Sounds like a big project! However, if they can get enough students to join, the ball might actually start rolling and things will be organized in time for the fall semester (less than two months away!).<br /><br />Hope to see some of you there!Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com0tag:blogger.com,1999:blog-97177745144378627.post-29993559110793040522010-03-15T08:21:00.003-04:002010-03-15T08:53:21.952-04:00Container ClassesIRC meetings have become so slow that <a href="http://seneblog.fardad.com/">Fardad Soleimanloo</a> has now decided to try using voice conferences through Skype! Though OOP344 is not an open source course (like <a href="https://scs.senecac.on.ca/course/osd600">OSD600</a>), the <a href="http://zenit.senecac.on.ca/wiki/index.php/Project_20101_OOP344">project</a> for it sure is starting to look and work like one. (Just this morning I had to chuckle at <a href="http://zenit.senecac.on.ca/wiki/index.php/Team_Mighty_Morphin_Coding_Rangers_-_OOP344">my team</a>--scheduling a meeting that works with everyone's schedules is a nightmare.) I find the course incredible because in all my years of studying, I've never seen a teacher put so much time into a course or students asked to put so much into it either. In university for Economics, I mastered the art of cramming for every midterm and test (those were all you were getting marked on, after all). I studied strategically and aced <span style="font-style: italic;">most</span> of them, but I didn't retain much info in the end. I'm finding that in college, with weekly due dates for each course, you have to keep at it or fall behind if you let things slide even by a week.<br /><br />Anyway, the real point of this post was to share a couple of nifty little webpages about container classes. In our last IRC meeting, my group had a bouncy, yellow question mark over our collective heads because we just didn't grasp the idea of them soon enough. But the fact is, container classes really are how Fardad described: they are an array (another kind of container) for objects. <a href="http://www.learncpp.com/cpp-tutorial/104-container-classes/">Here</a> is the webpage, complete with a sample class, from <a href="http://www.learncpp.com/">learncpp.com</a>. I haven't read <a href="http://www.parashift.com/c++-faq-lite/containers.html">this one</a> from <a href="http://www.parashift.com/c++-faq-lite/">parashift.com</a> yet, but the writing seemed pretty funny, especially after learning the basics of a container class.<br /><br />I haven't read the textbook section for stacks and queues yet (and yes, that means I haven't coded how a queue works yet, either), but the above webpages really helped me understand the basic idea for them. I hope they help someone else, too.Donna_Obereshttp://www.blogger.com/profile/00305404482714602892noreply@blogger.com1