Feeds:
Posts
Comments

Archive for the ‘Web Development’ Category

If you use KnockoutJS and want your input-fields to automatically grow and shrink with the input, use this custom handler.

Usage

<input 
  type="text" 
  data-bind="autosize: {
    maxWidth: 500, 
    minWidth: 100, 
    comfortZone: 15
}"/>

Code

Original code from javascript - Is there a jQuery autogrow plugin for text fields?

ko.bindingHandlers.autosize = {
   init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
        var o = $.extend({
           maxWidth: 1000,
           minWidth: 0,
           comfortZone: 70
       }, valueAccessor());
        var minWidth = o.minWidth || $(element).width(),
           val = '',
           input = $(element),
           testSubject = $('<tester/>').css({
               position: 'absolute',
               top: -9999,
               left: -9999,
               width: 'auto',
               fontSize: input.css('fontSize'),
               fontFamily: input.css('fontFamily'),
               fontWeight: input.css('fontWeight'),
               letterSpacing: input.css('letterSpacing'),
               whiteSpace: 'nowrap'
           }),
           check = function() {
                if (val === (val = input.val())) {
                   return;
               }
                // Enter new content into testSubject
               var escaped = val.replace(/&/g, '&amp;').replace(/\s/g, ' ').replace(/</g, '&lt;').replace(/>/g, '&gt;');
               testSubject.html(escaped);
                // Calculate new width + whether to change
               var testerWidth = testSubject.width(),
                   newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth,
                   currentWidth = input.width(),
                   isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth)
                       || (newWidth > minWidth && newWidth < o.maxWidth);
                // Animate width
               if (isValidWidthChange) {
                   input.width(newWidth);
               }
            };
        testSubject.insertAfter(element);
        ko.utils.registerEventHandler(element, 'keyup keydown blur update', check);
    }
    };

Read Full Post »

Soeben ist der dritte Artikel der DSL-Serie von Markus und mir bei der dotnetpro erschienen.

Bild 11

Abstract: Mehrspaltige Layouts für Webseiten sind komplex und stellen hohe Ansprüche an den Webprogrammierer. Warum nicht eine Sprache entwickeln, die solche Layouts vereinfacht? Mit Oslo M und dem ASP.NET MVC Framework lässt sich so eine Sprache realisieren.

Inhalt

Hauptsächlich dreht sich der Artikel um MGrammar, den Teil der Sprache Microsoft M (Teil von Microsoft Oslo) mit dem andere Sprachen definiert werden können. Zuerst wird die MGrammar (Arbeitstitel) anhand einer simplen “Hello, World”-Sprache erklärt.

Danach erstellen wir eine DSL zur Beschreibung mehrspaltiger Layouts und bringen diese mittels ASP.NET MVC und YAML ans laufen.

Das Beispiel im Artikel basiert auf der Oslo January CTP, der Quelltext für das Oslo May CTP kann aber bei mir angefragt werden.

Beispiel

Typisches dreispaltiges Portal-Layout.

Konkretes Layout - dreispalter

* Die Berechnung der Restbreite stimmt hier nicht. Richtig wäre:

Rest = (75%* Gesamtbreite) –400px

Dies mag aber von CSS-Framework zu CSS-Framework variieren.

DSL zur Beschreibung

Die Syntaxhervorhebung ergibt sich aus der Grammatik und ein wenig Konfiguration.

intellipad - Syntaxhervorhebung

Read Full Post »

One of my most-visited posts is the jQuery plugin “beautyOfCode” for the version 1.5 of Alex’ Syntax Highlighter. The main point of doing a wrapper was, that version 1.5 did require invalid html code.

In the new version of Syntax Highlighter this is fixed. But still, people ask for a new version of my code, too.

I finally released a new version with some more features:

  • Uses online hosting of styles, scripts and brushes. This means you only need to reference jQuery and beautyOfCode!
  • Supports the new features as smart-tab, html-script, themes, line-wrapping and much more
  • Still uses a code-tag inside a pre-tag as well as a more css-like configuration with classes instead of property syntaxes

Referencing  the plugin and configuring brushes

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
<script type="text/javascript" src="Scripts/jquery.beautyOfCode.js"></script>

<script type="text/javascript">
    $.beautyOfCode.init({
      brushes: ['Xml', 'JScript', 'CSharp', 'Plain', 'Php']
    }); 
</script>

Detection, default behaviour

By default, beautyOfCode will beautify all elements matching ‘pre.code:has(code[class])”:

