Chúng tôi đang viết trình soạn thảo WYSIWYG trực tuyến chính xác. Tại sao điều này là cần thiết?

Khi tôi viết lại mã, hay đúng hơn là một công cụ đơn giản, tôi quyết định triển khai một trình chỉnh sửa cho chính các trang của trang web, bao gồm cả bảng quản trị. Nhiều người trên diễn đàn viết - “Tại sao điều này lại cần thiết, hãy chỉnh sửa bằng notepad.” Nhưng tôi muốn nó giống như trong WordPress, nhưng để ngay cả trang chỉnh sửa cũng có sẵn để chỉnh sửa.

BÀI VIẾT CÓ THỂ KHÔNG HIỂU MỌI NGƯỜI. ĐẦU TIÊN TÔI SẼ ĐĂNG TOÀN BỘ NGUỒN NHỮNG GÌ TÔI ĐÃ LÀM. Liên kết đĩa Yandex TRONG THƯ MỤC WWW TẤT CẢ NGUỒN CÓ TỆP TPL

Bản thân trình chỉnh sửa nằm trong bảng quản trị, trong tệp admin.php. Cài đặt Denwer và khởi chạy bảng quản trị để rõ ràng.

Viết trình soạn thảo không khó lắm. Tôi đã viết một hàm để hiển thị các tệp từ thư mục gốc của trang web và tất cả các thư mục bằng phương pháp đệ quy. Và thêm chức năng hiển thị nội dung của file trong vùng văn bản, sử dụng file_get_contents() và mọi thứ dường như hoạt động. Lưu nội dung qua file_put_contents() rồi làm mới trang soạn thảo, NHƯNG.

Vấn đề là nếu tôi tải xuống để chỉnh sửa một tệp trang web sử dụng cùng một tệp này vùng văn bản, trong đó các tập tin được chỉnh sửa. Chỉ một phần mã được tải vào trình chỉnh sửa, cho đến thẻ đóng vùng văn bản. Phần còn lại của tệp đã chỉnh sửa đã được hợp nhất vào mã trang của trình soạn thảo.

Thêm chi tiết trong các hình ảnh dưới đây:

1. Trình soạn thảo được triển khai như thế nào. Xuất ra vùng văn bản nội dung tập tin bằng cách sử dụng một hàm.

2. Hàm đầu ra chứa gì sau khi đọc tệp soạn thảo.

3. Những gì hiển thị trong mã nguồn của trình soạn thảo khi tải một tệp để chỉnh sửa mã của nó.

4. Một đoạn mã được hiển thị trong chính trình soạn thảo, trong vùng văn bản.

Từ ảnh chụp màn hình, bạn có thể thấy rằng một phần mã đã được trình duyệt đọc chính xác đến dòng để đóng cái xấu số vùng văn bản. Kết quả rất rõ ràng, trình soạn thảo được hiển thị với một jamb và nếu bạn lưu những gì có trong trình chỉnh sửa, trình chỉnh sửa sẽ ngừng hoạt động vì sẽ chỉ có một phần mã cần thiết ở đó.

Tôi đã giải quyết vấn đề bằng cách thay thế thẻ kết thúc vùng văn bảnđến một biểu thức phức tạp có dạng, ví dụ: \.*-+*-*06textarea-*/+*-+*/+\. Hàm str_replace() .

Nghĩa là, khi chúng ta tải một tệp để xử lý và chỉnh sửa mã, chúng ta đọc nó thành một biến, duyệt qua hàm str_replace() và thay thế tệp mong muốn bằng một biểu thức lạ. Kết quả, trình soạn thảo sẽ hiển thị:

Và khi lưu mã đã chỉnh sửa vào file đang làm việc, chúng ta thực hiện quy trình ngược lại. Và tệp sẽ được hiển thị trên trang web của bạn sẽ có thẻ kết thúc bình thường vùng văn bản. Phương pháp này không phải là tốt nhất, nhưng tệ nhất nó lại là một giải pháp.


Lỗi tạo khóa AWP khi mở tài liệu văn bản.

Khi làm việc với chương trình tạo khóa AWP, các vấn đề thường phát sinh. Một số trong số chúng được mô tả trên trang web chính thức của Kho bạc, nhưng vấn đề xảy ra lỗi khi in đơn, ở cuối quy trình tạo, vì vậy […]

Cài đặt và kích hoạt Corel Draw/Corel Draw X4

Nhiều người gặp phải vấn đề cài đặt và kích hoạt chương trình Corel Dro. Bài viết này sẽ cho bạn biết cách giải quyết vấn đề khi cài đặt và kích hoạt. Tài liệu được chuẩn bị chỉ nhằm mục đích cung cấp thông tin, cài đặt chương trình theo cách […]

Dành riêng cho tất cả những người giao dịch với ví lạnh ví luna và đồng Expanse. Trong bài viết này tôi muốn phân tích vấn đề gửi tiền từ ví đến sàn giao dịch. Sự thật là […]

Giới thiệu và hiểu vấn đề

Tại sao điều này là cần thiết?

WYSIWYG( Bạn là gì Xem là những gì bạn nhận được) là một môi trường trong đó người dùng nhìn thấy ngay kết quả công việc của mình. Ví dụ: trình soạn thảo Frontpage - chúng tôi thấy ngay tài liệu ở hầu hết Hình thức cuối cùng, không giống như làm việc với mã nguồn trang. Hỗ trợ cho phép bạn tạo trình soạn thảo trực tuyến Trình duyệt của Microsoft trình duyệt web IE(phiên bản 5.5 trở lên), Mozilla (1.3+)/ Firefox và Opera (9.0+) Chế độ chỉnh sửa văn bản WYSIWYG (designMode).

Lưu ý 2: Opera 9 chưa được phát hành nên chúng tôi sẽ viết về nó sau. Nhìn chung, việc triển khai DesignMode trong Opera tương tự như trong Gecko.

Trình soạn thảo WYSIWYG giúp việc này trở nên dễ dàng hơn nhiều công việc thường ngày xuất bản nội dung. Nó cũng làm giảm các yêu cầu về trình độ chuyên môn đối với nhân viên làm việc với nội dung. Vì vậy, điều này là hữu ích và cần thiết.

