Light12306/Web12306/js/ui/widget_cityselector.js
2014-08-13 00:14:00 +08:00

407 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

define(function (require, exports) {
var $html = '<div id="city_selector"><ul class="city-tab-nav"><li class="selected">常用</li><li data-code="A-E">A-E</li><li data-code="F-J">F-J</li><li data-code="K-O">K-O</li><li data-code="P-T">P-T</li><li data-code="U-Z">U-Z</li></ul><div class="recent-city-list"><p>最近查询</p><dl><dd>TEST</dd></dl></div><div class="city-pop"><p>常用城市</p><ul class="city-list-container"></ul></div><div class="city-search"><p>站点列表</p><ul class="city-list-container"></ul><div class="city-list-pager"><button class="city-prev" disabled="disabled">上一页</button><button class="city-next">下一页</button></div></div></div>';
var selector;
var data = require("../data.js");
var parser = require("../platform/parser.js");
var cityMap = data.cities;
var citydata = data.citydata.data;
var popcity = data.citydata.popcity;
var maxRecentCity = 8;
var sessMgr = require("../account/sessionMgr.js");
var CitySelector = function (options) {
var that = this;
var dom = $("#city_selector");
var currentList = null;
var currentPage = 1;
var totalPage = 1;
var pageSize = options.rows * 4;
var target = null;
var prevTab = null;
var searchKey;
var tplRecentCity = doT.template("{{~it:c:i}}<dd data-code='{{=c.c}}'>{{!c.n}}</dd>{{~}}");
var cp;
var container = $("#city_selector");
var initRecentCity = function () {
cp = sessMgr.current;
container.find("dd").remove();
if (!cp || !cp.recentCity)
return;
var cities = _.filter(cp.recentCity.map(function (e) {
return cityMap[e];
}), function (e) { return e != null; });
container.find("dl").html(tplRecentCity(cities));
};
initRecentCity();
sessMgr.on("sessionChanged", initRecentCity);
this.addCityToRecent = function (code) {
if (!code || !cp)
return;
cp.recentCity = cp.recentCity || [];
var idx = _.indexOf(cp.recentCity, code);
if (idx != -1) {
return;
}
container.find("dd[data-code='" + code + "']").remove();
cp.recentCity.unshift(code);
sessMgr.save();
container.find("dl").prepend(tplRecentCity([cityMap[code]]));
};
that.findExtractCity = function (val) {
if (!val)
return null;
if (cityMap[val])
return cityMap[val];
for (var c in cityMap) {
var city = cityMap[c];
if (city.p === val || city.c === val || city.n === val)
return city;
}
return null;
};
that.getSelectedCity = function () {
var ele = $(this);
var val = ele.val();
var city = null;
//取得当前选择的城市。逻辑:如果有输入内容,则查找对应的城市是否存在,存在则直接返回;
//否则如果当前输入不为空,则找已选择的,有则返回,没有则取列表第一个返回;
//如果都无法返回则返回null
if (val) {
city = that.findExtractCity(val);
}
if (city === null) {
//查找已经选中的
var e = dom.find("dd.selected[data-code]:visible, li.selected[data-code]:visible");
if (e.length) {
var code = e.attr("data-code");
city = that.findExtractCity(code);
}
}
if (city === null) {
var nodes = that.currentShownCities;
if (nodes.length) {
city = that.findExtractCity(nodes.eq(0).attr("data-code"));
}
}
return city;
};
that.performSearch = function () {
target = $(this);
var key = target.val().replace(/\s/g, "");
if (key === searchKey) return;
searchKey = key;
if (!key) {
that.switchTab(prevTab);
return;
}
//清空选择
that.switchTab();
dom.find(".city-search").show().find(">p").html("搜索“" + key + "”");
//搜索城市
key = key.toUpperCase();
var lkey = key.toLowerCase();
currentList = _.filter(_.values(cityMap), function (e) {
return e.p.indexOf(lkey) != -1 ||
e.n.indexOf(key) != -1 ||
e.c.indexOf(key) != -1 ||
e.h.indexOf(lkey) != -1;
});
parser.sortCity(currentList);
currentPage = 0;
totalPage = Math.ceil(currentList.length / pageSize);
that.renderPage(1);
};
that.showPopup = function (ele) {
if (selector.isVisible)
return;
searchKey = null;
that.switchTab(dom.find(".city-tab-nav li:first"));
dom.find(".city-list-container li, dd[data-code]").removeClass("selected");
var offset = ele.offset();
dom.css({ left: offset.left + "px", top: (offset.top + ele.height()) + "px" });
dom.addClass("open");
target = ele;
};
that.hidePopup = function (force) {
if (!target)
return;
dom.removeClass("open");
//验证
var str = target.val();
var city = that.findExtractCity(str);
if (!city) {
target.val("");
target.attr("data-code", "");
} else {
target.val(city.n);
target.attr("data-code", city.c);
}
target[0].dispatchEvent(new UIEvent("change"));
if (force) {
dom.css("top", "-2000px");
}
};
that.switchTab = function (tab) {
dom.find(".city-tab-nav li").removeClass("selected");
dom.find(".city-search, .city-pop, .recent-city-list").hide();
if (!tab)
return;
tab.addClass("selected");
prevTab = tab;
var code = tab.attr("data-code");
currentPage = 0;
if (code) {
dom.find(".city-search>p").html("站点列表");
currentList = _.values(citydata[code]);
totalPage = Math.ceil(currentList.length / pageSize);
that.renderPage(1);
dom.find(".city-search").show();
} else {
currentList = null;
dom.find(".city-pop, .recent-city-list").show();
}
dom.find(".city-list-container ul, dd[data-code]").removeClass("selected");
that.currentShownCities = null;
};
that.renderPage = function (page) {
/// <summary>切换当前的分页</summary>
if (page < 1 || page === currentPage || page > totalPage)
return;
currentPage = page;
//绑定数据
var html = [];
var listCount = 0;
for (var i = (currentPage - 1) * pageSize; i < currentPage * pageSize && i < currentList.length; i++) {
var city = currentList[i];
listCount++;
html.push("<li data-code='" + city.c + "' data-py='" + city.p + "' data-name='" + city.n + "' data-fl='" + city.h + "'>" + city.n + "</li>");
}
if (listCount % 4 !== 0) {
for (var i = 0; i < 4 - listCount % 4; i++) {
html.push("<li></li>");
}
}
dom.find(".city-search ul").empty().append(html.join(""));
//上一页下一页可用性
$("button.city-prev")[0].disabled = currentPage <= 1;
$("button.city-next")[0].disabled = currentPage >= totalPage - 1;
that.currentShownCities = null;
};
that.showNextPage = function () {
that.renderPage(currentPage + 1);
};
that.showPrevPage = function () {
that.renderPage(currentPage - 1);
};
that.selectNext = function (offset) {
offset = offset || 1;
//当前的列表
var eles = dom.find("div.recent-city-list:visible dd[data-code], ul.city-list-container:visible li[data-code]");
var current = eles.filter(".selected");
var nextSelect = null;
if (!current.length) {
//尚没有选择
if (offset > 0) {
//向下移动,则默认选择第一个
(nextSelect = eles.first()).addClass("selected");
} else {
(nextSelect = eles.last()).addClass("selected");
}
} else {
var index = eles.index(current);
index += offset;
if (index < 0) {
if (currentPage > 1) {
that.showPrevPage();
(nextSelect = dom.find("div.city-search ul.city-list-container li[data-code]:last")).addClass("selected");
}
} else if (index >= eles.length) {
if (currentPage < totalPage) {
that.showNextPage();
(nextSelect = dom.find("div.city-search ul.city-list-container li[data-code]:first")).addClass("selected");
}
} else {
current.removeClass("selected");
nextSelect = eles.eq(index).addClass("selected");
}
}
if (nextSelect) {
that.selectToTarget(nextSelect.attr("data-code"));
}
};
dom.find("button.city-prev").click(that.showPrevPage);
dom.find("button.city-next").click(that.showNextPage);
Object.defineProperty(this, "isVisible", {
get: function () {
return dom.is(":visible");
}
});
//当前显示的城市节点
var _currnetShownNodes;
Object.defineProperty(this, "currentShownCities", {
get: function () {
return _currnetShownNodes || (_currnetShownNodes = dom.find("div.recent-city-list:visible dd[data-code], ul.city-list-container:visible li[data-code]"));
},
set: function (value) {
_currnetShownNodes = value;
}
});
dom.find(".city-tab-nav li").click(function () {
var tab = $(this);
if (tab.hasClass("selected"))
return;
selector.switchTab(tab);
});
that.selectToTarget = function (city, ele) {
ele = ele || target;
if (!ele)
return;
if (typeof (city) === "string")
city = that.findExtractCity(city);
if (!city)
city = that.getSelectedCity.call(ele);
if (!city)
return;
ele.data("data-code", city.c);
ele.val(city.n);
var ce = new UIEvent("change");
ele[0].dispatchEvent(ce);
};
$(document).on("click", ".recent-city-list dd[data-code], .city-list-container li[data-code]", function () {
//选定城市
that.selectToTarget(this.dataset.code);
that.hidePopup(true);
if (target) {
target[0].blur();
}
});
$("#city_selector").mousedown(function (e) {
e.stopPropagation();
e.preventDefault();
});
return this;
};
var init = function(args) {
$("body").append($html);
//初始化常用城市
(function() {
var html = [];
_.each(popcity, function(c) {
var city = cityMap[c];
html.push("<li data-code='" + city.c + "' data-py='" + city.p + "' data-name='" + city.n + "' data-fl='" + city.h + "'>" + city.n + "</li>");
});
if (popcity.length % 4 !== 0) {
for (var i = 0; i < 4 - popcity.length % 4; i++) {
html.push("<li></li>");
}
}
$("#city_selector .city-pop ul").append(html.join(""));
})();
args = $.extend({ rows: 9 }, args);
selector = new CitySelector(args);
exports.cityui = selector;
};
init();
exports.init = function (eleSelector) {
$(document).on("focus", eleSelector, function () {
selector.showPopup($(this));
setTimeout((function () { this.select(); }).bind(this), 1);
}).on("blur", eleSelector, function () {
selector.hidePopup();
}).on("keydown", eleSelector, function (e) {
var code = e.key || e.keyCode;
if ((code >= 37 && code <= 40) || code === 13) {
e.stopPropagation();
e.preventDefault();
switch (code) {
case 37:
//<
selector.selectNext(-1);
break;
case 38:
//^
selector.selectNext(-4);
break;
case 39:
//>
selector.selectNext();
break;
case 40:
//下
selector.selectNext(4);
break;
case 13:
//选定
selector.selectToTarget();
this.blur();
break;
default:
}
return false;
}
}).on("keyup", eleSelector, function (e) {
var code = e.key || e.keyCode;
if ((code >= 65 && code <= 90) || code === 8 || e.ctrlKey || code === 32)
selector.performSearch.call(this);
}).on("input", eleSelector, function (e) {
selector.performSearch.call(this);
});
}
});