ExtPascal: JS vs Ajax

Модератор: Модераторы

ExtPascal: JS vs Ajax

Сообщение Brainenjii » 12.07.2010 22:33:38

ExtPascal - инструмент для создания "богатых" веб-приложений c десктопоподобным окружением. Стандартным средством получения информации приложением о действиях пользователя является метод Ajax. Но так же, "богатость" означает и то, что часть действий может быть выполнена прямо в браузере. Из очевидных преимуществ этого можно отметить снятие лишней нагрузки на сервер, и - что важнее - гораздо большая "отзывчивость" интерфейса. К недостаткам я бы отнёс потерю контроля со стороны ExtPascal приложения над происходящим в браузере и необходимостью прибегать в JS. Для демонстрации этих двух возможностей по взаимодействию с пользователем я попробую показать в несколько переработаном примере с оф. сайта Sencha.
Итак, создадим новый пустой рабочий проект ExtPascal Application, как здесь: Изображение
Итак, для реализации примера, нам потребуется таблица и панель. За кадром остались DataStore - одно из ключевых понятий ExtJS и Template - шаблон. Объявим их:
Код: Выделить всё
{$M+}
Type

  { TExtWindow1 }

  TExtWindow1 = Class(TExtWindow)
  Private
    bButtonSwitch: TExtButton;
    bDataRecordMain: TExtDataRecord;
    bDataStoreMain: TExtDataStore;
    bPanelDetail: TExtPanel;
    bGridMain: TExtGridGridPanel;
    bTemplateMain: TExtTemplate;
    FunctionJS: TExtFunction; // Здесь будем хранить JS обработку выделения
    Procedure FillDataStore;
    Procedure ButtonSwitchToggle(Sender: TExtButton; Pressed: Boolean);
  Public
    Property GridMain: TExtGridGridPanel Read bGridMain;
    Property PanelDetail: TExtPanel Read bPanelDetail;
    Property ButtonSwitch: TExtButton Read bButtonSwitch; // кнопка для переключением между Ajax и JS
    Property TemplateMain: TExtTemplate Read bTemplateMain; // Шаблон
    Property DataStoreMain: TExtDataStore Read bDataStoreMain;
    Property DataRecordMain: TExtDataRecord Read bDataRecordMain; // Эта переменная требуется только для
    Constructor Create;                                                                            .// заполнения DataStore
    Procedure Show;
  Published
    Procedure GridMainRowSelect; // Здесь буде обрабатывать выделение через AJAX
  End;
{$M-}

Создадим наши контролы:
Код: Выделить всё
Constructor TExtWindow1.Create;
Var
  i: Integer;
  aData: TExtObjectList;
Begin
  Inherited;
{$IFDEF UseRuntime}
{$I unit1.inc}
{$ENDIF}
  Layout := lyBorder;
// Шаблон - удобная штука, но, кажется, применима только для JS
  bTemplateMain := TExtTemplate.Create('Полный путь: {fullname}<br />' +
    'Имя файла: {file}<br />Размер: {size}<br />Расширение: {ext}<br />');

// сюда будем выводить информацию об файле
  bPanelDetail := TExtPanel.AddTo(Items);
  PanelDetail.Region := rgSouth;
  PanelDetail.Split := TRUE;
  PanelDetail.Height := 100;

//JS функция, выводящая шаблон на PanelDetail в соответствии с данными в
// TExtDataRecord.
  FunctionJS := JSFunction('sm, rowIdx, r', TemplateMain.JSName + '.overwrite('+
    PanelDetail.JSName + '.body, r.data);');

// Собственно, таблица
  bGridMain := TExtGridGridPanel.AddTo(Items);
  GridMain.Region := rgCenter;
// Таблица может иметь несколько различных моделей выделения.
// В ExtJS это реализовано разными классами, что вводит
// некоторое неудобство из-за приведений типов
  GridMain.SelModel := TExtGridRowSelectionModel.Create;
  With TExtGridRowSelectionModel(GridMain.SelModel) Do
    Begin
      SingleSelect := TRUE;
      On('rowselect', FunctionJS); // назначение Listener'a на событие rowselect.
    End;
  aData := TExtObjectList.Create;
