--- /dev/null
+<!DOCTYPE html>
+<!--
+Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+-->
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>BBCode plugin playground – CKEditor Sample</title>
+ <script src="../../../ckeditor.js"></script>
+ <link href="../../../samples/sample.css" rel="stylesheet">
+ <style>
+body {
+ margin: 0;
+}
+
+#editables
+{
+ float:left;
+ width: 49%
+}
+
+#preview
+{
+ width: 50%;
+ float:right;
+}
+
+#console
+{
+ height: 300px;
+ padding: 5px 10px;
+ border: solid 3px #555;
+ overflow: auto;
+ color: #000;
+ -webkit-transition: border-color 0.5s;
+ -moz-transition: border-color 0.5s;
+ -o-transition: border-color 0.5s;
+ -ms-transition: border-color 0.5s;
+ transition: border-color 0.5s;
+ font-family: Monaco, monospace;
+ font-size: 13px;
+ white-space: normal;
+}
+
+#console.updated {
+ border-color: #0B0;
+}
+ </style>
+</head>
+<body>
+ <h1 class="samples">
+ CKEditor Sample — BBCode plugin playground
+ </h1>
+ <div id="main">
+ <div class="description">
+ <p>
+ This sample shows how to configure CKEditor to output <a href="http://en.wikipedia.org/wiki/BBCode">BBCode</a> format instead of HTML.
+ Please note that the editor configuration was modified to reflect what is needed in a BBCode editing environment.
+ Smiley images, for example, were stripped to the emoticons that are commonly used in some BBCode dialects.
+ </p>
+ <p>
+ Please note that currently there is no standard for the BBCode markup language, so its implementation
+ for different platforms (message boards, blogs etc.) can vary. This means that before using CKEditor to
+ output BBCode you may need to adjust the implementation to your own environment.
+ </p>
+ <p>
+ A snippet of the configuration code can be seen below; check the source of this page for
+ a full definition:
+ </p>
+ <pre class="samples">
+CKEDITOR.inline( 'editor1', {
+ <strong>extraPlugins : 'bbcode',</strong>
+ <i>(below configurations details omitted:)</i>
+ toolbar : ...,
+ fontSize_sizes : ...,
+ smiley_images : ...,
+ smiley_descriptions : ...
+});</pre>
+ </div>
+
+ <div id="editables">
+ <textarea id="editor1">
+[img]http://a.cksource.com/f/1/img/logo-ckeditor.gif[/img]
+"[b]Little Red Riding Hood[/b]" is a famous [url=http://en.wikipedia.org/wiki/Fairy_tale]fairy tale[/url] about a young girl's encounter with a wolf. The story has been changed considerably in its history and subject to numerous modern adaptations and readings.
+[list]
+[*]Chinese: [i]小紅帽[/i]
+[*]Italian: [i]Cappuccetto Rosso[/i]
+[*]Spanish: [i]Caperucita Roja[/i]
+[/list]
+[quote]It is about a girl called [color=#FF0000]Little Red Riding Hood :)[/color], after the red [url=http://en.wikipedia.org/wiki/Hood_%28headgear%29]hooded[/url] [url=http://en.wikipedia.org/wiki/Cape]cape[/url] or [url=http://en.wikipedia.org/wiki/Cloak]cloak[/url] she wears.
+The girl walks through the woods to deliver food to her sick grandmother. A wolf wants to eat the girl but is afraid to do so in public. He approaches the girl, and she naïvely tells him where she is going.
+He suggests the girl pick some flowers, which she does. In the meantime, he goes to the grandmother's house and gains entry by pretending to be the girl. He swallows the grandmother whole, and waits for the girl, disguised as the grandmother. When the girl arrives, she notices he looks very strange to be her grandma. In most retellings, this eventually culminates with Little Red Riding Hood saying, "My, what big teeth you have!"
+To which the wolf replies, "The better to eat you with," and swallows her whole, too.[/quote]
+The above version most widely known today is based on the [url=http://en.wikipedia.org/wiki/Brothers_Grimm]Brothers Grimm[/url] variant.
+ </textarea>
+ </div>
+ <div id="preview">
+ <h3 for="console">BBCode Output: </h3>
+ <pre id="console">
+ </pre>
+ </div>
+ </div>
+ <div id="footer">
+ <hr>
+ <p>
+ CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
+ </p>
+ <p id="copy">
+ Copyright © 2003-2013, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
+ Knabben. All rights reserved.
+ </p>
+ </div>
+ <script>
+(function() {
+ 'use strict';
+
+ var editor = CKEDITOR.replace( 'editor1', {
+ extraPlugins: 'bbcode',
+ // Remove unused plugins.
+ removePlugins: 'bidi,dialogadvtab,div,filebrowser,flash,format,forms,horizontalrule,iframe,justify,liststyle,pagebreak,showborders,stylescombo,table,tabletools,templates',
+ // Width and height are not supported in the BBCode format, so object resizing is disabled.
+ disableObjectResizing: true,
+ height: 250,
+ toolbar: [
+ ['Source', '-', 'Save', 'NewPage', '-', 'Undo', 'Redo'],
+ ['Find', 'Replace', '-', 'SelectAll', 'RemoveFormat'],
+ ['Link', 'Unlink', 'Image'],
+ '/',
+ ['FontSize', 'Bold', 'Italic', 'Underline'],
+ ['NumberedList', 'BulletedList', '-', 'Blockquote'],
+ ['TextColor', '-', 'Smiley', 'SpecialChar', '-', 'Maximize']
+ ],
+ // Define font sizes in percent values.
+ fontSize_sizes: '30/30%;50/50%;100/100%;120/120%;150/150%;200/200%;300/300%',
+ // Strip CKEditor smileys to those commonly used in BBCode.
+ smiley_images: [
+ 'regular_smile.png', 'sad_smile.png', 'wink_smile.png', 'teeth_smile.png', 'tongue_smile.png',
+ 'embarrassed_smile.png', 'omg_smile.png', 'whatchutalkingabout_smile.png', 'angel_smile.png',
+ 'shades_smile.png', 'cry_smile.png', 'kiss.png'
+ ],
+ smiley_descriptions: [
+ 'smiley', 'sad', 'wink', 'laugh', 'cheeky', 'blush', 'surprise',
+ 'indecision', 'angel', 'cool', 'crying', 'kiss'
+ ]
+ } );
+
+ function updatePreview() {
+ var consoleEl = CKEDITOR.document.getById( 'console' );
+ consoleEl.addClass( 'updated' );
+ setTimeout( function() { consoleEl.removeClass( 'updated' ); }, 500 );
+ // IE needs <br>, it doesn't even understand new lines.
+ consoleEl.setHtml( editor.getData().replace( /\n\r?/g, '<br>' ) );
+ }
+
+ function checkUpdatePreview() {
+ setTimeout( function() {
+ if ( editor.checkDirty() ) {
+ updatePreview();
+ editor.resetDirty();
+ }
+ }, 0 );
+ }
+
+ editor.on( 'instanceReady', updatePreview );
+ editor.on( 'key', checkUpdatePreview );
+ editor.on( 'selectionChange', checkUpdatePreview );
+
+})();
+ </script>
+</body>
+</html>
--- /dev/null
+/**
+ * @license Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+(function() {
+ CKEDITOR.on( 'dialogDefinition', function( ev ) {
+ var tab,
+ name = ev.data.name,
+ definition = ev.data.definition;
+
+ if ( name == 'link' ) {
+ definition.removeContents( 'target' );
+ definition.removeContents( 'upload' );
+ definition.removeContents( 'advanced' );
+ tab = definition.getContents( 'info' );
+ tab.remove( 'emailSubject' );
+ tab.remove( 'emailBody' );
+ } else if ( name == 'image' ) {
+ definition.removeContents( 'advanced' );
+ tab = definition.getContents( 'Link' );
+ tab.remove( 'cmbTarget' );
+ tab = definition.getContents( 'info' );
+ tab.remove( 'txtAlt' );
+ tab.remove( 'basic' );
+ }
+ });
+
+ var bbcodeMap = { b: 'strong', u: 'u', i: 'em', color: 'span', size: 'span', quote: 'blockquote', code: 'code', url: 'a', email: 'span', img: 'span', '*': 'li', list: 'ol' },
+ convertMap = { strong: 'b', b: 'b', u: 'u', em: 'i', i: 'i', code: 'code', li: '*' },
+ tagnameMap = { strong: 'b', em: 'i', u: 'u', li: '*', ul: 'list', ol: 'list', code: 'code', a: 'link', img: 'img', blockquote: 'quote' },
+ stylesMap = { color: 'color', size: 'font-size' },
+ attributesMap = { url: 'href', email: 'mailhref', quote: 'cite', list: 'listType' };
+
+ // List of block-like tags.
+ var dtd = CKEDITOR.dtd,
+ blockLikeTags = CKEDITOR.tools.extend( { table:1 }, dtd.$block, dtd.$listItem, dtd.$tableContent, dtd.$list );
+
+ var semicolonFixRegex = /\s*(?:;\s*|$)/;
+
+ function serializeStyleText( stylesObject ) {
+ var styleText = '';
+ for ( var style in stylesObject ) {
+ var styleVal = stylesObject[ style ],
+ text = ( style + ':' + styleVal ).replace( semicolonFixRegex, ';' );
+
+ styleText += text;
+ }
+ return styleText;
+ }
+
+ // Maintain the map of smiley-to-description.
+ var smileyMap = { smiley: ':)', sad: ':(', wink: ';)', laugh: ':D', cheeky: ':P', blush: ':*)', surprise: ':-o', indecision: ':|', angry: '>:(', angel: 'o:)', cool: '8-)', devil: '>:-)', crying: ';(', kiss: ':-*' },
+ smileyReverseMap = {},
+ smileyRegExp = [];
+
+ // Build regexp for the list of smiley text.
+ for ( var i in smileyMap ) {
+ smileyReverseMap[ smileyMap[ i ] ] = i;
+ smileyRegExp.push( smileyMap[ i ].replace( /\(|\)|\:|\/|\*|\-|\|/g, function( match ) {
+ return '\\' + match;
+ }));
+ }
+
+ smileyRegExp = new RegExp( smileyRegExp.join( '|' ), 'g' );
+
+ var decodeHtml = (function() {
+ var regex = [],
+ entities = {
+ nbsp: '\u00A0', // IE | FF
+ shy: '\u00AD', // IE
+ gt: '\u003E', // IE | FF | -- | Opera
+ lt: '\u003C' // IE | FF | Safari | Opera
+ };
+
+ for ( var entity in entities )
+ regex.push( entity );
+
+ regex = new RegExp( '&(' + regex.join( '|' ) + ');', 'g' );
+
+ return function( html ) {
+ return html.replace( regex, function( match, entity ) {
+ return entities[ entity ];
+ });
+ };
+ })();
+
+ CKEDITOR.BBCodeParser = function() {
+ this._ = {
+ bbcPartsRegex: /(?:\[([^\/\]=]*?)(?:=([^\]]*?))?\])|(?:\[\/([a-z]{1,16})\])/ig
+ };
+ };
+
+ CKEDITOR.BBCodeParser.prototype = {
+ parse: function( bbcode ) {
+ var parts, part,
+ lastIndex = 0;
+
+ while ( ( parts = this._.bbcPartsRegex.exec( bbcode ) ) ) {
+ var tagIndex = parts.index;
+ if ( tagIndex > lastIndex ) {
+ var text = bbcode.substring( lastIndex, tagIndex );
+ this.onText( text, 1 );
+ }
+
+ lastIndex = this._.bbcPartsRegex.lastIndex;
+
+ // "parts" is an array with the following items:
+ // 0 : The entire match for opening/closing tags and line-break;
+ // 1 : line-break;
+ // 2 : open of tag excludes option;
+ // 3 : tag option;
+ // 4 : close of tag;
+
+ part = ( parts[ 1 ] || parts[ 3 ] || '' ).toLowerCase();
+ // Unrecognized tags should be delivered as a simple text (#7860).
+ if ( part && !bbcodeMap[ part ] ) {
+ this.onText( parts[ 0 ] );
+ continue;
+ }
+
+ // Opening tag
+ if ( parts[ 1 ] ) {
+ var tagName = bbcodeMap[ part ],
+ attribs = {},
+ styles = {},
+ optionPart = parts[ 2 ];
+
+ if ( optionPart ) {
+ if ( part == 'list' ) {
+ if ( !isNaN( optionPart ) )
+ optionPart = 'decimal';
+ else if ( /^[a-z]+$/.test( optionPart ) )
+ optionPart = 'lower-alpha';
+ else if ( /^[A-Z]+$/.test( optionPart ) )
+ optionPart = 'upper-alpha';
+ }
+
+ if ( stylesMap[ part ] ) {
+ // Font size represents percentage.
+ if ( part == 'size' )
+ optionPart += '%';
+
+ styles[ stylesMap[ part ] ] = optionPart;
+ attribs.style = serializeStyleText( styles );
+ } else if ( attributesMap[ part ] )
+ attribs[ attributesMap[ part ] ] = optionPart;
+ }
+
+ // Two special handling - image and email, protect them
+ // as "span" with an attribute marker.
+ if ( part == 'email' || part == 'img' )
+ attribs[ 'bbcode' ] = part;
+
+ this.onTagOpen( tagName, attribs, CKEDITOR.dtd.$empty[ tagName ] );
+ }
+ // Closing tag
+ else if ( parts[ 3 ] )
+ this.onTagClose( bbcodeMap[ part ] );
+ }
+
+ if ( bbcode.length > lastIndex )
+ this.onText( bbcode.substring( lastIndex, bbcode.length ), 1 );
+ }
+ };
+
+ /**
+ * Creates a {@link CKEDITOR.htmlParser.fragment} from an HTML string.
+ *
+ * var fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<b>Sample</b> Text' );
+ * alert( fragment.children[ 0 ].name ); // 'b'
+ * alert( fragment.children[ 1 ].value ); // ' Text'
+ *
+ * @static
+ * @member CKEDITOR.htmlParser.fragment
+ * @param {String} source The HTML to be parsed, filling the fragment.
+ * @returns {CKEDITOR.htmlParser.fragment} The fragment created.
+ */
+ CKEDITOR.htmlParser.fragment.fromBBCode = function( source ) {
+ var parser = new CKEDITOR.BBCodeParser(),
+ fragment = new CKEDITOR.htmlParser.fragment(),
+ pendingInline = [],
+ pendingBrs = 0,
+ currentNode = fragment,
+ returnPoint;
+
+ function checkPending( newTagName ) {
+ if ( pendingInline.length > 0 ) {
+ for ( var i = 0; i < pendingInline.length; i++ ) {
+ var pendingElement = pendingInline[ i ],
+ pendingName = pendingElement.name,
+ pendingDtd = CKEDITOR.dtd[ pendingName ],
+ currentDtd = currentNode.name && CKEDITOR.dtd[ currentNode.name ];
+
+ if ( ( !currentDtd || currentDtd[ pendingName ] ) && ( !newTagName || !pendingDtd || pendingDtd[ newTagName ] || !CKEDITOR.dtd[ newTagName ] ) ) {
+ // Get a clone for the pending element.
+ pendingElement = pendingElement.clone();
+
+ // Add it to the current node and make it the current,
+ // so the new element will be added inside of it.
+ pendingElement.parent = currentNode;
+ currentNode = pendingElement;
+
+ // Remove the pending element (back the index by one
+ // to properly process the next entry).
+ pendingInline.splice( i, 1 );
+ i--;
+ }
+ }
+ }
+ }
+
+ function checkPendingBrs( tagName, closing ) {
+ var len = currentNode.children.length,
+ previous = len > 0 && currentNode.children[ len - 1 ],
+ lineBreakParent = !previous && writer.getRule( tagnameMap[ currentNode.name ], 'breakAfterOpen' ),
+ lineBreakPrevious = previous && previous.type == CKEDITOR.NODE_ELEMENT && writer.getRule( tagnameMap[ previous.name ], 'breakAfterClose' ),
+ lineBreakCurrent = tagName && writer.getRule( tagnameMap[ tagName ], closing ? 'breakBeforeClose' : 'breakBeforeOpen' );
+
+ if ( pendingBrs && ( lineBreakParent || lineBreakPrevious || lineBreakCurrent ) )
+ pendingBrs--;
+
+ // 1. Either we're at the end of block, where it requires us to compensate the br filler
+ // removing logic (from htmldataprocessor).
+ // 2. Or we're at the end of pseudo block, where it requires us to compensate
+ // the bogus br effect.
+ if ( pendingBrs && tagName in blockLikeTags )
+ pendingBrs++;
+
+ while ( pendingBrs && pendingBrs-- )
+ currentNode.children.push( previous = new CKEDITOR.htmlParser.element( 'br' ) );
+ }
+
+ function addElement( node, target ) {
+ checkPendingBrs( node.name, 1 );
+
+ target = target || currentNode || fragment;
+
+ var len = target.children.length,
+ previous = len > 0 && target.children[ len - 1 ] || null;
+
+ node.previous = previous;
+ node.parent = target;
+
+ target.children.push( node );
+
+ if ( node.returnPoint ) {
+ currentNode = node.returnPoint;
+ delete node.returnPoint;
+ }
+ }
+
+ parser.onTagOpen = function( tagName, attributes, selfClosing ) {
+ var element = new CKEDITOR.htmlParser.element( tagName, attributes );
+
+ // This is a tag to be removed if empty, so do not add it immediately.
+ if ( CKEDITOR.dtd.$removeEmpty[ tagName ] ) {
+ pendingInline.push( element );
+ return;
+ }
+
+ var currentName = currentNode.name;
+
+ var currentDtd = currentName && ( CKEDITOR.dtd[ currentName ] || ( currentNode._.isBlockLike ? CKEDITOR.dtd.div : CKEDITOR.dtd.span ) );
+
+ // If the element cannot be child of the current element.
+ if ( currentDtd && !currentDtd[ tagName ] ) {
+ var reApply = false,
+ addPoint; // New position to start adding nodes.
+
+ // If the element name is the same as the current element name,
+ // then just close the current one and append the new one to the
+ // parent. This situation usually happens with <p>, <li>, <dt> and
+ // <dd>, specially in IE. Do not enter in this if block in this case.
+ if ( tagName == currentName )
+ addElement( currentNode, currentNode.parent );
+ else if ( tagName in CKEDITOR.dtd.$listItem ) {
+ parser.onTagOpen( 'ul', {} );
+ addPoint = currentNode;
+ reApply = true;
+ } else {
+ addElement( currentNode, currentNode.parent );
+
+ // The current element is an inline element, which
+ // cannot hold the new one. Put it in the pending list,
+ // and try adding the new one after it.
+ pendingInline.unshift( currentNode );
+ reApply = true;
+ }
+
+ if ( addPoint )
+ currentNode = addPoint;
+ // Try adding it to the return point, or the parent element.
+ else
+ currentNode = currentNode.returnPoint || currentNode.parent;
+
+ if ( reApply ) {
+ parser.onTagOpen.apply( this, arguments );
+ return;
+ }
+ }
+
+ checkPending( tagName );
+ checkPendingBrs( tagName );
+
+ element.parent = currentNode;
+ element.returnPoint = returnPoint;
+ returnPoint = 0;
+
+ if ( element.isEmpty )
+ addElement( element );
+ else
+ currentNode = element;
+ };
+
+ parser.onTagClose = function( tagName ) {
+ // Check if there is any pending tag to be closed.
+ for ( var i = pendingInline.length - 1; i >= 0; i-- ) {
+ // If found, just remove it from the list.
+ if ( tagName == pendingInline[ i ].name ) {
+ pendingInline.splice( i, 1 );
+ return;
+ }
+ }
+
+ var pendingAdd = [],
+ newPendingInline = [],
+ candidate = currentNode;
+
+ while ( candidate.type && candidate.name != tagName ) {
+ // If this is an inline element, add it to the pending list, if we're
+ // really closing one of the parents element later, they will continue
+ // after it.
+ if ( !candidate._.isBlockLike )
+ newPendingInline.unshift( candidate );
+
+ // This node should be added to it's parent at this point. But,
+ // it should happen only if the closing tag is really closing
+ // one of the nodes. So, for now, we just cache it.
+ pendingAdd.push( candidate );
+
+ candidate = candidate.parent;
+ }
+
+ if ( candidate.type ) {
+ // Add all elements that have been found in the above loop.
+ for ( i = 0; i < pendingAdd.length; i++ ) {
+ var node = pendingAdd[ i ];
+ addElement( node, node.parent );
+ }
+
+ currentNode = candidate;
+
+
+ addElement( candidate, candidate.parent );
+
+ // The parent should start receiving new nodes now, except if
+ // addElement changed the currentNode.
+ if ( candidate == currentNode )
+ currentNode = currentNode.parent;
+
+ pendingInline = pendingInline.concat( newPendingInline );
+ }
+ };
+
+ parser.onText = function( text ) {
+ var currentDtd = CKEDITOR.dtd[ currentNode.name ];
+ if ( !currentDtd || currentDtd[ '#' ] ) {
+ checkPendingBrs();
+ checkPending();
+
+ text.replace( /(\r\n|[\r\n])|[^\r\n]*/g, function( piece, lineBreak ) {
+ if ( lineBreak !== undefined && lineBreak.length )
+ pendingBrs++;
+ else if ( piece.length ) {
+ var lastIndex = 0;
+
+ // Create smiley from text emotion.
+ piece.replace( smileyRegExp, function( match, index ) {
+ addElement( new CKEDITOR.htmlParser.text( piece.substring( lastIndex, index ) ), currentNode );
+ addElement( new CKEDITOR.htmlParser.element( 'smiley', { desc: smileyReverseMap[ match ] } ), currentNode );
+ lastIndex = index + match.length;
+ });
+
+ if ( lastIndex != piece.length )
+ addElement( new CKEDITOR.htmlParser.text( piece.substring( lastIndex, piece.length ) ), currentNode );
+ }
+ });
+ }
+ };
+
+ // Parse it.
+ parser.parse( CKEDITOR.tools.htmlEncode( source ) );
+
+ // Close all hanging nodes.
+ while ( currentNode.type != CKEDITOR.NODE_DOCUMENT_FRAGMENT ) {
+ var parent = currentNode.parent,
+ node = currentNode;
+
+ addElement( node, parent );
+ currentNode = parent;
+ }
+
+ return fragment;
+ };
+
+ var BBCodeWriter = CKEDITOR.tools.createClass({
+ $: function() {
+ this._ = {
+ output: [],
+ rules: []
+ };
+
+ // List and list item.
+ this.setRules( 'list', { breakBeforeOpen:1,breakAfterOpen:1,breakBeforeClose:1,breakAfterClose:1 });
+
+ this.setRules( '*', {
+ breakBeforeOpen: 1,
+ breakAfterOpen: 0,
+ breakBeforeClose: 1,
+ breakAfterClose: 0
+ });
+
+ this.setRules( 'quote', {
+ breakBeforeOpen: 1,
+ breakAfterOpen: 0,
+ breakBeforeClose: 0,
+ breakAfterClose: 1
+ });
+ },
+
+ proto: {
+ //
+ // Sets formatting rules for a given tag. The possible rules are:
+ // <ul>
+ // <li><b>breakBeforeOpen</b>: break line before the opener tag for this element.</li>
+ // <li><b>breakAfterOpen</b>: break line after the opener tag for this element.</li>
+ // <li><b>breakBeforeClose</b>: break line before the closer tag for this element.</li>
+ // <li><b>breakAfterClose</b>: break line after the closer tag for this element.</li>
+ // </ul>
+ //
+ // All rules default to "false". Each call to the function overrides
+ // already present rules, leaving the undefined untouched.
+ //
+ // @param {String} tagName The tag name to which set the rules.
+ // @param {Object} rules An object containing the element rules.
+ // @example
+ // // Break line before and after "img" tags.
+ // writer.setRules( 'list',
+ // {
+ // breakBeforeOpen : true
+ // breakAfterOpen : true
+ // });
+ setRules: function( tagName, rules ) {
+ var currentRules = this._.rules[ tagName ];
+
+ if ( currentRules )
+ CKEDITOR.tools.extend( currentRules, rules, true );
+ else
+ this._.rules[ tagName ] = rules;
+ },
+
+ getRule: function( tagName, ruleName ) {
+ return this._.rules[ tagName ] && this._.rules[ tagName ][ ruleName ];
+ },
+
+ openTag : function( tag ) {
+ if ( tag in bbcodeMap ) {
+ if ( this.getRule( tag, 'breakBeforeOpen' ) )
+ this.lineBreak( 1 );
+
+ this.write( '[', tag );
+ }
+ },
+
+ openTagClose : function( tag ) {
+ if ( tag == 'br' )
+ this._.output.push( '\n' );
+ else if ( tag in bbcodeMap ) {
+ this.write( ']' );
+ if ( this.getRule( tag, 'breakAfterOpen' ) )
+ this.lineBreak( 1 );
+ }
+ },
+
+ attribute : function( name, val ) {
+ if ( name == 'option' ) {
+ // Force simply ampersand in attributes.
+ if ( typeof val == 'string' )
+ val = val.replace( /&/g, '&' );
+
+ this.write( '=', val );
+ }
+ },
+
+ closeTag: function( tag ) {
+ if ( tag in bbcodeMap ) {
+ if ( this.getRule( tag, 'breakBeforeClose' ) )
+ this.lineBreak( 1 );
+
+ tag != '*' && this.write( '[/', tag, ']' );
+
+ if ( this.getRule( tag, 'breakAfterClose' ) )
+ this.lineBreak( 1 );
+ }
+ },
+
+ text: function( text ) {
+ this.write( text );
+ },
+
+ comment: function() {},
+
+ // Output line-break for formatting.
+ lineBreak: function() {
+ // Avoid line break when:
+ // 1) Previous tag already put one.
+ // 2) We're at output start.
+ if ( !this._.hasLineBreak && this._.output.length ) {
+ this.write( '\n' );
+ this._.hasLineBreak = 1;
+ }
+ },
+
+ write: function() {
+ this._.hasLineBreak = 0;
+ var data = Array.prototype.join.call( arguments, '' );
+ this._.output.push( data );
+ },
+
+ reset: function() {
+ this._.output = [];
+ this._.hasLineBreak = 0;
+ },
+
+ getHtml: function( reset ) {
+ var bbcode = this._.output.join( '' );
+
+ if ( reset )
+ this.reset();
+
+ return decodeHtml( bbcode );
+ }
+ }
+ });
+
+ var writer = new BBCodeWriter();
+
+ CKEDITOR.plugins.add( 'bbcode', {
+ requires: 'entities',
+
+ beforeInit: function( editor ) {
+ // Adapt some critical editor configuration for better support
+ // of BBCode environment.
+ var config = editor.config;
+ CKEDITOR.tools.extend( config, {
+ enterMode: CKEDITOR.ENTER_BR,
+ basicEntities: false,
+ entities: false,
+ fillEmptyBlocks: false
+ }, true );
+
+ editor.filter.disable();
+ },
+
+ init: function( editor ) {
+ var config = editor.config;
+
+ function BBCodeToHtml( code ) {
+ var fragment = CKEDITOR.htmlParser.fragment.fromBBCode( code ),
+ writer = new CKEDITOR.htmlParser.basicWriter();
+
+ fragment.writeHtml( writer, bbcodeFilter );
+ return writer.getHtml( true );
+ }
+
+ var bbcodeFilter = new CKEDITOR.htmlParser.filter();
+ bbcodeFilter.addRules({
+ elements: {
+ blockquote: function( element ) {
+ var quoted = new CKEDITOR.htmlParser.element( 'div' );
+ quoted.children = element.children;
+ element.children = [ quoted ];
+ var citeText = element.attributes.cite;
+ if ( citeText ) {
+ var cite = new CKEDITOR.htmlParser.element( 'cite' );
+ cite.add( new CKEDITOR.htmlParser.text( citeText.replace( /^"|"$/g, '' ) ) );
+ delete element.attributes.cite;
+ element.children.unshift( cite );
+ }
+ },
+ span: function( element ) {
+ var bbcode;
+ if ( ( bbcode = element.attributes.bbcode ) ) {
+ if ( bbcode == 'img' ) {
+ element.name = 'img';
+ element.attributes.src = element.children[ 0 ].value;
+ element.children = [];
+ } else if ( bbcode == 'email' ) {
+ element.name = 'a';
+ element.attributes.href = 'mailto:' + element.children[ 0 ].value;
+ }
+
+ delete element.attributes.bbcode;
+ }
+ },
+ ol: function( element ) {
+ if ( element.attributes.listType ) {
+ if ( element.attributes.listType != 'decimal' )
+ element.attributes.style = 'list-style-type:' + element.attributes.listType;
+ } else
+ element.name = 'ul';
+
+ delete element.attributes.listType;
+ },
+ a: function( element ) {
+ if ( !element.attributes.href )
+ element.attributes.href = element.children[ 0 ].value;
+ },
+ smiley: function( element ) {
+ element.name = 'img';
+
+ var description = element.attributes.desc,
+ image = config.smiley_images[ CKEDITOR.tools.indexOf( config.smiley_descriptions, description ) ],
+ src = CKEDITOR.tools.htmlEncode( config.smiley_path + image );
+
+ element.attributes = {
+ src: src,
+ 'data-cke-saved-src': src,
+ title: description,
+ alt: description
+ };
+ }
+ }
+ });
+
+ editor.dataProcessor.htmlFilter.addRules({
+ elements: {
+ $: function( element ) {
+ var attributes = element.attributes,
+ style = CKEDITOR.tools.parseCssText( attributes.style, 1 ),
+ value;
+
+ var tagName = element.name;
+ if ( tagName in convertMap )
+ tagName = convertMap[ tagName ];
+ else if ( tagName == 'span' ) {
+ if ( ( value = style.color ) ) {
+ tagName = 'color';
+ value = CKEDITOR.tools.convertRgbToHex( value );
+ } else if ( ( value = style[ 'font-size' ] ) ) {
+ var percentValue = value.match( /(\d+)%$/ );
+ if ( percentValue ) {
+ value = percentValue[ 1 ];
+ tagName = 'size';
+ }
+ }
+ } else if ( tagName == 'ol' || tagName == 'ul' ) {
+ if ( ( value = style[ 'list-style-type' ] ) ) {
+ switch ( value ) {
+ case 'lower-alpha':
+ value = 'a';
+ break;
+ case 'upper-alpha':
+ value = 'A';
+ break;
+ }
+ } else if ( tagName == 'ol' )
+ value = 1;
+
+ tagName = 'list';
+ } else if ( tagName == 'blockquote' ) {
+ try {
+ var cite = element.children[ 0 ],
+ quoted = element.children[ 1 ],
+ citeText = cite.name == 'cite' && cite.children[ 0 ].value;
+
+ if ( citeText ) {
+ value = '"' + citeText + '"';
+ element.children = quoted.children;
+ }
+
+ } catch ( er ) {}
+
+ tagName = 'quote';
+ } else if ( tagName == 'a' ) {
+ if ( ( value = attributes.href ) ) {
+ if ( value.indexOf( 'mailto:' ) !== -1 ) {
+ tagName = 'email';
+ // [email] should have a single text child with email address.
+ element.children = [ new CKEDITOR.htmlParser.text( value.replace( 'mailto:', '' ) ) ];
+ value = '';
+ } else {
+ var singleton = element.children.length == 1 && element.children[ 0 ];
+ if ( singleton && singleton.type == CKEDITOR.NODE_TEXT && singleton.value == value )
+ value = '';
+
+ tagName = 'url';
+ }
+ }
+ } else if ( tagName == 'img' ) {
+ element.isEmpty = 0;
+
+ // Translate smiley (image) to text emotion.
+ var src = attributes[ 'data-cke-saved-src' ] || attributes.src,
+ alt = attributes.alt;
+
+ if ( src && src.indexOf( editor.config.smiley_path ) != -1 && alt )
+ return new CKEDITOR.htmlParser.text( smileyMap[ alt ] );
+ else
+ element.children = [ new CKEDITOR.htmlParser.text( src ) ];
+ }
+
+ element.name = tagName;
+ value && ( element.attributes.option = value );
+
+ return null;
+ },
+
+ // Remove any bogus br from the end of a pseudo block,
+ // e.g. <div>some text<br /><p>paragraph</p></div>
+ br: function( element ) {
+ var next = element.next;
+ if ( next && next.name in blockLikeTags )
+ return false;
+ }
+ }
+ }, 1 );
+
+ editor.dataProcessor.writer = writer;
+
+ function onSetData( evt ) {
+ var bbcode = evt.data.dataValue;
+ evt.data.dataValue = BBCodeToHtml( bbcode );
+ }
+
+ // Skip the first "setData" call from inline creator, to allow content of
+ // HTML to be loaded from the page element.
+ if ( editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE )
+ editor.once( 'contentDom', function() {
+ editor.on( 'setData', onSetData );
+ });
+ else
+ editor.on( 'setData', onSetData );
+
+ },
+
+ afterInit: function( editor ) {
+ var filters;
+ if ( editor._.elementsPath ) {
+ // Eliminate irrelevant elements from displaying, e.g body and p.
+ if ( ( filters = editor._.elementsPath.filters ) ) {
+ filters.push( function( element ) {
+ var htmlName = element.getName(),
+ name = tagnameMap[ htmlName ] || false;
+
+ // Specialized anchor presents as email.
+ if ( name == 'link' && element.getAttribute( 'href' ).indexOf( 'mailto:' ) === 0 )
+ name = 'email';
+ // Styled span could be either size or color.
+ else if ( htmlName == 'span' ) {
+ if ( element.getStyle( 'font-size' ) )
+ name = 'size';
+ else if ( element.getStyle( 'color' ) )
+ name = 'color';
+ } else if ( name == 'img' ) {
+ var src = element.data( 'cke-saved-src' ) || element.getAttribute( 'src' );
+ if ( src && src.indexOf( editor.config.smiley_path ) === 0 )
+ name = 'smiley';
+ }
+
+ return name;
+ });
+ }
+ }
+ }
+ });
+
+})();
--- /dev/null
+<!DOCTYPE html>
+<!--
+Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+-->
+<html>
+<head>
+ <title>BBCode Plugin — CKEditor Sample</title>
+ <meta charset="utf-8">
+ <script src="../../../ckeditor.js"></script>
+ <script src="../../../samples/sample.js"></script>
+ <link rel="stylesheet" href="../../../samples/sample.css">
+ <meta name="ckeditor-sample-required-plugins" content="sourcearea">
+ <meta name="ckeditor-sample-name" content="Output for BBCode">
+ <meta name="ckeditor-sample-group" content="Additional Plugins">
+ <meta name="ckeditor-sample-description" content="Configuring CKEditor to produce BBCode tags instead of HTML.">
+</head>
+<body>
+ <h1 class="samples">
+ <a href="../../../samples/index.html">CKEditor Samples</a> » BBCode Plugin
+ </h1>
+ <div class="description">
+ <p>
+ This sample shows how to configure CKEditor to output <a href="http://en.wikipedia.org/wiki/BBCode">BBCode</a> format instead of HTML.
+ Please note that the editor configuration was modified to reflect what is needed in a BBCode editing environment.
+ Smiley images, for example, were stripped to the emoticons that are commonly used in some BBCode dialects.
+ </p>
+ <p>
+ Please note that currently there is no standard for the BBCode markup language, so its implementation
+ for different platforms (message boards, blogs etc.) can vary. This means that before using CKEditor to
+ output BBCode you may need to adjust the implementation to your own environment.
+ </p>
+ <p>
+ A snippet of the configuration code can be seen below; check the source of this page for
+ a full definition:
+ </p>
+ <pre class="samples">
+CKEDITOR.replace( 'editor1', {
+ <strong>extraPlugins: 'bbcode',</strong>
+ toolbar: [
+ [ 'Source', '-', 'Save', 'NewPage', '-', 'Undo', 'Redo' ],
+ [ 'Find', 'Replace', '-', 'SelectAll', 'RemoveFormat' ],
+ [ 'Link', 'Unlink', 'Image' ],
+ '/',
+ [ 'FontSize', 'Bold', 'Italic', 'Underline' ],
+ [ 'NumberedList', 'BulletedList', '-', 'Blockquote' ],
+ [ 'TextColor', '-', 'Smiley', 'SpecialChar', '-', 'Maximize' ]
+ ],
+ ... <i>some other configurations omitted here</i>
+}); </pre>
+ </div>
+ <form action="../../../samples/sample_posteddata.php" method="post">
+ <p>
+ <label for="editor1">
+ Editor 1:
+ </label>
+ <textarea cols="80" id="editor1" name="editor1" rows="10">This is some [b]sample text[/b]. You are using [url=http://ckeditor.com/]CKEditor[/url].</textarea>
+ <script>
+
+ // Replace the <textarea id="editor"> with an CKEditor
+ // instance, using the "bbcode" plugin, shaping some of the
+ // editor configuration to fit BBCode environment.
+ CKEDITOR.replace( 'editor1', {
+ extraPlugins: 'bbcode',
+ // Remove unused plugins.
+ removePlugins: 'bidi,dialogadvtab,div,filebrowser,flash,format,forms,horizontalrule,iframe,justify,liststyle,pagebreak,showborders,stylescombo,table,tabletools,templates',
+ // Width and height are not supported in the BBCode format, so object resizing is disabled.
+ disableObjectResizing: true,
+ // Define font sizes in percent values.
+ fontSize_sizes: "30/30%;50/50%;100/100%;120/120%;150/150%;200/200%;300/300%",
+ toolbar: [
+ [ 'Source', '-', 'Save', 'NewPage', '-', 'Undo', 'Redo' ],
+ [ 'Find', 'Replace', '-', 'SelectAll', 'RemoveFormat' ],
+ [ 'Link', 'Unlink', 'Image', 'Smiley', 'SpecialChar' ],
+ '/',
+ [ 'Bold', 'Italic', 'Underline' ],
+ [ 'FontSize' ],
+ [ 'TextColor' ],
+ [ 'NumberedList', 'BulletedList', '-', 'Blockquote' ],
+ [ 'Maximize' ]
+ ],
+ // Strip CKEditor smileys to those commonly used in BBCode.
+ smiley_images: [
+ 'regular_smile.png', 'sad_smile.png', 'wink_smile.png', 'teeth_smile.png', 'tongue_smile.png',
+ 'embarrassed_smile.png', 'omg_smile.png', 'whatchutalkingabout_smile.png', 'angel_smile.png',
+ 'shades_smile.png', 'cry_smile.png', 'kiss.png'
+ ],
+ smiley_descriptions: [
+ 'smiley', 'sad', 'wink', 'laugh', 'cheeky', 'blush', 'surprise',
+ 'indecision', 'angel', 'cool', 'crying', 'kiss'
+ ]
+ });
+
+ </script>
+ </p>
+ <p>
+ <input type="submit" value="Submit">
+ </p>
+ </form>
+ <div id="footer">
+ <hr>
+ <p>
+ CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a>
+ </p>
+ <p id="copy">
+ Copyright © 2003-2013, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico
+ Knabben. All rights reserved.
+ </p>
+ </div>
+</body>
+</html>
--- /dev/null
+/**
+ * Magic3 CKEditorプラグイン
+ *
+ * JavaScript 1.5
+ *
+ * LICENSE: This source file is licensed under the terms of the GNU General Public License.
+ *
+ * @package Magic3 Framework
+ * @author 平田直毅(Naoki Hirata) <naoki@aplo.co.jp>
+ * @copyright Copyright 2006-2013 Magic3 Project.
+ * @license http://www.gnu.org/copyleft/gpl.html GPL License
+ * @version SVN: $Id: googlemaps.js 6026 2013-05-20 04:55:58Z fishbone $
+ * @link http://www.magic3.org
+ */
+var GoogleMapsHandler = {
+ maps: {}, // マップ情報
+
+ // マップ情報取得
+ getMap: function(id){
+ return this.maps[id];
+ },
+
+ // マップ情報検出
+ detectMapScript: function(script)
+ {
+ if (!(/Magic3 googlemaps v1\.(\d+)/.test(script))) return false;
+
+ return true
+ },
+
+ // This can be called from the dialog
+ createNew: function()
+ {
+ var map = new GoogleMap();
+ this.maps[map.number] = map;
+ return map;
+ },
+};
+
+// Our object that will handle parsing of the script and creating the new one.
+var GoogleMap = function()
+{
+ var now = new Date();
+ this.number = '' + now.getFullYear() + now.getMonth() + now.getDate() + now.getHours() + now.getMinutes() + now.getSeconds();
+
+ this.width = CKEDITOR.config.googlemaps_width || 400;
+ this.height = CKEDITOR.config.googlemaps_height || 240;
+
+ this.centerLat = CKEDITOR.config.googlemaps_centerLat || 35.594757;
+ this.centerLon = CKEDITOR.config.googlemaps_centerLon || 139.620739;
+ this.zoom = CKEDITOR.config.googlemaps_zoom || 11;
+
+ this.markerPoints = [];
+
+ this.linePoints = '';
+ this.lineLevels = '';
+
+ this.mapType = 0;
+
+// this.WrapperClass = CKEDITOR.config.googlemaps_wrapperClass || '';
+}
+
+GoogleMap.prototype.generateStaticMap = function()
+{
+ var w = Math.min(this.width, 640);
+ var h = Math.min(this.height, 640);
+ var staticMapTypes = ['roadmap', 'satellite', 'hybrid', 'terrain'];
+
+ var mapUrl = 'http://maps.google.com/maps/api/staticmap?center=' + this.centerLat + ',' + this.centerLon
+ + '&zoom=' + this.zoom + '&size=' + w + 'x' + h
+ + '&maptype=' + staticMapTypes[ this.mapType ]
+ + this.generateStaticMarkers() + '&sensor=false';
+ return mapUrl;
+}
+
+GoogleMap.prototype.generateStaticMarkers = function()
+{
+ if (this.markerPoints.length == 0) return '';
+ var aPoints = [];
+ for (var i = 0; i < this.markerPoints.length; i++)
+ {
+ var point = this.markerPoints[i];
+ aPoints.push(point.lat + ',' + point.lon);
+ }
+ return ('&markers=' + aPoints.join('|'));
+}
+// Read the dimensions back from the fake node (the user might have manually resized it)
+GoogleMap.prototype.updateDimensions = function( oFakeNode )
+{
+ var iWidth, iHeight;
+ var regexSize = /^\s*(\d+)px\s*$/i;
+
+ if (oFakeNode.style.width)
+ {
+ var aMatchW = oFakeNode.style.width.match(regexSize);
+ if (aMatchW)
+ {
+ iWidth = aMatchW[1];
+ oFakeNode.style.width = '';
+ oFakeNode.width = iWidth;
+ }
+ }
+
+ if (oFakeNode.style.height)
+ {
+ var aMatchH = oFakeNode.style.height.match(regexSize);
+ if (aMatchH)
+ {
+ iHeight = aMatchH[1];
+ oFakeNode.style.height = '';
+ oFakeNode.height = iHeight;
+ }
+ }
+
+ this.width = iWidth ? iWidth : oFakeNode.width;
+ this.height = iHeight ? iHeight : oFakeNode.height;
+}
+GoogleMap.prototype.setDimensions = function(width, height)
+{
+ this.width = width;
+ this.height = height;
+}
+GoogleMap.prototype.decodeText = function(string)
+{
+ return string.replace(/<\\\//g, "</").replace(/\\n/g, "\n").replace(/\\'/g, "'").replace(/\\\\/g, "\\");
+}
+GoogleMap.prototype.encodeText = function(string)
+{
+ return string.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/<\//g, "<\\/");
+}
+
+GoogleMap.prototype.parse = function( script )
+{
+ // We only know about version 1:
+ if (!(/Magic3 googlemaps v1\.(\d+) mapid:(\d+)/.test(script))) return false;
+
+// var version = parseInt(RegExp.$1, 10);
+ delete GoogleMapsHandler.maps[this.number];
+ this.number = RegExp.$2;
+ GoogleMapsHandler.maps[this.number] = this;
+
+ // マップ高さ、幅を取得
+ var regexpDimensions = /<div id="gmap(\d+)" style="width\:\s*(\d+)px; height\:\s*(\d+)px;">/;
+ if (regexpDimensions.test( script ) )
+ {
+ this.width = RegExp.$2;
+ this.height = RegExp.$3;
+ }
+
+ // マップ位置座標を取得
+// map.setCenter(new GLatLng(42.4298,-8.07756), 8);
+ var regexpPosition = /map\.setCenter\(new google\.maps\.LatLng\((-?\d{1,3}\.\d{1,6}), (-?\d{1,3}\.\d{1,6})\)\);/;
+ if (regexpPosition.test(script))
+ {
+ this.centerLat = RegExp.$1;
+ this.centerLon = RegExp.$2;
+ }
+
+ // マップズームレベルを取得
+ var regexpPosition = /map\.setZoom\((\d{1,2})\);/;
+ if (regexpPosition.test(script))
+ {
+ this.zoom = RegExp.$1;
+ }
+
+ // AddMarkers( [{lat:37.45088, lon:-122.21123, text:'Write your text'}] );
+ var regexpMarkers = /\{lat\:(-?\d{1,3}\.\d{1,6}),\s*lon\:(-?\d{1,3}\.\d{1,6}),\s*text\:("|')(.*)\3}(?:,|])/;
+ var point;
+ var sampleText = script;
+ var startIndex = 0;
+ var totalLength = sampleText.length;
+ var result, pos;
+ while (startIndex != totalLength) {
+ result = regexpMarkers.exec(sampleText);
+ if (result && result.length > 0) {
+ pos = sampleText.indexOf(result[0]);
+ startIndex += pos;
+
+ this.markerPoints.push( {lat:result[1], lon:result[2], text:this.decodeText(result[4])} );
+
+ sampleText = sampleText.substr(pos + result[0].length);
+ startIndex += result[0].length;
+ } else {
+ break;
+ }
+ }
+// var encodedPoints = "iuowFf{kbMzH}N`IbJb@zBpYzO{dAvfF{LwDyN`_@`NzKqB|Ec@|L}BKmBbCoPjrBeEdy@uJ`Mn@zoAer@bjA~Xz{JczBa]pIps@de@tW}rCdxSwhPl`XgikCl{soA{dLdAaaF~cCyxCk_Aao@jp@kEvnCgoJ`]y[pVguKhCkUflAwrEzKk@yzCv^k@?mI";
+ var regexpLinePoints = /var encodedPoints\s*=\s*("|')(.*)\1;\s*\n/;
+ if (regexpLinePoints.test(script))
+ {
+ this.linePoints = RegExp.$2;
+ }
+
+// var encodedLevels = "B????????????????????????????????????B";
+ var regexpLineLevels = /var encodedLevels\s*=\s*("|')(.*)\1;\s*\n/;
+ if (regexpLineLevels.test(script))
+ {
+ this.lineLevels = RegExp.$2;
+ }
+
+// 1.8 mapType
+// map.setMapType( allMapTypes[ 1 ] );
+ //var regexpMapType = /setMapType\([^\[]*\[\s*(\d+)\s*\]\s*\)/;
+ var regexpMapType = /setMapTypeId\([^\[]*\[\s*(\d+)\s*\]\s*\)/;
+ if (regexpMapType.test(script))
+ {
+ this.mapType = RegExp.$1;
+ }
+
+/* var regexpWrapper = /<div class=("|')(.*)\1.*\/\/wrapper/;
+ if (regexpWrapper.test(script)){
+ this.WrapperClass = RegExp.$2;
+ } else {
+ this.WrapperClass = '';
+ }
+*/
+ return true;
+}
+
+GoogleMap.prototype.buildScript = function()
+{
+ var versionMarker = '// Magic3 googlemaps v1.00 mapid:' + this.number;
+
+ var aScript = [];
+ aScript.push('<script type="text/javascript">');
+ aScript.push('//<![CDATA[');
+ aScript.push(versionMarker);
+
+// if (this.WrapperClass !== '') aScript.push('document.write(\'<div class="' + this.WrapperClass + '">\'); //wrapper');
+// aScript.push('document.write(\'<div id="gmap' + this.number + '" style="width:' + this.width + 'px; height:' + this.height + 'px;display:none;">.<\\\/div>\');');
+// if (this.WrapperClass !== '') aScript.push('document.write(\'<\\\/div>\'); ');
+
+ aScript.push('$(function(){');
+ aScript.push(' var allMapTypes = [ google.maps.MapTypeId.ROADMAP,');
+ aScript.push(' google.maps.MapTypeId.SATELLITE,');
+ aScript.push(' google.maps.MapTypeId.HYBRID,');
+ aScript.push(' google.maps.MapTypeId.TERRAIN ];');
+ aScript.push(' var opts = { mapTypeControlOptions: { mapTypeIds: allMapTypes } };');
+ aScript.push(' var mapDiv = document.getElementById("gmap' + this.number + '");');
+ aScript.push(' var map = new google.maps.Map(mapDiv, opts);');
+ //aScript.push(' var mapDiv = $("#gmap' + this.number + '");');
+ //aScript.push(' var map = new google.maps.Map(mapDiv.get(0), opts);');
+ aScript.push(' map.setMapTypeId(allMapTypes[' + this.mapType + ']);');
+ aScript.push(' map.setCenter(new google.maps.LatLng(' + this.centerLat + ', ' + this.centerLon + '));');
+ aScript.push(' map.setZoom(' + this.zoom + ');');
+ aScript.push(' mapDiv.style.display = "";');
+ //aScript.push(' mapDiv.show();');
+
+ var aPoints = [];
+ for (var i = 0; i < this.markerPoints.length; i++)
+ {
+ var point = this.markerPoints[i];
+ aPoints.push('{lat:' + point.lat + ', lon:' + point.lon + ', text:\'' + this.encodeText(point.text) + '\'}');
+ }
+ aScript.push(' m3GooglemapsAddMarkers(map, [' + aPoints.join(',\r\n') + ']);');
+
+ if ((this.linePoints && this.linePoints != '') && (this.lineLevels && this.lineLevels != ''))
+ {
+ aScript.push(' var encodedPoints = "' + this.linePoints + '";');
+ aScript.push(' var encodedLevels = "' + this.lineLevels + '";');
+ aScript.push(' var polylinePoints = m3GooglemapsDecodePolyline(encodedPoints)');
+ aScript.push(' var encodedPolyline = new google.maps.Polyline({ strokeColor:"#3333cc",');
+ aScript.push(' strokeWeight:5,');
+ aScript.push(' path:polylinePoints });');
+ aScript.push(' encodedPolyline.setMap(map);');
+ }
+ aScript.push('});');
+ aScript.push('//]]>');
+ aScript.push('</script>');
+
+ return aScript.join('\r\n');
+}
+Number.prototype.RoundTo = function(precission)
+{
+ var base = Math.pow(10, precission);
+ return Math.round(this * base) / base;
+};
--- /dev/null
+/**
+ * Magic3 CKEditorプラグイン
+ *
+ * JavaScript 1.5
+ *
+ * LICENSE: This source file is licensed under the terms of the GNU General Public License.
+ *
+ * @package Magic3 Framework
+ * @author 平田直毅(Naoki Hirata) <naoki@aplo.co.jp>
+ * @copyright Copyright 2006-2013 Magic3 Project.
+ * @license http://www.gnu.org/copyleft/gpl.html GPL License
+ * @version SVN: $Id: main.js 6030 2013-05-22 00:48:33Z fishbone $
+ * @link http://www.magic3.org
+ */
+
+(function(){
+ CKEDITOR.dialog.add('googlemaps', function(editor){
+ var dialog;
+ var mode;
+ var mapDiv;
+ var mapInfo;
+ var mapObj;
+ var markers = [];
+ var activeMarker;
+ var fieldZoom;
+ var fieldCenterLatitude;
+ var fieldCenterLongitude;
+ var fakeImage;
+ var infoWindow;
+ var polyline;
+
+ // スクリプト読み込み
+// var path = CKEDITOR.plugins.getPath('googlemaps');
+// CKEDITOR.scriptLoader.load(CKEDITOR.getUrl(path) + 'dialogs/polyline.js');
+ var pluginUrl = CKEDITOR.getUrl(CKEDITOR.plugins.getPath( 'googlemaps' ));
+
+ var loadSelectionData = function()
+ {
+ if (fakeImage){ // マップ選択からの起動の場合
+ var className = fakeImage.$.className;
+ var mapNumber;
+ var regExp = /cke_googlemaps(\d+)/;
+ if (regExp.test(className)) mapNumber = RegExp.$1;
+ mapInfo = GoogleMapsHandler.getMap(mapNumber);
+ if (!mapInfo) mapInfo = GoogleMapsHandler.createNew();
+ } else { // マップが選択されていない場合は新規作成
+ mapInfo = GoogleMapsHandler.createNew();
+ }
+
+ // 入力値初期化
+ dialog.setValueOf('tab_map', 'txtWidth', mapInfo.width);
+ dialog.setValueOf('tab_map', 'txtHeight', mapInfo.height);
+ dialog.setValueOf('tab_map', 'cmbZoom', mapInfo.zoom);
+ dialog.setValueOf('tab_map', 'txtCenterLat', mapInfo.centerLat);
+ dialog.setValueOf('tab_map', 'txtCenterLon', mapInfo.centerLon);
+// dialog.setValueOf('tab_line', 'txtEncodedPolyline', mapInfo.linePoints);
+// dialog.setValueOf('tab_line', 'txtEncodedLevels', mapInfo.lineLevels);
+
+ // マップ作成
+ setPreviewElement(mapInfo.mapType);
+
+ // マーカー設定
+ var markerPoints = mapInfo.markerPoints;
+ for (var i = 0; i < markerPoints.length; i++)
+ {
+ var point = new google.maps.LatLng(parseFloat(markerPoints[i].lat), parseFloat(markerPoints[i].lon));
+ addMarkerAtPoint(point, markerPoints[i].text, false);
+ }
+
+ // ライン描画
+ polyline.setMap(mapObj);
+ polyline.decodePolyline(mapInfo.linePoints);
+ };
+ var setPreviewElement = function(mapType)
+ {
+ mapDiv = document.getElementById("gmapPreview" + editor.id);
+ resizeMap();
+
+ var allMapTypes = [ google.maps.MapTypeId.ROADMAP,
+ google.maps.MapTypeId.SATELLITE,
+ google.maps.MapTypeId.HYBRID,
+ google.maps.MapTypeId.TERRAIN ];
+ var opts = { mapTypeId:allMapTypes[mapType],
+ mapTypeControlOptions:{ mapTypeIds:allMapTypes } };
+ mapObj = new google.maps.Map(mapDiv, opts);
+
+ updatePreview();
+
+ // イベント設定
+ google.maps.event.addListener(mapObj, 'zoom_changed', function(){
+ fieldZoom.value = mapObj.getZoom();
+ });
+ google.maps.event.addListener(mapObj, 'center_changed', function(){ // out of memory on IE8
+ var point = mapObj.getCenter();
+ fieldCenterLatitude.value = point.lat().RoundTo(5);
+ fieldCenterLongitude.value = point.lng().RoundTo(5);
+ });
+ google.maps.event.addListener(mapObj, 'click', function(e){
+ var point = e.latLng;
+ var selectedTab = CKEDITOR.dialog.getCurrent().definition.dialog._.currentTabId; // 選択中のタブIDを取得
+ switch (selectedTab){
+ case 'tab_map':
+ case 'tab_search':
+ break;
+ case 'tab_marker':
+ if (mode == 'AddMarker') addMarkerAtPoint(point, editor.lang.googlemaps.markerDefaultText || '', true);
+ break;
+ case 'tab_line':
+ polyline.createPoint(point.lat(), point.lng(), 3);
+ polyline.createEncodings(false);
+ break;
+ }
+ //mapDiv.focus();
+ });
+ google.maps.event.addDomListener(mapDiv, 'keydown', function(e){
+ if (!e) e = window.event;
+
+ var iCode = (e.keyCode || e.charCode);
+ var selectedTab = CKEDITOR.dialog.getCurrent().definition.dialog._.currentTabId; // 選択中のタブIDを取得
+ if (iCode == 46){
+ switch(selectedTab){
+ case 'tab_map':
+ case 'tab_search':
+ case 'tab_marker':
+ break;
+ case 'tab_line':
+ polyline.deletePoint();
+ break;
+ }
+ }
+ });
+ };
+ var resizeMap = function()
+ {
+ if (!mapDiv) return;
+
+ mapDiv.style.width = dialog.getValueOf('tab_map', 'txtWidth') + 'px';
+ mapDiv.style.height = dialog.getValueOf('tab_map', 'txtHeight') + 'px';
+
+ //ResizeParent();
+ };
+ var updatePreview = function()
+ {
+ if (!mapObj) return;
+
+ mapObj.setCenter(new google.maps.LatLng(fieldCenterLatitude.value, fieldCenterLongitude.value));
+ mapObj.setZoom(parseInt(fieldZoom.value, 10));
+ };
+ var doSearch = function()
+ {
+ var address = dialog.getValueOf('tab_search', 'txtAddress');
+ var geocoder = new google.maps.Geocoder();
+
+ function processPoint(point)
+ {
+ if (point){
+ dialog.setValueOf('tab_map', 'txtCenterLat', point.lat().RoundTo(5));
+ dialog.setValueOf('tab_map', 'txtCenterLon', point.lng().RoundTo(5));
+
+ // 検索位置にマーカーを設定
+ addMarkerAtPoint(point, address);
+
+ updatePreview();
+ } else {
+ alert(editor.lang.googlemaps.msgNotFound.replace("%s", address));
+ }
+ }
+
+ geocoder.geocode({ 'address':address }, function(results, status){
+ if (status == google.maps.GeocoderStatus.OK){
+ processPoint(results[0].geometry.location);
+ } else {
+ alert(editor.lang.googlemaps.msgNotFound.replace("%s", address));
+ }
+ });
+ };
+ var addMarker = function()
+ {
+ if (mode == 'AddMarker'){
+ finishAddMarker();
+ return;
+ }
+ $('#btnAddNewMarker' + editor.id).attr('src', pluginUrl + 'images/AddMarkerDown.png');
+ $('#msgMarkerInstruction' + editor.id).text(editor.lang.googlemaps.msgMarkerInstruction2);
+ mode = 'AddMarker';
+ mapObj.setOptions({ draggableCursor:'crosshair' });
+ }
+ var addMarkerAtPoint = function(point, text, interactive)
+ {
+ var marker = createMarker(point, text);
+ marker.setMap(mapObj);
+ markers.push(marker);
+ finishAddMarker();
+
+ if (interactive) editMarker(marker);
+ };
+ var createMarker = function(point, html)
+ {
+ var marker = new google.maps.Marker({ position:point, title:html, draggable:true });
+ google.maps.event.addListener(marker, "click", function(){
+ editMarker(this);
+ });
+ return marker;
+ }
+ var finishAddMarker = function()
+ {
+ mode = '';
+
+ $('#btnAddNewMarker' + editor.id).attr('src', pluginUrl + 'images/AddMarker.png');
+ $('#msgMarkerInstruction' + editor.id).text(editor.lang.googlemaps.msgMarkerInstruction1);
+ mapObj.setOptions({ draggableCursor:'default' });
+ };
+ var editMarker = function(marker)
+ {
+ var selectedTab = CKEDITOR.dialog.getCurrent().definition.dialog._.currentTabId; // 選択中のタブIDを取得
+ if (selectedTab == 'tab_marker'){ // マーカーコンテンツを編集
+ activeMarker = marker;
+ mode = 'EditMarker';
+
+ if (infoWindow) infoWindow.close();
+ infoWindow = new google.maps.InfoWindow({ content:generateEditPopupString(marker.getTitle()) });
+ google.maps.event.addListener(infoWindow, 'domready', function(){ // 吹き出しの入力画面のイベントを設定
+ $("#btnOk").click(function (){
+ updateCurrentMarker();
+ });
+ $("#btnCancel").click(function (){
+ closeInfoWindow();
+ });
+ $("#btnDeleteMarker").click(function (){
+ deleteCurrentMarker();
+ });
+ });
+ infoWindow.open(mapObj, marker);
+ } else {
+ if (infoWindow) infoWindow.close();
+ infoWindow = new google.maps.InfoWindow({ content:marker.getTitle() });
+ infoWindow.open(mapObj, marker);
+ }
+ };
+ var closeInfoWindow = function()
+ {
+ mode = '';
+
+ if (infoWindow) infoWindow.close();
+ infoWindow = null;
+ activeMarker = null;
+ };
+ var updateCurrentMarker = function ()
+ {
+ if (activeMarker) activeMarker.setTitle($('#txtMarkerText' + editor.id).val().replace(/\n/g, '<br>'));
+ closeInfoWindow();
+ };
+ var deleteCurrentMarker = function()
+ {
+ for (var j = 0; j < markers.length; j++){
+ if (markers[j] == activeMarker){
+ markers.splice(j, 1);
+ break;
+ }
+ }
+ var tmp = activeMarker;
+ closeInfoWindow();
+
+ tmp.setMap(null);
+ };
+ var generateEditPopupString = function(text)
+ {
+ return '<div><label for="txtMarkerText' + editor.id + '">' + editor.lang.googlemaps.markerText + '</label></div>' +
+ '<div><textarea id="txtMarkerText' + editor.id + '" class="cke_dialog_ui_input_textarea" style="width:300px; height:120px;">' + text.replace(/<br>/g, '\n') + '</textarea></div>' +
+ '<div class="cke_dialog_footer_buttons"><div style="width:50%;display:inline-block;float:left;"><div class="cke_dialog_ui_hbox_child" style="display:inline-block;"><a id="btnDeleteMarker" class="cke_dialog_ui_button"><span class="cke_dialog_ui_button">' + editor.lang.googlemaps.deleteMarker + '</span></a></div></div>' +
+ '<div style="width:40%;display:inline-block;float:right;"><div class="cke_dialog_ui_hbox_first" style="display:inline-block;"><a id="btnOk" class="cke_dialog_ui_button cke_dialog_ui_button_ok"><span class="cke_dialog_ui_button">' + editor.lang.common.ok + '</span></a></div><div class="cke_dialog_ui_hbox_last" style="display:inline-block;">' +
+ '<a id="btnCancel" class="cke_dialog_ui_button cke_dialog_ui_button_cancel"><span class="cke_dialog_ui_button">' + editor.lang.common.cancel + '</span></a></div></div></div>';
+ };
+ var commitValue = function(data){
+ var id = this.id;
+ if ( !data.info ) data.info = {};
+ data.info[id] = this.getValue();
+ };
+ return {
+ title: editor.lang.googlemaps.title,
+ minWidth: 420,
+ minHeight: 310,
+ onLoad: function(){ // 初期処理
+ dialog = this; // 参照取得
+
+ // ダイアログ画面作成
+ // ダイアログサイズの設定
+// var width = dialog.getSize().width;
+// var height = dialog.getSize().height;
+// dialog.resize(width, height);
+
+ // マップの位置を修正
+/* var off = $('#placeholder_map').position();
+ $('#placeholder_search').css({position:'absolute', top:off.top + 'px',left:off.left + 'px'});
+ $('#placeholder_marker').css({position:'absolute', top:off.top + 'px',left:off.left + 'px'});
+ $('#placeholder_line').css({position:'absolute', top:off.top + 'px',left:off.left + 'px'});
+ */
+ // タブが変更された場合はマップを移動
+ dialog.on('selectPage', function(e){
+ switch (e.data.page){
+ case 'tab_map':
+ $('#gmapPreview' + editor.id).appendTo('#placeholder_map' + editor.id);
+ break;
+ case 'tab_search':
+ $('#gmapPreview' + editor.id).appendTo('#placeholder_search' + editor.id);
+ break;
+ case 'tab_marker':
+ $('#gmapPreview' + editor.id).appendTo('#placeholder_marker' + editor.id);
+ break;
+ case 'tab_line':
+ $('#gmapPreview' + editor.id).appendTo('#placeholder_line' + editor.id);
+ break;
+ }
+
+ if (e.data.page == 'tab_line'){
+ polyline.showLinePoints();
+ } else {
+ polyline.hideLinePoints();
+ }
+
+ if (e.data.page != 'tab_marker') finishAddMarker();
+ });
+ // イベント登録
+ $('#btnAddNewMarker' + editor.id).click(function(){
+ addMarker();
+ }).attr({ title:editor.lang.googlemaps.addMarker, alt:editor.lang.googlemaps.addMarker });
+ },
+ /* onFocus: function() {
+ mapDiv.focus();
+ },*/
+ onShow: function(){
+ // マップ初期化
+ markers = [];
+ polyline = new Polyline();
+
+ // 選択されているマップの情報を取り込む
+ var selectedElement = this.getSelectedElement();
+ if (selectedElement){
+ fakeImage = selectedElement;
+ var realElement = editor.restoreRealElement(selectedElement);
+ } else {
+ fakeImage = null;
+ }
+ loadSelectionData();
+ },
+ onOk: function(){
+ // A container for our field data
+ var data = {};
+
+ // 入力データの確定
+ this.commitContent(data);
+
+ // マップ情報更新
+ mapInfo.width = data.info['txtWidth'];
+ mapInfo.height = data.info['txtHeight'];
+ mapInfo.zoom = data.info['cmbZoom'];
+ mapInfo.centerLat = data.info['txtCenterLat'];
+ mapInfo.centerLon = data.info['txtCenterLon'];
+ var markerPoints = [];
+ for (var i=0; i < markers.length; i++){
+ var point = markers[i].getPosition();
+ markerPoints.push({ lat:point.lat().RoundTo(5), lon:point.lng().RoundTo(5), text:markers[i].getTitle() });
+ }
+ mapInfo.markerPoints = markerPoints;
+
+ // マップ埋め込みタグの作成
+ mapInfo.linePoints = polyline.encodedPolyline;
+ mapInfo.lineLevels = polyline.encodedLevels;
+ var script = mapInfo.buildScript();
+// var scriptElement = CKEDITOR.dom.element.createFromHtml(script, editor.document);
+// var newMapElement = CKEDITOR.dom.element.createFromHtml('<div></div>', editor.document);
+// newMapElement.append(scriptElement);
+ var newMapElement = CKEDITOR.dom.element.createFromHtml('<div>' + script + '</div>', editor.document); // IE8 not work.
+ var style = 'width:' + mapInfo.width + 'px;height:' + mapInfo.height + 'px;display:none;';
+ newMapElement.setAttributes({
+ 'id': 'gmap' + mapInfo.number,
+ 'style': style,
+ 'class': 'm3googlemaps'
+ });
+
+ // ビュー更新前、画像のみ変更
+ var extraStyles = { 'background-image': 'url(' + mapInfo.generateStaticMap() + ')',
+ 'background-position': 'center center',
+ 'background-repeat': 'no-repeat',
+ 'border': '0px',
+ 'width': mapInfo.width + 'px',
+ 'height': mapInfo.height + 'px'
+ };
+ var newFakeImage = editor.createFakeElement(newMapElement, 'cke_googlemaps' + mapInfo.number, 'div', false);
+ newFakeImage.setStyles( extraStyles );
+
+ if (fakeImage){ // マップ更新の場合
+ newFakeImage.replace( fakeImage );
+ editor.getSelection().selectElement( newFakeImage );
+ } else {
+ editor.insertElement( newFakeImage );
+ }
+ },
+ onCancel: function(){
+ fakeImage = null;
+ },
+ contents: [{
+ id: 'tab_map',
+ label: editor.lang.googlemaps.mapTitle,
+ elements :[
+ {
+ // 項目を横に配置
+ type: 'hbox',
+ widths: [ '10%', '20%' ], // 項目間幅を調整
+ /* padding: '5px',*/
+ children: [
+ {
+ type : 'text',
+ id : 'txtWidth',
+ label: editor.lang.googlemaps.width,
+ width: '40px',
+ 'default': 400,
+ validate : function() {
+ var pass = true,
+ value = this.getValue();
+ pass = pass && CKEDITOR.dialog.validate.integer()( value ) && value > 0;
+ if ( !pass ){
+ alert( "Invalid Width" );
+ this.select();
+ }
+ return pass;
+ },
+ onChange: function(){
+ resizeMap();
+ },
+ commit: commitValue
+ }, {
+ type : 'text',
+ id : 'txtHeight',
+ label: editor.lang.googlemaps.height,
+ width: '40px',
+ 'default': 240,
+ validate : function() {
+ var pass = true,
+ value = this.getValue();
+ pass = pass && CKEDITOR.dialog.validate.integer()( value ) && value > 0;
+ if ( !pass ){
+ alert( "Invalid Height" );
+ this.select();
+ }
+ return pass;
+ },
+ onChange: function(){
+ resizeMap();
+ },
+ commit: commitValue
+ }, {
+ type: 'select',
+ id: 'cmbZoom',
+ label: editor.lang.googlemaps.zoomLevel,
+ style: 'width:50px',
+ 'default': '',
+ items: [
+ [ '0', '0' ],
+ [ '1', '1' ],
+ [ '2', '2' ],
+ [ '3', '3' ],
+ [ '4', '4' ],
+ [ '5', '5' ],
+ [ '6', '6' ],
+ [ '7', '7' ],
+ [ '8', '8' ],
+ [ '9', '9' ],
+ [ '10', '10' ],
+ [ '11', '11' ],
+ [ '12', '12' ],
+ [ '13', '13' ],
+ [ '14', '14' ],
+ [ '15', '15' ],
+ [ '16', '16' ],
+ [ '17', '17' ]
+ ],
+ onLoad: function(){
+ fieldZoom = document.getElementById(this.getInputElement().$.id); // 参照を取得
+ },
+ onChange: function() {
+ if (mapObj) mapObj.setZoom(parseInt(this.getValue()), 10);
+ },
+ commit: commitValue
+ } ]
+ }, {
+ type: 'hbox',
+ widths: [ '50%', '50%' ],
+ children: [
+ {
+ type: 'text',
+ id: 'txtCenterLat',
+ // requiredContent: 'img(cke-xyz)', // Random text like 'xyz' will check if all are allowed.
+ label: editor.lang.googlemaps.latitude,
+ 'default': '',
+ onLoad: function(){
+ fieldCenterLatitude = document.getElementById(this.getInputElement().$.id); // 参照を取得
+ },
+ onChange: function() {
+ if (mapObj) mapObj.setCenter(new google.maps.LatLng(this.getValue(), fieldCenterLongitude.value));
+ },
+ commit: commitValue
+ }, {
+ type: 'text',
+ id: 'txtCenterLon',
+ //requiredContent: 'img[title]',
+ label: editor.lang.googlemaps.longitude,
+ 'default': '',
+ onLoad: function(){
+ fieldCenterLongitude = document.getElementById(this.getInputElement().$.id); // 参照を取得
+ },
+ onChange: function() {
+ if (mapObj) mapObj.setCenter(new google.maps.LatLng(fieldCenterLatitude.value, this.getValue()));
+ },
+ commit: commitValue
+ } ]
+ }, {
+ type: 'html',
+ html: '<div id="placeholder_map' + editor.id + '"><div id="gmapPreview' + editor.id + '" style="outline:0;" tabIndex="-1"></div></div>'
+ } ] // elements
+ }, {
+ id: 'tab_search',
+ label: editor.lang.googlemaps.searchTitle,
+ elements: [
+ {
+ type: 'hbox',
+ widths: [ '5%', '5%' ],
+ children: [
+ {
+ type: 'text',
+ id: 'txtAddress',
+ label: editor.lang.googlemaps.searchLabel,
+ width: '300px',
+ labelLayout: 'horizontal'
+ /*onLoad: function(){
+ fieldAddress = $('#' + this.getInputElement().$.id); // 参照を取得
+ }*/
+ }, {
+ type: 'button',
+ id: 'btnSearch',
+ align: 'left',
+ //style: 'width:50px',
+ label: editor.lang.googlemaps.search,
+ onClick: function(){
+ doSearch();
+ }
+ } ]
+ }, {
+ type: 'html',
+ html: '<div id="placeholder_search' + editor.id + '"></div>'
+ } ]
+ }, {
+ id: 'tab_marker',
+ label: editor.lang.googlemaps.markerTitle,
+ elements: [
+ {
+ type: 'html',
+html: '<img id="btnAddNewMarker' + editor.id + '" src="' + pluginUrl + 'images/AddMarker.png" style="cursor:pointer;" /><div id="msgMarkerInstruction' + editor.id + '" style="display:inline-block;">' + editor.lang.googlemaps.msgMarkerInstruction1 + '</div>'
+ }, {
+ type: 'html',
+ html: '<div id="placeholder_marker' + editor.id + '"></div>'
+ } ]
+ }, {
+ id: 'tab_line',
+ label: editor.lang.googlemaps.lineTitle,
+ elements: [
+ {
+ type: 'html',
+ html: '<p>' + editor.lang.googlemaps.msgLineInstruction + '</p>'
+ }, {
+ type: 'html',
+ html: '<div id="placeholder_line' + editor.id + '"></div>'
+ } ]
+ } ]
+ };
+ });
+})();
--- /dev/null
+/**
+ * Magic3 CKEditorプラグイン
+ *
+ * JavaScript 1.5
+ *
+ * LICENSE: This source file is licensed under the terms of the GNU General Public License.
+ *
+ * @package Magic3 Framework
+ * @author 平田直毅(Naoki Hirata) <naoki@aplo.co.jp>
+ * @copyright Copyright 2006-2013 Magic3 Project.
+ * @license http://www.gnu.org/copyleft/gpl.html GPL License
+ * @version SVN: $Id: polyline.js 6021 2013-05-20 04:21:13Z fishbone $
+ * @link http://www.magic3.org
+ */
+function Polyline()
+{
+ this.map;
+ this.points = [];
+ this.highlighted_marker = null;
+ this.point_markers = [];
+ this.currentIndex = -1;
+ this.encodedLevels = '';
+ this.encodedPolyline = '';
+}
+Polyline.prototype.setMap = function(map)
+{
+ this.map = map;
+}
+Polyline.prototype.findMarkerIndex = function(point_marker)
+{
+ var index = -1;
+
+ for (var i = 0; i < this.point_markers.length; ++i){
+ if (this.point_markers[i] == point_marker){
+ index = i;
+ break;
+ }
+ }
+ return index;
+}
+
+Polyline.prototype.createPoint = function(lat, lng, pLevel)
+{
+ var newPoint = { lat: lat,
+ lon: lng,
+ Level: pLevel };
+
+ if (this.currentIndex > -1){
+ this.points.splice(this.currentIndex + 1, 0, newPoint);
+ } else {
+ this.points.push(newPoint);
+ }
+
+ //var point_marker = this.createPointMarker(new GLatLng(lat, lng), false);
+ var point_marker = this.createPointMarker(new google.maps.LatLng(lat, lng), false);
+ point_marker.focusable = true; // To signal that the map must get the focus.
+
+ //map.addOverlay(point_marker);
+ point_marker.setMap(this.map);
+
+ if (this.currentIndex > -1){
+ this.point_markers.splice(this.currentIndex + 1, 0, point_marker);
+ } else {
+ this.point_markers.push(point_marker);
+ }
+
+ this.highlight(this.currentIndex + 1);
+}
+
+Polyline.prototype.createPointMarker = function(point, highlighted)
+{
+ var clr = highlighted ? "yellow" : "blue";
+ var point_marker = this.createColorMarker(point, clr);
+
+ //GEvent.addListener(point_marker, "drag", function(){
+ google.maps.event.addListener(point_marker, 'drag', function(){
+ var index = this.findMarkerIndex(point_marker);
+
+ if (index >= 0){
+// var nLat = point_marker.getPoint().lat();
+// var nLng = point_marker.getPoint().lng();
+ var nLat = point_marker.getPosition().lat();
+ var nLng = point_marker.getPosition().lng();
+ var pLevel = this.points[index].Level;
+
+ var modifiedPoint = { lat: nLat,
+ lon: nLng,
+ Level: pLevel };
+
+ this.points[index] = modifiedPoint;
+ this.createEncodings();
+ }
+ });
+/* GEvent.addListener(point_marker, "click", function() {
+ highlight(this.findMarkerIndex(point_marker));
+ });*/
+ google.maps.event.addListener(point_marker, "click", function(){
+ this.highlight(this.findMarkerIndex(point_marker));
+ });
+ return point_marker;
+}
+
+Polyline.prototype.highlight = function(index)
+{
+ if (this.point_markers[index] != null && this.point_markers[index] != this.highlighted_marker){
+ //map.removeOverlay(this.point_markers[index]);
+ this.point_markers[index].setMap(null);
+ }
+
+ if (this.highlighted_marker != null){
+ var oldIndex = this.findMarkerIndex(this.highlighted_marker);
+ //map.removeOverlay(this.highlighted_marker);
+ this.highlighted_marker.setMap(null);
+
+ if (oldIndex != index){
+ //this.point_markers[oldIndex] = this.createPointMarker(this.highlighted_marker.getPoint(), false);
+ //map.addOverlay(this.point_markers[oldIndex]);
+ this.point_markers[oldIndex] = this.createPointMarker(this.highlighted_marker.getPosition(), false);
+ this.point_markers[oldIndex].setMap(this.map);
+ }
+ }
+
+ //this.highlighted_marker = this.createPointMarker(this.point_markers[index].getPoint(), true);
+ this.highlighted_marker = this.createPointMarker(this.point_markers[index].getPosition(), true);
+ this.point_markers[index] = this.highlighted_marker;
+ //map.addOverlay(this.highlighted_marker);
+ this.highlighted_marker.setMap(this.map);
+
+ this.currentIndex = index ;
+}
+
+Polyline.prototype.encodeSignedNumber = function(num)
+{
+ var sgn_num = num << 1;
+
+ if (num < 0) sgn_num = ~(sgn_num);
+
+ return (this.encodeNumber(sgn_num));
+}
+
+Polyline.prototype.encodeNumber = function(num)
+{
+ var encodeString = "";
+
+ while (num >= 0x20) {
+ encodeString += (String.fromCharCode((0x20 | (num & 0x1f)) + 63));
+ num >>= 5;
+ }
+
+ encodeString += (String.fromCharCode(num + 63));
+ return encodeString;
+}
+
+Polyline.prototype.deletePoint = function()
+{
+ if (this.points.length > 0){
+ var point_index = this.currentIndex;
+
+ if (point_index >= 0 && point_index < this.points.length){
+ this.points.splice(point_index, 1);
+
+ if (this.highlighted_marker == this.point_markers[point_index]){
+ this.highlighted_marker = null;
+ this.currentIndex=-1;
+ }
+
+ //map.removeOverlay(this.point_markers[point_index]);
+ this.point_markers[point_index].setMap(null);
+ this.point_markers.splice(point_index, 1);
+ this.createEncodings();
+ }
+
+ if (this.points.length > 0){
+ if (point_index == 0) point_index++;
+
+ this.highlight(point_index - 1);
+ }
+ }
+}
+Polyline.prototype.createEncodings = function()
+{
+ if (this.points.length == 0)
+ {
+// document.getElementById('this.encodedLevels').value = '';
+// document.getElementById('encodedPolyline').value = '';
+ this.encodedLevels = '';
+ this.encodedPolyline = '';
+ if (document.overlay){
+ //map.removeOverlay(document.overlay);
+ document.overlay.setMap(null);
+ }
+ return;
+ }
+
+ var encoded_levels='';
+ var encoded_points='';
+ var vZoom, vLevels;
+
+ vLevels = 4;
+ vZoom = 32;
+
+ var plat = 0;
+ var plng = 0;
+ var pathCoordinates = [];
+ for (var i = 0; i < this.points.length; ++i){
+ var point = this.points[i];
+ var lat = point.lat;
+ var lng = point.lon;
+ var level = point.Level;
+
+ var late5 = Math.floor(lat * 1e5);
+ var lnge5 = Math.floor(lng * 1e5);
+
+ dlat = late5 - plat;
+ dlng = lnge5 - plng;
+
+ plat = late5;
+ plng = lnge5;
+
+ encoded_points += this.encodeSignedNumber(dlat) + this.encodeSignedNumber(dlng);
+ encoded_levels += this.encodeNumber(level);
+
+ pathCoordinates.push(new google.maps.LatLng(lat, lng));
+ }
+
+// document.getElementById('encodedLevels').value = encoded_levels.replace(/\\/g, "\\\\");
+// document.getElementById('encodedPolyline').value = encoded_points.replace(/\\/g, "\\\\");
+ this.encodedLevels = encoded_levels.replace(/\\/g, "\\\\");
+ this.encodedPolyline = encoded_points.replace(/\\/g, "\\\\");
+
+ if (document.overlay){
+ //map.removeOverlay(document.overlay);
+ document.overlay.setMap(null);
+ }
+
+ if (this.points.length > 1){
+ /*
+ document.overlay = GPolyline.fromEncoded({ color: "#3333cc",
+ weight: 5,
+ points: encoded_points,
+ zoomFactor: vZoom,
+ levels: encoded_levels,
+ numLevels: vLevels });*/
+ document.overlay = new google.maps.Polyline({ strokeColor:'#3333cc',
+ strokeWeight:5,
+ path:pathCoordinates });
+
+ //map.addOverlay(document.overlay);
+ document.overlay.setMap(this.map);
+ }
+}
+Polyline.prototype.decodeLine = function(encoded)
+{
+ var len = encoded.length;
+ var index = 0;
+ var array = [];
+ var lat = 0;
+ var lng = 0;
+
+ while (index < len){
+ var b;
+ var shift = 0;
+ var result = 0;
+ do {
+ b = encoded.charCodeAt(index++) - 63;
+ result |= (b & 0x1f) << shift;
+ shift += 5;
+ } while (b >= 0x20);
+ var dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
+ lat += dlat;
+
+ shift = 0;
+ result = 0;
+ do {
+ b = encoded.charCodeAt(index++) - 63;
+ result |= (b & 0x1f) << shift;
+ shift += 5;
+ } while (b >= 0x20);
+ var dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
+ lng += dlng;
+
+ array.push([lat * 1e-5, lng * 1e-5]);
+ }
+
+ return array;
+}
+
+Polyline.prototype.decodeLevels = function(encoded)
+{
+ var levels = [];
+
+ for (var pointIndex = 0; pointIndex < encoded.length; ++pointIndex){
+ var pointLevel = encoded.charCodeAt(pointIndex) - 63;
+ levels.push(pointLevel);
+ }
+
+ return levels;
+}
+
+Polyline.prototype.decodePolyline = function(encoded_points)
+{
+ encoded_points = encoded_points.replace(/\\\\/g, "\\");
+ if (encoded_points.length == 0) return;
+
+ var enc_points = this.decodeLine(encoded_points);
+ if (enc_points.length == 0) return;
+
+ this.points = [];
+ for (var i = 0; i < enc_points.length; ++i){
+ this.createPoint(enc_points[i][0], enc_points[i][1], 3);
+ }
+ this.createEncodings();
+}
+
+Polyline.prototype.showLinePoints = function()
+{
+ if (this.points.length == 0) return;
+
+ for (var i = 0; i < this.points.length; i++)
+ {
+ var point = this.points[i] ;
+ //var point_marker = this.createPointMarker(new GLatLng(point.lat, point.lon), false);
+ var point_marker = this.createPointMarker(new google.maps.LatLng(point.lat, point.lon), false);
+ //map.addOverlay(point_marker);
+ point_marker.setMap(this.map);
+
+ this.point_markers.push(point_marker);
+ }
+
+ this.highlight(this.points.length - 1);
+}
+
+Polyline.prototype.hideLinePoints = function()
+{
+ for (var i = this.point_markers.length -1; i >= 0; i--)
+ {
+ //map.removeOverlay(this.point_markers[i]);
+ this.point_markers[i].setMap(null);
+ }
+ this.point_markers = [] ;
+ this.highlighted_marker = null;
+ this.currentIndex=-1;
+}
+
+Polyline.prototype.createColorMarker = function(point, color)
+{
+ var pluginUrl = CKEDITOR.getUrl(CKEDITOR.plugins.getPath( 'googlemaps' ));
+ var markerImage = new google.maps.MarkerImage( pluginUrl + 'images/mm_20_' + color + '.png',
+ new google.maps.Size(12, 20), // size
+ new google.maps.Point(0,0), // origin
+ new google.maps.Point(6, 20)); // anchor
+ var shadowImage = new google.maps.MarkerImage( pluginUrl + 'images/mm_20_shadow.png',
+ new google.maps.Size(22, 20), // size
+ new google.maps.Point(0,0), // origin
+ new google.maps.Point(6, 20)); // anchor
+ var newMarker = new google.maps.Marker({ position:point, icon:markerImage, shadow:shadowImage, draggable:true });
+ return newMarker;
+}
--- /dev/null
+/**
+ * Magic3 CKEditorプラグイン
+ *
+ * JavaScript 1.5
+ *
+ * LICENSE: This source file is licensed under the terms of the GNU General Public License.
+ *
+ * @package Magic3 Framework
+ * @author 平田直毅(Naoki Hirata) <naoki@aplo.co.jp>
+ * @copyright Copyright 2006-2013 Magic3 Project.
+ * @license http://www.gnu.org/copyleft/gpl.html GPL License
+ * @version SVN: $Id: en.js 5979 2013-05-10 09:20:24Z fishbone $
+ * @link http://www.magic3.org
+ */
+CKEDITOR.plugins.setLang( 'googlemaps', 'en', {
+ toolbar: 'Google Maps',
+ title: 'Google Maps',
+ mapTitle: 'Map',
+ searchTitle: 'Search',
+ markerTitle: 'Marker',
+ lineTitle: 'Line',
+ width: 'Width',
+ height: 'Height',
+ zoomLevel: 'Zoom Level',
+ msgDefaultMarkerText: 'Input text.'
+});
--- /dev/null
+/**
+ * Magic3 CKEditorプラグイン
+ *
+ * JavaScript 1.5
+ *
+ * LICENSE: This source file is licensed under the terms of the GNU General Public License.
+ *
+ * @package Magic3 Framework
+ * @author 平田直毅(Naoki Hirata) <naoki@aplo.co.jp>
+ * @copyright Copyright 2006-2013 Magic3 Project.
+ * @license http://www.gnu.org/copyleft/gpl.html GPL License
+ * @version SVN: $Id: ja.js 6030 2013-05-22 00:48:33Z fishbone $
+ * @link http://www.magic3.org
+ */
+CKEDITOR.plugins.setLang( 'googlemaps', 'ja', {
+ toolbar: 'Googleマップ',
+ title: 'Googleマップ',
+ mapTitle: 'マップ',
+ searchTitle: '検索',
+ markerTitle: 'マーカー',
+ lineTitle: 'ライン',
+ width: '幅',
+ height: '高さ',
+ zoomLevel: 'ズームレベル',
+ latitude: '緯度',
+ longitude: '経度',
+ search:'検索',
+ searchLabel:'住所検索',
+ msgNotFound: '%s が見つかりません',
+ markerText: 'テキスト',
+ markerDefaultText: 'テキストを入力してください',
+ marker: 'マーカー',
+ deleteMarker: 'マーカーを削除',
+ addMarker: 'マーカーを追加',
+ msgMarkerInstruction1: 'アイコンをクリックしてください。',
+ msgMarkerInstruction2: '地図をクリックして、新しいマーカーを追加してください。',
+ line: 'ライン',
+ msgLineInstruction: 'クリックするとポイントが追加されます。<br />ポイントはドラッグすることもDELキーで削除することもできます。'
+});
--- /dev/null
+/**
+ * Magic3 CKEditorプラグイン
+ *
+ * JavaScript 1.5
+ *
+ * LICENSE: This source file is licensed under the terms of the GNU General Public License.
+ *
+ * @package Magic3 Framework
+ * @author 平田直毅(Naoki Hirata) <naoki@aplo.co.jp>
+ * @copyright Copyright 2006-2013 Magic3 Project.
+ * @license http://www.gnu.org/copyleft/gpl.html GPL License
+ * @version SVN: $Id: plugin.js 6003 2013-05-16 07:33:07Z fishbone $
+ * @link http://www.magic3.org
+ */
+(function() {
+ // デフォルト値
+ CKEDITOR.config.googlemaps_width = 500; // マップデ幅
+ CKEDITOR.config.googlemaps_height = 300; // マップ高さ
+// CKEDITOR.config.googlemaps_centerLat = 35.594757; // マップ緯度
+// CKEDITOR.config.googlemaps_centerLon = 139.620739; // マップ経度
+// CKEDITOR.config.googlemaps_zoom = 11; // ズームレベル
+
+ var path = CKEDITOR.plugins.getPath('googlemaps');
+ //CKEDITOR.scriptLoader.load(CKEDITOR.getUrl(CKEDITOR.plugins.getPath('googlemaps')) + 'dialogs/googlemaps.js');
+ CKEDITOR.scriptLoader.load(CKEDITOR.getUrl(path) + 'dialogs/googlemaps.js');
+ CKEDITOR.scriptLoader.load(CKEDITOR.getUrl(path) + 'dialogs/polyline.js');
+
+/* function createFakeElement(editor, realElement) {
+ var fakeElement = editor.createFakeParserElement(realElement, 'cke_script', 'script', false);
+ return fakeElement;
+ }*/
+
+ CKEDITOR.plugins.add( 'googlemaps', {
+ lang: 'en,ja',
+ icons: 'googlemaps',
+
+ init: function(editor){
+ // ダイアログ登録
+ editor.addCommand('googlemaps', new CKEDITOR.dialogCommand('googlemaps'));
+ CKEDITOR.dialog.add('googlemaps', this.path + 'dialogs/main.js');
+
+ // ツールバーボタン登録
+ if (editor.ui.addButton){
+ editor.ui.addButton('Googlemaps', {
+ label: editor.lang.googlemaps.toolbar,
+ command: 'googlemaps',
+ toolbar: 'others'
+ });
+ }
+
+ // オブジェクトダブルクリック時にダイアログを開く
+ editor.on( 'doubleclick', function( evt ) {
+ var element = evt.data.element;
+ var className = element.$.className;
+ if (element.is('img') && element.data('cke-real-element-type') == 'div' && className.lastIndexOf('cke_googlemaps', 0) == 0) evt.data.dialog = 'googlemaps';
+ });
+ },
+ // 初期起動時、ソースモード切替時に呼び出し
+ afterInit: function(editor){
+ // SCRIPTタグのGoogleマップ情報読み込み
+ var div = document.createElement('div');
+ div.innerHTML = editor.getData();
+ var scripts = div.getElementsByTagName('script');
+ for (var i = 0; i < scripts.length; i++) {
+ var content = scripts[i].outerHTML;
+ if (GoogleMapsHandler.detectMapScript(content)){ // マップ情報の場合は保存
+ var mapInfo = GoogleMapsHandler.createNew();
+ mapInfo.parse(content);
+ }
+ }
+/* var jScripts = $(editor.getData()).filter("script");
+ jScripts.each(function(index){
+ var content = $(this).get(0).outerHTML;
+ if (GoogleMapsHandler.detectMapScript(content)){ // マップ情報の場合は保存
+ var mapInfo = GoogleMapsHandler.createNew();
+ mapInfo.parse(content);
+ }
+ });*/
+
+ var dataProcessor = editor.dataProcessor;
+ var dataFilter = dataProcessor && dataProcessor.dataFilter;
+ if (dataFilter) {
+ dataFilter.addRules({
+ elements: {
+ div: function(element){
+ // Googleマップの埋め込みタグの場合は固定マップ画像を設定
+ var objectId = element.attributes.id;
+ var className = element.attributes['class'];
+ if (className == 'm3googlemaps'){
+ // マップ情報取得
+ var mapNumber;
+ var regExp = /gmap(\d+)/;
+ if (regExp.test(objectId)) mapNumber = RegExp.$1;
+ var mapInfo = GoogleMapsHandler.getMap(mapNumber);
+ if (mapInfo){
+ // 幅、高さを設定
+ var width, height;
+ var style = element.attributes.style;
+ if ((/width:\s*(\d+)px/i).test(style)) width = RegExp.$1;
+ if ((/height:\s*(\d+)px/i).test(style)) height = RegExp.$1;
+ if (!width || !height){
+ width = CKEDITOR.config.googlemaps_width;
+ height = CKEDITOR.config.googlemaps_height;
+ }
+ mapInfo.setDimensions(width, height);
+
+ // 画像を背景に配置しリサイズ不可にする
+ CKEDITOR.addCss(
+ 'img.cke_googlemaps' + mapNumber +
+ '{' +
+ 'background-image: url(' + mapInfo.generateStaticMap() + ');' +
+ 'background-position: center center;' +
+ 'background-repeat: no-repeat;' +
+ 'border: 0px;' +
+ 'width: ' + width + 'px;' +
+ 'height: ' + height + 'px;' +
+ '}'
+ );
+ var fakeImage = editor.createFakeParserElement(element, 'cke_googlemaps' + mapNumber, 'div', false/*リサイズ不可*/);
+ return fakeImage;
+ } else { // マップ情報が見つからない場合はダミーの画像を表示
+ // 画像を背景に配置しリサイズ不可にする
+ CKEDITOR.addCss(
+ 'img.cke_googlemaps' + mapNumber +
+ '{' +
+ 'background-image: url(' + CKEDITOR.getUrl(CKEDITOR.plugins.getPath('googlemaps')) + 'images/maps_res_logo.png' + ');' +
+ 'background-position: center center;' +
+ 'background-repeat: no-repeat;' +
+ 'border: 1px solid #a9a9a9;' +
+ 'width: ' + CKEDITOR.config.googlemaps_width + 'px;' +
+ 'height: ' + CKEDITOR.config.googlemaps_height + 'px;' +
+ '}'
+ );
+ var fakeImage = editor.createFakeParserElement(element, 'cke_googlemaps' + mapNumber, 'div', false/*リサイズ不可*/);
+ return fakeImage;
+ }
+ }
+ return null;
+ }
+ }
+ }, 5);
+ }
+ }
+ });
+})();
--- /dev/null
+■Magic3追加プラグイン
+
+・linkinfo - リンク先情報取得
+ Magic3用のリンク先情報を取得するためのプラグイン
+・youtube - YouTube
+ YouTube動画埋め込みプラグイン
+・googlemaps - Googleマップ
+ Googleマップ埋め込みプラグイン
+
+・bbcode - BBCode処理 v4.3.0
+ CKEditorオプション
\ No newline at end of file
--- /dev/null
+/**
+ * Magic3 CKEditorプラグイン
+ *
+ * JavaScript 1.5
+ *
+ * LICENSE: This source file is licensed under the terms of the GNU General Public License.
+ *
+ * @package Magic3 Framework
+ * @author 平田直毅(Naoki Hirata) <naoki@aplo.co.jp>
+ * @copyright Copyright 2006-2013 Magic3 Project.
+ * @license http://www.gnu.org/copyleft/gpl.html GPL License
+ * @version SVN: $Id$
+ * @link http://www.magic3.org
+ */
+CKEDITOR.dialog.add('linkinfoDialog', function(editor){
+ var accessPoint = ''; // アクセスポイント
+ var dialog; // このダイアログへの参照
+
+ // コンテンツリスト、コンテンツ内容表示を更新
+ function updateContentList()
+ {
+ // コンテンツリストを取得
+ var elementId = '#' + dialog.getContentElement('tab_basic', 'content_list').getInputElement().$.id;
+ var contentType = dialog.getContentElement('tab_basic', 'content_type').getValue();
+ var pageNo = 1;
+
+ // コンテンツプレビュークリア
+ dialog.getContentElement('tab_basic', 'url').setValue('');
+ $('#content_text').text('');
+
+ // Ajaxでページ情報を取得
+ m3_ajax_request('', 'task=linkinfo&act=getcontentlist&contenttype=' + contentType + '&accesspoint=' + accessPoint + '&page=' + pageNo, function(request, retcode, jsondata){ // 正常終了
+ // コンテンツ種別選択メニューを更新
+ $('option', elementId).remove();
+ if (jsondata.contentlist){
+ $.each(jsondata.contentlist, function(index, item) {
+ $(elementId).get(0).options[$(elementId).get(0).options.length] = new Option(item[1], item[0]);
+ });
+ }
+ }, function(request){ // 異常終了
+ alert('通信に失敗しました。');
+ });
+ }
+ // コンテンツタイプを取得
+ function updateContentType()
+ {
+ var elementId = '#' + dialog.getContentElement('tab_basic', 'content_type').getInputElement().$.id;
+
+ // Ajaxでコンテンツタイプを取得
+ m3_ajax_request('', 'task=linkinfo&act=getcontenttype&accesspoint=' + accessPoint, function(request, retcode, jsondata){ // 正常終了
+ // コンテンツ種別選択メニューを更新
+ $('option', elementId).remove();
+ if (jsondata.contenttype){
+ $.each(jsondata.contenttype, function(index, item) {
+ $(elementId).get(0).options[$(elementId).get(0).options.length] = new Option(item[1], item[0]);
+ });
+ }
+
+ // デフォルトのコンテンツリストを取得
+ updateContentList();
+ }, function(request){ // 異常終了
+ alert('通信に失敗しました。');
+ });
+ }
+ // ページリストを取得
+ function updatePageList()
+ {
+ var elementId = '#' + dialog.getContentElement('tab_basic', 'page_list').getInputElement().$.id;
+
+ // Ajaxでページ情報を取得
+ m3_ajax_request('', 'task=linkinfo&act=getpage&accesspoint=' + accessPoint, function(request, retcode, jsondata){ // 正常終了
+ // ページ選択メニューを更新
+ $('option', elementId).remove();
+ if (jsondata.pagelist){
+ $.each(jsondata.pagelist, function(index, item) {
+ $(elementId).get(0).options[$(elementId).get(0).options.length] = new Option(item[1], item[0]);
+ });
+ }
+ }, function(request){ // 異常終了
+ alert('通信に失敗しました。');
+ });
+ }
+ // ダイアログ上の項目の表示制御
+ function updateItems()
+ {
+ // リンク対象を取得
+ var selValue = dialog.getValueOf('tab_basic', 'link_target');
+
+ switch (selValue){
+ case 'content':
+ dialog.getContentElement('tab_basic', 'content_type').getElement().show();
+ dialog.getContentElement('tab_basic', 'content_list').getElement().show();
+ dialog.getContentElement('tab_basic', 'page_list').getElement().hide();
+ dialog.getContentElement('tab_basic', 'content_label').getElement().show();
+ $('#content_text').show();
+ break;
+ case 'page':
+ dialog.getContentElement('tab_basic', 'content_type').getElement().hide();
+ dialog.getContentElement('tab_basic', 'content_list').getElement().hide();
+ dialog.getContentElement('tab_basic', 'page_list').getElement().show();
+ dialog.getContentElement('tab_basic', 'content_label').getElement().hide();
+ $('#content_text').hide();
+ break;
+ case 'others':
+ dialog.getContentElement('tab_basic', 'content_type').getElement().hide();
+ dialog.getContentElement('tab_basic', 'content_list').getElement().hide();
+ dialog.getContentElement('tab_basic', 'page_list').getElement().hide();
+ dialog.getContentElement('tab_basic', 'content_label').getElement().hide();
+ $('#content_text').hide();
+ break;
+ }
+ }
+ // URLを更新。必要項目が選択されていない場合はクリア。
+ function updateUrl()
+ {
+ var url = M3_ROOT_URL;
+ if (accessPoint != '') url += '/' + accessPoint;
+ url += '/index.php';
+
+ // リンク対象を取得
+ var linkTarget = dialog.getValueOf('tab_basic', 'link_target');
+ switch (linkTarget){
+ case 'content':
+ var contentType = dialog.getContentElement('tab_basic', 'content_type').getValue();
+ var contentId = dialog.getContentElement('tab_basic', 'content_list').getValue();
+
+ if (contentId){
+ switch (contentType){
+ case 'content':
+ case 'product':
+ case 'event':
+ case 'photo':
+ url += '?' + contentType + 'id=' + contentId;
+ break;
+ case 'blog':
+ url += '?entryid=' + contentId;
+ break;
+ case 'wiki':
+ url += '?' + encodeURIComponent(contentId);
+ break;
+ }
+ } else {
+ url = '';
+ }
+ break;
+ case 'page':
+ var pageSubId = dialog.getContentElement('tab_basic', 'page_list').getValue();
+ switch (pageSubId){
+ case '':
+ url = '';
+ break;
+ case '_root':
+ url = M3_ROOT_URL;
+ if (accessPoint != '') url += '/' + accessPoint;
+ url += '/';
+ break;
+ default:
+ url += '?sub=' + pageSubId;
+ break;
+ }
+ break;
+ case 'others':
+ url = '';
+ break;
+ }
+ dialog.getContentElement('tab_basic', 'url').setValue(url);
+ }
+ return {
+ title: editor.lang.linkinfo.title,
+ minWidth: 500,
+ minHeight: 300,
+
+ onLoad: function(){
+ // 設定変更時の確認ダイアログを非表示にする
+ this.on('cancel', function(cancelEvent){ return false; }, this, null, -1);
+
+ // このダイアログへの参照を取得
+ dialog = this;
+
+ // ダイアログ項目の表示制御
+ updateItems();
+
+ // 起動時の初期値を設定
+ accessPoint = _m3AccessPoint; // アクセスポイント
+ dialog.getContentElement('tab_basic', 'url').setValue(_m3Url);
+ },
+ onShow : function(){ // 再表示時イベント
+ // ダイアログ項目の表示制御
+ updateItems();
+
+ // 起動時の初期値を設定
+ $('#content_text').text('');// コンテンツプレビュークリア
+ accessPoint = _m3AccessPoint; // アクセスポイント
+ dialog.getContentElement('tab_basic', 'url').setValue(_m3Url);
+
+ // フレーム内にある場合は表示位置を調整
+ if (window.parent != window.self){
+ this.move(this.getPosition().x, 0);
+ }
+ },
+ contents: [
+ {
+ id: 'tab_basic',
+ label: editor.lang.linkinfo.tab_info_title,
+ elements: [
+ { // リンク対象選択
+ type : 'radio',
+ id : 'link_target',
+ label : editor.lang.linkinfo.link_target_title,
+ items : [
+ [ 'コンテンツ', 'content' ], [ 'ページ', 'page' ], [ 'その他', 'others' ]
+ ],
+ 'default': 'content',
+ onClick: function(){
+ // ダイアログ項目の表示制御
+ updateItems();
+
+ // URLを更新
+ updateUrl();
+ }
+ },
+ { // コンテンツ種別選択
+ type : 'select',
+ id : 'content_type',
+ label : editor.lang.linkinfo.content_type_title,
+ items : [
+ [ '接続中', '' ]
+ ],
+ onShow : function(){ // 選択値変更時イベント
+ // コンテンツタイプ更新
+ updateContentType();
+ },
+ onChange : function(){ // 選択値変更時イベント
+ // コンテンツリストを更新
+ updateContentList();
+ }
+ },
+ { // コンテンツリスト
+ type : 'select',
+ id : 'content_list',
+ label : editor.lang.linkinfo.content_list_title,
+ items : [
+ [ '接続中', '' ]
+ ],
+ onChange : function(){ // 選択値変更時イベント
+ // コンテンツプレビュークリア
+ $('#content_text').text('');
+
+ // コンテンツ内容を取得
+ var contentType = dialog.getContentElement('tab_basic', 'content_type').getValue();
+ var contentId = dialog.getContentElement('tab_basic', 'content_list').getValue();
+
+ // Ajaxでコンテンツ内容を取得
+ m3_ajax_request('', 'task=linkinfo&act=getcontent&contenttype=' + contentType + '&contentid=' + contentId + '&accesspoint=' + accessPoint, function(request, retcode, jsondata){ // 正常終了
+
+ if (jsondata.content){
+ $('#content_text').text(jsondata.content);
+ $('#content2_image').hide();
+ $('#content2_text').hide();
+ }
+
+ // URLを更新
+ updateUrl();
+ }, function(request){ // 異常終了
+ alert('通信に失敗しました。');
+ });
+ }
+ },
+ {
+ type : 'select',
+ id : 'page_list',
+ label : editor.lang.linkinfo.page_list_title,
+ items : [
+ [ '接続中', '' ]
+ ],
+ //onLoad : function(){ // 起動時イベント
+ onShow : function(){ // 再表示イベント
+ // ページリスト更新
+ updatePageList();
+ },
+ onChange : function(){ // 選択値変更時イベント
+ // URLを更新
+ updateUrl();
+ }
+ },
+ {
+ type : 'html',
+ id: 'content_label',
+ html : '<label>コンテンツ内容:</label>'
+ },
+ {
+ type: 'html',
+ html: '<p id="content_text" style="white-space: -moz-pre-wrap; white-space: pre-wrap; word-wrap: break-word;"></p>'
+ },
+ {
+ type: 'hbox',
+ widths: [ '20%', '80%' ],
+ children: [
+ {
+ type: 'html',
+ html: '<p id="content2_image"></p>'
+ },{
+ type: 'html',
+ html: '<p id="content2_text" style="white-space: -moz-pre-wrap; white-space: pre-wrap; word-wrap: break-word;"></p>'
+ } ]
+ },
+ {
+ type: 'text',
+ id: 'url',
+ label: editor.lang.linkinfo.url_title,
+ width: '100%'
+ }
+ ]
+ },
+ {
+ id: 'tab_advanced',
+ label: editor.lang.linkinfo.tab_advanced_title,
+ elements: [
+ {
+ type : 'select',
+ id : 'access_point',
+ label : editor.lang.linkinfo.access_point_title,
+ items : [
+ [ '接続中', '' ]
+ ],
+ onLoad : function(){ // 起動時イベント
+ var elementId = '#' + this.getInputElement().$.id;
+
+ // Ajaxでページ情報を取得
+ m3_ajax_request('', 'task=linkinfo&act=getaccesspoint', function(request, retcode, jsondata){ // 正常終了
+ // アクセスポイント選択メニューを更新
+ $('option', elementId).remove();
+ if (jsondata.accesspoint){
+ $.each(jsondata.accesspoint, function(index, item){
+ $(elementId).get(0).options[$(elementId).get(0).options.length] = new Option(item[1], item[0]);
+ });
+ }
+ // 項目を再選択
+ $(elementId).val(accessPoint);
+ }, function(request){ // 異常終了
+ alert('通信に失敗しました。');
+ });
+ },
+ onShow : function(){ // 再表示イベント
+ var elementId = '#' + this.getInputElement().$.id;
+
+ // 項目を再選択
+ $(elementId).val(accessPoint);
+ },
+ onChange : function(){
+ // アクセスポイント変更
+ accessPoint = dialog.getContentElement('tab_advanced', 'access_point').getValue();
+
+ // コンテンツタイプ更新
+ updateContentType();
+
+ // ページリスト更新
+ updatePageList();
+ }
+ }
+ ]
+ }
+ ],
+ onOk: function(){
+ var url = dialog.getContentElement('tab_basic', 'url').getValue();
+
+ // 作成したURLを設定
+ if (typeof _m3SetUrlCallback == 'function'){
+ _m3SetUrlCallback(url);
+ }
+ }
+ };
+});
--- /dev/null
+/**
+ * Magic3 CKEditorプラグイン
+ *
+ * JavaScript 1.5
+ *
+ * LICENSE: This source file is licensed under the terms of the GNU General Public License.
+ *
+ * @package Magic3 Framework
+ * @author 平田直毅(Naoki Hirata) <naoki@aplo.co.jp>
+ * @copyright Copyright 2006-2013 Magic3 Project.
+ * @license http://www.gnu.org/copyleft/gpl.html GPL License
+ * @version SVN: $Id$
+ * @link http://www.magic3.org
+ */
+CKEDITOR.plugins.setLang( 'linkinfo', 'en', {
+ toolbar: 'Create URL for Magic3',
+ title: 'Create URL for Magic3',
+ tab_info_title: 'URL Info',
+ tab_advanced_title: 'Advanced Settings',
+ link_target_title: 'Select the link target.',
+ page_list_title: 'Page',
+ content_type_title: 'Content Type',
+ content_list_title: 'Content',
+ access_point_title: 'Access Point',
+ url_title: 'URL',
+content_label_title: 'Content Summary:'
+});
--- /dev/null
+/**
+ * Magic3 CKEditorプラグイン
+ *
+ * JavaScript 1.5
+ *
+ * LICENSE: This source file is licensed under the terms of the GNU General Public License.
+ *
+ * @package Magic3 Framework
+ * @author 平田直毅(Naoki Hirata) <naoki@aplo.co.jp>
+ * @copyright Copyright 2006-2013 Magic3 Project.
+ * @license http://www.gnu.org/copyleft/gpl.html GPL License
+ * @version SVN: $Id$
+ * @link http://www.magic3.org
+ */
+CKEDITOR.plugins.setLang( 'linkinfo', 'ja', {
+ toolbar: 'Magic3 URL作成',
+ title: 'Magic3 URL作成',
+ tab_info_title: 'URL情報',
+ tab_advanced_title: '高度な設定',
+ link_target_title: 'リンク対象を選択してください。',
+ page_list_title: 'ページ',
+ content_type_title: 'コンテンツ種別',
+ content_list_title: 'コンテンツ',
+ access_point_title: 'アクセスポイント',
+ url_title: 'URL',
+ content_title: 'タイトル',
+ content_label_title: 'コンテンツ内容:'
+});
--- /dev/null
+/**
+ * Magic3 CKEditorプラグイン
+ *
+ * JavaScript 1.5
+ *
+ * LICENSE: This source file is licensed under the terms of the GNU General Public License.
+ *
+ * @package Magic3 Framework
+ * @author 平田直毅(Naoki Hirata) <naoki@aplo.co.jp>
+ * @copyright Copyright 2006-2013 Magic3 Project.
+ * @license http://www.gnu.org/copyleft/gpl.html GPL License
+ * @version SVN: $Id: plugin.js 5938 2013-04-16 23:20:50Z fishbone $
+ * @link http://www.magic3.org
+ */
+(function() {
+ var pluginName = 'linkinfo';
+
+ // Register a plugin named "linkinfo".
+ CKEDITOR.plugins.add( pluginName, {
+ lang: 'en,ja',
+ icons: pluginName,
+ init: function( editor ) {
+ //if ( editor.blockless ) return;
+
+ editor.addCommand( pluginName, new CKEDITOR.dialogCommand( 'linkinfoDialog' ) );
+ CKEDITOR.dialog.add( 'linkinfoDialog', this.path + 'dialogs/linkinfo.js' );
+
+ editor.ui.addButton && editor.ui.addButton( 'LinkInfo', {
+ label: editor.lang.linkinfo.toolbar,
+ command: pluginName,
+ toolbar: 'others'
+ });
+ }
+ });
+})();
--- /dev/null
+/**
+ * Magic3 CKEditorプラグイン
+ *
+ * JavaScript 1.5
+ *
+ * LICENSE: This source file is licensed under the terms of the GNU General Public License.
+ *
+ * @package Magic3 Framework
+ * @author 平田直毅(Naoki Hirata) <naoki@aplo.co.jp>
+ * @copyright Copyright 2006-2013 Magic3 Project.
+ * @license http://www.gnu.org/copyleft/gpl.html GPL License
+ * @version SVN: $Id: youtubeDialog.js 6004 2013-05-17 01:46:23Z fishbone $
+ * @link http://www.magic3.org
+ */
+CKEDITOR.dialog.add( 'youtubeDialog', function( editor ){
+ return {
+ title: editor.lang.youtube.title,
+ minWidth: 390,
+ minHeight: 130,
+ contents : [
+ {
+ id : 'tab_single',
+ label : 'Settings',
+ title : 'Settings',
+ expand : true,
+ padding : 0,
+ elements :[
+ {
+ // 項目を縦に配置
+ type: 'vbox',
+ widths : [ null, null ],
+ styles : [ 'vertical-align:top' ],
+ padding: '5px',
+ children: [
+ {
+ type : 'html',
+ padding: '5px',
+ html : editor.lang.youtube.instruction
+ }, {
+ type : 'text',
+ id : 'txtVideoId',
+ label: editor.lang.youtube.videoId,
+ style: 'margin-top:5px;',
+ 'default': '',
+ validate: function() {
+ // Just a little light validation
+ // 'this' is now a CKEDITOR.ui.dialog.textInput object which
+ // is an extension of a CKEDITOR.ui.dialog.uiElement object
+ var value = this.getValue();
+ value = value.replace(/http:.*youtube.*?v=/, '');
+ this.setValue(value);
+ },
+ // The commit function gets called for each form element
+ // when the dialog's commitContent Function is called.
+ // For our dialog, commitContent is called when the user
+ // Clicks the "OK" button which is defined a little further down
+ commit: function( data ) {
+ var id = this.id;
+ if ( !data.info ) data.info = {};
+ data.info[id] = this.getValue();
+ }
+ } ]
+ }, {
+ // 項目を横に配置
+ type: 'hbox',
+ widths : [ null, null ],
+ styles : [ 'vertical-align:top' ],
+ padding: '5px',
+ children: [
+ {
+ type : 'text',
+ id : 'txtWidth',
+ label: editor.lang.youtube.width,
+ // We need to quote the default property since it is a reserved word
+ // in javascript
+ 'default': 500,
+ validate : function() {
+ var pass = true,
+ value = this.getValue();
+ pass = pass && CKEDITOR.dialog.validate.integer()( value ) && value > 0;
+ if ( !pass ){
+ alert( "Invalid Width" );
+ this.select();
+ }
+ return pass;
+ },
+ commit: function( data ) {
+ var id = this.id;
+ if ( !data.info ) data.info = {};
+ data.info[id] = this.getValue();
+ }
+ }, {
+ type : 'text',
+ id : 'txtHeight',
+ label: editor.lang.youtube.height,
+ 'default': 300,
+ validate : function() {
+ var pass = true,
+ value = this.getValue();
+ pass = pass && CKEDITOR.dialog.validate.integer()( value ) && value > 0;
+ if ( !pass ){
+ alert( "Invalid Height" );
+ this.select();
+ }
+ return pass;
+ },
+ commit: function( data ) {
+ var id = this.id;
+ if ( !data.info ) data.info = {};
+ data.info[id] = this.getValue();
+ }
+ }, {
+ type : 'checkbox',
+ id : 'chkAutoplay',
+ label: editor.lang.youtube.autoplay,
+ commit: function( data ) {
+ var id = this.id;
+ if ( !data.info ) data.info = {};
+ data.info[id] = this.getValue();
+ }
+ } ]
+ } ] // elements
+ } ],
+ onOk : function() {
+ // A container for our field data
+ var data = {};
+
+ // Commit the field data to our data object
+ // This function calls the commit function of each field element
+ // Each field has a commit function (that we define below) that will
+ // dump it's value into the data object
+ this.commitContent( data );
+
+ if (data.info) {
+ var info = data.info;
+ var src = 'http://youtube.com/embed/' + info.txtVideoId;
+ if (info.chkAutoplay) src += '?' + 'autoplay=1';
+
+ // Create the iframe element
+ var iframe = new CKEDITOR.dom.element( 'iframe' );
+ // Add the attributes to the iframe.
+ iframe.setAttributes({
+ 'width': info.txtWidth,
+ 'height': info.txtHeight,
+ 'type': 'text/html',
+ 'src': src,
+ 'frameborder': 0
+ });
+ // Finally insert the element into the editor.
+ editor.insertElement(iframe);
+ }
+ }
+ };
+});
--- /dev/null
+/**
+ * Magic3 CKEditorプラグイン
+ *
+ * JavaScript 1.5
+ *
+ * LICENSE: This source file is licensed under the terms of the GNU General Public License.
+ *
+ * @package Magic3 Framework
+ * @author 平田直毅(Naoki Hirata) <naoki@aplo.co.jp>
+ * @copyright Copyright 2006-2013 Magic3 Project.
+ * @license http://www.gnu.org/copyleft/gpl.html GPL License
+ * @version SVN: $Id: en.js 6004 2013-05-17 01:46:23Z fishbone $
+ * @link http://www.magic3.org
+ */
+CKEDITOR.plugins.setLang( 'youtube', 'en', {
+ toolbar: 'YouTube',
+ title: 'YouTube',
+ videoId: 'Video ID',
+ width: 'Width',
+ height: 'Height',
+ autoplay: 'Autoplay',
+ instruction: 'You can find the youtube video id in the url of the video. <br/> e.g. http://www.youtube.com/watch?v=<strong>VIDEO_ID</strong>.'
+});
--- /dev/null
+/**
+ * Magic3 CKEditorプラグイン
+ *
+ * JavaScript 1.5
+ *
+ * LICENSE: This source file is licensed under the terms of the GNU General Public License.
+ *
+ * @package Magic3 Framework
+ * @author 平田直毅(Naoki Hirata) <naoki@aplo.co.jp>
+ * @copyright Copyright 2006-2013 Magic3 Project.
+ * @license http://www.gnu.org/copyleft/gpl.html GPL License
+ * @version SVN: $Id: ja.js 6004 2013-05-17 01:46:23Z fishbone $
+ * @link http://www.magic3.org
+ */
+CKEDITOR.plugins.setLang( 'youtube', 'ja', {
+ toolbar: 'YouTube',
+ title: 'YouTube',
+ videoId: '動画ID',
+ width: '幅',
+ height: '高さ',
+ autoplay: '自動起動',
+ instruction: 'YouTube動画のURLから動画IDを取得してください。<br/> 例) http://www.youtube.com/watch?v=<strong>動画ID</strong>'
+});
--- /dev/null
+/**
+ * Magic3 CKEditorプラグイン
+ *
+ * JavaScript 1.5
+ *
+ * LICENSE: This source file is licensed under the terms of the GNU General Public License.
+ *
+ * @package Magic3 Framework
+ * @author 平田直毅(Naoki Hirata) <naoki@aplo.co.jp>
+ * @copyright Copyright 2006-2013 Magic3 Project.
+ * @license http://www.gnu.org/copyleft/gpl.html GPL License
+ * @version SVN: $Id: plugin.js 5957 2013-04-22 05:50:34Z fishbone $
+ * @link http://www.magic3.org
+ */
+CKEDITOR.plugins.add( 'youtube', {
+ lang: 'en,ja',
+ icons: 'youtube',
+
+ init: function( editor ) {
+ // プラグインを登録
+ editor.addCommand( 'youtube', new CKEDITOR.dialogCommand( 'youtubeDialog' ) );
+
+ // 実行するダイアログを登録
+ CKEDITOR.dialog.add( 'youtubeDialog', this.path + 'dialogs/youtubeDialog.js' );
+
+ // ツールバーにボタンを登録
+ if ( editor.ui.addButton ) {
+ editor.ui.addButton( 'YouTube', {
+ label: editor.lang.youtube.toolbar,
+ command: 'youtube',
+ toolbar: 'others'
+ });
+ }
+ }
+});