Nhưng nó cũng có một nhược điểm nghiêm trọng - hãy gọi nó là "Hội chứng từ" - sự chiếm ưu thế của đánh dấu trực quan so với logic, khi nói một cách tương đối, tiêu đề trong tài liệu được tạo bằng cách đặt một ký tự lớn và in đậm. Trong dự án của chúng tôi, chúng tôi sẽ cố gắng tránh nhược điểm này (hoặc ít nhất là giảm thiểu nó).

Cần phân biệt giữa người thiết kế bố cục tạo ra các mẫu và thiết kế phức tạp và người vận hành làm việc với nội dung. Chúng tôi sẽ giả định rằng trình soạn thảo trực tuyến nên được thực hiện tập trung chủ yếu vào người vận hành; hãy để người thiết kế bố cục thực hiện bố cục trong sổ ghi chú hoặc biên tập viên chuyên ngành. Anh ấy là người chuyên nghiệp, anh ấy biết rõ hơn. Nhưng đối với người điều hành, việc biên tập thêm là không cần thiết. Do đó, hãy để anh ta làm việc trong giao diện quản trị với trình soạn thảo WYSIWYG của chúng tôi, một trong những nhiệm vụ của nhiệm vụ này là giữ cho người vận hành nằm trong ranh giới của biểu định kiểu do nhà thiết kế chỉ định (và giúp anh ta “quay lại dễ dàng hơn”. con đường đúng đắn”). Không thể (hoặc sẽ khó) đưa “diễn viên hài béo đỏ +3” lên trang web mà bỏ qua nhà thiết kế.

Nó phải như thế nào (Đúng WYSIWYG)

Rõ ràng, đại đa số các trình soạn thảo trực tuyến được cung cấp đều được xây dựng dựa trên nguyên tắc “Chọn phông chữ, kích thước, màu sắc”, tức là chúng không chính xác. Bởi vì việc đánh dấu mã thu được với sự trợ giúp của họ không thể được gọi là logic theo bất kỳ cách nào. Điều này có nghĩa là chúng tôi sẽ viết một trình soạn thảo trong đó người dùng thao tác với các thực thể như “Tiêu đề cấp N”, “Ghi chú đoạn văn” và “Văn bản quan trọng” và giao diện của chúng do người thiết kế trang web quyết định, đăng ký quyết định của anh ấy trong bảng định kiểu. Do đó, trình soạn thảo của chúng tôi sẽ phải hoạt động với các thẻ và lớp kiểu được phép.

Hiện thân

Vấn đề lớn mà chúng tôi phải đối mặt là các giao diện tiêu chuẩn cho trình chỉnh sửa tích hợp được triển khai trong trình duyệt có xu hướng thiên về “cỡ chữ-màu sắc”. Nhân tiện, đây là lý do dẫn đến sự “không chính xác” của các trình soạn thảo WYSIWYG nói trên. Giao diện có lệnh “tô màu phông chữ”, có lệnh “đặt cỡ chữ” nhưng không có lệnh “đóng khung vùng chọn” với thẻ được yêu cầu với lớp được yêu cầu." Để biết thêm thông tin về API (Giao diện chương trình ứng dụng) của các trình soạn thảo tích hợp, hãy xem thông tin trên các trang web của Mạng lưới nhà phát triển Microsoft - MSDN và Mozilla.

Vì vậy, công việc của chúng tôi sẽ là triển khai những khả năng bổ sung này.

Lưu ý: Vì cuộc chiến trình duyệt vẫn chưa kết thúc nên chúng ta cần phải các trình duyệt khác nhau viết mã khác nhau. Chúng tôi sẽ phân biệt giữa các trình duyệt bằng cách kiểm tra xem chúng hỗ trợ mã nào và mã nào không. Điều này sẽ cho phép chúng tôi không phải bận tâm đến việc kiểm tra tác nhân người dùng và phiên bản.

Vì vậy, hãy xây dựng những gì chúng ta cần:

Thiết kế vùng chọn bằng thẻ khối bắt buộc (may mắn thay, có lệnh formatBlock) với thuộc tính lớp bắt buộc (không có gì được tạo sẵn ở đây) hoặc không có thuộc tính này.
Thiết kế lựa chọn với thẻ nội tuyến mong muốn có hoặc không có lớp.
Gán các thuộc tính (chủ yếu là các lớp) cho các đối tượng không phải văn bản - hình ảnh (cũng hữu ích khi gán src và alt cho chúng), bảng, dòng


.
Xóa định dạng không phù hợp bảng đã cho kiểu (hữu ích khi sao chép văn bản từ tài liệu của Microsoft Office, các trang web khác, v.v.).
Chà, ngoài tất cả mọi thứ, người biên tập phải biện minh cho tiêu đề “WYSIWYG”, có tính đến các tệp CSS từ trang web khi hiển thị văn bản.

Bảng chỉnh sửa

Bảng chỉnh sửa trên nhiều trình duyệt là một tài liệu có thuộc tính DesignMode được đặt thành "Bật". Vì chúng ta thường không cần chỉnh sửa toàn bộ nội dung của cửa sổ trình duyệt nên việc đính kèm tài liệu này trong một khung (khung thông thường hoặc iframe nổi) sẽ rất thuận tiện.

Sẽ là một ý tưởng hay nếu thêm một vùng văn bản vào khung này để có thể chuyển trình soạn thảo từ chế độ trực quan sang chế độ làm việc với mã HTML.

Trình duyệt tự động thay thế địa chỉ của các liên kết tương đối được chèn vào trình chỉnh sửa, chuyển chúng thành dạng tuyệt đối. Nghĩa là, nói một cách tương đối, nếu trình soạn thảo của chúng tôi có địa chỉ http://www.site.ru/admin/, chúng tôi chèn một ảnh có địa chỉ image.gif vào đó, thì nó sẽ tự động được chuyển thành http://www .site.ru/ admin/image.gif và rất có thể chúng tôi sẽ không nhìn thấy ảnh. Đây là một vấn đề, vì đối với một trình soạn thảo "phù hợp" thì rất mong muốn có thể chèn liên kết tương đối.