// Этот жуткий цикл нужен, чтобы создать столбцы в таблице
// и объявить количество полей у DataRecordMain.
  For i := 0 To 2 Do
    Begin
      With TExtDataField.AddTo(aData) Do
        Begin
          Name := 'с' + IntToStr(i);
          TypeJS := 'string';
        End;
      With TExtGridColumn.AddTo(GridMain.Columns) Do
        Begin
          ID := 'c' + IntToStr(i);
          Width := 90;
          Case i Of
            0:
              Begin
// DataIndex должен соответствовать полю записи в DataStore
                DataIndex := 'file';
                Header := 'Файл';
              End;
            1:
              Begin
                DataIndex := 'ext';
                Header := 'Расширение';
              End;
            2:
              Begin
                DataIndex := 'size';
                Header := 'Размер';
              End;
          End;
        End;
    End;
  With TExtDataField.AddTo(aData) Do
    Begin
      Name := 'с3';
      TypeJS := 'string';
    End;
  bDataRecordMain := TExtDataRecord.Create(aData);
// Об этом чуть ниже
  bDataStoreMain := TExtDataStore.Create;
  FillDataStore;

  GridMain.Store := DataStoreMain;
  GridMain.AutoExpandColumn := 'c0';

  bButtonSwitch := TExtButton.AddTo(TbarArray);
  ButtonSwitch.Text := 'Ajax';
  ButtonSwitch.EnableToggle := TRUE;
  ButtonSwitch.AllowDepress := TRUE;
  ButtonSwitch.OnToggle := ButtonSwitchToggle; // Delphi-style назначения обработчика события
End;

DataStore - это, как не сложно догадаться, хранилище данных, которые могут быть представлены пользователю в виде ComboBox'a или, в нашем случае, таблицы. В своей реализации заимствованного примера оно (DataStore) будет заполнено информацией о файлах нашего проекта:
Код: Выделить всё
// Заполним содержимое таблицы файлами проекта. Поле Fullname хранится  в
// DataStore, но не будет отображено в таблице
Procedure TExtWindow1.FillDataStore;
Var
  aPath: String;
  aSearch: TSearchRec;
Begin
  aPath := ExtractFileDir(ParamStr(0));
  If FindFirst(ExtractFileDir(ParamStr(0)) + '/*', faAnyFile, aSearch) = 0 Then
    Repeat
      bDataStoreMain.Insert(0, JSArray('new ' + DataRecordMain.JSName + '({' +
        'file:' + StrToJS(ExtractFileName(aSearch.Name)) + ',ext:' +
        StrToJS(ExtractFileExt(aSearch.Name)) + ',size:' +
        IntToStr(aSearch.Size) + ',fullname:' + StrToJS(aPath +
        aSearch.Name) + '})'));
    Until Not(FindNext(aSearch) = 0);
  FindClose(aSearch);
End;

Теперь реализуем переключение между Ajax и JS:
Код: Выделить всё
Procedure TExtWindow1.ButtonSwitchToggle(Sender: TExtButton; Pressed: Boolean);
Begin
  With TExtGridRowSelectionModel(GridMain.SelModel) Do
    Begin
      PurgeListeners;
      If Pressed Then
        On('rowselect', Ajax(GridMainRowSelect, ['file', ExtData.
          TExtDataRecord(GetSelected).Get('file')]))
      Else
        On('rowselect', FunctionJS);
    End;
End;

И реализуем показ той же информации через Ajax:
Код: Выделить всё
Procedure TExtWindow1.GridMainRowSelect;
Var
  aPath: String;
  aSearch: TSearchRec;
