Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
- [Коротко](#summary) - [Инициализация](#init) - [Контролы](#controls) - [Зависимости](#dependencies) - [Повторения](#repeats) - [Концепция](#common) - [Режим диагностики](#debug)
Expromptum — библиотека JavaScript, предназначенная для расширения функциональности работы элементов в HTML.
Использует библиотеку jQuery для работы с элементами (версии 1.8.0 и выше).
Чтобы использовать библиотеку надо подключить ее к странице содержащей соответствующий HTML и выполнить инициализацию.
<script src="jquery.js"></script>
<script src="expromptum.js"></script>
<style>
.field {position: relative;}
.show_on_blured_and_invalid {display: none;}
.blured.invalid .show_on_blured_and_invalid {display: block; position: absolute; left: 0; bottom: -3em;}
</style>
...
<form method="post">
<span class="field">
<input name="email" placeholder="Email" data-xp="type: 'email', required: true"/>
<span class="show_on_blured_and_invalid">Enter a valid email address.</span>
</span>
<span class="field">
<input name="password" placeholder="Password" type="password" data-xp="required: true"/>
</span>
<input type="submit" value="Sign in" data-xp="enabled_on_completed: true"/>
</form>
...
<script>
expromptum();
</script>
Тип контрола определяется CSS-селектором или значением свойства type
в атрибуте data-xp
. Для остальных свойств контрола указаны противоположные или отличные от используемых по умолчанию значения.
<strong for="sheet_2">Sheet 2</strong>
<div class="sheet" id="sheet_1" data-xp="type: 'sheet'"></div>
<div class="sheet selected" id="sheet_2" data-xp="type: 'sheet'"></div>
Без указания зависимости computed, в этом контроле мало смысла.
Button
Button
<div><a href="#controls.submit">Кнопка отправки</a></div>
```html
<input type="submit" data-xp="type: 'submit'"/>
Для получения значений контролов в выражениях используются CSS-селекторы по атрибутам (например, [name=some]
) и [this]
для данного контрола.
<div data-xp="
name: 'имя',
repeat: {
id: 'идентификатор',
min: 1,
max: 10,
reset: true,
template: true
}
">
...
<button class="repeat_append_button">+</button>
<button class="repeat_remove_button">−</button>
</div>
Возвращает список expromptum контролов.
expromptum()
data-xp
или подходящие под CSS-селекторы по умолчанию, заданные в контролах.expromptum(selector[, expromptum object | jQuery object])
expromptum(element | elements array | jQuery object)
Возвращает массив объектов с дополнительными методами, позволяющими добавлять в него только уникальные экземпляры объектов.
new expromptum.list(array)
.append(object)
.remove(object)
.each(function())
false
, то перебор объектов завершится. Возвращает список объектов..first([function()])
null
, если список пустой. Может выполнить переданную функцию для первого объекта..last([function()])
null
, если список пустой. Может выполнить переданную функцию для последнего объекта..eq(index[, function()])
null
, если такового нет. Может выполнить переданную функцию для найденного объекта.Используется в качестве базового класса для всех остальных.
Класс expromptum.base
.init(params)
.destroy([function()[, remove]])
true
во втором параметре, удаляет функцию из списка. При вызове метода без параметров — выполняет функции в списке. Возвращает объект..change([function()[, remove]])
true
во втором параметре, удаляет функцию из списка. При вызове метода без параметров — выполняет функции в списке. Возвращает объект..param(name[, value])
При инициализации контрола тип определяется по значению параметра type
в атрибуте data-xp
или по селектору типа.
<input name="age" data-xp='{"type": "number"}'/>
<input name="age" class="number"/>
Поле с проверкой на соответствие выражению.
xP.controls.register({name: 'zip', base: '_field', prototype: {
element_selector: '.zip input, input.zip',
valid: /^\d{6}$/,
allow_chars_pattern: /^\d+$/
}});
Слайдер для числового значения с использованием виджета Slider.
xP.controls.register({name: 'slider_number', base: 'number', prototype: {
element_selector: '.slider input',
init: function(params){
xP.controls.slider_number.base.init.apply(this, arguments);
var that = this;
var slider = this._param(
'slider',
$('<div class="slider_control"/>')
.appendTo(this.$element.parent())
.slider({
min: params.min,
max: params.max,
value: this.val(),
slide: function(event, ui){
that.val(ui.value);
}
})
);
this.change(function(){
slider.slider('value', this.val());
});
},
destroy: function(handler, remove){
if(!arguments.length){
this._param('slider').destroy();
}
return xP.controls.slider_number.base.destroy.apply(
this, arguments
);
},
param: function(name, value){
switch(name){
case 'min':
case 'max':
case 'step':
this._param('slider').slider('option', name, value);
break;
};
return xP.controls.slider_number.base.param.apply(
this, arguments
);
},
disable: function(disabled){
disabled = !arguments.length || disabled;
if(this.disabled !== disabled){
this._param('slider').slider(
disabled ? 'disable' : 'enable'
);
}
return xP.controls.slider_number.base.disable.apply(
this, arguments
);
}
}});
Слайдер для набора значений с использованием виджета Slider.
xP.controls.register({name: 'slider_select', base: 'select', prototype: {
element_selector: '.slider select',
init: function(params){
xP.controls.slider_select.base.init.apply(this, arguments);
var that = this;
var slider = this._param(
'slider',
$('<div class="slider_control"/>')
.insertAfter(this.$element)
.slider({
min: 0,
max: this.$element[0].options.length - 1,
value: this.$element[0].selectedIndex,
slide: function(event, ui){
that.$element[0].selectedIndex = ui.value;
}
})
);
this.change(function(){
slider.slider('value', this.$element[0].selectedIndex);
});
},
destroy: function(handler, remove){
if(!arguments.length){
this._param('slider').destroy();
}
return xP.controls.slider_select.base.destroy.apply(
this, arguments
);
},
param: function(name, value){
switch(name){
case 'min':
case 'max':
case 'step':
this._param('slider').slider('option', name, value);
break;
};
return xP.controls.slider_select.base.param.apply(
this, arguments
);
},
disable: function(disabled){
disabled = !arguments.length || disabled;
if(this.disabled !== disabled){
this._param('slider').slider(
disabled ? 'disable' : 'enable'
);
}
return xP.controls.slider_select.base.disable.apply(
this, arguments
);
}
}});
Поле с редактированием через Реформатор.
xP.controls.register({name: 'wysiwyg', base: 'string', prototype: {
element_selector: '.wysiwyg textarea',
init: function(params){
xP.controls.wysiwyg.base.init.apply(this, arguments);
this._param('reformator', reformator.append(this.$element[0], {bar: true}));
},
destroy: function(handler, remove){
if(!arguments.length){
this._param('reformator').destroy();
}
return xP.controls.wysiwyg.base.destroy.apply(this, arguments);
}
}});
Поля для ввода даты с использованием виджета Datepicker.
xP.controls.register({name: 'date_picker', base: '_secret', prototype: {
element_selector: 'input.date.picker, .date.picker input',
init: function(params){
this.locale = xP.locale;
xP.controls.date_picker.base.init.apply(this, arguments);
var month_names = [],
day_names = [this.locale.weekday[6].name],
day_names_min = [this.locale.weekday[6].abbr];
for(var i = 0, ii = this.locale.month.length; i < ii; i++){
month_names.push(this.locale.month[i].name);
}
for(var i = 0, ii = this.locale.weekday.length - 1; i < ii; i++){
day_names.push(this.locale.weekday[i].name);
day_names_min.push(this.locale.weekday[i].abbr);
}
this.$element.datepicker($.extend({
autoSize: true,
changeMonth: true,
changeYear: true,
dateFormat: this.locale.date,
firstDay: this.locale.first_day,
prevText: this.locale.prev_month,
nextText: this.locale.next_month,
dayNames: day_names,
dayNamesMin: day_names_min,
monthNamesShort: month_names,
altField: this.$secret,
altFormat: 'yy-mm-dd'
}, this.datepicker));
if(this._.initial_value){
this.$element.datepicker(
'setDate',
new Date(this._.initial_value.replace(/\s*\d+:\S+\s*/, ''))
);
}
},
destroy: function(handler, remove){
if(!arguments.length){
this.locale.destroy();
this.$element.datepicker('destroy');
}
return xP.controls.date_picker.base.destroy.apply(this, arguments);
},
param: function(name, value){
switch(name){
case 'min':
this.$element.datepicker('option', 'minDate', value);
return value;
break;
default:
return xP.controls.datepicker.base.param.apply(this, arguments);
};
},
date: function(){
return this.$element.datepicker('getDate');
},
val: function(value){
if(!arguments.length){
return this.disabled
? undefined
: (
this.$secret
? this.$secret.val()
: this.$element.val()
);
}else{
this.$element.datepicker('setDate', new Date(value));
return this;
}
}
}});
xP.controls.register({name: 'datetime_picker', base: 'date_picker', prototype: {
element_selector: 'input.datetime.picker, .datetime.picker input',
init: function(params){
var value = params.$element.val();
xP.controls.datetime_picker.base.init.apply(this, arguments);
this._.$time = $('<input value="' + value.substr(11,2)
+ '" class="hours"/>:<input value="' + value.substr(14,2)
+ '" class="minutes"/>').insertAfter(this.$element);
var that = this,
add_time = function(){
that.$secret.val(
that.$secret.val().replace(/\s+\d+:\d+/, '')
+ ' ' + that._.$time.first().val() + ':'
+ that._.$time.last().val()
);
};
this._.time_control = new xP.list();
this._.$time.filter('input').each(function(){
that._.time_control.append(
(new xP.controls.number({
$element: $(this),
min: 0,
max: 23,
changed: null
}))
.change(add_time)
.change(function(){
that.change();
})
);
});
this._.time_control.last().max = 59;
this.change(add_time);
if(this._.initial_value){
this.$secret.val(this._.initial_value);
}
},
destroy: function(handler, remove){
if(!arguments.length){
this._.time_control.each(function(){this.destroy();});
this._.$time.remove();
}
return xP.controls.datetime_picker.base.destroy.apply(this, arguments);
},
disable: function(disabled){
disabled = !arguments.length || disabled;
if(this.disabled !== disabled){
xP.controls.datetime_picker.base.disable.apply(this, arguments);
this._.time_control.each(function(){this.disable(disabled);});
}
return this;
}
}});
_item
xP.base
Используется в качестве базового класса для классов контролов.
.$element
.$container
container_selector
или на основной элемент..disabled
true
или false
, в зависимости от доступности контрола..container_selector
.container_disabled_class = 'disabled'
.autofocus
true
или false
, по которому определяется необходимость перехода фокуса на данный контрол при инициализации..remove()
.parent()
.root()
.val([value])
.disable([disabled])
html
_item
.xp_html
Используется для вывода в HTML значений других контролов через зависимость computed
.
<input name="number_1" data-xp="type: 'number'"/>
<select name="operator">
<option>+</option>
<option>-</option>
<option>*</option>
<option>/</option>
</select>
<input name="number_2" data-xp="type: 'number'"/>
=
<span data-xp="type: 'html', computed: 'eval([name=number_1] * 1 + [name=operator] + [name=number_2] * 1)'"></span>
_parent
_item
.xp
Используется в качестве базового класса для всех контролов, которые могут выступать родителем для других.
.children()
.val([object | objects array])
form
_parent
form
.completed_on_required = true
true
или false
, по которому определяется считается ли форма готовой для отправки при незаполненных обязательных контролах..completed_on_valid_required = true
true
или false
, по которому определяется считается ли форма готовой для отправки при неправильно заполненных обязательных контролах..completed_on_valid = false
true
или false
, по которому определяется считается ли форма готовой для отправки при неправильно заполненных контролах..completed_on_changed = false
true
или false
, по которому определяется считается ли форма готовой для отправки если не менялось значение хотя бы одного из контролов..locked = false
true
или false
, по которому определяется возможность отправки формы. Можно использовать для калькуляторов или форм работающих через ajax..submit([function()[, remove]])
true
во втором параметре, удаляет функцию из списка. Возвращает контрол.true
или false
..uncompleted()
null
. Иначе — строку в которой указана причина (required
, invalid_required
, invalid
, unchanged
).
Получить список конфликтных контролов, можно через метод ._param('зависимость')
.<form method="post">
<div class="field">
<label for="field_name">Name</label>
<input name="name" id="field_name" data-xp="required: true"/>
</div>
<div class="field">
<label for="field_email">Email</label>
<input name="email" id="field_email" data-xp="type: 'email', required: true"/>
</div>
<div class="field">
<label for="field_message">Message</label>
<textarea name="message" id="field_message" data-xp="required: true"></textarea>
</div>
<div class="field">
<input type="submit" value="Send" data-xp="enabled_on_completed: true"/>
</div>
<div id="uncompleted"></div>
</form>
<script>
(function(){
expromptum();
var uncompleted = $('#uncompleted');
expromptum('form').first().change(function(){
var html = '';
this._param('required')
.append(this._param('invalid'))
.each(function(){
html += (html ? ', ': '') + this.$label.text();
});
uncompleted.html((html ? 'Fill fields: ' : '') + html);
});
})();
</script>
fields
_parent
fieldset, .fields, .sheets
.name
.$label
for
равным id
основного элемента данного контрола..count()
sheet
fields
.sheet
.$label
for
равным id
основного элемента данного контрола..selected_class = 'selected'
.unselected_class = 'unselected'
.select([select])
foldable
fields
.foldable
.duration = 200
.folded_class = 'folded'
.unfolded_class = 'unfolded'
.fold([fold])
fold = false
) контрол. Возвращает данный контрол._field
_parent
input
Селектор контейнера .field
.$label
for
равным id
основного элемента данного контрола..allow_chars_pattern
.container_blured_class = 'blured'
blur
у основного элемента данного контрола..val([value])
string
_field
input[type=text], input:not([type])
text
_field
textarea
hidden
_field
input[type=hidden]
file
_field
input[type=file]
button
_parent
input[type=button], button, .button
submit
_item
input[type=submit], button[type=submit]
select
_field
select
.hide_disabled_option = true
false
нужный результат будет только в тех браузерах, которые это поддерживают..disable([disabled[, values]])
.append(values)
[значение для value, значение для подписи]
) или объектом (вида: {value: значение для value, label: значение для подписи}
). Возвращает данный контрол..remove()
options
fields
.options
Группирующий контрол, применяемый для назначения зависимостей на группу переключателей или включателей.
_option
_field
Селектор контейнера .option
Используется в качестве базового класса для контролов переключателей и включателей.
.container_selector = '.option'
.selected = null
true
или false
, по которому определяется отмечен данный контрол или нет..container_initial_selected_class = 'initial_selected'
.container_selected_class = 'selected'
.select([selected])
.append(values)
[значение для value, значение для подписи]
) или объектом (вида: {value: значение для value, label: значение для подписи}
). Возвращает список добавленных контролов.radio
_option
input[type=radio]
checkbox
_option
input[type=checkbox]
email
_field
.email input, input.email
phone
_field
.phone input, input.phone
_secret
_field
Используется в качестве базового класса для всех контролов, внешний вид которых требует создания альтернативных элементов для ввода данных.
.$secret
password
_secret
input[type=password]
Позволяет управлять видимостью введенных символов в поле для ввода пароля.
.container_view_class = 'alt'
.control_button_view_class = 'control_button_password_view'
.control_button_view_html = '<span class="control_button control_button_password"/>'
number
_secret
input.number, .number input
Позволяет вводить только числа и управлять значением с помощью стрелок на клавиатуре или созданных дополнительно элементов управления.
.step = 1
.min = 1 - Number.MAX_VALUE
.def = 0
inc
и dec
при пустом value
..max = Number.MAX_VALUE - 1
.element_wrap_html = '<span class="number_control"/>'
.control_button_dec_html = '<span class="control_button control_button_dec"/>'
.control_button_inc_html = '<span class="control_button control_button_inc"/>'
.inc()
.dec()
datemonth
_field
input.datemonth, .datemonth input
.date([date])
<input name="datemonth" value="2013-04" class="datemonth"/>
date
datemonth
input.date, .date input
<span class="date field">
<input id="date_from" name="date_from" value="2010-02-20"/>
</span>
<span class="date field">
<input id="date_to" name="date_to" data-xp="
valid: '[name=date_from] < [this]'
"/>
</span>
datetime
date
input.datetime, .datetime input
<input name="datetime" value="2013-04-01 12:00" class="datetime"/>
combobox
string
.combobox input, input.combobox, input[list]
Ввод данных с возможность выбора значений из выпадающего списка.
.search_from_start = true
.case_sensitive = false
.[list](#controls._combolist)
_combolist
select
Вспомогательный контрол для комбобокса.
.show()
.hide()
_item
expromptum.base
Используется в качестве базового класса для всех зависисмостей.
.to='[this]'
classed
_item
.on
to
, будет назначено имя CSS-класса из свойства do
..do
<input name="some"/>
<input name="thing" data-xp="classed: {on: '[name=some]', do: 'some'}"/>
<input name="some"/>
<input name="thing" data-xp="classed: [{on: '[name=some]', do: 'some'}, {on: '[name=some] == \'\'', do: 'no'}]"/>
computed
_item
.on
.val(значение)
) контролу, указанному в свойстве to
..do
.param(свойство, значение)
) контрола, указанного в свойстве to
.<input name="number_1" data-xp="type: 'number'"/>
<select name="operator">
<option>+</option>
<option>-</option>
<option>*</option>
<option>/</option>
</select>
<input name="number_2" data-xp="type: 'number'"/>
=
<input name="number_3" data-xp="type: 'number', computed: 'eval([name=number_1] * 1 + [name=operator] + [name=number_2] * 1)'" readonly="true"/>
enabled
_item
.on
to
, будет недоступен для работы (disabled
).<input name="a"/>
<input name="b" data-xp="enabled: '[name=a]'"/>
enabled_on_completed
_item
В зависимости от выполнения условий на обязательность и правильность заполнения формы, делает контрол доступным или недоступным для работы (disabled
).
<form>
<textarea name="message" data-xp="required: true"></textarea>
<input type="submit" data-xp="enabled_on_completed: true"/>
</form>
_rooted
_item
Используется в качестве базового класса для остальных зависисмостей, которые могут быть задействованы в условиях полного заполнения формы.
required
_rooted
.on
to
, становится обязательным для заполнения..container_required_class = 'required'
.container_unrequired_class = 'unrequired'
<input name="name" data-xp="required: true"/>
<input name="a"/>
<input name="b" data-xp="required: '[name=a]'"/>
valid
_rooted
.on
.container_valid_class = 'valid'
on
возвращает true
..container_invalid_class = 'invalid'
on
возвращает false
.<input name="zip" data-xp="valid: /^\d{6}$/'"/>
changed
_rooted
Данная зависимость назначается всем контролам при инициализации.
.container_changed_class = 'changed'
.max = 300
.min = 1
.reset
reset_on_repeat
..template
<span class="field">
<input name="a[0]" data-xp="repeat: true"/>
<button class="repeat_append_button">+</button>
<button class="repeat_remove_button">−</button>
</span>
Все значения свойств у основных объектов библиотеки (контролов, зависимостей и повторений) устанавливаются через параметры при инициализации или через вызов метода .param('имя', значение)
. Получение значений возможно и через прямое обращение к свойству.
Большинство методов основных объектов библиотеки возвращают сам объект.
Методы и свойства названия которых начинаются с символа подчеркивания, предназначены только для использования внутри библиотеки. Если же есть необходимости обратится к таким свойствам, это следует делать через вызов метода ._param('имя', значение)
.
Названия свойств, значениями которых являются jQuery-объекты, начинаются с символа доллара.
Для диагностики работы в адресной строке можно передать параметр xP=значение
. При этом в консоль браузера будут выводится все обнаруженные ошибки и соответствующие значению сообщения:
controls
— инициализация контролов;
submit
— отправка формы;
dependencies
— инициализация и обработка всех зависимостей;
classed
, enabled
, enabled_on_completed
, required
, valid
, changed
— обработка зависимостей данного типа;
repeats
— инициализация повторений.
FAQs
- [Коротко](#summary) - [Инициализация](#init) - [Контролы](#controls) - [Зависимости](#dependencies) - [Повторения](#repeats) - [Концепция](#common) - [Режим диагностики](#debug)
We found that expromptum demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.