<pre class="code">
  <code class="javasript">
    alert("Hello, World!");
  </code>
</pre>

Explicit

If auto detection is not desired, the plugin has to be initialized differently:

<script type="text/javascript">
    $.beautyOfCode.init({
      brushes: ['Xml', 'JScript'],
      ready: function() {
        $('#mycode').beautify('javascript');
      }
    }); 
</script>

This would then only beautify following code:

<pre id="mycode">
  <code>
    alert("Hello, World!");
  </code>
</pre>

Initialization Options

These are the default options, which can be overridden by $.jQuery.beautyOfCode.init:

settings: {
    // should the syntax highlighter and brushes
    // be loaded dynamically
    autoLoad: true,
    
    // the base url to alex' hosted sources
    // http://alexgorbatchev.com/wiki/SyntaxHighlighter:Hosting
    baseUrl: 'http://alexgorbatchev.com/pub/sh/2.0.320/',
    
    // the baseurl for the hosted scripts
    scripts: 'scripts/',
    
    // the baseurl for the hosted styles
    styles: 'styles/',
    
    // themes from http://alexgorbatchev.com/wiki/SyntaxHighlighter:Themes
    theme: 'Default',
    
    // the brushes that should be loaded - case sensitive!
    // http://alexgorbatchev.com/wiki/SyntaxHighlighter:Brushes
    brushes: ['Xml', 'JScript', 'CSharp', 'Plain'],
    
    // overrides for configurations and defaults
    // http://alexgorbatchev.com/wiki/SyntaxHighlighter:Configuration
    config: {},
    defaults: {},
    
    // function to be called, when all scripts are loaded
    ready: function() {
        jQuery.beautyOfCode.beautifyAll();
    }
}

Example with current version, Django-theme and no gutter

<script type="text/javascript">
    $.beautyOfCode.init({
        theme: 'Django',
        baseUrl: 'http://alexgorbatchev.com/pub/sh/current/'
        defaults: { gutter: false },
        brushes: ['Xml', 'JScript']
    }); 
</script>

Options

Find a reference for all options on SyntaxHighlighter Configuration.

The options can either be specified as defaults in init, on the beautify-call or as css classes.

Specify options in code:

$('#myCode').beautify('javascript', {'wrap-lines':true, 'first-line:2'});

Specify options in html:

In this case the gutter would not be shown and the lines 3 and 6 (5 and 8 in Listing) would be highlighted.

<pre class="code">
  <code class="javasript boc-no-gutter boc-highlight[3,6]">
    alert("Hello, World!");
    
    function x() {
        if (true)
            x();
    }    
  </code>
</pre>

Syntax for options in html:

  • The flags smart-tabs, ruler, gutter, toolbar, collapse, auto-links, wrap-lines and html-script mean true, then prefixed with boc-, and false, when prefixed with boc-no-.
  • class-name, first-line and tab-size are prefixed with boc- and followed by their values in square brackets. For example first-line[3] means, the gutter starts with a three.
  • highlight is also prefixed with a boc- and followed by a comma-separated list of line numbers in square brackets that are to be highlighted.

Sources

Find the plugin source code and a demo page on the bitbucked beautyOfCode project page. If you like the plugin, please also vote on the jQuey plugin site.

Feel free to submit issues and patches. The code is not very well tested, since I don’t use it in any production environment today.

Read Full Post »

I just wrote off some ping urls (some german services, too) from the book Website Boosting 2.0 by Mario Fisher. When posting with Windows Live Writer these can be configured for beeing pinged on publishing new blog posts. Several blog engines also have configuration options or plugins for auto-pinging available.

http://blo.gs
http://weblogs.com
http://blogsearch.google.com/ping
http://blogsearch.google.com/ping/RPC2
http://blogg.de/ping.php
http://rpc.technorati.com/rpc/ping
http://blogoole.com/ping/
http://api.feedster.com/ping
http://api.my.yahoo.com/RPC2
http://api.my.yahoo.com/rss/ping
http://bblog.com/ping.php
http://blogmatcher.com/u.php
http://bulkfeeds.net/rpc
http://coreblog.org/ping/
http://ping.feedburner.com
http://ping.syndic8.com/xmlrpc.php
http://ping.wordblog.de/
http://rpc.blogbuzzmachine.com/RPC2
http://rpc.blogrolling.com/pinger/
http://rpc.newsgator.com/
http://rpc.pingomatic.com/
http://rpc.weblogs.com/RPC2
http://www.bloglines.com/ping
http://www.pingomatic.com/
http://xmlrpc.blogg.de

