Angular.js: Mendukung atribut HTML5 contentEditable

Dibuat pada 20 Agu 2011  ·  78Komentar  ·  Sumber: angular/angular.js

Kita harus melakukan pengikatan dua arah bahkan untuk elemen selain input, jika ada atribut contentEditable.

Lots of comments moderate not core broken expected use feature

Komentar yang paling membantu

Halo semuanya,
mengikat ke contenteditable bukanlah sesuatu yang akan kami dukung pada intinya:

  • menangani konten yang dapat diedit dengan cara yang kuat dan komprehensif sangat kompleks
  • Dukungan resmi akan mengambil banyak sumber daya dari tim (kecil) yang menangani AngularJs 1.x saat ini.
  • Namun, bahkan dengan tim yang lebih besar, contenteditable akan menjadi proyek besar yang membutuhkan perhatian terus-menerus
  • Kita harus menggandakan / memasukkan banyak kode yang telah ditulis oleh orang lain yang menangani berbagai perbedaan dan kebiasaan browser.
  • "binding to contenteditable" bukanlah konsep yang digambarkan dengan jelas. Dukungan untuk pengikatan "sederhana" akan bertambah besar karena perbedaan browser perlu ditangani, dan mungkin meningkatkan permintaan untuk editor teks kaya / WYSIWYG lengkap

Untungnya, sudah ada proyek yang menangani editor teks yang dapat diedit dan kaya, beberapa yang dibungkus untuk diintegrasikan dengan Angular, dan beberapa yang khusus ditulis untuk itu. Saya tidak punya waktu untuk menguji semua proyek, saya hanya ingin menyoroti direktif textAngulars taBind, yang menangani pengikatan dua arah "sederhana" yang dapat diedit dengan ngModel. Sejauh yang saya bisa katakan, ruang lingkup masalah ini: tidak ada editor mewah, tetapi hanya cara untuk memiliki konten yang dapat diedit yang kuat yang menangani berbagai teknik input dan perbedaan browser. Saya telah membuat plunker yang menampilkan konten sederhana yang dapat diedit yang telah ditingkatkan dengan taBind: http://plnkr.co/edit/kKPfk0LCXWrMpZ1gkblb?p=preview (textAngular juga menyediakan editor lengkap jika Anda memerlukannya).

Semua 78 komentar

sepotong kode basi dari diskusi milis sebelumnya

<!doctype html>
<html xmlns:ng="http://angularjs.org" xmlns:ngx="http://angularjs.org/extras" ng:controller="MyCtrl">
 <script ng:autobind src="http://code.angularjs.org/angular-0.9.10.js"></script>
  <script>
   function MyCtrl() {
     this.reset = function(){
       this.text = "Hello <b>World</b>!";
     };
     this.reset();
   }

   angular.widget("<strong i="6">@ngx</strong>:contenteditable", function(expression, template){
     template.attr('contenteditable', 'true');
     return angular.extend(function($updateView, instance) {
       var scope = this,
           lastHtml = instance.html();
       instance.bind('blur keyup paste', function(){
         scope.$set(expression, lastHtml = instance.html());
         $updateView();
       });

       this.$watch(expression, function(value){
         if (value != lastHtml)
           instance.html(value);
       });

     }, {$inject:['$updateView']});
   })
  </script>

 <body ng:controller="MyCtrl">
  <h1>Editor</h1>
  <hr/>
  <div ngx:contenteditable="text" style="border: 1px solid black;"></div>
  [ <a href="" ng:click="reset()">reset</a> ]
  <hr/>
  <textarea rows="10" cols="80" name="text"></textarea>
 </body>
</html>

Hai semuanya, jadi saya tidak bisa mendapatkan contoh yang diberikan untuk bekerja dengan 0.9.10, apalagi dengan 1.0.0r6.

Bimbingan lebih lanjut akan sangat dihargai! (Karena saya lebih suka menggunakan contenteditable daripada arahan yang diganti denganuntuk suntingan sebaris) :D

Kode di atas sudah usang. Bisakah Anda memperbaruinya?

Ya, alangkah baiknya jika kita bisa menggunakan contenteditables dengan AngularJS.

