Friday 31 October 2014

Slide animation of ajax loaded divs with jQuery

Since I'm a real newbie in terms of web development this will most probably be really helpful mostly to me sometime in the future when I've forgotten all this.

I'm building a simple single-page website which requires some sliding animation, but the divs which are getting animated are actually separate .html files loaded with ajax through jQuery. There's a lot of information on loading pages through jQuery or animating html elements. Not so much on using both at the same time. And for a beginner it posed certain problem.

First the links which trigger the animation:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<nav id="menu">
    <ul>
        <li>
            <div style="background-color: rgba(175, 120, 75, 0.5)">
                <a href="#" id="mainpage">Main page</a>
            </div>
        </li>
        <li>
            <div style="background-color: rgba(120, 90, 175, 0.5)">
                <a href="#" id="page2">Second page</a>
            </div>
        </li>
        <li>
            <div style="background-color: rgba(75, 175, 90, 0.5)">
                <a href="#" id="page3">Third page</a>
            </div>
        </li>
    </ul>
</nav>

Here's the html for sliding-animated divs:

1
2
3
4
5
6
<div id="slideWrapper">
    <div id="slider1">
    </div>
    <div id="slider2">
    </div>
</div>

Here's the CSS:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#slideWrapper {
    width: 100%;
    height: 300px;
    float: left;
    position: relative; 
}

div#slideWrapper > div {
    margin: 0 5px 0 0;
    border: 1px solid black;
    width: 100%;
    height: 300px;
    float: left;
    position: absolute;
    overflow: hidden;
}

And here's the javascript:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
var _showedSubPage = "";

$(document).ready(function () {

    // Configure on click events, 
    // first argument: id of the button I'm clicking on, second: url
    loadPageOnClick("mainpage", "subpages/page1.html");
    loadPageOnClick("page2", "subpages/page2.html");
    loadPageOnClick("page3", "subpages/page3.html");
    
    // Initial load of the page
    $("#slider1").load("subpages/page1.html");
    $("#slider1").addClass("slidedIn");
    $("#slider2").addClass("slidedOut");

    _showedSubPage = "mainpage";
});

loadPageOnClick = function (sourceId, url) {
    jQuery(document).ready(function () {
        jQuery("#" + sourceId).click(function () {
            
            var divToSlideIn = $("#slideWrapper").find(".slidedOut");
            var divToSlideOut = $(divToSlideIn).siblings(".slidedIn");

            // don't animate if the click is on the same button
            if (_showedSubPage != sourceId
                && !$(divToSlideOut).hasClass("animating")
                && !$(divToSlideIn).hasClass("animating")) {
                _showedSubPage = sourceId;
                
                $(divToSlideOut).addClass("animating");
                $(divToSlideIn).addClass("animating");

                // change classes on slider divs
                $(divToSlideOut).removeClass("slidedIn").addClass("slidedOut");
                $(divToSlideIn).removeClass("slidedOut").addClass("slidedIn");

                // load webpage through ajax
                $(divToSlideIn).load(url);

                $(divToSlideOut).animate({
                    right: $(divToSlideOut).width()
                }, 600, null, function() {
                    $(divToSlideOut).hide();
                    $(divToSlideOut).empty();
                    $(divToSlideOut).insertBefore($(divToSlideIn));
                    $(divToSlideOut).removeClass("animating");
                });

                $(divToSlideIn).show().css({
                    right: -($(divToSlideIn).width())
                }).animate({
                    right: 0
                }, 600, null, function() {
                    $(divToSlideIn).removeClass("animating");
                });
            }
        });
    });
};

To summarize, what I do is I juggle with 2 divs. One is being shown, the other is hidden. On click on one of the links I load the hidden div with the html from the appropriate webpages. Then I animate and slide in the div with the newly loaded html and display it while sliding out and hiding the previous one. This cycle is being done every time any link is clicked.

UPDATE:
I've noticed that the comparing with the current button wasn't working so I fixed it, also added blocking of the animation while it's running and hooked up the complete callback properly.

Tuesday 21 October 2014

Developer Days 2014, Wrocław, Poland

