English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
يستخدم هذا الملحق angular.js وjQuery (يحتاج إلى دمج jQuery قبل angular).
يمكن للمستخدم التحقق من الخيارات الإلزامية والتحقق من نوع عدد صحيح ونوع عدد عشري وما إلى ذلك بعد إدخال البيانات في مربع الإدخال.
إذا كان التحقق من مربع الإدخال داخل form، يمكن النقر على زر التأكيد لتحقيق التحقق من الخيارات الإلزامية.
الصورة التوضيحية كالتالي:
(1) أنماط الخلفية الحمراء عند الفشل في التحقق، وما إلى ذلك
input.ng-invalid, select.ng-invalid { background-color: #ee82ee !important; border: 1px solid #CCC; }); .qtip { position: absolute; max-width: 260px; display: none; min-width: 50px; font-size: 10.5px; line-height: 12px; direction: ltr; }); .qtip-content { position: relative; padding: 5px 9px; overflow: hidden; text-align: left; word-wrap: break-word; }); .qtip-rounded, .qtip-tipsy { -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }); .qtipmodal-ie6fix { position: absolute !important; }); .box-shadow-tips { background-color: #F63; border-color: #F5A88F; color: white; -moz-box-shadow: 2px 2px 2px #969696; -webkit-box-shadow: 2px 2px 2px #969696; box-shadow: 2px 2px 2px #969696; });
بسبب أن angular.js يحتوي على تحقق مدمج لا يتم فيه التحقق، يتم إضافة نمط .ng-invalid إلى العنصر تلقائيًا، لأننا هنا نعيد كتابة هذا النمط
input.ng-invalid, select.ng-invalid { background-color: #ee82ee !important; border: 1px solid #CCC; });
(2) رمز HTML كالتالي
<body ng-app="myApp"> <form name="baseInfoForm"> <div ng-controller="testCtrl"> <input type="text" ng-model="age" my-valid="r"><br> <input type="text" ng-model="name" my-valid="int fn:certCheck"><br> <input type="button" value="إرسال" ng-click="submit()"> </div> </form> </body>
(3) يستخدم هذا الملحق directive myValid
app.directive('myValid', ['$parse', 'uiTipsFactory', 'uiValidFactory', function ($parse, tips, valid) { var uiValidAttrIdName = 'ui-valid-id'; return { restrict: 'A', require: 'ngModel', link: function (scope, el, attrs, ctrl) { var validId = el.attr(uiValidAttrIdName); if (!validId) { validId = Math.guid(); el.attr(uiValidAttrIdName, validId); }); var getRules = function () { return attrs.myValid; }); var lastOldRules; var validFn = function (value, oldRules) { var sp = '_'; var rules = getRules(); var r = valid.check(value, rules, scope, attrs.uiValidTips); إذا (lastOldRules && !oldRules) { oldRules = lastOldRules; }); إذا (r.flag && oldRules) { rules = rules ? rules + ' ' + oldRules : oldRules; }); إذا (rules) { var arrInner = rules.split(' '); var i = 0; for (; i < arrInner.length; i++) { var oneRule = arrInner[i]; إذا (!oneRule.trim()) { continue; }); ctrl.$setValidity(attrs.ngModel + sp + oneRule, r.flag ? true : oneRule != r.rule); }); }); إذا (!r.flag) { tips.on(el, r.msg); else { tips.off(el); }); return r.flag; }); var init = function () { var rules = getRules(); إذا (!rules) { return; }); var parsers = ctrl.$parsers; إذا (parsers && parsers.length > 0) { parsers.clean(); }); parsers.unshift(function (value) { return validFn(value) ? value : undefined; validFn(ctrl.$modelValue, oldRules); }); scope.$watch(attrs.ngModel, function (newVal, oldVal) { إذا (newVal === oldVal) { return; }); إذا (ctrl.$modelValue != undefined && (ctrl.$invalid || el.hasClass('ng-invalid'))) { validFn(ctrl.$modelValue); }); validFn(ctrl.$modelValue, oldRules); scope.$watch(getRules, function (newRules, oldRules) { init(); lastOldRules = oldRules; if (ctrl.$modelValue === undefined || ctrl.$modelValue === null) { var needValid = false; el.hasClass('ng-invalid'); var isValNaN = ctrl.$viewValue !== ctrl.$viewValue; if (ctrl.$invalid || (ctrl.$viewValue !== undefined && !isValNaN)) { needValid = true; }); if (needValid) { ctrl.$setViewValue(ctrl.$viewValue); }); else { if (!ctrl.$dirty && attrs.dirtyCheck) { console.log('----'); else { } }); }); validFn(ctrl.$modelValue, oldRules); }); }); });
من خلال الاستماع إلى attrs.ngModel، قواعد التحقق rules، وctrl.$parser، يتم تنفيذ استجابة تغيير محتوى مربع الإدخال.
باستخدام هذا directive، يتم إضافة ID ديناميكي إلى مربع الإدخال الحالي، مما يسمح بتغيير معلومات خلفية التحقق لمربع الإدخال بعد التحقق من نجاحه.
(4) معالجة منطق التحقق uiValidFactory
app.factory('uiValidFactory', ['$parse', 'uiTipsFactory', function ($parse, tips) { return { check: function (val, rules, $scope, defaultTips, extendParam) { إذا (!rules) { return { flag: true }); }); var rulesArr = rules.split(' '); isBlank = val === null || val === undefined || val === '' || ('' + val === ''); //إذا لم يكن العنصر إلزاميًا وكان ليس لديه قيمة، يتم مسح نافذة الإشعارات إذا (jQuery.inArray('r', rulesArr) === -1 && isBlank) { return { flag: true }); }); var i = 0, len = rulesArr.length; for (; i < len; i++) { var rule = rulesArr[i]; إذا (!rule) { continue; }); var flag = true; إذا ('r' === rule) { //إذا كان العنصر إلزاميًا وكان لديه قيمة، فسيتم العودة إلى الصحيح flag = !isBlank; } آخرا إذا (rule.contains(':')) { //إذا كان قاعدة التحقق هي fn:ctrl.certCheck flag = this.checkRule(val, rule.split(/:/), $scope, extendParam); else { //تحقق من أن النمط هو int باستخدام مطابقة النمط الرقمي البريد الإلكتروني الطول var pat = this.pats[rule]; إذا (pat instanceof RegExp) { إذا (angular.isString(val)) { flag = this.mat(val, pat); }); } آخرا إذا (angular.isFunction(pat)) { flag = pat(val); else { flag = false; }); }); //ما هو الغرض من هذا إذا (angular.isString(flag)) { return { flag: false, msg: flag, rule: rule }); }); إذا (flag === false) { var msg = this.getMsg(rule, defaultTips) || this.getMsg('tips.valid'); console.log(msg); return { flag: false, msg: msg, rule: rule }); }); }); return { flag: true }); }, checkRule: function (val, ruleArr, $scope, extendParam) { //ruleArr fn:certCheck var rule = ruleArr[0]; إذا (rule === 'fn') { fnName = ruleArr[1]; //تحديد اسم الدالة المطلوبة certCheck var fn = $parse(fnName)($scope); إذا (!fn) { return true; }); return fn.call($scope, val, extendParam); else { return true; }); }, checkValidForm: function (formName) { //تحقق فقط من الحقول الإلزامية //استخدام مبدأ التصفية للحصول على جميع العناصر داخلها var formContext = $('form[name="{0}"],[ng-form="{0}"],[data-ng-form="{0}"]'.format(formName)), validList = formContext.find('[my-valid]');//validList ليس قائمة، بل هو مجموعة وهمية إذا (!validList.length) { return; }); var that = this; validFlags = []; validList.each(function () { var ele = $(this), val = ele.val(), ruleStr = ele.attr('my-valid'); إذا (!ruleStr) { return true; }); إذا (angular.isString(val)) { val = val.trim(); }); var validRules = ruleStr.split(' '); إذا (!$.inArray('r', validRules) != -1 && !val) { var modelValue = ele.attr('ng-model') || ele.attr('data-ng-model'); validFlags.push(modelValue); tips.on(ele, that.getMsg('r')); }); }); ); return validFlags; }, mat: function (val, pat) { إذا (!pat) { return; }); return pat.test(val); }); , getMsg: function (rule, tips) { tips = tips || ''; //يمكن كتابة tips مباشرة على الواجهة إذا (tips && tips.contains(':')) { return tips; }); var msg = this.msgs[rule]; if (msg) { var params0 = tips.contains(':') ? tips.split(/:/)[0] : ''; var params1 = ''; if (rule.startsWith('min') || rule.startsWith('max')) { var ruleArr = rule.split(/:/); params1 = ruleArr[ruleArr.length - 1]; }); return msg.format(params0, params1); else { }); }); , regPat: function (code, pat, msg) { if (this.pat[code]) { return; }); this.pats[code] = pat; this.msgs[code] = msg; }); , msgs: { 'r': '必填', 'int': '{0}必须为整数' }); , pats: { 'int': /^[\-\+]?([0-9]+)$/ }); }); }); }) ;
من خلال الحصول على قاعدة التحقق ele.myValid
1、إذا كانت إلزامية، يتم عرض هذا المربع النصي باللون الأحمر، ويتم عرض معلومات التحقق "إلزامي" عند تحريك الماوس فوقه.
2、إذا كان التحقق من عدد صحيح أو نوع عدد عشري وما إلى ذلك، يتم التحقق من خلال تعبير نمطي.
3、إذا كان أكبر (max) أو أصغر (min)، يتم استخدام منطق مخصص.
4、إذا كان التحقق من fn، يتم التحقق بناءً على الدالة في controller المحدد.
5、المستخدم ينقر على زر التأكيد، ثم يتم التحقق مما إذا كانت الخيارات الإلزامية، وإذا لم يتم التحقق، يتم تحديد خلفية العنصر باللون الأحمر.
(5) التحقق من الفشل، يظهر التشجيع Factory---uiTipsFactory
app.factory('uiTipsFactory', function () { return { filterClass: function (ele, invalid) { if (invalid) { // إذا لم يتم التحقق من الصحة ele.removeClass('ng-valid').removeClass('ng-pristine').addClass('ng-invalid').addClass('ng-dirty'); else { ele.removeClass('ng-invalid').addClass('ng-valid'); }); }, on: function (ele, msg) { var lastTip = ele.data('last-tip'); if (lastTip && lastTip === msg) { return; }); ele.data('last-tip', msg); this.filterClass(ele, true); var offset = ele.offset(); if (!offset.top && !offset.left && ele.is('hidden')) { offset = ele.show().offset(); }); var id = ele.attr('ui-valid-id'); if (!id) { id = Math.guid(); ele.attr('ui-valid-id', id); }); if (id.contains('.')) { id = id.replace(/\\./g, '_'); }); var top = offset.top; left = offset.left; var getTips = function () { var _tip = $('#vtip_' + id); if (_tip.length) { _tip.html(msg).css({ 'display': 'none', 'top': top + 'px', 'left': left + ele.width() + 10 + 'px' validFn(ctrl.$modelValue, oldRules); else { var html = '<div id="vtip_{' + id + '}" class="vtip qtip qtip-rounded box-shadow-tips">' <div class="qtip-content">' + msg + '</div>; $(html).css({ 'display': 'none', 'position': 'absolute', 'top': top + 'px', 'left': left + ele.width() + 10 + 'px' }).appendTo($('body')); }); }); var bindTipsShow = function () { getTips(); ele.unbind('mouseenter mouseleave').bind('mouseenter', function () { var _tip = $('#vtip_' + id); if (_tip.is(':hidden')) { _tip.show(); }); }).bind('mouseleave', function () { $('#vtip_' + id).hide(); validFn(ctrl.$modelValue, oldRules); }); bindTipsShow(); }, off: function (ele) { ele.data('last-tip', ''); this.filterClass(ele); var id = ele.attr('ui-valid-id'); if (!id) { return; }); if (id.contains('.')) { id = id.replace(/\\./g, '_'); }); $('#vtip_' + id).remove(); ele.unbind('mouseenter mouseleave'); }); }); validFn(ctrl.$modelValue, oldRules);
1-إذا لم يتم التحقق من النجاح، يتم إضافة لون الخلفية، يتم التعامل مع CSS للعنصر كما يلي
ele.removeClass('ng-valid').removeClass('ng-pristine').addClass('ng-invalid').addClass('ng-dirty');
بعد التحقق من النجاح، يتم التعامل مع CSS كما يلي
ele.removeClass('ng-invalid').addClass('ng-valid');
2-إذا كانت الرسالة الخلفية، فإنها تضيف طبقة div على الجسم.
(6)كود مرتبط آخر
تعريف app = angular.module('myApp', []); app.controller('testCtrl', ['$scope', 'uiValidFactory', function ($scope, uiValidFactory) { $scope.certCheck = function (val) { إذا كان val > 32) { يعود "رقم كبير جدا"; }); return true; }); $scope.submit = function () { إذا (!uiValidFactory.checkValidForm($scope.baseInfoForm.$name)) { }); }); }] ); Math.guid = function () { تعريف a = "", b = 1; للدوران (; b <= 32; b++) { تعريف c = Math.floor(Math.random() * 16).toString(16); a += c; إذا كان b === 8 أو b === 12 أو b === 16 أو b === 20) { a += '-'; }); }); يعود a; }); String.prototype.contains = String.prototype.contains || function (a) { يعود هذا.indexOf(a) != -1; }); String.prototype.format = String.prototype.format || function () { var a = Array.prototype.slice.call(arguments); return this.replace(/\{(\d+)}/g, function (c, b) { return a[b]; }) });
النص الكامل كالتالي:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script src="jquery-1.11.1.js"></script> <script src="angular.js"></script> <style type="text/css"> input.ng-invalid, select.ng-invalid { background-color: #ee82ee !important; border: 1px solid #CCC; }); .qtip { position: absolute; max-width: 260px; display: none; min-width: 50px; font-size: 10.5px; line-height: 12px; direction: ltr; }); .qtip-content { position: relative; padding: 5px 9px; overflow: hidden; text-align: left; word-wrap: break-word; }); .qtip-rounded, .qtip-tipsy { -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }); .qtipmodal-ie6fix { position: absolute !important; }); .box-shadow-tips { background-color: #F63; border-color: #F5A88F; color: white; -moz-box-shadow: 2px 2px 2px #969696; -webkit-box-shadow: 2px 2px 2px #969696; box-shadow: 2px 2px 2px #969696; }); </style> </head> <body ng-app="myApp"> <form name="baseInfoForm"> <div ng-controller="testCtrl"> <input type="text" ng-model="age" my-valid="r"><br> <input type="text" ng-model="name" my-valid="int fn:certCheck"><br> <input type="button" value="إرسال" ng-click="submit()"> </div> </form> </body> <script type="text/javascript"> تعريف app = angular.module('myApp', []); app.controller('testCtrl', ['$scope', 'uiValidFactory', function ($scope, uiValidFactory) { $scope.certCheck = function (val) { إذا كان val > 32) { يعود "رقم كبير جدا"; }); return true; }); $scope.submit = function () { إذا (!uiValidFactory.checkValidForm($scope.baseInfoForm.$name)) { }); }); }] ); Math.guid = function () { تعريف a = "", b = 1; للدوران (; b <= 32; b++) { تعريف c = Math.floor(Math.random() * 16).toString(16); a += c; إذا كان b === 8 أو b === 12 أو b === 16 أو b === 20) { a += '-'; }); }); يعود a; }); String.prototype.contains = String.prototype.contains || function (a) { يعود هذا.indexOf(a) != -1; }); String.prototype.format = String.prototype.format || function () { var a = Array.prototype.slice.call(arguments); return this.replace(/\{(\d+)}/g, function (c, b) { return a[b]; }) }); app.factory('uiTipsFactory', function () { return { filterClass: function (ele, invalid) { if (invalid) { // إذا لم يتم التحقق من الصحة ele.removeClass('ng-valid').removeClass('ng-pristine').addClass('ng-invalid').addClass('ng-dirty'); else { ele.removeClass('ng-invalid').addClass('ng-valid'); }); }, on: function (ele, msg) { var lastTip = ele.data('last-tip'); if (lastTip && lastTip === msg) { return; }); ele.data('last-tip', msg); this.filterClass(ele, true); var offset = ele.offset(); if (!offset.top && !offset.left && ele.is('hidden')) { offset = ele.show().offset(); }); var id = ele.attr('ui-valid-id'); if (!id) { id = Math.guid(); ele.attr('ui-valid-id', id); }); if (id.contains('.')) { id = id.replace(/\\./g, '_'); }); var top = offset.top; left = offset.left; var getTips = function () { var _tip = $('#vtip_' + id); if (_tip.length) { _tip.html(msg).css({ 'display': 'none', 'top': top + 'px', 'left': left + ele.width() + 10 + 'px' validFn(ctrl.$modelValue, oldRules); else { var html = '<div id="vtip_{' + id + '}" class="vtip qtip qtip-rounded box-shadow-tips">' <div class="qtip-content">' + msg + '</div>; $(html).css({ 'display': 'none', 'position': 'absolute', 'top': top + 'px', 'left': left + ele.width() + 10 + 'px' }).appendTo($('body')); }); }); var bindTipsShow = function () { getTips(); ele.unbind('mouseenter mouseleave').bind('mouseenter', function () { var _tip = $('#vtip_' + id); if (_tip.is(':hidden')) { _tip.show(); }); }).bind('mouseleave', function () { $('#vtip_' + id).hide(); validFn(ctrl.$modelValue, oldRules); }); bindTipsShow(); }, off: function (ele) { ele.data('last-tip', ''); this.filterClass(ele); var id = ele.attr('ui-valid-id'); if (!id) { return; }); if (id.contains('.')) { id = id.replace(/\\./g, '_'); }); $('#vtip_' + id).remove(); ele.unbind('mouseenter mouseleave'); }); }); validFn(ctrl.$modelValue, oldRules); app.factory('uiValidFactory', ['$parse', 'uiTipsFactory', function ($parse, tips) { return { check: function (val, rules, $scope, defaultTips, extendParam) { إذا (!rules) { return { flag: true }); }); var rulesArr = rules.split(' '); isBlank = val === null || val === undefined || val === '' || ('' + val === ''); //إذا لم يكن العنصر إلزاميًا وكان ليس لديه قيمة، يتم مسح نافذة الإشعارات إذا (jQuery.inArray('r', rulesArr) === -1 && isBlank) { return { flag: true }); }); var i = 0, len = rulesArr.length; for (; i < len; i++) { var rule = rulesArr[i]; إذا (!rule) { continue; }); var flag = true; إذا ('r' === rule) { //إذا كان العنصر إلزاميًا وكان لديه قيمة، فسيتم العودة إلى الصحيح flag = !isBlank; } آخرا إذا (rule.contains(':')) { //إذا كان قاعدة التحقق هي fn:ctrl.certCheck flag = this.checkRule(val, rule.split(/:/), $scope, extendParam); else { //تحقق من أن النمط هو int باستخدام مطابقة النمط الرقمي البريد الإلكتروني الطول var pat = this.pats[rule]; إذا (pat instanceof RegExp) { إذا (angular.isString(val)) { flag = this.mat(val, pat); }); } آخرا إذا (angular.isFunction(pat)) { flag = pat(val); else { flag = false; }); }); //ما هو الغرض من هذا إذا (angular.isString(flag)) { return { flag: false, msg: flag, rule: rule }); }); إذا (flag === false) { var msg = this.getMsg(rule, defaultTips) || this.getMsg('tips.valid'); console.log(msg); return { flag: false, msg: msg, rule: rule }); }); }); return { flag: true }); }, checkRule: function (val, ruleArr, $scope, extendParam) { //ruleArr fn:certCheck var rule = ruleArr[0]; إذا (rule === 'fn') { fnName = ruleArr[1]; //تحديد اسم الدالة المطلوبة certCheck var fn = $parse(fnName)($scope); إذا (!fn) { return true; }); return fn.call($scope, val, extendParam); else { return true; }); }, checkValidForm: function (formName) { //تحقق فقط من الحقول الإلزامية //استخدام مبدأ التصفية للحصول على جميع العناصر داخلها var formContext = $('form[name="{0}"],[ng-form="{0}"],[data-ng-form="{0}"]'.format(formName)), validList = formContext.find('[my-valid]');//validList ليس قائمة، بل هو مجموعة وهمية إذا (!validList.length) { return; }); var that = this; validFlags = []; validList.each(function () { var ele = $(this), val = ele.val(), ruleStr = ele.attr('my-valid'); إذا (!ruleStr) { return true; }); إذا (angular.isString(val)) { val = val.trim(); }); var validRules = ruleStr.split(' '); إذا (!$.inArray('r', validRules) != -1 && !val) { var modelValue = ele.attr('ng-model') || ele.attr('data-ng-model'); validFlags.push(modelValue); tips.on(ele, that.getMsg('r')); }); }); ); return validFlags; }, mat: function (val, pat) { إذا (!pat) { return; }); return pat.test(val); }); , getMsg: function (rule, tips) { tips = tips || ''; //يمكن كتابة tips مباشرة على الواجهة إذا (tips && tips.contains(':')) { return tips; }); var msg = this.msgs[rule]; if (msg) { var params0 = tips.contains(':') ? tips.split(/:/)[0] : ''; var params1 = ''; if (rule.startsWith('min') || rule.startsWith('max')) { var ruleArr = rule.split(/:/); params1 = ruleArr[ruleArr.length - 1]; }); return msg.format(params0, params1); else { }); }); , regPat: function (code, pat, msg) { if (this.pat[code]) { return; }); this.pats[code] = pat; this.msgs[code] = msg; }); , msgs: { 'r': '必填', 'int': '{0}必须为整数' }); , pats: { 'int': /^[\-\+]?([0-9]+)$/ }); }); }); }) ; app.directive('myValid', ['$parse', 'uiTipsFactory', 'uiValidFactory', function ($parse, tips, valid) { var uiValidAttrIdName = 'ui-valid-id'; return { restrict: 'A', require: 'ngModel', link: function (scope, el, attrs, ctrl) { var validId = el.attr(uiValidAttrIdName); if (!validId) { validId = Math.guid(); el.attr(uiValidAttrIdName, validId); }); var getRules = function () { return attrs.myValid; }); var lastOldRules; var validFn = function (value, oldRules) { var sp = '_'; var rules = getRules(); var r = valid.check(value, rules, scope, attrs.uiValidTips); إذا (lastOldRules && !oldRules) { oldRules = lastOldRules; }); إذا (r.flag && oldRules) { rules = rules ? rules + ' ' + oldRules : oldRules; }); إذا (rules) { var arrInner = rules.split(' '); var i = 0; for (; i < arrInner.length; i++) { var oneRule = arrInner[i]; إذا (!oneRule.trim()) { continue; }); ctrl.$setValidity(attrs.ngModel + sp + oneRule, r.flag ? true : oneRule != r.rule); }); }); إذا (!r.flag) { tips.on(el, r.msg); else { tips.off(el); }); return r.flag; }); var init = function () { var rules = getRules(); إذا (!rules) { return; }); var parsers = ctrl.$parsers; إذا (parsers && parsers.length > 0) { parsers.clean(); }); parsers.unshift(function (value) { return validFn(value) ? value : undefined; validFn(ctrl.$modelValue, oldRules); }); scope.$watch(attrs.ngModel, function (newVal, oldVal) { إذا (newVal === oldVal) { return; }); إذا (ctrl.$modelValue != undefined && (ctrl.$invalid || el.hasClass('ng-invalid'))) { validFn(ctrl.$modelValue); }); validFn(ctrl.$modelValue, oldRules); scope.$watch(getRules, function (newRules, oldRules) { init(); lastOldRules = oldRules; if (ctrl.$modelValue === undefined || ctrl.$modelValue === null) { var needValid = false; el.hasClass('ng-invalid'); var isValNaN = ctrl.$viewValue !== ctrl.$viewValue; if (ctrl.$invalid || (ctrl.$viewValue !== undefined && !isValNaN)) { needValid = true; }); if (needValid) { ctrl.$setViewValue(ctrl.$viewValue); }); else { if (!ctrl.$dirty && attrs.dirtyCheck) { console.log('----'); else { } }); }); validFn(ctrl.$modelValue, oldRules); }); }); }); </script> </html>
بيان: محتويات هذا المقال تم جمعها من الإنترنت، وتعود حقوق الملكية إلى صاحبها، يتم جمع المحتويات من قبل المستخدمين على الإنترنت وتم تحميلها بشكل مستقل، ويتمتع هذا الموقع بعدم امتلاك حقوق الملكية، ولا يتم تعديل المحتويات بشكل يدوي، ولا يتحمل هذا الموقع أي مسؤولية قانونية متعلقة بذلك. إذا كنت قد وجدت محتوى يشتبه في انتهاك حقوق النسخ، فيرجى إرسال بريد إلكتروني إلى: notice#oldtoolbag.com (عند إرسال البريد الإلكتروني، يرجى استبدال # ب @) للإبلاغ، وتقديم الدليل المتعلق، وإذا تم التحقق من صحة المعلومات، سيتم حذف المحتوى المزعوم فوراً.