Read Full Post »

UPDATE: Support for Syntax Highlighter 2.0 + jQuery Listed + bitbucket Repository

The Syntaxhighlighter by Alex Gorbatchev is the best I have seen so far. As you see in this post, wordpress.com uses it, too.

But the required syntax is not xhtml-compliant (name on pre is forbidden).

<pre name="code" class="javascript">
  // my code
</pre>

In order to enable compliant xhtml I had to rewrite a small part anyway, so I just made a small jQuery-Plugin that just uses Alex's scripts right away (thanks Alex!).

Beautify explicitely

<pre id="myCode">
  <code>
     // my code
  </code>
</pre>

Using beautyOfCode you don't have to decorate your html in order to enable syntax highlighting. Just call beautifyCode on any selected pre or textarea

$(function(){
    $.beautyOfCode.init('clipboard.swf');
    $("#myCode").beautifyCode('javascript');
});

Beautify all

If you prefer to decorate your html and then just let the highlighter take care of the rest, you may use following notation.

<pre class="code">
  <code class="javascript">
     // my code
  </code>
</pre>

<pre class="code">
  <code class="css boc-nocontrols">
    body {
      font-size: 2em;
    }
  </code>
</pre>

Make sure you have these few lines

$(function(){
    $.beautyOfCode.init('clipboard.swf');
    $.beautyOfCode.beautifyAll();
});

Settings

Default Settings

{
   noGutter: false, // hide line numbers?
   addControls: true, // copy, view plain, ...
   collapse: false, // show controls with expand link
   showColumns: false, // show column numbers
   firstLine: 1 // start with another line number?
}

Change Settings with Javascript

$(function(){
  $.beautyOfCode.init('clipboard.swf', {
    // add global settings here
    firstLine: 4,
    collapse: true
  });

  // change options per listing
  $("#myCode").beautifyCode('javascript', {
    noGutter: true
  });
});

Change Settings in Element-Decoration

Settings with in the html are added as additional classes on the code-element.

<pre class="code">
  <!-- You dont have to specify default values. -->
  <code class="javascript boc-firstline[3]
    boc-nocontrols
    boc-nogutter
    boc-showcolumns
    boc-collapse">
     // my code
  </code>
</pre>

kick it on DotNetKicks.com

Source Code

Notice: beautyOfCode is using Syntaxhighlighter. You need to link in SyntaxHighlighter.css, shCore.js and the brushes you want to use.

jQuery.beautyOfCode = {
  initialized: false,

  settings: {

    // hide line numbers?
    noGutter: false,

    // show copy, plain, ... links
    addControls: true,

    // collapse to control bar. cant be used
    // with addControls set to false
    collapse: false,

    // show column numbers
    showColumns: false,

    // start with another line number?
    firstLine: 1
  },

  brushByAlias: {},

  init: function (clipboardSwf, settings) {
    dp.SyntaxHighlighter.ClipboardSwf = clipboardSwf;

    if (settings)
      jQuery.extend(jQuery.beautyOfCode.settings, settings);

    if (jQuery.beautyOfCode.isInitialized)
      return;

    // creates a map of each registered brush by alias
    jQuery.each(dp.sh.Brushes, function (i, brush) {
      var aliases = brush.Aliases;

      if(aliases == null)
       return;

      jQuery.each(aliases, function (ii, alias) {
        jQuery.beautyOfCode.brushByAlias[alias] = brush;
      });
    });

    jQuery.beautyOfCode.isInitialized = true;
  },

  addCssForBrush: function (brush, highlighter) {
    if (brush.isCssInitialized)
      return;

    var headNode = $("head")[0];
    if(highlighter.Style && headNode)
    {
      var styleNode = document.createElement('style');
      styleNode.setAttribute('type', 'text/css');

      if(styleNode.styleSheet) // for IE
        styleNode.styleSheet.cssText = highlighter.Style;
      else // for everyone else
        $(styleNode).text(highlighter.Style);

      headNode.appendChild(styleNode);
    }

    brush.isCssInitialized = true;
  },

  beautifyAll: function() {
    jQuery("pre.code:has(code[class])").each(function (i, item) {

      function getOptionValue(name, list)
      {
        var regex = new RegExp('^' + name + '\\[(\\w+)\\]$', 'gi');
        var matches = null;

        for(var i = 0; i < list.length; i++)
         if((matches = regex.exec(list[i])) != null)
          return matches[1];

        return null;
      }

      var $item = jQuery(item);
      var $code = $item.children("code");
      var code = $code[0];

      var options = code.className.split(" ");
      var language = options[0];

      var settings = {};

      if ($code.hasClass("boc-nogutter"))
        settings.noGutter = true;

      if ($code.hasClass("boc-nocontrols"))
        settings.addControls = false;

      if ($code.hasClass("boc-showcolumns"))
        settings.showColumns = true;

      if ($code.hasClass("boc-collapse"))
        settings.collapse = true;        

      var firstLine = getOptionValue("boc-firstline", options, 1);
      if (firstLine)
        settings.firstLine = firstLine;

      $item.beautifyCode(language, settings);
    });
  }
};