Saya setuju, perlu pengikatan data 2 arah agar konten dapat diedit

Saya memang menemukan jalan keluarnya dengan menerapkan arahan saya sendiri (perhatikan JS ada di CoffeeScript):

angular.module('NameOfYourApp').directive('contenteditable', ->
  return {
    restrict: 'A', 
    require: '?ngModel',
    link: (scope, element, attr, ngModel) ->
      return if not ngModel

      ngModel.$render = ->
        element.html(ngModel.$viewValue)

      element.bind 'blur', ->
        if ngModel.$viewValue isnt $.trim(element.html())
          scope.$apply(read)

      read = ->
        console.log("read()")
        ngModel.$setViewValue($.trim(element.html()))
  }
)

Sunting:

Dan jika Anda tidak menggunakan CoffeeScript, inilah versi JS:

angular.module('NameOfYourApp').directive('contenteditable', function() {
    return {
      restrict: 'A',
      require: '?ngModel',
      link: function(scope, element, attr, ngModel) {
        var read;
        if (!ngModel) {
          return;
        }
        ngModel.$render = function() {
          return element.html(ngModel.$viewValue);
        };
        element.bind('blur', function() {
          if (ngModel.$viewValue !== $.trim(element.html())) {
            return scope.$apply(read);
          }
        });
        return read = function() {
          console.log("read()");
          return ngModel.$setViewValue($.trim(element.html()));
        };
      }
    };
  });

Apakah Anda mengetahui demo contentEditable ini? http://docs.angularjs.org/api/ng.directive :ngModel.NgModelController

@mhevery Apakah ada alasan untuk tidak menyertakan arahan ini di Angular?

Saya sadar, meskipun saya seharusnya menunjukkan bahwa milik saya sedikit berbeda dan bergantung pada fungsi trim jQuery.

@wizek Anda harus menarik garis di suatu tempat.

Pada Selasa, 7 Agustus 2012 pukul 23.50, Hengjie [email protected] menulis:

Saya sadar, meskipun saya seharusnya menunjukkan bahwa milik saya sedikit
berbeda dan bergantung pada fungsi trim jQuery.


Balas email ini secara langsung atau lihat di Gi tHubhttps://github.com/angular/angular.js/issues/528#issuecomment -7576294.

@mhevery Saya tidak akan membantahnya sebentar.

Padahal, bolehkah saya bertanya logika apa yang Anda ikuti ketika memutuskan di mana Anda menggambar garis itu?

@mhevery Jika Angular menyertakan 'input, textfield, dll' berdasarkan bidang input dalam spesifikasi HTML4, maka dengan dasar itu, kita harus menyertakan 'contenteditable' karena itu adalah bagian dari input spesifikasi HTML5.

Saya kira kita hanya menebak. Kami tidak memiliki aturan resmi. Anda bebas untuk membuat kasus Anda, atau lebih baik lagi, kirimkan permintaan tarik kepada kami. Demonya menurut saya agak sepele karena menurut saya konten yang bisa diedit lebih rumit, tapi mungkin hanya itu yang perlu dilakukan.

Baru saja menggali ini, dan lumpur yang saya ekstrak sebenarnya cukup kotor...

Jika Anda mencoba contoh yang disebutkan sebelumnya, Anda akan melihat bahwa dengan Chrome, setiap spasi tambahan akan menghasilkan "&nbsp;" final ditampilkan di akhir textarea terikat. Hal yang sama berlaku jika Anda memasukkan dua spasi berikutnya. Perilakunya sangat berbeda di Firefox, tetapi masalah yang sama memang muncul.

Ini menguraikan sesuatu yang penting: dalam hal-hal yang dapat diedit itu, Anda sebenarnya dapat memasukkan kode HTML apa pun. Coba salin/tempel beberapa komponen halaman web ke dalam contoh itu, dan dapatkan untung.