Chúng ta sẽ giải quyết vấn đề này như thế này:

Đầu tiên, điều cần thiết là tài liệu đóng vai trò là bảng chỉnh sửa phải có địa chỉ là địa chỉ của trang trên trang mà chúng tôi đang chỉnh sửa, chính xác đến location.search (phần địa chỉ sau dấu “?”). Khi đó các liên kết tương đối từ văn bản trong trình soạn thảo và trên trang web sẽ giống nhau.

Thứ hai, khi chuyển trình soạn thảo sang chế độ nguồn HTML và lưu, bạn nên chuyển đổi địa chỉ liên kết thành dạng tương đối (tối thiểu, hãy xóa khỏi chúng phần địa chỉ chung cho trang đang được chỉnh sửa và liên kết).

Về vấn đề này, chúng tôi sẽ tải vào khung tài liệu riêng biệt Với địa chỉ cần thiết(ví dụ: để công cụ trang web xuất ra tài liệu trống khi yêu cầu một trang có khóa?wysiwyg=yes). Hay đúng hơn là không trống hoàn toàn, đối với MSIE, tài liệu cần phải có thẻ , nếu không sẽ không có gì để gán cho InternalHTML. Chúng tôi cho rằng việc công cụ tạo ra văn bản có thể chỉnh sửa thay vì HTML trống là không phù hợp vì điều này làm phức tạp công cụ một cách không cần thiết mà không mang lại bất kỳ lợi ích nào. Chúng ta sẽ nhận văn bản từ vùng văn bản, điều này vẫn cần thiết cho giao diện soạn thảo.

Đồng thời, bạn có thể thêm kiểu vào tài liệu đã tải này:

,

Bạn cũng có thể liên kết một biểu định kiểu với một tài liệu được tải vào iframe bằng cách tạo một phần tử thuộc loại trong phần đầu của nó bằng các phương thức DOM , trỏ đến một tệp có biểu định kiểu.

var style = document.createElement("link") style.rel = "stylesheet" style.type = "text/css" style.href = "myStyleSheet.css" document.getElementsByTagName("head").appendChild(style)

Tài liệu ở đây là tài liệu của trình soạn thảo khung.

Có thể có một số vấn đề khi gán nội dung do thực tế là việc gán phải được thực hiện sau tất cả các loại tải và sau một thời gian chờ sau khi cài đặt DesignMode (trong MSIE). Giải pháp sau đây có thể được đề xuất:
Bằng cách sử dụng try-catch(), chúng tôi cố gắng gán InternalHTML; nếu điều đó không hiệu quả, chúng tôi thực hiện một setTimeout nhỏ và thử lại. Thực tế cho thấy rằng ngay cả khi thời gian chờ là 0 mili giây, việc lặp lại vẫn không xảy ra. Ban đầu, bạn có thể thực hiện bài tập dựa trên thời gian chờ.

Lưu ý 1: Đầu tiên chúng ta đặt DesignMode, sau đó chúng ta gán nội dung.

Lưu ý 2: Trong Gecko bạn không thể đặt DesignMode yếu tố ẩn(không trưng bày). Điều này sẽ cần phải được tính đến, vì trình chỉnh sửa đang được tạo bằng bảng chuyển đổi nguồn WYSIWYG / HTML.

Hãy bắt đầu viết mã.

HTML

Ở đây chúng tôi có một vùng văn bản để làm việc với nguồn HTML và iframe cho WYSIWYG. Trình chỉnh sửa ở chế độ nguồn HTML (iframe ẩn). Để thay đổi mặc định, chỉ cần di chuyển display:none; theo phong cách vùng văn bản.

Bạn có thể thêm một nút để chuyển đổi chế độ:

Bây giờ chúng tôi không nghĩ về chức năng đặc biệt. Bạn có thể tạo hộp kiểm, bạn có thể thực hiện chuyển đổi tab "Bình thường - HTML", v.v.

Javascript // Khởi tạo trình soạn thảo onload = function())( wysiwyg_init("wysiwyg_textarea", "wysiwyg_iframe") ) // Khởi tạo các hàm làm đầu vào, chúng tôi cung cấp id của các thành phần vùng văn bản và iframe của hàm soạn thảo wysiwyg_init(textarea_id, iframe_id )( var textarea = document.getElementById (textarea_id) var iframe = document.getElementById(iframe_id) // Kiểm tra sự tồn tại của iframe và textarea // Sử dụng offsetWidth, kiểm tra mức độ hiển thị của iframe - nghĩa là trình soạn thảo ở dạng trực quan mode if(iframe && textarea && iframe.offsetWidth)( iframe.contentWindow. document.designMode = "On" // Đối với Gecko, chúng tôi đặt chế độ để việc định dạng được thực hiện bằng thẻ chứ không phải kiểu // Để ngăn MSIE đưa ra lỗi , chúng tôi ẩn phần này trong cấu trúc try-catch try( iframe.contentWindow.document.execCommand("useCSS ", false, true) )catch(e)() // Sao chép văn bản từ textarea sang iframe wysiwyg_textarea2iframe(textarea_id, iframe_id) ) ) // Sao chép văn bản từ vùng văn bản sang iframe hàm wysiwyg_textarea2iframe(textarea_id, iframe_id)( try( document.getElementById (iframe_id).contentWindow.document.body.innerHTML = document.getElementById(textarea_id).value )catch(e)( setTimeout( "wysiwyg_textarea2iframe("" + textarea_id + "", "" + iframe_id + "")", 0 ) ) ) // Chuyển trình soạn thảo từ chế độ trực quan sang chế độ HTML và quay lại chức năng wysiwyg_switch_mode(textarea_id, iframe_id)( var textarea = document .getElementById(textarea_id) var iframe = document.getElementById(iframe_id) if(iframe && textarea)( / / editor ở chế độ chỉnh sửa nguồn HTML if(textarea.offsetWidth)( // Đầu tiên hiển thị iframe, sau đó ẩn vùng văn bản. // Thứ tự này để việc cuộn không bị nhảy // do trang bị rút ngắn trong giây lát. iframe.style.display = "" textarea.style.display = "none" wysiwyg_init(textarea_id, iframe_id) iframe.focus() )else( // Trình chỉnh sửa ở chế độ trực quan textarea.style.display = "" iframe.style.display = "không" textarea.value = iframe.contentWindow.document.body.innerHTML textarea.focus() ) ) )

