Technik, Gothic und Anderes

Technik ist Spiel, Gothic ist ernst und Zeit hat man zuviel

Archiv für 'Theorie und Schnipsel' Kategorie


Ein Ajax Baum der sich sein Zustand merkt

Geschrieben von skaldrom am 25. November 2006

Man gönnt sich ja sonst nichts… Ich wollte für eine mit dem Symfony Framework erstellte Webanwendung eine Baumansicht. Da leichtes implemenieren langweilig ist, musste es schon ein Ajaxbaum mit Kontextmenü und allem Schnickschnack sein. Nach längerem Suchen fiel die Wahl auf Dojo, einem Toolkit mit vielen Widgets und sonstigen Spassmachern. Der Baum besitz viele Nodes, darum sollten diese dynamisch nachgeladen werden (ok, etwas Masochismus war auch dabei). Die Anwendung besteht eigentlich aus herkömmlichen Seitenwechseln, und so musste der Baum auch seinen Zustand halten können. Nundenn, nach laaaaaanger Probierephase (die Dokumentation ist nicht gerade erschlagend) und der Hilfe vom Web wurde es dennoch Realität *freu*.

Hilfreiche Websites:

Tipps generell:

  • var djConfig = {isDebug: true }; aktiviert die Debugeingaben, dojo.debug(’Blah’); kann für Debugausgaben benutzt werden.
  • saveExpandedIndices und restoreExpandedIndices sind methoden des erweiterten tree-Controllers! Er muss also require’d und gemixint werden (siehe unten)
  • Der Baumzustand wird in einem Cookie gespeichert, damit hat man in der Applikation nichts mehr damit zu tun.

Wie das Ganze in Symfony integriert wurde kann gerne nachgefragt werden.

Nundenn, gimme Code:

<script type="text/javascript" src="/js/dojo.js"></script>
<script type="text/javascript">
var djConfig = {isDebug: true }; // Comment if debugguing
dojo.require("dojo.widget.Tree");
dojo.require("dojo.widget.TreeSelector");
dojo.require("dojo.widget.TreeNode");
dojo.require("dojo.widget.TreeContextMenu");
dojo.require("dojo.widget.TreeLoadingController");
dojo.require("dojo.widget.TreeControllerExtension");
// Do something if a node is clicked
function modulTreeSelectFired() {
    var treeSelector = dojo.widget.manager.getWidgetById('modulTreeSelector');
    var treeNode = treeSelector.selectedNode;

    < !– get a reference to the songDisplay div –>
    //var hostDiv = document.getElementById("songDisplay");

    var isFolder = treeNode['isFolder'];
    if ( !isFolder) {
       //var song = treeNode['title']
       //hostDiv.innerHTML = "You clicked on "+song;
    } else {
       //hostDiv.innerHTHML = "";
    }
    //hostDiv.style.display = "";
}

// Set up Dojo and the tree
function init() {
    var treeSelector = dojo.widget.manager.getWidgetById('modulTreeSelector');
    dojo.event.connect(treeSelector,'select','modulTreeSelectFired');

    var modulTree = dojo.widget.manager.getWidgetById('modulTree');
    dojo.event.topic.subscribe(modulTree.eventNames.collapse, "saveExpandedIndices");
    dojo.event.topic.subscribe(modulTree.eventNames.expand, "saveExpandedIndices");

    // add extensions to controller
    dojo.lang.mixin(dojo.widget.byId('modulTreeController'), dojo.widget.TreeControllerExtension.prototype);

    // Restore old state
    restoreExpandedIndices();
 }

// Save the tree state
function saveExpandedIndices() {
        // You can save this object as tree persistent state
        indices = dojo.widget.byId('modulTreeController').saveExpandedIndices(
            dojo.widget.byId('modulTree')
        );
        var flatIndices = dojo.json.serialize(indices);
        //dojo.debug(flatIndices);
        dojo.io.cookie.setCookie('modulTree/saveindices',flatIndices, 365, null, null, null);
    }

// Restore the tree state
function restoreExpandedIndices() {
        flatIndices = dojo.io.cookie.getCookie('modulTree/saveindices');
        indices = dojo.json.evalJson(flatIndices);
        //dojo.debug(flatIndices)
        if(indices) {
            dojo.widget.byId('modulTreeController').restoreExpandedIndices(dojo.widget.byId('modulTree'), indices
            );
        }
    }

// Initialize
dojo.addOnLoad(init);</script>

Der HTML-Code sollte eigentlich klar sein: Controller, Kontextmenü und Tree aufbauen (nur die erste Hierarchiestufe) und der PHP-Teil ist nach Vorgabe. Sind mehr Details gewünscht, liefere ich diese gerne nach.

Stichworte: persistent tree state, remembering tree state

Ergänzung, Juli 2008: Oky, Ihr habt recht: Gimme Code! Schwatzen kann jeder!

Hier mal den Quellcode (eher das Gerüst, bzw proof-of-concept :) ) des Moduls und den Inhalt des web/js Verzeichnisses. Hilft das was? Braucht es mehr, damit es sinnvoll ist?