Begin
  aPath := ExtractFileDir(ParamStr(0)) + '/';
  If FindFirst(aPath + CurrentThread.Query['file'], faAnyFile, aSearch) = 0 Then
    Begin
      ExtMessageBox.Alert('Информация', 'Полный путь: ' + StrToJS(aPath +
        aSearch.Name) + '<br />Имя файл: ' + StrToJS(aSearch.Name) + '<br />' +
        'Размер: ' + IntToStr(aSearch.Size) +  '<br />Расширение: ' +
        StrToJS(ExtractFileExt(aSearch.Name)) + '<br />');
    End;
End;

Итак, то, ради чего я сжёг свой ужин:
Код: Выделить всё
Unit Unit1;

Interface

Uses
  SysUtils, Classes,
{$DEFINE UseRuntime}
{$IFDEF UseRuntime}
  Ext, ExtPascal, ExtPascalUtils, ExtForm,
  ExtData, ExtGrid, ExtUtil, ExtAir, ExtDd,
  ExtLayout, ExtMenu, ExtDirect, ExtState, ExtTree,
  ExtUxForm;

Type
  {$M+}
  TExtPanel_Tab = TExtPanel;
  TExtFormTextField_Grid = TExtFormTextField;
  TExtFormNumberField_Grid = TExtFormNumberField;
  TExtFormDateField_Grid = TExtFormDateField;
  TExtFormTimeField_Grid = TExtFormTimeField;
  TExtFormCheckbox_Grid = TExtFormCheckbox;
  TExtFormComboBox_Grid = TExtFormComboBox;
  {$M-}

{$ELSE}
  ExtP_Design_Ctrls;
{$ENDIF}

{$M+}
Type

  { TExtWindow1 }

  TExtWindow1 = Class(TExtWindow)
  Private
    bButtonSwitch: TExtButton;
    bDataRecordMain: TExtDataRecord;
    bDataStoreMain: TExtDataStore;
    bPanelDetail: TExtPanel;
    bGridMain: TExtGridGridPanel;
    bTemplateMain: TExtTemplate;
    FunctionJS: TExtFunction; // Здесь будем хранить JS обработку выделения
    Procedure FillDataStore;
    Procedure ButtonSwitchToggle(Sender: TExtButton; Pressed: Boolean);
  Public
    Property GridMain: TExtGridGridPanel Read bGridMain;
    Property PanelDetail: TExtPanel Read bPanelDetail;
    Property ButtonSwitch: TExtButton Read bButtonSwitch;
    Property TemplateMain: TExtTemplate Read bTemplateMain;
    Property DataStoreMain: TExtDataStore Read bDataStoreMain;
    Property DataRecordMain: TExtDataRecord Read bDataRecordMain;
    Constructor Create;
    Procedure Show;
  Published
    Procedure GridMainRowSelect; // Здесь буде обрабатывать выделение через AJAX
  End;
{$M-}

Implementation

Uses
  AppThread;

// Заполним содержимое таблицы файлами проекта. Fullname хранится только в
// DataStore, но не в таблице
Procedure TExtWindow1.FillDataStore;
Var
  aPath: String;
  aSearch: TSearchRec;
Begin
  aPath := ExtractFileDir(ParamStr(0));
  If FindFirst(ExtractFileDir(ParamStr(0)) + '/*', faAnyFile, aSearch) = 0 Then
    Repeat
      bDataStoreMain.Insert(0, JSArray('new ' + DataRecordMain.JSName + '({' +
        'file:' + StrToJS(ExtractFileName(aSearch.Name)) + ',ext:' +
        StrToJS(ExtractFileExt(aSearch.Name)) + ',size:' +
        IntToStr(aSearch.Size) + ',fullname:' + StrToJS(aPath +
        aSearch.Name) + '})'));
    Until Not(FindNext(aSearch) = 0);
  FindClose(aSearch);
End;

Constructor TExtWindow1.Create;
Var
  i: Integer;
  aData: TExtObjectList;
Begin
  Inherited;
{$IFDEF UseRuntime}
{$I unit1.inc}
{$ENDIF}
  Layout := lyBorder;