Menjadi adalah situasi ini adalah kekacauan konseptual, setidaknya jika seperti saya, Anda hanya bersedia menggunakan ini sebagai kotak input yang mewah. Jadi saya memutuskan untuk menyederhanakan banyak hal, dan hanya menyimpan informasi teks biasa. Tetapi jika Anda ingin pengikatan yang sebenarnya tidak mengejutkan pengguna, Anda harus menghapus pemformatan dari $viewValue dan elemen contenteditable itu sendiri.

Dan di sini kita berada di dalam kekhususan browser yang sangat luas. Menangani pengetikan biasa hampir baik-baik saja, namun ketika harus menyalin/menempel, tidak ada solusi sederhana ... Maksud saya, baik Chrome maupun Firefox tidak memiliki acara "tempel", tetapi tempel teks dengan pemformatan, sedangkan sesuatu seperti KHTML hanya akan menolak untuk menempelkan apapun...

Saya memulai sesuatu di sini , yang (hampir) stabil untuk Chrome, berfungsi untuk Firefox dan belum teruji untuk peramban yang tidak berguna dan umumnya tidak kompatibel (tetapi itu memang menciptakan atribut yang dapat diedit \o/).

Namun, saya sebenarnya tidak menganjurkan penggunaan contenteditable. Memang, jika Anda mencoba menyalin/menempel beberapa DOM termasuk a

Hanya untuk memberi tahu Anda bahwa sebenarnya ada dua tempat adalah dokumen (dan setidaknya satu di milis) yang menjelaskan (secara tangensial sebagai contoh) bagaimana menerapkan arahan yang dapat diedit.

Satu di sini:
http://docs.angularjs.org/guide/concepts (Di bagian Arahan)

Satu di sini:
http://docs.angularjs.org/api/ng.directive :ngModel.NgModelController

Mempertimbangkan bagaimana ini sudah ada di dokumen, dan telah dibahas di milis, dan ada tiket berusia satu tahun yang masih mendapat komentar, yang ini (setidaknya bagi saya) tampaknya jelas untuk dimasukkan dalam inti. Jika Anda membutuhkan lebih banyak orang untuk :+1: ini, inilah suara saya.

+1

+1

Silakan kirim permintaan tarik dengan implementasi, pengujian, dan pembaruan dokumen.

@IgorMinar : bagaimana dengan penempelan HTML? Saya tidak yakin itu dapat sepenuhnya dicegah, yang mengarah ke penempelan kode HTML arbitrer yang tidak disengaja atau berbahaya, termasuk

+1

+1

+1

Implementasi Hengjie bekerja lebih baik daripada dua contoh di dokumen. Ia bekerja pada elemen arbitrer, misalnya td.
Adapun dua contoh, menggunakan contenteditable dan ng-model pada td, td tidak menampilkan konten.

+1

+1

+1

sudahkah Anda melihat https://github.com/akatov/angular-contenteditable ? mari berkontribusi untuk itu, dan masukkan ke AngularUI..

+1

+1

2 tahun...

+1

:+1: x :100:

+1

+1, 2 tahun yang lalu.

+1

Begitulah cara saya menangani penempelan saat menghapus pemformatan:

document.getElementById("titlesection").addEventListener('paste', function(e){ 
  scope.$apply(function(){
    e.preventDefault();
    var text = e.clipboardData.getData("text/plain");
    document.execCommand("insertHTML", false, text.fulltrim());
  });
});

reedit: mengevaluasi konten teks dari div yang dapat diedit pada keydown/keyup/keypress mungkin harus berfungsi meskipun perilakunya berbeda di beberapa browser. Dan mengubah konten elemen yang dapat diedit saat difokuskan dapat menimbulkan beberapa masalah dalam menangani posisi tanda sisipan saat disetel ulang setiap kali. Misalnya jika menerapkan koreksi otomatis, itu bisa bermasalah.

Atau, saya mengelola beberapa pengikatan 2 arah dengan pengamat mutasi tetapi itu hanya digunakan di browser terbaru. Dan masalah jika saya ingin mengubah teks tetap (yaitu posisi caret direset ke posisi paling kiri). Saya telah mencoba untuk bermain dengan rentang/pilihan API tetapi itu benar-benar terlalu rumit untuk berurusan dengan cara penanganan node teks yang berbeda.

