From a2567121f31f8a3e1dfd0adb13545c9be211a246 Mon Sep 17 00:00:00 2001 From: Angel Aviel Domaoan Date: Thu, 27 Jan 2022 08:51:54 +0000 Subject: [PATCH] Setup ckeditor --- Gemfile | 2 +- Gemfile.lock | 96 ++++++++------ .../javascripts/frameworks/main.ckeditor.js | 23 ++++ app/assets/javascripts/frameworks/main.js.erb | 117 ++++++++++++++++++ app/views/layouts/application.html.erb | 2 + config/application.rb | 3 + config/initializers/assets.rb | 28 +++++ public/icons.png | Bin 0 -> 5598 bytes public/images/sprites.png | Bin 0 -> 7086 bytes 9 files changed, 231 insertions(+), 40 deletions(-) create mode 100644 app/assets/javascripts/frameworks/main.ckeditor.js create mode 100644 app/assets/javascripts/frameworks/main.js.erb create mode 100644 public/icons.png create mode 100644 public/images/sprites.png diff --git a/Gemfile b/Gemfile index da26087..db0cd20 100644 --- a/Gemfile +++ b/Gemfile @@ -13,7 +13,7 @@ gem "foreman" # Use Puma as the app server gem 'puma', '~> 5.0' # Use SCSS for stylesheets -gem 'sass-rails', '>= 6' +gem "sass-rails", "~> 5.1" # Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker gem 'webpacker', '~> 5.0' # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks diff --git a/Gemfile.lock b/Gemfile.lock index f1fffd2..af508c3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -100,8 +100,8 @@ GEM bindex (0.8.1) binding_of_caller (1.0.0) debug_inspector (>= 0.0.1) - bootsnap (1.9.3) - msgpack (~> 1.0) + bootsnap (1.10.2) + msgpack (~> 1.2) builder (3.2.4) byebug (11.1.3) cable_ready (4.5.0) @@ -166,18 +166,37 @@ GEM warden (~> 1.2.3) ed25519 (1.3.0) erubi (1.10.0) - faraday (2.0.1) - faraday-net_http (~> 2.0) + faraday (1.9.3) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0) + faraday-multipart (~> 1.0) + faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.0) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) + faraday-retry (~> 1.0) ruby2_keywords (>= 0.0.4) - faraday-net_http (2.0.1) - ffi (1.15.4) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.0) + faraday-excon (1.1.0) + faraday-httpclient (1.0.1) + faraday-multipart (1.0.3) + multipart-post (>= 1.2, < 3) + faraday-net_http (1.0.1) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) + faraday-retry (1.0.3) + ffi (1.15.5) figaro (1.2.0) thor (>= 0.14.0, < 2) foreman (0.87.2) globalid (1.0.0) activesupport (>= 5.0) highline (2.0.3) - i18n (1.8.11) + i18n (1.9.0) concurrent-ruby (~> 1.0) jbuilder (2.11.5) actionview (>= 5.0.0) @@ -194,7 +213,7 @@ GEM activerecord kaminari-core (= 1.2.2) kaminari-core (1.2.2) - listen (3.7.0) + listen (3.7.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) loofah (2.13.0) @@ -207,27 +226,26 @@ GEM method_source (1.0.0) mini_mime (1.1.2) minitest (5.15.0) - msgpack (1.4.2) + msgpack (1.4.4) + multipart-post (2.1.1) net-scp (3.0.0) net-ssh (>= 2.6.5, < 7.0.0) net-ssh (6.1.0) nio4r (2.5.8) - nokogiri (1.13.0-x86_64-darwin) - racc (~> 1.4) - nokogiri (1.13.0-x86_64-linux) + nokogiri (1.13.1-x86_64-linux) racc (~> 1.4) nokogiri-styles (0.1.2) nokogiri okcomputer (1.18.4) options (2.3.2) orm_adapter (0.5.0) - paper_trail (12.1.0) + paper_trail (12.2.0) activerecord (>= 5.2) request_store (~> 1.1) parallel (1.21.0) parser (3.1.0.0) ast (~> 2.4.1) - pg (1.2.3) + pg (1.3.0) pr_geohash (1.0.0) progress_bar (1.3.3) highline (>= 1.6, < 3) @@ -235,7 +253,7 @@ GEM public_suffix (4.0.6) public_uid (2.1.1) activerecord (> 4.2) - puma (5.5.2) + puma (5.6.1) nio4r (~> 2.0) racc (1.6.0) rack (2.2.3) @@ -271,14 +289,14 @@ GEM method_source rake (>= 0.13) thor (~> 1.0) - rainbow (3.0.0) + rainbow (3.1.1) rake (13.0.6) rb-fsevent (0.11.0) rb-inotify (0.10.1) ffi (~> 1.0) redis (4.5.1) regexp_parser (2.2.0) - request_store (1.5.0) + request_store (1.5.1) rack (>= 1.4) responders (3.0.1) actionpack (>= 5.0) @@ -288,9 +306,9 @@ GEM rsolr (2.4.0) builder (>= 2.1.2) faraday (>= 0.9.0) - rubocop (1.24.1) + rubocop (1.25.0) parallel (~> 1.10) - parser (>= 3.0.0.0) + parser (>= 3.1.0.0) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) rexml @@ -303,37 +321,38 @@ GEM rubocop (>= 0.90, < 2.0) rubocop-packaging (0.5.1) rubocop (>= 0.89, < 2.0) - rubocop-performance (1.13.1) + rubocop-performance (1.13.2) rubocop (>= 1.7.0, < 2.0) rubocop-ast (>= 0.4.0) - rubocop-rails (2.13.1) + rubocop-rails (2.13.2) activesupport (>= 4.2.0) rack (>= 1.1) rubocop (>= 1.7.0, < 2.0) ruby-progressbar (1.11.0) ruby2_keywords (0.0.5) rubyzip (2.3.2) - sass-rails (6.0.0) - sassc-rails (~> 2.1, >= 2.1.1) - sassc (2.4.0) - ffi (~> 1.9) - sassc-rails (2.1.2) - railties (>= 4.0.0) - sassc (>= 2.0) - sprockets (> 3.0) - sprockets-rails - tilt + sass (3.7.4) + sass-listen (~> 4.0.0) + sass-listen (4.0.0) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + sass-rails (5.1.0) + railties (>= 5.2.0) + sass (~> 3.1) + sprockets (>= 2.8, < 4.0) + sprockets-rails (>= 2.0, < 4.0) + tilt (>= 1.1, < 3) secure_headers (6.3.3) selenium-webdriver (4.1.0) childprocess (>= 0.5, < 5.0) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2) semantic_range (3.0.0) - sentry-ruby (4.8.1) + sentry-ruby (4.9.2) concurrent-ruby (~> 1.0, >= 1.0.2) - faraday (>= 1.0) - sentry-ruby-core (= 4.8.1) - sentry-ruby-core (4.8.1) + faraday (~> 1.0) + sentry-ruby-core (= 4.9.2) + sentry-ruby-core (4.9.2) concurrent-ruby faraday sidekiq (6.4.0) @@ -341,7 +360,7 @@ GEM rack (~> 2.0) redis (>= 4.2.0) spring (3.1.1) - sprockets (4.0.2) + sprockets (3.7.2) concurrent-ruby (~> 1.0) rack (> 1, < 3) sprockets-rails (3.4.2) @@ -389,7 +408,7 @@ GEM tzinfo (2.0.4) concurrent-ruby (~> 1.0) unicode-display_width (2.1.0) - view_component (2.47.0) + view_component (2.48.0) activesupport (>= 5.0.0, < 8.0) method_source (~> 1.0) warden (1.2.9) @@ -416,7 +435,6 @@ GEM zeitwerk (2.5.3) PLATFORMS - x86_64-darwin-20 x86_64-linux DEPENDENCIES @@ -467,7 +485,7 @@ DEPENDENCIES rubocop-packaging rubocop-performance rubocop-rails - sass-rails (>= 6) + sass-rails (~> 5.1) secure_headers (>= 6.3.0) selenium-webdriver sentry-ruby (~> 4.8) diff --git a/app/assets/javascripts/frameworks/main.ckeditor.js b/app/assets/javascripts/frameworks/main.ckeditor.js new file mode 100644 index 0000000..0caa3f7 --- /dev/null +++ b/app/assets/javascripts/frameworks/main.ckeditor.js @@ -0,0 +1,23 @@ +//= require ckeditor/config +//= require ckeditor/init + +$('.i-ckeditor').each(function(){ + var a, b; + a = $(this), b = a.attr('id') || ('ckeditor' + (new Date).getTime()) + // +}) + +$('.i-ckeditor-readonly').each(function(){ + var a, b; + a = $(this), b = a.attr('id') || ('ckeditor' + (new Date).getTime()) + var options = {}; + options.readOnly = true + options.toolbar = [ + { name: 'document', items : [ 'Source', 'Maximize' ] } + ] + options.resize_enabled = false; + + if (typeof CKEDITOR != 'undefined') { editor = CKEDITOR.replace(b, options); } +}) diff --git a/app/assets/javascripts/frameworks/main.js.erb b/app/assets/javascripts/frameworks/main.js.erb new file mode 100644 index 0000000..ad807e8 --- /dev/null +++ b/app/assets/javascripts/frameworks/main.js.erb @@ -0,0 +1,117 @@ +//= require frameworks/main.ckeditor + +(function () { + $.cachedScript = function( url, options ) { + options = $.extend( options || {}, { + dataType: "script", + cache: true, + async: true, + url: url + }); + return $.ajaxq(url,options); + } + + $.fn.doesExist = function() { + return $(this).length > 0; + }; + + if($('.i-ckeditor').doesExist()){ + $.cachedScript("<%= asset_path 'frameworks/main.ckeditor.js' %>"); + } + if($('.i-ckeditor-readonly').doesExist()){ + $.cachedScript("<%= asset_path 'frameworks/main.ckeditor.js' %>"); + } +}) + +/* +Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ + +CKEDITOR.editorConfig = function( config ) +{ + // Define changes to default configuration here. For example: + // config.language = 'fr'; + // config.uiColor = '#AADC6E'; + + /* Filebrowser routes */ + // The location of an external file browser, that should be launched when "Browse Server" button is pressed. + config.filebrowserBrowseUrl = "/ckeditor/attachment_files"; + + // The location of an external file browser, that should be launched when "Browse Server" button is pressed in the Flash dialog. + config.filebrowserFlashBrowseUrl = "/ckeditor/attachment_files"; + + // The location of a script that handles file uploads in the Flash dialog. + config.filebrowserFlashUploadUrl = "/ckeditor/attachment_files"; + + // The location of an external file browser, that should be launched when "Browse Server" button is pressed in the Link tab of Image dialog. + config.filebrowserImageBrowseLinkUrl = "/ckeditor/pictures"; + + // The location of an external file browser, that should be launched when "Browse Server" button is pressed in the Image dialog. + config.filebrowserImageBrowseUrl = "/ckeditor/pictures"; + + // The location of a script that handles file uploads in the Image dialog. + config.filebrowserImageUploadUrl = "/ckeditor/pictures"; + + // The location of a script that handles file uploads. + config.filebrowserUploadUrl = "/ckeditor/attachment_files"; + + // Rails CSRF token + config.filebrowserParams = function(){ + var csrf_token, csrf_param, meta, + metas = document.getElementsByTagName('meta'), + params = new Object(); + + for ( var i = 0 ; i < metas.length ; i++ ){ + meta = metas[i]; + + switch(meta.name) { + case "csrf-token": + csrf_token = meta.content; + break; + case "csrf-param": + csrf_param = meta.content; + break; + default: + continue; + } + } + + if (csrf_param !== undefined && csrf_token !== undefined) { + params[csrf_param] = csrf_token; + } + + return params; + }; + + config.addQueryString = function( url, params ){ + var queryString = []; + + if ( !params ) { + return url; + } else { + for ( var i in params ) + queryString.push( i + "=" + encodeURIComponent( params[ i ] ) ); + } + + return url + ( ( url.indexOf( "?" ) != -1 ) ? "&" : "?" ) + queryString.join( "&" ); + }; + + // Integrate Rails CSRF token into file upload dialogs (link, image, attachment and flash) + CKEDITOR.on( 'dialogDefinition', function( ev ){ + // Take the dialog name and its definition from the event data. + var dialogName = ev.data.name; + var dialogDefinition = ev.data.definition; + var content, upload; + + if (CKEDITOR.tools.indexOf(['link', 'image', 'attachment', 'flash'], dialogName) > -1) { + content = (dialogDefinition.getContents('Upload') || dialogDefinition.getContents('upload')); + upload = (content == null ? null : content.get('upload')); + + if (upload && upload.filebrowser && upload.filebrowser['params'] === undefined) { + upload.filebrowser['params'] = config.filebrowserParams(); + upload.action = config.addQueryString(upload.action, upload.filebrowser['params']); + } + } + }); +}; diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 7dc4feb..8b2ab89 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -24,5 +24,7 @@ + + <%= javascript_include_tag 'frameworks/main' %> diff --git a/config/application.rb b/config/application.rb index 71fbd02..1dc0fc6 100644 --- a/config/application.rb +++ b/config/application.rb @@ -18,5 +18,8 @@ module CdaoPjet # # config.time_zone = "Central Time (US & Canada)" # config.eager_load_paths << Rails.root.join("extras") + + # Enable the asset pipeline + config.assets.enabled = true end end diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index 4b828e8..c5a52cd 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -12,3 +12,31 @@ Rails.application.config.assets.paths << Rails.root.join('node_modules') # application.js, application.css, and all non-JS/CSS in the app/assets # folder are already added. # Rails.application.config.assets.precompile += %w( admin.js admin.css ) + +Rails.application.config.assets.precompile += Ckeditor.assets << /ckeditor\/lang\/.*.js/ + +assets_filter_precompile = lambda do |filename, path| + app_filters = [/(frameworks\/main|app|init|frameworks\/main.ckeditor|frameworks)\.(css|js)/, "frameworks/main.js"] + filters = [/.*\.woff/, /.*\.eot/, /.*\.svg/, /.*\.ttf/, /.*\.swf/] + # Assets to precompile in app/assets + precompile = path =~ /app\/assets/ && app_filters.concat(filters).any? do |filter| + if filter.is_a?(Regexp) + filter.match(filename) + else + File.fnmatch(filter.to_s, filename) + end + end + # Assets to precompile for not under in app/assets + # Skip if +precompile+ is `true` + precompile = !(path =~ /app\/assets/) && filters.any? do |filter| + if filter.is_a?(Regexp) + filter.match(filename) + else + File.fnmatch(filter.to_s, filename) + end + end unless precompile + precompile +end + +Rails.application.config.assets.precompile += [assets_filter_precompile] +Rails.application.config.assets.precompile += %w(ckeditor/*) diff --git a/public/icons.png b/public/icons.png new file mode 100644 index 0000000000000000000000000000000000000000..7c3bf195dd35a2dd3773a5cae7e4712a1133a5d5 GIT binary patch literal 5598 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 M(7LLX%GRO(1EjHd^8f$< literal 0 HcmV?d00001 diff --git a/public/images/sprites.png b/public/images/sprites.png new file mode 100644 index 0000000000000000000000000000000000000000..0cb4e1c6c37e5ffa475f73bb252adbec70135ac4 GIT binary patch literal 7086 zcmc(EWl)?=ur3HVPo0dInHUQTi%e5P)c`ZnVqp=C z6F$I5Jto1NSXeBcnySi1K8xra5+9?Ph5-}8r`Y=J#52$Ex!;CRuoLqUn�~;+yNk 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