Tuesday, June 17, 2014

This will format your Twitter Bootstrap forms nicely. Block errors, inline help. (symfony 1.4 form formatter, decoration, twitter bootstrap, apply a formatter to an application)

123456789101112
 
require_once dirname(__FILE__).'/../lib/vendor/symfony/lib/autoload/sfCoreAutoload.class.php';
sfCoreAutoload::register();
 
class ProjectConfiguration extends sfProjectConfiguration
{
public function setup()
{
sfWidgetFormSchema::setDefaultFormFormatterName('bootstrap');
}
}
This will format your Twitter Bootstrap forms nicely. Block errors, inline help.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
 
class sfWidgetFormSchemaFormatterBootstrap extends sfWidgetFormSchemaFormatter
{
protected
$rowFormat = "
\"control-group %error_class%\">\n%label%\n
\"controls\">%field%\n%help%\n%error%
\n%hidden_fields%
\n",
$helpFormat = '%help%',
$errorRowFormat = "\n%errors%\n",
$errorListFormatInARow = " \n%errors%\n",
$errorRowFormatInARow = "
\"help-block\">%error%
\n",
$namedErrorRowFormatInARow = "
\"help-block\">%name%: %error%
\n",
$decoratorFormat = "%content%",
$widgetSchema = null,
$translationCatalogue = null;
public function generateLabel($name, $attributes = array()) {
$labelName = $this->generateLabelName($name);
if (false === $labelName)
{
return '';
}
if (!isset($attributes['for']))
{
$attributes['for'] = $this->widgetSchema->generateId($this->widgetSchema->generateName($name));
}
if (isset($attributes['class'])) {
$attributes['class'] .= ' ';
} else {
$attributes['class'] = '';
}
$attributes['class'] .= 'control-label';
return $this->widgetSchema->renderContentTag('label', $labelName, $attributes);
}
public function formatRow($label, $field, $errors = array(), $help = '', $hiddenFields = null)
{
return strtr($this->getRowFormat(), array(
'%label%' => $label,
'%error_class%' => count($errors) ? 'error' : '',
'%field%' => $field,
'%error%' => $this->formatErrorsForRow($errors),
'%help%' => $this->formatHelp($help),
'%hidden_fields%' => null === $hiddenFields ? '%hidden_fields%' : $hiddenFields,
));
}
}
PS: to use this format in backend only, you can do:
root/lib/form/BaseForm.class.php
class BaseForm extends sfFormSymfony
{

public function configure()
{

//use bootstrap form layout at backend
if (sfConfig::get('sf_app') == 'backend') sfWidgetFormSchema::setDefaultFormFormatterName('bootstrap');
} 

Thursday, June 12, 2014

Random tricks when using AngularJS | Tomaka's blog

Random tricks when using AngularJS | Tomaka's blog



Random tricks when using AngularJS

If you don’t know AngularJS, it is a very good Javascript library that allows you to easily build web applications. Here are some random useful tricks that I found for AngularJS users.

TERNARY OPERATOR IN EXPRESSIONS

When you write an expression, like {{ id }}, you can’t use the ternary operator ?:. But you can use the && and || operators. These two lines are identical provided that b always equals true:
a ? b : c
a && b || c
For example:
<p>This feature is {{ feature.isActivated && "activated" || "not activated" }}</p>
This reason why it works is that "a && b" is treated like "if (a) return b; return a;" and "a || b" is treated like "if (!a) return b; return a;".

USING ARRAYS OR OBJECTS INSIDE EXPRESSIONS

You can use arrays or objects directly from inside AngularJS expressions. For example, you can write the list of days of the week like this:
<ul>
  <li ng-repeat="day in [1,2,3,4,5,6,7]">Name of the day: {{ ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'][day-1] }}</li>
</ul>
This will output:
<ul>
  <li>Name of the day: Mon</li>
  <li>Name of the day: Tue</li>
  <li>Name of the day: Wed</li>
  <li>Name of the day: Thu</li>
  <li>Name of the day: Fri</li>
  <li>Name of the day: Sat</li>
  <li>Name of the day: Sun</li>
</ul>

WATCHING TWO VARIABLES ARE ONCE

AngularJS allows you to watch a variable and will call a callback whenever its content is modified. But what if you need to watch two variables at once? You can write this:
function callback() {
  ...
}

$scope.$watch('a', callback);
$scope.$watch('b', callback);
But you can also write this, which is more elegant:
$scope.$watch('a + b', function() {
  ...
});
The value of "a + b" will change whenever either a or b changes. Therefore you watch both variable at once.

SYNTAX OF DIRECTIVES

The tutorial of AngularJS writes directives like this: "ng-model". But you can also write: "x-ng-model", "ng:model", "ng_model", "data-ng-model". They are all equivalent and work the same. I like to use the syntax with "data-" because it is standard-compliant.

ADDING A LOADING SCREEN ON AJAX REQUEST

This module will add a loading screen over the whole page whenever an AJAX request is made using AngularJS's $http or $resource. This will prevent the user from clicking anywhere, which is a good solution if you don't want to handle the consequences of clicks during requests. Just don't use this if you load several megabytes of data.
angular
    .module('loadingOnAJAX', [])
    .config(function($httpProvider) {
        var numLoadings = 0;
        var loadingScreen = $('<div style="position:fixed;top:0;left:0;right:0;bottom:0;z-index:10000;background-color:gray;background-color:rgba(70,70,70,0.2);"><img style="position:absolute;top:50%;left:50%;" alt="" src="data:image/gif;base64,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" /></div>')
            .appendTo($('body')).hide();
        $httpProvider.responseInterceptors.push(function() {
            return function(promise) {
                numLoadings++;
                loadingScreen.show();
                var hide = function(r) { if (!(--numLoadings)) loadingScreen.hide(); return r; };
                return promise.then(hide, hide);
            };
        });
    });

GLOBAL ERRORS HANDLER

In web applications you usually handle AJAX errors globally. If the server returns an error, an error message will be displayed, and it's always at the same location in the application no matter the location of the error. This module allows you to define the location where they will be displayed.
angular
    .module('globalErrors', [])
    .config(function($provide, $httpProvider, $compileProvider) {
        var elementsList = $();

        var showMessage = function(content, cl, time) {
            $('<div/>')
                .addClass('message')
                .addClass(cl)
                .hide()
                .fadeIn('fast')
                .delay(time)
                .fadeOut('fast', function() { $(this).remove(); })
                .appendTo(elementsList)
                .text(content);
        };
        
        $httpProvider.responseInterceptors.push(function($timeout, $q) {
            return function(promise) {
                return promise.then(function(successResponse) {
                    if (successResponse.config.method.toUpperCase() != 'GET')
                        showMessage('Success', 'successMessage', 5000);
                    return successResponse;

                }, function(errorResponse) {
                    switch (errorResponse.status) {
                        case 401:
                            showMessage('Wrong usename or password', 'errorMessage', 20000);
                            break;
                        case 403:
                            showMessage('You don\'t have the right to do this', 'errorMessage', 20000);
                            break;
                        case 500:
                            showMessage('Server internal error: ' + errorResponse.data, 'errorMessage', 20000);
                            break;
                        default:
                            showMessage('Error ' + errorResponse.status + ': ' + errorResponse.data, 'errorMessage', 20000);
                    }
                    return $q.reject(errorResponse);
                });
            };
        });

        $compileProvider.directive('appMessages', function() {
            var directiveDefinitionObject = {
                link: function(scope, element, attrs) { elementsList.push($(element)); }
            };
            return directiveDefinitionObject;
        });
    });
Usage :
<div class="messagesList" app-messages></div>
Whenever an HTTP request (made using AngularJS's $http or $resource object) returns an error code, or when a non-GET request succeeds, a message will be displayed inside this container for a few seconds. Thanks to this, you almost don't need to worry about errors anymore.

USING HTTP BASIC AUTH

Some web applications use HTTP basic authentication (through HTTPS). You can also use this with AngularJS by setting the value of the "Authorization" header for the $http service.
$http.defaults.headers.common['Authorization'] = 'Basic ' + Base64.encode($scope.login.login + ':' + $scope.login.password);
Note that Base64.encode comes from this website. IE9 and below don't support atob and bota.
Here is an example code for a login form:
var LoginController = function($scope, $http) {
    $scope.login = {};
    $scope.login.user = null;

    $scope.login.connect = function() {
        $http.get('/users/me').success(function(data, status) {
            if (status < 200 || status >= 300)
                return;
            $scope.login.user = data;
        });
    };
    
    $scope.login.disconnect = function() {
        $scope.login.user = null;
    };

    $scope.$watch('login.login + login.password', function() {
        $http.defaults.headers.common['Authorization'] = 'Basic ' + Base64.encode($scope.login.login + ':' + $scope.login.password);
    });
};
<div ng-controller="LoginController">
  <div ng-hide="login.user">
    <form action="" ng-submit="login.connect()">
      <fieldset>
        <legend>Login</legend>
        <p><input ng-model="login.login" name="email" type="text" placeholder="Login" required /></p>
        <p><input ng-model="login.password" name="password" type="password" placeholder="Password" required /></p>
        <p><button type="submit">Login</button></p>
      </fieldset>
    </form>
  </div>

  <div ng-show="login.user">
    <p>Welcome, {{login.user.userName}}!</p>
    <p><button ng-click="login.disconnect()">Logout</button></p>
  </div>
</div>
What if the user enters a wrong username or password? The global errors handler (see above) will show an error message.
Note: this is out of topic, but if your server returns a 401 code, the web browser will display a "login dialog", asking the login/password of the user. You don't have any control over this dialog. The solution to prevent this is not to return 401 but another status code (418 I'm a Teapot is a good candidate). A clean way to do so is to add a header to tell the server, like this:
$http.defaults.headers.common['X-StatusOnLoginFail'] = '418';

TWO-WAY BINDING FOR HTML

If you want to write some HTML that you loaded using AJAX, you can use ng-bind-html-unsafe. But this is a one-directional binding. If the content of the element is modified (thanks to contenteditable for example), the content of the variable is not updated.
This module allows two-way HTML binding between a variable and an element.
angular
 .module('twoWayHTMLBinding', [])
 .directive('adminBindHtml', function($timeout) {
  return {
   link: function compile(scope, tElement, tAttrs) {
    var refresh = function() {
     scope.$apply(tAttrs.adminBindHtml + ' = "' + tElement.html().replace(/"/g, '\\"') + '"');
     $timeout(refresh, 200);
    };
    scope.$watch(tAttrs.adminBindHtml, function(val, oldVal) {
     if (val != oldVal && tElement.html() != val)
      tElement.html(scope.$eval(tAttrs.adminBindHtml));
    });
    $timeout(refresh, 200);
   }
  };
 });
Example:
<div ng-init="htmlData = '&lt;p&gt;Hello!&lt;/p&gt;'">
  <div admin-bind-html="htmlData" contenteditable="true"></div>
</div>
Note: this may seem obvious, but don't allow non-admins to modify HTML code that can be displayed to anyone, or if you do you must add a server-side filter.

Moving around - Vim Tips Wiki

Moving around - Vim Tips Wiki

AngularJS Fundamentals - Online Training Course for Developers

AngularJS Fundamentals - Online Training Course for Developers

Cross-browser, CSS-only modal box

Cross-browser, CSS-only modal box

Thursday, April 17, 2014

MySQL not starting up

130502 10:47:03 InnoDB: The InnoDB memory heap is disabled 
130502 10:47:03 InnoDB: Mutexes and rw_locks use GCC atomic builtins 
130502 10:47:03 InnoDB: Compressed tables use zlib 1.2.3 
130502 10:47:03 InnoDB: Initializing buffer pool, size = 128.0M 
130502 10:47:03 InnoDB: Completed initialization of buffer pool 
130502 10:47:03 InnoDB: highest supported file format is Barracuda. 
130502 10:47:03  InnoDB: Waiting for the background threads to start 
130502 10:47:04 InnoDB: 1.1.8 started; log sequence number 1438711997 
/Applications/AMPPS/mysql/bin/mysqld: File './mysql-bin.000108' not found (Errcode: 2) 
130502 10:47:04 [ERROR] Failed to open log (file './mysql-bin.000108', errno 2) 
130502 10:47:04 [ERROR] Could not open log file 
130502 10:47:04 [ERROR] Can't init tc log 
130502 10:47:04 [ERROR] Aborting 

130502 10:47:04  InnoDB: Starting shutdown... 
130502 10:47:05  InnoDB: Shutdown completed; log sequence number 1438711997 
130502 10:47:05 [Note] /Applications/AMPPS/mysql/bin/mysqld: Shutdown complete 







Solution:



delete /Applications/AMPPS/var/mysql-bin.index



or 



Delete all the files from /Applications/AMPPS/var/ like mysql-bin.*,  mysql-bin.index, ib*, etc and try starting the mysql server. DONT REMOVE ANY FOLDER. 

Tuesday, February 04, 2014

How to reset Admin password in Prestashop? | PrestaShop Documentation Blog By Invertus

How to reset Admin password in Prestashop? | PrestaShop Documentation Blog By Invertus



Reset Prestashop Admin PasswordIf you lost your Prestashop admin password you can reset it in many ways but sometimes it’s not so easy to accomplish it as it may seem.
Today I will explain main three methods how you can change your lost password – one is really easy and quick :) .

Introduction
Prestashop saves all passwords encrypted – not in plain text. So there is no possibility to view them in a database. This ensures better security. OK lets find out how it is possible to reset users passwords.

1. Reset your password by email
Prestashop allows to reset your password by email but this method may not work all the time. You can find more information about configuring Prestahop email settings here.
Ok go to your back office login page and click “Lost your password?” link:

Lost your password screen
Lost your password screen
Enter your user’s email and click Send:
Entery your user's email
Enter your user's email
If mail was sent successfully you should see this screen:
Password sent Successfully
Password sent Successfully
Now check your inbox. If you do not see email with new password, check your inboxspam area. If you still can’t find email with new password, then something went wrong. If you’ll try to resend password one more time you will get this error:
You can regenerate your password only each 360 minute(s)
You can regenerate your password only each 360 minute(s)
UPS – we can’t wait so long and the password was changed also so you can stop trying to remember it.
If your Prestashop email configuration is wrong and your server does not allow to usemail() function then you may get such error: “Error occurred when sending the e-mail.” You can read more about how Prestashop sends emails here.
OK there are other solutions if the first one does not help. Keep reading.

2. Reset  password with our “invertus_passwd_reseter.php“ script.
Notice: This script has new features and you can read about them here. The link did not change so you can download this script form the link provided in this post.
This method is the fastest one – you’ll need 2 minutes if you have FTP access.
I wrote simple script to reset user passwords as I need it constantly. It helps when it is urgent o reset password and access system. Usually I don’t have access to users email so I can’t reset password  by email. Sometimes even phpMyAdmin is not installed.
Download our PHP script from here: invertus_passwd_reseter.rar. It is tested with Prestashop 1.3 and 1.4 versions.
Extract this archive and you will find invertus_passwd_reseter.php file. If you want to check it then open it with some text or PHP editor. The code is commented and easy to read.
Upload invertus_passwd_reseter.php to your server where Prestashop is installed – to Prestashop root directory.
Now open this link www.yourshoplink.tld/invertus_passwd_reseter.php. You will see this page:
Select your user's email
Select your user's email
Select your user’s email and press Submit. And that’s it. Your new password will be:aaa333aaa
Updated: 2011-07-02
Now password resetter can backup old passwords (save in txt file emails and passwords) and recover them (upload txt file). It is very convenient because I can reset password, do my job and recover back the old customer password – customers do not have to change their passwords.
3. Reset  password with phpMyAdmin.
First off all you need to access your phpMyadmin if it is installed. You can ask your system administrator or install it manually. If you decided to install it by your self then read this post: “How to install phpMyAdmin?”
OK we need one more thing: _COOKIE_KEY_. This parameter is unique to every shop and is saved in config/settings.inc.php file. Find it and copy to some text file – you’ll need it.
When phpMyAdmin is ready and you have _COOKIE_KEY_ we can start resetting user password.
Login to your phpMyAdmin and find your database – it is located in the left side of phpMyAdmin:
Select your database
Select your database
Now find table ps_employee. Table prefix ps_ may be different. Select ps_employeetable and click on pencil icon in the line where your user’s email is entered:
Edit emplee - user.
Edit emplee - user.
You should see this form:
Enter new password
Enter new password
Enter _COOKIE_KEY_ and your new password in to the field passwd (column value).Your passwd string should look something like:
bV0C71uVJYZFTVwC4RP17CKbfrc5hmUd6AL4Rx42TcQRTB30wxOLKWdAmynewpassowrd
As you can see _COOKIE_KEY_ goes first and your password goes next.
Chose function MD5 (column Function).
Press Go.
That’s it. Now go to your back office login page and try to login with the new password. It worked for me with Prestashop 1.3 and 1.4 versins :) .
3. You still cannot access your back office?
Read this post.
If you have questions write them to donatas@invertus.lt.