Menarik, memang benar bahwa API clipboard semakin terstandarisasi, tetapi dapatkah dianggap didukung cukup luas mengingat implikasi keamanan yang dimilikinya?

+1

Satu argumen untuk dimasukkan ke dalam basis sudut: Tampaknya bagi saya bahwa input sudut = arahan teks sudah memecahkan banyak masalah yang akan dihadapi oleh setiap arahan yang dapat diedit mengenai input pengguna. Terutama penggunaan layanan pribadi $sniffer / $browser untuk mendukung browser tanpa oninput harus diduplikasi oleh komponen pihak ke-3 ($timeout dapat digunakan untuk $browser, tetapi memiliki overhead).

e: sepertinya Anda bisa menyuntikkan $browser dan $sniffer. Jadi pribadi berarti 'gunakan dengan risiko Anda sendiri'?

Satu argumen menentangnya: contenteditable sangat tidak konsisten di antara browser. Lihat misalnya http://a-software-guy.com/2013/01/a-summary-of-markup-changes-in-contenteditable-divs-in-webkitfirefox-and-msie/ Jika termasuk ke dalam sudut, ada akan menjadi banyak masalah yang hanya menangani ketidakkonsistenan dan permintaan fitur ini (editor teks kaya, dll.). Saya lebih suka para pengembang inti fokus pada hal-hal yang lebih penting.

Meskipun sulit untuk membuatnya konsisten, saya tidak melihatnya sebagai masalah yang sulit untuk dipecahkan, terutama mengingat bahwa masalah tersebut telah diselesaikan oleh orang-orang seperti Aloha-Editor

Dimana?

Peretasan lama tidak berfungsi dengan sudut 1.2.3.

Saya telah menggunakan versi saya https://github.com/angular/angular.js/issues/528#issuecomment -7573166 pada 1.2.x dan tidak masalah. Beri tahu saya apa yang tidak berhasil dan saya dapat memperbarui skrip itu.

Tentu saja Angular seharusnya tidak menampilkan editor teks kayanya sendiri. Namun, akan lebih baik jika contenteditable bermain bagus dengan ngModel .

Saya mendapati diri saya menyalin banyak kode dari ngInput directive , terutama kode untuk mendukung ngMaxlength . Bisakah direktif ngInput diperluas untuk menyertakan dukungan untuk contenteditable ?

Ping @Hengjie

Ya, menggunakan arahan ngInput adalah awal yang baik. Akan ada masalah lain yang kami khawatirkan:

  • Terkadang div yang tampak kosong sebenarnya memiliki p atau span atau br di sana. Saya pikir saya memiliki beberapa kode di suatu tempat (baik backend Ruby dan JS) yang akan membersihkan elemen kosong. Ini agar kami dapat membandingkan satu string dengan string lainnya dan memastikan bahwa kami menyimpannya hanya jika ada perubahan konten yang sebenarnya.

Salah satu cara yang saya periksa adalah dengan memanggil isEmpty() dengan HTML sebagai argumen:

KopiScript:

isEmpty = (el) -> el = $('<div>').html(el) if typeof el is 'string' return $.trim($(el).text()) is ''

Javascript:

var isEmpty;
isEmpty = function(el) {
  if (typeof el === 'string') {
    el = $('<div>').html(el);
  }
  return $.trim($(el).text()) === '';
};

Di atas bergantung pada jQuery. Kodenya mirip dengan cara Aloha melakukannya

  • Masalah keamanan dengan konten yang mengikat. Saya menggunakan Sanitize Gem untuk menyiasati orang yang menyuntikkan JS ke dalam yang dapat diedit. Ada ng.sanitize sehingga itu juga bisa berfungsi (untuk aplikasi JS murni)
  • Mengklik contenteditable akan mengaktifkan acara focus tetapi jika ada tautan di dalamnya maka Anda ingin mendengarkan acara click dan menghentikan propagasinya.
  • Berurusan dengan enter untuk menyimpan (jika Anda ingin itu bertindak seperti bidang input ).
  • Placeholder

