Archive for the 'actionscript' Category

set selectedItem w ComboBox Flexa

Kiedy z bazy danych pobieramy hm, dane, a któraś z kolumn przybiera wartości z pewnego niewielkiego zbioru (jak np. dla typu ENUM w MySQL), to w formularzu edycji rekordu chcielibyśmy zwykle użyć komponentu ComboBox do edycji tej kolumny. Problem polega na tym, że ComboBox nie ma prostej metody do ustawiania zadanej wartości. Można owszem ustawić selectedItem, ale tylko przekazując jeden z obiektów z dataProvidera Combo. Nie taki sam obiekt, ale ten sam. Tyle że wygodniej jest przekazać wartość, np. pobraną ze wspomnianej bazy. No i niech etykieta (label) Combo ustawi się sama. Oto rozszerzenie ComboBoksa, które robi co trzeba:

<?xml version="1.0" encoding="utf-8"?>
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml">
    <!--
    komponent SmartComboBox z automatycznym ustawianiem selectedIndex
    na podaną wartość
    licencja: do swobodnego wykorzystania
    -->
    <mx:Script>
        <![CDATA[
            protected var _myDP:Object;
            [Bindable]
            public function set value(v:*):void
            {
                var found:Boolean = false;
                for(var i:int = 0; (i < dataProvider.length) && !found; i++) {
                    if(v == _myDP[i].data) {
                        selectedIndex = i;
                        found = true;
                    }
                }
                if(!found) throw(new Error("invalid value " + v + " for SmartComboBox.",99));
            }
            [Bindable]
            override public function set dataProvider(v:Object):void
            {
                _myDP = v;
                super.dataProvider = v;
            }
        ]]>
    </mx:Script>
</mx:ComboBox>

AMFPHP i błąd 403 - Forbidden

Długo szukałem rozwiązania problemu, jaki pojawił się po przeniesieniu aplikacji AMFPHP z Windows na Linuksa. Skrypt gateway.php wywoływany z ‘palca’, czyli z URLa http://serwer/gateway.php odpowiadał prawidłowo. Browser już gorzej - nie wyświetlał prawego panelu z listą metod, a FireBug poproszony o przedstawienie odpowiedzi serwera napisał o błędzie 403 - Forbidden. Ciekawe, że w Google nie znalazłem nic konkretnego, na jednym tylko forum wskazówkę, że chodzi o prawa dostępu. To akurat było łatwe do wydedukowania. Śledztwo wykazało winnego - w skrypcie /core/shared/util/MethodTable.php, w linii 164 wywoływana jest funkcja touch($sourcePath) , gdzie $sourcePath wskazuje na nazwę uruchamianej usługi. Wystarczy ustawić Apaczowi prawo do zapisu pliku usługi (np. /services/Usluga.php) i od razu jest lepiej.

Piszą o AMFPHP na flashzone.pl.

wielokolumnowy układ tekstu w actionscript

Jest taki przykład w dokumentacji Flexa, jest też trochę o tym na blogu niejakiego Daniela. Jednak oba przykłady kończą się tam, gdzie zaczyna się próba przelewania HTMLa przez kilka ramek tekstowych. Dla zwykłego, czystego tekstu to proste - zobaczyć ile się nie zmieściło w ramce n i wlać to do ramki n+1, aż do ostatniej ramki albo końca tekstu.

W przypadku HTMLa jednak Flash nas nie oszczędza. Obliczenie pozycji, na której powinien nastąpić podział jest skomplikowane, bo trzeba uwzględnić - niewidoczne w ramce - tagi, w dodatku pamiętać o automatycznym zamykaniu ich i otwieraniu w kolejnych ramkach. Metody klasy TextField jak getLineOffset() zwracają pozycję w czystym tekście, a podział musi nastąpić w odpowiadającym jej miejscu HTMLa. Na dokładkę HTML, jaki naprawdę jest w obiekcie TextField zupełnie niekoniecznie przypomina ten, który przypisaliśmy do htmlText! Dlatego trzeba najpierw wlać tekst do ramki:

naszTextField.htmlText = nowyHtml;

potem pobrać go do zmiennej i dalej pracować już nad nim:

processedHtml = naszTextField.htmlText;

a oto procedurka przelewająca:

protected function flow():void
{
var lastSplit:                int     = 0;
var newSplit:                int     = 0;
var tb:                        VTextBox;
var tbNum:                    int        = linkedTextBoxes.length;
var tagsHeap:                Array      = new Array();
var opening:                String;
var closing:                String;
var tempText:                String;
var remainder:                String;
var remainLinesNum:            int;
var lastVisibleLineIndex:    int;
var cutIndex:                int;

// liczba stron, na jaką trzeba będzie podzielić tekst
pagesNum             = 0;
// pozycje podziału stron
splitIndices         = new Array();
splitIndices.push(0);
// pozostała do wlania część tekstu - najpierw cały
remainder = processedText;
textPieces = new Array();

while(remainder.length > 0) {
textPieces[pagesNum] = new Array();
for(var i:int = 0; i < tbNum; i++) {
// kolejna ramka tekstowa
tb = linkedTextBoxes[i];
trace(’strona ‘ + pagesNum + ‘, box nr ‘ + i);

// Jeśli tekst już się skończył, kolejne ramki bieżącej strony wypełniamy pustym tekstem.
// Jeśli tekst jeszcze jest, wlewamy pozostałą część i badamy ile się zmieściło
if(remainder.length == 0) {
textPieces[pagesNum][i] = ”;
} else {
// dodajemy na początek otwarcie wszystkich tagów kontynuowanych z poprzedniej ramki
opening                 = Html.getOpeningHtml(tagsHeap);
// wlewamy cały pozostały tekst
tb.htmlText             = opening + remainder;
// obliczamy, ile linii jest poza ramką
remainLinesNum             = tb.maxScrollV - 1;
trace(’poza ramką jest linii: ‘ + remainLinesNum);

if(remainLinesNum == 0) {
textPieces[pagesNum][i] = opening + remainder;
remainder = ”;
} else {
// obliczamy index ostatniej linii
lastVisibleLineIndex     = tb.numLines - remainLinesNum - 1;
trace(’indeks ostatniej linii: ‘ + lastVisibleLineIndex);
// pobieramy indeks ostatniego widocznego znaku
cutIndex                 = tb.getLineOffset(lastVisibleLineIndex) + tb.getLineLength(lastVisibleLineIndex) - 1;
trace(’cutIndex: ‘ + cutIndex);
trace(’cut rigth after …’ + tb.getLineText(lastVisibleLineIndex));
// pozostawiamy tylko mieszczącą się część tekstu
tempText                = remainder.substring(0, cutIndex);
remainder                = remainder.substr(cutIndex);
// uzupełniamy listę otwartych tagów
tagsHeap                 = Html.getTags(tempText, tagsHeap);
// pobieramy tagi do zamknięcia w ramce
closing = Html.getClosingHtml(tagsHeap);
textPieces[pagesNum][i] = opening + tempText + closing;
}
}
}
pagesNum++;
}

displayPage(0);
}

A oto link do video, w świetle którego całe powyższe rozważanie wkrótce straci sens.

« Previous PageNext Page »