سؤال

أواجه مشكلة غير عادية مع مستند IE مع ضبط contentEditable على true.يؤدي استدعاء التحديد () على نطاق يتم وضعه في نهاية العقدة النصية التي تسبق عنصر الكتلة مباشرة إلى تحويل التحديد إلى الحرف الصحيح وظهوره في مكان لا ينبغي أن يظهر فيه.لقد أرسلت خطأً إلى Microsoft ضد IE8.إذا أمكن، يرجى التصويت لهذه المشكلة حتى يتم إصلاحها.

https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=390995

لقد كتبت حالة اختبار لتوضيح التأثير:

<html>
  <body>
    <iframe id="editable">
      <html>
        <body>
          <div id="test">
            Click to the right of this line -&gt;
            <p id="par">Block Element</p>
          </div>
        </body>
      </html>
    </iframe>
    <input id="mytrigger" type="button" value="Then Click here to Save and Restore" />
    <script type="text/javascript">
        window.onload = function() {
            var iframe = document.getElementById('editable');
            var doc = iframe.contentDocument || iframe.contentWindow.document;

            // An IFRAME without a source points to a blank document.  Here we'll
            // copy the content we stored in between the IFRAME tags into that
            // document.  It's a hack to allow us to use only one HTML file for this
            // test.
            doc.body.innerHTML = iframe.textContent || iframe.innerHTML;

            // Marke the IFRAME as an editable document
            if (doc.body.contentEditable) {
                doc.body.contentEditable = true;
            } else {
                var mydoc = doc;
                doc.designMode = 'On';
            }

            // A function to demonstrate the bug.
            var myhandler = function() {
                // Step 1 Get the current selection
                var selection = doc.selection || iframe.contentWindow.getSelection();
                var range = selection.createRange ? selection.createRange() : selection.getRangeAt(0);

                // Step 2 Restore the selection
                if (range.select) {
                    range.select();
                } else {
                    selection.removeAllRanges();
                    selection.addRange(range);
                    doc.body.focus();
                }
            }

            // Set up the button to perform the test code.
            var button = document.getElementById('mytrigger');
            if (button.addEventListener) {
                button.addEventListener('click', myhandler, false);
            } else {
                button.attachEvent('onclick', myhandler);
            }
          }
    </script>
  </body>
</html>

تم الكشف عن المشكلة في وظيفة myhandler.هذا هو كل ما أفعله، لا توجد خطوة 3 بين حفظ التحديد واستعادته، ومع ذلك يتحرك المؤشر.لا يبدو أن هذا يحدث إلا إذا كان التحديد فارغًا (على سبيل المثال.لدي مؤشر وامض، ولكن لا يوجد نص)، ويبدو أن هذا يحدث فقط عندما يكون المؤشر في نهاية العقدة النصية التي تسبق عقدة الكتلة مباشرة.

يبدو أن النطاق لا يزال في الموضع الصحيح (إذا قمت باستدعاءparentElement على النطاق فإنه يُرجع div)، ولكن إذا حصلت على نطاق جديد من التحديد الحالي، فسيكون النطاق الجديد داخل علامة الفقرة، وهذا هو ParentElement.

كيف يمكنني التغلب على هذه المشكلة وحفظ التحديد واستعادته باستمرار في Internet Explorer؟

هل كانت مفيدة؟

المحلول

لقد اكتشفت بعض الطرق للتعامل مع نطاقات IE مثل هذا.

إذا كان كل ما تريد القيام به هو حفظ مكان المؤشر، ثم استعادته، فيمكنك استخدام أسلوب اللصقHTML لإدراج مسافة فارغة في الموضع الحالي للمؤشر، ثم استخدام أسلوب moveToElementText لوضعه مرة أخرى في هذا الموضع مرة أخرى:

// Save position of cursor
range.pasteHTML('<span id="caret"></span>')

...

// Create new cursor and put it in the old position
var caretSpan = iframe.contentWindow.document.getElementById("caret");
var selection = iframe.contentWindow.document.selection;
newRange = selection.createRange();
newRange.moveToElementText(caretSpan);

وبدلاً من ذلك، يمكنك حساب عدد الأحرف التي تسبق موضع المؤشر الحالي وحفظ هذا الرقم:

var selection = iframe.contentWindow.document.selection;
var range = selection.createRange().duplicate();
range.moveStart('sentence', -1000000);
var cursorPosition = range.text.length;

لاستعادة المؤشر، قم بضبطه على البداية ثم قم بتحريكه بهذا العدد من الأحرف:

var newRange = selection.createRange();
newRange.move('sentence', -1000000);
newRange.move('character', cursorPosition);

أتمنى أن يساعدك هذا.

نصائح أخرى

