はじめに
プリザンターのサーバスクリプトの関数の1つである「context.AddResponse」、マニュアルページはあるものの記載されている内容はかなりシンプルで、何がどこまで出来るの?というところまでは記載がありません。今回は実装から中身を読み解いていきます。
実装を見てみる
早速実装をみてみましょう。サーバスクリプト(ClearScript)で呼び出される部分は下記になります。
public void AddResponse(
string method,
string target = null,
object value = null,
string options = null)
{
ResponseCollection.Add(
method: method,
target: target,
value: value,
options: options);
}
ここでは受け取った値をResponseCollection.Add
に渡しているだけなので、ResponseCollection.Add
を見てみます。
public ResponseCollection Add(
string method,
string target = null,
object value = null,
string options = null)
{
Add(new Response(
method: method,
target: target,
value: value != null
? value
: string.Empty,
options: options));
return this;
}
ざっくりと説明してしまうと、ResponseCollection
にcontext.AddResponse
でセットされた値を追加していっています。最終的にResponseCollection
にセットされた値はJSONにシリアライズされブラウザに送られます。
ブラウザ側で送られたResponseCollection
を受け取っているのはJavaScriptで書かれたライブラリです。その実装部を見てみましょう。
$p.setByJsonElement = function (jsonElement, data, $control) {
var method = jsonElement.Method;
var target = jsonElement.Target;
var value = jsonElement.Value;
var options = jsonElement.Options !== undefined
? JSON.parse(jsonElement.Options)
: {};
switch (method) {
case 'Html':
$(target).html(value);
break;
case 'ReplaceAll':
$(value).replaceAll(target);
break;
case 'Message':
$p.setMessage(target, value);
break;
case 'Href':
$control.addClass('no-send');
$p.transition(value);
break;
case 'PushState':
history.pushState(target, '', value);
break;
case 'Set':
var $target = $p.getControl(target);
if (!$target) {
$target = $(target);
}
$p.set($target, value);
break;
case 'SetData':
$p.setData($(target));
break;
case 'SetFormData':
data[target] = value;
break;
case 'SetMemory':
$p[target] = value;
break;
case 'Append':
$(target).append(value);
break;
case 'Prepend':
$(target).prepend(value);
break;
case 'After':
if ($(target).length !== 0) {
$(target).after(value);
} else {
$control.after(value);
}
break;
case 'Before':
if ($(target).length !== 0) {
$(target).before(value);
} else {
$control.before(value);
}
break;
case 'InsertText':
$p.insertText($(target), value);
break;
case 'Remove':
$(target).remove();
break;
case 'Attr':
var json = JSON.parse(value);
$(target).attr(json.Name, json.Value);
break;
case 'RemoveAttr':
$(target).removeAttr(value);
break;
case 'Css':
var json = JSON.parse(value);
$(target).css(json.Name, json.Value);
break;
case 'Focus':
if (target === '') {
$('#' + data.ControlId).focus();
} else {
$(target).focus();
}
break;
case 'SetValue':
$p.setValue($(target), value);
$p.hideField(target, options);
break;
case 'ClearFormData':
$p.clearData(target, data, value);
break;
case 'CloseDialog':
$p.clearMessage();
if (target !== undefined) {
if ($(target).hasClass('ui-dialog-content')) {
$(target).dialog('close');
}
} else {
$('.ui-dialog-content').dialog('close');
}
break;
case 'Paging':
$p.paging(target);
break;
case 'Toggle':
$(target).toggle(value === '1');
break;
case 'Trigger':
$(target).trigger(value);
break;
case 'Invoke':
$p[target](value);
break;
case 'Events':
$p.execEvents(target, '');
break;
case 'WindowScrollTop':
$(window).scrollTop(value);
break;
case 'ScrollTop':
$(target).scrollTop(value);
break;
case 'LoadScroll':
$p.loadScroll();
break;
case 'FocusMainForm':
$p.focusMainForm();
break;
case 'Disabled':
$(target).prop('disabled', value);
case 'Log':
if (value) {
console.log(value);
}
break;
}
}
ここまで来ると何か見たことがあるものがありませんか?そうですswitch文で処理されているmethod
です。
このmethod
がマニュアルに記載されている引数method
そのものになります。
method
を細かく見ていく
では実際にそれぞれのmethod
でどのような処理が行われているか見てみましょう。
Html
$(target).html(value);
とある通り、jQueryのhtml
メソッドそのままです。target
で指定された要素の中身をvalue
で書き換えます。
ReplaceAll ※マニュアルに記載あり
$(target).replaceAll(value);
とある通り、jQueryのreplaceAll
メソッドそのままです。target
で指定された要素ごとvalue
で書き換えます。
Message
$p.setMessage(target, value);
なので、スクリプトの$p.setMessage
になります。
Href
$control.addClass('no-send');
で現在の画面内容をサーバに対して送信しない様にしたあとに、$p.transition
を呼んでいます。$p.transition
の実装は下記のようになっています。
$p.transition = function (url) {
try {
location.href = url;
} catch (e) {
if (e.number !== -2147467259) {
throw e;
}
}
};
location.href
にvalue
を渡しています。location.href
はJavaScriptの標準プロパティなので、mdn web docsを参照してください。location: href プロパティ
PushState
history.pushState
を呼び出しています。JavaScriptの標準メソッドなので、mdn web docsを参照してください。History: pushState() メソッド
Set ※マニュアルに記載あり
指定された要素に$p.set
で値をセットしています。ポイントとなるのは詳しくは$p.getControl
で標準項目の取得を行い、取得出来なければそのままで要素が使用されるという部分です。$p.set
についてはマニュアルを参照してください。
SetData
指定された要素に$p.setData
で値をセットしています。$p.setData
はマニュアルに記載がないので簡単に紹介します。実装を見てみましょう。
$p.setData = function ($control, data) {
var controlId = $control.attr('id');
if (!$control.hasClass('not-send')) {
if (data === undefined) {
data = $p.getData($control);
}
$p.setGridTimestamp($control, data);
switch ($control.prop('type')) {
case 'checkbox':
data[controlId] = $control.prop('checked');
break;
case 'radio':
if ($control.prop('checked')) {
var name = $control.attr('name');
data[name] = $control.val();
$('[id="' + name + '"]').val($control.val());
$('[id="' + name + '-error"]').remove();
}
break;
default:
switch ($control.prop('tagName')) {
case 'SPAN':
data[controlId] = $control.attr('data-value') !== undefined
? $control.attr('data-value')
: $control.text();
break;
case 'SELECT':
if ($control.attr('multiple')) {
$p.setMultiSelectData($control);
} else {
data[controlId] = $control.val();
}
break;
case 'OL':
if ($control.hasClass('control-selectable')) {
data[controlId] = $p.toJson($control.find('li.ui-selected'));
if ($control.hasClass('send-all')) {
data[controlId + 'All'] = $p.toJson($control.find('li'));
}
} else {
data[controlId] = $p.toJson($control.find('li'));
}
break;
case 'TABLE':
data[controlId] = JSON.stringify($control
.find('.select')
.filter(':checked')
.map(function () {
return $(this).closest('.grid-row').attr('data-id');
})
.toArray());
break;
case 'P':
if ($control.hasClass('control-slider')) {
data[controlId] = $control.attr('data-value');
} else {
data[controlId] = $control.val();
}
break;
default:
data[controlId] = $control.val();
break;
}
break;
}
}
}
指定された要素がnot-send
という属性を持つときのみdata
という連想配列にセットされているデータを詰め替えています。このdata
というのはプリザンターのブラウザからサーバに対して送るデータを保持しているものになります。UIや$p.set
などでデータの変更を行うときに裏で動いている関数となります。通常は使うことがないので詳細は割愛します。
SetFormData
前項のSetData
と類似ではあるのですが、コントロールを直接指定しているという部分が異なります。通常は使うことがないので詳細は割愛します。
SetMemory
$p
という連想配列にデータをセットします。メソッド名の示すとおり一時的にデータを保管する用途で使用されます。任意の関数を作成して一時的に格納するということにも使用可能で、その場合はInvoke
で発火させます。
Append
$(target).append(value);
とある通り、jQueryのappend
メソッドそのままです。value
をtarget
の末尾に追加します。
Prepend
$(target).prepend(value);
とある通り、jQueryのprepend
メソッドそのままです。value
をtarget
の先頭に追加します。
After
$(target).after(value);
とある通り、jQueryのafter
メソッドそのままです。target
の直後に要素を追加します。
Before
$(target).before(value);
とある通り、jQueryのbefore
メソッドそのままです。target
の直前に要素を追加します。
InsertText
$p.insertText
を呼び出しています。$p.insertText
の実装を見てみましょう。
$p.insertText = function ($control, value) {
var body = $control.get(0);
body.focus();
var start = body.value;
var caret = body.selectionStart;
var next = caret + value.length;
body.value = start.substr(0, caret) + value + start.substr(caret);
body.setSelectionRange(next, next);
$p.setData($control);
if (!$control.is(':visible')) {
$p.showMarkDownViewer($control);
}
}
指定された要素の末尾で文字列を追記して、送信データに組み入れる処理を行っています。説明項目などに文字列を追記する時に使用します。
Remove
$(target).remove();
とある通り、jQueryのremove
メソッドそのままです。target
をまるごと削除します。
Attr
$(target).attr(json.Name, json.Value);
とある通り、jQueryのattr
メソッドそのままです。target
に属性を追加します。使い方に若干癖があり、value
に対して{Name:'',Value:''}
というJSONをシリアライズしたものを格納する必要があります。
RemoveAttr
$(target).attr(json.Name, json.Value);
とある通り、jQueryのattr
メソッドそのままです。target
から指定属性を削除します。
Css
$(target).css(value);
とある通り、jQueryのcss
メソッドそのままです。target
に対してCSSを適用します。使い方に若干癖があり、value
に対して{Name:'',Value:''}
というJSONをシリアライズしたものを格納する必要があります。
Focus
$(target).focus();
とある通り、jQueryのfocus
メソッドそのままです。target
に対してファーカスを当てる操作を行います。
SetValue
$p.setValue($(target), value);
と$p.hideField(target, options);
が連続実行されています。まずは$p.setValue
の実装を見てみましょう。
$p.setValue = function ($control, value) {
switch ($control.prop('type')) {
case 'checkbox':
$control.prop('checked', value);
break;
case 'radio':
$control.val([value]);
break;
case 'textarea':
$control.val(value);
$p.showMarkDownViewer($control);
break;
default:
switch ($control.prop('tagName')) {
case 'SELECT':
if ($control.attr('multiple')) {
$p.selectMultiSelect($control, value);
} else {
$control.val(value);
}
break;
case 'SPAN':
$control.html(value);
case 'TIME':
$control.html(value);
$control.attr('datetime', value);
break;
default:
if ($control.hasClass('radio-value')) {
// type="radio"のチェック変更
$('input[name="' + $control.attr('id') + '"]').val([value]);
}
$control.val(value);
break;
}
}
}
やっていることはとても簡単で指定要素をvalue
で書き換えています。$p.set
と似たような処理ではあるのですが、差違としては$p.setData
を叩いていない(=サーバに送るデータとして処理しない)部分になります。
次は$p.hideField
を見てみましょう。
$p.hideField = function (target, options) {
$field = $(target + 'Field');
if (options.Hide && !$field.hasClass('hidden')) {
$field.addClass('hidden');
} else if (options.Hide !== true && $field.hasClass('hidden')) {
$field.removeClass('hidden');
}
}
項目の表示・非表示を判断して、表示・非表示を再設定しています。$p.setValue
で表示・非表示が外れることがあるので、この関数で復旧させています。
画面上の要素で表示名などのデータ以外の項目を書き換えたいときに使用します。
ClearFormData
$p.clearData
を呼び出しています。実装を見てみましょう。
$p.clearData = function (target, data, type) {
if (!data) {
data = $p.getData($('.main-form'));
}
if (target === undefined) {
for (controlId in data) {
if (!$('#' + controlId).hasClass('control-selectable')) {
Delete(controlId);
}
}
} else if (type === 'startsWith') {
for (controlId in data) {
if (controlId.indexOf(target) === 0) {
Delete(controlId);
}
}
} else {
if (target in data) {
Delete(target);
} else if ($(target).length !== 0) {
Delete($(target).attr('id'));
}
}
function Delete(key) {
if (type === 'ignoreView') {
if (key.indexOf('View') === 0) {
return;
}
}
delete data[key];
}
};
$p.setData
とは反対にdata
にセットされたデータを削除(=サーバに送信しないデータにする)を行っています。通常は使用することはないため割愛します。
CloseDialog
開かれているダイアログを閉じるために使用します。通常は使用することはないため割愛します。
Paging
$p.paging
を呼び出しています。実装を見てみましょう。
$p.paging = function (selector) {
if ($('.ui-dialog:visible').length > 0) {
return;
}
var $control = $(selector);
var $offset = $(selector + 'Offset');
if ($control.length) {
if ($(window).scrollTop() + $(window).height() >= $control.offset().top + $control.height()) {
if ($offset.val() !== '-1') {
$p.setData($offset);
$offset.val('-1');
$p.send($control);
}
}
}
}
一覧項目などでサイトの下部までスクロールした際に次の項目を読み出してくるときに使用します。通常は使用することはないため割愛します。
Toggle
$(target).toggle(value === '1');
とある通り、jQueryのtoggle
メソッドそのままです。指定された要素の表示・非表示を切替ます。value
が1
かそうでないかでtrue/false
を指定しているので、true/false
を直接指定出来ないことに注意が必要です。
Trigger
$(target).trigger(value);
とある通り、jQueryのtrigger
メソッドそのままです。指定された要素に対してトリガーを発火させることができます。サーバスクリプト側から選択肢一覧のモーダルを表示させたり、一覧メニューを表示させたりとUI操作でかなり強力な操作が可能です。
Invoke
$p[target](value);
と書いてある通り、$p
にセットされている任意の関数を実行出来ます。SetMemory
でセットしてInvoke
で発火させるという使い方になります。
Events
$p.execEvents
を呼び出しています。実装を見てみましょう。
$p.execEvents = function (event, args) {
var result = exec(event);
var $control = args.$control;
if ($control) {
result = exec(event + '_' + $control.attr('id')) && result;
if ($control.attr('id') !== $control.attr('data-action')) {
result = exec(event + '_' + $control.attr('data-action')) && result;
}
}
return result;
function exec(name) {
if ($p.events[name] !== undefined) {
return ($p.events[name](args) === false) ? false : true;
}
return true;
}
}
かなり強力な機能で、任意の関数を実行することが可能ですが、実行対象は$p.events
に格納されている関数になるので、使いどころがむずかいしいところがあります。
WindowScrollTop
$(window).scrollTop(value);
とある通り、jQueryのscrollTop
メソッドそのままです。value
に指定された数値の位置までスクロールします。
ScrollTop
$(target).scrollTop(value);
とある通り、jQueryのscrollTop
メソッドそのままです。value
に指定された数値の位置までスクロールします。WindowScrollTop
との違いは、ウインドウではなく要素が指定されているところになります。
LoadScroll
$p.loadScroll
を呼んでいるので、$p.loadScroll
の実装を見てみましょう。
$p.loadScroll = function () {
window.scroll($p.scrollX, $p.scrollY);
}
さらに別の$p.scrollX
と$p.scrollY
も出てきたので、こちらの実装も見てみます。
$p.saveScroll = function () {
$p.scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
$p.scrollY = document.documentElement.scrollTop || document.body.scrollTop;
}
$p.clearScroll = function () {
$p.scrollX = 0;
$p.scrollY = 0;
}
これは現在のスクロール位置を取得しています。
画面の再ロードがおこなわれた際に元々の表示位置に画面をスクロールするのに使用します。通常は使用することはない思います。
FocusMainForm
$p.focusMainForm
が呼び出されています。実装を見てみましょう。
$p.focusMainForm = function () {
$('#FieldSetGeneral').find('[class^="control-"]').each(function () {
if (!$(this).is(':hidden') &&
!$(this).hasClass('control-text') &&
!$(this).hasClass('control-markup')) {
$(this).focus();
return false;
}
});
}
編集画面中の先頭のアイテムにフォーカスを当てる動作をしています。通常は使用することはないとおもいm
Disabled
$(target).prop('disabled', value);
とある通り、jQueryのprop
メソッドそのままです。指定要素にdisabled
を付与したり外したりといった操作が可能です。
Log
value
に値が格納されていればconsole.log
で値が出力されます。context.Log
と同じ働きをします。
まとめ
今回はcontext.AddResponse
の中身を見てみました。マニュアルには記載がないけどかなり使えるmethod
が複数あります。Href
やWindowScrollTop
などかなり使いどころがある機能なので、是非使ってみてください。