mobile playground and some wip on architecture
This commit is contained in:
parent
68f91c3f1b
commit
bb63555ab2
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
.idea
|
||||
src/scss/*.css
|
||||
|
||||
|
167
playground/basic/basic.html
Normal file
167
playground/basic/basic.html
Normal file
@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>QUnit Example</title>
|
||||
<link href="../../src/scss/core.css" rel="stylesheet"/>
|
||||
<link href="../../src/scss/theme/default/layout.css" rel="stylesheet"/>
|
||||
|
||||
<script src="../../vendor/jquery-2.1.0.js" type="text/javascript"></script>
|
||||
<script src="../../src/js/util.js"></script>
|
||||
<script src="../../src/js/data.js"></script>
|
||||
<script src="../../src/js/selection.js"></script>
|
||||
<script src="../../src/js/results.js"></script>
|
||||
<script src="../../src/js/core.js"></script>
|
||||
|
||||
<script>
|
||||
$(function () {
|
||||
$("#source").on("change", function () {
|
||||
console.log("onchange");
|
||||
});
|
||||
new s2.Select($("#source"), {
|
||||
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<input type="text" style="width:300px" autofocus/><br/>
|
||||
<select style="width:300px" id="source">
|
||||
<option value="AK">Alaska</option>
|
||||
<option value="HI">Hawaii</option>
|
||||
<option value="CA">California</option>
|
||||
<option value="NV">Nevada</option>
|
||||
<option value="OR">Oregon</option>
|
||||
<option value="WA">Washington</option>
|
||||
<option value="AZ">Arizona</option>
|
||||
<option value="CO">Colorado</option>
|
||||
<option value="ID">Idaho</option>
|
||||
<option value="MT">Montana</option>
|
||||
<option value="NE">Nebraska</option>
|
||||
<option value="NM">New Mexico</option>
|
||||
<option value="ND">North Dakota</option>
|
||||
<option value="UT">Utah</option>
|
||||
<option value="WY">Wyoming</option>
|
||||
<option value="AL">Alabama</option>
|
||||
<option value="AR">Arkansas</option>
|
||||
<option value="IL">Illinois</option>
|
||||
<option value="IA">Iowa</option>
|
||||
<option value="KS">Kansas</option>
|
||||
<option value="KY">Kentucky</option>
|
||||
<option value="LA">Louisiana</option>
|
||||
<option value="MN">Minnesota</option>
|
||||
<option value="MS">Mississippi</option>
|
||||
<option value="MO">Missouri</option>
|
||||
<option value="OK">Oklahoma</option>
|
||||
<option value="SD">South Dakota</option>
|
||||
<option value="TX">Texas</option>
|
||||
<option value="TN">Tennessee</option>
|
||||
<option value="WI">Wisconsin</option>
|
||||
<option value="CT">Connecticut</option>
|
||||
<option value="DE">Delaware</option>
|
||||
<option value="FL">Florida</option>
|
||||
<option value="GA">Georgia</option>
|
||||
<option value="IN">Indiana</option>
|
||||
<option value="ME">Maine</option>
|
||||
<option value="MD">Maryland</option>
|
||||
<option value="MA">Massachusetts</option>
|
||||
<option value="MI">Michigan</option>
|
||||
<option value="NH">New Hampshire</option>
|
||||
<option value="NJ">New Jersey</option>
|
||||
<option value="NY">New York</option>
|
||||
<option value="NC">North Carolina</option>
|
||||
<option value="OH">Ohio</option>
|
||||
<option value="PA">Pennsylvania</option>
|
||||
<option value="RI">Rhode Island</option>
|
||||
<option value="SC">South Carolina</option>
|
||||
<option value="VT">Vermont</option>
|
||||
<option value="VA">Virginia</option>
|
||||
<option value="WV">West Virginia</option>
|
||||
</select><br/>
|
||||
<input type="text" style="width:300px"/><br/>
|
||||
<select style="width:300px">
|
||||
<option value="AK">Alaska</option>
|
||||
<option value="HI">Hawaii</option>
|
||||
<option value="CA">California</option>
|
||||
<option value="NV">Nevada</option>
|
||||
<option value="OR">Oregon</option>
|
||||
<option value="WA">Washington</option>
|
||||
<option value="AZ">Arizona</option>
|
||||
<option value="CO">Colorado</option>
|
||||
<option value="ID">Idaho</option>
|
||||
<option value="MT">Montana</option>
|
||||
<option value="NE">Nebraska</option>
|
||||
<option value="NM">New Mexico</option>
|
||||
<option value="ND">North Dakota</option>
|
||||
<option value="UT">Utah</option>
|
||||
<option value="WY">Wyoming</option>
|
||||
<option value="AL">Alabama</option>
|
||||
<option value="AR">Arkansas</option>
|
||||
<option value="IL">Illinois</option>
|
||||
<option value="IA">Iowa</option>
|
||||
<option value="KS">Kansas</option>
|
||||
<option value="KY">Kentucky</option>
|
||||
<option value="LA">Louisiana</option>
|
||||
<option value="MN">Minnesota</option>
|
||||
<option value="MS">Mississippi</option>
|
||||
<option value="MO">Missouri</option>
|
||||
<option value="OK">Oklahoma</option>
|
||||
<option value="SD">South Dakota</option>
|
||||
<option value="TX">Texas</option>
|
||||
<option value="TN">Tennessee</option>
|
||||
<option value="WI">Wisconsin</option>
|
||||
<option value="CT">Connecticut</option>
|
||||
<option value="DE">Delaware</option>
|
||||
<option value="FL">Florida</option>
|
||||
<option value="GA">Georgia</option>
|
||||
<option value="IN">Indiana</option>
|
||||
<option value="ME">Maine</option>
|
||||
<option value="MD">Maryland</option>
|
||||
<option value="MA">Massachusetts</option>
|
||||
<option value="MI">Michigan</option>
|
||||
<option value="NH">New Hampshire</option>
|
||||
<option value="NJ">New Jersey</option>
|
||||
<option value="NY">New York</option>
|
||||
<option value="NC">North Carolina</option>
|
||||
<option value="OH">Ohio</option>
|
||||
<option value="PA">Pennsylvania</option>
|
||||
<option value="RI">Rhode Island</option>
|
||||
<option value="SC">South Carolina</option>
|
||||
<option value="VT">Vermont</option>
|
||||
<option value="VA">Virginia</option>
|
||||
<option value="WV">West Virginia</option>
|
||||
</select>
|
||||
|
||||
<div style="width: 300px; height: 300px; border: 1px solid black" tabindex="10" id="outer">
|
||||
|
||||
<div style="width:100px; height: 100px; border: 1px solid blue" id="inner"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div style="position: absolute; left:0; top:0; background: white; border: 1px solid red;" id="focus-spy">hello there
|
||||
</div>
|
||||
<script>
|
||||
$(function () {
|
||||
var el = $("#focus-spy");
|
||||
$(window).bind("scroll", function () {
|
||||
el.css({top: $(window).scrollTop()});
|
||||
});
|
||||
window.setInterval(function () {
|
||||
var a = document.activeElement;
|
||||
var b = $(a);
|
||||
el.html("tag: " + a.tagName + " id:" + a.id + " class:" + b.attr("class") + " val:" + b.val());
|
||||
}, 100);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
158
playground/mobile/dropdown.html
Normal file
158
playground/mobile/dropdown.html
Normal file
@ -0,0 +1,158 @@
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<meta2s name="viewport" content="width=device-width">
|
||||
|
||||
<style>
|
||||
|
||||
|
||||
.dropdown {
|
||||
background-color: green;
|
||||
border: 3px solid red;
|
||||
position: fixed;
|
||||
padding: 10px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.search input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.results {
|
||||
overflow: scroll;
|
||||
border: 1px solid blue;
|
||||
}
|
||||
|
||||
.results ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.results li {
|
||||
border: 1px solid red;
|
||||
height: 10vh;
|
||||
height: 40px;
|
||||
margin: 3px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
<script src="jquery-2.1.0.js"></script>
|
||||
<script>
|
||||
$(function () {
|
||||
|
||||
function adjust() {
|
||||
var height = $(".dropdown").height();
|
||||
var searchHeight = $(".search").height();
|
||||
var needed = height - searchHeight;
|
||||
console.log(height, searchHeight, needed);
|
||||
$(".results").css({maxHeight: needed});
|
||||
}
|
||||
|
||||
|
||||
$(".dropdown")
|
||||
.on("scroll", function (e) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
});
|
||||
|
||||
$(".search input").on("blur", function() {
|
||||
$(".dropdown").hide();
|
||||
})
|
||||
|
||||
|
||||
//window.setInterval(adjust, 100);
|
||||
|
||||
$("#trigger").on("focus", function(e) {
|
||||
$(".dropdown").show();
|
||||
$(".search input").focus();
|
||||
$("head").append('<meta name = "viewport" content = "user-scalable=no, width=device-width, initial-scale=1.0, maximium-scale=1.0, minimum-scale=1.0"/>');
|
||||
adjust();
|
||||
});
|
||||
|
||||
$("#resize").on("click", adjust);
|
||||
|
||||
var a = 0;
|
||||
$(window).on("resize", function () {
|
||||
adjust();
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<form>
|
||||
<p>
|
||||
<input type="text"/>
|
||||
</p>
|
||||
<p>
|
||||
<input type="text"/>
|
||||
</p>
|
||||
<p>
|
||||
<input type="text" id="trigger"/>
|
||||
</p>
|
||||
<p>
|
||||
<input type="text"/>
|
||||
</p>
|
||||
</form>
|
||||
|
||||
<div class="dropdown" style="display:none">
|
||||
|
||||
<div class="result-list">
|
||||
<div class="search">
|
||||
<a href="#">reload</a><span id="message"></span><a href="#" id="resize">resize</a>
|
||||
<input type="text"/>
|
||||
</div>
|
||||
<div class="results">
|
||||
<ul>
|
||||
<li>Result 1</li>
|
||||
<li>Result 2</li>
|
||||
<li>Result 3</li>
|
||||
<li>Result 4</li>
|
||||
<li>Result 5</li>
|
||||
<li>Result 6</li>
|
||||
<li>Result 7</li>
|
||||
<li>Result 8</li>
|
||||
<li>Result 9</li>
|
||||
<li>Result 10</li>
|
||||
<li>Result 11</li>
|
||||
<li>Result 12</li>
|
||||
<li>Result 13</li>
|
||||
<li>Result 14</li>
|
||||
<li>Result 15</li>
|
||||
<li>Result 16</li>
|
||||
<li>Result 17</li>
|
||||
<li>Result 18</li>
|
||||
<li>Result 19</li>
|
||||
<li>Result 20</li>
|
||||
<li>Result 21</li>
|
||||
<li>Result 22</li>
|
||||
<li>Result 23</li>
|
||||
<li>Result 24</li>
|
||||
<li>Result 25</li>
|
||||
<li>Result 26</li>
|
||||
<li>Result 27</li>
|
||||
<li>Result 28</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
9111
playground/mobile/jquery-2.1.0.js
vendored
Normal file
9111
playground/mobile/jquery-2.1.0.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
130
src/js/core.js
Normal file
130
src/js/core.js
Normal file
@ -0,0 +1,130 @@
|
||||
(function ($, document, window, undefined) {
|
||||
|
||||
var s2 = window.s2 = window.s2 || {};
|
||||
var util = s2.util;
|
||||
var data = s2.data;
|
||||
var assert = util.assert;
|
||||
|
||||
s2.Select = util.clazz(util.Observable, {
|
||||
|
||||
construct: function (element, options) {
|
||||
this.super();
|
||||
|
||||
|
||||
this.isOpen = false;
|
||||
this.element = element;
|
||||
this.options = options;
|
||||
|
||||
var self = this;
|
||||
|
||||
this.data = new data.local(element);
|
||||
|
||||
var markup = self.render();
|
||||
|
||||
this.container = $(markup.toString());
|
||||
this.element.after(this.container);
|
||||
|
||||
var selectionContainer = this.container.find(".s2-selection-container");
|
||||
this.selection = new s2.SingleSelection();
|
||||
selectionContainer.html(this.selection.render().toString());
|
||||
this.selection.bind(this.container);
|
||||
this.selection.on("toggle", function () {
|
||||
self.toggle.apply(self, arguments)
|
||||
});
|
||||
|
||||
var resultsContainer = this.container.find(".s2-results-container");
|
||||
this.dropdown = new s2.Dropdown({select: element});
|
||||
this.dropdown.bind(this.container, resultsContainer);
|
||||
this.results = new s2.ResultList({data: this.data, select: element});
|
||||
this.results.decorateWith(new s2.ResultListWithSearch());
|
||||
resultsContainer.html(this.results.render().toString());
|
||||
this.results.bind(resultsContainer);
|
||||
this.results.on("select", function (params) {
|
||||
self.onOptionSelected.apply(self, arguments);
|
||||
self.close();
|
||||
});
|
||||
|
||||
this.results.on("close", function (params) {
|
||||
self.close(params);
|
||||
});
|
||||
|
||||
this.dropdown.hide();
|
||||
|
||||
this.value = this.data.lookup();
|
||||
|
||||
this.selection.update(this.value);
|
||||
|
||||
|
||||
this.container.width(this.element.width());
|
||||
this.element.hide();
|
||||
|
||||
// util.detectPlatform(this.container);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
return new util.Markup(
|
||||
"<div class='s2-container'>", //
|
||||
" <div class='s2-selection-container'></div>", //
|
||||
" <div class='s2-results-container s2-hidden'></div>", //
|
||||
"</div>");
|
||||
|
||||
},
|
||||
|
||||
bind: function () {
|
||||
this.selection.bind(this.container);
|
||||
this.dropdown.bind(this.container);
|
||||
this.results.bind(this.container);
|
||||
},
|
||||
|
||||
onOptionSelected: function (params) {
|
||||
assert.isObject(params, "params argument must be set");
|
||||
assert.isObject(params.data, "params.data must point to the option's data object");
|
||||
assert.isEvent(params.event, "params.event must point to the event that triggered the selection");
|
||||
assert.isElement(params.element, "opts.element must point to the option element");
|
||||
|
||||
if (this.element.prop("multiple")) {
|
||||
|
||||
} else {
|
||||
if (this.value.length) {
|
||||
$(this.value[0].element).removeProp("selected");
|
||||
}
|
||||
this.value = [params.data];
|
||||
$(this.value[0].element).prop("selected", true);
|
||||
|
||||
}
|
||||
|
||||
this.selection.update(this.value);
|
||||
|
||||
|
||||
},
|
||||
|
||||
toggle: function (event) {
|
||||
if (this.isOpen) {
|
||||
this.close();
|
||||
} else {
|
||||
this.open();
|
||||
}
|
||||
},
|
||||
|
||||
open: function (param) {
|
||||
if (this.isOpen) return;
|
||||
var self = this;
|
||||
this.dropdown.show();
|
||||
this.results.show();
|
||||
this.results.focus();
|
||||
this.isOpen = true;
|
||||
},
|
||||
|
||||
close: function (params) {
|
||||
if (!this.isOpen) return;
|
||||
var self = this;
|
||||
|
||||
// this.results.hide();
|
||||
this.dropdown.hide();
|
||||
this.isOpen = false;
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
})(jQuery, document, window);
|
45
src/js/data.js
Normal file
45
src/js/data.js
Normal file
@ -0,0 +1,45 @@
|
||||
(function ($, document, window, undefined) {
|
||||
|
||||
var s2 = window.s2 = window.s2 || {};
|
||||
var data = s2.data = s2.data || {};
|
||||
var util=s2.util;
|
||||
|
||||
data.local = util.clazz(Object, {
|
||||
construct: function (select) {
|
||||
this.select = select;
|
||||
},
|
||||
lookup: function () {
|
||||
var data = [], self = this;
|
||||
this.select.find(":selected").each(function () {
|
||||
data.push(self.item($(this)));
|
||||
});
|
||||
return data;
|
||||
},
|
||||
query: function (params) {
|
||||
var data = [], self = this;
|
||||
self.select.find("option").each(function () {
|
||||
var option = $(this);
|
||||
if (self.matches(params, option)) {
|
||||
data.push(self.item($(this)));
|
||||
}
|
||||
});
|
||||
return data;
|
||||
},
|
||||
matches: function (params, option) {
|
||||
if (params && params.term) {
|
||||
var text = option.text().toUpperCase();
|
||||
if (text.indexOf(params.term.toUpperCase()) >= 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
item: function (option) {
|
||||
return {value: option.attr("value"), text: option.text(), element: option.get(0)};
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery, document, window);
|
241
src/js/results.js
Normal file
241
src/js/results.js
Normal file
@ -0,0 +1,241 @@
|
||||
(function ($, document, window, undefined) {
|
||||
|
||||
var s2 = window.s2 = window.s2 || {};
|
||||
|
||||
var util = s2.util;
|
||||
var assert = util.assert;
|
||||
|
||||
|
||||
s2.Dropdown = util.clazz(util.Observable, {
|
||||
|
||||
construct: function (opts) {
|
||||
assert.isNotNull(opts, "opts parameter must be set");
|
||||
assert.isElement(opts.select, "opts.select must point to the select element");
|
||||
|
||||
this.super();
|
||||
|
||||
this.opts = opts;
|
||||
},
|
||||
|
||||
bind: function (container, tag) {
|
||||
assert.isElement(container, "container parameter must be set");
|
||||
assert.isElement(tag, "tag parameter must be set");
|
||||
|
||||
|
||||
this.container = container;
|
||||
this.element = tag;
|
||||
this.element.addClass("s2-dropdown");
|
||||
this.element.detach();
|
||||
this.element.removeClass("s2-hidden");
|
||||
|
||||
//util.detectPlatform(this.element);
|
||||
},
|
||||
|
||||
show: function () {
|
||||
var self = this;
|
||||
self.opts.select.parent("body").append(this.element);
|
||||
self.position();
|
||||
self.container.addClass("s2-active");
|
||||
},
|
||||
|
||||
hide: function () {
|
||||
var self = this;
|
||||
self.element.detach();
|
||||
self.container.removeClass("s2-active");
|
||||
|
||||
},
|
||||
position: function () {
|
||||
var self = this,
|
||||
container = self.container;
|
||||
|
||||
var
|
||||
offset = container.offset(),
|
||||
height = container.outerHeight(false),
|
||||
width = container.outerWidth(false),
|
||||
dropTop = offset.top + height,
|
||||
dropLeft = offset.left;
|
||||
|
||||
self.element.css({ top: dropTop, left: dropLeft, width: width });
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
s2.SearchField = util.clazz(util.Observable, {
|
||||
|
||||
construct: function (element) {
|
||||
this.super();
|
||||
var self = this;
|
||||
this.value = element.val();
|
||||
this.element = element;
|
||||
this.element.on("keyup.s2", function () {
|
||||
self.onKeyUp.apply(self, arguments)
|
||||
});
|
||||
},
|
||||
onKeyUp: function (e) {
|
||||
var self = this;
|
||||
if (self.value !== self.element.val()) {
|
||||
self.trigger("valueChanged", { oldValue: self.value, value: self.element.val(), event: e});
|
||||
self.value = self.element.val();
|
||||
}
|
||||
},
|
||||
focus: function () {
|
||||
this.element.focus();
|
||||
},
|
||||
val: function () {
|
||||
return this.element.val();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
s2.ResultList = util.clazz(util.Observable, {
|
||||
construct: function (opts) {
|
||||
assert.isNotNull(opts, "opts argument must be set");
|
||||
assert.isElement(opts.select, "opts.select must point to the select element");
|
||||
|
||||
this.super();
|
||||
|
||||
this.opts = opts;
|
||||
this.tag = util.tag();
|
||||
this.queryParams = {};
|
||||
},
|
||||
render: function () {
|
||||
return new util.Markup("<div class='s2-results' id='", this.tag, "'></div>");
|
||||
},
|
||||
bind: function (container) {
|
||||
var self = this;
|
||||
this.container = container;
|
||||
|
||||
this.element = container.find("#" + this.tag);
|
||||
assert.isElement(this.element, "Could not find result list element");
|
||||
|
||||
this.container.attr("tabindex", "0");
|
||||
this.container.on("keydown", function (e) {
|
||||
self.onKeyDown(e);
|
||||
});
|
||||
|
||||
this.container.on("focusout", function (e) {
|
||||
self.onBlur(e);
|
||||
});
|
||||
|
||||
this.element.on("click", function () {
|
||||
self.onClick.apply(self, arguments);
|
||||
});
|
||||
|
||||
//util.detectPlatform(this.element);
|
||||
},
|
||||
show: function () {
|
||||
var self = this;
|
||||
self.update();
|
||||
},
|
||||
update: function () {
|
||||
var self = this;
|
||||
|
||||
var index = 0;
|
||||
self.data = [];
|
||||
|
||||
self.element.find(".s2-options").remove();
|
||||
var options = $("<ul class='s2-options'></ul>");
|
||||
self.element.append(options);
|
||||
|
||||
$.each(self.query(), function () {
|
||||
var option = $(["<li class='s2-option' data-s2-index='" + index, "'>", this.text, "</li>"].join(""));
|
||||
options.append(option);
|
||||
self.data.push(this);
|
||||
index++;
|
||||
});
|
||||
|
||||
options.find("li").first().addClass("s2-highlighted");
|
||||
},
|
||||
query: function () {
|
||||
return this.opts.data.query(this.queryParams);
|
||||
},
|
||||
onClick: function (event) {
|
||||
var target = $(event.target);
|
||||
var option = target.is(".s2-option") ? target : target.parents(".s2-option").first();
|
||||
if (option.length > 0) {
|
||||
// option clicked
|
||||
this.trigger("select", { event: event, element: option, data: this.data[option.data("s2-index")] });
|
||||
}
|
||||
|
||||
},
|
||||
focus: function () {
|
||||
var self = this;
|
||||
this.container.focus();
|
||||
},
|
||||
onBlur: function (event) {
|
||||
var self = this;
|
||||
window.setTimeout(function () {
|
||||
// done in a time out because we want the current focusout event processed so that
|
||||
// document.activeElement points to element that received the new focus
|
||||
//console.log("blur event", event);
|
||||
//console.log("blur container", self.container.get(0));
|
||||
//console.log("blur active", document.activeElement);
|
||||
//console.log("blur contains", $.contains(self.container.get(0), document.activeElement));
|
||||
if (!$.contains(self.container.get(0), document.activeElement) && self.container.get(0) !== document.activeElement) {
|
||||
self.trigger("close", {event: event});
|
||||
}
|
||||
}, 0);
|
||||
},
|
||||
onKeyDown: function (event) {
|
||||
if (event.which == util.key.DOWN) {
|
||||
this.moveHighlight({delta: 1, event: event});
|
||||
event.preventDefault();
|
||||
|
||||
} else if (event.which === util.key.UP) {
|
||||
this.moveHighlight({delta: -1, event: event});
|
||||
event.preventDefault();
|
||||
} else if (event.which === util.key.ENTER) {
|
||||
this.selectHighlighted({event: event});
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
selectHighlighted: function (param) {
|
||||
var option = this.element.find(".s2-highlighted").first();
|
||||
this.trigger("select", { event: param.event, element: option, data: this.data[option.data("s2-index")] });
|
||||
},
|
||||
moveHighlight: function (param) {
|
||||
var delta = param.delta;
|
||||
var current = this.element.find(".s2-highlighted");
|
||||
var next = null;
|
||||
if (delta === 1) {
|
||||
next = current.next();
|
||||
} else {
|
||||
next = current.prev();
|
||||
}
|
||||
|
||||
current.removeClass("s2-highlighted");
|
||||
next.addClass("s2-highlighted");
|
||||
}
|
||||
});
|
||||
|
||||
s2.ResultListWithSearch = util.clazz(Object, {
|
||||
render: function () {
|
||||
this.searchTag = util.tag();
|
||||
var markup = new util.Markup(
|
||||
"<div class='s2-search'>", //
|
||||
" <input type='text' id='", this.searchTag, "'/>", //
|
||||
" <a href='#' class='s2-test'>click me</a>", //
|
||||
" {{original}}", //
|
||||
"</div>");
|
||||
|
||||
markup.replace("original", this.decorated());
|
||||
return markup;
|
||||
},
|
||||
bind: function (container) {
|
||||
this.decorated(container);
|
||||
var self = this;
|
||||
this.searchField = new s2.SearchField(container.find("#" + this.searchTag));
|
||||
this.searchField.on("valueChanged", function (params) {
|
||||
self.onSearch.apply(self, arguments);
|
||||
});
|
||||
},
|
||||
focus: function () {
|
||||
this.searchField.focus();
|
||||
},
|
||||
onSearch: function (params) {
|
||||
this.delegate.queryParams.term = this.searchField.val();
|
||||
this.delegate.update();
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery, document, window);
|
40
src/js/selection.js
Normal file
40
src/js/selection.js
Normal file
@ -0,0 +1,40 @@
|
||||
(function ($, document, window, undefined) {
|
||||
|
||||
var s2 = window.s2 = window.s2 || {};
|
||||
var util = s2.util;
|
||||
|
||||
s2.SingleSelection = util.clazz(util.Observable, {
|
||||
init: function () {
|
||||
util.Observable.prototype.init.apply(this);
|
||||
this.tag = util.tag();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
return new util.Markup("<div class='s2-single-select' id='", this.tag, "'><div class='s2-selection'></div></div>");
|
||||
},
|
||||
|
||||
bind: function (container) {
|
||||
this.element = container.find("#" + this.tag);
|
||||
|
||||
var self = this;
|
||||
this.element.on("click", function () {
|
||||
self.onClick.apply(self, arguments);
|
||||
});
|
||||
},
|
||||
|
||||
update: function (data) {
|
||||
var text = "";
|
||||
if (data.length == 0) {
|
||||
// clear
|
||||
} else {
|
||||
text = data[0].text;
|
||||
}
|
||||
this.element.find(".s2-selection").html(text);
|
||||
},
|
||||
|
||||
onClick: function (event) {
|
||||
this.trigger("toggle", {event: event});
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery, document, window);
|
238
src/js/util.js
Normal file
238
src/js/util.js
Normal file
@ -0,0 +1,238 @@
|
||||
(function ($, document, window, undefined) {
|
||||
|
||||
var s2 = window.s2 = window.s2 || {};
|
||||
var util = s2.util = s2.util || {};
|
||||
|
||||
util.methods = function (object) {
|
||||
var methods = {};
|
||||
var proto = object.__proto__;
|
||||
while (proto !== Object.prototype) {
|
||||
for (var methodName in proto) {
|
||||
if (!methods[methodName] && typeof(proto[methodName]) === "function") {
|
||||
methods[methodName] = proto[methodName];
|
||||
}
|
||||
}
|
||||
proto = proto.__proto__;
|
||||
|
||||
}
|
||||
return methods;
|
||||
};
|
||||
|
||||
util.decorate = function (decorator) {
|
||||
var decoratorMethods = util.methods(decorator);
|
||||
for (var methodName in decoratorMethods) {
|
||||
var decoratorMethod = decoratorMethods[methodName];
|
||||
if (typeof(decoratorMethod) === "function" && !(methodName === "construct" || methodName.name === "onDelegateAttached" || methodName === "decorateWith")) {
|
||||
this[methodName] = (function (prototype, methodName, method, decorator) {
|
||||
return function () {
|
||||
var delegate = this;
|
||||
try {
|
||||
decorator.decorated = function () {
|
||||
return prototype.apply(delegate, arguments);
|
||||
}
|
||||
return method.apply(decorator, arguments);
|
||||
} finally {
|
||||
delete decorator.decorated;
|
||||
}
|
||||
};
|
||||
})(this[methodName], methodName, decoratorMethod, decorator);
|
||||
this[methodName].displayName = methodName + "#decorator";
|
||||
}
|
||||
}
|
||||
|
||||
if (decorator.onDelegateAttached) {
|
||||
decorator.onDelegateAttached(this);
|
||||
}
|
||||
|
||||
decorator.delegate = this;
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
util.uid = (function () {
|
||||
var id = 0;
|
||||
return function () {
|
||||
return id++;
|
||||
};
|
||||
}());
|
||||
|
||||
util.tag = function () {
|
||||
return "s2-x-" + util.uid();
|
||||
}
|
||||
|
||||
util.marker = {};
|
||||
|
||||
util.clazz = function (SuperClass, methods) {
|
||||
|
||||
var constructor = function () {
|
||||
if (arguments.length == 1 && arguments[0] == util.marker) {
|
||||
return;
|
||||
}
|
||||
if (this.construct) {
|
||||
this.construct.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
constructor.prototype = SuperClass !== Object ? new SuperClass(util.marker) : new SuperClass;
|
||||
|
||||
for (var methodName in methods) {
|
||||
|
||||
constructor.prototype[methodName] = (function (prototype, methodName, method) {
|
||||
return function () {
|
||||
var currentSuper = this.super;
|
||||
try {
|
||||
this.super = prototype;
|
||||
return method.apply(this, arguments);
|
||||
} finally {
|
||||
this.super = currentSuper;
|
||||
}
|
||||
};
|
||||
})(constructor.prototype[methodName], methodName, methods[methodName]);
|
||||
|
||||
constructor.prototype[methodName].displayName = methodName;
|
||||
}
|
||||
|
||||
if (!constructor.prototype.decorateWith) {
|
||||
constructor.prototype.decorateWith = util.decorate;
|
||||
}
|
||||
|
||||
return constructor;
|
||||
|
||||
};
|
||||
|
||||
util.shift = (function () {
|
||||
var arrayShift = Array.prototype.shift;
|
||||
return function (array) {
|
||||
arrayShift.apply(array);
|
||||
return array;
|
||||
}
|
||||
}());
|
||||
|
||||
util.Observable = util.clazz(Object, {
|
||||
construct: function () {
|
||||
this.listeners = {};
|
||||
},
|
||||
on: function (event, callback) {
|
||||
if (event in this.listeners) {
|
||||
this.listeners[event].push(callback);
|
||||
} else {
|
||||
this.listeners[event] = [callback];
|
||||
}
|
||||
},
|
||||
trigger: function (event) {
|
||||
if (event in this.listeners) {
|
||||
this.invoke(this.listeners[event], util.shift(arguments));
|
||||
}
|
||||
if ("*" in this.listeners) {
|
||||
this.invoke(this.listeners["*"], arguments);
|
||||
}
|
||||
},
|
||||
invoke: function (listeners, params) {
|
||||
for (var i = 0, len = listeners.length; i < len; i++) {
|
||||
listeners[i].apply(this, params);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
util.Markup = util.clazz(Object, {
|
||||
construct: function () {
|
||||
this.data = [];
|
||||
if (arguments.length > 0) this.append.apply(this, arguments);
|
||||
},
|
||||
append: function () {
|
||||
var parts = null;
|
||||
if (arguments.length === 1) {
|
||||
if ($.isArray(arguments[0])) {
|
||||
parts = arguments[0];
|
||||
} else {
|
||||
this.appendPart(arguments[0]);
|
||||
return this;
|
||||
}
|
||||
} else {
|
||||
parts = arguments;
|
||||
}
|
||||
for (var i = 0, len = parts.length; i < len; i++) {
|
||||
this.appendPart(parts[i]);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
appendPart: function (part) {
|
||||
if (typeof(part) === "string") {
|
||||
this.data.push(part);
|
||||
} else {
|
||||
this.data.push("" + part);
|
||||
}
|
||||
},
|
||||
replace: function (id, markup) {
|
||||
var key = "{{" + id + "}}";
|
||||
for (var i = 0, len = this.data.length; i < len; i++) {
|
||||
if (this.data[i].trim().indexOf(key) === 0) {
|
||||
markup.data.unshift(1);
|
||||
markup.data.unshift(i);
|
||||
Array.prototype.splice.apply(this.data, markup.data);
|
||||
//this.data.splice(i, 1, markup.data);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
toString: function () {
|
||||
return this.data.join("");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var assert = util.assert = {
|
||||
error: function (value, error) {
|
||||
throw error + " (current value: " + value + ")";
|
||||
},
|
||||
isTrue: function (value, error) {
|
||||
if (value !== true) assert.error(value, error);
|
||||
},
|
||||
isNotNull: function (value, error) {
|
||||
assert.isTrue(value !== undefined && value !== null, error);
|
||||
},
|
||||
isInstanceOf: function (type, value, error) {
|
||||
assert.isNotNull(value, error);
|
||||
assert.isTrue(value instanceof type, error);
|
||||
},
|
||||
isObject: function (value, error) {
|
||||
return assert.isInstanceOf(Object, value, error);
|
||||
},
|
||||
isElement: function (value, error) {
|
||||
assert.isInstanceOf($, value, error);
|
||||
assert.isTrue(value.length > 0, error);
|
||||
},
|
||||
isEvent: function (value, error) {
|
||||
return assert.isInstanceOf($.Event, value, error);
|
||||
},
|
||||
isString: function (value, error) {
|
||||
return assert.isTrue(typeof(value) === "string" || typeof(value) === "String");
|
||||
},
|
||||
isFunction: function (value, error) {
|
||||
if (!$.isFunction(value)) throw error;
|
||||
}
|
||||
};
|
||||
|
||||
util.key = {
|
||||
TAB: 9,
|
||||
ENTER: 13,
|
||||
ESC: 27,
|
||||
SPACE: 32,
|
||||
LEFT: 37,
|
||||
UP: 38,
|
||||
RIGHT: 39,
|
||||
DOWN: 40,
|
||||
SHIFT: 16,
|
||||
CTRL: 17,
|
||||
ALT: 18,
|
||||
PAGE_UP: 33,
|
||||
PAGE_DOWN: 34,
|
||||
HOME: 36,
|
||||
END: 35,
|
||||
BACKSPACE: 8,
|
||||
DELETE: 46
|
||||
};
|
||||
|
||||
})(jQuery, document, window);
|
96
src/scss/core.scss
Normal file
96
src/scss/core.scss
Normal file
@ -0,0 +1,96 @@
|
||||
.s2-container {
|
||||
margin: 0;
|
||||
position: relative;
|
||||
zoom: 1;
|
||||
vertical-align: middle;
|
||||
|
||||
&.s2-active {
|
||||
border: 1px solid #5897fb;
|
||||
border-top: bottom;
|
||||
}
|
||||
|
||||
.s2-single-select {
|
||||
display: block;
|
||||
height: 26px;
|
||||
padding: 0 0 0 8px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
border: 1px solid #aaa;
|
||||
white-space: nowrap;
|
||||
line-height: 26px;
|
||||
color: #444;
|
||||
text-decoration: none;
|
||||
|
||||
border-radius: 4px;
|
||||
|
||||
background-clip: padding-box;
|
||||
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
background-color: #fff;
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.5, #fff));
|
||||
background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 50%);
|
||||
background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 50%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#ffffff', endColorstr = '#eeeeee', GradientType = 0);
|
||||
background-image: linear-gradient(to top, #eee 0%, #fff 50%);
|
||||
|
||||
.s2-selection {
|
||||
margin-right: 26px;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
|
||||
white-space: nowrap;
|
||||
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.s2-open {
|
||||
.select2-container-active .select2-choice,
|
||||
.select2-container-active .select2-choices {
|
||||
border: 1px solid #5897fb;
|
||||
outline: none;
|
||||
|
||||
-webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3);
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, .3);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.s2-search {
|
||||
input {
|
||||
-webkit-box-sizing: border-box; /* webkit */
|
||||
-moz-box-sizing: border-box; /* firefox */
|
||||
box-sizing: border-box; /* css3 */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.s2-dropdown {
|
||||
width: 100%;
|
||||
margin-top: -1px;
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
overflow: scroll;
|
||||
|
||||
background: #fff;
|
||||
color: #000;
|
||||
border: 1px solid #5897fb;
|
||||
border-top: none;
|
||||
|
||||
border-radius: 0 0 4px 4px;
|
||||
|
||||
-webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
|
||||
box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
|
||||
}
|
||||
|
||||
|
||||
.s2-hidden {
|
||||
display: none;
|
||||
}
|
11
src/scss/theme/default/layout.scss
Normal file
11
src/scss/theme/default/layout.scss
Normal file
@ -0,0 +1,11 @@
|
||||
.s2-highlighted {
|
||||
background-color: #5897fb;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.s2-dropdown {
|
||||
max-height: 300px;
|
||||
overflow: scroll;
|
||||
|
||||
}
|
||||
|
9111
vendor/jquery-2.1.0.js
vendored
Normal file
9111
vendor/jquery-2.1.0.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user