@Hengjie Saya percaya bahwa banyak hal yang Anda sebutkan mungkin _not_ menjadi bagian dari inti Angular. Mereka adalah lapisan di atas. Angular harus fokus untuk membuat arahannya berfungsi dengan spesifikasi, bukan menambal inkonsistensi browser.

Menurut pendapat saya, perpanjangan ngInput untuk memasukkan contenteditable hanya akan membutuhkan paritas fitur dengan input teks lainnya — dukungan untuk ngModel dan ngMaxlength , misalnya .

Catatan tambahan: Jika itu menarik bagi Anda, saya sedang ~3 minggu dalam perjalanan untuk menulis editor teks kaya saya sendiri (karena TinyMCE dkk tidak memberikan kekuatan yang cukup untuk saya, dan arsitekturnya berumur bertahun-tahun). Saat ini saya sedang memikirkan bagaimana ini akan terintegrasi dengan Angular — semua yang tampaknya hilang adalah dukungan mendasar untuk contenteditable . (Ini ditulis untuk spesifikasi sehingga tidak berfungsi di IE (mereka belum menerapkan API Seleksi); yang mengatakan itu terlihat untuk menambal inkonsistensi browser antara Chrome/Firefox/Safari. Belum ada dokumen juga.)

+1

+1 - tidak memerlukan editor lengkap, tetapi penjilidan 2 arah yang bagus untuk teks akan menyenangkan... 3 tahun pada edisi terbuka.

+1 Ini akan menjadi tambahan yang bagus

+1

Adakah yang melihat ketidakkonsistenan posisi tanda sisipan/simpul teks antara browser yang berbeda?

edit: melihat respons OliverJAsh di atas (https://github.com/guardian/scribe), yang lebih mendalam daripada yang saya lakukan sendiri .. Anda mengerti mengapa masalah ini masih belum terselesaikan setelah 3 tahun. Akan sangat bagus jika ada perbaikan cepat tetapi saya juga mengerti bahwa itu bukan prioritas untuk tim inti.

Scribe sedang diproduksi di Guardian dan sudah cukup lama, jadi sudah teruji dengan sangat baik. Bulan depan sudah ada dokumentasinya jadi mudah-mudahan bisa mulai digunakan. Saya masih percaya contenteditable memiliki tempat di Angular, dengan pengikatan model dan atribut input teks (misalnya ngMaxlength).

Mendorong beberapa dokumen: https://github.com/guardian/scribe

Kami menggunakannya di Angular. Jika Anda tertarik bagaimana saya akan menggali kode, cukup lakukan penjilidan model secara manual.

+1

@OliverJAsh Saya ingin melihat detail lebih lanjut tentang bagaimana Anda menggunakan ini dengan Angular

Saya telah memasang contoh penggunaan Scribe dengan Angular. Contohnya komprehensif dan mencakup banyak plugin.

https://github.com/guardian/scribe-angular-example

Anda dapat melihat contoh di http://guardian.github.io/scribe-angular-example/.

Saya tidak senang dengan implementasinya, tetapi berhasil. Saya ingin bekerja dengan semua orang di sini untuk meningkatkan desain dan melakukan semua ini dengan cara Angular yang disukai.

Mendapatkan 404 di https://github.com/guardian/scribe-angular-example

Mungkin repo itu pribadi?

@commandtab Coba lagi :-)

Ini terlihat sangat bagus! Saya akan mulai menggedornya segera. Terima kasih!

Terlihat cukup lengkap fiturnya. Oliver. Demonya luar biasa.

Bagi mereka yang hanya membutuhkan sesuatu yang lebih dekat dengan elemen ng-input, saya telah mencoba memasak sesuatu:
Contoh saya memiliki jquery sebagai ketergantungan untuk acara kunci/fokus tetapi harus cukup mudah dilakukan tanpanya (misalnya dengan mengatur jam tangan sudut pada properti fokus elemen dom). Saya juga telah mengabaikan pemangkasan nbsp dan trailing break dll. ini masalah menemukan ekspresi reguler yang benar dan kapan menerapkannya, saya pikir.
bekerja di chrome rupanya .. belum mengujinya di tempat lain.

Ini bekerja dengan ngModel (sebenarnya didokumentasikan dalam dokumen terbaru).