Lựa chọn
“Tuyển chọn” là một khái niệm then chốt trong công việc của người biên tập. Đây là khu vực mà lệnh định dạng sẽ tác động. Nó có thể là văn bản hoặc “khách quan”. Hãy thử tạo một tài liệu có ảnh trong một số trình soạn thảo (ví dụ: Word), sau đó trỏ chuột vào ảnh và nhấn Ctrl+A (chọn tất cả) - bạn sẽ thấy rằng việc chọn ảnh sẽ trông khác - trong trường hợp đầu tiên, nó được chọn làm hình ảnh (đối tượng), trong phần thứ hai - như một phần của văn bản.

Nếu chúng ta muốn hình ảnh chỉ định một lớp, chúng ta sẽ phải phân bổ nó theo đối tượng. Nếu chúng tôi muốn đặt một liên kết từ nó - bằng văn bản.

Trình chỉnh sửa của chúng tôi sẽ có thể nhận danh sách các nút tài liệu đã chọn, tạo các nút mới nếu cần (nếu một phần của nút cần áp dụng định dạng nội tuyến được chọn).

Chức năng cơ bản khi làm việc với một vùng chọn là lấy các nút bắt đầu và kết thúc của vùng chọn. Từ cặp này, chúng ta có thể lấy toàn bộ tập hợp các nút thuộc loại mà chúng ta cần đưa vào vùng chọn.

Chúng tôi nhận được các nút bắt đầu và kết thúc của lựa chọn (cũng như cha mẹ chung gần nhất của chúng)
Lưu ý: Có một yếu tố không hề nhỏ ở đây do cách triển khai lựa chọn "lạ" trong MSIE.

// Lấy các nút lựa chọn ngoài cùng (root - root và nút ngoài cùng "left" và "right" - bắt đầu và kết thúc) // cung cấp một cửa sổ làm đầu vào (tức là iframe.contentWindow) function get_selection_bounds(editor_window)( var range, root , start, end if(editor_window.getSelection)( // Gecko, Opera var Selection = editor_window.getSelection() // Một vùng chọn, nói chung, có thể bao gồm nhiều vùng. // Nhưng khi viết một trình soạn thảo, chúng ta không cần quan tâm về điều này, hãy lấy số 0: range = Selection.getRangeAt(0) start = range.startContainer end = range.endContainer root = range.commonAncestorContainer if(start == end) root = start if(start.nodeName.toLowerCase() = = "body") trả về null // nếu các nút là văn bản, hãy lấy cha mẹ của chúng if(start.nodeName == "#text") start = start.parentNode if(end.nodeName == "#text") end = end .parentNode return ( root : root, start: start, end: end ) )else if(editor_window.document.selection)( // MSIE range = editor_window.document.selection.createRange() if(!range.duplicate) return null var r1 = range.copy() var r2 = range.duplicate() r1.collapse(true) r2.moveToElementText(r1.parentElement()) r2.setEndPoint("EndToStart", r1) start = r1.parentElement() r1 = range.duplicate( ) r2 = range.duplicate() r2.collapse(false) r1.moveToElementText(r2.parentElement()) r1.setEndPoint("StartToEnd", r2) end = r2.parentElement() root = range. parentElement() if( start == end) root = start return ( root: root, start: start, end: end) ) return null // trình duyệt không hỗ trợ lựa chọn)

Chúng tôi nhận được danh sách tất cả các nút có tên thẻ cụ thể nằm giữa đầu và cuối của vùng chọn
Khi chúng tôi áp dụng lệnh định dạng cho các khối hoặc nội tuyến bằng một thẻ cụ thể với một lớp cụ thể, chúng tôi có thể kết thúc bằng nhiều nút, vì vậy chúng tôi không chỉ quan tâm đến nút bắt đầu và nút kết thúc. Việc thông qua nextSiblings là không phù hợp, bởi vì Chúng ta có thể cần phải đi lên và xuống cây nút trong quá trình truyền tải. Do đó, thuật toán như sau: sau khi nhận được cha mẹ chung gần nhất (gốc), từ cây con của con cháu nó, bị giới hạn bởi nút bắt đầu và nút kết thúc, chúng ta chọn tất cả các nút mà chúng ta cần.

Hàm này rất có thể cần được tối ưu hóa, nếu không nó sẽ được viết thông qua một biến toàn cục...

var Global_stage // biến toàn cục xấu // giới hạn - mảng // tag_name - tên thẻ // các đối số khác không được chỉ định, được sử dụng cho hàm đệ quy find_tags_in_subtree(bounds, tag_name, stage, giây)( var root =bounds["root"] var start = giới hạn["bắt đầu"] var end = giới hạn["end"] if(start == end) return if(!second) Global_stage=stage if(global_stage == 2) return if(!global_stage) Global_stage = 0 tag_name = tag_name.toLowerCase() var node= for(var node = root.firstChild; node; node = node.nextSibling)( if(node==start && Global_stage==0)( Global_stage = 1 ) if(node.nodeName . toLowerCase() == tag_name && node.nodeName != "#text" || tag_name == "")( if(global_stage == 1)( node.push(node) ) ) if(node==end && Global_stage = =1)( Global_stage = 2 ) node=nodes.concat(find_tags_in_subtree((root:node, start:start, end:end), tag_name, Global_stage, true)) ) trả về các nút )

Cha mẹ gần nhất có thẻ mong muốn
Chúng tôi cung cấp tên nút và thẻ làm đầu vào. Nếu nút đã là thẻ mong muốn, nếu nó không có nút cha phù hợp hoặc nếu tên thẻ trống, hãy trả về nút đó. Nếu không, chúng tôi trả về phần tử cha gần nhất có tên thẻ mong muốn.

