کنترلهای زیر جهت ورود اطلاعات در ویرایشگر پشتیبانی میشوند:
- text
- textarea
- select
- date
- datetime
- dateui
- combodate
- html5types
- checklist
- wysihtml5
- typeahead
- typeaheadjs
- select2
clear | دکمهای جهت حذف محتوای کادر متنی است. مقدار پیش فرض آن true است. |
escape | برای
دفاع در برابر کدهای مخرب html به کار میرود و کاراکترهای مدنظر را در صورت
true بودن غیرفعال میکند. البته اگر از خاصیت display استفاده کنید این
گزینه تاثیرش را از دست خواهد داد. |
inputclass | یک کلاس css را به کادر متنی اعمال میکند. |
placeholder | مقدار داده شده را در صورتی که کادر متنی خالی باشد، نشان میدهد. |
tpl | به معنی یک قالب. شما میتوانید کد html تگ input خود را وارد کنید؛ ولی توصیه نمیشود. |
TextArea
همان خاصیتهای قبلی را دارد بعلاوه rows که نمایانگر مقدار ارتفاع آن است.
select
خاصیتهای escape,input,class و tpl را دارد بهعلاوه خاصیتهای زیر:
prepend | همانند گزینه پایینی است ولی قبل از آن دادههای خود را اضافه میکند. |
source | از
آنجا که یک لیست، لیستی از آیتمها را دارد و کاربر یکی از آنها را
انتخاب میکند، این بخش، منبع آیتمها را معرفی میکند. این خاصیت چهار نوع
داده میپذیرد: آرایه یا شیءایی از مقادیر. تابعی که بعد از انجام هر عملی،
اطلاعات به آن پاس میشوند و یا از نوع رشته که این رشته یک آدرس سمت سرور
است که با درخواست از آن آدرس، اطلاعات را دریافت میکند. |
sourceCache | اگه خاصیت بالا با آدرسی پر شده باشد که از سمت سرور بخواند، در دفعات بعدی مقدار دریافتی را از کش خواهد خواند. |
sourceError | یک پیام خطا هنگام بارگزاری اطلاعات |
sourceOptions | در
صورتیکه قصد اضافه کردن پارامتری را به درخواست ایجکسی دارید. یک شیء از پارامترها را به آن
نسبت میدهیم و برای رونویسی پارامترها از یک تابع استفاده میکنیم که نحوهی تغییرات را قبلا در جدول شماره یک دیدهاید. |
date
خاصیتهای مشترک قبلی : tpl,input,class,escape و clear است.
datepicker | پیکربندی تقویم را بر عهده دارد. برای اطلاعات بیشتر در مورد پیکربندی تقویم به این لینک مراجعه فرمایید.{ weekStart: 0, startView: 0, minViewMode: 0, autoclose: false } |
format | قالب بندی فرمت تاریخ جهت ارسال به سرور\ حالت پیش فرض yyyy-mm-dd مقادیری که میتوان به کار برد: yy yyyy mm m dd d |
viewformat | این فرمت هنگام نمایش به کار میآید و در صورتیکه مقدار عنصر در این قالب نباشد، آن را تبدیل میکند. |
datetime در بوت استراپ
کاملا مشترک با مورد قبلی.
dateUI
مختص JqueryUI است و کاملا مشترک با مورد قبلی.
combodate
موارد مشترک قبلی را دارد ولی به جای خاصیت datepicker از combodate استفاده میشود که پیکربندی آن در این لینک قرار دارد.
نوعهای HTML 5
شامل موارد زیر است:
- password
- url
- tel
- number
- range
- time
خاصیتهای ذکر شده در مورد نوع text، در مورد آنها نیز صدق میکند.
checklist
همانند نوع select است؛ فقط خاصیت separator را دارد که کارش جدا کردن مقادیر است و مقدار پیش فرض آن علامت ',' است.
wysihtml5
سورس و دمو ی این نوع ادیتور که بر پایهی بوت استرپ بنا شده است و زحمت اضافه کردن کتابخانهها به صفحه، بر عهده شماست.
مداخل زیر را به طور دستی به صفحه اضافه کنید:
<link href="js/inputs-ext/wysihtml5/bootstrap-wysihtml5-0.0.2/bootstrap-wysihtml5-0.0.2.css" rel="stylesheet" type="text/css"></link> <script src="js/inputs-ext/wysihtml5/bootstrap-wysihtml5-0.0.2/wysihtml5-0.3.0.min.js"></script> <script src="js/inputs-ext/wysihtml5/bootstrap-wysihtml5-0.0.2/bootstrap-wysihtml5-0.0.2.min.js"></script>
<script src="js/inputs-ext/wysihtml5/wysihtml5.js"></script>
typeahead
این گزینه فقط مختص بوت استرپ 2 است و یک کنترل autocomplete به شمار میآید. منبع دادههای آن از طریق خاصیت source به دو صورت آرایه و object تامین میگردد.
['text1', 'text2', 'text3' ...] //or [{value: 1, text: "text1"}, {value: 2, text: "text2"}, ...]
typeaheadjs
همانند قبلی است و بر اساس twitterBootstrap است و شامل همان خصوصیات قبلی است. تنها خصوصیت typeahead آن است که باید از این پیکربندی استفاده کنید.
Select2
این المان بر اساس این کتابخانه سورس باز ایجاد میشود. و مستندات آن شامل جزئیات و پیکربندی آن میشود. برای معرفی آن فایلهای زیر را به صفحه معرفی کنید.
<link href="select2/select2.css" rel="stylesheet" type="text/css"></link> <script src="select2/select2.js"></script>
<link href="select2-bootstrap.css" rel="stylesheet" type="text/css"></link>
نکته: در حال حاضر خاصیت autotext روی این المان جواب نمیدهد و میتوانید از خاصیت data-value به جای آن استفاده کنید.
قالبی نو برای ویرایشگر
ویرایشگر فعلی ما به خصوص در بوت استرپ، ظاهر فوق العادهای دارد. ولی اگر بازهم مایل به تغییر و رونویسی هستید، این امکان فراهم شده است.
fn.editableform.template$
مقدار پیش فرض آن که حتما باید شامل تگ فرم و کلاسهای مدنظر باشد:
<form> <div> <div><div></div><div></div></div> <div></div> </div> </form>
- control-group
- editable-input
- editable-buttons
- editable-error-block
fn.editableform.buttons$
<button type="submit">ok</button> <button type="button">cancel</button>
و نهایتا جهت تغییر loading
fn.editableform.loading$
<div></div>
گاهی اوقات نیاز است که خصوصیات این ویرایشگر را در شرایط متغیر صفحه کنترل کنیم، برای مثال گاهی پیش میآید که بخواهید در یک شرایط خاص ویرایشگر یک المان خاص را غیرفعال کنید. کد زیر مثال این تغییرات است.
$('#favsite').editable('option', 'disabled', false);
متدها و رویدادها
متدهایی که روی آن قابل اجراست:
editable | ویرایشگر را بر اساس مقادیر اولیه روی عنصر مشخص شده فعال میکند. |
() activate | فوکوس را به input ویرایشگر باز میگرداند. |
() destory | حذف ویژگی ویرایش از روی عنصر |
() disable | غیرفعال کردن ویرایشگر |
() enable | فعال سازی آن |
()getvalue | باعث بازگردانی
مقدار جاری همه عناصر توسط شیء جفت کلید مقدار میشود و عناصری که شامل
متن یا مقداری نیستند، از آن حذف میشوند. در صورتیکه قصد دارید مقدار تنها
یک عنصر قابل دریافت باشد، با خاصیت isSingle آن را true کنید. $('#username, #fullname').editable('getValue'); //result: { username: "superuser", fullname: "John" } //isSingle = true $('#username').editable('getValue', true); //result "superuser" |
()hide | مخفی کردن تگ فرم ویرایشگر |
(option(key,value | تغییر خصوصیات یک عنصر که در بالا هم نمونه کد آن را دیدیم. |
(setvalue(value,convertStr | ست کردن مقدار جدید کنترل و پارامتر دوم وضعیت تبدیل این مقدار به فرمت داخلی است که برای آن تعریف شده است مثل date |
() show | نمایش ویرایشگر |
( submit(options | در
صورتی که خاصیت ارسال خودکار به سمت سرور را غیر فعال کرده باشید، با این
گزینه میتوانید همه اطلاعات و تغییرات را ارسال کنید. برای ایجاد فرم بر
اساس ویرایشگرها و ارسال اطلاعات با کلیک بر روی دکمه submit کاربرد دارد. یک مثال
در این زمینه . پارامترهای options به شرح زیر هستند: url data ajaxoptions (error(obj (success(obj,config از نسخه 1.5.1 میتوان این گزینه را به راحتی روی یک المان خاص هم صدا زد: $('#username').editable('submit') |
() toggle | کدی که صدا زده میشود بین دو وضعیت show و hide سوئیچ میکند. |
() toggleDisabled | تغییر وضعیت بین دو حالت enable و disable |
() validate | انجام اعتبارسنجی بر روی همه کنترل ها.$('#username, #fullname').editable('validate'); // possible result: { username: "username is required", fullname: "fullname should be minimum 3 letters length" } |
رویدادها
hidden | این
رویداد زمانی رخ میدهد که ویرایشگر دیگر قابل مشاهده نیست و شامل دو پارامتر
event و reason است. reason دلیل اینکه چرا ویرایشگر از دید خارج شده است
را با یکی از گزینههای زیر مشخص میکند. save cancel onblur nochange manual $('#username').on('hidden', function(e, reason) { if(reason === 'save' || reason === 'cancel') { //auto-open next editable $(this).closest('tr').next().find('.editable').editable('show'); } }); |
init | موقعی صدا زده میشود که متد editable روی عنصر صدا زده میشود و به یاد داشته باشید که این رویداد باید قبل از آن ست شده باشد.$('#username').on('init', function(e, editable) { alert('initialized ' + editable.options.name); }); $('#username').editable(); |
save | موقعی
که مقدار جدید، با موفقیت تایید میشود. دو پارامتر event و params را باز
میگرداند که params شامل دو خصوصیت newValue و response است که به ترتیب
مقدار جدید و اطلاعات برگشت داده شده از درخواست آژاکس است.$('#username').on('save', function(e, params) { alert('Saved value: ' + params.newValue); }); |
shown | موقعیکه ویرایشگر نمایش مییابد و فرم با موفقیت رندر شده است. برای اشیایی چون select باید صبر کنید تا مقادیر آنها بارگذاری شوند.$('#username').on('shown', function(e, editable) { editable.input.$input.val('overwriting value of input..'); }); |
حل مشکل این ابزار در کندو
موقعیکه من این ابزار را بر روی treeview قرار دادم، به این مشکل برخوردم که اطراف پنجره باز شده، توسط حاشیههای treeview محدود شده است و مطابق شکل زیر قسمتهایی از آن دیده نمیشود. به همین علت cssهای کندو را به اندازه یک خط ویرایش کردم.
برای حل این مشکل فایل kendo.common-xxx را باز کنید. xxx بر اساس قالبی که برای کندو انتخاب کردهاید، میتواند متفاوت باشد. در مثالهای کندو عموما این xxx به نام default شناخته میشود یا برای مثال من، bootstrap بود.
بعد از اینکه باز کردید، به دنبال چنین استایلی بگردید:
div.k-treeview{ border-width: 0px; background: transparent none repeat scroll 0px center; overflow: auto; white-space: nowrap; }
overflow: auto;
نکته بعدی اینکه وقتی ویرایشگر در حالت popup قرار میگیرد، مقدار خاصیت title نمایش مییابد که عموما با مضامینی چون "کلمه جدید را وارد نمایید" و ... پر میشود که به طور پیش فرض سمت چپ قرار گرفته است. کد زیر را در صفحه وارد کنید تا متن در سمت راست قرار بگیرد:
.popover-title { text-align: right; }
وارد کردن کتابخانه ها
این کتابخانه شامل دو فایل css و JS میباشد که بسته به محیطی که در آن کار میکنید متفاوت هستند. در این صفحه شما میتوانید برای 4 محیط Jquery ,JqueryUI , Bootstrap2 و Bootsrap3 بستهی مخصوصش را یا به صورت دانلود فایلها یا از طریق CDN دریافت نمایید. در اینجا هم یک دمو از قابلیتهای آن قابل مشاهده است.
برای شروع، کتابخانهی مورد نظر خود را دریافت و آنها را به صفحهی خود اضافه نمایید. در صورتیکه از Bootstrap استفاده میکنید، ابتدا فایلهای زیر را اضافه کنید:
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet"> <script src="http://code.jquery.com/jquery-2.0.3.min.js"></script> <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
اولین حالتیکه میتوانید با این کتابخانه کار کنید، استفاده از خاصیت *-data است. نمونه زیر را در نظر بگیرید:
<a href="#" id="favsite" data-type="text" data-pk="1" data-url="@Url.Action(MVC.Categories.EditCategory())" data-title="Enter your favorite site">dotnettips.info</a>
$(document).ready(function () { $('#favsite').editable(); });
$(document).ready(function () { $.fn.editable.defaults.mode = 'inline'; $('#favsite').editable(); });
حالت بعدی که میتوان استفاده کرد به شکل زیر است:
<a href="#" id="favsite" >dotnettips.info</a>
$.fn.editable.defaults.mode = 'inline'; $(document).ready(function () { $('#favsite').editable({ type: 'text', pk: 1, url: '@Url.Action(MVC.Categories.EditCategory())', title: 'Enter your favorite site' }); });
خوبی این روش این است که میتوان اطلاعات بیشتری چون رویدادها را به آن پاس داد. تا الان با نحوهی انتساب آن به اشیاء آشنا شدیم. اجازه دهید تا با خصوصیات آن آشنا شویم.
AjaxOptions | همانطور
که متوجه شدید به طور خودکار اطلاعات ویرایش شده، به سمت آدرس داده شده،
به شیوه Post ارسال میگردند. در صورتیکه قصد دست بردن
در نوع درخواست را دارید، میتوانید از این ویژگی استفاده کنید: ajaxOptions: { type: 'put', dataType: 'json' } |
Anim | این
ویژگی که تنها در حالت inline پاسخ میدهد، میتواند زمان بسته شدن
x-editable را تغییر دهد که به طور پیش فرض با false مقداردهی شده است. جهت
تغییر زمان بسته شدن، کد زیر را وارد نمایید: anim:'false' //or anim: { duration: 2000 } |
autotext | در انتهای جدول آمده است. |
defaultValue | در
صورتیکه عنصر مورد نظر محتوایی نداشته باشد و این خصوصیت را
مقداردهی کنید، موقع ویرایش، این عبارت تعیین شده نمایش مییابد. در مثال
بالا باید متن تگ a را حذف کرده تا نتیجه را ببینید: (البته فیلد value نباید مقداری داشته باشد) defaultValue: 'default val' //or defaultValue: undefined //or defaultValue: null |
disabled | false کردن این ویژگی باعث غیرفعال شدن x-editable بر روی کنترل جاری میگردد. |
display | خاصیت
display یا مقدار بولین false را دریافت میکند، یا نال، یا یک تابع
callback را میتوان به آن پاس داد. این خصوصت زمانی صدا زده میشود که
اطلاعات به سمت آدرس سرور رفته و با موفقیت بازگشت داده میشوند (در صورتی
که این ویژگی غیرفعال باشد، بلافاصه بعد از تایید کاربر، از اطلاعات وارد شده
صدا زده میشود) و سپس متن جدید عنصر تغییر مییابد. حال اگر این خاصیت نال
که مقدار پیش فرض آن است باشد، متن تغییر مییابد. ولی اگر false باشد، متن سابق
باقی خواهد ماند و در صورتیکه تابعی به آن پاس داده باشید، طبق تابع شما
عمل خواهد کرد. پارامترهایی که تابع شما میتواند داشته باشد به شرح زیر است: value : مقدار جدید response : پاسخ سرور ( در صورتی که ارسال از طریق Ajax صورت گرفته باشد) و در صورتیکه عنصر شما checlklist یا select باشد که حاوی منبعی از مقادیر هست، مقادیرشان در قالب یک آرایه با نام sourceData بازگشت خواهد خورد. برای دسترسی به آیتمهای انتخابی هم از کد زیر استفاده میکنیم: $.fn.editableutils.itemsByValue(value, sourceData) |
emptyclass | معرفی یک کلاس css برای موقعیکه عنصر خالی است. |
emptytext | در صورتی خالی بودن عنصر، این متن را برای عنصر نمایش بده. |
highlight | بعد از به روز رسانی متن عنصر، آن را با این رنگ highlight خواهد کرد و کد رنگی باید در مبنای هگز باشد. مقدار پیش فرض آن false است. |
mode | دو
حالت نمایشی دارد که پیش فرض آن popup است و با باز کردن یک پنجره، مقدار
جدید را دریافت میکند. مورد بعدی inline است که به جای باز کردن پنجره،
متن عنصر را به حالت ویرایش تغییر میدهد. |
name | نام فیلدی که مقدارش تغییر میکند. |
onblur | زمانی که کاربر فوکوس را از ویرایشگر میگیرد، ویرایشگر چه پاسخی باید به آن بدهد، باز بماند؟ ignore ، بسته شود؟ cancel و یا مقدار داده شده را تایید کند؟submit |
params | پارامترهای درخواست ایجکسی که کنترل در حالت پیش فرض ارسال میکند؛ شامل Pk که آن را با id
رکورد پر میکنیم. name نام فیلدی که تغییر یافته است و value که مقدار جدید
است. در صورتیکه دوست دارید اطلاعات اضافیتری نیز ارسال شوند،
میتوانید از این خاصیت استفاده کنید و پارامترها را در قالب Object به آن
پاس کنید. ولی اگر بخواهید در کل همهی پارامترها را رونویسی کنید باید یک
تابع را به آن پاس کنید: params: function(params) { //در این حالت پارامترهای پیش فرض ارسال نشده و تنها پارامترهای معرفی شده در این تابع ارسال میشوند params.a = 1; return params; } |
pk | کلید
اصلی رکورد شما در دیتابیس یا هان id است. در صورتی که از کلیدهای ترکیبی
استفاده میکنید، نگران نباشید فکر آن را هم کرده اند.//کلید عدد pk:1, //کلید رشته ای pk:'dp123' //کلید ترکیبی pk:{id: 1, lang: 'en'} //معرفی یک تابع به آن و بازگشت |
Placement | این ویژگی فقط به درد حالت Popup میخورد که پنجره را کجای عنصر نمایش دهد و شامل چهار مقدار left,right,top,bottom میشود. |
saveonchange | زمانی
که مقدار جدید، برابر مقدار فعلی باشد و این خاصیت false باشد، هیچ تغییری رخ
نخواهد داد. ولی اگر برابر true باشد ،مقدار جدید اسال و جایگزین مقدار فعلی
خواهد شد. مقدار پیش فرض آن false است. |
selector |
با استفاده از این خصوصیت در عنصر انتخابی به دنبال عناصری که در selector
تعیین شده میگردد و حالت ویرایش را روی آنها فعال میکند. در این حالت استفاده از خصوصیات emptytext و autotext در ابتدای امر ممکن نیست و بعد از اولین کلیک قابل استفاده هستند. نکته بعدی اینکه شما باید کلاسهای زیر را دستی اضافه کنید. کلاس editable-click برای همه کنترلها وکلاس editable-empty به کنترلهای بدون مقدار و برای مقداردهی کنترلهای بدون مقدار میتوان از خاصیت ''=data-value استفاده کرد. <div id="user"> <!-- empty --> <a href="#" data-name="username" data-type="text" data-value="" title="Username">Empty</a> <!-- non-empty --> <a href="#" data-name="group" data-type="select" data-source="/groups" data-value="1" title="Group">Operator</a> </div> <script> $('#user').editable({ selector: 'a', url: '/post', pk: 1 }); </script> |
send | سه
مقدار auto,always و never را دریافت میکند. موقعی که شما آن را روی auto
تنظیم کنید؛ در صورتی مقادیر به سمت سرور ارسال میشوند که دو خاصیت url و
pk تعریف شده باشند. در غیر این صورت ویرایش فقط در حالت محلی و روی سیستم
کاربر رخ خواهد داد. |
showbuttons | در
صورتیکه با false مقداردهی شود، تایید فرم به طور خودکار انجام میگیرد و
اگر با یکی از مقادیر left یا Bottom پر شود، دکمهها را در آن قسمت نشان
میدهد. |
success | اطلاعات به سمت سرور
رفته و با موفقیت با کد 200 بازگشت داده شدهاند. در مستندات نوشته است، هر
کد وضعیتی غیر از 200 بازگشت داده شود، به سمت خاصیت error هدایت میشو.د ولی
آن طور که من با httpresponsemessage
تست کردم، چنین چیزی را مشاهده نکردم و مجددا success صدا زده شد. پس بهتر
هست دادهای را که به سمت کنترل برگشت میدهید، خودتان کنترل کنید. به خصوص
اگر انتقال اطلاعات صحیح باشد. ولی اگر در دیتابیس، تغییر با خطا روبرو گردد
بهتر است نتیجهی آن ارسال شده و از تغییر مقدار فعلی ممانعت به عمل آورید. success: function(response, newValue) { if(!response.success) return response.msg; } |
toggle | اگر قصد دارید که باز و بسته کردن ویرایشگر را بر عهدهی مثلا یک دکمهی روی صفحه بگذارید، این خصوصیت به شما کمک میکند:$('#edit-button').click(function(e) { e.stopPropagation(); $('#favsite').editable('toggle'); }); |
type | نوع
ویرایشی را که قرار است انجام گیرد، مشخص میکند. text برای متن، date برای
تاریخ، textarea جهت متون طولانیتر نسبت به text و بسیاری از موارد دیگر |
unsavedclass | این
کلاس موقعی اعمال میگردد که اطلاعاتی را ویرایش کردهاید، ولی اطلاعاتی
به سمت سرور ارسال نشده است. مثلا pk مقداردهی نشده یا send=never قرار
داید و یا اینکه به صورت محلی ذخیره میکنید و میخواهید در آخر همهی اطلاعات را
ارسال کنید. این خاصیت به طور پیش فرض با کلاس editable-unsaved مقداردهی شده که میتوانید با نال کردن، از شرش خلاص شوید. |
url | این
خاصیت با آدرس سمت سرور پر میشود. ولی میتوان به آن یک تابع هم پاس کرد که
این تابع جایگزین درخواست ایجکسی خودش خواهد شد و برای بازگشت دادن نتیجهی این درخواست به سمت تابعهای callback خودش میتوانید یک deferred object را برگشت دهید: url: function(params) { var d = new $.Deferred; if(params.value === 'abc') { //returning error via deferred object return d.reject('error message'); } else { //async saving data in js model someModel.asyncSaveMethod({ ..., success: function(){ d.resolve(); } }); return d.promise(); } } |
validate | مقدار
پیش فرض آن نال است و میتوان به آن یک تابع را جهت اعتبارسنجی سمت کلاینت پاس
داد. به عنوان آرگومان، مقدار جدیدی را ارسال کرده و در آن به اعتبارسنجی
میپردازید. در صورتی که مقدار، نامعتبر باشد، میتوانید یک پیام خطا از نوع
رشتهای را برگردانید. در صورتی که از نسخهی 1.5.1 به بعد استفاده میکنید، دریافت یک object با مقادیر زیر نیز ممکن شده است: newValue: مقدار جدید و جایگزین مقدار غیر معتبر. msg : پیام خطا. به کدهای زیر در سه حالت نگاه کنید: validate: function (value) { if ($.trim(value) == '') { //در تمامی نسخههای یک پیام متنی باز میگردد return 'This field is required'; //1.5.1 //یک مقدار جدید برگشت میدهد که بلافاصله آن را // تایید میکند و متن عنصر به روز میشود return { newValue: 'validated' }; //متن جدید ار ارسال کرده و پیام هشدار را نشان میدهد //ولی تایید نمیکند و منتظر تایید کاربر است return { newValue: 'validated', |
value | مقدار پیش فرضی که در ویرایشگر نشان میدهد و اگر مقداردهی نشود، از متن عنصر استفاده میکند. |
autotext | سه مقدار دارد auto (پیش فرض)،always و never. موقعیکه عنصر شما متنی نداشته باشد و روی auto تنظیم شده باشد، مقدار value را به عنوان متن عنصر نمایش میدهد. always کاری ندارد که عنصر شما متن دارد یا خالی است؛ مقدار value به آن انتساب داده خواهد شد. never هیچگاه. |
در قسمت بعدی که قسمت پایانی است مطالب را ادامه میدهیم.
حذف کامل jQuery از Bootstrap v5
یک HTML builder مخصوص بوت استرپ
کتابخانه bootstrap-rating
یک. قبل از آپلود امکان برش وجود داشته باشد.
دو. سیستم برش قابلیت پشتیبانی از تناسب بین پهنا و ارتفاع را داشته باشد.
سه. قابلیت استفاده خارج از قواعد Ajax را داشته باشد و بتوان ارسال آن را به طور دستی کنترل کرد.
چهار. پشتیبانی برش تصاویر به صورت تاچ برای گوشیهای همراه را نیز دارا باشد.
کتابخانه jcrop کتابخانهای است که این امکانات را برای شما فراهم میکند. این کتابخانه بدین صورت است که در حین برش به شما 4 عدد x1,x2,y1,y2 را داده و شما با ارسال آن به سمت سرور میتوانید بر اساس این اعداد، عکس اصلی را برش بزنید. بدین صورت شما هم عکس اصلی را دارید و هم مختصات برش را دارید و اگر دوست دارید در جاهای مختلف از عکس اصلی برش داشته باشید، بسیار مفید خواهد بود.
مرحله اول:
ابتدا فایل jcrop را دانلود نمایید.
مرحله دوم:
کد Html زیر را به صفحه اضافه کنید:
<div> <!-- upload form --> <!-- hidden crop params --> <input type="hidden" id="x1" name="x1" /> <input type="hidden" id="y1" name="y1" /> <input type="hidden" id="x2" name="x2" /> <input type="hidden" id="y2" name="y2" /> <h2>ابتدا تصویر خود را انتخاب کنید</h2> <div><input type="file" name="postedFileBase" data-buttonText="انتخاب تصویر" id="image_file" onchange="fileSelectHandler()" /></div> <div></div> <div> <h2>قسمتی از تصویر را انتخاب نمایید</h2> <img id="preview" /> <div> <label>حجم فایل </label> <input type="text" id="filesize" name="filesize" /> <label>نوع فایل</label> <input type="text" id="filetype" name="filetype" /> <label>ابعاد فایل</label> <input style="direction: ltr;" type="text" id="filedim" name="filedim" /> </div> </div> </div>
تگ step2 نیز بعد از نمایش موفقیت آمیز تصویر نشان داده میشود که کاربر میتواند در آن تصویر را برش دهد و شامل بخش info نیز میباشد تا بتوان اندازه اصلی تصویر، نوع فایل تصویر Content Type و حجم آن را نمایش داد.
مرحله سوم:
سپس برای استایل دهی کدهای بالا از کد Css زیر استفاده میکنیم:
.bheader { background-color: #DDDDDD; border-radius: 10px 10px 0 0; padding: 10px 0; text-align: center; } .bbody { color: #000; overflow: hidden; padding-bottom: 20px; text-align: center; background: -moz-linear-gradient(#ffffff, #f2f2f2); background: -ms-linear-gradient(#ffffff, #f2f2f2); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #f2f2f2)); background: -webkit-linear-gradient(#ffffff, #f2f2f2); background: -o-linear-gradient(#ffffff, #f2f2f2); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f2f2f2'); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f2f2f2')"; background: linear-gradient(#ffffff, #f2f2f2); } .bbody h2, .info, .error { margin: 10px 0; } .step2, .error { display: none; } .error { color: red; } .info { } label { margin: 0 5px; } .roundinput { border: 1px solid #CCCCCC; border-radius: 10px; padding: 4px 8px; text-align: center; width: 150px; } .jcrop-holder { display: inline-block; } input[type=submit] { background: #e3e3e3; border: 1px solid #bbb; border-radius: 3px; -webkit-box-shadow: inset 0 0 1px 1px #f6f6f6; box-shadow: inset 0 0 1px 1px #f6f6f6; color: #333; padding: 8px 0 9px; text-align: center; text-shadow: 0 1px 0 #fff; width: 150px; } input[type=submit]:hover { background: #d9d9d9; -webkit-box-shadow: inset 0 0 1px 1px #eaeaea; box-shadow: inset 0 0 1px 1px #eaeaea; color: #222; cursor: pointer; } input[type=submit]:active { background: #d0d0d0; -webkit-box-shadow: inset 0 0 1px 1px #e3e3e3; box-shadow: inset 0 0 1px 1px #e3e3e3; color: #000; }
مرحله چهارم:
افزودن کد جاوااسکریپتی زیر برای کار کردن با کتابخانه Jcrop میباشد:
function bytesToSize(bytes) { var sizes = ['بایت', 'کیلو بایت', 'مگابایت']; if (bytes == 0) return 'n/a'; var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i]; }; function updateInfo(e) { $('#x1').val(e.x); $('#y1').val(e.y); $('#x2').val(e.x2); $('#y2').val(e.y2); }; var jcrop_api, boundx, boundy; function fileSelectHandler() { var oFile = $('#image_file')[0].files[0]; $('.error').hide(); var rFilter = /^(image\/jpeg|image\/png)$/i; if (!rFilter.test(oFile.type)) { $('.error').html('فقط تصویر معتبر انتخاب نمایید').show(); return; } var oImage = document.getElementById('preview'); var oReader = new FileReader(); oReader.onload = function (e) { oImage.src = e.target.result; oImage.onload = function () { $('.step2').fadeIn(500); var sResultFileSize = bytesToSize(oFile.size); $('#filesize').val(sResultFileSize); $('#filetype').val(oFile.type); $('#filedim').val(oImage.naturalWidth + ' x ' + oImage.naturalHeight); if (typeof jcrop_api != 'undefined') { jcrop_api.destroy(); jcrop_api = null; $('#preview').width(oImage.naturalWidth); $('#preview').height(oImage.naturalHeight); } $('#preview').Jcrop({ aspectRatio: 2, bgFade: true, bgOpacity: .3, onChange: updateInfo, onSelect: updateInfo }, function () { //var bounds = this.getBounds(); //var boundx = bounds[0]; //var boundy = bounds[1]; // Store the Jcrop API in the jcrop_api variable jcrop_api = this; }); }; }; oReader.readAsDataURL(oFile); }
تابع fileSelectHandler
function fileSelectHandler() { var oFile = $('#image_file')[0].files[0]; $('.error').hide(); var rFilter = /^(image\/jpeg|image\/png)$/i; if (!rFilter.test(oFile.type)) { $('.error').html('فقط تصویر معتبر انتخاب نمایید').show(); return; }
در ادامه همین تابع بالا، کدهای زیر را اضافه میکنیم:
var oImage = document.getElementById('preview'); var oReader = new FileReader(); oReader.onload = function (e) { oImage.src = e.target.result; oImage.onload = function () { $('.step2').fadeIn(500); var sResultFileSize = bytesToSize(oFile.size); $('#filesize').val(sResultFileSize); $('#filetype').val(oFile.type); $('#filedim').val(oImage.naturalWidth + ' x ' + oImage.naturalHeight); if (typeof jcrop_api != 'undefined') { jcrop_api.destroy(); jcrop_api = null; $('#preview').width(oImage.naturalWidth); $('#preview').height(oImage.naturalHeight); } $('#preview').Jcrop({ aspectRatio: 2, bgFade: true, bgOpacity: .3, onChange: updateInfo, onSelect: updateInfo, onRelease: clearInfo }, function () { //var bounds = this.getBounds(); //var boundx = bounds[0]; //var boundy = bounds[1]; jcrop_api = this; }); }; }; oReader.readAsDataURL(oFile);
FileReader یکی از توابع موجود در HTML است که مستندات آن در سایت موزیلا موجود است و قابلیت خواندن غیرهمزمان فایلها و اشیا Blob را دارد. در خط آخر به عنوان پارامتر ما فایلی را که در آپلودر خوانده ایم و در مرحله قبل نوع فایل آن را بررسی کردیم، پاس میکنیم و باعث میشود که رویداد Load شیء FileReader صدا زده شود.
در این رویداد ابتدا اطلاعات این فایل را از قبیل سایز و ابعاد و نوع فایل، خوانده و در همان تگ Div که با کلاس info تعیین شده بود، نمایش میدهیم. سپس متغیر jcrop_api را که به صورت global در بالای تابع صدا زدیم، بررسی میکنم که آیا از قبل پر شدهاست یا خیر؟ اگر از قبل پرشدهاست باید شیء Jcrop را که به آن اعمال شده است، نابود و آن را نال کنیم تا برای تصویر جدید آماده شود. این کد زمانی کاربرد دارد که کاربر از تصویر قبلی انصراف دادهاست و تصویر جدیدی را انتخاب نموده است یا اینکه عملیات دارد به صورت ایجکسی پیاده میشود. اگر عملیات نابودی روی این پلاگین صورت نگیرد، برای مرتبه دوم کار نخواهد کرد.
سپس پلاگین جیکوئری Jcrop را بر روی آن اعمال میکنیم. در پرامتر اول یک سری تنظیمات اولیه را انجام میدهیم که در ادامه با آن آشنا میشویم و در پارامتر دوم یک callback را به آن پاس میکنیم تا بعد از آماده شدن پلاگین اجرا شود که در آن شیء جدید ایجاد شده یعنی this را در متغیری به اسم jcrop_api دخیره میکنیم تا در بررسیهای آتی که در بند بالا توضیح داده شد، در دسترس داشته باشیم. همچنین در این تابع شما میتوانید اندازه تصویر انتخابی را نیز داشته باشید.
این پلاگین شامل optionهای متفاوتی در پارامتر اول است که آنها را بررسی میکنیم:
MinSize : شما میتوانید حداقل پهنا و ارتفاعی را برای برش زدن تصویر در نظر بگیرید.
minSize:[40,20]
aspectRatio:1.5
bgOpacity از 0 تا یک مقدار میگیرد و میزان opacity محلهای تاریک را تعیین میکند. همچنین شامل سه رویداد onSelect,onChange,onrelease هم میباشد که به ترتیب در موارد زیر رخ میدهند:
ناحیه مورد نظر انتخاب شد.
ناحیه مورد نظر در حالت انتخاب است و ماوس در حال درگ شدن است و با هر حرکتی ماوس اجرا میگردد.
ناحیه انتخابی از حالت انتخاب خارج شد.
دو رویداد اول یعنی onchange و onSelect را برای به روزسانی فیلدهای مخفی و مختصات استفاده میکنیم:
function updateInfo(e) { $('#x1').val(e.x); $('#y1').val(e.y); $('#x2').val(e.x2); $('#y2').val(e.y2); };
این مختصات از طریق یک پارامتر به آنها پاس میشود. به غیر از این چهار عدد مختصات میتوانید با استفاده از متغیرهای w و h هم اندازه پهنا و ارتفاع محل برش خورده را نیز به دست آورید. هر چند که این اعداد، از تفریق خود مختصات هم به دست میآیند.
یک تابع جزئی دیگر هم در این فایل وجود دارد که حین نمایش اندازه تصویر، واحد نمایش مناسب آن را برای ما انتخاب میکند:
function bytesToSize(bytes) { var sizes = ['بایت', 'کیلو بایت', 'مگابایت']; if (bytes == 0) return 'n/a'; var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i]; };
بعد از اینکه کدهای سمت کلاینت را تمام کردیم لازم است با نحوه برش تصویر در سمت سرور هم آشنا شویم:
public static byte[] Resize(this byte[] byteImageIn, int x1,int y1,int x2,int y2) { ImageConverter ic = new ImageConverter(); Image src = (Image)(ic.ConvertFrom(byteImageIn)); Bitmap target = new Bitmap(x2 - x1, y2 - y1); using (Graphics graphics = Graphics.FromImage(target)) graphics.DrawImage(src, new Rectangle(0, 0, target.Width, target.Height), new Rectangle(x1,y1,x2-x1,y2-y1), GraphicsUnit.Pixel); src = target; using (var ms = new MemoryStream()) { src.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); return ms.ToArray(); } }
از آنجا که ما تصاویر را در دیتابیس به صورت آرایهای از بایتها ذخیره میکنیم، extension method ذکر شده در بالا تصویر را در حالت آرایهای از بایتها برش میدهد. بدیهی که بسته به نیاز شما کد بالا دست خوش تغییراتی خواهد شد. ابتدا تصویر باینری را به شی Image تبدیل میکنیم و یک شیء Bitmap جدید را به عنوان بوم خالی و به اندازه کادر برش ایجاد میکنیم تا تصویر برش خورده در آن قرار بگیرد و سپس توسط متد DrawImage میخواهیم که تصویر مبدا را با مختصات شیء Rectangle از نقطه 0 و 0 بوم آغاز کرده و تا انتهای آن شروع به ترسیم کند. سپس آن را ذخیره و مجددا در قالب همان آرایهای از بایتها بر میگردانیم.
تنها یک نکته را به خاطر داشته باشید که مقادیر مختصاتی که پلاگین جی کوئری ارسال میکند در قالب اعداد اعشاری هستند و برای ارسال و دریافت آنها در سرور این نکته را به خاطر داشته باشید.
کتابخانه jquery-sortable
jQuery Sortable is a flexible, opinionated sorting plugin. It enables items in a list (or table etc.) to be sorted horizontally and vertically using the mouse. Supports nested lists and pure drag/drop containers. Demo
jQuery Sortable does not depend on jQuery UI and works well with Twitter's Bootstrap (You can even sort the Bootstrap navigation).
کتابخانه gridstack.js
gridstack.js is a jQuery plugin for widget layout. This is drag-and-drop multi-column grid. It allows you to build draggable responsive bootstrap v3 friendly layouts. It also works great with knockout.js, angular.js and touch devices. Demo Demo
کتابخانه lobipanel
jQuery plugin for bootstrap panels. It extends panels with several common and useful functions. Demo
Features
- Sort, drag, expand, resize, minimize bootstrap panels
- Specify url and load content in panel from this url
- Change the name of the panel
- Customize action icons and action tooltips
- Works for nested panels
- HTML5 localStorage support
- Save panel state: (pinned, unpinned, collapsed, fullscreen, minimized) and apply it on page load
- Save panel position among siblings and apply on next time