Geschrieben wurde es mit Symfony 1.0 und Dojo 0.4 Rev: 6258.

In der Zwischenzeit bin ich aber von dem Dojo-Ajax Zeux wieder etwas weggekommen. Ich progge für Intra- und Extranetapplikationen, und da sind zu viele Browser mit zu vielen Konfigurationen im Einsatz. Für “öffentliche” Websites ist es sicher schön, auch wenn es (wie bei Symfony üblich) nicht voll Ajax ist, sondern halt nur Komponentenweise, was ich nicht als schön empfinde…

Ich bin zurück zum guten alten PHP-Layersmenü (Beitrag dazu folgt noch). Das fallbackt sehr schön ohne Java Script.

Teile und geniesse:
  • Technorati
  • del.icio.us
  • MisterWong
  • Digg
  • StumbleUpon
  • blogmarks
  • Furl
  • Simpy
  • Spurl
  • YahooMyWeb

Eingeordnet in Theorie und Schnipsel, Webapplikationen | 6 Komentare »

Unicode-Hölle: PHP, Apache, Mysql und Symfony in UTF-8

Geschrieben von skaldrom am 20. November 2006

Ich will mein altes ASCII wieder!!! Unicode ist die Hölle. Vielleicht helfen folgende Dinge dem, der damit rumkämpfen will/muss:

  • Im ganzen Pfad muss die Codierung stimmen bzw. gezielt umgewandelt werden. In unserem Beispiel also Dateisystem, Datenbank, (PHP), Applikation und Browser.
  • Glaube nicht was Du siehst! Was angezeigt wird ist wieder aus einer Applikation die irgendwie encodiert.
  • Firefox: View -> Character Encoding ist Dein Freund. Damit sieht man, was der Browser denkt er erhalte und das Umschalten auf 8859-1 kann zeigen, dass man es noch nicht geschafft hat und immernoch das alte Encoding verwendet wird.
  • utf8_encode() und utf8_decode() sind böse! Wenn man die braucht stimmt etwas nicht.

Hier ein paar Hilfen und Tools.

Dateisystem:

locale -a zeigt die Codierungen. Auf Debian kann man mittels dpkg-reconfigure locales einiges umstellen. Hier mal Unicode zu haben schadet nicht.

Konvertierung mit recode:

Folgendes Kommando wandelt eine Datei in ISO88591 in Unicode um:

recode ISO-8859-1..UTF-8 DATEI

Mysql:
Um Daten in UTF-8 abzulegen, muss:

  • das charset stimmen
  • die Verbindung vom Client zum Server stimmen
  • die Datenbank eine Collation “utf8_unicode_ci” besitzen
  • jede Tabelle eine Collation “utf8_unicode_ci” besitzen
  • die Daten in UTF-8 abgefüllt sein

Für das Abfüllen eignet sich mysql-query-browser, da dieser schon mit utf-8 arbeiten kann, was bei der Konsole nicht immer ganz sicher ist.

  • Tools: SHOW VARIABLES LIKE ‘character%’,damit sieht man, wie man unterwegs ist
  • set names utf8 zwingt die Verbindung zu utf8
  • select _utf8′Trällöällä’ wandelt den String inUTF-8

Apache:

Irgendwo im Conf sollte AddDefaultCharset UTF-8 stehen. Das vereint das Charset über HTTP.

PHP/Browser:

Wenn der Browser kein UTF-8 anzeigen will, kann man das im php.ini umstellen: default_charset = “UTF-8″.

Links

http://www.phpwact.org/php/i18n/charsets ist eine wirklich gute, praktische Einführung in das Problem im Zusammenhang mit PHP.

Symfony/Creole:

Um da mit UTF-8 zu arbeiten muss databases.yml gefüllt werden. KEIN dsn benutzen, denn dann funzts nicht:

all:
  modul:
    class:      sfPropelDatabase
    param:
      phptype:  mysql
      username: dbuser
      password: dbuserpass
      database: modul
      host:     localhost
      encoding: utf8

Ein ähnliches, hässliches Problem bei der Datenbankmigration wird bei Orthogonal Thought beschrieben.

Teile und geniesse:
  • Technorati
  • del.icio.us
  • MisterWong
  • Digg
  • StumbleUpon
  • blogmarks
  • Furl
  • Simpy
  • Spurl
  • YahooMyWeb

Eingeordnet in Theorie und Schnipsel | 4 Komentare »

MySQL Views verwenden mit Propel und Symfony

Geschrieben von skaldrom am 13. November 2006

Symfony, das PHP-Framework ist genial. Will man allerdings die Datenbank-Views verwenden, geht das nicht so direkt.

Damit die Propel orm-Klassen generiert werden, muss im config/schema.yml die Struktur so definiert werden, dass sie nicht direkt in die Datenbank abgespitzt wird:

