diff --git a/README.md b/README.md index a566b21..ecba5eb 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,9 @@ A small demo app demonstrating a working setup for Rails 3.2 ([demo](http://murm ### Add the gem to your Gemfile gem 'tinymce-rails-imageupload', '~> 4.0.0.beta' - + # or use git - + gem 'tinymce-rails-imageupload', github: 'PerfectlyNormal/tinymce-rails-imageupload' ### Set up TinyMCE as you would normally, but in the call to `.tinymce()`, add @@ -41,6 +41,20 @@ A small demo app demonstrating a working setup for Rails 3.2 ([demo](http://murm and the rest should happen automatically. +You can also globally have imageupload globally disabled but enabled on specific instances. + +~~~yml +# tinymce.yml +toolbar: bold italic underline | uploadimage +plugins: + - uploadimage +uploadimage: false +~~~ + +~~~erb +<%= tinymce uploadimage: true %> +~~~ + ### Set up upload URL and handler The plugin defaults to POSTing to `/tinymce_assets`. You may modify it by @@ -51,10 +65,6 @@ Set it up using something similar in `routes.rb`: post '/tinymce_assets' => 'tinymce_assets#create' -The plugin will relay option `uploadimage_hint` in the call to `.tinymce()` -to the POSTed URL as param `hint`. You may use this to relay any hints -you wish (for example, blog post ID #) to the controller. - This action gets called with a file parameter creatively called `file`, and must respond with JSON, containing the URL to the image. @@ -76,19 +86,81 @@ Example: end end + If the JSON response contains a `width` and/or `height` key, those will be used in the inserted HTML (``), but if those are not present, the inserted HTML is just ``. +### Hint param + +Per request `hint` data can be sent to the `create` action through the call to `.tinymce()` or `tinymce.yml`. You may use this to relay any hints you wish (for example, blog post ID #) to the controller. + +- `uploadimage_hint_key` - override the hint key. Default is `hint`. +- `uploadimage_hint` - hint value. + +Example: + +~~~erb +<%= tinymce uploadimage_hint_key: 'post_id', uploadimage_hint: @post.id %> +~~~ + +Would result in a `params` object that looks like this: + +~~~ruby +{ + "post_id": 1, + "file": ..., + // ... +} +~~~ + +### Model attributes + +Params can be sent in a more standard attributes format by setting `uploadimage_model`. + +- `uploadimage_model` - nest attributes within model namespace. + +Example: + +~~~erb +<%= tinymce uploadimage_model: 'post' %> +~~~ + +Would result in a `params` object that looks like this: + +~~~ruby +{ + "post": { + "file": ..., + // ... + }, +} +~~~ + ### Default class for img tag By default the plugin doesn't assign any class to the img tag. You can set the class(es) by supplying the `uploadimage_default_img_class` option in the call to `.tinymce()`. -`class="..."` will only be added to the img tag if a default is specified. +`class="..."` will only be added to the img tag if a default or custom class is specified. Otherwise the inserted HTML is just ``. +### Custom classes + +You can set `image_class_list` to an array of `title`, `value` objects to provide uploaders a pre-defined list of CSS classes to apply. + +~~~yml +# tinymce.yml +image_class_list: + - title: 'Center' + value: 'img-center' + - title: 'Left thumbnail' + value: 'img-left img-thumbnail' + - title: 'Right thumbnail' + value: 'img-right img-thumbnail' +~~~ + ## Asset Pipeline Several people have had trouble with asset precompilation using the asset pipeline, both for the locales, and the plugin itself. diff --git a/app/assets/javascripts/tinymce/plugins/uploadimage/plugin.js b/app/assets/javascripts/tinymce/plugins/uploadimage/plugin.js index ce3f4c3..860c63d 100644 --- a/app/assets/javascripts/tinymce/plugins/uploadimage/plugin.js +++ b/app/assets/javascripts/tinymce/plugins/uploadimage/plugin.js @@ -7,22 +7,44 @@ iframe, win, throbber, + selected_class = '', editor = ed; function showDialog() { + var classList = getClassList(); + var body = [ + {type: 'iframe', url: 'javascript:void(0)'}, + {type: 'textbox', name: 'file', label: ed.translate('Choose an image'), subtype: 'file'}, + {type: 'textbox', name: 'alt', label: ed.translate('Image description')} + ]; + + if (classList.length > 0) { + selected_class = classList[0].value; + body = body.concat([ + { + type: 'listbox', + name: 'class', + label: ed.translate('Class'), + values: classList, + onSelect: function(e) { + selected_class = this.value(); + } + } + ]); + } + + body = body.concat([ + {type: 'container', classes: 'error', html: "

 

"}, + + // Trick TinyMCE to add a empty div that "preloads" the throbber image + {type: 'container', classes: 'throbber'} + ]); + win = editor.windowManager.open({ title: ed.translate('Insert an image from your computer'), width: 520 + parseInt(editor.getLang('uploadimage.delta_width', 0), 10), height: 180 + parseInt(editor.getLang('uploadimage.delta_height', 0), 10), - body: [ - {type: 'iframe', url: 'javascript:void(0)'}, - {type: 'textbox', name: 'file', label: ed.translate('Choose an image'), subtype: 'file'}, - {type: 'textbox', name: 'alt', label: ed.translate('Image description')}, - {type: 'container', classes: 'error', html: "

 

"}, - - // Trick TinyMCE to add a empty div that "preloads" the throbber image - {type: 'container', classes: 'throbber'}, - ], + body: body, buttons: [ { text: ed.translate('Insert'), @@ -38,10 +60,6 @@ plugin_url: url }); - // TinyMCE likes pointless submit handlers - win.off('submit'); - win.on('submit', insertImage); - /* WHY DO YOU HATE
, TINYMCE!? */ iframe = win.find("iframe")[0]; form = createElement('form', { @@ -59,7 +77,7 @@ // Create some needed hidden inputs form.appendChild(createElement('input', {type: "hidden", name: "utf8", value: "✓"})); form.appendChild(createElement('input', {type: 'hidden', name: 'authenticity_token', value: getMetaContents('csrf-token')})); - form.appendChild(createElement('input', {type: 'hidden', name: 'hint', value: ed.getParam("uploadimage_hint", "")})); + form.appendChild(createElement('input', {type: 'hidden', name: hintName(), value: hintValue()})); var el = win.getEl(); var body = document.getElementById(el.id + "-body"); @@ -77,7 +95,7 @@ if(ctrl.tagName.toLowerCase() == 'input' && ctrl.type != "hidden") { if(ctrl.type == "file") { - ctrl.name = "file"; + ctrl.name = inputName('file'); // Hack styles tinymce.DOM.setStyles(ctrl, { @@ -86,7 +104,7 @@ 'webkitBoxShadow': 'none', }); } else { - ctrl.name = "alt"; + ctrl.name = inputName('alt'); } } } @@ -94,8 +112,24 @@ body.appendChild(form); } + function hintName() { + return inputName(ed.getParam('uploadimage_hint_key', 'hint')); + } + + function hintValue() { + return ed.getParam('uploadimage_hint', ''); + } + + function inputName(name) { + if (ed.getParam('uploadimage_model', false)) { + return ed.getParam('uploadimage_model') + '[' + name + ']'; + } else { + return name; + } + } + function insertImage() { - if(getInputValue("file") == "") { + if(getInputValue(inputName('file')) == "") { return handleError('You must choose a file'); } @@ -128,7 +162,7 @@ var target = iframe.getEl(); if(target.document || target.contentDocument) { var doc = target.contentDocument || target.contentWindow.document; - if(String(doc.contentType).includes("html")) { + if(String(doc.contentType).indexOf("html") > -1) { handleResponse(doc.getElementsByTagName("body")[0].innerHTML); } else { handleResponse(doc.getElementsByTagName("pre")[0].innerHTML); @@ -180,19 +214,20 @@ } function buildHTML(json) { + var image = json[ed.getParam('uploadimage_model', 'image')]; var default_class = ed.getParam("uploadimage_default_img_class", ""); var figure = ed.getParam("uploadimage_figure", false); - var alt_text = getInputValue("alt"); + var alt_text = getInputValue(inputName('alt')); - var imgstr = ""; @@ -237,20 +272,34 @@ return null; } - // Add a button that opens a window - editor.addButton('uploadimage', { - tooltip: ed.translate('Insert an image from your computer'), - icon : 'image', - onclick: showDialog - }); - - // Adds a menu item to the tools menu - editor.addMenuItem('uploadimage', { - text: ed.translate('Insert an image from your computer'), - icon : 'image', - context: 'insert', - onclick: showDialog - }); + function getClassList() { + var config = ed.getParam('image_class_list', []); + var values = []; + for (var i = 0; i < config.length; i++) { + values[i] = { + text: config[i]['title'], + value: config[i]['value'] + }; + } + return values; + }; + + if (editor.getParam('uploadimage', true)) { + // Add a button that opens a window + editor.addButton('uploadimage', { + tooltip: ed.translate('Insert an image from your computer'), + icon : 'image', + onclick: showDialog + }); + + // Adds a menu item to the tools menu + editor.addMenuItem('uploadimage', { + text: ed.translate('Insert an image from your computer'), + icon : 'image', + context: 'insert', + onclick: showDialog + }); + } } });