// Шаблон - удобен для "убирания" лишнего текста
  bTemplateMain := TExtTemplate.Create('Полный путь: {fullname}<br />' +
    'Имя файла: {file}<br />Размер: {size}<br />Расширение: {ext}<br />');

// сюда будем выводить информацию об файле
  bPanelDetail := TExtPanel.AddTo(Items);
  PanelDetail.Region := rgSouth;
  PanelDetail.Split := TRUE;
  PanelDetail.Height := 100;

  bGridMain := TExtGridGridPanel.AddTo(Items);
  GridMain.Region := rgCenter;
  GridMain.SelModel := TExtGridRowSelectionModel.Create;
  FunctionJS := JSFunction('sm, rowIdx, r', TemplateMain.JSName + '.overwrite('+
    PanelDetail.JSName + '.body, r.data);');
  With TExtGridRowSelectionModel(GridMain.SelModel) Do
    Begin
      SingleSelect := TRUE;
      On('rowselect', FunctionJS);
    End;
  aData := TExtObjectList.Create;
  For i := 0 To 2 Do
    Begin
      With TExtDataField.AddTo(aData) Do
        Begin
          Name := 'с' + IntToStr(i);
          TypeJS := 'string';
        End;
      With TExtGridColumn.AddTo(GridMain.Columns) Do
        Begin
          ID := 'c' + IntToStr(i);
          Width := 90;
          Case i Of
            0:
              Begin
                DataIndex := 'file';
                Header := 'Файл';
              End;
            1:
              Begin
                DataIndex := 'ext';
                Header := 'Расширение';
              End;
            2:
              Begin
                DataIndex := 'size';
                Header := 'Размер';
              End;
          End;
        End;
    End;
  With TExtDataField.AddTo(aData) Do
    Begin
      Name := 'с3';
      TypeJS := 'string';
    End;
  bDataRecordMain := TExtDataRecord.Create(aData);
  bDataStoreMain := TExtDataStore.Create;
  FillDataStore;
  GridMain.Store := DataStoreMain;
  GridMain.AutoExpandColumn := 'c0';

  bButtonSwitch := TExtButton.AddTo(TbarArray);
  ButtonSwitch.Text := 'Ajax';
  ButtonSwitch.EnableToggle := TRUE;
  ButtonSwitch.AllowDepress := TRUE;
  ButtonSwitch.ToggleGroup := 'switch';
  ButtonSwitch.OnToggle := ButtonSwitchToggle;
End;

Procedure TExtWindow1.Show;
Begin
  Inherited Show;
End;

Procedure TExtWindow1.GridMainRowSelect;
Var
  aPath: String;
  aSearch: TSearchRec;
Begin
  aPath := ExtractFileDir(ParamStr(0)) + '/';
  If FindFirst(aPath + CurrentThread.Query['file'], faAnyFile, aSearch) = 0 Then
    Begin
      ExtMessageBox.Alert('Информация', 'Полный путь: ' + StrToJS(aPath +
        aSearch.Name) + '<br />Имя файл: ' + StrToJS(aSearch.Name) + '<br />' +
        'Размер: ' + IntToStr(aSearch.Size) +  '<br />Расширение: ' +
        StrToJS(ExtractFileExt(aSearch.Name)) + '<br />');
    End;
End;

Procedure TExtWindow1.ButtonSwitchToggle(Sender: TExtButton; Pressed: Boolean);
Begin
  With TExtGridRowSelectionModel(GridMain.SelModel) Do
    If Pressed Then
      Begin
        PurgeListeners;
        On('rowselect', Ajax(GridMainRowSelect, ['file', ExtData.
          TExtDataRecord(GetSelected).Get('file')]));
      End
    Else
      Begin
        PurgeListeners;
        On('rowselect', FunctionJS);
      End;
End;

End.
Аватара пользователя
Brainenjii
энтузиаст
 
Сообщения: 1345
Зарегистрирован: 10.05.2007 00:04:46

Вернуться в Сеть

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1

Рейтинг@Mail.ru