czwartek, 27 grudnia 2012

Łączenie URL-i jak Path.Combine()

Pracując z aplikacjami webowymi dosyć często zachodzi potrzeba połączenia dwóch stringów będących URL-ami. Można to zrobić w bardzo prosty sposób jak zwykłe łączenie dwóch stringów, przy pomocy plusa. Jednak to rozwiązanie jest nieeleganckie i może być źródłem nieoczekiwanych problemów.

Z drugiej strony w przypadku operowania na stringach będących ścieżkami na dysku możemy skorzystać z metody Path.Combine(), która bezpiecznie łączy dwa ciągi znaków. Dodając lub nie "\" w miejscu ich łączenia.

W przypadku łączenia URL-i nie mamy gotowej metody w frameworku, która działała by w taki sam sposób jak Path.Combine(). Można tu wykorzystać naturalną możliwość łączenia jaką daje konstruktor klasy Uri() jednak jego działanie nie będzie zgodne z oczekiwaniem. Dodatkowym problemem jest to, że nie można podać łączonych URL-i jako stringów.
string urlA = "http://example.org/info";
string urlB = "test.html";

Uri baseUri = new Uri(urlA);
Uri pathUri = new Uri(urlB, UriKind.Relative);
Console.Write(new Uri(baseUri, pathUri).ToString());

Wynikiem działania powyższego kodu będzie adres w postaci: http://example.org/test.html. Nie taki był zamiar, bo zgodnie z oczekiwaniem adres miał wyglądać tak: http://example.org/info/test.html aby zachować zachowanie takie jak Path.Combine().
Gdy lekko zmodyfikujemy łączone adresy:
string urlA = "http://example.org/info/";
string urlB = "test.html";

To otrzymamy właściwy adres zgodnie z oczekiwaniem. A co gdy dołączana część adresu będzie się zaczynać od "/"?
string urlA = "http://example.org/info/";
string urlB = "/test.html";

Otrzymamy znowu adres: http://example.org/info.html, więc wróciliśmy do punktu wyjścia. Kilka spostrzeżeń:
  • Pierwsza część adresu musi zawsze kończyć się znakiem "/"
  • druga część adresu nie może się zaczynać od znaku "/"
Zastosujmy więc poniższe wnioski do początkowego kodu:
string urlA = "http://example.org/info/";
string urlB = "/test.html";

Uri baseUri = new Uri((urlA.EndsWith("/") ? urlA : urlA + '/'));
Uri pathUri = new Uri(urlB.TrimStart('/'), UriKind.Relative);
Console.Write(new Uri(baseUri, pathUri).ToString());
Lub w bardziej przyjaznej formie metody:
public static string UrlCombine(string urlA, string urlB)
{
   // dodajmy / na końcu gdy go nie ma
   Uri baseUri = new Uri((urlA.EndsWith("/") ? urlA : urlA + '/'));
   // zawsze usuwamy znak / z początku
   Uri pathUri = new Uri(urlB.TrimStart('/'), UriKind.Relative); 
   return new Uri(baseUri, pathUri).ToString();
}

Omijając kilka właściwości klasy Uri udało się stworzyć metodę, która może ułatwić i przyspieszyć prozaiczną czynność jak łączenie adresów.

piątek, 4 maja 2012

HTML5: Element progress - pasek postępu

Standard HTML5 wprowadza kilka elementów, bardziej związanych z aplikacjami niż z typowymi dokumentami tekstowymi. Jednym z nich jest pasek postępu, który pozwala na graficzną reprezentację postępu czasochłonnej czynności, jak ściąganie/wysyłanie plików, przetwarzanie danych przez algorytm. Umieszczenie elementu w dokumencie:

<progress max="100"></progress>

Parametry:
  • max - wartość maksymalna,
  • value - aktualna wartość wskazywana przez pasek,
  • form - formularz do którego przypisany jest pasek.
Dostęp do paska postępu w JavaScript

<progress id="test" max="100"></progress>

Kod w JavaScript:

bar = document.getElementById("test");
bar.value = 50; // 50% postępu



W przypadku nieokreślenia parametru max pasek postępu, przyjmuje postać, w której nie wskazuje na aktualny postęp tylko pracę w toku (przesuwający się prostokąt).



Określanie wyglądu paska

Określenie tła i obramowania wygląda tak samo jak w innych elementach HTML. Problemem może być tu określenie koloru wskazującego na postęp. Nie można tego dokonać żadnym standardowym parametrem CSS.
Należy użyć pseudostyli dla konkretnej przeglądarki, w tym przypadku dla Firefoksa i Chrome:

progress::-webkit-progress-bar-value, 
progress::-webkit-progress-value,
progress::-moz-progress-bar {background-color: Red;}