Доброго времени суток, уважаемое Хабросообщество! Не пытаясь скрыть легкое волнение, публикую свой первый пост, темой которого стал мой скромный jQuery-велосипед для быстрого и безболезненного сбора данных, введенных пользователем на странице (сразу небольшая оговорка для тех, кто закричит — «ату его! Зачем еще один подобный плагин?», отвечу: во-первых — а быть может именно это кто-то из хаброчитателей и искал, во-вторых — для саморазвития, в-третьх: для собственного удобства и безболезненного использования в своих програмных продуктах).
Итак, помимо, собственно моего небольшого плагина, нам понадобится сам jQuery последней версии, а так же небольшой плагин к нему, реализующий преобразование объектов\массивов в json-строку, для того, чтобы полученные данные можно было быстренько передавать на сервер.
updated
updated 2 — добавлена мультизагрузка!
А теперь приступим к описанию методов плагина. Их немного :) Точнее — три.
Первый: $.form.get(formName,toJson,multi). Функция возвращает данные с указанной формы в виде массива или json-строки. Коротко о главном, то есть о входных переменных.
Второй: $.form.set(formName,elemName,value) Служит для установки новых значений для элемента формы. Входные параметры:
Третий: $.form.save(params) По сути дела, это обертка, получающая необходимую форму и отправляющая ее посредством post запроса на сервер. Входной параметр один, это объект следующего вида:
{
name: "", //имя формы
url: "", //адрес серверного скрипта
params: {}, //объект, содержащий дополнительные параметры, передаваемые серверному скрипту
multi: false, //то же, что и в предыдущих функциях
test: false, //true/false — если true, то ответ сервера выводится с помощью функции alert
callback: function(data){}, //функция, вызываемая после выполнения post-запроса. Принимает в качестве единственного параметра ответ сервера.
}
Если какой-то из параметров не передан, то они заменятся на значения по-умолчанию. Но понятно, что если не передать name и url, то получится билеберда =)
Ну и последнее: для того, чтобы указать имя формы для элементов input, select и textarea я использовал аттрибут class. Изначально попробовал ввести свой аттрибут form, но это оказалось не кроссбраузерно)
Код плагина в конце статьи
UPD
Итак, обновил скрипт и демо. Теперь плагин поддерживает ajax-upload файлов с прогрессбаром. Flash для загрузчика не требуется. Для отображения прогрессбара используется jQueryUI.
Для того, чтобы использовать input:file с нашим плагином, добавляем на страницу элемент, подобный этому:
<input type=«file» name=«file» class=«upload»>
Далее, на событие document.ready вешаем функцию, преобразующую этот инпут в наш ajax-загрузчик:
$.form.makeUpload('.upload[name=test]',{
upload:'upload.php?action=uploadFile',
progress:'upload.php?action=progress',
directory:'uploads',
multi:true,
autoUpload:true
});
Вот что получается в итоге:
Получать данные с таким элементов можно все той же функцией $.form.get
Возвращаемые после загрузки файла значения:
Функция $.form.makeUpload принимает два входящих параметра
Ну. пока вроде все. Спасибо всем за внимание )
Спасибо всем за карму! Перес в jquery.
Внимание тем кто уже загружал плагин! jquery.form.js и upload.php изменены. Добавлена мультизагрузка и исправлен один баг!
Плагин уже используется в личном кабинете компании СМС услуги, работает там ишачком на нужды клиентов, заливающих excel-файлы с базами абонентов для последующих смс рассылок. =) В числе клиентов куча офисных работников с IE самых разных видов, ни у кого проблем при аплоаде не возникает. Пользуйтесь ;)
Так как хостинг, держащий эти файлы пропал, выкладываю код плагина здесь, демка пропала без вести ) Не забудьте подключить jQuery и jQuery UI!
Итак, помимо, собственно моего небольшого плагина, нам понадобится сам jQuery последней версии, а так же небольшой плагин к нему, реализующий преобразование объектов\массивов в json-строку, для того, чтобы полученные данные можно было быстренько передавать на сервер.
updated
updated 2 — добавлена мультизагрузка!
А теперь приступим к описанию методов плагина. Их немного :) Точнее — три.
Первый: $.form.get(formName,toJson,multi). Функция возвращает данные с указанной формы в виде массива или json-строки. Коротко о главном, то есть о входных переменных.
- formName — как следует из названия, передаем сюда имя формы.
- toJson — true/false. Если true — то возвращается json-строка, содержащая значения формы. Если же false — то объект. По умолчанию — true.
- multi — так же принимает true/false. Если передано true, то функция понимает, что инпутов с одинаковым именем на странице может быть несколько, и собирает значения всех этих одноименных элементов формы в понумерованный массив. Передавая false, мы указываем, что одноименных input'ов на форме не предвидится, и можно не колеблясь запихивать значения в виде строки (исключения составляют элементы select с аттрибутом multiple и чекбоксы). По-умолчанию передается false;
Второй: $.form.set(formName,elemName,value) Служит для установки новых значений для элемента формы. Входные параметры:
- formName — то же, что и в предыдущей функции.
- elemName — значение аттрибута name элемента формы
- value — строка или массив, содержащий новые значения элемента.
Третий: $.form.save(params) По сути дела, это обертка, получающая необходимую форму и отправляющая ее посредством post запроса на сервер. Входной параметр один, это объект следующего вида:
{
name: "", //имя формы
url: "", //адрес серверного скрипта
params: {}, //объект, содержащий дополнительные параметры, передаваемые серверному скрипту
multi: false, //то же, что и в предыдущих функциях
test: false, //true/false — если true, то ответ сервера выводится с помощью функции alert
callback: function(data){}, //функция, вызываемая после выполнения post-запроса. Принимает в качестве единственного параметра ответ сервера.
}
Если какой-то из параметров не передан, то они заменятся на значения по-умолчанию. Но понятно, что если не передать name и url, то получится билеберда =)
Ну и последнее: для того, чтобы указать имя формы для элементов input, select и textarea я использовал аттрибут class. Изначально попробовал ввести свой аттрибут form, но это оказалось не кроссбраузерно)
Код плагина в конце статьи
UPD
Итак, обновил скрипт и демо. Теперь плагин поддерживает ajax-upload файлов с прогрессбаром. Flash для загрузчика не требуется. Для отображения прогрессбара используется jQueryUI.
Для того, чтобы использовать input:file с нашим плагином, добавляем на страницу элемент, подобный этому:
<input type=«file» name=«file» class=«upload»>
Далее, на событие document.ready вешаем функцию, преобразующую этот инпут в наш ajax-загрузчик:
$.form.makeUpload('.upload[name=test]',{
upload:'upload.php?action=uploadFile',
progress:'upload.php?action=progress',
directory:'uploads',
multi:true,
autoUpload:true
});
Вот что получается в итоге:
Получать данные с таким элементов можно все той же функцией $.form.get
Возвращаемые после загрузки файла значения:
- directory — директория на сервере, куда был загружен файл
- serverFileName — имя файла на сервере
- path — directory+"/"+serverFileName
- size — размер файла в байтах
- isUploaded — 0 или 1. А был ли вообще загружен файл? :)
Функция $.form.makeUpload принимает два входящих параметра
- multi — разрешить мультизагрузку, true\false. False по-умолчанию
- selector — селектор объекта\объектов, которые нужно преобразовать в загрузчик
- params — объект со следующими ключами:
- upload — адрес серверного скрипта, который отвечает за upload файла
- progress — адрес серверного скрипта, который отображает прогресс загрузки файла
- serverFileName — имя, которое будет присвоено файлу на сервере. Если в этом параметре встречается слово %real%, то оно заменяется на настоящее имя файла
- directory — директория, в которую будет загружен файл
- autoUpload — true\false — начинать ли аплоад сразу после выбора файла
- onSelect — функция, в которую передается объект, который в данный момент я и описываю) Вызывается в тот момент, когда был выбран файл
- onStart — функция, которая вызывается, когда стартавал аплоад файла
- onComplete — также функция. Вызывается в тот момент, когда загрузка файла завершена. Принимает в качестве параметра объект, содержащий ключи path (путь до файла на сервере), size (размер в байтах), name (имя файла)
- <?php
- function uploadFile()
- {
- if (sizeof($_FILES))
- {
- $dir = getDir();
- if ($dir !='' && !is_dir($dir))
- mkdir($dir);
- foreach($_FILES as $file)
- {
- $filename = str_replace('%real%', $file['name'], $_POST[$_POST['inputName'].'_serverFileName_def']);
- move_uploaded_file($file['tmp_name'], $dir."/".$filename);
- }
- }
- }
-
- function getDir()
- {
- $dir = '';
- if ($_POST[$_POST['inputName'].'_directory'] !='') $dir = $_POST[$_POST['inputName'].'_directory'];
- return $dir;
- }
-
- function progress()
- {
- if (!isset($_POST['file'])) die();
- $filename = $_POST['file'];
- if (function_exists("uploadprogress_get_info"))
- {
- $r = uploadprogress_get_info($_POST['key']);
- if (is_array($r))
- $r = array_merge($r,array("result"=>1));
- else
- {
- $size = 0;
- if (file_exists($_POST['file'])) $size = filesize($_POST['file']);
- $r = array("result" => -1, "size"=> $size);
- }
- echo json_encode($r);
- }
- else
- {
- $size = 0;
- if (file_exists($_POST['file'])) $size = filesize($_POST['file']);
- echo json_encode(array("result" => 0,"size" => $size));
- }
- }
- if (isset($_GET['action']))
- {
- if($_GET['action'] == 'uploadFile') uploadFile();
- elseif ($_GET['action'] == 'progress') progress();
- }
- ?>
* This source code was highlighted with Source Code Highlighter.
Ну. пока вроде все. Спасибо всем за внимание )
Спасибо всем за карму! Перес в jquery.
Внимание тем кто уже загружал плагин! jquery.form.js и upload.php изменены. Добавлена мультизагрузка и исправлен один баг!
Плагин уже используется в личном кабинете компании СМС услуги, работает там ишачком на нужды клиентов, заливающих excel-файлы с базами абонентов для последующих смс рассылок. =) В числе клиентов куча офисных работников с IE самых разных видов, ни у кого проблем при аплоаде не возникает. Пользуйтесь ;)
Так как хостинг, держащий эти файлы пропал, выкладываю код плагина здесь, демка пропала без вести ) Не забудьте подключить jQuery и jQuery UI!
jQuery.form = {<br> set:function(form,name,values)<br> {<br> var selector = "."+form+"[name="+name+"]";<br> if ($(selector).is(':checkbox'))<br> {<br> if (!$.isArray(values)) values = new Array(values);<br> $(selector).removeAttr("checked");<br> for (var i = 0; i < values.length; i++)<br> $(selector+"[value='"+values[i]+"']").attr("checked","checked");<br> return;<br> }<br> if ($(selector).is(':radio'))<br> {<br> $(selector).removeAttr("checked");<br> $(selector+"[value='"+values+"']").attr("checked","checked");return;<br> }<br> $(selector).val(values);<br> return;<br> },<br> save:function(params)//name,url,key,callback,params,multi<br> {<br> var p = {<br> name:'form',<br> url:'',<br> key:null,<br> test:false,<br> callback:function(){},<br> params:{},<br> multi:false<br> }<br> p = $.extend(p,params);<br> var form = $.form.get(p.name,false,p.multi);<br> if ( p.key !=null )<br> {<br> var c = {};<br> c[p.key] = form;<br> form = c;<br> }<br> form = $.toJSON(form);<br> if (p.params == null) p.params = {p:form};<br> else p.params.p = form;<br> $.post(p.url,p.params,function(data){<br> if (p.test)<br> alert(data);<br> data = $.parseJSON(data);<br> if (data.code == 1)<br> $.form.ok(p.name,data.descr,data.title);<br> else $.form.error(p.name,data.descr,data.title);<br> p.callback(data);<br> },'html');<br> },<br> get:function(form,json,multi){<br> if (multi == null) multi = false;<br> if (json == null) json = true;<br> if (form == null || form.length == 0)<br> {<br> if (!json) return {};<br> else return $.toJSON({});<br> }<br> var selector = "input."+form+":radio:checked,input."+form+":checkbox:checked,input."+form+":text,input."+form+":hidden,input."+form+":file,input."+form+":password,textarea."+form+",select."+form;<br> var inputs = $(selector);<br> var values = {};<br> $.each(inputs,function(){<br> var name = $(this).attr("name");<br> var value = $(this).val();<br> <br> if (($.isArray(value) && value[0] == null) || value == null)<br> return;<br> if ($(this).is(':file'))<br> {<br> var name = $(this).attr("name");<br><br> var key = $(this).attr("key");<br> var s = "input[type=hidden][key="+key+"]"; <br> var v = {};<br> v.directory = $(s+"[name="+name+"_directory]").attr("value");<br> v.serverFileName = $(s+"[name="+name+"_serverFileName]").attr("value");<br> v.path = $(s+"[name="+name+"_path]").attr("value");<br> v.size = $(s+"[name="+name+"_size]").attr("value");<br> v.isUploaded = $(s+"[name="+name+"_isUploaded]").attr("value");<br> if (v.isUploaded == false || v.isUploaded == 0 || v.isUploaded == "0") return;<br> if (!multi && !$.form.intervals[key].wasMulti) values[name] = v;<br> else<br> {<br> if (values[name] == null) values[name] = new Array();<br> values[name][values[name].length] = v;<br> }<br> return;<br> }<br> if (multi || $(this).is(':checkbox'))<br> {<br> if ($(this).is(":checkbox") && !$(this).attr("checked")) return;<br> if (values[name] == null) values[name] = new Array();<br> values[name][values[name].length] = value;<br> }<br> else<br> {<br> values[name] = value;<br> }<br> });<br><br> if (json == false)<br> return values;<br> else<br> return $.toJSON(values);<br> },<br> addInputFile:function(form,name,container)<br> {<br> var key = $('.'+form+'[name='+name+']').attr("key");<br><br> var p = {};<br> var oldparams = $.form.intervals[key];<br> p.upload = oldparams.upload;<br> p.progress = oldparams.progress;<br> p.serverFileName = oldparams.serverFileName_def;<br> p.directory = oldparams.directory;<br> p.autoUpload = oldparams.autoUpload;<br> p.multi = false;<br> p.wasMulti = oldparams.wasMulti;<br> p.onSelect = oldparams.onSelect;<br> p.onStart = oldparams.onStart;<br> p.onComplete = oldparams.onComplete;<br><br> $(container).append("<input type=file name="+name+" class="+form+">");<br> $.form.makeUpload('.'+form+'[name='+name+']',p,'multi');<br> },<br> uploadChange:function(key,param,value){<br> $("input[key='"+key+"'][name='"+param+"']").attr("value",value);<br> },<br> makeUpload: function (selector,params,add){<br><br> var elements = $(selector);<br> $.each(elements,function(){<br> var p = {<br> upload:"/upload.php?action=uploadFile",<br> progress:"/upload.php?action=progress",<br> serverFileName:"%real%",<br> directory:"",<br> userParam:"",<br> autoUpload:false,<br> multi:false,<br> wasMulti:false,<br> onSelect:function(){},<br> onStart:function(){},<br> onComplete:function(){},<br> name:$(selector).attr("name")<br> }<br> if ($(this).attr("key")!=null) return;<br> var date = new Date();<br> var key = date.getMilliseconds().toString()+date.getMinutes().toString()+date.getSeconds().toString()+Math.round(Math.random()*(1000000 - 0)).toString();<br> p = $.extend(p,params);<br> if (add == null)<br> p.wasMulti = p.multi;<br> else (p.wasMulti = true);<br> p.selector = "[type=file][key="+key+"]";<br> p.key = key;<br> p.serverFileName_def = p.serverFileName;<br> $(this).attr("key",key).change(function(){<br> if ($("#submit_"+key).length == 0)<br> {<br> $.form.intervals[key].onSelect($.form.intervals[key]);<br> $(this).after("<input type=submit value='Загрузить' id=submit_"+key+">");<br> if ($.form.intervals[key].autoUpload == true)<br> $("#submit_"+key).click();<br> }<br> });<br> $(this).wrap("<form key='"+key+"' onsubmit=\"return $.form.uploadSelectedFile(this)\" name=wfUpload_"+key+" action='"+p.upload+"' target=iframe_"+key+" enctype='multipart/form-data' method=post></form>")<br> $(this).parent().append("<input type=hidden name=key value='"+key+"'>");<br> $(this).before('<input type="hidden" name="UPLOAD_IDENTIFIER" value="'+key+'">');<br> var span = $(this).parent();<br> var html =<br> "<input type=hidden name='"+p.name+"_directory' key='"+key+"' value='"+p.directory+"'>" +<br> "<input type=hidden name='"+p.name+"_serverFileName' key='"+key+"' value='"+p.serverFileName+"'>" +<br> "<input type=hidden name='"+p.name+"_serverFileName_def' key='"+key+"' value='"+p.serverFileName_def+"'>" +<br> "<input type=hidden name='"+p.name+"_path' key='"+key+"' value=''>" +<br> "<input type=hidden name='inputName' key='"+key+"' value='"+p.name+"'>" +<br> "<input type=hidden name='userParam' key='"+key+"' value='"+p.userParam+"'>" +<br> "<input type=hidden name='"+p.name+"_isUploaded' key='"+key+"' value='0'>" +<br> "<input type=hidden name='"+p.name+"_size' key='"+key+"' value=''>" +<br> "<span uploaded=0 class=uploadDescr style='display:none' key='"+key+"'></span>" +<br> "<iframe style='display:none;' onLoad=$.form.uploadComplete('"+key+"') name=iframe_"+key+" id=iframe_"+key+"></iframe>";<br> $(span).append(html);<br> if ($.form.intervals[key] == null)<br> $.form.intervals[key] = p;<br> });<br> if (params.multi == true)<br> {<br> var l = elements.length;<br> if (l > 0 && $('#more_files_'+$(elements[l-1]).attr("key")).length == 0)<br> $(elements[l-1]).parent('form').after("<br><input type=submit value='Добавить еще один файл' onclick=$.form.addInputFile('"+$(elements[l-1]).attr("class")+"','"+$(elements[l-1]).attr("name")+"','#more_files_"+$(elements[l-1]).attr("key")+"')><br>").after('<span id=more_files_'+$(elements[l-1]).attr("key")+'></span>');<br> }<br> },<br> uploadSelectedFile: function(s,params)<br> {<br> var p = {<br> width:100,<br> height:15<br> }<br> p = $.extend(p,params);<br> var key = $(s).attr("key");<br> $("#submit_"+key).attr("disabled","disabled");<br> var span = $(s).children(".uploadDescr");<br> var style = {display:'none', margin:"10px"};<br> $(span).html("<div class=progressbar></div> <span style='text-align:right;' class=uploadedFileDetailInfo>Загрузка началась. Пожалуйста, подождите...</span>").css(style);<br> var bar = $(span).children('div.progressbar');<br> bar.progressbar({value: 0});<br> //alert($.form.intervals[key].selector);<br> var fname = $($.form.intervals[key].selector).attr("value");<br> fname = fname.split('\\');<br> $.form.intervals[key].realFileName = fname[fname.length-1];<br> $.form.intervals[key].key = key;<br> $.form.intervals[key].bar = bar;<br> $.form.intervals[key].span = span;<br> $($.form.intervals[key].span).attr("uploaded",0);<br> $.form.intervals[key].onStart($.form.intervals[key]);<br> //$.form.uploadProgress(key);<br> $.form.intervals[key].interval = setInterval('$.form.uploadProgress("'+key+'")',1000);<br> },<br> uploadProgress: function(key){<br> $.ajax({<br> error:function(XMLHttpRequest, textStatus, errorThrown) {<br> },<br> start:function(){},<br> beforeSend:function ( request ) {<br> request.setRequestHeader( 'Cookie', document.cookie );<br> },<br> url:$.form.intervals[key].progress,<br> data:{<br> key:key,<br> file:$.form.intervals[key].directory+"/"+$.form.intervals[key].realFileName<br> },<br> complete:function(){},<br> dataType:'html',<br> type:'post',<br> success:function(data){<br> data = $.parseJSON(data);<br> if (data.result == 1)<br> {<br> var timelast=data.time_last;<br> var total = data.bytes_total;<br> var speed = data.speed_average;<br> var bytes = data.bytes_uploaded;<br> var eta = data.est_sec;<br> var min = Math.round(eta / 60);<br> var sec = eta - min*60;<br> if(min==0){var time=sec+" сек."}else{var time=min+" мин."+sec+" сек."}<br> var speeds = $.form.speeds(speed);<br> var percents = Math.round(bytes * 100 / total);<br> $.form.intervals[key].size = total;<br> $($.form.intervals[key].span).children('.uploadedFileDetailInfo').html("<b>"+percents+"%</b>, <i>скорость:</i> <b>"+speeds+"</b>, <i>загружено</i> <b>"+$.form.fsize(bytes)+"</b> <i>из</i> <b>"+$.form.fsize(total)+"</b>");<br> $.form.intervals[key].bar.progressbar('value',percents);<br> }<br> if (data.result == -1 )<br> $.form.intervals[key].size = data.size;<br> if (data.result == 0)<br> {<br> $.form.intervals[key].size = data.size;<br> //alert(data.size);<br> if ($($.form.intervals[key].span).attr("uploaded") == 0)<br> $($.form.intervals[key].span).html("Сервер не поддерживает отображение процесса загрузки. Подождите завершения загрузки файла...");<br> }<br><br> $($.form.intervals[key].span).slideDown();<br> }});<br> },<br> uploadCompleteAfterTimer:function(key){<br> if ($.form.intervals[key].realFileName == null ) return;<br> clearInterval($.form.intervals[key].interval);<br> var size = "false";<br> if ($.form.intervals[key].size != null) size = $.form.intervals[key].size;<br> var serverFileName = $.form.str_replace('%real%',$.form.intervals[key].realFileName,$.form.intervals[key].serverFileName);<br> var value = $.form.intervals[key].directory+"/"+serverFileName;<br> $("input[key="+key+"][name="+$.form.intervals[key].name+"_path]").attr("value",value);<br> $("input[key="+key+"][name="+$.form.intervals[key].name+"_isUploaded]").attr("value",1);<br> $("input[key="+key+"][name="+$.form.intervals[key].name+"_size]").attr("value",size);<br> $("input[key="+key+"][name="+$.form.intervals[key].name+"_serverFileName]").attr("value",serverFileName);<br> $($.form.intervals[key].span).attr("uploaded",1);<br> $("#submit_"+key).remove();<br> $(".uploadDescr[key="+key+"]").html("Загрузка завершена!!!");<br> var opt = {<br> path:value,<br> size:size,<br> name:$.form.intervals[key].realFileName<br> };<br> $.form.intervals[key].onComplete(opt);<br> },<br> uploadComplete:function(key){<br> setTimeout("$.form.uploadCompleteAfterTimer('"+key+"')",500);<br> },<br> intervals:{},<br> "fsize":function(x) {<br> x = Math.round(x / 1024);<br> if (x < 1000) {<br> return x + " " + "Кб";<br> }<br> x = Math.round(x * 100 / 1024) / 100;<br> return x + " " + "Мб";<br> },<br> "speeds":function (x) {<br> x = Math.round(x / 1024);<br> if (x < 1000) {<br> return x + " " + "Кб/сек";<br> }<br> x = Math.round(x * 100 / 1024) / 100;<br> return x + " " + "Мб/сек";<br> },<br> "str_replace":function (search, replace, subject, count) {<br> var i = 0, j = 0, temp = '', repl = '', sl = 0, fl = 0,<br> f = [].concat(search),<br> r = [].concat(replace),<br> s = subject,<br> ra = r instanceof Array, sa = s instanceof Array;<br> s = [].concat(s);<br> if (count) {<br> this.window[count] = 0;<br> }<br><br> for (i=0, sl=s.length; i < sl; i++) {<br> if (s[i] === '') {<br> continue;<br> }<br> for (j=0, fl=f.length; j < fl; j++) {<br> temp = s[i]+'';<br> repl = ra ? (r[j] !== undefined ? r[j] : '') : r[0];<br> s[i] = (temp).split(f[j]).join(repl);<br> if (count && s[i] !== temp) {<br> this.window[count] += (temp.length-s[i].length)/f[j].length;}<br> }<br> }<br> return sa ? s : s[0];<br> }<br>}<br><br>* This source code was highlighted with Source Code Highlighter.