Существует ли стандартный компонент типа SpinEdit
Привет уважаемому XUL сообществу.
Подскажите пожалуйста существует ли в Mozilla такой контрол поле ввода с кнопочками стрелками сбоку, клик по которым наращивает (уменьшает) на определенную величину значение в поле ввода. Если такого контрола нет, то направьте, пожалуйста, в какую сторону копать, чтобы реализовать данную функциональность.
Заранее благодарен.
Подскажите пожалуйста существует ли в Mozilla такой контрол поле ввода с кнопочками стрелками сбоку, клик по которым наращивает (уменьшает) на определенную величину значение в поле ввода. Если такого контрола нет, то направьте, пожалуйста, в какую сторону копать, чтобы реализовать данную функциональность.
Заранее благодарен.
<spinbuttons> пока еще не работает: bug 155053
Так что придется делать самому, благо это несложно. У меня получился такой вот XBL:
<?xml version="1.0" encoding="UTF-8"?> <bindings id="spinboxBindings" xmlns="http://www.mozilla.org/xbl" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:xbl="http://www.mozilla.org/xbl"> <binding id="spinbox"> <resources> <stylesheet src="spinbox.css"/> </resources> <content> <xul:hbox flex="1"> <xul:textbox id="textField" flex="1" xbl:inherits="type,value,maxlength,timeout,oninput,onchange,disabled"/> <xul:vbox align="center"> <xul:image id="upButton" class="up"/> <xul:image id="downButton" class="down"/> </xul:vbox> </xul:hbox> </content> <implementation> <constructor> <![CDATA[ if (this.getAttribute('onup')) this.setAttribute('onup', this.getAttribute('onup')); if (this.getAttribute('ondown')) this.setAttribute('ondown', this.getAttribute('ondown')); ]]> </constructor> <property name="value" onget="return document.getAnonymousElementByAttribute(this, 'id', 'textField').value" onset="document.getAnonymousElementByAttribute(this, 'id', 'textField').value = val"/> </implementation> <handlers> <handler event="DOMAttrModified"> <![CDATA[ if (event.target == this && (event.attrName == 'onup' || event.attrName == 'ondown')) this[event.attrName] = new Function('event', event.newValue); ]]> </handler> <handler event="click"> <![CDATA[ var eventName = event.originalTarget.className; if (eventName != 'up' && eventName != 'down') return; var newEvent = document.createEvent('Events'); newEvent.initEvent(eventName, false, true); this.dispatchEvent(newEvent); if (typeof this['on' + eventName] == 'function') this['on' + eventName].call(this, newEvent); ]]> </handler> </handlers> </binding> </bindings>
Записываем это в spinbox.xml, к нему еще spinbox.css:
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); .up { list-style-image: url("spinbtn-up.gif") } .up:hover:active { list-style-image: url("spinbtn-up-act.gif") } .down { list-style-image: url("spinbtn-dn.gif") } .down:hover:active { list-style-image: url("spinbtn-dn-act.gif") }
Картинки качаем из вышеупомянутого бага (или делаем сами, как больше нравится). В стилях приложения/расширения прописываем:
spinbox { -moz-binding: url(spinbox.xml#spinbox); }
И теперь можем использовать новый элемент в своем XUL-файле:
<spinbox value="0" onup="this.value++" ondown="this.value--" />
Немного переделанный xbl, может, кому пригодится.
?xml version="1.0" encoding="UTF-8"?> <bindings id="spinboxBindings" xmlns="http://www.mozilla.org/xbl" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:xbl="http://www.mozilla.org/xbl"> <binding id="spinbox"> <resources> <stylesheet src="data:text/css;charset=utf-8;base64,QG5hbWVzcGFjZSB1cmwoImh0dHA6Ly93d3cubW96aWxsYS5vcmcva2V5bWFzdGVyL2dhdGVrZWVwZXIvdGhlcmUuaXMub25seS54dWwiKTsNCi51cCB7IGxpc3Qtc3R5bGUtaW1hZ2U6IHVybCgiZGF0YTppbWFnZS9naWYsR0lGODlhJTBEJTAwJTBCJTAwJTkxJTAwJTAwaWltJUNGJUNGJUQxJTAwJTAwJTAwJUEwJUEwJUE0ISVGOSUwNCUwMCUwMCUwMCUwMCUwMCUyQyUwMCUwMCUwMCUwMCUwRCUwMCUwQiUwMCUwMCUwMiUyMiU4QyU4RiUyNjElRUQlMEYlRDYlOUIlMjMlQjInJUEwdCVBMiUzQiVDQnUlNUUlQjUlODklMjZ5USUwRCVBOCVBRSUxMiUwMCVDNyVGMmIlRDZiJTAxJTAwJTNCIik7IH0NCi51cFtkaXNhYmxlZD0idHJ1ZSJdIHsgbGlzdC1zdHlsZS1pbWFnZTogdXJsKCJkYXRhOmltYWdlL2dpZixHSUY4OWElMEQlMDAlMEIlMDAlQjMlMDAlMDBpaW0lQ0YlQ0YlRDElMDAlMDAlMDAlQTAlQTAlQTQlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMkMlMDAlMDAlMDAlMDAlMEQlMDAlMEIlMDAlMDAlMDQlMUJQJUM4SSVFOSVCODglMEYlQTklM0IlQ0YlODIlRjYlNUQlMTMlMTglOTIlMTYlOEFWamclQkElMkYlQkNWdCUwNCUwMCUzQiIpOyB9DQoudXBbZGlzYWJsZWQ9InRydWUiXTpob3ZlcjphY3RpdmUgeyBsaXN0LXN0eWxlLWltYWdlOiB1cmwoImRhdGE6aW1hZ2UvZ2lmLEdJRjg5YSUwRCUwMCUwQiUwMCVCMyUwMCUwMGlpbSVDRiVDRiVEMSUwMCUwMCUwMCVBMCVBMCVBNCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUyQyUwMCUwMCUwMCUwMCUwRCUwMCUwQiUwMCUwMCUwNCUxQlAlQzhJJUU5JUI4OCUwRiVBOSUzQiVDRiU4MiVGNiU1RCUxMyUxOCU5MiUxNiU4QVZqZyVCQSUyRiVCQ1Z0JTA0JTAwJTNCIik7IH0NCi51cDpob3ZlcjphY3RpdmUgeyBsaXN0LXN0eWxlLWltYWdlOiB1cmwoImRhdGE6aW1hZ2UvZ2lmLEdJRjg5YSUwRCUwMCUwQiUwMCU5MSUwMCUwMCVGRiVGRiVGRmlpbSUwMCUwMCUwMCVBMCVBMCVBNCElRjklMDQlMDAlMDAlMDAlMDAlMDAlMkMlMDAlMDAlMDAlMDAlMEQlMDAlMEIlMDAlMDAlMDIhJTk0JThGJTE4JUNCJTFEJTE2JTg2JTlDJUYzJTg5OCUwMSVCNXglODBfQSVEMkdKJTlDRyU5NiclQjUlODlseDlOQiUxRiUwNSUwMCUzQiIpOyB9DQouZG93biB7IGxpc3Qtc3R5bGUtaW1hZ2U6IHVybCgiZGF0YTppbWFnZS9naWYsR0lGODlhJTBEJTAwJTBCJTAwJTkxJTAwJTAwaWltJUNGJUNGJUQxJTAwJTAwJTAwJUEwJUEwJUE0ISVGOSUwNCUwMCUwMCUwMCUwMCUwMCUyQyUwMCUwMCUwMCUwMCUwRCUwMCUwQiUwMCUwMCUwMiUyMyU4QyU4RiUyNjElRUQlMEYlRDYlOUIlMjMlQjIhJUIyJTE2VSVCNiVDRHUlRDclOTc5JUQ2JTE0NidleiVBQ1glMDElRjIlM0MlMkYlRTAtJTE0JTAwJTNCIik7IH0NCi5kb3duW2Rpc2FibGVkPSJ0cnVlIl0geyBsaXN0LXN0eWxlLWltYWdlOiB1cmwoImRhdGE6aW1hZ2UvZ2lmLEdJRjg5YSUwRCUwMCUwQiUwMCVCMyUwMCUwMGlpbSVDRiVDRiVEMSUwMCUwMCUwMCVBMCVBMCVBNCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUyQyUwMCUwMCUwMCUwMCUwRCUwMCUwQiUwMCUwMCUwNCUxQ1AlQzhJJUU5JUI4OCUwRiVBOSUzQiVERiU5NXAlN0QlRTAlODQlOTFlJTg2biVEQSVFQSU4OSU5RCUwQSVDN2NoRyUwMCUzQiIpOyB9DQouZG93bltkaXNhYmxlZD0idHJ1ZSJdOmhvdmVyOmFjdGl2ZSB7IGxpc3Qtc3R5bGUtaW1hZ2U6IHVybCgiZGF0YTppbWFnZS9naWYsR0lGODlhJTBEJTAwJTBCJTAwJUIzJTAwJTAwaWltJUNGJUNGJUQxJTAwJTAwJTAwJUEwJUEwJUE0JTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTAwJTJDJTAwJTAwJTAwJTAwJTBEJTAwJTBCJTAwJTAwJTA0JTFDUCVDOEklRTklQjg4JTBGJUE5JTNCJURGJTk1cCU3RCVFMCU4NCU5MWUlODZuJURBJUVBJTg5JTlEJTBBJUM3Y2hHJTAwJTNCIik7IH0NCi5kb3duOmhvdmVyOmFjdGl2ZSB7IGxpc3Qtc3R5bGUtaW1hZ2U6IHVybCgiZGF0YTppbWFnZS9naWYsR0lGODlhJTBEJTAwJTBCJTAwJTkxJTAwJTAwJUZGJUZGJUZGaWltJTAwJTAwJTAwJUEwJUEwJUE0ISVGOSUwNCUwMCUwMCUwMCUwMCUwMCUyQyUwMCUwMCUwMCUwMCUwRCUwMCUwQiUwMCUwMCUwMiElOTQlOEYlMTglQ0IlMUQlMTYlODYlOUMlRjMlODklMDglQjIlMDYlQzMlQzYlQjFxJTFENGklMTVZUiUxRSVDNSVBRSVFQ3k5TkIlMUYlMDUlMDAlM0IiKTsgfQ0KdGV4dGJveCB7IHBhZGRpbmc6IDBweDsgbWFyZ2luLXJpZ2h0OiAwcHg7IH0NCg%3D%3D"/> </resources> <content> <xul:hbox xbl:inherits="flex,width,disabled"> <xul:textbox id="textField" flex="1" xbl:inherits="type,value,maxlength,timeout,oninput,onchange,disabled"/> <xul:vbox pack="center"> <xul:image id="upButton" class="up" xbl:inherits="disabled"/> <xul:image id="downButton" class="down" xbl:inherits="disabled"/> </xul:vbox> </xul:hbox> </content> <implementation> <constructor> <![CDATA[ if (this. getAttribute ("onup")) this. setAttribute ("onup", this. getAttribute ("onup")); if (this. getAttribute ("ondown")) this. setAttribute ("ondown", this. getAttribute ("ondown")); ]]> </constructor> <property name="value" onget="return document.getAnonymousElementByAttribute(this,'id','textField').value" onset="document.getAnonymousElementByAttribute(this,'id','textField').value=val"/> <field name="pressed">false</field> <field name="_intervalID">false</field> </implementation> <handlers> <handler event="DOMAttrModified"> <![CDATA[ if (event. target == this && (event. attrName == "onup" || event. attrName == "ondown")) this [event. attrName] = new Function ("event", event. newValue); ]]> </handler> <handler event="click"> <![CDATA[ if (this. getAttribute ("disabled")) return; if (this. pressed) clearInterval (this. _intervalID); this. pressed = false; var eventName = event. originalTarget. className; if (eventName != "up" && eventName != "down") return; var newEvent = document. createEvent ("Events"); newEvent. initEvent (eventName, false, true); this. dispatchEvent (newEvent); if (typeof this ["on" + eventName] == "function") this ["on" + eventName]. call (this, newEvent); ]]> </handler> <handler event="mousedown"> <![CDATA[ if (this. getAttribute ("disabled")) return; var eventName = event. originalTarget. className; if (eventName != "up" && eventName != "down") return; this. pressed = true; var newEvent = document. createEvent ("Events"); newEvent. initEvent (eventName, false, true); this. dispatchEvent (newEvent); if (typeof this ["on" + eventName] == "function") { var x = this; this. _intervalID = setInterval (function () { if (x. pressed) x ["on" + eventName]. call (x, newEvent); }, 250); } ]]> </handler> <handler event="mouseup"> <![CDATA[ if (this. pressed) clearInterval (this. _intervalID); this. pressed = false; var eventName = event. originalTarget. className; if (eventName != "up" && eventName != "down") return; ]]> </handler> <handler event="mouseout"> <![CDATA[ try { var eventName = event. originalTarget. className; } catch (e) { return; } if (eventName != "up" && eventName != "down") return; if (this. pressed) clearInterval (this. _intervalID); this. pressed = false; ]]> </handler> </handlers> </binding> </bindings