لقد قمت ببعض الحفر وللأسف لم أتمكن من رؤية الحل البديل ...على الرغم من أن شيئًا واحدًا لاحظته أثناء تصحيح أخطاء جافا سكريبت، يبدو أن المشكلة تكمن في الواقع في كائن النطاق نفسه وليس في كائن النطاق اللاحق range.select().إذا نظرت إلى القيم الموجودة في نطاق الكائن selection.createRange() إرجاع، نعم قد يكون كائن dom الأصلي صحيحًا، لكن معلومات تحديد الموضع تشير بالفعل إلى بداية السطر التالي (أيOffsetLeft/Top وboundingLeft/Top وما إلى ذلك كلها خاطئة بالفعل).

بناء على المعلومات هنا, هنا و هنا, ، أعتقد أنك غير محظوظ مع IE، نظرًا لأنه لا يمكنك الوصول إلا إلى كائن TextRange الخاص بـ Microsoft، والذي يبدو أنه معطل.من خلال تجربتي، يمكنك تحريك النطاق ووضعه في المكان الذي يجب أن يكون فيه بالضبط، ولكن بمجرد القيام بذلك، ينتقل كائن النطاق تلقائيًا إلى السطر التالي حتى قبل أن تحاول ذلك .select() هو - هي.على سبيل المثال، يمكنك رؤية المشكلة عن طريق وضع هذا الرمز بين الخطوة 1 والخطوة 2:

if (range.boundingWidth == 0)
{
    //looks like its already at the start of the next line down...
    alert('default position: ' + range.offsetLeft + ', ' + range.offsetTop);
    //lets move the start of the range one character back
    //(i.e. select the last char on the line)
    range.moveStart("character", -1);
    //now the range looks good (except that its width will be one char);
    alert('one char back: ' + range.offsetLeft + ', ' + range.offsetTop);
    //calculate the true end of the line...
    var left = range.offsetLeft + range.boundingWidth;
    var top = range.offsetTop;
    //now we can collapse back down to 0 width range
    range.collapse();
    //the position looks right
    alert('moving to: ' + left + ', ' + top);
    //move there.
    range.moveToPoint(left, top);
    //oops... on the next line again... stupid IE.
    alert('moved to: ' + range.offsetLeft + ', ' + range.offsetTop);
}

لذا، لسوء الحظ، لا يبدو أن هناك أي طريقة للتأكد من أن النطاق في المكان الصحيح عند تحديده مرة أخرى.

من الواضح أن هناك إصلاحًا تافهًا للتعليمات البرمجية الخاصة بك أعلاه، وذلك عن طريق تغيير الخطوة 2 إلى هذا:

// Step 2 Restore the selection
if (range.select) {
    if (range.boundingWidth > 0) {
        range.select();
    }
} else {
    selection.removeAllRanges();
    selection.addRange(range);
    doc.body.focus();
}

ولكن من المفترض أنك تريد فعلًا القيام بشيء ما بين الخطوة 1 والخطوة 2 في موقعك الفعلي والذي يتضمن نقل التحديد، ومن هنا الحاجة إلى إعادة تعيينه.ولكن فقط في حالة.:)

لذا، أفضل ما يمكنني فعله هو الذهاب والتصويت لصالح الخطأ الذي قمت بإنشائه...نأمل أن يصلحوه.

لقد عملت مؤخرًا في موقع يستخدم Microsoft CMS مع "حزمة MSIB+" من عناصر التحكم التي تتضمن محرر WYSIWYG الذي يعمل في Internet Explorer.

يبدو أنني أتذكر بعض التعليقات في محرر Javascript من جانب العميل والتي كانت مرتبطة على وجه التحديد بهذا الخطأ في IE وطريقة Range.Select().

لسوء الحظ، أنا لا أعمل هناك بعد الآن لذا لا أستطيع الوصول إلى ملفات جافا سكريبت، ولكن ربما يمكنك الحصول عليها من مكان آخر؟

حظ سعيد

ربما أسيء الفهم، ولكن إذا نقرت على يمين السطر الأول، فسيظهر المؤشر على الفور في بداية السطر الثاني، لذا فهذه ليست مشكلة TextRange، أليس كذلك؟

تؤدي إضافة نوع مستند بحيث يتم عرض صفحة الاختبار في الوضع القياسي بدلاً من وضع المراوغات إلى إصلاح ذلك بالنسبة لي.

ولا يمكنني إعادة إنتاج ما تفعله وظيفة myhandler الخاصة بك، لأن النقر على هذا الزر ينقل التركيز بعيدًا إلى الزر بحيث لا أستطيع رؤية المؤشر ولا يمكنني استعادته أيضًا.العثور على موضع المؤشر في أ contentEditable منطقة يبدو أن مشكلة مختلفة تماما.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top