// Cha mẹ gần nhất với hàm thẻ mong muốn gần nhất_parent_by_tag_name(node, tag_name)( tag_name = tag_name.toLowerCase() var p = node do( if(tag_name == "" || p.nodeName.toLowerCase() == tag_name) return p )while(p = p.parentNode) return node ) Một mảng gồm tất cả các nút có thẻ mong muốn được bao gồm trong hàm chọn get_selected_tags(editor_window, tag_name)( if(tag_name)( tag_name = tag_name.toLowerCase() )else( tag_name) = "" ) var giới hạn = get_selection_bounds(editor_window) if(!bounds) trả về giới hạn null["start"] = Near_parent_by_tag_name(bounds["start"], tag_name) giới hạn["end"] = Near_parent_by_tag_name(bounds["end" ], tag_name) trả về find_tags_in_subtree(bounds, tag_name) )

Khối định dạng

API có lệnh formatBlock, nó được đặt tên của thẻ khối làm đầu vào và nó định dạng lựa chọn hiện tại bằng thẻ này.
Ví dụ:
document.execCommand("formatBlock", sai, "

").

// Chúng tôi thiết kế vùng chọn với thẻ khối bắt buộc có hàm lớp bắt buộc wysiwyg_format_block(iframe_id, tag_name, class_name)( var iframe = document.getElementById(iframe_id) var wysiwyg = iframe.contentWindow.document // Chúng tôi thiết kế với khối mong muốn gắn thẻ wysiwyg.execCommand("khối định dạng" ,false,"<" + tag_name + ">") // Chọn tất cả các thẻ có tên mong muốn từ vùng chọn và gán cho chúng một lớp var node = get_selected_tags(iframe.contentWindow, tag_name) for(var i = 0; i< nodes.length; i++){ if(class_name){ // Устанавливаем класс nodes[i].className = class_name }else{ // Убираем класс, если он нам не нужен nodes[i].removeAttribute("class") nodes[i].removeAttribute("className") } } iframe.focus() }

Định dạng từ (nội tuyến)

Thoạt nhìn có vẻ như giữa nội tuyến và khối yếu tố không có sự khác biệt cơ bản nào về việc chúng có thể được xử lý theo cùng một cách. Thực ra không phải vậy... Thực tế là trong API biên tập trực quan Không có lệnh để tạo kiểu bằng thẻ dòng tùy chỉnh. Và bằng cách nào đó chúng ta cần chèn một thẻ chưa tồn tại dọc theo ranh giới lựa chọn. Có một ý tưởng là sử dụng một trong các lệnh cho việc này để chèn một thẻ chuỗi nhưng có hại về mặt ý thức hệ.

Một giải pháp đầy hứa hẹn là sử dụng lệnh ForeColor, lệnh này sẽ chèn . Riêng tôi chúng tôi thực sự không cần nó trong trình soạn thảo nhất quán về mặt tư tưởng của mình, nhưng điều này sẽ cho phép chúng tôi tạo các nút chuỗi theo cách thông thường mà chúng tôi có thể chọn lại từ vùng chọn và thay đổi tagName và className của chúng (và xóa thuộc tính màu sắc). Để đảm bảo an toàn, chúng ta có thể chèn và sau đó tìm kiếm một màu cụ thể, được chọn theo cách gần như loại bỏ tình huống khi chúng ta gặp nó trong văn bản được sao chép từ một tài liệu khác, chẳng hạn như #00ff01 (mặc dù nó sẽ vẫn bị phá hủy bởi trình dọn dẹp HTML mà chúng tôi đã lên kế hoạch).

// "Magic" màu không được sử dụng var magic_unusual_color="#00f001" // Chúng tôi thiết kế vùng chọn với thẻ dòng (nội tuyến) mong muốn với hàm lớp mong muốn format_inline(iframe_id, tag_name, class_name)( var iframe = document.getElementById(iframe_id ) var wysiwyg = iframe .contentWindow.document // Xóa mọi thứ định dạng hiện có wysiwyg.execCommand("RemoveFormat", false, true) // Trong MSIE, sau RemoveFormat còn lại các span, hãy xóa chúng luôn clean_nodes(get_selected_tags(iframe.contentWindow, "span")) // Nếu tên thẻ không được chỉ định (được sử dụng khi chúng ta chỉ muốn xóa định dạng) if(tag_name!="")( // Chèn wysiwyg.execCommand("ForeColor", false, magic_unusual_color) // Thay thế các nút được tạo bởi phông chữ bằng các nút mới đúng tên và lớp var node=get_selected_tags(iframe.contentWindow, "font") var new_node for(var i=0;i = 0 ; i--)( if(!classname || nút[i].className == class_name)( nút[i].removeNode(false) ) ) )

Dành cho chính bạn: clean_nodes trên nhiều trình duyệt

LỖI:
1: MSIE: các không gian ranh giới biến mất (những không gian trong vùng chọn và những không gian bên ngoài trong đó. Rõ ràng là do sự phân công lại của InnerHTML)
2: đôi khi trong MSIE, khi áp dụng định dạng nội tuyến cho nhiều đoạn văn cùng một lúc, một phần văn bản vẫn có màu xanh (magic_unusual_color). Nhân tiện, trong Mozilla, đôi khi cũng vậy, nhưng trong những trường hợp khác... Có lẽ tôi nên chọn tất cả các phông chữ từ toàn bộ tài liệu chứ không chỉ từ vùng chọn? // Kruglov
Làm việc với danh sách
Điều này đề cập đến việc làm việc với đánh số và danh sách có dấu đầu dòng. Thật may mắn cho chúng ta, API đã có hầu hết mọi thứ (và thậm chí nhiều hơn mức cần thiết, nhưng chúng ta đừng vượt quá khả năng của mình).

Chúng tôi muốn chuyển đổi các đoạn văn thành cả hai loại danh sách và ngược lại, cũng như kiểm soát việc lồng các danh sách (thay đổi thụt lề).

Dưới đây là danh sách các lệnh có sẵn trong API DesignMode:

InsertOrderedList - chèn

    InsertUnorderedList - chèn
      Thụt lề - tăng thụt lề (tạo danh sách phụ) Thụt lề - giảm thụt lề (thoát danh sách phụ)

      Ở dạng vùng văn bản, bạn cần tạo một trình soạn thảo văn bản với các thẻ định dạng đơn giản nhất (in đậm, in nghiêng). nhưng bản thân các thẻ, như được thực hiện trong hầu hết các trình soạn thảo tương tự, không được vừa với vùng văn bản và văn bản đã chọn sau khi định dạng sẽ trở thành in đậm, in nghiêng hoặc in đậm và in nghiêng cùng lúc trực tiếp trong vùng văn bản.
      và vấn đề thứ hai không thể giải quyết được. Văn bản được nhập từ bàn phím hoặc dán từ bảng ghi tạm phải được giới hạn ở 11 dòng, mỗi dòng chứa không quá 40 ký tự. chuyển tới hàng tiếp theo, tất nhiên, phải tự động.

      cảm ơn bạn trước!!!

      Tôi đã xem xét một số biên tập viên wysiwyg, nhưng đây là những chương trình lớn có rất nhiều tính năng thú vị. và tôi chỉ cần định dạng văn bản bằng các thẻ in đậm, in nghiêng và gạch chân. Chà, cũng có thể dán văn bản từ bộ đệm và sao chép nó vào bộ đệm, nhưng điều này không cần thiết. Tôi tự cắt nó chức năng cần thiết Tôi không thể từ các biên tập viên wysiwyg. Tất nhiên, bạn có thể sử dụng toàn bộ js được tìm thấy mà không cần cắt bỏ các chức năng cần thiết, nhưng các tệp sẽ nặng rất nhiều.
      và làm cách nào để giới hạn số lượng ký tự trong vùng văn bản? không hoạt động thông qua maxlength. Người dùng nên xem mình vẫn có thể gõ được bao nhiêu ký tự, tức là. một bộ đếm là cần thiết.

      Chà, mọi người đổ xô đi giành quyền kiểm soát người dùng trực tuyến... :)
      Tôi muốn nói với bạn, samovar thân mến, rằng tôi đã kết thúc cái trình soạn thảo wysiwyg ngu ngốc này, với chức năng cơ bản, Mình đã làm việc được tháng thứ hai rồi, nếu làm việc này hết tóc mà không rụng hết thì may quá... :)
      Và hiện tại chỉ có một trình soạn thảo văn bản trên mạng - TinyMCE. Nhưng than ôi, chiếc xe tải không được bao gồm trong đó...

      Dmitry, hiện tại tôi đang tìm hiểu về TinyMCE này. nhưng cắt tính năng tối thiểu, điều tôi cần, tôi không thể.

      được rồi, vậy hãy thu hẹp vấn đề hiện tại. Tôi cần nhập hoặc dán văn bản từ bộ đệm vào vùng văn bản, văn bản này sẽ bị giới hạn ở 10 (hoặc 11, tôi vẫn chưa quyết định chính xác sẽ có bao nhiêu dòng). làm thế nào để đảm bảo rằng sau khi gõ dòng cuối cùng văn bản không được gõ hoặc bị cắt nếu đầu vào đến từ bảng ghi tạm? và cần có một bộ đếm để cho người dùng biết anh ta vẫn còn bao nhiêu dòng. những thứ kia. sau khi chuyển sang dòng tiếp theo, bộ đếm hiển thị n=n-1, trong đó n là tổng số dòng. nguồn cấp dữ liệu xảy ra khi quấn="hard".

      cảm ơn bạn trước!!!

      Các tính năng hữu ích(Bộ lọc đầu vào cho trương Văn bản) . Bạn có thể tự mình đếm số lượng ký tự có giá trị.
      Nói chung là cưng ấm đun nước [Hồ sơ] , tuyên bố vấn đề thật kỳ lạ - Tôi không thể tự mình làm được, nhưng bạn có thể làm được. Hoặc học hoặc cung cấp nó cho những người muốn giải quyết nó để kiếm tiền. Lòng vị tha có giới hạn.

      Evgeniy Petrov thân mến! Tôi có thể đếm số ký tự, nhưng tôi cần đếm số dòng, không quá 10. Mỗi dòng chứa một số ký tự khác nhau, bởi vì Việc chuyển sang dòng tiếp theo không xảy ra khi đạt đến một giới hạn nhất định về số lượng ký tự mà xảy ra trước một từ không vừa với dòng.
      Tôi hoàn toàn đồng ý với nhận xét của bạn, mọi thứ đều có giới hạn. Đó là lý do tại sao tôi không tỏ ra ngạo mạn trong trường hợp của biên tập viên wysiwyg mà tự mình tìm hiểu kỹ về nó. nhưng tôi hoàn toàn không biết cách đếm số dòng trong một vùng văn bản. Tôi không yêu cầu bạn làm mọi thứ một cách trọn vẹn, nhưng ít nhất hãy thúc đẩy một giải pháp nhất định.

      Về nguyên tắc, Samovar có một giải pháp với div ẩn (tức là khả năng hiển thị = "ẩn"), có chiều rộng cố định.
      Khi người dùng nhập văn bản vào vùng văn bản, mỗi khi văn bản thay đổi, bạn xuất tất cả văn bản vào div rất ẩn này. Vì chiều rộng của nó là cố định nên nó sẽ kéo dài về chiều cao. Hơn nữa, biết chiều cao chuỗi tiêu chuẩn(À, giả sử phông chữ 10pt có chiều cao 16px) và chiều cao của div kéo dài (clientHeight), bạn có thể đếm số dòng được nhập. Nếu có nhiều dòng hơn mức cần thiết, hãy hiển thị cảnh báo kèm theo thông báo lỗi.
      Bằng cách này.

      ấm đun nước [Hồ sơ] "chuỗi" là một khái niệm linh hoạt theo nghĩa đen và nghĩa bóng của từ này. Tại sao chính xác là 11 dòng? Đây có phải là hạn chế về logic công nghệ hoặc kinh doanh không? Nếu là công nghệ thì nó luôn có thể được thể hiện bằng số lượng ký tự. Nếu đó là logic nghiệp vụ, thì một lần nữa, việc thay đổi logic nghiệp vụ sẽ dễ dàng hơn không phải là đấu tranh với người dùng và trình duyệt mà là thay đổi logic nghiệp vụ - mọi người sẽ chỉ được hưởng lợi từ việc này.

      Cảm ơn tất cả các bạn rất nhiều vì câu trả lời của bạn!
      Evgeny Petrov, uh... cảm ơn, tôi sẽ suy nghĩ về điều đó, nhưng tôi vẫn chưa nghĩ ra)))
      Dmitry, tôi cũng có ý tưởng này, nhưng thực tế của vấn đề là kích thước phông chữ và bản thân phông chữ có thể thay đổi.
      GRay, tôi không biết nhiệm vụ đó được xác định như thế nào, bức tranh chung về khái niệm soạn thảo văn bản Tôi không có. được yêu cầu giới hạn số dòng. và theo số ký tự đã nhập thì không thể cố định được số dòng, vì Mỗi dòng sẽ có số lượng ký tự khác nhau. do đó, số dòng có cùng số ký tự có thể là +-2.

      Tôi tìm thấy đoạn mã sau cho Explorer, tác giả nói rằng bạn có thể đếm số dòng, nhưng tôi không hiểu cách kết nối đoạn mã này với biểu mẫu vùng văn bản:

      hàm textareaCurLineNum(obj)
      {
      var rowHeight = obj.clientHeight/obj.rows;
      var curHeight = obj.createTextRange().boundingHeight;

      trả về phân tích cú phápInt(curHeight/rowHeight)+(obj.value!=""?1:0);
      }

      ấm đun nước [Hồ sơ] Tôi chỉ nói rằng chúng ta cần hiểu lý do tại sao hạn chế này được đưa ra. Việc thực hiện nó

      1. không tầm thường và do đó sẽ mất rất nhiều thời gian và không biết liệu có đạt được kết quả hay không
      2. thực tế Thật khó để tưởng tượng những tình huống mà hạn chế này có thể hữu ích, điều đó có nghĩa là những nỗ lực đã bỏ ra khó có thể được đền đáp.

      GRay, tôi đã tìm ra lý do tại sao nhiệm vụ nên được đặt ra theo hình thức này. Một tờ báo nhỏ được tổng hợp từ nhiều bài viết khác nhau, sau đó được dịch sang pdf. bài viết có thể là 1/4, 2/4, 3/4 hoặc toàn trang. Người sắp chữ tự chọn hình thức mong muốn với số dòng cố định. Tôi không đi sâu vào chi tiết, nhưng tôi nghĩ rằng có rất nhiều hình dạng phù hợp trên trang với số lượng khác nhau dòng. nếu bài viết không phù hợp với hình thức thì một bài viết khác sẽ được lấy, với một lượng lớn dòng... theo tôi hiểu thì đây là công việc của người đánh máy đang được tự động hóa. mặc dù tôi có thể sai, nhưng như tôi đã nói, tôi không đi sâu vào chi tiết, bạn bè tôi chỉ nhờ tôi giúp đỡ.
      Điều chính là giới thiệu các hạn chế về hàng và đặt bộ đếm hàng.

      À, chính bạn đã nói rằng không được quá 11 dòng và không quá 40 ký tự trên mỗi dòng. Như vậy, số ký tự tối đa sẽ là 440. Việc đếm các ký tự trong một dòng không phải là vấn đề, thuật toán trở nên phức tạp hơn chỉ do các ngắt dòng gặp phải phải được tính là các ký tự “dài” có độ dài bằng chênh lệch giữa 40 và phần còn lại của việc chia số ký tự được điền cho các ký tự tối đa sự chuyển giao này dòng (không tính đến dấu gạch nối) bằng 40. Việc bắt các phần chèn từ bộ đệm là một chủ đề riêng biệt. Đối với IE thì có onb Beforepaste, nhưng đối với mozilla, điều tương tự chỉ được mong đợi trong FF 3. Nếu tôi là bạn, tôi sẽ thực hiện xác thực sau dữ liệu đã nhập với thông báo tiếp theo của người dùng và không tính toán theo thời gian thực.

      Ngoài ra còn có Nhiều loại khác nhau phông chữ (chẳng hạn như monospace)... Đối với chúng, số lượng ký tự sẽ khác nhau khi điền cùng một cách. IMHO việc mô phỏng dải này một cách trực quan sẽ dễ dàng hơn thay vì tham gia vào các phép tính không tương ứng với thực tế.

      Evgeniy Petrov [Hồ sơ] Nói một cách dễ hiểu, nếu chúng ta đang nói về một số loại "trợ giúp cho người sắp chữ", chúng ta cần phải tính đến mọi thứ;) cả kích thước và chiều rộng của mỗi ký tự trong phông chữ đã chọn và khoảng cách dòng vân vân. Tuy nhiên, tác giả đã quy định ngay từ đầu rằng các dòng có độ dài cố định về số lượng ký tự và trong trường hợp này có thể bỏ qua kích thước và loại phông chữ.

      ấm đun nước [Hồ sơ] , những dòng này đã được trao cho bạn. Tại sao lại đếm chúng nếu Chúng ta đang nói về về việc vật liệu sẽ vừa hay không vừa với một hình chữ nhật có kích thước nhất định. Evgeniy Petrov [Hồ sơ] Bạn hoàn toàn đúng, điều đó phụ thuộc vào phông chữ bạn nhập tài liệu.
      Dmitry [Hồ sơ] cho bạn lời khuyên khôn ngoan, sao chép tất cả văn bản vào div, xem kích thước của nó và rút ra kết luận.

      balou, những dòng này là cần thiết để hiển thị rõ ràng hơn cho người sắp chữ xem anh ta còn bao nhiêu khoảng trống. số lượng ký tự sẽ luôn khác nhau nhưng số dòng sẽ cố định. Bộ đếm hiển thị số dòng còn lại để gõ. Người dùng không quan tâm nhiệm vụ được thực hiện như thế nào; họ cần sự rõ ràng và thuận tiện.

      ấm đun nước [Hồ sơ] Bạn vẫn cần làm cho khách hàng biết rằng độ dài của dòng tính bằng ký tự không giống với độ dài của dòng tính bằng centimét. Hãy để họ cung cấp cho bạn những hướng dẫn rõ ràng về cách họ sẽ xử lý tình huống với các phông chữ, cỡ chữ khác nhau, v.v. Nếu bạn bỏ qua các tham số phông chữ, biết độ dài dòng, vấn đề của bạn có thể được giải quyết như tôi mô tả, nếu không thì không.

      ấm đun nước [Hồ sơ] Vậy thì chúc may mắn ;) HTML không dành cho bố cục với độ chính xác đến từng milimet. Có thể thực hiện những gì họ muốn trên cơ sở trình duyệt, nhưng thật là tệ hại đến nỗi tốt hơn hết là bạn không nên bắt đầu - bạn sẽ không làm hài lòng mọi người và sẽ làm hoen ố danh tiếng của mình.

      Được rồi, HTML không được dùng nhưng PDF thì có. Bạn có thể thực hiện hiển thị trước nền/theo yêu cầu HTML sang PDF, chẳng hạn như với sử dụng AJAX và thậm chí tự động điều chỉnh HTML dựa trên kết quả của nó. Đối với các ký tự 10x40 sẽ không bị chậm lại. Thư viện PDF Theo quy định, chúng hỗ trợ các chức năng tính toán độ dài của một dòng trong một phông chữ nhất định và các tính năng liên quan khác. Tất nhiên là có phần nghịch lý nhưng nó phù hợp với nhiệm vụ.

      ngày mười ba tháng năm [Hồ sơ] Bạn sẽ muốn triển khai nó;) Hơn nữa, bạn đếm các dòng như thế nào? Gửi tất cả văn bản đến máy chủ thông qua từng ký tự đã nhập, hiển thị nó thành PDF (hoặc không hiển thị mà đếm theo cách khác), bằng cách nào đó hiểu được nội dung được hiển thị đã mất bao nhiêu dòng và gửi lại kết quả. Ừm. Có phải là quá nhiều không? :) Và với tình yêu chung của người dùng dành cho wysiwyg, có thể nói là sẽ rất khó để thuyết phục anh ta làm việc với giao diện như vậy;)

      Chà, bạn sẽ không cười mà chỉ cười trong vài ngày... ;) Tùy chọn này, tất nhiên, sẽ hoạt động với việc kiểm tra theo yêu cầu, nhưng nó sẽ rõ ràng. Và nếu bạn cần toàn thời gian thực, thì bạn có thể làm hỏng nó như thế này: chọn kích thước phần tử HTML nhập theo đoạn PDF tương ứng, trên một cụm từ trung bình, tức là khoảng. Nếu phông chữ không thay đổi thì bạn có thể thực hiện khó khăn, nếu có, bạn sẽ phải thực hiện quy trình đồng bộ hóa (cũng như AJAX). Trong mọi trường hợp, tôi nghĩ trên cơ sở dữ liệu thống kê gồm hàng tá câu, bạn có thể đạt được độ chính xác +/- 1,2 ký tự so với giá trị trung bình. Chỉ có một điểm tồi ở đây: nếu người dùng bắt đầu nhầm lẫn với định dạng, chẳng hạn như đặt khoảng cách giữa các từ lớn với dấu cách hoặc vẽ bằng đồ họa giả, tức là. một loạt các ký tự cùng loại và khác biệt đáng kể so với độ dài trung bình của các ký tự trong một hàng thì độ chính xác sẽ không còn nữa. Có, trong trường hợp này sẽ có một jamb, bạn không thể định dạng nó như vậy, vì chúng tôi không làm điều đó trong Word, thậm chí có vấn đề với nó và nhiệm vụ của chúng tôi dường như là nhập một đoạn văn bản đơn giản không bị biến dạng nên tôi nghĩ điểm này có thể bỏ qua. Vì vậy, kết quả là chúng ta nhận được một tập hợp các dòng phù hợp “chính xác” với HTML, về độ dài, sẽ hơi khác một chút khi được hiển thị thành PDF. Dựa trên một số kinh nghiệm, tôi có thể giả định rằng đối với văn bản “bình thường”, có thể đảm bảo độ chính xác của một vài ký tự. Bây giờ điều quan trọng nhất là làm cách nào chúng ta có thể nhập các cổ phiếu này vào bản PDF để chúng không khác nhau ở đó? - Chỉ. Thư viện PDF hỗ trợ thao tác như khớp một dòng vào một khu vực nhất định (do ma trận chuyển đổi, tỷ lệ đọc) và vì Các đường nét ban đầu của chúng tôi khác nhau rất ít; tỷ lệ này gần như không thể nhận thấy bằng mắt. Đối với những người “nghiệp dư” thực sự, chúng tôi có thể đề xuất một phương pháp liên quan đến việc thay đổi khoảng cách giữa các từ/ký tự. Đương nhiên, điều này sẽ yêu cầu sửa đổi trình chuyển đổi HTML->PDF, thay vì chỉ một chức năng tiêu chuẩnĐể xuất văn bản thành PDF, bạn sẽ phải viết một kilobyte mã chia tỷ lệ. Tất cả điều này không đáng sợ như nó có vẻ. Hãy tự suy nghĩ, tất cả những gì bạn cần làm là đồng bộ hóa kích thước của các vùng chứa và áp dụng tỷ lệ khi xuất sang PDF.

      [dossier], chính xác thì bạn xin lỗi vì điều gì?
      Vấn đề không hề tầm thường. Tác giả thẳng thắn viết rằng ông không hiểu những điều phức tạp. Tuy nhiên, nếu bạn có đủ trình độ kiến ​​​​thức, sẵn sàng tìm hiểu và dành 2 ngày đã nêu, chúc bạn thực hiện may mắn.

      bạn bè của tôi đã thay đổi cách trình bày bài toán và đơn giản hóa nó một cách đáng kể. phông chữ bây giờ sẽ không đổi và số dòng có thể được tính tương ứng với chiều cao của dòng.
      đã làm như sau:

      8 là chiều cao dòng gần đúng trong vùng văn bản. nhưng làm cách nào để cắt bớt văn bản nếu nó không được nhập từ bàn phím mà được chèn từ bộ đệm? Tôi đã cố gắng làm điều tương tự với onpaste cũng như với onkeydown, nhưng không được.
      Giải pháp chỉ có thể được thực hiện cho Explorer; máy sắp chữ vẫn chỉ hoạt động với nó.