m_my_view:
  _attributes: { phpName: ModulCompleteView, skipSql: true}
  post_id:        {type: integer}
  post_title:     {type: varchar, size: 255}
  post_content:   {type: longvarchar}
  comment_id:     {type: integer}
  comment_content:{type: longvarchar}

Damit die View bei symfony propel-insert-sql erstellt wird, sollte eine Datei im gleichen Verzeichnis erstellt werden in dem auch lib.model.schema.swl ist (normalerweise /data/sql). Wir nennen sie my-view.sql:

CREATE OR REPLACE view m_my_view as
SELECT
  post.id as post_id,
  post.title as post_title,
  post.content as post_content,
  comment.id as comment_id,
  comment.content as comment_content
FROM
  post, comment
WHERE
  comment.post_id=post.id

Und nun nur noch die Datei sqldb.map ergänzen:

my-view.sql=DB-VERBINDUNG

und nun sollts funzen.

Teile und geniesse:
  • Technorati
  • del.icio.us
  • MisterWong
  • Digg
  • StumbleUpon
  • blogmarks
  • Furl
  • Simpy
  • Spurl
  • YahooMyWeb

Eingeordnet in Theorie und Schnipsel | Keine Kommentare »

Geburtstagsliste mit MySQL

Geschrieben von skaldrom am 26. October 2006

DAS zentrale Feature unseres Informationssystem ist eine Geburtstagsliste *gähn*. Ich habe eine Tabelle und möchte nun Geburtstage ab heute mit sql herausselecten. Diese birthday list hat folgende Probleme:

  • Ich kann sie nicht nach Geburtstagen ordnen, weil das Jahr keine Rolle spielt.
  • Ich kann auch nicht DAYOFYEAR verwenden, weil es ein Gnusch mit den Schalttagen gibt.
  • Es muss zyklisch sein, so dass Ende Jahr die Geburtstage vom Januar angezeigt werden.

Nun, die rettende Idee war, das Datum umzufomatieren. Also der 26.10.2006 zum 1026 zu machen und danach zu ordnen. Der Rest ist gna:

SELECT id, name, vorname, geburtsdatum
FROM personen_complete
WHERE geburtsdatum IS NOT NULL
ORDER BY
  IF( DATE_FORMAT(geburtsdatum,'%m%d') >= DATE_FORMAT(CURDATE(),'%m%d'),0,1),
  DATE_FORMAT(geburtsdatum,'%m%d') ASC,
  name, vorname
Teile und geniesse:
  • Technorati
  • del.icio.us
  • MisterWong
  • Digg
  • StumbleUpon
  • blogmarks
  • Furl
  • Simpy
  • Spurl
  • YahooMyWeb

Eingeordnet in Theorie und Schnipsel | Keine Kommentare »

Bug ist nicht gleich Bug

Geschrieben von skaldrom am 6. September 2006

Per Zufall bin ich wirklich faszinierende Bugnamen gestossen… Wenn jemand noch mehr kennt, wäre ich Dankbar für eine Mitteilung:

Der Heisenbug
Verändert sich wenn er beobachtet wird. Tritt zum Beispiel auf, wenn sich die Kompilieroptionen für Release und Debug unterscheiden und der Bug nur im Release auftritt.
Der Bohrbug
Ist ein unter allen Umständen und leicht zu reproduzierender Fehler.
Der Mandelbug
Der Mandelbug ist ein Bug, dessen Ursachen so komplex sind, dass er chaotisch erscheint.
Der Schroedinbug
Beim Schroedinbug (oder Shroedinbug) handelt es sich um einen Bug - also einen Fehler in einem Programm - der jedoch noch nicht bekannt ist, weil noch niemand die entsprechende Funktion bzw. die entsprechende Kombinationen von Funktionen ausprobiert hat.
Der Zeilinbug
Die Herkunft der Benennung ist hier nicht bekannt. Zeilinbug bezeichnet einen Fehler, der sich im Code herumbeamt, ohne das man genau weiss warum. Schuld daran können fehlerhaftes Kopieren und Einfügen oder wirre Codegeneratoren sein. Manchmal auch ein konzeptionelles Fehlwissen der Entwickler.
Der Nelsonbug (benannt nach Ted Nelson)
Ein Bug, der entsteht, weil ein Teil der Implementierung auf später verschoben wurde und dieser dann vergessen gegangen ist. Er kann auch auftreten wenn generell nur Stubs vorhanden sind. Ist mit dem Schroedinbug verwandt.
EBCAK
Error Between Chair And Keyboard, Nuff said :)…
ID10T (Ai-Di-Ten-Ti)
Tja, das ist nun nur für 1337.
JASE
Just another System Bug.

Quellen: Wikipedia, Bullhost und A1 Weblog.

Nachtrag (16.03.2008): Die englische Wikipedia hat auch eine Seite für Bugs!

Teile und geniesse:
  • Technorati
  • del.icio.us
  • MisterWong
  • Digg
  • StumbleUpon
  • blogmarks
  • Furl
  • Simpy
  • Spurl
  • YahooMyWeb

Eingeordnet in Theorie und Schnipsel | 2 Komentare »