I haven't been going to many IT events recently, so Developer Days in Wrocław, was a nice refreshment. I'll note down all the interesting buzzword I've heard and a small wrap-up of some of the lectures I've attended.

1. Keynote: The present and future of .NET by Tomasz Kopacz

Every lecture by Tomasz is a pleasure to listen to, and choosing him to lead with the first morning lecture was a wise thing to do. His energetic speech worked better than coffee and was full of interesting tid bits from the .NET world. He maintained this throughout all his lectures.

2. Use all of Visual Studio and be a better developer by Kate Gregory

This lecture was a bit of a let down, especially for any developer who uses resharper extensively. The target audience was around junior .NET dev level. It was nice to listen to Kate however because she's a very good lecturer and previously I really enjoyed listening to her in several .NET rocks podcasts she attended.

3. Architecting an ASP.NET MVC solution by Andrea Saltarello

Because I'm a complete newbie in terms of web development I was expecting some in-depth MVC knowledge as a requirement for this session. To my surprise  the session focused on several js libraries/frameworks and SEO, which I was happy to find because of my meager knowledge on the subject.

Some keywords:

- schema ( schema.org ): by adorning html elements we're able to tell webcrawlers what type of data each element displays
- sitemaps ( sitemaps.org ): adds information about different sub pages of the website available for the webcrawlers
- google dev tools: has a free possibility of testing how "crawlable" is any given website
- bootstrap ( bootstrap.org  ): allows for building a website which easily changes layout to fit available screen space
- template engine chooser on github: http://garann.github.io/template-chooser/

I'll probably add some additional pieces of information once I read up on them more

Sunday 29 June 2014

Display directories over 1 GB in Windows

      I had to do a bit of a hard drive clean up cause of the hard drive space growing short. My first choice was to do it with some nice command line app. I knew similar functionality is brought by the sysinternals component, disk usage app, it did not quite make the cut though.

In search of a more robust way I found the following solution on stackoverflow, it uses disk usage and windows power shell to print a simple list of all folders above 1GB in size 3 levels down the directory tree:

.\du.exe -c -l 3 C:\ | ConvertFrom-Csv -Header Size,Path | Where-Object { [int]$_.Size -gt 1048576 } | Sort-Object { [int]$_.Size } -descending