http://jsfiddle.net/zCbjG/81/

Anda dapat melihat apa yang telah kami lakukan di textAngular (Pengungkapan penuh - Saya mengelola repo untuk pemiliknya).
Tidak hanya itu editor teks kaya tetapi kami memiliki arahan yang disebut taBind (Kode Khusus Di Sini ) yang kami gunakan untuk mengikat konten yang dapat diedit. Ada banyak perbaikan khusus browser dan saya menggunakannya sebagai pengganti ng-bind-html di beberapa tempat.

Secara pribadi saya tidak berpikir contenteditable adalah sesuatu yang harus didukung oleh perpustakaan sudut inti saat ini karena dukungannya yang buruk di browser. Ini menjadi lebih baik secara perlahan tetapi benar-benar cerdik saat ini, terutama ketika menyangkut daftar dan setiap browser menambahkan tag acak pada waktu yang berbeda. Misalnya chrome dalam kasus tertentu suka menambahkan beberapa gaya berikut dengan rentang teks saat membatalkan penerapan pemformatan: <span style="line-height: 1.428571429; color: inherit; line-height: 1.1;"> .

Untuk editor yang sangat sederhana, contoh ngModelController di atas sudah cukup, Anda dapat ctrl-B untuk huruf tebal, ctrl-I untuk huruf miring, dll. Apa pun yang lebih rumit dari itu mengharuskan Anda menggunakan perpustakaan seperti Rangy atau mulai bermain dengan execCommand seperti yang telah kita lakukan di textAngular.

Di sisi lain, jika Anda membuat sesuatu seperti ini sebagai bagian inti dari Angular, saya akan dengan senang hati membantu PR dll karena saya mungkin dapat membuat textAngular lebih ringan!!

Saya suka modul scribe dan demo sudutnya --- mungkin ada baiknya mendukung itu daripada mencoba mendukungnya secara asli.

+1

+1

:+1:

+1

+1

+1

+1

+1

+1

+1

:heavy_plus_sign: 1

+1

+1

:+1: untuk solusi dari @atd86 http://jsfiddle.net/zCbjG/81/

👍

+1

Halo semuanya,
mengikat ke contenteditable bukanlah sesuatu yang akan kami dukung pada intinya:

  • menangani konten yang dapat diedit dengan cara yang kuat dan komprehensif sangat kompleks
  • Dukungan resmi akan mengambil banyak sumber daya dari tim (kecil) yang menangani AngularJs 1.x saat ini.
  • Namun, bahkan dengan tim yang lebih besar, contenteditable akan menjadi proyek besar yang membutuhkan perhatian terus-menerus
  • Kita harus menggandakan / memasukkan banyak kode yang telah ditulis oleh orang lain yang menangani berbagai perbedaan dan kebiasaan browser.
  • "binding to contenteditable" bukanlah konsep yang digambarkan dengan jelas. Dukungan untuk pengikatan "sederhana" akan bertambah besar karena perbedaan browser perlu ditangani, dan mungkin meningkatkan permintaan untuk editor teks kaya / WYSIWYG lengkap

Untungnya, sudah ada proyek yang menangani editor teks yang dapat diedit dan kaya, beberapa yang dibungkus untuk diintegrasikan dengan Angular, dan beberapa yang khusus ditulis untuk itu. Saya tidak punya waktu untuk menguji semua proyek, saya hanya ingin menyoroti direktif textAngulars taBind, yang menangani pengikatan dua arah "sederhana" yang dapat diedit dengan ngModel. Sejauh yang saya bisa katakan, ruang lingkup masalah ini: tidak ada editor mewah, tetapi hanya cara untuk memiliki konten yang dapat diedit yang kuat yang menangani berbagai teknik input dan perbedaan browser. Saya telah membuat plunker yang menampilkan konten sederhana yang dapat diedit yang telah ditingkatkan dengan taBind: http://plnkr.co/edit/kKPfk0LCXWrMpZ1gkblb?p=preview (textAngular juga menyediakan editor lengkap jika Anda memerlukannya).

Apakah halaman ini membantu?
0 / 5 - 0 peringkat