jQuery.fn.beautifyCode = function (language, settings) {

  var saveLanguage = language;
  var saveSettings = settings;

  // iterate all elements
  this.each( function (i, item) {
    var $item = jQuery(item);

    var settings = jQuery.extend({}, jQuery.beautyOfCode.settings, saveSettings);

    var brush = jQuery.beautyOfCode.brushByAlias[saveLanguage];

    if (!brush)
      return;

    // instantiate brush
    highlighter = new brush();

    // set brush options
    jQuery.extend(highlighter, settings);

    jQuery.beautyOfCode.addCssForBrush(brush, highlighter);

    // IE Bug?: code in pre has to be skipped
    // in order to preserver line breaks.
    if ($item.is("pre") && ($code = $item.children("code")))
      $item.text($code.text());

    highlighter.Highlight($item.html());
    highlighter.source = item;

    $item.replaceWith(highlighter.div);
  });
}

Read Full Post »

Das Problem

Das ASP.NET Session Cookie funktioniert nicht mehr wie es soll. Befindet man in einer Webapplikation und ist angemeldet, oder hält irgendeinen anderen Status in der ASP.NET Session, teilt sich diese Information auch mit neu geöffneten Browsern oder Fenstern. Es ist also beispielsweise nicht möglich, sich mit einem anderen Benutzer in einer zweiten Browserinstanz an derselben Applikation anzumelden.

Der Übeltäter

Nach langer Suche haben wir festgestellt, dass der Cookie-Manager im EfA-Fontsize Skript buggy ist. Das eingebundene Cookie-Skript geht alle Cookies (vorher in this.cookies abgelegt) durch und schreibt sie neu.

for(var name in this.cookies) {
  expires = (this.expiration[name])?this.expiration[name]:this.defaultExpiration;
  path = this.defaultPath;
  domain = this.defaultDomain;
  if(name) {
    var cookies = name + '=' + this.cookies[name] + '; expires=' + expires + '; path=' + path + '; domain=' + domain;
    if(cookies != '') {
      document.cookie = cookies;
     }
   }
}

Dabei wird die expires auf Heute+7 Tage gesetzt. Der Wert wird zwar über this.expiration[name] vermeintlich "wiederhergestellt", er wurde aber nie abgelegt. Dadurch werden temporäre Cookies zu permanenten. Auch path und domain für alle Cookies auf den gleichen Wert zu setzen ist ein kleines Verbrechen.

Cookiemanager.prototype.getExpiration = function() {
  var date = new Date();
  date.setTime(date.getTime()+(7*24*60*60*1000));
  return date.toGMTString();
}

 

Die Lösung

Das Skript für die EfA-Fontsize-Switcher scheint nicht mehr verfügbar zu sein: http://www.einfach-fuer-alle.de/artikel/fontsize/

Also habe ich mir auch nicht die Mühe gemacht, dass Skript zu patchen, sondern den Cookiemanager durch ein jQuery Plugin ersetzt.

  1. Plugin herunterladen und einbinden: Plugins | jQuery Plugins | Cookie
  2. Die Datei efa_fontsize.js anpassen

  3. Efa_Fontsize06.prototype.getCookie = function() {
      var cookie = $.cookie(this.cookieName);
      return (cookie)?cookie:false;
    }
    Efa_Fontsize06.prototype.setCookie = function(cookieValue) {
      return $.cookie(this.cookieName, cookieValue, { expires: 7, path: '/' });
    }
    
  4. Alle anderen Referenzen auf cookies.js aktualisieren oder entfernen und die Skript-Datei löschen.

Read Full Post »

Follow

Get every new post delivered to your Inbox.

Join 433 other followers