( source: http://superuser.com/questions/420973/using-du-exe-sysinternals-is-it-possible-to-show-folders-above-a-certain-size )

       After a little bit of tinkering I've noticed that this exact syntax does not work for me for some reason. It turns out that the newest version of du.exe adds it's own headers on top of the listing it produces. Because of it the script tries to parse these headers as data which ends in parsing errors.
Hence we would need to tell the windows powershell to select the column headers that are already there.

PS D:\Tools\DU> D:\Tools\DU\du.exe -c -l 3 C:\ | ConvertFrom-Csv | select Path,DirectorySize | Where-Object { [int]$_.DirectorySize -gt 1048576 }

This shorter version omits the sorting which can be easily added.

Here's where you can download disk usage app:
http://technet.microsoft.com/en-us/sysinternals/bb896651.aspx

Sunday 8 June 2014

Mundial 2014 TV Guide

An app I was working on with my friend, Igor Redchuk ( http://igorredchuk.blogspot.com/ ) got released. It's an upcoming World Cup 2014 football tournament TV notification guide. So, if you're interested in getting information about channels and being notified about the games you can try it here, the first week's for free:
  
                                                                      

Monday 26 May 2014

Batch operations on images

Recently I've found myself in need of doing some batch operations to a couple of icons. I've noticed as well I need to do something like this every now and then. Frequently enough to have a set of tools for that.

Previously I've used GIMP with a Batch Process plugin (free with UI integrated into GIMP: http://registry.gimp.org/node/20893). Unfortunately the plugin doesn't have the functionality I needed last time.

This is where I found ImageMagick:
http://www.imagemagick.org/

It's a pretty cool app. With several batch commands I can do batch operations on the icons:

    Change transparent background of all .png images in the app's folder to snow2 colour ( bright grey )
    mogrify -path D:\new -background snow2 -flatten -format "_snow2.png" *.png

    Change transparent background of all .png images in the app's folder to white colour
    mogrify -path D:\new -flatten -format "_white.png" *.png

    Resize all images to the resolution 76 x 76.
    mogrify -path D:\new -sharpen 0x1.2 -quality 95 -resize 76x76 -format "_r76.png" *.png

All of the commands above copy the result to D:\new folder. They add appropriate endings to output file names ( for instance _r76.png ).


Tuesday 11 February 2014

Inno Setup, installing MySQL server and .net 4.0

    I needed to create a package which I could install on a machine with at least Windows XP SP3 on board. Because I only have free Visual Studio 2012 Express, the simplest option was to use something that works out of the box and is easy to use. That's how I found Inno Setup, a nice app for creating setup packages.

And because it was not that easy to use from the get go I'll do a short summary of what I did to make it run on my bare Windows XP running inside of a VirtualBox.

Most of the options are described well enough in the documentation and samples. Hence I'll focus on two sections that are being used in the setup script used by Inno Setup.

[Files]
Source: "C:\SetupFiles\mysql-installer-community-5.6.16.0.msi"; DestDir: "{tmp}";
Source: "C:\SetupFiles\database.sql"; DestDir: "{tmp}";
Source: "C:\SetupFiles\loadDB.bat"; DestDir: "{tmp}";
Source: "C:\SetupFiles\dotNetFx40_Full_x86_x64.exe"; DestDir: "{tmp}";

Now, every DestDir is set to {tmp}, because the temp directory is being removed after the installation, and we won't need these files later.

Next is the [Run] section that describes how the above are gonna be installed. I'll add break lines in the listing below for the clarity, but in Inno Setup everything has to be in one line.

[Run]   

; Installing .net in quiet, unattended mode. 
Filename: "{tmp}\dotNetFx40_Full_x86_x64.exe";
Parameters: "/q"; WorkingDir:{tmp};
Flags: runhidden;
StatusMsg: Installing .Net Framework

; Installing MySQL installation package, which by default goes to C:\Program Files\MySQL\
; /qn also makes msiexec go quiet and unattended.
Filename: msiexec.exe; Parameters: " /i""{tmp}\mysql-installer-community-5.6.16.0.msi"" /qn";
StatusMsg: Unpacking Mysql 5.6.16.0 installation;
Flags: runhidden

; Using the MySQLInstallerConsole.exe to install the MySQL server. We need to set the type of installation
; ( -t ) to Custom to make it install only the server ( and omit for example Workbench ). We need to set the
; initial root password ( below set to root ). Lack of --nowait makes the console wait for user input.
Filename: "C:\Program Files\MySQL\MySQL Installer\MySQLInstallerConsole.exe";
Parameters: " --action=install -t=Custom --config=mysql-server-5.6-win32:passwd=root --product=mysql-server-5.6-win32 --catalog=mysql-5.6-win32 --nowait";
StatusMsg: Installing MySQL Server;
Flags: runhidden
                       
; Quite self explanatory, we just add mysql service to services currently running on the pc
Filename: "C:\Program Files\MySQL\MySQL Server 5.6\bin\mysqld.exe"; Parameters:" --install";
WorkingDir: {app};
StatusMsg: Installing MySQL Service;
Flags: runhidden

; Starting the service
Filename: net.exe;
Parameters: start mysql;
StatusMsg: Starting MySQL Server;
Flags: runhidden

; Loading the database inside of a batch file, for some reason InnoDb has problems running queries using       ; mysql
Filename: "{tmp}\LoadDB.bat";
StatusMsg: Loading database;
Flags: runhidden  

        In case you're reinstalling using the setup, it might get more tricky because you must either remove the C:\Documents And Settings\All Users\Application Data\MySQL (in case of Windows XP) directory or pass the existing password to the MySQLInstallerConsole.exe config parameter.

          --action=install -t=Custom --config=mysql-server-5.6-win32:passwd=root;existingpasswd=root
          --product=mysql-server-5.6-win32 --catalog=mysql-5.6-win32

Both are pretty bad, and there's a bit of fiddling required to make them work on all systems, and under different circumstances.

Links:





Saturday 18 January 2014

Deploying local Nodejs git repo to Heroku, what to remember about?

A short summary on deploying local code using git to heroku, which requires a fair bit of googling  every time I'm attempting it. All we need to do after we've got our code working locally with all the packages we required installed.
  1. heroku create appname - creates a heroku app with a given name ( if not explicitly stated it's gonna get randomized )
  2. git remote -v - will show us whether the remote was successfully created for our local repo.
  3. create a procfile, which describes what types of processes are gonna be launched on Heroku in my case (a web server) the inside of the files were as follows:

    web: node name_of_the_node_server_file.js

  4. Create a package.json file which contains information about the app, especially the packages info, and launching script. In my case it looked like that:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    {
      "name": "AppName",
      "version": "0.0.1",  
      "description": "Description",
      "main": "name_of_the_server_file.js",
      "dependencies": {
     "connect": "x.x.x",
     "util": "x.x.x"
      },
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "start": "node name_of_the_server_file.js"
      },
      "repository": {
        "type": "git",
        "url": "https://bitbucket_login@bitbucket.org/bitbucket_login/repo_name.git"
      },
      "author": "Name"
    }
    


  5. We need to add these files and use a standard git commit
  6. git push heroku master - where heroku is a remote created by "heroku create".
  7. Now we can open our app on heroku.
  8. In case of errors we can check the logs from the server through command line:

    heroku logs 
Helpful links:

         Deploying to Heroku with git - https://devcenter.heroku.com/articles/git
         Heroku logs - https://devcenter.heroku.com/articles/logging
         Procfile types - https://devcenter.heroku.com/articles/procfile


Friday 10 January 2014

Hooking up a new git repository to bitbucket

I always forget one of the steps and end up googling. That's why I'll leave this little list here to have a safety net next time I'm connecting my local repo to bitbucket.
  1. Created repository folder with a file inside inside. Something like:  /Repositories/NewRepo/helloworld.txt

  2. Open console inside of the NewRepo folder. It initiates a new git repository in the NewRepo folder:       git init

  3. We're adding the file (proposing the changes) by using:
        git add helloworld.txt
                                or
        git add *

  4. To commit the changes we use:
        git commit -m "Adding helloworld.txt"

  5. We create a repository in https://bitbucket.org/ by clicking "Create Repository" button and just filling out the form. We end up having bitbucket repository called: BitbucketLogin/reponame. Lets say our reponame is also NewRepo.

    We need to add a remote to the bitbucket repository:
    git remote add origin       https:/BitbucketLogin@bitbucket.org/BitbucketLogin/oureponame.git

    In case we're trying to commit to someone else's repo, we should use:
    git remote add origin https:/OurLogin@bitbucket.org/SomeonesLogin/soomeoneseponame.git

  6. If we made a typo in the above, we can remove the remote and add it again:
    git remote rm origin

  7. All that is left is to push the changes to bitbucket:
    git push origin master

Sunday 5 January 2014

Adding Drag and drop behaviour to ItemsControls Part 3

        Third part of the drag and drop tutorial in WPF. I'll start with the mouse move event and checking whether anything is being dragged.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
private static void OnMouseMove(object sender, MouseEventArgs e)
{
    ItemsControl source = (ItemsControl)sender;

    System.Windows.Point currentPos = e.GetPosition(null);
    Vector diff = startPoint - currentPos;

    if (e.LeftButton == MouseButtonState.Pressed &&
       ( Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
         Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
    {                
        object data = GetDataFromSource(source, e.GetPosition(source));

        if (data != null)
        {
            DragDrop.DoDragDrop(source as DependencyObject, data, DragDropEffects.Move);
        }                
    }
}

         Above handler uses GetDataFromSource method for retrieving the dragged data from the source control. The method finds the UIElement that has been clicked, checks in the loop, if the item is indeed in the ItemsControl collection and generates adequate dto that is gonna be transferred between collections. In case the SourceControl is reached in the loop it means that the particular item has not been found.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
private static object GetDataFromSource(ItemsControl source, System.Windows.Point point)
{
    UIElement element = source.InputHitTest(point) as UIElement;

    if (element != null)
    {   
        object data = DependencyProperty.UnsetValue;
        while (data == DependencyProperty.UnsetValue)
        {
            element = VisualTreeHelper.GetParent(element) as UIElement;
            if (element == source)                    
                return null;
            
            data = source.ItemContainerGenerator.ItemFromContainer(element);            
        }

        if (data != DependencyProperty.UnsetValue)                
            return data;                
    }
    return null;
}

        Then comes the method for handling drop events, we need to take notice of several special cases, most are commented the rest self explanatory.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
private static void Drop(object sender, DragEventArgs e)
{
    ItemsControl parent = (ItemsControl)sender;

    // Checking if there's a group that has control assigned to it
    if (!dragSources[GetGroupName(parent as DependencyObject)].Any(p => p == parent))
        return;
    
    // Get the type of data that's used for the object transfered between containers
    var dataType = parent.ItemsSource.GetType().GetGenericArguments().Single(); 
    // Aquiring data of the particular type
    var data = e.Data.GetData(dataType);                                        

    // This will hit when we'll try to drop garbage into the container
    if (data == null)   
        return;

    // We don't wanna drop the same data to the same control again
    if (((IList)parent.ItemsSource).Contains(data)) 
        return;

    var foundControl = dragSources[GetGroupName(parent as DependencyObject)]
        .Find(p => ((IList)p.ItemsSource).Contains(data));

    if (foundControl == null)
        return;

    ((IList)foundControl.ItemsSource).Remove(data);
    ((IList)parent.ItemsSource).Add(data);
    BindingOperations.GetBindingExpressionBase(parent as DependencyObject, 
        ItemsControl.ItemsSourceProperty).UpdateTarget();
    BindingOperations.GetBindingExpressionBase(foundControl as DependencyObject,
        ItemsControl.ItemsSourceProperty).UpdateTarget();
}

        Last thing left is to add the code for several more handlers we've already used in the previous post. Except for the OnLeftButtonDown, they are all used to prepare the container as a drag and drop container after it becomes visible to the user and remove it from the drag and drop mechanism when it is being hidden from the user. Hence every time the window with such container is being brought forth all adorned ItemsControls are being added to the behaviour and removed when for instance the window containing them hides.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private static void OnLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    startPoint = e.GetPosition(null);
}

private static void DragSource_Loaded(object sender, RoutedEventArgs e)
{
    Add(dragSources, sender);
}

private static void DragSource_Unloaded(object sender, RoutedEventArgs e)
{
    Remove(dragSources, sender);
}

private static void DropTarget_Loaded(object sender, RoutedEventArgs e)
{
    Add(dropTargets, sender);
}

private static void DropTarget_Unloaded(object sender, RoutedEventArgs e)
{
    Remove(dropTargets, sender);
}

       The last handler is the one servicing the drag and drop group name changes, in case the group name is bound to something that changes it during run time. If that happens we need to switch the ItemsControl drag and drop container to a different group.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
private static void GroupNameUpdated(DependencyObject dp, DependencyPropertyChangedEventArgs args)
{
    var itemsControl = dp as ItemsControl;
    string newGroupName = (string)args.NewValue;

    InitializeDragDropCollections();

    if (!dragSources.Any(p => p.Key == newGroupName))
        dragSources.Add((String)args.NewValue, new List<ItemsControl>());
    if (!dropTargets.Any(p => p.Key == newGroupName))
        dropTargets.Add((String)args.NewValue, new List<ItemsControl>());

    var foundCollection = dragSources.Where(p => p.Value.Any(k => k == itemsControl) == true);
    if (foundCollection != null && foundCollection.Count() > 0)
    {
        foundCollection.First().Value.Remove(itemsControl);
        if (!dragSources[((String)args.NewValue)].Any(p => p == itemsControl))
            dragSources[((String)args.NewValue)].Add(itemsControl);
    }            
}

       If you'd like to get the whole code I added the class to my github account:
       http://github.com/simonkatanski/WpfDragAndDropBehavior.git