UNPKG

alpaca

Version:

Alpaca provides the easiest and fastest way to generate interactive forms for the web and mobile devices. It runs simply as HTML5 or more elaborately using Bootstrap, jQuery Mobile or jQuery UI. Alpaca uses Handlebars to process JSON schema and provide

440 lines (369 loc) 10.3 kB
/** * plugin.js * * Copyright, Moxiecode Systems AB * Released under LGPL License. * * License: http://www.tinymce.com/license * Contributing: http://www.tinymce.com/contributing */ /*global tinymce:true */ tinymce.PluginManager.add('image', function(editor) { function getImageSize(url, callback) { var img = document.createElement('img'); function done(width, height) { if (img.parentNode) { img.parentNode.removeChild(img); } callback({width: width, height: height}); } img.onload = function() { done(img.clientWidth, img.clientHeight); }; img.onerror = function() { done(); }; var style = img.style; style.visibility = 'hidden'; style.position = 'fixed'; style.bottom = style.left = 0; style.width = style.height = 'auto'; document.body.appendChild(img); img.src = url; } function buildListItems(inputList, itemCallback, startItems) { function appendItems(values, output) { output = output || []; tinymce.each(values, function(item) { var menuItem = {text: item.text || item.title}; if (item.menu) { menuItem.menu = appendItems(item.menu); } else { menuItem.value = item.value; itemCallback(menuItem); } output.push(menuItem); }); return output; } return appendItems(inputList, startItems || []); } function createImageList(callback) { return function() { var imageList = editor.settings.image_list; if (typeof(imageList) == "string") { tinymce.util.XHR.send({ url: imageList, success: function(text) { callback(tinymce.util.JSON.parse(text)); } }); } else if (typeof(imageList) == "function") { imageList(callback); } else { callback(imageList); } }; } function showDialog(imageList) { var win, data = {}, dom = editor.dom, imgElm = editor.selection.getNode(); var width, height, imageListCtrl, classListCtrl, imageDimensions = editor.settings.image_dimensions !== false; function recalcSize() { var widthCtrl, heightCtrl, newWidth, newHeight; widthCtrl = win.find('#width')[0]; heightCtrl = win.find('#height')[0]; if (!widthCtrl || !heightCtrl) { return; } newWidth = widthCtrl.value(); newHeight = heightCtrl.value(); if (win.find('#constrain')[0].checked() && width && height && newWidth && newHeight) { if (width != newWidth) { newHeight = Math.round((newWidth / width) * newHeight); heightCtrl.value(newHeight); } else { newWidth = Math.round((newHeight / height) * newWidth); widthCtrl.value(newWidth); } } width = newWidth; height = newHeight; } function onSubmitForm() { function waitLoad(imgElm) { function selectImage() { imgElm.onload = imgElm.onerror = null; if (editor.selection) { editor.selection.select(imgElm); editor.nodeChanged(); } } imgElm.onload = function() { if (!data.width && !data.height && imageDimensions) { dom.setAttribs(imgElm, { width: imgElm.clientWidth, height: imgElm.clientHeight }); } selectImage(); }; imgElm.onerror = selectImage; } updateStyle(); recalcSize(); data = tinymce.extend(data, win.toJSON()); if (!data.alt) { data.alt = ''; } if (data.width === '') { data.width = null; } if (data.height === '') { data.height = null; } if (!data.style) { data.style = null; } // Setup new data excluding style properties data = { src: data.src, alt: data.alt, width: data.width, height: data.height, style: data.style, "class": data["class"] }; editor.undoManager.transact(function() { if (!data.src) { if (imgElm) { dom.remove(imgElm); editor.focus(); editor.nodeChanged(); } return; } if (!imgElm) { data.id = '__mcenew'; editor.focus(); editor.selection.setContent(dom.createHTML('img', data)); imgElm = dom.get('__mcenew'); dom.setAttrib(imgElm, 'id', null); } else { dom.setAttribs(imgElm, data); } waitLoad(imgElm); }); } function removePixelSuffix(value) { if (value) { value = value.replace(/px$/, ''); } return value; } function srcChange(e) { var meta = e.meta || {}; if (imageListCtrl) { imageListCtrl.value(editor.convertURL(this.value(), 'src')); } tinymce.each(meta, function(value, key) { win.find('#' + key).value(value); }); if (!meta.width && !meta.height) { var srcURL = this.value(), absoluteURLPattern = new RegExp('^(?:[a-z]+:)?//', 'i'), baseURL = editor.settings.document_base_url; //Pattern test the src url and make sure we haven't already prepended the url if (baseURL && !absoluteURLPattern.test(srcURL) && srcURL.substring(0, baseURL.length) !== baseURL) { this.value(baseURL + srcURL); } getImageSize(this.value(), function(data) { if (data.width && data.height && imageDimensions) { width = data.width; height = data.height; win.find('#width').value(width); win.find('#height').value(height); } }); } } width = dom.getAttrib(imgElm, 'width'); height = dom.getAttrib(imgElm, 'height'); if (imgElm.nodeName == 'IMG' && !imgElm.getAttribute('data-mce-object') && !imgElm.getAttribute('data-mce-placeholder')) { data = { src: dom.getAttrib(imgElm, 'src'), alt: dom.getAttrib(imgElm, 'alt'), "class": dom.getAttrib(imgElm, 'class'), width: width, height: height }; } else { imgElm = null; } if (imageList) { imageListCtrl = { type: 'listbox', label: 'Image list', values: buildListItems( imageList, function(item) { item.value = editor.convertURL(item.value || item.url, 'src'); }, [{text: 'None', value: ''}] ), value: data.src && editor.convertURL(data.src, 'src'), onselect: function(e) { var altCtrl = win.find('#alt'); if (!altCtrl.value() || (e.lastControl && altCtrl.value() == e.lastControl.text())) { altCtrl.value(e.control.text()); } win.find('#src').value(e.control.value()).fire('change'); }, onPostRender: function() { imageListCtrl = this; } }; } if (editor.settings.image_class_list) { classListCtrl = { name: 'class', type: 'listbox', label: 'Class', values: buildListItems( editor.settings.image_class_list, function(item) { if (item.value) { item.textStyle = function() { return editor.formatter.getCssText({inline: 'img', classes: [item.value]}); }; } } ) }; } // General settings shared between simple and advanced dialogs var generalFormItems = [ { name: 'src', type: 'filepicker', filetype: 'image', label: 'Source', autofocus: true, onchange: srcChange }, imageListCtrl ]; if (editor.settings.image_description !== false) { generalFormItems.push({name: 'alt', type: 'textbox', label: 'Image description'}); } if (imageDimensions) { generalFormItems.push({ type: 'container', label: 'Dimensions', layout: 'flex', direction: 'row', align: 'center', spacing: 5, items: [ {name: 'width', type: 'textbox', maxLength: 5, size: 3, onchange: recalcSize, ariaLabel: 'Width'}, {type: 'label', text: 'x'}, {name: 'height', type: 'textbox', maxLength: 5, size: 3, onchange: recalcSize, ariaLabel: 'Height'}, {name: 'constrain', type: 'checkbox', checked: true, text: 'Constrain proportions'} ] }); } generalFormItems.push(classListCtrl); function updateStyle() { function addPixelSuffix(value) { if (value.length > 0 && /^[0-9]+$/.test(value)) { value += 'px'; } return value; } if (!editor.settings.image_advtab) { return; } var data = win.toJSON(); var css = dom.parseStyle(data.style); delete css.margin; css['margin-top'] = css['margin-bottom'] = addPixelSuffix(data.vspace); css['margin-left'] = css['margin-right'] = addPixelSuffix(data.hspace); css['border-width'] = addPixelSuffix(data.border); win.find('#style').value(dom.serializeStyle(dom.parseStyle(dom.serializeStyle(css)))); } if (editor.settings.image_advtab) { // Parse styles from img if (imgElm) { data.hspace = removePixelSuffix(imgElm.style.marginLeft || imgElm.style.marginRight); data.vspace = removePixelSuffix(imgElm.style.marginTop || imgElm.style.marginBottom); data.border = removePixelSuffix(imgElm.style.borderWidth); data.style = editor.dom.serializeStyle(editor.dom.parseStyle(editor.dom.getAttrib(imgElm, 'style'))); } // Advanced dialog shows general+advanced tabs win = editor.windowManager.open({ title: 'Insert/edit image', data: data, bodyType: 'tabpanel', body: [ { title: 'General', type: 'form', items: generalFormItems }, { title: 'Advanced', type: 'form', pack: 'start', items: [ { label: 'Style', name: 'style', type: 'textbox' }, { type: 'form', layout: 'grid', packV: 'start', columns: 2, padding: 0, alignH: ['left', 'right'], defaults: { type: 'textbox', maxWidth: 50, onchange: updateStyle }, items: [ {label: 'Vertical space', name: 'vspace'}, {label: 'Horizontal space', name: 'hspace'}, {label: 'Border', name: 'border'} ] } ] } ], onSubmit: onSubmitForm }); } else { // Simple default dialog win = editor.windowManager.open({ title: 'Insert/edit image', data: data, body: generalFormItems, onSubmit: onSubmitForm }); } } editor.addButton('image', { icon: 'image', tooltip: 'Insert/edit image', onclick: createImageList(showDialog), stateSelector: 'img:not([data-mce-object],[data-mce-placeholder])' }); editor.addMenuItem('image', { icon: 'image', text: 'Insert image', onclick: createImageList(showDialog), context: 'insert', prependToContext: true }); editor.addCommand('mceImage', createImageList(showDialog)); });