/*=====================================================
* Script Name: tour_module_suggest.js
* Description: 空席照会モジュール サジェスト 共通処理
* Version: 1.01
* Last Up Date: 2017/10/25
=====================================================*/
var INPUT_LABEL_LENGTH = 25;
var strategies = undefined;
/**
* util
*/
var isMobile = false;
var isIE8 = function() {
if (/msie 8\.0/i.test(navigator.userAgent)) {
return true;
}
return false;
};
var isIE7 = function() {
if (/msie 7\.0/i.test(navigator.userAgent)) {
return true;
}
return false;
};
var isIE6 = function() {
if (/msie 6\.0/i.test(navigator.userAgent)) {
return true;
}
return false;
};
var isFirefox = function() {
if (/firefox/i.test(navigator.userAgent.toLowerCase())) {
return true;
}
return false;
};
var isDOMContentLoaded = false;
$tour_module_jq.event.add(window,"load",function() {
isDOMContentLoaded = true;
});
(function($) {
'use strict';
//:focusable selector
function focusable(element, isTabIndexNotNaN) {
var map, mapName, img,
nodeName = element.nodeName.toLowerCase();
if ('area' === nodeName) {
map = element.parentNode;
mapName = map.name;
if (!element.href || !mapName || map.nodeName.toLowerCase() !== 'map') {
return false;
}
img = $tour_module_jq('img[usemap=#' + mapName + ']')[0];
return !!img && visible(img);
}
return (/input|select|textarea|button|object/.test(nodeName) ?
!element.disabled :
'a' === nodeName ?
element.href || isTabIndexNotNaN :
isTabIndexNotNaN) && visible(element);
}
function visible(element) {
return $tour_module_jq.expr.filters.visible(element) &&
!$tour_module_jq(element).parents().addBack().filter(function() {
return $tour_module_jq.css(this, 'visibility') === 'hidden';
}).length;
}
$tour_module_jq.extend($tour_module_jq.expr[':'], {
data: function(elem, i, match) {
return !!$tour_module_jq.data(elem, match[3]);
},
focusable: function(element) {
return focusable(element, !isNaN($tour_module_jq.attr(element, 'tabindex')));
}
});
var chopText = function(text, length) {
var _r = new RegExp('^.{1,' + length + '}');
text = text.match(_r);
return text;
};
/**
* Bind the func to the context.
*/
var bind = function(func, context) {
if (func.bind) {
// Use native Function#bind if it's available.
return func.bind(context);
} else {
return function() {
func.apply(context, arguments);
};
}
};
/**
* Get the styles of any element from property names.
*/
var getStyles = (function() {
var color;
color = $tour_module_jq('
').css(['color']).color;
if (typeof color !== 'undefined') {
return function($el, properties) {
return $el.css(properties);
};
} else { // for jQuery 1.8 or below
return function($el, properties) {
var styles;
styles = {};
$tour_module_jq.each(properties, function(i, property) {
styles[property] = $el.css(property);
});
return styles;
};
}
})();
var ListView = (function() {
function ListView($el, completer) {
this.$el = $el;
this.$wrapper = $tour_module_jq(this.$el).parents(completer.strategies.targetAutocompleteSelector);
this.$resultWrapper = $tour_module_jq(this.$el).parents(completer.strategies.targetResultListWrapperSelector);
this.$result = $tour_module_jq(this.$wrapper).find(completer.strategies.targetResultDataSelector);
this.defaultOffset = 194;
this.index = 0;
this.completer = completer;
this.scrollPosition = 0;
this.wrapperHeight = this.$resultWrapper.height();
this.$el.on('mousedown', 'li', bind(this.onClick, this));
$tour_module_jq(window).on('resize', bind(this.deactivate,this));
};
$tour_module_jq.extend(ListView.prototype, {
shown: false,
render: function(data) {
var uniq, label, html;
this.index = 0;
this.data = data;
uniq = this.completer.strategies.uniq;
label = this.completer.strategies.dispLabel;
html = _.template(('<% _.each(d, function(_sugg) {%>' +
'' + label + '<% }); %>').replace(/<%= /g, '<%= _sugg.'),
{d: data}).replace(/\[\d{3}\]/, '').replace(/\+\]/g, ']');
this.$el.append(html);
this.scrollPosition = 0;
if (data.length) {
this.activateIndexedItem();
}
},
clear: function() {
this.$el.html('');
this.index = 0;
return this;
},
active: function() {
if (!this.shown) {
this.$el.show();
this.$wrapper.show();
this.shown = true;
this.defaultOffset = this.getItem(0).offset().top;
}
return this;
},
select: function(uniq) {
this.completer.onSelect(uniq);
this.completer.$el.blur();
this.deactivate();
},
deactivate: function() {
if (this.shown) {
this.$el.hide();
this.$wrapper.hide();
this.shown = false;
this.data = this.index = null;
}
return this;
},
activateIndexedItem: function() {
this.$el.find('.is-select').removeClass('is-select');
this.getActiveItem().addClass('is-select');
},
getActiveItem: function() {
return $tour_module_jq(this.$el.children().get(this.index));
},
getItem: function(index) {
return $tour_module_jq(this.$el.children().get(index));
},
onKeydown: function(e) {
if (!this.shown) return;
if (e.keyCode === 27) { // ESC
e.preventDefault();
this.deactivate();
} else if (e.keyCode === 38) { // UP
e.preventDefault();
if (this.index === 0) {
this.index = _.size(this.data) - 1;
this.scrollPosition = this.getScrollBottomPosition()
} else {
this.index -= 1;
}
this.activateIndexedItem();
this.active();
var currentOffset = this.getActiveItem().offset().top;
var activateItemHeight = this.getActiveItem().outerHeight(true);
if ((currentOffset - this.defaultOffset) < 0) {
this.scrollPosition = this.getActiveItem().position().top;
}
if (this.scrollPosition < 0) {
this.scrollPosition = 0;
}
} else if (e.keyCode === 40) { // DOWN
e.preventDefault();
if (this.index === _.size(this.data) - 1) {
this.index = 0;
this.scrollPosition = 0;
} else {
this.index += 1;
}
this.activateIndexedItem();
this.active();
var currentOffset = this.getActiveItem().offset().top;
var activateItemHeight = this.getActiveItem().outerHeight(true);
var offsetScrollPosition = currentOffset - this.defaultOffset + activateItemHeight - this.wrapperHeight;
if (offsetScrollPosition > 0) {
this.scrollPosition += offsetScrollPosition;
}
} else if (e.keyCode === 13 || e.keyCode === 9) { // ENTER or TAB
e.preventDefault();
this.select(this.getActiveItem().attr('data-label'));
}
},
getScrollBottomPosition : function() {
var result = 0;
for (var i = 0; i < _.size(this.data); i++) {
if (this.getItem(i).position().top + this.getItem(i).outerHeight(true) >= this.wrapperHeight) {
result += this.getItem(i).outerHeight(true);
}
}
return result;
},
onClick: function(e) {
var $e = $tour_module_jq(e.target);
e.originalEvent.keepTextCompleteDropdown = true;
if (!$e.hasClass('m_listItem')) {
$e = $e.parents('li.m_listItem');
}
this.select($e.attr('data-label'));
}
});
return ListView;
})();
/**
* Textarea manager class.
*
* @param {Object} $el 補完対象の
* @param {Object} $target 送信されるデータが入る
* @param {Object} strategies 補完処理の外部
*/
var Completer = (function() {
function Completer($el, target, strategies) {
var $wrapper, $list, focused, $overlay, $clearBtn;
var zindex;
this.target = target;
this.el = $el.get(0); // textarea element
this.$el = $el;
this.strategies = strategies;
this.completed = false; //確定状態フラグ
this.term = this.$el.val();
//クリアボタンがある状態と無い状態の横幅
this.elNorm = this.$el.width();
this.elClear = this.$el.width() -
(parseInt(this.$el.css('font-size'), 10) * 2);
//Elements
$wrapper = $tour_module_jq(this.$el).parents(this.strategies.targetWrapperSelector);
$list = $wrapper.find(this.strategies.targetResultListSelector);
$overlay = $wrapper.find(this.strategies.targetTextOverlaySelector);
$clearBtn = $wrapper.find(this.strategies.targetClearButtonSelector);
//z-indexを調整する
zindex = $wrapper.css('z-index') -
$tour_module_jq('div.m_autocompleteWrapper').index($wrapper);
$wrapper.css({'z-index': zindex});
this.overLay = $overlay;
this.$clearBtn = $tour_module_jq($clearBtn).hide();
this.listView = new ListView($list, this);
this.listView.clear();
//Events
this.$el.on('keyup', bind(this.onKeyup, this));
this.$el.on('focus', bind(this.onFocus, this));
this.$el.on('blur', bind(this.onBlur, this));
this.$el.on('keydown', bind(this.onKeydown, this));
this.$el.on('keydown', bind(this.listView.onKeydown, this.listView));
this.$el.on('onSelect', bind(this.onSelect, this));
this.$el.on('clear', bind(this.clear, this));
if (isIE6() || isIE7() || isIE8() || isMobile) {
this.$clearBtn.remove();
}
var self = this;
this.overLay.on('mousedown touchend', function(e) {
//ie6 ie7 and tablet
if (isIE6() || isIE7() || isIE8() || isMobile) {
var focusableElements = $tour_module_jq(':focusable'),
next = focusableElements.index(self.$el) + 1;
focusableElements.eq(next).trigger('click');
return false;
}
$tour_module_jq(this).hide();
});
$tour_module_jq($clearBtn).on('click', bind(this.clear, this));
}
$tour_module_jq.extend(Completer.prototype, {
clear: function() {
this.overLay.trigger('mousedown');
this.listView.deactivate();
this.suggestList = null;
// this.$el.val('');
this.completed = false;
this.overLay.text('');
this.$clearBtn.hide();
},
find: function(text) {
var u = this.strategies.uniq;
return _.find(this.strategies.dictionary, function(o) {
return o[u] === text;
});
},
doRule: function(keyEvent) { //ruleを評価して結果をキャッシュ
var term = this.$el.val();
this.suggestList = [];
if (term.length) {
//if (keyEvent && this.term === term) return;
// Ignore shift-key or something.
this.term = term;
this.suggestList = this.strategies.rule(this.term, this);
return this.suggestList;
} else {
return false;
}
},
onBlur: function(e) {
if (isIE6() || isIE7() || isIE8() || isMobile) {
//何もしない
} else if (!this.suggestList) { // 候補が存在しない場合はクリアする。
this.clear();
} else if (_.size(this.suggestList) == 1) { //候補が一つの場合は確定する。
this.onSelect(this.suggestList[0][this.strategies.uniq], e);
} else if (_.size(this.suggestList) <= 0) {
this.clear();
}
var self = this;
self.listView.deactivate();
e.preventDefault();
},
onFocus: function() {
//ie6 ie7 and tablet
if (isIE6() || isIE7() || isIE8() || isMobile) {
var focusableElements = $tour_module_jq(':focusable'),
next = focusableElements.index(this.$el) + 1;
focusableElements.eq(next).trigger('click');
$tour_module_jq(this.$el).blur();
return false;
}
if (this.doRule() && _.size(this.suggestList) > 1) {
this.listView.clear();
this.listView.render(this.suggestList);
this.listView.active();
} else {
this.listView.deactivate();
}
},
onKeyup: function(e) {
e.preventDefault();
if (this.doRule() && e.keyCode !== 38 && e.keyCode !== 40) {
if (_.size(this.suggestList) > 0) { //todo
this.listView.clear();
this.listView.render(this.suggestList);
this.listView.active();
} else {
this.listView.deactivate();
}
} else {
if (e.keyCode == 46 || e.keyCode == 8) { //BS or DEL
this.listView.deactivate();
}
}
},
onKeydown: function(e) {
if (e.keyCode == 46 || e.keyCode == 8) { //BS or DEL
if (this.$el.val().length == this.$el.get(0).selectionStart &&
this.completed == true) {
e.preventDefault();
this.clear();
} else {
this.$clearBtn.hide();
this.completed = false;
}
} else {
if (this.completed === true) {
e.preventDefault();
}
}
},
onSelect: function(uid, ev) {
var uid, label, ieLabel;
if (uid == '') {
return false;
}
label = _.template(this.strategies.label, this.find(uid))
.replace(/\[\d{3}\]$/, '').replace(/\+\]$/, ']');
if ((isIE6() || isIE7() || isIE8() || isMobile) &&
label.length >= INPUT_LABEL_LENGTH) {
ieLabel = chopText(label, INPUT_LABEL_LENGTH) + '...';
}
if (!ev && !isFirefox()) {
ev = event;
}
this.completed = true;
this.overLay.text(ieLabel ? ieLabel : label);
this.overLay.show();
this.$el.val(label);
this.listView.deactivate();
this.$clearBtn.show();
if (isFirefox()) {
if (isDOMContentLoaded) {
var focusableElements = $tour_module_jq(':focusable');
focusableElements.eq(focusableElements.index(this.$el) + 1).focus();
}
} else {
if (event != null && event.type !== 'DOMContentLoaded') {
var focusableElements = $tour_module_jq(':focusable');
focusableElements.eq(focusableElements.index(this.$el) + 1).focus();
}
}
}
});
/**
* Completer's private functions
*/
var prepareWrapper = function($el) {
return $baseWrapper.clone().css('display', $el.css('display'));
};
return Completer;
})();
strategies = function(args) {
var defaults = {
targetNode : '',
targetWrapperSelector : 'div.m_autocompleteWrapper',
targetAutocompleteSelector : 'div.m_autocomplete',
targetResultDataSelector : 'span.m_resultData',
targetResultListSelector : 'ul.m_resultList',
targetResultListWrapperSelector : 'div.m_resultListWrapper',
targetTextOverlaySelector : 'div.m_textOverlay',
targetClearButtonSelector : 'a.m_clear',
scrollInertia : 0,
type: 'ja',
uniq: 'course_base_cd',
label: '<%= course_basic_name_jpn %>', //ラベルの書式フォーマット
dispLabel: '<%= course_basic_name_jpn %>', //ラベルの書式フォーマット
rule: function(text, obj) {
var startingCharacterCount = m_inttourModulePkg_suggestSetting.startingCharacterCount;
var startReg = new RegExp('^[\x20-\x7E]{' + startingCharacterCount + ',}.*$', 'g');
if (text.match(/^[^ -~。-゚]{1,}.*$/) ||
text.match(startReg)) {
var self = this;
var t = text.replace(/(\(|\)|\[|\]|\\|\^|\+|\*|\?)/g, '\\$&');
var r = new RegExp(t, 'i');
// 入力文字に一致する定義情報を絞込み
var filterResult = _(this.dictionary).chain().filter(function(w) {
if (w['course_basic_name_jpn'].match(r)) {
return true;
} else {
return false;
}
}).value();
return filterResult;
} else {
return false;
}
},
sortDisplayList: function(displayList) {
displayList.sort(function(item01,item02) {
if( item01['order'] < item02['order'] ) return -1;
if( item01['order'] > item02['order'] ) return 1;
return 0;
});
return displayList;
},
getFirstFewDatas: function(displayList, count) {
var firstFewDatas;
firstFewDatas = displayList.slice(0, count);
return firstFewDatas;
},
dictionary: m_inttourModulePkg_TourNameJson['data']
};
$tour_module_jq.extend(true,this,defaults)
$tour_module_jq.extend(true,this,args);
return this;
};
$tour_module_jq.fn.suggest = function(target, strategies) {
$tour_module_jq(this).attr('autocomplete', 'off');
new Completer(this, target, strategies);
return this;
};
})(window.jQuery || window.Zepto);