diff --git a/Gemfile b/Gemfile
index 34e81cef6..4f2f47682 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,4 +1,5 @@
source 'http://rubygems.org'
+#source 'http://ruby.taobao.com'
#source 'http://ruby.sdutlinux.org/'
unless RUBY_PLATFORM =~ /w32/
@@ -23,6 +24,7 @@ gem 'ruby-ole'
#gem 'email_verifier', path: 'lib/email_verifier'
gem 'rufus-scheduler'
#gem 'dalli', path: 'lib/dalli-2.7.2'
+gem 'rails_kindeditor'
group :development do
gem 'grape-swagger'
#gem 'grape-swagger-ui', git: 'https://github.com/guange2015/grape-swagger-ui.git'
diff --git a/app/controllers/discuss_demos_controller.rb b/app/controllers/discuss_demos_controller.rb
new file mode 100644
index 000000000..31b0f1dcc
--- /dev/null
+++ b/app/controllers/discuss_demos_controller.rb
@@ -0,0 +1,34 @@
+class DiscussDemosController < ApplicationController
+ def index
+ @discuss_demo_list = DiscussDemo.where("body is not null").order("created_at desc").page(params[:page] || 1).per(10)
+ end
+
+ def new
+ @discuss_demo = DiscussDemo.create
+ @discuss_demo.save!
+ @discuss_demo
+ end
+
+ def create
+
+ end
+
+ def update
+ @discuss_demo = DiscussDemo.find(params[:id])
+ @discuss_demo.update_attributes(:title => params[:discuss_demo][:title],:body => params[:discuss_demo][:body])
+ redirect_to :controller=> 'discuss_demos',:action => 'show',:id => params[:id]
+ end
+
+ def delete
+
+ end
+
+ def destroy
+ DiscussDemo.delete_all(["id = ?",params[:id]])
+ redirect_to :controller=> 'discuss_demos',:action => 'index'
+ end
+
+ def show
+ @discuss_demo = DiscussDemo.find(params[:id])
+ end
+end
diff --git a/app/helpers/discuss_demos_helper.rb b/app/helpers/discuss_demos_helper.rb
new file mode 100644
index 000000000..71bf8fb62
--- /dev/null
+++ b/app/helpers/discuss_demos_helper.rb
@@ -0,0 +1,2 @@
+module DiscussDemosHelper
+end
diff --git a/app/models/discuss_demo.rb b/app/models/discuss_demo.rb
new file mode 100644
index 000000000..74b21f9d4
--- /dev/null
+++ b/app/models/discuss_demo.rb
@@ -0,0 +1,4 @@
+class DiscussDemo < ActiveRecord::Base
+ attr_accessible :title, :body
+ has_many_kindeditor_assets :attachments, :dependent => :destroy
+end
diff --git a/app/models/kindeditor/asset.rb b/app/models/kindeditor/asset.rb
new file mode 100644
index 000000000..bae948c99
--- /dev/null
+++ b/app/models/kindeditor/asset.rb
@@ -0,0 +1,15 @@
+class Kindeditor::Asset < ActiveRecord::Base
+ self.table_name = 'kindeditor_assets'
+ mount_uploader :asset, Kindeditor::AssetUploader
+ validates_presence_of :asset
+ before_save :update_asset_attributes
+ attr_accessible :asset
+
+ private
+ def update_asset_attributes
+ if asset.present? && asset_changed?
+ self.file_size = asset.file.size
+ self.file_type = asset.file.content_type
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/models/kindeditor/file.rb b/app/models/kindeditor/file.rb
new file mode 100644
index 000000000..4b5f11441
--- /dev/null
+++ b/app/models/kindeditor/file.rb
@@ -0,0 +1,3 @@
+class Kindeditor::File < Kindeditor::Asset
+ mount_uploader :asset, Kindeditor::FileUploader
+end
\ No newline at end of file
diff --git a/app/models/kindeditor/flash.rb b/app/models/kindeditor/flash.rb
new file mode 100644
index 000000000..efaf5de9b
--- /dev/null
+++ b/app/models/kindeditor/flash.rb
@@ -0,0 +1,3 @@
+class Kindeditor::Flash < Kindeditor::Asset
+ mount_uploader :asset, Kindeditor::FlashUploader
+end
\ No newline at end of file
diff --git a/app/models/kindeditor/image.rb b/app/models/kindeditor/image.rb
new file mode 100644
index 000000000..a400c816d
--- /dev/null
+++ b/app/models/kindeditor/image.rb
@@ -0,0 +1,3 @@
+class Kindeditor::Image < Kindeditor::Asset
+ mount_uploader :asset, Kindeditor::ImageUploader
+end
\ No newline at end of file
diff --git a/app/models/kindeditor/media.rb b/app/models/kindeditor/media.rb
new file mode 100644
index 000000000..071763319
--- /dev/null
+++ b/app/models/kindeditor/media.rb
@@ -0,0 +1,3 @@
+class Kindeditor::Media < Kindeditor::Asset
+ mount_uploader :asset, Kindeditor::MediaUploader
+end
\ No newline at end of file
diff --git a/app/views/discuss_demos/index.html.erb b/app/views/discuss_demos/index.html.erb
new file mode 100644
index 000000000..b24937357
--- /dev/null
+++ b/app/views/discuss_demos/index.html.erb
@@ -0,0 +1,25 @@
+
文章列表
+
+
+ <% @discuss_demo_list.each do |e| %>
+
+
+ <%= truncate(e.title,:length => 50) %>
+
+ <%= truncate(e.body,:length => 50) %>
+
+
+ <%= link_to '查看文章',{:controller => 'discuss_demos',:action => 'show',:id=>e.id} %>
+
+
+
+ <%= link_to '删除文章',discuss_demo_path(e.id), :method => :delete,:confirm => l(:text_are_you_sure) %>
+
+
+
+
+ <% end %>
+
+ <% paginate @discuss_demo_list %>
+ <%= link_to '新建文章',new_discuss_demo_path %>
+
\ No newline at end of file
diff --git a/app/views/discuss_demos/new.html.erb b/app/views/discuss_demos/new.html.erb
new file mode 100644
index 000000000..8cf1630e2
--- /dev/null
+++ b/app/views/discuss_demos/new.html.erb
@@ -0,0 +1,7 @@
+<%= javascript_include_tag src='/assets/kindeditor/kindeditor' %>
+新建文章
+<%= form_for @discuss_demo,:url => {:controller => 'discuss_demos',:action => "show",:id =>@discuss_demo.id, :method => :put} do |f| %>
+ <%= f.text_field :title %>
+ <%= f.kindeditor :body ,:owner_id => @discuss_demo.id%>
+ <%= f.submit :value=> '提交' %>
+<% end %>
\ No newline at end of file
diff --git a/app/views/discuss_demos/show.html.erb b/app/views/discuss_demos/show.html.erb
new file mode 100644
index 000000000..4b6bd3cee
--- /dev/null
+++ b/app/views/discuss_demos/show.html.erb
@@ -0,0 +1,3 @@
+<%= @discuss_demo.title %>
+<%= textAreailizable @discuss_demo.body %>
+<%=link_to "返回首页",discuss_demos_path %>
\ No newline at end of file
diff --git a/config/initializers/rails_kindeditor.rb b/config/initializers/rails_kindeditor.rb
new file mode 100644
index 000000000..e928a6c7d
--- /dev/null
+++ b/config/initializers/rails_kindeditor.rb
@@ -0,0 +1,19 @@
+RailsKindeditor.setup do |config|
+
+ # Specify the subfolders in public directory.
+ # You can customize it , eg: config.upload_dir = 'this/is/my/folder'
+ config.upload_dir = 'files/uploads'
+
+ # Allowed file types for upload.
+ config.upload_image_ext = %w[gif jpg jpeg png bmp]
+ config.upload_flash_ext = %w[swf flv]
+ config.upload_media_ext = %w[swf flv mp3 wav wma wmv mid avi mpg asf rm rmvb]
+ config.upload_file_ext = %w[doc docx xls xlsx ppt htm html txt zip rar gz bz2]
+
+ # Porcess upload image size
+ # eg: 1600x1600 => 800x800
+ # 1600x800 => 800x400
+ # 400x400 => 400x400 # No Change
+ # config.image_resize_to_limit = [800, 800]
+
+end
diff --git a/config/routes.rb b/config/routes.rb
index 365c5a78e..ff562926c 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -27,6 +27,9 @@
RedmineApp::Application.routes.draw do
+ resources :discuss_demos
+ #match '/discuss_demos/new',:to => 'discuss_demo#create',:via =>[:post]
+ #match '/discuss_demo/show',:to => 'discuss_demo#show'
mount Mobile::API => '/api'
resources :homework_users
diff --git a/db/migrate/20150316032155_create_discuss_demos.rb b/db/migrate/20150316032155_create_discuss_demos.rb
new file mode 100644
index 000000000..af7a2a6ed
--- /dev/null
+++ b/db/migrate/20150316032155_create_discuss_demos.rb
@@ -0,0 +1,9 @@
+class CreateDiscussDemos < ActiveRecord::Migration
+ def change
+ create_table :discuss_demos do |t|
+ t.string :title
+ t.text :body
+ t.timestamps
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 4cce0b5c8..bad1cf2ae 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20150311013036) do
+ActiveRecord::Schema.define(:version => 20150305081132) do
create_table "activities", :force => true do |t|
t.integer "act_id", :null => false
diff --git a/public/assets/kindeditor/kindeditor.js b/public/assets/kindeditor/kindeditor.js
new file mode 100644
index 000000000..e58e4b2be
--- /dev/null
+++ b/public/assets/kindeditor/kindeditor.js
@@ -0,0 +1,5963 @@
+/*******************************************************************************
+* KindEditor - WYSIWYG HTML Editor for Internet
+* Copyright (C) 2006-2013 kindsoft.net
+*
+* @author Roddy
+* @website http://www.kindsoft.net/
+* @licence http://www.kindsoft.net/license.php
+* @version 4.1.10 (2013-11-23)
+*******************************************************************************/
+(function (window, undefined) {
+ if (window.KindEditor) {
+ return;
+ }
+if (!window.console) {
+ window.console = {};
+}
+if (!console.log) {
+ console.log = function () {};
+}
+var _VERSION = '4.1.10 (2013-11-23)',
+ _ua = navigator.userAgent.toLowerCase(),
+ _IE = _ua.indexOf('msie') > -1 && _ua.indexOf('opera') == -1,
+ _NEWIE = _ua.indexOf('msie') == -1 && _ua.indexOf('trident') > -1,
+ _GECKO = _ua.indexOf('gecko') > -1 && _ua.indexOf('khtml') == -1,
+ _WEBKIT = _ua.indexOf('applewebkit') > -1,
+ _OPERA = _ua.indexOf('opera') > -1,
+ _MOBILE = _ua.indexOf('mobile') > -1,
+ _IOS = /ipad|iphone|ipod/.test(_ua),
+ _QUIRKS = document.compatMode != 'CSS1Compat',
+ _IERANGE = !window.getSelection,
+ _matches = /(?:msie|firefox|webkit|opera)[\/:\s](\d+)/.exec(_ua),
+ _V = _matches ? _matches[1] : '0',
+ _TIME = new Date().getTime();
+function _isArray(val) {
+ if (!val) {
+ return false;
+ }
+ return Object.prototype.toString.call(val) === '[object Array]';
+}
+function _isFunction(val) {
+ if (!val) {
+ return false;
+ }
+ return Object.prototype.toString.call(val) === '[object Function]';
+}
+function _inArray(val, arr) {
+ for (var i = 0, len = arr.length; i < len; i++) {
+ if (val === arr[i]) {
+ return i;
+ }
+ }
+ return -1;
+}
+function _each(obj, fn) {
+ if (_isArray(obj)) {
+ for (var i = 0, len = obj.length; i < len; i++) {
+ if (fn.call(obj[i], i, obj[i]) === false) {
+ break;
+ }
+ }
+ } else {
+ for (var key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ if (fn.call(obj[key], key, obj[key]) === false) {
+ break;
+ }
+ }
+ }
+ }
+}
+function _trim(str) {
+ return str.replace(/(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g, '');
+}
+function _inString(val, str, delimiter) {
+ delimiter = delimiter === undefined ? ',' : delimiter;
+ return (delimiter + str + delimiter).indexOf(delimiter + val + delimiter) >= 0;
+}
+function _addUnit(val, unit) {
+ unit = unit || 'px';
+ return val && /^\d+$/.test(val) ? val + unit : val;
+}
+function _removeUnit(val) {
+ var match;
+ return val && (match = /(\d+)/.exec(val)) ? parseInt(match[1], 10) : 0;
+}
+function _escape(val) {
+ return val.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"');
+}
+function _unescape(val) {
+ return val.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/&/g, '&');
+}
+function _toCamel(str) {
+ var arr = str.split('-');
+ str = '';
+ _each(arr, function(key, val) {
+ str += (key > 0) ? val.charAt(0).toUpperCase() + val.substr(1) : val;
+ });
+ return str;
+}
+function _toHex(val) {
+ function hex(d) {
+ var s = parseInt(d, 10).toString(16).toUpperCase();
+ return s.length > 1 ? s : '0' + s;
+ }
+ return val.replace(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/ig,
+ function($0, $1, $2, $3) {
+ return '#' + hex($1) + hex($2) + hex($3);
+ }
+ );
+}
+function _toMap(val, delimiter) {
+ delimiter = delimiter === undefined ? ',' : delimiter;
+ var map = {}, arr = _isArray(val) ? val : val.split(delimiter), match;
+ _each(arr, function(key, val) {
+ if ((match = /^(\d+)\.\.(\d+)$/.exec(val))) {
+ for (var i = parseInt(match[1], 10); i <= parseInt(match[2], 10); i++) {
+ map[i.toString()] = true;
+ }
+ } else {
+ map[val] = true;
+ }
+ });
+ return map;
+}
+function _toArray(obj, offset) {
+ return Array.prototype.slice.call(obj, offset || 0);
+}
+function _undef(val, defaultVal) {
+ return val === undefined ? defaultVal : val;
+}
+function _invalidUrl(url) {
+ return !url || /[<>"]/.test(url);
+}
+function _addParam(url, param) {
+ return url.indexOf('?') >= 0 ? url + '&' + param : url + '?' + param;
+}
+function _extend(child, parent, proto) {
+ if (!proto) {
+ proto = parent;
+ parent = null;
+ }
+ var childProto;
+ if (parent) {
+ var fn = function () {};
+ fn.prototype = parent.prototype;
+ childProto = new fn();
+ _each(proto, function(key, val) {
+ childProto[key] = val;
+ });
+ } else {
+ childProto = proto;
+ }
+ childProto.constructor = child;
+ child.prototype = childProto;
+ child.parent = parent ? parent.prototype : null;
+}
+function _json(text) {
+ var match;
+ if ((match = /\{[\s\S]*\}|\[[\s\S]*\]/.exec(text))) {
+ text = match[0];
+ }
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
+ cx.lastIndex = 0;
+ if (cx.test(text)) {
+ text = text.replace(cx, function (a) {
+ return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ }
+ if (/^[\],:{}\s]*$/.
+ test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
+ replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
+ replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+ return eval('(' + text + ')');
+ }
+ throw 'JSON parse error';
+}
+var _round = Math.round;
+var K = {
+ DEBUG : false,
+ VERSION : _VERSION,
+ IE : _IE,
+ GECKO : _GECKO,
+ WEBKIT : _WEBKIT,
+ OPERA : _OPERA,
+ V : _V,
+ TIME : _TIME,
+ each : _each,
+ isArray : _isArray,
+ isFunction : _isFunction,
+ inArray : _inArray,
+ inString : _inString,
+ trim : _trim,
+ addUnit : _addUnit,
+ removeUnit : _removeUnit,
+ escape : _escape,
+ unescape : _unescape,
+ toCamel : _toCamel,
+ toHex : _toHex,
+ toMap : _toMap,
+ toArray : _toArray,
+ undef : _undef,
+ invalidUrl : _invalidUrl,
+ addParam : _addParam,
+ extend : _extend,
+ json : _json
+};
+var _INLINE_TAG_MAP = _toMap('a,abbr,acronym,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,img,input,ins,kbd,label,map,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'),
+ _BLOCK_TAG_MAP = _toMap('address,applet,blockquote,body,center,dd,dir,div,dl,dt,fieldset,form,frameset,h1,h2,h3,h4,h5,h6,head,hr,html,iframe,ins,isindex,li,map,menu,meta,noframes,noscript,object,ol,p,pre,script,style,table,tbody,td,tfoot,th,thead,title,tr,ul'),
+ _SINGLE_TAG_MAP = _toMap('area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed'),
+ _STYLE_TAG_MAP = _toMap('b,basefont,big,del,em,font,i,s,small,span,strike,strong,sub,sup,u'),
+ _CONTROL_TAG_MAP = _toMap('img,table,input,textarea,button'),
+ _PRE_TAG_MAP = _toMap('pre,style,script'),
+ _NOSPLIT_TAG_MAP = _toMap('html,head,body,td,tr,table,ol,ul,li'),
+ _AUTOCLOSE_TAG_MAP = _toMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr'),
+ _FILL_ATTR_MAP = _toMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'),
+ _VALUE_TAG_MAP = _toMap('input,button,textarea,select');
+// Begining of modification by Macrow
+function _getBasePath() {
+ var refPath = '/assets/kindeditor/';
+ var els = document.getElementsByTagName('script'), src;
+ for (var i = 0, len = els.length; i < len; i++) {
+ src = els[i].src || '';
+ if (/(kindeditor|application)[\w\-\.]*\.js/.test(src)) {
+ return src.substring(0, src.indexOf('assets')) + refPath;
+ }
+ }
+ return refPath;
+}
+// End of modification by Macrow
+K.basePath = _getBasePath();
+K.options = {
+ designMode : true,
+ fullscreenMode : false,
+ filterMode : true,
+ wellFormatMode : true,
+ shadowMode : true,
+ loadStyleMode : true,
+ basePath : K.basePath,
+ themesPath : K.basePath + 'themes/',
+ langPath : K.basePath + 'lang/',
+ pluginsPath : K.basePath + 'plugins/',
+ themeType : 'default',
+ langType : 'zh_CN',
+ urlType : '',
+ newlineTag : 'p',
+ resizeType : 2,
+ syncType : 'form',
+ pasteType : 2,
+ dialogAlignType : 'page',
+ useContextmenu : true,
+ fullscreenShortcut : false,
+ bodyClass : 'ke-content',
+ indentChar : '\t',
+ cssPath : '',
+ cssData : '',
+ minWidth : 650,
+ minHeight : 100,
+ minChangeSize : 50,
+ zIndex : 811213,
+ items : [
+ 'source', '|', 'undo', 'redo', '|', 'preview', 'print', 'template', 'code', 'cut', 'copy', 'paste',
+ 'plainpaste', 'wordpaste', '|', 'justifyleft', 'justifycenter', 'justifyright',
+ 'justifyfull', 'insertorderedlist', 'insertunorderedlist', 'indent', 'outdent', 'subscript',
+ 'superscript', 'clearhtml', 'quickformat', 'selectall', '|', 'fullscreen', '/',
+ 'formatblock', 'fontname', 'fontsize', '|', 'forecolor', 'hilitecolor', 'bold',
+ 'italic', 'underline', 'strikethrough', 'lineheight', 'removeformat', '|', 'image', 'multiimage',
+ 'flash', 'media', 'insertfile', 'table', 'hr', 'emoticons', 'baidumap', 'pagebreak',
+ 'anchor', 'link', 'unlink', '|', 'about'
+ ],
+ noDisableItems : ['source', 'fullscreen'],
+ colorTable : [
+ ['#E53333', '#E56600', '#FF9900', '#64451D', '#DFC5A4', '#FFE500'],
+ ['#009900', '#006600', '#99BB00', '#B8D100', '#60D978', '#00D5FF'],
+ ['#337FE5', '#003399', '#4C33E5', '#9933E5', '#CC33E5', '#EE33EE'],
+ ['#FFFFFF', '#CCCCCC', '#999999', '#666666', '#333333', '#000000']
+ ],
+ fontSizeTable : ['9px', '10px', '12px', '14px', '16px', '18px', '24px', '32px'],
+ htmlTags : {
+ font : ['id', 'class', 'color', 'size', 'face', '.background-color'],
+ span : [
+ 'id', 'class', '.color', '.background-color', '.font-size', '.font-family', '.background',
+ '.font-weight', '.font-style', '.text-decoration', '.vertical-align', '.line-height'
+ ],
+ div : [
+ 'id', 'class', 'align', '.border', '.margin', '.padding', '.text-align', '.color',
+ '.background-color', '.font-size', '.font-family', '.font-weight', '.background',
+ '.font-style', '.text-decoration', '.vertical-align', '.margin-left'
+ ],
+ table: [
+ 'id', 'class', 'border', 'cellspacing', 'cellpadding', 'width', 'height', 'align', 'bordercolor',
+ '.padding', '.margin', '.border', 'bgcolor', '.text-align', '.color', '.background-color',
+ '.font-size', '.font-family', '.font-weight', '.font-style', '.text-decoration', '.background',
+ '.width', '.height', '.border-collapse'
+ ],
+ 'td,th': [
+ 'id', 'class', 'align', 'valign', 'width', 'height', 'colspan', 'rowspan', 'bgcolor',
+ '.text-align', '.color', '.background-color', '.font-size', '.font-family', '.font-weight',
+ '.font-style', '.text-decoration', '.vertical-align', '.background', '.border'
+ ],
+ a : ['id', 'class', 'href', 'target', 'name'],
+ embed : ['id', 'class', 'src', 'width', 'height', 'type', 'loop', 'autostart', 'quality', '.width', '.height', 'align', 'allowscriptaccess'],
+ img : ['id', 'class', 'src', 'width', 'height', 'border', 'alt', 'title', 'align', '.width', '.height', '.border'],
+ 'p,ol,ul,li,blockquote,h1,h2,h3,h4,h5,h6' : [
+ 'id', 'class', 'align', '.text-align', '.color', '.background-color', '.font-size', '.font-family', '.background',
+ '.font-weight', '.font-style', '.text-decoration', '.vertical-align', '.text-indent', '.margin-left'
+ ],
+ pre : ['id', 'class'],
+ hr : ['id', 'class', '.page-break-after'],
+ 'br,tbody,tr,strong,b,sub,sup,em,i,u,strike,s,del' : ['id', 'class'],
+ iframe : ['id', 'class', 'src', 'frameborder', 'width', 'height', '.width', '.height']
+ },
+ layout : ''
+};
+var _useCapture = false;
+var _INPUT_KEY_MAP = _toMap('8,9,13,32,46,48..57,59,61,65..90,106,109..111,188,190..192,219..222');
+var _CURSORMOVE_KEY_MAP = _toMap('33..40');
+var _CHANGE_KEY_MAP = {};
+_each(_INPUT_KEY_MAP, function(key, val) {
+ _CHANGE_KEY_MAP[key] = val;
+});
+_each(_CURSORMOVE_KEY_MAP, function(key, val) {
+ _CHANGE_KEY_MAP[key] = val;
+});
+function _bindEvent(el, type, fn) {
+ if (el.addEventListener){
+ el.addEventListener(type, fn, _useCapture);
+ } else if (el.attachEvent){
+ el.attachEvent('on' + type, fn);
+ }
+}
+function _unbindEvent(el, type, fn) {
+ if (el.removeEventListener){
+ el.removeEventListener(type, fn, _useCapture);
+ } else if (el.detachEvent){
+ el.detachEvent('on' + type, fn);
+ }
+}
+var _EVENT_PROPS = ('altKey,attrChange,attrName,bubbles,button,cancelable,charCode,clientX,clientY,ctrlKey,currentTarget,' +
+ 'data,detail,eventPhase,fromElement,handler,keyCode,metaKey,newValue,offsetX,offsetY,originalTarget,pageX,' +
+ 'pageY,prevValue,relatedNode,relatedTarget,screenX,screenY,shiftKey,srcElement,target,toElement,view,wheelDelta,which').split(',');
+function KEvent(el, event) {
+ this.init(el, event);
+}
+_extend(KEvent, {
+ init : function(el, event) {
+ var self = this, doc = el.ownerDocument || el.document || el;
+ self.event = event;
+ _each(_EVENT_PROPS, function(key, val) {
+ self[val] = event[val];
+ });
+ if (!self.target) {
+ self.target = self.srcElement || doc;
+ }
+ if (self.target.nodeType === 3) {
+ self.target = self.target.parentNode;
+ }
+ if (!self.relatedTarget && self.fromElement) {
+ self.relatedTarget = self.fromElement === self.target ? self.toElement : self.fromElement;
+ }
+ if (self.pageX == null && self.clientX != null) {
+ var d = doc.documentElement, body = doc.body;
+ self.pageX = self.clientX + (d && d.scrollLeft || body && body.scrollLeft || 0) - (d && d.clientLeft || body && body.clientLeft || 0);
+ self.pageY = self.clientY + (d && d.scrollTop || body && body.scrollTop || 0) - (d && d.clientTop || body && body.clientTop || 0);
+ }
+ if (!self.which && ((self.charCode || self.charCode === 0) ? self.charCode : self.keyCode)) {
+ self.which = self.charCode || self.keyCode;
+ }
+ if (!self.metaKey && self.ctrlKey) {
+ self.metaKey = self.ctrlKey;
+ }
+ if (!self.which && self.button !== undefined) {
+ self.which = (self.button & 1 ? 1 : (self.button & 2 ? 3 : (self.button & 4 ? 2 : 0)));
+ }
+ switch (self.which) {
+ case 186 :
+ self.which = 59;
+ break;
+ case 187 :
+ case 107 :
+ case 43 :
+ self.which = 61;
+ break;
+ case 189 :
+ case 45 :
+ self.which = 109;
+ break;
+ case 42 :
+ self.which = 106;
+ break;
+ case 47 :
+ self.which = 111;
+ break;
+ case 78 :
+ self.which = 110;
+ break;
+ }
+ if (self.which >= 96 && self.which <= 105) {
+ self.which -= 48;
+ }
+ },
+ preventDefault : function() {
+ var ev = this.event;
+ if (ev.preventDefault) {
+ ev.preventDefault();
+ } else {
+ ev.returnValue = false;
+ }
+ },
+ stopPropagation : function() {
+ var ev = this.event;
+ if (ev.stopPropagation) {
+ ev.stopPropagation();
+ } else {
+ ev.cancelBubble = true;
+ }
+ },
+ stop : function() {
+ this.preventDefault();
+ this.stopPropagation();
+ }
+});
+var _eventExpendo = 'kindeditor_' + _TIME, _eventId = 0, _eventData = {};
+function _getId(el) {
+ return el[_eventExpendo] || null;
+}
+function _setId(el) {
+ el[_eventExpendo] = ++_eventId;
+ return _eventId;
+}
+function _removeId(el) {
+ try {
+ delete el[_eventExpendo];
+ } catch(e) {
+ if (el.removeAttribute) {
+ el.removeAttribute(_eventExpendo);
+ }
+ }
+}
+function _bind(el, type, fn) {
+ if (type.indexOf(',') >= 0) {
+ _each(type.split(','), function() {
+ _bind(el, this, fn);
+ });
+ return;
+ }
+ var id = _getId(el);
+ if (!id) {
+ id = _setId(el);
+ }
+ if (_eventData[id] === undefined) {
+ _eventData[id] = {};
+ }
+ var events = _eventData[id][type];
+ if (events && events.length > 0) {
+ _unbindEvent(el, type, events[0]);
+ } else {
+ _eventData[id][type] = [];
+ _eventData[id].el = el;
+ }
+ events = _eventData[id][type];
+ if (events.length === 0) {
+ events[0] = function(e) {
+ var kevent = e ? new KEvent(el, e) : undefined;
+ _each(events, function(i, event) {
+ if (i > 0 && event) {
+ event.call(el, kevent);
+ }
+ });
+ };
+ }
+ if (_inArray(fn, events) < 0) {
+ events.push(fn);
+ }
+ _bindEvent(el, type, events[0]);
+}
+function _unbind(el, type, fn) {
+ if (type && type.indexOf(',') >= 0) {
+ _each(type.split(','), function() {
+ _unbind(el, this, fn);
+ });
+ return;
+ }
+ var id = _getId(el);
+ if (!id) {
+ return;
+ }
+ if (type === undefined) {
+ if (id in _eventData) {
+ _each(_eventData[id], function(key, events) {
+ if (key != 'el' && events.length > 0) {
+ _unbindEvent(el, key, events[0]);
+ }
+ });
+ delete _eventData[id];
+ _removeId(el);
+ }
+ return;
+ }
+ if (!_eventData[id]) {
+ return;
+ }
+ var events = _eventData[id][type];
+ if (events && events.length > 0) {
+ if (fn === undefined) {
+ _unbindEvent(el, type, events[0]);
+ delete _eventData[id][type];
+ } else {
+ _each(events, function(i, event) {
+ if (i > 0 && event === fn) {
+ events.splice(i, 1);
+ }
+ });
+ if (events.length == 1) {
+ _unbindEvent(el, type, events[0]);
+ delete _eventData[id][type];
+ }
+ }
+ var count = 0;
+ _each(_eventData[id], function() {
+ count++;
+ });
+ if (count < 2) {
+ delete _eventData[id];
+ _removeId(el);
+ }
+ }
+}
+function _fire(el, type) {
+ if (type.indexOf(',') >= 0) {
+ _each(type.split(','), function() {
+ _fire(el, this);
+ });
+ return;
+ }
+ var id = _getId(el);
+ if (!id) {
+ return;
+ }
+ var events = _eventData[id][type];
+ if (_eventData[id] && events && events.length > 0) {
+ events[0]();
+ }
+}
+function _ctrl(el, key, fn) {
+ var self = this;
+ key = /^\d{2,}$/.test(key) ? key : key.toUpperCase().charCodeAt(0);
+ _bind(el, 'keydown', function(e) {
+ if (e.ctrlKey && e.which == key && !e.shiftKey && !e.altKey) {
+ fn.call(el);
+ e.stop();
+ }
+ });
+}
+var _readyFinished = false;
+function _ready(fn) {
+ if (_readyFinished) {
+ fn(KindEditor);
+ return;
+ }
+ var loaded = false;
+ function readyFunc() {
+ if (!loaded) {
+ loaded = true;
+ fn(KindEditor);
+ _readyFinished = true;
+ }
+ }
+ function ieReadyFunc() {
+ if (!loaded) {
+ try {
+ document.documentElement.doScroll('left');
+ } catch(e) {
+ setTimeout(ieReadyFunc, 100);
+ return;
+ }
+ readyFunc();
+ }
+ }
+ function ieReadyStateFunc() {
+ if (document.readyState === 'complete') {
+ readyFunc();
+ }
+ }
+ if (document.addEventListener) {
+ _bind(document, 'DOMContentLoaded', readyFunc);
+ } else if (document.attachEvent) {
+ _bind(document, 'readystatechange', ieReadyStateFunc);
+ var toplevel = false;
+ try {
+ toplevel = window.frameElement == null;
+ } catch(e) {}
+ if (document.documentElement.doScroll && toplevel) {
+ ieReadyFunc();
+ }
+ }
+ _bind(window, 'load', readyFunc);
+}
+if (_IE) {
+ window.attachEvent('onunload', function() {
+ _each(_eventData, function(key, events) {
+ if (events.el) {
+ _unbind(events.el);
+ }
+ });
+ });
+}
+K.ctrl = _ctrl;
+K.ready = _ready;
+function _getCssList(css) {
+ var list = {},
+ reg = /\s*([\w\-]+)\s*:([^;]*)(;|$)/g,
+ match;
+ while ((match = reg.exec(css))) {
+ var key = _trim(match[1].toLowerCase()),
+ val = _trim(_toHex(match[2]));
+ list[key] = val;
+ }
+ return list;
+}
+function _getAttrList(tag) {
+ var list = {},
+ reg = /\s+(?:([\w\-:]+)|(?:([\w\-:]+)=([^\s"'<>]+))|(?:([\w\-:"]+)="([^"]*)")|(?:([\w\-:"]+)='([^']*)'))(?=(?:\s|\/|>)+)/g,
+ match;
+ while ((match = reg.exec(tag))) {
+ var key = (match[1] || match[2] || match[4] || match[6]).toLowerCase(),
+ val = (match[2] ? match[3] : (match[4] ? match[5] : match[7])) || '';
+ list[key] = val;
+ }
+ return list;
+}
+function _addClassToTag(tag, className) {
+ if (/\s+class\s*=/.test(tag)) {
+ tag = tag.replace(/(\s+class=["']?)([^"']*)(["']?[\s>])/, function($0, $1, $2, $3) {
+ if ((' ' + $2 + ' ').indexOf(' ' + className + ' ') < 0) {
+ return $2 === '' ? $1 + className + $3 : $1 + $2 + ' ' + className + $3;
+ } else {
+ return $0;
+ }
+ });
+ } else {
+ tag = tag.substr(0, tag.length - 1) + ' class="' + className + '">';
+ }
+ return tag;
+}
+function _formatCss(css) {
+ var str = '';
+ _each(_getCssList(css), function(key, val) {
+ str += key + ':' + val + ';';
+ });
+ return str;
+}
+function _formatUrl(url, mode, host, pathname) {
+ mode = _undef(mode, '').toLowerCase();
+ if (url.substr(0, 5) != 'data:') {
+ url = url.replace(/([^:])\/\//g, '$1/');
+ }
+ if (_inArray(mode, ['absolute', 'relative', 'domain']) < 0) {
+ return url;
+ }
+ host = host || location.protocol + '//' + location.host;
+ if (pathname === undefined) {
+ var m = location.pathname.match(/^(\/.*)\//);
+ pathname = m ? m[1] : '';
+ }
+ var match;
+ if ((match = /^(\w+:\/\/[^\/]*)/.exec(url))) {
+ if (match[1] !== host) {
+ return url;
+ }
+ } else if (/^\w+:/.test(url)) {
+ return url;
+ }
+ function getRealPath(path) {
+ var parts = path.split('/'), paths = [];
+ for (var i = 0, len = parts.length; i < len; i++) {
+ var part = parts[i];
+ if (part == '..') {
+ if (paths.length > 0) {
+ paths.pop();
+ }
+ } else if (part !== '' && part != '.') {
+ paths.push(part);
+ }
+ }
+ return '/' + paths.join('/');
+ }
+ if (/^\//.test(url)) {
+ url = host + getRealPath(url.substr(1));
+ } else if (!/^\w+:\/\//.test(url)) {
+ url = host + getRealPath(pathname + '/' + url);
+ }
+ function getRelativePath(path, depth) {
+ if (url.substr(0, path.length) === path) {
+ var arr = [];
+ for (var i = 0; i < depth; i++) {
+ arr.push('..');
+ }
+ var prefix = '.';
+ if (arr.length > 0) {
+ prefix += '/' + arr.join('/');
+ }
+ if (pathname == '/') {
+ prefix += '/';
+ }
+ return prefix + url.substr(path.length);
+ } else {
+ if ((match = /^(.*)\//.exec(path))) {
+ return getRelativePath(match[1], ++depth);
+ }
+ }
+ }
+ if (mode === 'relative') {
+ url = getRelativePath(host + pathname, 0).substr(2);
+ } else if (mode === 'absolute') {
+ if (url.substr(0, host.length) === host) {
+ url = url.substr(host.length);
+ }
+ }
+ return url;
+}
+function _formatHtml(html, htmlTags, urlType, wellFormatted, indentChar) {
+ if (html == null) {
+ html = '';
+ }
+ urlType = urlType || '';
+ wellFormatted = _undef(wellFormatted, false);
+ indentChar = _undef(indentChar, '\t');
+ var fontSizeList = 'xx-small,x-small,small,medium,large,x-large,xx-large'.split(',');
+ html = html.replace(/(<(?:pre|pre\s[^>]*)>)([\s\S]*?)(<\/pre>)/ig, function($0, $1, $2, $3) {
+ return $1 + $2.replace(/<(?:br|br\s[^>]*)>/ig, '\n') + $3;
+ });
+ html = html.replace(/<(?:br|br\s[^>]*)\s*\/?>\s*<\/p>/ig, '');
+ html = html.replace(/(<(?:p|p\s[^>]*)>)\s*(<\/p>)/ig, '$1 $2');
+ html = html.replace(/\u200B/g, '');
+ html = html.replace(/\u00A9/g, '©');
+ html = html.replace(/\u00AE/g, '®');
+ html = html.replace(/<[^>]+/g, function($0) {
+ return $0.replace(/\s+/g, ' ');
+ });
+ var htmlTagMap = {};
+ if (htmlTags) {
+ _each(htmlTags, function(key, val) {
+ var arr = key.split(',');
+ for (var i = 0, len = arr.length; i < len; i++) {
+ htmlTagMap[arr[i]] = _toMap(val);
+ }
+ });
+ if (!htmlTagMap.script) {
+ html = html.replace(/(<(?:script|script\s[^>]*)>)([\s\S]*?)(<\/script>)/ig, '');
+ }
+ if (!htmlTagMap.style) {
+ html = html.replace(/(<(?:style|style\s[^>]*)>)([\s\S]*?)(<\/style>)/ig, '');
+ }
+ }
+ var re = /(\s*)<(\/)?([\w\-:]+)((?:\s+|(?:\s+[\w\-:]+)|(?:\s+[\w\-:]+=[^\s"'<>]+)|(?:\s+[\w\-:"]+="[^"]*")|(?:\s+[\w\-:"]+='[^']*'))*)(\/)?>(\s*)/g;
+ var tagStack = [];
+ html = html.replace(re, function($0, $1, $2, $3, $4, $5, $6) {
+ var full = $0,
+ startNewline = $1 || '',
+ startSlash = $2 || '',
+ tagName = $3.toLowerCase(),
+ attr = $4 || '',
+ endSlash = $5 ? ' ' + $5 : '',
+ endNewline = $6 || '';
+ if (htmlTags && !htmlTagMap[tagName]) {
+ return '';
+ }
+ if (endSlash === '' && _SINGLE_TAG_MAP[tagName]) {
+ endSlash = ' /';
+ }
+ if (_INLINE_TAG_MAP[tagName]) {
+ if (startNewline) {
+ startNewline = ' ';
+ }
+ if (endNewline) {
+ endNewline = ' ';
+ }
+ }
+ if (_PRE_TAG_MAP[tagName]) {
+ if (startSlash) {
+ endNewline = '\n';
+ } else {
+ startNewline = '\n';
+ }
+ }
+ if (wellFormatted && tagName == 'br') {
+ endNewline = '\n';
+ }
+ if (_BLOCK_TAG_MAP[tagName] && !_PRE_TAG_MAP[tagName]) {
+ if (wellFormatted) {
+ if (startSlash && tagStack.length > 0 && tagStack[tagStack.length - 1] === tagName) {
+ tagStack.pop();
+ } else {
+ tagStack.push(tagName);
+ }
+ startNewline = '\n';
+ endNewline = '\n';
+ for (var i = 0, len = startSlash ? tagStack.length : tagStack.length - 1; i < len; i++) {
+ startNewline += indentChar;
+ if (!startSlash) {
+ endNewline += indentChar;
+ }
+ }
+ if (endSlash) {
+ tagStack.pop();
+ } else if (!startSlash) {
+ endNewline += indentChar;
+ }
+ } else {
+ startNewline = endNewline = '';
+ }
+ }
+ if (attr !== '') {
+ var attrMap = _getAttrList(full);
+ if (tagName === 'font') {
+ var fontStyleMap = {}, fontStyle = '';
+ _each(attrMap, function(key, val) {
+ if (key === 'color') {
+ fontStyleMap.color = val;
+ delete attrMap[key];
+ }
+ if (key === 'size') {
+ fontStyleMap['font-size'] = fontSizeList[parseInt(val, 10) - 1] || '';
+ delete attrMap[key];
+ }
+ if (key === 'face') {
+ fontStyleMap['font-family'] = val;
+ delete attrMap[key];
+ }
+ if (key === 'style') {
+ fontStyle = val;
+ }
+ });
+ if (fontStyle && !/;$/.test(fontStyle)) {
+ fontStyle += ';';
+ }
+ _each(fontStyleMap, function(key, val) {
+ if (val === '') {
+ return;
+ }
+ if (/\s/.test(val)) {
+ val = "'" + val + "'";
+ }
+ fontStyle += key + ':' + val + ';';
+ });
+ attrMap.style = fontStyle;
+ }
+ _each(attrMap, function(key, val) {
+ if (_FILL_ATTR_MAP[key]) {
+ attrMap[key] = key;
+ }
+ if (_inArray(key, ['src', 'href']) >= 0) {
+ attrMap[key] = _formatUrl(val, urlType);
+ }
+ if (htmlTags && key !== 'style' && !htmlTagMap[tagName]['*'] && !htmlTagMap[tagName][key] ||
+ tagName === 'body' && key === 'contenteditable' ||
+ /^kindeditor_\d+$/.test(key)) {
+ delete attrMap[key];
+ }
+ if (key === 'style' && val !== '') {
+ var styleMap = _getCssList(val);
+ _each(styleMap, function(k, v) {
+ if (htmlTags && !htmlTagMap[tagName].style && !htmlTagMap[tagName]['.' + k]) {
+ delete styleMap[k];
+ }
+ });
+ var style = '';
+ _each(styleMap, function(k, v) {
+ style += k + ':' + v + ';';
+ });
+ attrMap.style = style;
+ }
+ });
+ attr = '';
+ _each(attrMap, function(key, val) {
+ if (key === 'style' && val === '') {
+ return;
+ }
+ val = val.replace(/"/g, '"');
+ attr += ' ' + key + '="' + val + '"';
+ });
+ }
+ if (tagName === 'font') {
+ tagName = 'span';
+ }
+ return startNewline + '<' + startSlash + tagName + attr + endSlash + '>' + endNewline;
+ });
+ html = html.replace(/(<(?:pre|pre\s[^>]*)>)([\s\S]*?)(<\/pre>)/ig, function($0, $1, $2, $3) {
+ return $1 + $2.replace(/\n/g, '\n') + $3;
+ });
+ html = html.replace(/\n\s*\n/g, '\n');
+ html = html.replace(/\n/g, '\n');
+ return _trim(html);
+}
+function _clearMsWord(html, htmlTags) {
+ html = html.replace(/ /ig, '')
+ .replace(//ig, '')
+ .replace(/'
+ ];
+ if (!_isArray(cssPath)) {
+ cssPath = [cssPath];
+ }
+ _each(cssPath, function(i, path) {
+ if (path) {
+ arr.push(' ');
+ }
+ });
+ if (cssData) {
+ arr.push('');
+ }
+ arr.push('