├── .eslintignore ├── js └── tinymce │ ├── skins │ └── lightgray │ │ ├── Radio.less │ │ ├── Spacer.less │ │ ├── fonts │ │ ├── readme.md │ │ ├── tinymce.eot │ │ ├── tinymce.ttf │ │ ├── tinymce.woff │ │ ├── tinymce-small.eot │ │ ├── tinymce-small.ttf │ │ └── tinymce-small.woff │ │ ├── StackLayout.less │ │ ├── img │ │ ├── anchor.gif │ │ ├── loader.gif │ │ ├── object.gif │ │ └── trans.gif │ │ ├── Content.Inline.less │ │ ├── Iframe.less │ │ ├── ColorBox.less │ │ ├── SelectBox.less │ │ ├── FitLayout.less │ │ ├── Animations.less │ │ ├── Container.less │ │ ├── Panel.less │ │ ├── FieldSet.less │ │ ├── AbsoluteLayout.less │ │ ├── ResizeHandle.less │ │ ├── Throbber.less │ │ ├── ImagePanel.less │ │ ├── ListBox.less │ │ ├── Content.less │ │ ├── Label.less │ │ ├── Slider.less │ │ ├── MenuButton.less │ │ ├── Progress.less │ │ ├── MenuBar.less │ │ ├── Path.less │ │ ├── FlowLayout.less │ │ ├── Scrollable.less │ │ ├── TabPanel.less │ │ ├── ComboBox.less │ │ ├── Menu.less │ │ ├── Reset.less │ │ ├── TextBox.less │ │ ├── SplitButton.less │ │ ├── Checkbox.less │ │ ├── CropRect.less │ │ ├── InfoBox.less │ │ ├── ColorButton.less │ │ ├── FloatPanel.less │ │ ├── ButtonGroup.less │ │ └── Mixins.less │ ├── themes │ └── inlite │ │ ├── config │ │ ├── bolt │ │ │ ├── atomic.js │ │ │ ├── prod.js │ │ │ ├── demo.js │ │ │ └── browser.js │ │ └── dent │ │ │ └── depend.js │ │ └── src │ │ ├── test │ │ ├── .eslintrc │ │ └── js │ │ │ ├── atomic │ │ │ ├── alien │ │ │ │ ├── ArrTest.js │ │ │ │ └── UuidTest.js │ │ │ └── core │ │ │ │ ├── ConvertTest.js │ │ │ │ ├── MatcherTest.js │ │ │ │ └── UrlTypeTest.js │ │ │ └── browser │ │ │ ├── core │ │ │ └── PredicateIdTest.js │ │ │ ├── file │ │ │ ├── ConversionsTest.js │ │ │ └── SelectionMatcher.js │ │ │ └── alien │ │ │ └── UnlinkTest.js │ │ ├── demo │ │ ├── css │ │ │ └── demo.css │ │ └── js │ │ │ └── tinymce │ │ │ └── inlite │ │ │ └── Demo.js │ │ └── main │ │ └── js │ │ └── tinymce │ │ └── inlite │ │ ├── alien │ │ ├── Arr.js │ │ └── Uuid.js │ │ ├── core │ │ ├── UrlType.js │ │ ├── PredicateId.js │ │ ├── Convert.js │ │ ├── Matcher.js │ │ ├── SkinLoader.js │ │ ├── ElementMatcher.js │ │ ├── SelectionMatcher.js │ │ └── Measure.js │ │ └── file │ │ ├── Conversions.js │ │ └── Picker.js │ ├── plugins │ ├── compat3x │ │ └── img │ │ │ ├── icons.gif │ │ │ ├── items.gif │ │ │ ├── tabs.gif │ │ │ ├── buttons.png │ │ │ ├── progress.gif │ │ │ ├── menu_arrow.gif │ │ │ └── menu_check.gif │ ├── media │ │ └── moxieplayer.swf │ ├── visualblocks │ │ └── img │ │ │ ├── dl.gif │ │ │ ├── h1.gif │ │ │ ├── h2.gif │ │ │ ├── h3.gif │ │ │ ├── h4.gif │ │ │ ├── h5.gif │ │ │ ├── h6.gif │ │ │ ├── ol.gif │ │ │ ├── p.gif │ │ │ ├── ul.gif │ │ │ ├── div.gif │ │ │ ├── pre.gif │ │ │ ├── address.gif │ │ │ ├── article.gif │ │ │ ├── aside.gif │ │ │ ├── figure.gif │ │ │ ├── hgroup.gif │ │ │ ├── section.gif │ │ │ └── blockquote.gif │ ├── emoticons │ │ ├── img │ │ │ ├── smiley-cry.gif │ │ │ ├── smiley-cool.gif │ │ │ ├── smiley-frown.gif │ │ │ ├── smiley-kiss.gif │ │ │ ├── smiley-smile.gif │ │ │ ├── smiley-wink.gif │ │ │ ├── smiley-yell.gif │ │ │ ├── smiley-innocent.gif │ │ │ ├── smiley-laughing.gif │ │ │ ├── smiley-sealed.gif │ │ │ ├── smiley-embarassed.gif │ │ │ ├── smiley-surprised.gif │ │ │ ├── smiley-tongue-out.gif │ │ │ ├── smiley-undecided.gif │ │ │ ├── smiley-foot-in-mouth.gif │ │ │ └── smiley-money-mouth.gif │ │ └── plugin.js │ ├── imagetools │ │ ├── config │ │ │ └── bolt │ │ │ │ ├── atomic.js │ │ │ │ ├── browser.js │ │ │ │ ├── demo.js │ │ │ │ └── prod.js │ │ └── src │ │ │ ├── demo │ │ │ └── html │ │ │ │ └── demo.html │ │ │ └── main │ │ │ └── js │ │ │ ├── UndoStack.js │ │ │ ├── ImageSize.js │ │ │ └── Utils.js │ ├── example │ │ ├── dialog.html │ │ └── plugin.js │ ├── print │ │ └── plugin.js │ ├── hr │ │ └── plugin.js │ ├── codesample │ │ └── classes │ │ │ └── Utils.js │ ├── example_dependency │ │ └── plugin.js │ ├── nonbreaking │ │ └── plugin.js │ ├── anchor │ │ └── plugin.js │ ├── table │ │ └── classes │ │ │ └── Utils.js │ ├── directionality │ │ └── plugin.js │ ├── code │ │ └── plugin.js │ └── wordcount │ │ └── plugin.js │ ├── langs │ └── readme.md │ └── classes │ ├── dom │ ├── Sizzle.jQuery.js │ ├── NodePath.js │ └── Dimensions.js │ ├── ui │ ├── Radio.js │ ├── MenuBar.js │ ├── StackLayout.js │ ├── Spacer.js │ ├── FlowLayout.js │ ├── Toolbar.js │ ├── FitLayout.js │ ├── FormItem.js │ ├── FieldSet.js │ ├── Panel.js │ ├── ButtonGroup.js │ ├── ColorBox.js │ ├── AbsoluteLayout.js │ ├── Resizable.js │ ├── Tooltip.js │ ├── Progress.js │ ├── ResizeHandle.js │ └── ElementPath.js │ ├── text │ └── Zwsp.js │ ├── Register.js │ ├── util │ ├── Uuid.js │ ├── JSONP.js │ ├── VK.js │ └── Fun.js │ ├── fmt │ └── Hooks.js │ ├── file │ ├── UploadStatus.js │ └── BlobCache.js │ ├── data │ └── Binding.js │ └── LegacyInput.js ├── tests ├── tinymce │ ├── util │ │ ├── json_rpc_ok.js │ │ ├── test.xml │ │ ├── json_rpc_error.js │ │ ├── Tools.js │ │ ├── Promise.js │ │ ├── XHR.js │ │ ├── JSON.js │ │ ├── Observable.js │ │ ├── Color.js │ │ ├── JSONRequest.js │ │ ├── Fun.js │ │ └── I18n.js │ ├── ui │ │ ├── img │ │ │ └── raster.gif │ │ ├── css │ │ │ └── ui-overrides.css │ │ ├── AbsoluteLayout.js │ │ ├── TextBox.js │ │ ├── Panel.js │ │ └── FitLayout.js │ ├── text │ │ ├── ExtendingChar.js │ │ └── Zwsp.js │ ├── file │ │ ├── Conversions.js │ │ ├── UploadStatus.js │ │ └── ImageScanner.js │ ├── caret │ │ └── LineUtils.js │ ├── WindowManager.js │ ├── dom │ │ ├── NodePath.js │ │ └── Dimensions.js │ ├── data │ │ └── ObservableObject.js │ ├── InsertList.js │ ├── html │ │ └── Serializer.js │ ├── AddOnManager.js │ └── fmt │ │ └── Hooks.js ├── manual │ ├── css │ │ ├── gecko_caret.css │ │ ├── custom_theme_content.css │ │ ├── noneditable_manual.css │ │ ├── development.css │ │ └── content_editable.css │ ├── img │ │ └── dogleft.jpg │ ├── tests.js │ ├── jquery.html │ ├── dirty.html │ └── index.html ├── .eslintrc ├── js │ ├── tinymce_loader.js │ ├── module_loader.js │ └── qunit │ │ └── QUnit.LICENSE ├── coverage │ ├── js │ │ └── reporter.js │ └── index.html ├── plugins │ ├── jquery_initialization.js │ ├── noneditable.js │ └── charmap.js └── .jshintrc ├── .travis.yml ├── .editorconfig ├── .gitattributes ├── tools ├── docs │ ├── tinymce.ProgressStateEvent.js │ ├── tinymce.CommandEvent.js │ ├── tinymce.FocusEvent.js │ ├── tinymce.ResizeEvent.js │ ├── tinymce.ContentEvent.js │ └── tinymce.Event.js └── tasks │ ├── amdlc.js │ └── bundle.js ├── .gitignore ├── package.json └── .eslintrc /.eslintignore: -------------------------------------------------------------------------------- 1 | **/bolt/*.js 2 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/Radio.less: -------------------------------------------------------------------------------- 1 | // Radio - not implemented yet 2 | -------------------------------------------------------------------------------- /tests/tinymce/util/json_rpc_ok.js: -------------------------------------------------------------------------------- 1 | {"result": "Hello JSON-RPC", "error": null, "id": 1} -------------------------------------------------------------------------------- /tests/manual/css/gecko_caret.css: -------------------------------------------------------------------------------- 1 | *[contentEditable]:focus { 2 | outline: 1px solid red; 3 | } -------------------------------------------------------------------------------- /tests/tinymce/util/test.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/tests/tinymce/util/test.xml -------------------------------------------------------------------------------- /tests/manual/img/dogleft.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/tests/manual/img/dogleft.jpg -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/Spacer.less: -------------------------------------------------------------------------------- 1 | // Spacer 2 | 3 | .@{prefix}-spacer { 4 | visibility: hidden; 5 | } 6 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/fonts/readme.md: -------------------------------------------------------------------------------- 1 | Icons are generated and provided by the http://icomoon.io service. 2 | -------------------------------------------------------------------------------- /tests/tinymce/ui/img/raster.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/tests/tinymce/ui/img/raster.gif -------------------------------------------------------------------------------- /tests/tinymce/util/json_rpc_error.js: -------------------------------------------------------------------------------- 1 | {"result": null, "error": {"message":"General failure","code":42}, "id": 1} -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/config/bolt/atomic.js: -------------------------------------------------------------------------------- 1 | configure({ 2 | configs: [ 3 | './prod.js' 4 | ] 5 | }); 6 | -------------------------------------------------------------------------------- /js/tinymce/plugins/compat3x/img/icons.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/compat3x/img/icons.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/compat3x/img/items.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/compat3x/img/items.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/compat3x/img/tabs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/compat3x/img/tabs.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/media/moxieplayer.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/media/moxieplayer.swf -------------------------------------------------------------------------------- /js/tinymce/plugins/visualblocks/img/dl.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/visualblocks/img/dl.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/visualblocks/img/h1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/visualblocks/img/h1.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/visualblocks/img/h2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/visualblocks/img/h2.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/visualblocks/img/h3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/visualblocks/img/h3.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/visualblocks/img/h4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/visualblocks/img/h4.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/visualblocks/img/h5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/visualblocks/img/h5.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/visualblocks/img/h6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/visualblocks/img/h6.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/visualblocks/img/ol.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/visualblocks/img/ol.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/visualblocks/img/p.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/visualblocks/img/p.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/visualblocks/img/ul.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/visualblocks/img/ul.gif -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/StackLayout.less: -------------------------------------------------------------------------------- 1 | // StackLayout 2 | 3 | .@{prefix}-stack-layout-item { 4 | display: block; 5 | } 6 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/img/anchor.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/skins/lightgray/img/anchor.gif -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/img/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/skins/lightgray/img/loader.gif -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/img/object.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/skins/lightgray/img/object.gif -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/img/trans.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/skins/lightgray/img/trans.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/compat3x/img/buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/compat3x/img/buttons.png -------------------------------------------------------------------------------- /js/tinymce/plugins/compat3x/img/progress.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/compat3x/img/progress.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/visualblocks/img/div.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/visualblocks/img/div.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/visualblocks/img/pre.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/visualblocks/img/pre.gif -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/fonts/tinymce.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/skins/lightgray/fonts/tinymce.eot -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/fonts/tinymce.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/skins/lightgray/fonts/tinymce.ttf -------------------------------------------------------------------------------- /tests/manual/css/custom_theme_content.css: -------------------------------------------------------------------------------- 1 | body, div, h1 { font-family: 'trebuchet ms', verdana, arial } 2 | body {font-size: 10pt; } 3 | -------------------------------------------------------------------------------- /js/tinymce/plugins/compat3x/img/menu_arrow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/compat3x/img/menu_arrow.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/compat3x/img/menu_check.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/compat3x/img/menu_check.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/emoticons/img/smiley-cry.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/emoticons/img/smiley-cry.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/imagetools/config/bolt/atomic.js: -------------------------------------------------------------------------------- 1 | configure({ 2 | configs: [ 3 | './test.js', 4 | './prod.js' 5 | ] 6 | }); 7 | -------------------------------------------------------------------------------- /js/tinymce/plugins/imagetools/config/bolt/browser.js: -------------------------------------------------------------------------------- 1 | configure({ 2 | configs: [ 3 | './test.js', 4 | './prod.js' 5 | ] 6 | }); 7 | -------------------------------------------------------------------------------- /js/tinymce/plugins/visualblocks/img/address.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/visualblocks/img/address.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/visualblocks/img/article.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/visualblocks/img/article.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/visualblocks/img/aside.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/visualblocks/img/aside.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/visualblocks/img/figure.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/visualblocks/img/figure.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/visualblocks/img/hgroup.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/visualblocks/img/hgroup.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/visualblocks/img/section.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/visualblocks/img/section.gif -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/fonts/tinymce.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/skins/lightgray/fonts/tinymce.woff -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4.2" 4 | - "5.1" 5 | before_script: 6 | - npm install -g grunt-cli 7 | script: "grunt" 8 | -------------------------------------------------------------------------------- /js/tinymce/plugins/emoticons/img/smiley-cool.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/emoticons/img/smiley-cool.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/emoticons/img/smiley-frown.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/emoticons/img/smiley-frown.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/emoticons/img/smiley-kiss.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/emoticons/img/smiley-kiss.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/emoticons/img/smiley-smile.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/emoticons/img/smiley-smile.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/emoticons/img/smiley-wink.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/emoticons/img/smiley-wink.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/emoticons/img/smiley-yell.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/emoticons/img/smiley-yell.gif -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/Content.Inline.less: -------------------------------------------------------------------------------- 1 | /* Content.Inline.less */ 2 | 3 | @import "Mixins.less"; 4 | @import "Content.Objects.less"; 5 | -------------------------------------------------------------------------------- /js/tinymce/plugins/emoticons/img/smiley-innocent.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/emoticons/img/smiley-innocent.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/emoticons/img/smiley-laughing.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/emoticons/img/smiley-laughing.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/emoticons/img/smiley-sealed.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/emoticons/img/smiley-sealed.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/visualblocks/img/blockquote.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/visualblocks/img/blockquote.gif -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/fonts/tinymce-small.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/skins/lightgray/fonts/tinymce-small.eot -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/fonts/tinymce-small.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/skins/lightgray/fonts/tinymce-small.ttf -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/fonts/tinymce-small.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/skins/lightgray/fonts/tinymce-small.woff -------------------------------------------------------------------------------- /tests/manual/css/noneditable_manual.css: -------------------------------------------------------------------------------- 1 | .mceNonEditable { 2 | background: #ffadad; 3 | } 4 | 5 | .mceEditable { 6 | background: #adffad; 7 | } 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.{js,css,html}] 4 | charset = utf-8 5 | indent_style = tab 6 | trim_trailing_whitespace = true 7 | end_of_line = lf 8 | -------------------------------------------------------------------------------- /js/tinymce/plugins/emoticons/img/smiley-embarassed.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/emoticons/img/smiley-embarassed.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/emoticons/img/smiley-surprised.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/emoticons/img/smiley-surprised.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/emoticons/img/smiley-tongue-out.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/emoticons/img/smiley-tongue-out.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/emoticons/img/smiley-undecided.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/emoticons/img/smiley-undecided.gif -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/Iframe.less: -------------------------------------------------------------------------------- 1 | // Iframe 2 | 3 | .@{prefix}-iframe { 4 | border: 0 solid @iframe-border; 5 | width: 100%; height: 100%; 6 | } 7 | -------------------------------------------------------------------------------- /js/tinymce/plugins/emoticons/img/smiley-foot-in-mouth.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/emoticons/img/smiley-foot-in-mouth.gif -------------------------------------------------------------------------------- /js/tinymce/plugins/emoticons/img/smiley-money-mouth.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tes/tinymce/master/js/tinymce/plugins/emoticons/img/smiley-money-mouth.gif -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/ColorBox.less: -------------------------------------------------------------------------------- 1 | // ColorBox 2 | 3 | .@{prefix}-colorbox i { 4 | border: 1px solid @textbox-border; 5 | width: 14px; height: 14px; 6 | } 7 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/SelectBox.less: -------------------------------------------------------------------------------- 1 | // SelectBox 2 | 3 | .@{prefix}-selectbox { 4 | background: @selectbox-bg; 5 | border: 1px solid @selectbox-border; 6 | } 7 | -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/config/bolt/prod.js: -------------------------------------------------------------------------------- 1 | configure({ 2 | sources: [ 3 | source('amd', 'tinymce/inlite', '../../src/main/js', mapper.hierarchical) 4 | ] 5 | }); 6 | -------------------------------------------------------------------------------- /js/tinymce/langs/readme.md: -------------------------------------------------------------------------------- 1 | This is where language files should be placed. 2 | 3 | Please DO NOT translate these directly use this service: https://www.transifex.com/projects/p/tinymce/ 4 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/FitLayout.less: -------------------------------------------------------------------------------- 1 | // FitLayout 2 | 3 | .@{prefix}-fit-layout { 4 | .inline-block(); 5 | } 6 | 7 | .@{prefix}-fit-layout-item { 8 | position: absolute; 9 | } 10 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/Animations.less: -------------------------------------------------------------------------------- 1 | // Animations 2 | 3 | .@{prefix}-fade { 4 | opacity: 0; 5 | .transition(opacity .15s linear); 6 | 7 | &.@{prefix}-in { 8 | opacity: 1; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/Container.less: -------------------------------------------------------------------------------- 1 | // Container 2 | 3 | .@{prefix}-container, .@{prefix}-container-body { 4 | display: block; 5 | } 6 | 7 | .@{prefix}-autoscroll { 8 | overflow: hidden; 9 | } 10 | -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/config/bolt/demo.js: -------------------------------------------------------------------------------- 1 | configure({ 2 | configs: [ 3 | './prod.js' 4 | ], 5 | sources: [ 6 | source('amd', 'tinymce/inlite/Demo', '../../src/demo/js', mapper.hierarchical) 7 | ] 8 | }); 9 | -------------------------------------------------------------------------------- /js/tinymce/plugins/example/dialog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

Custom dialog

5 | Input some text: 6 | 7 | 8 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/Panel.less: -------------------------------------------------------------------------------- 1 | // Panel 2 | 3 | .@{prefix}-panel { 4 | border: 0 solid mix(rgb(red(@panel-border), green(@panel-border), blue(@panel-border)), @panel-bg, 20%); 5 | border: 0 solid @panel-border; 6 | .vertical-gradient(@panel-bg, @panel-bg-hlight); 7 | } 8 | -------------------------------------------------------------------------------- /js/tinymce/plugins/imagetools/config/bolt/demo.js: -------------------------------------------------------------------------------- 1 | configure({ 2 | configs: [ 3 | './prod.js' 4 | ], 5 | sources: [ 6 | source('amd', 'tinymce/imagetoolsplugin/Demo', '../../src/demo/js', function(id) {return id.replace(/^tinymce\/imagetoolsplugin\//, '')}) 7 | ] 8 | }); 9 | -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "amd": true 5 | }, 6 | 7 | "globals": { 8 | "assert": true, 9 | "test": true, 10 | "asynctest": true 11 | }, 12 | 13 | "extends": "../../../../../../.eslintrc" 14 | } 15 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * eol=lf 2 | *.jar binary 3 | *.gif binary 4 | *.png binary 5 | *.jpg binary 6 | *.swf binary 7 | *.xap binary 8 | *.zip binary 9 | *.eot binary 10 | *.woff binary 11 | *.ttf binary 12 | *.mov binary 13 | *.avi binary 14 | *.flv binary 15 | *.rm binary 16 | *.dcr binary 17 | -------------------------------------------------------------------------------- /tests/tinymce/util/Tools.js: -------------------------------------------------------------------------------- 1 | ModuleLoader.require(["tinymce/util/Tools"], function(Tools) { 2 | module("tinymce.util.Tools"); 3 | 4 | test('extend', function() { 5 | deepEqual({a: 1, b: 2, c: 3}, Tools.extend({a: 1}, {b: 2}, {c: 3})); 6 | deepEqual({a: 1, c: 3}, Tools.extend({a: 1}, null, {c: 3})); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/test/js/atomic/alien/ArrTest.js: -------------------------------------------------------------------------------- 1 | test('atomic/alien/ArrTest', [ 2 | 'tinymce/inlite/alien/Arr' 3 | ], function (Arr) { 4 | var testFlatten = function () { 5 | assert.eq(Arr.flatten([1, 2, [3, 4, [5, 6]], [7, 8], 9]), [1, 2, 3, 4, 5, 6, 7, 8, 9]); 6 | }; 7 | 8 | testFlatten(); 9 | }); 10 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/FieldSet.less: -------------------------------------------------------------------------------- 1 | // FieldSet 2 | 3 | .@{prefix}-fieldset { 4 | border: 0 solid #9E9E9E; 5 | .border-radius(3px); 6 | } 7 | 8 | .@{prefix}-fieldset > .@{prefix}-container-body { 9 | margin-top: -15px; 10 | } 11 | 12 | .@{prefix}-fieldset-title { 13 | margin-left: 5px; 14 | padding: 0 5px 0 5px; 15 | } -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/test/js/atomic/alien/UuidTest.js: -------------------------------------------------------------------------------- 1 | test('atomic/alien/UuidTest', [ 2 | 'tinymce/inlite/alien/Uuid' 3 | ], function (Uuid) { 4 | var testUuid = function () { 5 | assert.eq(Uuid.uuid('mce').indexOf('mce'), 0); 6 | assert.eq(Uuid.uuid('mce') !== Uuid.uuid('mce'), true); 7 | }; 8 | 9 | testUuid(); 10 | }); 11 | -------------------------------------------------------------------------------- /tests/tinymce/text/ExtendingChar.js: -------------------------------------------------------------------------------- 1 | ModuleLoader.require(["tinymce/text/ExtendingChar"], function(ExtendingChar) { 2 | module("tinymce.text.ExtendingChar"); 3 | 4 | test('isExtendingChar', function() { 5 | strictEqual(ExtendingChar.isExtendingChar('a'), false); 6 | strictEqual(ExtendingChar.isExtendingChar('\u0301'), true); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /js/tinymce/plugins/imagetools/config/bolt/prod.js: -------------------------------------------------------------------------------- 1 | configure({ 2 | sources: [ 3 | source('amd', 'ephox/imagetools', '../../../../../../node_modules/@ephox/imagetools/src/main/js', mapper.hierarchical), 4 | source('amd', 'tinymce/imagetoolsplugin', '../../src/main/js', function(id) {return id.replace(/^tinymce\/imagetoolsplugin\//, '');}) 5 | ] 6 | }); 7 | -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/config/bolt/browser.js: -------------------------------------------------------------------------------- 1 | configure({ 2 | configs: [ 3 | './prod.js' 4 | ], 5 | sources: [ 6 | source('amd', 'ephox/tinymce', '', mapper.constant('../../../../../tinymce')), 7 | source('amd', 'ephox.mcagar', '../../lib/test', mapper.flat), 8 | source('amd', 'ephox', '../../lib/test', mapper.flat) 9 | ] 10 | }); 11 | -------------------------------------------------------------------------------- /tests/manual/css/development.css: -------------------------------------------------------------------------------- 1 | .example1 { 2 | font-weight: bold; 3 | font-size: 14px 4 | } 5 | 6 | .example2 { 7 | font-weight: bold; 8 | font-size: 12px; 9 | color: #FF0000 10 | } 11 | 12 | tr.tablerow1 { 13 | background-color: #BBBBBB; 14 | } 15 | 16 | p.red {color:red;} 17 | strong.red {color: red;} 18 | strong.red.italic {color: red; font-style: italic;} 19 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/AbsoluteLayout.less: -------------------------------------------------------------------------------- 1 | // AbsoluteLayout 2 | 3 | .@{prefix}-abs-layout { 4 | position: relative; 5 | } 6 | 7 | body .@{prefix}-abs-layout-item, .@{prefix}-abs-end { 8 | position: absolute; 9 | } 10 | 11 | .@{prefix}-abs-end { 12 | width: 1px; height: 1px; 13 | } 14 | 15 | .@{prefix}-container-body.@{prefix}-abs-layout { 16 | overflow: hidden; 17 | } 18 | -------------------------------------------------------------------------------- /tests/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "amd": true, 5 | "qunit": true 6 | }, 7 | 8 | "globals": { 9 | "tinymce": true, 10 | "Utils": true, 11 | "editor": true, 12 | "inlineEditor": true, 13 | "ModuleLoader": true 14 | }, 15 | 16 | "rules": { 17 | "max-len": 0, 18 | "space-before-blocks": 0, 19 | "consistent-this": 0 20 | }, 21 | 22 | "extends": "../.eslintrc" 23 | } 24 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/ResizeHandle.less: -------------------------------------------------------------------------------- 1 | .@{prefix}-container-body .@{prefix}-resizehandle { 2 | position: absolute; 3 | right: 0; 4 | bottom: 0; 5 | width: 16px; 6 | height: 16px; 7 | visibility: visible; 8 | cursor: s-resize; 9 | margin: 0; 10 | } 11 | 12 | .@{prefix}-container-body .@{prefix}-resizehandle-both { 13 | cursor: se-resize; 14 | } 15 | 16 | i.@{prefix}-i-resize { 17 | color: @text; 18 | } 19 | -------------------------------------------------------------------------------- /tests/tinymce/text/Zwsp.js: -------------------------------------------------------------------------------- 1 | ModuleLoader.require(["tinymce/text/Zwsp"], function(Zwsp) { 2 | module("tinymce.text.Zwsp"); 3 | 4 | test('ZWSP', function() { 5 | strictEqual(Zwsp.ZWSP, '\u200b'); 6 | }); 7 | 8 | test('isZwsp', function() { 9 | strictEqual(Zwsp.isZwsp(Zwsp.ZWSP), true); 10 | }); 11 | 12 | test('isZwsp', function() { 13 | strictEqual(Zwsp.trim('a' + Zwsp.ZWSP + 'b'), 'ab'); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/Throbber.less: -------------------------------------------------------------------------------- 1 | // Throbber 2 | 3 | .@{prefix}-throbber { 4 | position: absolute; 5 | top: 0; left: 0; 6 | width: 100%; height: 100%; 7 | .opacity(0.6); 8 | background: @throbber-bg; 9 | } 10 | 11 | .@{prefix}-throbber-inline { 12 | position: static; 13 | height: 50px; 14 | } 15 | 16 | .@{prefix}-menu .@{prefix}-throbber-inline { 17 | height: 25px; 18 | background-size: contain; 19 | } 20 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/ImagePanel.less: -------------------------------------------------------------------------------- 1 | // ImagePanel 2 | 3 | .@{prefix}-imagepanel { 4 | overflow: auto; 5 | background: black; 6 | } 7 | 8 | .@{prefix}-imagepanel img { 9 | position: absolute; 10 | } 11 | 12 | .@{prefix}-imagetool.@{prefix}-btn .@{prefix}-ico { 13 | display: block; 14 | width: 20px; 15 | height: 20px; 16 | text-align: center; 17 | line-height: 20px; 18 | font-size: 20px; 19 | padding: 5px; 20 | } 21 | -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/demo/css/demo.css: -------------------------------------------------------------------------------- 1 | blockquote { 2 | border-left: 3px solid rgba(0,0,0,.8); 3 | padding-left: 20px; 4 | margin: 0; 5 | } 6 | 7 | .mce-edit-focus { 8 | outline: 1px solid blue; 9 | } 10 | 11 | .tinymce { 12 | margin: 10px; 13 | padding: 10px; 14 | overflow: auto; 15 | border: 1px solid gray; 16 | } 17 | 18 | table, td { 19 | border: 1px dashed gray; 20 | } 21 | 22 | /*.mce-tinymce-inline { 23 | transition: left 50ms ease-in-out, top 50ms ease-in-out; 24 | } 25 | */ -------------------------------------------------------------------------------- /js/tinymce/plugins/imagetools/src/demo/html/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ImageTools Demo Page 5 | 6 | 7 | 10 | 11 | 12 | 13 |

ImageTools Demo Page

14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /tools/docs/tinymce.ProgressStateEvent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This class is the event object send when the ProgressState event occurs. 3 | * 4 | * @class tinymce.ProgressStateEvent 5 | * @extends tinymce.Event 6 | */ 7 | 8 | /** 9 | * True/false state when to show/hide the progress/throbber state for the editor. 10 | * 11 | * @property {Boolean} state State if the progress/throbber should be shown/hidden. 12 | */ 13 | 14 | /** 15 | * Time to wait before the progress/throbber is shown. 16 | * 17 | * @property {Number} time 18 | */ 19 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/ListBox.less: -------------------------------------------------------------------------------- 1 | // ListBox 2 | 3 | .@{prefix}-listbox button { 4 | text-align: left; 5 | padding-right: 20px; 6 | position: relative; 7 | } 8 | 9 | .@{prefix}-listbox .@{prefix}-caret { 10 | position: absolute; 11 | margin-top: -2px; 12 | right: 8px; 13 | top: 50%; 14 | } 15 | 16 | // RTL 17 | 18 | .@{prefix}-rtl .@{prefix}-listbox .@{prefix}-caret { 19 | right: auto; 20 | left: 8px; 21 | } 22 | 23 | .@{prefix}-rtl .@{prefix}-listbox button { 24 | padding-right: 10px; 25 | padding-left: 20px; 26 | } 27 | -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/config/dent/depend.js: -------------------------------------------------------------------------------- 1 | var lib = 'lib'; 2 | var run = lib + '/run'; 3 | var depend = run + '/depend'; 4 | var licenses = run + '/licenses'; 5 | var demo = lib + '/demo'; 6 | var test = lib + '/test'; 7 | var config = lib + '/config'; 8 | 9 | var cleanDirs = [ lib ]; 10 | 11 | var dependencies = [ 12 | { 13 | name: 'mcagar', 14 | repository: 'buildrepo2', 15 | source: 'mcagar.zip', 16 | targets: [ 17 | { name: 'module/*.js', path: test }, 18 | { name: 'depend/*.js', path: test } 19 | ] 20 | } 21 | ]; 22 | -------------------------------------------------------------------------------- /js/tinymce/classes/dom/Sizzle.jQuery.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sizzle.jQuery.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /*global jQuery:true */ 12 | 13 | /* 14 | * Fake Sizzle using jQuery. 15 | */ 16 | define("tinymce/dom/Sizzle", [], function() { 17 | // Detect if jQuery is loaded 18 | if (!window.jQuery) { 19 | throw new Error("Load jQuery first"); 20 | } 21 | 22 | return jQuery.find; 23 | }); 24 | -------------------------------------------------------------------------------- /tests/tinymce/file/Conversions.js: -------------------------------------------------------------------------------- 1 | ModuleLoader.require(["tinymce/file/Conversions"], function(Conversions) { 2 | module("tinymce.file.Conversions"); 3 | 4 | if (!tinymce.Env.fileApi) { 5 | test("File API not supported by browser.", function() { 6 | QUnit.ok(true); 7 | }); 8 | 9 | return; 10 | } 11 | 12 | QUnit.asyncTest("uriToBlob", function() { 13 | Conversions.uriToBlob("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D").then(Conversions.blobToDataUri).then(function(dataUri) { 14 | QUnit.equal(dataUri, "data:text/plain;base64,SGVsbG8sIFdvcmxkIQ=="); 15 | }).then(QUnit.start); 16 | }); 17 | }); -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/main/js/tinymce/inlite/alien/Arr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Arr.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2016 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | define('tinymce/inlite/alien/Arr', [ 12 | ], function () { 13 | var flatten = function (arr) { 14 | return arr.reduce(function (results, item) { 15 | return Array.isArray(item) ? results.concat(flatten(item)) : results.concat(item); 16 | }, []); 17 | }; 18 | 19 | return { 20 | flatten: flatten 21 | }; 22 | }); 23 | -------------------------------------------------------------------------------- /js/tinymce/classes/ui/Radio.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Radio.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * Creates a new radio button. 13 | * 14 | * @-x-less Radio.less 15 | * @class tinymce.ui.Radio 16 | * @extends tinymce.ui.Checkbox 17 | */ 18 | define("tinymce/ui/Radio", [ 19 | "tinymce/ui/Checkbox" 20 | ], function(Checkbox) { 21 | "use strict"; 22 | 23 | return Checkbox.extend({ 24 | Defaults: { 25 | classes: "radio", 26 | role: "radio" 27 | } 28 | }); 29 | }); -------------------------------------------------------------------------------- /tests/js/tinymce_loader.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var baseURL; 3 | 4 | // Get base where the tinymce script is located 5 | var scripts = document.getElementsByTagName('script'); 6 | for (var i = 0; i < scripts.length; i++) { 7 | var src = scripts[i].src; 8 | 9 | if (/tinymce_loader\.js/.test(src)) { 10 | baseURL = src.substring(0, src.lastIndexOf('/')); 11 | break; 12 | } 13 | } 14 | 15 | if (document.location.search.indexOf('min=true') > 0) { 16 | document.write(''); 17 | } else { 18 | document.write(''); 19 | } 20 | })(); 21 | -------------------------------------------------------------------------------- /tools/docs/tinymce.CommandEvent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This class is the event object send when the BeforeExecCommand and ExecCommand event occurs. 3 | * 4 | * @class tinymce.CommandEvent 5 | * @extends tinymce.Event 6 | * @example 7 | * tinymce.activeEditor.on('ExecCommand', function(e) { 8 | * console.log(e.command, e.ui, e.value); 9 | * }); 10 | */ 11 | 12 | /** 13 | * Name of the command to execute. 14 | * 15 | * @property {String} command 16 | */ 17 | 18 | /** 19 | * User interface state. Normally false. 20 | * 21 | * @property {Boolean} ui User interface state. 22 | */ 23 | 24 | /** 25 | * Value object for the execCommand call. 26 | * 27 | * @property {Object} value 28 | */ 29 | -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/test/js/atomic/core/ConvertTest.js: -------------------------------------------------------------------------------- 1 | test('atomic/core/ConvertTest', [ 2 | 'tinymce/inlite/core/Convert' 3 | ], function (Convert) { 4 | var testConvert = function () { 5 | assert.eq({x: 1, y: 2, w: 3, h: 4}, Convert.fromClientRect({left: 1, top: 2, width: 3, height: 4})); 6 | assert.eq({x: 2, y: 3, w: 4, h: 5}, Convert.fromClientRect({left: 2, top: 3, width: 4, height: 5})); 7 | assert.eq({left: 1, top: 2, width: 3, height: 4, bottom: 2 + 4, right: 1 + 3}, Convert.toClientRect({x: 1, y: 2, w: 3, h: 4})); 8 | assert.eq({left: 2, top: 3, width: 4, height: 5, bottom: 3 + 5, right: 2 + 4}, Convert.toClientRect({x: 2, y: 3, w: 4, h: 5})); 9 | }; 10 | 11 | testConvert(); 12 | }); 13 | -------------------------------------------------------------------------------- /tests/manual/tests.js: -------------------------------------------------------------------------------- 1 | { 2 | "title": "tinymce", 3 | "tests": [ 4 | {"title": "Gecko caret", "url": "gecko_caret.html", "manual": true}, 5 | {"title": "Noneditable", "url": "noneditable.html", "manual": true}, 6 | {"title": "Removeformat", "url": "removeformat.html", "manual": true}, 7 | {"title": "Resize", "url": "resize.html", "manual": true}, 8 | {"title": "Visual blocks", "url": "visualblocks.html", "manual": true}, 9 | {"title": "Custom theme", "url": "custom_theme.html", "manual": true}, 10 | {"title": "Development", "url": "development.html", "manual": true}, 11 | {"title": "Classic theme", "url": "classic.html", "manual": true}, 12 | {"title": "Inline editing", "url": "inline.html", "manual": true} 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/Content.less: -------------------------------------------------------------------------------- 1 | /* Content.less */ 2 | 3 | @font-family: Verdana, Arial, Helvetica, sans-serif; 4 | @font-size: 11px; 5 | 6 | body { 7 | background-color: #FFFFFF; 8 | color: #000000; 9 | font-family: @font-family; 10 | font-size: @font-size; 11 | scrollbar-3dlight-color: #F0F0EE; 12 | scrollbar-arrow-color: #676662; 13 | scrollbar-base-color: #F0F0EE; 14 | scrollbar-darkshadow-color: #DDDDDD; 15 | scrollbar-face-color: #E0E0DD; 16 | scrollbar-highlight-color: #F0F0EE; 17 | scrollbar-shadow-color: #F0F0EE; 18 | scrollbar-track-color: #F5F5F5; 19 | } 20 | 21 | td, th { 22 | font-family: @font-family; 23 | font-size: @font-size; 24 | } 25 | 26 | @import "Mixins.less"; 27 | @import "Content.Objects.less"; 28 | -------------------------------------------------------------------------------- /tools/docs/tinymce.FocusEvent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This class is the event object sent when editors are focused/blurred. 3 | * 4 | * @class tinymce.FocusEvent 5 | * @extends tinymce.Event 6 | * @example 7 | * tinymce.activeEditor.on('focus', function(e) { 8 | * console.log(e.blurredEditor); 9 | * }); 10 | * 11 | * tinymce.activeEditor.on('blur', function(e) { 12 | * console.log(e.focusedEditor); 13 | * }); 14 | */ 15 | 16 | /** 17 | * Optional editor instance that got the focus when the blur event occurs. 18 | * 19 | * @property {tinymce.Editor} focusedEditor 20 | */ 21 | 22 | /** 23 | * Optional editor instance that got blurred when the focus event occurs. 24 | * 25 | * @property {tinymce.Editor} blurredEditor 26 | */ 27 | -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/test/js/browser/core/PredicateIdTest.js: -------------------------------------------------------------------------------- 1 | test('browser/core/PredicateIdTest', [ 2 | 'ephox/tinymce', 3 | 'tinymce/inlite/core/PredicateId' 4 | ], function (tinymce, PredicateId) { 5 | var testFromContextToolbars = function () { 6 | var isTrue = function () { 7 | return true; 8 | }; 9 | 10 | var isFalse = function () { 11 | return false; 12 | }; 13 | 14 | var predIds = PredicateId.fromContextToolbars([ 15 | {toolbar: 'a b c', predicate: isTrue, id: 'a'}, 16 | {toolbar: 'd e', predicate: isFalse, id: 'b'} 17 | ]); 18 | 19 | assert.eq([ 20 | PredicateId.create('a', isTrue), 21 | PredicateId.create('b', isFalse) 22 | ], predIds); 23 | }; 24 | 25 | testFromContextToolbars(); 26 | }); 27 | -------------------------------------------------------------------------------- /tests/coverage/js/reporter.js: -------------------------------------------------------------------------------- 1 | headings = []; 2 | 3 | onload = function(){ 4 | headings = document.querySelectorAll('h2'); 5 | }; 6 | 7 | onscroll = function(e){ 8 | var heading = find(window.scrollY); 9 | if (!heading) return; 10 | var links = document.querySelectorAll('#menu a') 11 | , link; 12 | 13 | for (var i = 0, len = links.length; i < len; ++i) { 14 | link = links[i]; 15 | link.className = link.getAttribute('href') == '#' + heading.id 16 | ? 'active' 17 | : ''; 18 | } 19 | }; 20 | 21 | function find(y) { 22 | var i = headings.length 23 | , heading; 24 | 25 | while (i--) { 26 | heading = headings[i]; 27 | if (y > heading.offsetTop) { 28 | return heading; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/Label.less: -------------------------------------------------------------------------------- 1 | // Label 2 | 3 | .@{prefix}-label { 4 | .inline-block(); 5 | text-shadow: @text-shadow; 6 | overflow: hidden; 7 | } 8 | 9 | .@{prefix}-label.@{prefix}-autoscroll { 10 | overflow: auto; 11 | } 12 | 13 | .@{prefix}-label.@{prefix}-disabled { 14 | color: @text-disabled; 15 | } 16 | 17 | .@{prefix}-label.@{prefix}-multiline { 18 | white-space: pre-wrap; 19 | } 20 | 21 | .@{prefix}-label.@{prefix}-success { 22 | color: @text-success; 23 | } 24 | 25 | .@{prefix}-label.@{prefix}-warning { 26 | color: @text-warning; 27 | } 28 | 29 | .@{prefix}-label.@{prefix}-error { 30 | color: @text-error; 31 | } 32 | 33 | // RTL 34 | 35 | .@{prefix}-rtl .@{prefix}-label { 36 | text-align: right; 37 | direction: rtl; 38 | } 39 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/Slider.less: -------------------------------------------------------------------------------- 1 | // Slider 2 | 3 | .@{prefix}-slider { 4 | .border-radius(3px); 5 | border: 1px solid @slider-border; 6 | background: @slider-bg; 7 | width: 100px; 8 | height: 10px; 9 | position: relative; 10 | display: block; 11 | } 12 | 13 | .@{prefix}-slider.@{prefix}-vertical { 14 | width: 10px; 15 | height: 100px; 16 | } 17 | 18 | .@{prefix}-slider-handle { 19 | .border-radius(3px); 20 | border: 1px solid @slider-handle-border; 21 | background: @slider-handle-bg; 22 | display: block; 23 | width: 13px; 24 | height: 13px; 25 | position: absolute; 26 | top: 0; left: 0; 27 | margin-left: -1px; 28 | margin-top: -2px; 29 | } 30 | 31 | .@{prefix}-slider-handle:focus { 32 | background: @slider-handle-bg-focus; 33 | } 34 | -------------------------------------------------------------------------------- /tools/tasks/amdlc.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | grunt.registerMultiTask("amdlc", "Compiles AMD modules to libraries.", function() { 3 | var config = grunt.config([this.name, this.target]).options; 4 | 5 | config.reporter = { 6 | level: "debug", 7 | 8 | debug: function(message) { 9 | grunt.log.debug(message); 10 | }, 11 | 12 | info: function(message) { 13 | grunt.log.ok(message); 14 | }, 15 | 16 | warning: function(message) { 17 | grunt.fail.warn(message); 18 | }, 19 | 20 | error: function(message) { 21 | grunt.log.error(message); 22 | }, 23 | 24 | fatal: function(message) { 25 | grunt.log.error(message); 26 | } 27 | }; 28 | 29 | require("amdlc").compile(config); 30 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /js/tinymce/classes/ui/MenuBar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MenuBar.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * Creates a new menubar. 13 | * 14 | * @-x-less MenuBar.less 15 | * @class tinymce.ui.MenuBar 16 | * @extends tinymce.ui.Container 17 | */ 18 | define("tinymce/ui/MenuBar", [ 19 | "tinymce/ui/Toolbar" 20 | ], function(Toolbar) { 21 | "use strict"; 22 | 23 | return Toolbar.extend({ 24 | Defaults: { 25 | role: 'menubar', 26 | containerCls: 'menubar', 27 | ariaRoot: true, 28 | defaults: { 29 | type: 'menubutton' 30 | } 31 | } 32 | }); 33 | }); -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/main/js/tinymce/inlite/core/UrlType.js: -------------------------------------------------------------------------------- 1 | /** 2 | * UrlType.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2016 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | define('tinymce/inlite/core/UrlType', [ 12 | ], function () { 13 | var isDomainLike = function (href) { 14 | return /^www\.|\.(com|org|edu|gov|uk|net|ca|de|jp|fr|au|us|ru|ch|it|nl|se|no|es|mil)$/i.test(href.trim()); 15 | }; 16 | 17 | var isAbsolute = function (href) { 18 | return /^https?:\/\//.test(href.trim()); 19 | }; 20 | 21 | return { 22 | isDomainLike: isDomainLike, 23 | isAbsolute: isAbsolute 24 | }; 25 | }); 26 | 27 | 28 | -------------------------------------------------------------------------------- /js/tinymce/classes/text/Zwsp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Zwsp.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * .... 13 | * 14 | * @private 15 | * @class tinymce.text.Zwsp 16 | * @example 17 | * var isZwsp = Zwsp.isZwsp('\u200b'); 18 | * var abc = Zwsp.trim('a\u200bc'); 19 | */ 20 | define("tinymce/text/Zwsp", [], function() { 21 | var ZWSP = '\u200b'; 22 | 23 | function isZwsp(chr) { 24 | return chr == ZWSP; 25 | } 26 | 27 | function trim(str) { 28 | return str.replace(new RegExp(ZWSP, 'g'), ''); 29 | } 30 | 31 | return { 32 | isZwsp: isZwsp, 33 | ZWSP: ZWSP, 34 | trim: trim 35 | }; 36 | }); -------------------------------------------------------------------------------- /js/tinymce/plugins/print/plugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * plugin.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /*global tinymce:true */ 12 | 13 | tinymce.PluginManager.add('print', function(editor) { 14 | editor.addCommand('mcePrint', function() { 15 | editor.getWin().print(); 16 | }); 17 | 18 | editor.addButton('print', { 19 | title: 'Print', 20 | cmd: 'mcePrint' 21 | }); 22 | 23 | editor.addShortcut('Meta+P', '', 'mcePrint'); 24 | 25 | editor.addMenuItem('print', { 26 | text: 'Print', 27 | cmd: 'mcePrint', 28 | icon: 'print', 29 | shortcut: 'Meta+P', 30 | context: 'file' 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/MenuButton.less: -------------------------------------------------------------------------------- 1 | /* MenuButton */ 2 | 3 | .@{prefix}-menubtn button { 4 | color: @btn-text; 5 | //margin-right: 2px; 6 | //line-height: @line-height; 7 | //*line-height: @line-height - 4px; 8 | } 9 | 10 | .@{prefix}-menubtn.@{prefix}-btn-small span { 11 | font-size: @font-size - 2px; 12 | } 13 | 14 | .@{prefix}-menubtn.@{prefix}-fixed-width span { 15 | display: inline-block; 16 | overflow-x: hidden; 17 | text-overflow: ellipsis; 18 | width: 90px; 19 | } 20 | 21 | .@{prefix}-menubtn.@{prefix}-fixed-width.@{prefix}-btn-small span { 22 | width: 70px; 23 | } 24 | 25 | .@{prefix}-menubtn .@{prefix}-caret { 26 | *margin-top: 6px; 27 | } 28 | 29 | // RTL 30 | 31 | .@{prefix}-rtl .@{prefix}-menubtn button { 32 | direction: rtl; 33 | text-align: right; 34 | } 35 | -------------------------------------------------------------------------------- /js/tinymce/plugins/hr/plugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * plugin.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /*global tinymce:true */ 12 | 13 | tinymce.PluginManager.add('hr', function(editor) { 14 | editor.addCommand('InsertHorizontalRule', function() { 15 | editor.execCommand('mceInsertContent', false, '
'); 16 | }); 17 | 18 | editor.addButton('hr', { 19 | icon: 'hr', 20 | tooltip: 'Horizontal line', 21 | cmd: 'InsertHorizontalRule' 22 | }); 23 | 24 | editor.addMenuItem('hr', { 25 | icon: 'hr', 26 | text: 'Horizontal line', 27 | cmd: 'InsertHorizontalRule', 28 | context: 'insert' 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/Progress.less: -------------------------------------------------------------------------------- 1 | // Progress 2 | 3 | .@{prefix}-progress { 4 | display: inline-block; 5 | position: relative; 6 | height: 20px; 7 | } 8 | 9 | .@{prefix}-progress .@{prefix}-bar-container { 10 | display: inline-block; 11 | width: 100px; 12 | height: 100%; 13 | margin-right: 8px; 14 | border: 1px solid @progress-border; 15 | overflow: hidden; 16 | .border-radius(4px); 17 | } 18 | 19 | .@{prefix}-progress .@{prefix}-text { 20 | display: inline-block; 21 | margin-top: auto; 22 | margin-bottom: auto; 23 | font-size: 14px; 24 | width: 40px; 25 | color: @progress-text; 26 | } 27 | 28 | .@{prefix}-bar { 29 | display: block; 30 | width: 0%; 31 | height: 100%; 32 | .vertical-gradient(@progress-bar-bg, @progress-bar-bg-hlight); 33 | .transition(width .2s ease); 34 | } 35 | -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/main/js/tinymce/inlite/file/Conversions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Conversions.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2016 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | define('tinymce/inlite/file/Conversions', [ 12 | 'global!tinymce.util.Promise' 13 | ], function (Promise) { 14 | var blobToBase64 = function (blob) { 15 | return new Promise(function(resolve) { 16 | var reader = new FileReader(); 17 | 18 | reader.onloadend = function() { 19 | resolve(reader.result.split(',')[1]); 20 | }; 21 | 22 | reader.readAsDataURL(blob); 23 | }); 24 | }; 25 | 26 | return { 27 | blobToBase64: blobToBase64 28 | }; 29 | }); 30 | 31 | 32 | -------------------------------------------------------------------------------- /js/tinymce/classes/Register.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Register.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * This registers tinymce in common module loaders. 13 | * 14 | * @private 15 | * @class tinymce.Register 16 | */ 17 | define("tinymce/Register", [ 18 | ], function() { 19 | /*eslint consistent-this: 0 */ 20 | var context = this || window; 21 | 22 | var tinymce = function() { 23 | return context.tinymce; 24 | }; 25 | 26 | if (typeof context.define === "function") { 27 | // Bolt 28 | if (!context.define.amd) { 29 | context.define("ephox/tinymce", [], tinymce); 30 | } 31 | } 32 | 33 | return {}; 34 | }); 35 | -------------------------------------------------------------------------------- /tests/coverage/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Code Coverage 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /js/tinymce/plugins/codesample/classes/Utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Utils.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * Various utility functions. 13 | * 14 | * @class tinymce.codesample.Utils 15 | * @private 16 | */ 17 | define("tinymce/codesampleplugin/Utils", [ 18 | ], function() { 19 | function isCodeSample(elm) { 20 | return elm && elm.nodeName == 'PRE' && elm.className.indexOf('language-') !== -1; 21 | } 22 | 23 | function trimArg(predicateFn) { 24 | return function(arg1, arg2) { 25 | return predicateFn(arg2); 26 | }; 27 | } 28 | 29 | return { 30 | isCodeSample: isCodeSample, 31 | trimArg: trimArg 32 | }; 33 | }); -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/demo/js/tinymce/inlite/Demo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Demo.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2016 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /*eslint no-console:0 */ 12 | 13 | define('tinymce/inlite/Demo', [ 14 | 'tinymce/inlite/Theme', 15 | 'global!tinymce' 16 | ], function(Theme, tinymce) { 17 | tinymce.init({ 18 | selector: 'div.tinymce', 19 | theme: 'inlite', 20 | plugins: 'image table link paste contextmenu textpattern autolink', 21 | insert_toolbar: 'quickimage quicktable', 22 | selection_toolbar: 'bold italic | quicklink h2 h3 blockquote', 23 | inline: true, 24 | paste_data_images: true 25 | }); 26 | 27 | return function() {}; 28 | }); 29 | -------------------------------------------------------------------------------- /tests/tinymce/ui/css/ui-overrides.css: -------------------------------------------------------------------------------- 1 | /* Hardcodes sizes since fonts vary on platforms */ 2 | 3 | .mce-spacer { 4 | width: 20px; 5 | height: 20px; 6 | visibility: visible; 7 | border: 0 solid black; 8 | } 9 | 10 | .mce-head .mce-title { 11 | width: 100px; 12 | height: 20px; 13 | display: inline-block; 14 | } 15 | 16 | .mce-btn .mce-txt { 17 | width: 20px; 18 | } 19 | 20 | /* Colors used for debugging */ 21 | 22 | .mce-red {background-color: red;} 23 | .mce-green {background-color: green;} 24 | .mce-blue {background-color: blue;} 25 | .mce-yellow {background-color: yellow;} 26 | .mce-magenta {background-color: magenta;} 27 | .mce-cyan {background-color: cyan;} 28 | .mce-dotted {background-image: url(../img/raster.gif);} 29 | .mce-i-test {background: red;} 30 | 31 | body .mce-window, body .mce-notification { 32 | transform: none; 33 | } 34 | -------------------------------------------------------------------------------- /js/tinymce/classes/ui/StackLayout.js: -------------------------------------------------------------------------------- 1 | /** 2 | * StackLayout.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * This layout uses the browsers layout when the items are blocks. 13 | * 14 | * @-x-less StackLayout.less 15 | * @class tinymce.ui.StackLayout 16 | * @extends tinymce.ui.FlowLayout 17 | */ 18 | define("tinymce/ui/StackLayout", [ 19 | "tinymce/ui/FlowLayout" 20 | ], function(FlowLayout) { 21 | "use strict"; 22 | 23 | return FlowLayout.extend({ 24 | Defaults: { 25 | containerClass: 'stack-layout', 26 | controlClass: 'stack-layout-item', 27 | endClass: 'break' 28 | }, 29 | 30 | isNative: function() { 31 | return true; 32 | } 33 | }); 34 | }); -------------------------------------------------------------------------------- /js/tinymce/classes/util/Uuid.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Uuid.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2016 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * Generates unique ids. 13 | * 14 | * @class tinymce.util.Uuid 15 | * @private 16 | */ 17 | define("tinymce/util/Uuid", [ 18 | ], function() { 19 | var count = 0; 20 | 21 | var seed = function () { 22 | var rnd = function () { 23 | return Math.round(Math.random() * 0xFFFFFFFF).toString(36); 24 | }; 25 | 26 | var now = new Date().getTime(); 27 | return 's' + now.toString(36) + rnd() + rnd() + rnd(); 28 | }; 29 | 30 | var uuid = function (prefix) { 31 | return prefix + (count++) + seed(); 32 | }; 33 | 34 | return { 35 | uuid: uuid 36 | }; 37 | }); 38 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/MenuBar.less: -------------------------------------------------------------------------------- 1 | /* MenuBar */ 2 | 3 | .@{prefix}-menubar .@{prefix}-menubtn { 4 | border-color: transparent; 5 | background: transparent; 6 | .border-radius(0); 7 | .box-shadow(none); 8 | filter: none; 9 | } 10 | 11 | .@{prefix}-menubar .@{prefix}-menubtn button { 12 | color: @menubar-menubtn-text; 13 | } 14 | 15 | .@{prefix}-menubar { 16 | border: 1px solid @menubar-border; 17 | } 18 | 19 | .@{prefix}-menubar .@{prefix}-menubtn button span { 20 | color: @text; 21 | } 22 | 23 | .@{prefix}-menubar .@{prefix}-caret { 24 | border-top-color: @text; 25 | } 26 | 27 | .@{prefix}-menubar .@{prefix}-menubtn:hover, .@{prefix}-menubar .@{prefix}-menubtn.@{prefix}-active, .@{prefix}-menubar .@{prefix}-menubtn:focus { 28 | border-color: darken(@btn-bg, 20%); 29 | background: @menu-bg; 30 | filter: none; 31 | .box-shadow(none); 32 | } 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | tmp 4 | .settings 5 | .idea 6 | .project 7 | *.sublime-* 8 | .externalToolBuilders 9 | *~ 10 | *.diff 11 | *.patch 12 | *.bak 13 | *.log 14 | *.swp 15 | .DS_Store 16 | .project 17 | node_modules 18 | js/tinymce/tinymce.js 19 | js/tinymce/tinymce.jquery.js 20 | js/tinymce/plugins/table/plugin.js 21 | js/tinymce/plugins/spellchecker/plugin.js 22 | js/tinymce/plugins/paste/plugin.js 23 | js/tinymce/plugins/imagetools/plugin.js 24 | js/tinymce/plugins/codesample/plugin.js 25 | js/tinymce/themes/inlite/theme.js 26 | imagemanager 27 | filemanager 28 | mcmanager 29 | powerpaste 30 | tinymcespellchecker 31 | a11ychecker 32 | codemirror 33 | mentions 34 | *.min.js 35 | *.dev.js 36 | *.full.js 37 | *.min.css 38 | *.dev.less 39 | skin.less 40 | skin.ie7.less 41 | skin.ie7.dev.less 42 | **/bolt/bootstrap*.js 43 | **/dist 44 | **/scratch 45 | **/lib 46 | **/dependency 47 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/Path.less: -------------------------------------------------------------------------------- 1 | // Path 2 | 3 | .@{prefix}-path { 4 | .inline-block(); 5 | padding: 8px; 6 | white-space: normal; 7 | } 8 | 9 | .@{prefix}-path .@{prefix}-txt { 10 | display: inline-block; 11 | padding-right: 3px; 12 | } 13 | 14 | .@{prefix}-path .@{prefix}-path-body { 15 | display: inline-block; 16 | } 17 | 18 | .@{prefix}-path-item { 19 | .inline-block(); 20 | cursor: pointer; 21 | color: @path-text; 22 | } 23 | 24 | .@{prefix}-path-item:hover { 25 | text-decoration: underline; 26 | } 27 | 28 | .@{prefix}-path-item:focus { 29 | background: @path-bg-focus; 30 | color: @path-text-focus; 31 | } 32 | 33 | .@{prefix}-path .@{prefix}-divider { 34 | display: inline; 35 | } 36 | 37 | .@{prefix}-disabled .@{prefix}-path-item { 38 | color: @text-disabled; 39 | } 40 | 41 | // RTL 42 | 43 | .@{prefix}-rtl .@{prefix}-path { 44 | direction: rtl; 45 | } 46 | -------------------------------------------------------------------------------- /tests/js/module_loader.js: -------------------------------------------------------------------------------- 1 | (function(exports) { 2 | exports.AMDLC_TESTS = true; 3 | 4 | function resolve(id) { 5 | var i, target = exports, fragments = id.split(/[.\/]/); 6 | 7 | for (i = 0; i < fragments.length; i++) { 8 | if (!target[fragments[i]]) { 9 | return; 10 | } 11 | 12 | target = target[fragments[i]]; 13 | } 14 | 15 | return target; 16 | } 17 | 18 | function require(ids, callback) { 19 | var i, module, defs = [], privateModules = exports.privateModules || {}; 20 | 21 | for (i = 0; i < ids.length; i++) { 22 | module = privateModules[ids[i]] || resolve(ids[i]); 23 | 24 | if (!module) { 25 | throw 'module definition dependency not found: ' + ids[i]; 26 | } 27 | 28 | defs.push(module); 29 | } 30 | 31 | callback.apply(null, defs); 32 | } 33 | 34 | exports.ModuleLoader = { 35 | require: require 36 | }; 37 | })(this); 38 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/FlowLayout.less: -------------------------------------------------------------------------------- 1 | // FlowLayout 2 | 3 | .@{prefix}-flow-layout-item { 4 | .inline-block(); 5 | } 6 | 7 | .@{prefix}-flow-layout-item { 8 | margin: @flow-layout-spacing 0 @flow-layout-spacing @flow-layout-spacing; 9 | } 10 | 11 | .@{prefix}-flow-layout-item.@{prefix}-last { 12 | margin-right: @flow-layout-spacing; 13 | } 14 | 15 | .@{prefix}-flow-layout { 16 | white-space: normal; 17 | } 18 | 19 | .@{prefix}-tinymce-inline .@{prefix}-flow-layout { 20 | white-space: nowrap; 21 | } 22 | 23 | // RTL 24 | 25 | .@{prefix}-rtl .@{prefix}-flow-layout { 26 | text-align: right; 27 | direction: rtl; 28 | } 29 | 30 | .@{prefix}-rtl .@{prefix}-flow-layout-item { 31 | margin: @flow-layout-spacing @flow-layout-spacing @flow-layout-spacing 0; 32 | } 33 | 34 | .@{prefix}-rtl .@{prefix}-flow-layout-item.@{prefix}-last { 35 | margin-left: @flow-layout-spacing; 36 | } 37 | -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/main/js/tinymce/inlite/alien/Uuid.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Uuid.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2016 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * Generates unique ids this is the same as in core but since 13 | * it's not exposed as a global we can't access it. 14 | */ 15 | define("tinymce/inlite/alien/Uuid", [ 16 | ], function() { 17 | var count = 0; 18 | 19 | var seed = function () { 20 | var rnd = function () { 21 | return Math.round(Math.random() * 0xFFFFFFFF).toString(36); 22 | }; 23 | 24 | return 's' + Date.now().toString(36) + rnd() + rnd() + rnd(); 25 | }; 26 | 27 | var uuid = function (prefix) { 28 | return prefix + (count++) + seed(); 29 | }; 30 | 31 | return { 32 | uuid: uuid 33 | }; 34 | }); 35 | -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/main/js/tinymce/inlite/core/PredicateId.js: -------------------------------------------------------------------------------- 1 | /** 2 | * PredicateId.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2016 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | define('tinymce/inlite/core/PredicateId', [ 12 | 'global!tinymce.util.Tools' 13 | ], function (Tools) { 14 | var create = function (id, predicate) { 15 | return { 16 | id: id, 17 | predicate: predicate 18 | }; 19 | }; 20 | 21 | // fromContextToolbars :: [ContextToolbar] -> [PredicateId] 22 | var fromContextToolbars = function (toolbars) { 23 | return Tools.map(toolbars, function (toolbar) { 24 | return create(toolbar.id, toolbar.predicate); 25 | }); 26 | }; 27 | 28 | return { 29 | create: create, 30 | fromContextToolbars: fromContextToolbars 31 | }; 32 | }); 33 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/Scrollable.less: -------------------------------------------------------------------------------- 1 | // Scrollbar 2 | 3 | .@{prefix}-scrollbar { 4 | position: absolute; 5 | width: 7px; 6 | height: 100%; 7 | top: 2px; 8 | right: 2px; 9 | .opacity(0.4); 10 | } 11 | 12 | .@{prefix}-scrollbar-h { 13 | top: auto; 14 | right: auto; 15 | left: 2px; 16 | bottom: 2px; 17 | width: 100%; 18 | height: 7px; 19 | } 20 | 21 | .@{prefix}-scrollbar-thumb { 22 | position: absolute; 23 | background-color: #000; 24 | border: 1px solid #888; 25 | border-color: rgba(85, 85, 85, .6); 26 | width: 5px; 27 | height: 100%; 28 | .border-radius(7px); 29 | } 30 | 31 | .@{prefix}-scrollbar-h .@{prefix}-scrollbar-thumb { 32 | width: 100%; 33 | height: 5px; 34 | } 35 | 36 | .@{prefix}-scrollbar:hover, .@{prefix}-scrollbar.@{prefix}-active { 37 | background-color: #AAA; 38 | .opacity(0.6); 39 | .border-radius(7px); 40 | } 41 | 42 | .@{prefix}-scroll { 43 | position: relative; 44 | } 45 | -------------------------------------------------------------------------------- /tests/tinymce/ui/AbsoluteLayout.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | module("tinymce.ui.AbsoluteLayout", { 3 | setup: function() { 4 | document.getElementById('view').innerHTML = ''; 5 | }, 6 | 7 | teardown: function() { 8 | tinymce.dom.Event.clean(document.getElementById('view')); 9 | } 10 | }); 11 | 12 | function createPanel(settings) { 13 | return tinymce.ui.Factory.create(tinymce.extend({ 14 | type: 'panel', 15 | layout: 'absolute', 16 | width: 200, 17 | height: 200 18 | }, settings)).renderTo(document.getElementById('view')).reflow(); 19 | } 20 | 21 | test("spacer x:10, y:20, minWidth: 100, minHeight: 100", function() { 22 | var panel = createPanel({ 23 | items: [ 24 | {type: 'spacer', x: 10, y: 20, w: 100, h: 120, classes: 'red'} 25 | ] 26 | }); 27 | 28 | deepEqual(Utils.rect(panel), [0, 0, 200, 200]); 29 | deepEqual(Utils.rect(panel.find('spacer')[0]), [10, 20, 100, 120]); 30 | }); 31 | })(); -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/TabPanel.less: -------------------------------------------------------------------------------- 1 | // TabPanel 2 | 3 | .@{prefix}-tabs { 4 | display: block; 5 | border-bottom: 1px solid @tab-border; 6 | } 7 | 8 | .@{prefix}-tabs, 9 | .@{prefix}-tabs + .@{prefix}-container-body { 10 | background: @tabs-bg; 11 | } 12 | 13 | .@{prefix}-tab { 14 | .inline-block(); 15 | border: 1px solid @tab-border; 16 | border-width: 0 1px 0 0; 17 | background: @tab-bg; 18 | padding: 8px; 19 | text-shadow: @text-shadow; 20 | height: 13px; 21 | cursor: pointer; 22 | } 23 | 24 | .@{prefix}-tab:hover { 25 | background: @tab-bg-hover; 26 | } 27 | 28 | .@{prefix}-tab.@{prefix}-active { 29 | background: @tab-bg-active; 30 | border-bottom-color: transparent; 31 | margin-bottom: -1px; 32 | height: 14px; 33 | } 34 | 35 | // RTL 36 | 37 | .@{prefix}-rtl .@{prefix}-tabs { 38 | text-align: right; 39 | direction: rtl; 40 | } 41 | 42 | .@{prefix}-rtl .@{prefix}-tab { 43 | border-width: 0 0 0 1px; 44 | } 45 | -------------------------------------------------------------------------------- /tests/tinymce/ui/TextBox.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | module("tinymce.ui.TextBox", { 3 | setup: function() { 4 | document.getElementById('view').innerHTML = ''; 5 | }, 6 | 7 | teardown: function() { 8 | tinymce.dom.Event.clean(document.getElementById('view')); 9 | } 10 | }); 11 | 12 | function createTextBox(settings) { 13 | return tinymce.ui.Factory.create(tinymce.extend({ 14 | type: 'textbox' 15 | }, settings)).renderTo(document.getElementById('view')); 16 | } 17 | 18 | test("textbox text, size chars: 5", function() { 19 | var textBox1 = createTextBox({text: 'X', size: 5}); 20 | var textBox2 = createTextBox({text: 'X', size: 6}); 21 | 22 | ok(Utils.size(textBox1)[0] < Utils.size(textBox2)[0]); 23 | }); 24 | 25 | test("textbox text, size 100x100", function() { 26 | var textBox = createTextBox({text: 'X', width: 100, height: 100}); 27 | 28 | deepEqual(Utils.size(textBox), [100, 100]); 29 | }); 30 | })(); 31 | -------------------------------------------------------------------------------- /tools/docs/tinymce.ResizeEvent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This class is the event object sent when objects gets resized within the editor. 3 | * 4 | * @class tinymce.ResizeEvent 5 | * @extends tinymce.Event 6 | * @example 7 | * tinymce.activeEditor.on('ObjectResizeStart', function(e) { 8 | * if (e.target.nodeName == 'IMG') { 9 | * // Prevent resize 10 | * e.preventDefault(); 11 | * } 12 | * }); 13 | * 14 | * tinymce.activeEditor.on('ObjectResized', function(e) { 15 | * console.log(e.target, e.width, e.height); 16 | * }); 17 | */ 18 | 19 | /** 20 | * Current element that is to be resized or has been resized. 21 | * 22 | * @property {DOMElement} target 23 | */ 24 | 25 | /** 26 | * Current width of the object before or after resize. 27 | * 28 | * @property {Number} width 29 | */ 30 | 31 | /** 32 | * Current height of the object before or after resize. 33 | * 34 | * @property {Number} height 35 | */ 36 | -------------------------------------------------------------------------------- /js/tinymce/plugins/example_dependency/plugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * plugin.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /*jshint unused:false */ 12 | /*global tinymce:true */ 13 | 14 | /** 15 | * Register the plugin, specifying the list of the plugins that this plugin depends on. They are specified in a list, 16 | * with the list loaded in order. plugins in this list will be initialised when this plugin is initialized. (before the 17 | * init method is called). plugins in a depends list should typically be specified using the short name). If necessary 18 | * this can be done with an object which has the url to the plugin and the shortname. 19 | */ 20 | tinymce.PluginManager.add('example_dependency', function() { 21 | // Example logic here 22 | }, ['example']); 23 | -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/main/js/tinymce/inlite/core/Convert.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Convert.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2016 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | define('tinymce/inlite/core/Convert', [ 12 | ], function () { 13 | var fromClientRect = function (clientRect) { 14 | return { 15 | x: clientRect.left, 16 | y: clientRect.top, 17 | w: clientRect.width, 18 | h: clientRect.height 19 | }; 20 | }; 21 | 22 | var toClientRect = function (geomRect) { 23 | return { 24 | left: geomRect.x, 25 | top: geomRect.y, 26 | width: geomRect.w, 27 | height: geomRect.h, 28 | right: geomRect.x + geomRect.w, 29 | bottom: geomRect.y + geomRect.h 30 | }; 31 | }; 32 | 33 | return { 34 | fromClientRect: fromClientRect, 35 | toClientRect: toClientRect 36 | }; 37 | }); 38 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/ComboBox.less: -------------------------------------------------------------------------------- 1 | // ComboBox 2 | 3 | .@{prefix}-combobox { 4 | .inline-block(); 5 | .border-radius(3px); 6 | .box-shadow(@textbox-box-shadow); 7 | *height: 32px; 8 | } 9 | 10 | .@{prefix}-combobox input { 11 | border: 1px solid @textbox-border; 12 | border-right-color: @combobox-border; 13 | height: 28px; 14 | } 15 | 16 | .@{prefix}-combobox.@{prefix}-disabled input { 17 | color: mix(@text, @textbox-bg, 40%); 18 | } 19 | 20 | .@{prefix}-combobox.@{prefix}-has-open input { 21 | .border-radius(4px 0 0 4px); 22 | } 23 | 24 | .@{prefix}-combobox .@{prefix}-btn { 25 | border: 1px solid @textbox-border; 26 | border-left: 0; 27 | .border-radius(0 4px 4px 0); 28 | } 29 | 30 | .@{prefix}-combobox button { 31 | padding-right: 8px; 32 | padding-left: 8px; 33 | } 34 | 35 | .@{prefix}-combobox.@{prefix}-disabled .@{prefix}-btn button { 36 | cursor: default; 37 | .box-shadow(none); 38 | .opacity(@btn-box-disabled-opacity); 39 | } 40 | -------------------------------------------------------------------------------- /js/tinymce/classes/util/JSONP.js: -------------------------------------------------------------------------------- 1 | /** 2 | * JSONP.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | define("tinymce/util/JSONP", [ 12 | "tinymce/dom/DOMUtils" 13 | ], function(DOMUtils) { 14 | return { 15 | callbacks: {}, 16 | count: 0, 17 | 18 | send: function(settings) { 19 | var self = this, dom = DOMUtils.DOM, count = settings.count !== undefined ? settings.count : self.count; 20 | var id = 'tinymce_jsonp_' + count; 21 | 22 | self.callbacks[count] = function(json) { 23 | dom.remove(id); 24 | delete self.callbacks[count]; 25 | 26 | settings.callback(json); 27 | }; 28 | 29 | dom.add(dom.doc.body, 'script', { 30 | id: id, 31 | src: settings.url, 32 | type: 'text/javascript' 33 | }); 34 | 35 | self.count++; 36 | } 37 | }; 38 | }); -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/main/js/tinymce/inlite/core/Matcher.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Matcher.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2016 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | define('tinymce/inlite/core/Matcher', [ 12 | ], function () { 13 | // result :: String, Rect -> Matcher.result 14 | var result = function (id, rect) { 15 | return { 16 | id: id, 17 | rect: rect 18 | }; 19 | }; 20 | 21 | // match :: Editor, [(Editor -> Matcher.result | Null)] -> Matcher.result | Null 22 | var match = function (editor, matchers) { 23 | for (var i = 0; i < matchers.length; i++) { 24 | var f = matchers[i]; 25 | var result = f(editor); 26 | 27 | if (result) { 28 | return result; 29 | } 30 | } 31 | 32 | return null; 33 | }; 34 | 35 | return { 36 | match: match, 37 | result: result 38 | }; 39 | }); 40 | -------------------------------------------------------------------------------- /tests/manual/jquery.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | jQuery test file 5 | 6 | 7 | 8 | 15 | 16 | 17 |
18 |
19 |
20 | 21 |
22 | 23 |
24 | 25 |
26 | 27 | 28 |
29 |
30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/tinymce/caret/LineUtils.js: -------------------------------------------------------------------------------- 1 | ModuleLoader.require([ 2 | "tinymce/Env", 3 | "tinymce/caret/LineUtils" 4 | ], function(Env, LineUtils) { 5 | module("tinymce.caret.LineUtils"); 6 | 7 | if (!Env.ceFalse) { 8 | return; 9 | } 10 | 11 | function rect(x, y, w, h) { 12 | return { 13 | left: x, 14 | top: y, 15 | bottom: y + h, 16 | right: x + w, 17 | width: w, 18 | height: h 19 | }; 20 | } 21 | 22 | test('findClosestClientRect', function() { 23 | deepEqual(LineUtils.findClosestClientRect([rect(10, 10, 10, 10), rect(30, 10, 10, 10)], 15), rect(10, 10, 10, 10)); 24 | deepEqual(LineUtils.findClosestClientRect([rect(10, 10, 10, 10), rect(30, 10, 10, 10)], 27), rect(30, 10, 10, 10)); 25 | deepEqual(LineUtils.findClosestClientRect([rect(10, 10, 10, 10), rect(30, 10, 10, 10)], 23), rect(10, 10, 10, 10)); 26 | deepEqual(LineUtils.findClosestClientRect([rect(10, 10, 10, 10), rect(20, 10, 10, 10)], 13), rect(10, 10, 10, 10)); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /tests/tinymce/ui/Panel.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var panel; 3 | 4 | module("tinymce.ui.Panel", { 5 | setup: function() { 6 | document.getElementById('view').innerHTML = ''; 7 | }, 8 | 9 | teardown: function() { 10 | tinymce.dom.Event.clean(document.getElementById('view')); 11 | } 12 | }); 13 | 14 | function createPanel(settings) { 15 | return tinymce.ui.Factory.create(tinymce.extend({ 16 | type: 'panel' 17 | }, settings)).renderTo(document.getElementById('view')).reflow(); 18 | } 19 | 20 | test("panel width: 100, height: 100", function() { 21 | panel = createPanel({ 22 | width: 100, 23 | height: 100 24 | }); 25 | 26 | Utils.nearlyEqualRects(Utils.rect(panel), [0, 0, 100, 100], 4); 27 | }); 28 | 29 | test("panel border: 1, width: 100, height: 100", function() { 30 | panel = createPanel({ 31 | width: 100, 32 | height: 100, 33 | border: 1 34 | }); 35 | 36 | Utils.nearlyEqualRects(Utils.rect(panel), [0, 0, 100, 100], 4); 37 | }); 38 | })(); 39 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/Menu.less: -------------------------------------------------------------------------------- 1 | // Menu 2 | 3 | .@{prefix}-menu { 4 | position: absolute; 5 | left: 0; top: 0; 6 | .reset-gradient(); 7 | z-index: 1000; 8 | padding: 5px 0 5px 0; 9 | margin: @menu-margin; 10 | min-width: 160px; 11 | background: @menu-bg; 12 | border: 1px solid mix(rgb(red(@menu-border), green(@menu-border), blue(@menu-border)), @panel-bg, round(alpha(@menu-border) * 200)); 13 | border: 1px solid @menu-border; 14 | z-index: 1002; 15 | .border-radius(6px); 16 | .box-shadow(0 5px 10px rgba(0,0,0,.2)); 17 | max-height: 400px; 18 | overflow: auto; 19 | overflow-x: hidden; 20 | } 21 | 22 | .@{prefix}-menu i { 23 | display: none; 24 | } 25 | 26 | .@{prefix}-menu-has-icons i { 27 | display: inline-block; 28 | *display: inline; 29 | } 30 | 31 | .@{prefix}-menu-sub-tr-tl { margin: -6px 0 0 -1px; } 32 | .@{prefix}-menu-sub-br-bl { margin: 6px 0 0 -1px; } 33 | .@{prefix}-menu-sub-tl-tr { margin: -6px 0 0 1px; } 34 | .@{prefix}-menu-sub-bl-br { margin: 6px 0 0 1px; } 35 | -------------------------------------------------------------------------------- /tests/plugins/jquery_initialization.js: -------------------------------------------------------------------------------- 1 | module("tinymce.plugins.jQueryInitialization", { 2 | setupModule: function() { 3 | document.getElementById('view').innerHTML = ( 4 | '' + 5 | '' 6 | ); 7 | 8 | this.val = $.fn.val; 9 | 10 | QUnit.stop(); 11 | 12 | $(function() { 13 | QUnit.start(); 14 | }); 15 | }, 16 | 17 | teardown: function() { 18 | $.fn.val = this.val; 19 | } 20 | }); 21 | 22 | test("applyPatch is only called once", function() { 23 | expect(1); 24 | 25 | var options = {plugins: [ 26 | "pagebreak,layer,table,save,emoticons,insertdatetime,preview,media,searchreplace", 27 | "print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,template" 28 | ]}, 29 | oldValFn; 30 | 31 | $('#elm1').tinymce(options); 32 | 33 | oldValFn = $.fn.val = function() { 34 | // no-op 35 | }; 36 | 37 | $('#elm2').tinymce(options); 38 | 39 | equal($.fn.val, oldValFn); 40 | }); 41 | -------------------------------------------------------------------------------- /js/tinymce/classes/util/VK.js: -------------------------------------------------------------------------------- 1 | /** 2 | * VK.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * This file exposes a set of the common KeyCodes for use. Please grow it as needed. 13 | */ 14 | define("tinymce/util/VK", [ 15 | "tinymce/Env" 16 | ], function(Env) { 17 | return { 18 | BACKSPACE: 8, 19 | DELETE: 46, 20 | DOWN: 40, 21 | ENTER: 13, 22 | LEFT: 37, 23 | RIGHT: 39, 24 | SPACEBAR: 32, 25 | TAB: 9, 26 | UP: 38, 27 | 28 | modifierPressed: function(e) { 29 | return e.shiftKey || e.ctrlKey || e.altKey || this.metaKeyPressed(e); 30 | }, 31 | 32 | metaKeyPressed: function(e) { 33 | // Check if ctrl or meta key is pressed. Edge case for AltGr on Windows where it produces ctrlKey+altKey states 34 | return (Env.mac ? e.metaKey : e.ctrlKey && !e.altKey); 35 | } 36 | }; 37 | }); 38 | -------------------------------------------------------------------------------- /js/tinymce/classes/ui/Spacer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Spacer.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * Creates a spacer. This control is used in flex layouts for example. 13 | * 14 | * @-x-less Spacer.less 15 | * @class tinymce.ui.Spacer 16 | * @extends tinymce.ui.Widget 17 | */ 18 | define("tinymce/ui/Spacer", [ 19 | "tinymce/ui/Widget" 20 | ], function(Widget) { 21 | "use strict"; 22 | 23 | return Widget.extend({ 24 | /** 25 | * Renders the control as a HTML string. 26 | * 27 | * @method renderHtml 28 | * @return {String} HTML representing the control. 29 | */ 30 | renderHtml: function() { 31 | var self = this; 32 | 33 | self.classes.add('spacer'); 34 | self.canFocus = false; 35 | 36 | return '
'; 37 | } 38 | }); 39 | }); -------------------------------------------------------------------------------- /tests/tinymce/util/Promise.js: -------------------------------------------------------------------------------- 1 | ModuleLoader.require(["tinymce/util/Promise"], function(Promise) { 2 | module("tinymce.util.Promise"); 3 | 4 | asyncTest('Promise resolve', function() { 5 | new Promise(function(resolve) { 6 | resolve("123"); 7 | }).then(function(result) { 8 | equal("123", result); 9 | QUnit.start(); 10 | }); 11 | }); 12 | 13 | asyncTest('Promise reject', function() { 14 | new Promise(function(resolve, reject) { 15 | reject("123"); 16 | }).then(function() { 17 | }, function(result) { 18 | equal("123", result); 19 | QUnit.start(); 20 | }); 21 | }); 22 | 23 | asyncTest('Promise reject', function() { 24 | var promises = [ 25 | new Promise(function(resolve) { 26 | resolve("123"); 27 | }), 28 | 29 | new Promise(function(resolve) { 30 | resolve("456"); 31 | }) 32 | ]; 33 | 34 | Promise.all(promises).then(function(results) { 35 | equal("123", results[0]); 36 | equal("456", results[1]); 37 | QUnit.start(); 38 | }); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /tests/tinymce/util/XHR.js: -------------------------------------------------------------------------------- 1 | if (location.protocol != "file:") { 2 | module("tinymce.util.XHR"); 3 | 4 | asyncTest("Successful request", function() { 5 | expect(5); 6 | 7 | tinymce.util.XHR.on('beforeSend', function(e) { 8 | e.xhr.test = 123; 9 | e.settings.test = 456; 10 | }); 11 | 12 | tinymce.util.XHR.send({ 13 | url: 'tinymce/util/json_rpc_ok.js', 14 | success: function(data, xhr, input) { 15 | equal(tinymce.trim(data), '{"result": "Hello JSON-RPC", "error": null, "id": 1}'); 16 | ok(!!xhr.status); 17 | equal(input.url, 'tinymce/util/json_rpc_ok.js'); 18 | equal(xhr.test, 123); 19 | equal(input.test, 456); 20 | start(); 21 | } 22 | }); 23 | }); 24 | 25 | asyncTest("Unsuccessful request", function() { 26 | expect(3); 27 | 28 | tinymce.util.XHR.send({ 29 | url: 'tinymce/util/404.js', 30 | error: function(type, xhr, input) { 31 | equal(type, 'GENERAL'); 32 | ok(!!xhr.status); 33 | equal(input.url, 'tinymce/util/404.js'); 34 | start(); 35 | } 36 | }); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /tests/tinymce/WindowManager.js: -------------------------------------------------------------------------------- 1 | ModuleLoader.require([ 2 | ], function() { 3 | module("tinymce.WindowManager", { 4 | setupModule: function() { 5 | QUnit.stop(); 6 | 7 | tinymce.init({ 8 | selector: "textarea", 9 | add_unload_trigger: false, 10 | disable_nodechange: true, 11 | init_instance_callback: function(ed) { 12 | window.editor = ed; 13 | QUnit.start(); 14 | } 15 | }); 16 | }, 17 | 18 | teardown: function() { 19 | editor.off('CloseWindow OpenWindow'); 20 | } 21 | }); 22 | 23 | test('OpenWindow/CloseWindow events', function() { 24 | var openWindowArgs, closeWindowArgs; 25 | 26 | editor.on('CloseWindow', function(e) { 27 | closeWindowArgs = e; 28 | }); 29 | 30 | editor.on('OpenWindow', function(e) { 31 | openWindowArgs = e; 32 | e.win.close(); 33 | }); 34 | 35 | editor.windowManager.alert('test'); 36 | 37 | equal(openWindowArgs.type, 'openwindow'); 38 | equal(closeWindowArgs.type, 'closewindow'); 39 | equal(editor.windowManager.getWindows().length, 0); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tinymce", 3 | "version": "4.4.1", 4 | "repository": { 5 | "type": "git", 6 | "url": "https://github.com/tinymce/tinymce.git" 7 | }, 8 | "description": "TinyMCE rich text editor", 9 | "author": "Johan Sörlin ", 10 | "bugs": { 11 | "url": "http://www.tinymce.com/develop/bugtracker.php" 12 | }, 13 | "private": true, 14 | "engines": { 15 | "node": ">=0.10.26" 16 | }, 17 | "devDependencies": { 18 | "@ephox/bolt": "^1.6.0", 19 | "@ephox/imagetools": "1.0.6", 20 | "grunt": "~0.4.5", 21 | "grunt-contrib-clean": "~0.6.0", 22 | "grunt-contrib-connect": "~0.8.0", 23 | "grunt-contrib-copy": "^0.8.2", 24 | "grunt-contrib-less": "~1.0.0", 25 | "grunt-contrib-qunit": "~0.5.2", 26 | "grunt-contrib-uglify": "~0.5.1", 27 | "grunt-contrib-watch": "~0.6.1", 28 | "grunt-eslint": "~18.0.0", 29 | "grunt-nuget-pack": "^0.0.6", 30 | "grunt-saucelabs": "~8.3.2", 31 | "load-grunt-tasks": "~0.6.0", 32 | "amdlc": "~0.1.3", 33 | "moxie-zip": "~0.0.3", 34 | "jquery": "~1.11.3" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/Reset.less: -------------------------------------------------------------------------------- 1 | // Reset 2 | 3 | .@{prefix}-container, .@{prefix}-container *, .@{prefix}-widget, .@{prefix}-widget *, .@{prefix}-reset { 4 | margin: 0; padding: 0; border: 0; outline: 0; 5 | vertical-align: top; background: transparent; 6 | text-decoration: none; color: @text; 7 | font-family: @font-family; 8 | font-size: @font-size; text-shadow: none; float: none; 9 | position: static; width: auto; height: auto; 10 | white-space: nowrap; cursor: inherit; 11 | -webkit-tap-highlight-color: transparent; 12 | line-height: normal; font-weight: normal; 13 | text-align: left; 14 | -moz-box-sizing: content-box; 15 | -webkit-box-sizing: content-box; 16 | box-sizing: content-box; 17 | direction: ltr; 18 | max-width: none; 19 | } 20 | 21 | .@{prefix}-widget button { 22 | -moz-box-sizing: border-box; 23 | -webkit-box-sizing: border-box; 24 | box-sizing: border-box; 25 | } 26 | 27 | .@{prefix}-container *[unselectable] { 28 | -moz-user-select: none; 29 | -webkit-user-select: none; 30 | -o-user-select: none; 31 | user-select: none; 32 | } 33 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/TextBox.less: -------------------------------------------------------------------------------- 1 | // TextBox 2 | 3 | .@{prefix}-textbox { 4 | background: @textbox-bg; 5 | border: 1px solid @textbox-border; 6 | .border-radius(3px); 7 | .box-shadow(@textbox-box-shadow); 8 | display: inline-block; 9 | .transition(~"border linear .2s, box-shadow linear .2s"); 10 | height: 28px; 11 | resize: none; 12 | padding: 0 4px 0 4px; 13 | white-space: pre-wrap; 14 | *white-space: pre; 15 | color: @text; 16 | } 17 | 18 | .@{prefix}-textbox:focus, .@{prefix}-textbox.@{prefix}-focus { 19 | border-color: @textbox-border-focus; 20 | .box-shadow(inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px fadeout(@textbox-border-focus, 15%)); 21 | } 22 | 23 | .@{prefix}-placeholder .@{prefix}-textbox { 24 | color: @textbox-text-placeholder; 25 | } 26 | 27 | .@{prefix}-textbox.@{prefix}-multiline { 28 | padding: 4px; 29 | height: auto; 30 | } 31 | 32 | .@{prefix}-textbox.@{prefix}-disabled { 33 | color: mix(@text, @textbox-bg, 40%); 34 | } 35 | 36 | // RTL 37 | 38 | .@{prefix}-rtl .@{prefix}-textbox { 39 | text-align: right; 40 | direction: rtl; 41 | } 42 | -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/main/js/tinymce/inlite/file/Picker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Picker.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2016 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | define('tinymce/inlite/file/Picker', [ 12 | 'global!tinymce.util.Promise' 13 | ], function (Promise) { 14 | var pickFile = function () { 15 | return new Promise(function (resolve) { 16 | var fileInput; 17 | 18 | fileInput = document.createElement("input"); 19 | fileInput.type = "file"; 20 | fileInput.style.position = 'fixed'; 21 | fileInput.style.left = 0; 22 | fileInput.style.top = 0; 23 | fileInput.style.opacity = 0.001; 24 | document.body.appendChild(fileInput); 25 | 26 | fileInput.onchange = function(e) { 27 | resolve(Array.prototype.slice.call(e.target.files)); 28 | }; 29 | 30 | fileInput.click(); 31 | fileInput.parentNode.removeChild(fileInput); 32 | }); 33 | }; 34 | 35 | return { 36 | pickFile: pickFile 37 | }; 38 | }); 39 | 40 | 41 | -------------------------------------------------------------------------------- /tests/manual/css/content_editable.css: -------------------------------------------------------------------------------- 1 | .mce-content-body *[contentEditable=true], .mce-content-body *[data-mce-contenteditable=true] { 2 | background: #adffad; 3 | border: 1px solid #999; 4 | } 5 | 6 | .mce-content-body *[contentEditable=false], .mce-content-body *[data-mce-contenteditable=false] { 7 | background: #ffadad; 8 | border: 1px solid #999; 9 | margin: 0 1px 0 2px; 10 | } 11 | 12 | .mce-content-body div[contentEditable=false], .mce-content-body p[contentEditable=false] { 13 | margin: 2px 0 2px 0; 14 | } 15 | 16 | .mce-content-body *[contentEditable]:focus { 17 | outline: 2px dotted blue; 18 | } 19 | 20 | /* Debug overrides */ 21 | 22 | .mce-visual-caret { 23 | outline: 2px solid red; 24 | } 25 | 26 | .mce-visual-caret-before { 27 | outline: 2px solid green; 28 | } 29 | 30 | .mce-content-body *[data-mce-selected] { 31 | outline: 2px solid blue; 32 | } 33 | 34 | .mce-content-body .mce-offscreen-selection { 35 | left: auto; 36 | right: 0; 37 | } 38 | 39 | *[data-mce-caret] { 40 | outline: 1px solid green; 41 | position: absolute; 42 | left: auto; 43 | right: 0; 44 | top: 0; 45 | margin: 0; 46 | padding: 0; 47 | } 48 | -------------------------------------------------------------------------------- /tests/js/qunit/QUnit.LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 John Resig, http://jquery.com/ 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /tests/tinymce/dom/NodePath.js: -------------------------------------------------------------------------------- 1 | ModuleLoader.require([ 2 | "tinymce/dom/NodePath" 3 | ], function(NodePath) { 4 | module("tinymce.dom.NodePath", {}); 5 | 6 | function getRoot() { 7 | return document.getElementById('view'); 8 | } 9 | 10 | function setupHtml(html) { 11 | getRoot().innerHTML = html; 12 | } 13 | 14 | test("create", function() { 15 | setupHtml('

a12

'); 16 | 17 | deepEqual(NodePath.create(getRoot(), getRoot().firstChild), [0]); 18 | deepEqual(NodePath.create(getRoot(), getRoot().firstChild.firstChild), [0, 0]); 19 | deepEqual(NodePath.create(getRoot(), getRoot().firstChild.lastChild.lastChild), [1, 1, 0]); 20 | }); 21 | 22 | test("resolve", function() { 23 | setupHtml('

a12

'); 24 | 25 | deepEqual(NodePath.resolve(getRoot(), NodePath.create(getRoot(), getRoot().firstChild)), getRoot().firstChild); 26 | deepEqual(NodePath.resolve(getRoot(), NodePath.create(getRoot(), getRoot().firstChild.firstChild)), getRoot().firstChild.firstChild); 27 | deepEqual(NodePath.resolve(getRoot(), NodePath.create(getRoot(), getRoot().firstChild.lastChild.lastChild)), getRoot().firstChild.lastChild.lastChild); 28 | }); 29 | }); -------------------------------------------------------------------------------- /tests/tinymce/util/JSON.js: -------------------------------------------------------------------------------- 1 | module("tinymce.util.JSON"); 2 | 3 | test('serialize', 2, function() { 4 | equal( 5 | tinymce.util.JSON.serialize({ 6 | arr1 : [1, 2, 3, [1, 2, 3]], 7 | bool1 : true, 8 | float1: 3.14, 9 | int1 : 123, 10 | null1 : null, 11 | obj1 : {key1 : "val1", key2 : "val2"}, str1 : '\"\'abc\u00C5123\\'} 12 | ), 13 | '{"arr1":[1,2,3,[1,2,3]],"bool1":true,"float1":3.14,"int1":123,"null1":null,"obj1":{"key1":"val1","key2":"val2"},"str1":"\\"\'abc\\u00c5123\\\\"}' 14 | ); 15 | 16 | equal( 17 | tinymce.util.JSON.serialize({ 18 | arr1 : [1, 2, 3, [1, 2, 3]], 19 | bool1 : true, 20 | float1: 3.14, 21 | int1 : 123, 22 | null1 : null, 23 | obj1 : {key1 : "val1", key2 : "val2"}, str1 : '\"\'abc\u00C5123'}, "'" 24 | ), 25 | "{'arr1':[1,2,3,[1,2,3]],'bool1':true,'float1':3.14,'int1':123,'null1':null,'obj1':{'key1':'val1','key2':'val2'},'str1':'\\\"\\'abc\\u00c5123'}" 26 | ); 27 | }); 28 | 29 | test('parse', 1, function() { 30 | equal(tinymce.util.JSON.parse('{"arr1":[1,2,3,[1,2,3]],"bool1":true,"float1":3.14,"int1":123,"null1":null,"obj1":{"key1":"val1","key2":"val2"},"str1":"abc\\u00c5123"}').str1, 'abc\u00c5123'); 31 | }); 32 | -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/test/js/atomic/core/MatcherTest.js: -------------------------------------------------------------------------------- 1 | test('browser/atomic/MatcherTest', [ 2 | 'tinymce/inlite/core/Matcher' 3 | ], function (Matcher) { 4 | var testMatch = function (mockEditor, matches, expectedResult) { 5 | var result; 6 | 7 | result = Matcher.match(mockEditor, matches); 8 | assert.eq(expectedResult, result); 9 | }; 10 | 11 | var match = function (key) { 12 | return function (editor) { 13 | return editor[key]; 14 | }; 15 | }; 16 | 17 | var testMatcher = function () { 18 | var mockEditor = { 19 | success1: 'success1', 20 | success2: 'success2', 21 | failure: null 22 | }; 23 | 24 | testMatch(mockEditor, [ 25 | match('success1') 26 | ], 'success1'); 27 | 28 | testMatch(mockEditor, [ 29 | match(null), 30 | match('success2') 31 | ], 'success2'); 32 | 33 | testMatch(mockEditor, [ 34 | match('success1'), 35 | match('success2') 36 | ], 'success1'); 37 | 38 | testMatch(mockEditor, [ 39 | match(null) 40 | ], null); 41 | 42 | testMatch(mockEditor, [ 43 | match(null), 44 | match(null) 45 | ], null); 46 | 47 | testMatch(mockEditor, [], null); 48 | }; 49 | 50 | testMatcher(); 51 | }); 52 | -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/main/js/tinymce/inlite/core/SkinLoader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * SkinLoader.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2016 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | define('tinymce/inlite/core/SkinLoader', [ 12 | 'global!tinymce.EditorManager', 13 | 'global!tinymce.DOM' 14 | ], function (EditorManager, DOM) { 15 | var fireSkinLoaded = function (editor, callback) { 16 | var done = function () { 17 | editor.fire('SkinLoaded'); 18 | callback(); 19 | }; 20 | 21 | if (editor.initialized) { 22 | done(); 23 | } else { 24 | editor.on('init', done); 25 | } 26 | }; 27 | 28 | var load = function (editor, skin, callback) { 29 | var baseUrl = EditorManager.baseURL; 30 | var skinUrl = baseUrl + '/skins/' + skin; 31 | 32 | var done = function () { 33 | fireSkinLoaded(editor, callback); 34 | }; 35 | 36 | DOM.styleSheetLoader.load(skinUrl + '/skin.min.css', done); 37 | editor.contentCSS.push(skinUrl + '/content.inline.min.css'); 38 | }; 39 | 40 | return { 41 | load: load 42 | }; 43 | }); 44 | 45 | 46 | -------------------------------------------------------------------------------- /js/tinymce/plugins/imagetools/src/main/js/UndoStack.js: -------------------------------------------------------------------------------- 1 | /** 2 | * UndoStack.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2016 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | define("tinymce/imagetoolsplugin/UndoStack", [ 12 | ], function() { 13 | return function() { 14 | var data = [], index = -1; 15 | 16 | function add(state) { 17 | var removed; 18 | 19 | removed = data.splice(++index); 20 | data.push(state); 21 | 22 | return { 23 | state: state, 24 | removed: removed 25 | }; 26 | } 27 | 28 | function undo() { 29 | if (canUndo()) { 30 | return data[--index]; 31 | } 32 | } 33 | 34 | function redo() { 35 | if (canRedo()) { 36 | return data[++index]; 37 | } 38 | } 39 | 40 | function canUndo() { 41 | return index > 0; 42 | } 43 | 44 | function canRedo() { 45 | return index != -1 && index < data.length - 1; 46 | } 47 | 48 | return { 49 | data: data, 50 | add: add, 51 | undo: undo, 52 | redo: redo, 53 | canUndo: canUndo, 54 | canRedo: canRedo 55 | }; 56 | }; 57 | }); 58 | -------------------------------------------------------------------------------- /js/tinymce/classes/dom/NodePath.js: -------------------------------------------------------------------------------- 1 | /** 2 | * NodePath.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * Handles paths of nodes within an element. 13 | * 14 | * @private 15 | * @class tinymce.dom.NodePath 16 | */ 17 | define("tinymce/dom/NodePath", [ 18 | "tinymce/dom/DOMUtils" 19 | ], function(DOMUtils) { 20 | function create(rootNode, targetNode, normalized) { 21 | var path = []; 22 | 23 | for (; targetNode && targetNode != rootNode; targetNode = targetNode.parentNode) { 24 | path.push(DOMUtils.nodeIndex(targetNode, normalized)); 25 | } 26 | 27 | return path; 28 | } 29 | 30 | function resolve(rootNode, path) { 31 | var i, node, children; 32 | 33 | for (node = rootNode, i = path.length - 1; i >= 0; i--) { 34 | children = node.childNodes; 35 | 36 | if (path[i] > children.length - 1) { 37 | return null; 38 | } 39 | 40 | node = children[path[i]]; 41 | } 42 | 43 | return node; 44 | } 45 | 46 | return { 47 | create: create, 48 | resolve: resolve 49 | }; 50 | }); -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/SplitButton.less: -------------------------------------------------------------------------------- 1 | // SplitButton 2 | 3 | .@{prefix}-splitbtn .@{prefix}-open { 4 | border-left: 1px solid transparent; 5 | } 6 | 7 | .@{prefix}-splitbtn:hover .@{prefix}-open { 8 | border-left-color: darken(@btn-bg, 20%); 9 | } 10 | 11 | .@{prefix}-splitbtn button when (@has-button-borders = false) { 12 | padding-right: 6px; 13 | padding-left: 6px; 14 | } 15 | 16 | .@{prefix}-splitbtn button when (@has-button-borders = true) { 17 | padding-right: 4px; 18 | padding-left: 8px; 19 | } 20 | 21 | .@{prefix}-splitbtn .@{prefix}-open { 22 | padding-right: 4px; 23 | padding-left: 4px; 24 | } 25 | 26 | .@{prefix}-splitbtn .@{prefix}-open.@{prefix}-active { 27 | .vertical-gradient(darken(@btn-bg, 10%), darken(@btn-bg-hlight, 5%)); 28 | outline: 1px solid darken(@btn-bg, 20%); 29 | } 30 | 31 | .@{prefix}-splitbtn.@{prefix}-btn-small .@{prefix}-open { 32 | padding: 0 3px 0 3px; 33 | } 34 | 35 | // RTL 36 | 37 | .@{prefix}-rtl .@{prefix}-splitbtn { 38 | direction: rtl; 39 | text-align: right; 40 | } 41 | 42 | .@{prefix}-rtl .@{prefix}-splitbtn button { 43 | padding-right: 4px; 44 | padding-left: 4px; 45 | } 46 | 47 | .@{prefix}-rtl .@{prefix}-splitbtn .@{prefix}-open { 48 | border-left: 0; 49 | } 50 | -------------------------------------------------------------------------------- /js/tinymce/classes/ui/FlowLayout.js: -------------------------------------------------------------------------------- 1 | /** 2 | * FlowLayout.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * This layout manager will place the controls by using the browsers native layout. 13 | * 14 | * @-x-less FlowLayout.less 15 | * @class tinymce.ui.FlowLayout 16 | * @extends tinymce.ui.Layout 17 | */ 18 | define("tinymce/ui/FlowLayout", [ 19 | "tinymce/ui/Layout" 20 | ], function(Layout) { 21 | return Layout.extend({ 22 | Defaults: { 23 | containerClass: 'flow-layout', 24 | controlClass: 'flow-layout-item', 25 | endClass: 'break' 26 | }, 27 | 28 | /** 29 | * Recalculates the positions of the controls in the specified container. 30 | * 31 | * @method recalc 32 | * @param {tinymce.ui.Container} container Container instance to recalc. 33 | */ 34 | recalc: function(container) { 35 | container.items().filter(':visible').each(function(ctrl) { 36 | if (ctrl.recalc) { 37 | ctrl.recalc(); 38 | } 39 | }); 40 | }, 41 | 42 | isNative: function() { 43 | return true; 44 | } 45 | }); 46 | }); -------------------------------------------------------------------------------- /tests/tinymce/dom/Dimensions.js: -------------------------------------------------------------------------------- 1 | ModuleLoader.require([ 2 | "tinymce/util/Arr", 3 | "tinymce/dom/Dimensions" 4 | ], function(Arr, Dimensions) { 5 | module("tinymce.dom.Dimensions"); 6 | 7 | function setupHtml(html) { 8 | var viewElm; 9 | 10 | viewElm = document.getElementById('view'); 11 | viewElm.innerHTML = html; 12 | 13 | return viewElm; 14 | } 15 | 16 | test('getClientRects', function() { 17 | var viewElm = setupHtml('abc123'); 18 | 19 | strictEqual(Dimensions.getClientRects(viewElm.firstChild).length, 1); 20 | strictEqual(Dimensions.getClientRects(viewElm.lastChild).length, 1); 21 | strictEqual(Dimensions.getClientRects(viewElm.firstChild)[0].node, viewElm.firstChild); 22 | strictEqual(Dimensions.getClientRects(viewElm.firstChild)[0].left > 3, true); 23 | strictEqual(Dimensions.getClientRects(viewElm.lastChild)[0].left > 3, true); 24 | }); 25 | 26 | test('getClientRects from array', function() { 27 | var viewElm = setupHtml('ab'), 28 | clientRects = Dimensions.getClientRects(Arr.toArray(viewElm.childNodes)); 29 | 30 | strictEqual(clientRects.length, 2); 31 | strictEqual(clientRects[0].node, viewElm.childNodes[0]); 32 | strictEqual(clientRects[1].node, viewElm.childNodes[1]); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /tests/tinymce/util/Observable.js: -------------------------------------------------------------------------------- 1 | module("tinymce.util.Observable"); 2 | 3 | test("Event bubbling/removed state", function() { 4 | var lastName, lastState, data = ''; 5 | 6 | function Class(parentObj) { 7 | this.toggleNativeEvent = function(name, state) { 8 | lastName = name; 9 | lastState = state; 10 | }; 11 | 12 | this.parent = function() { 13 | return parentObj; 14 | }; 15 | } 16 | 17 | tinymce.util.Tools.extend(Class.prototype, tinymce.util.Observable); 18 | 19 | var inst1 = new Class(); 20 | 21 | inst1.on('click', function() { data += 'a'; }); 22 | strictEqual(lastName, 'click'); 23 | strictEqual(lastState, true); 24 | 25 | lastName = lastState = null; 26 | inst1.on('click', function() { data += 'b'; }); 27 | strictEqual(lastName, null); 28 | strictEqual(lastState, null); 29 | 30 | var inst2 = new Class(inst1); 31 | inst2.on('click', function() { data += 'c'; }); 32 | 33 | inst2.fire('click'); 34 | strictEqual(data, 'cab'); 35 | 36 | inst2.on('click', function(e) { e.stopPropagation(); }); 37 | 38 | inst2.fire('click'); 39 | strictEqual(data, 'cabc'); 40 | 41 | inst1.on('remove', function() { data += 'r'; }); 42 | inst1.removed = true; 43 | inst1.fire('click'); 44 | inst1.fire('remove'); 45 | strictEqual(data, 'cabcr'); 46 | }); 47 | -------------------------------------------------------------------------------- /js/tinymce/classes/ui/Toolbar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Toolbar.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * Creates a new toolbar. 13 | * 14 | * @class tinymce.ui.Toolbar 15 | * @extends tinymce.ui.Container 16 | */ 17 | define("tinymce/ui/Toolbar", [ 18 | "tinymce/ui/Container" 19 | ], function(Container) { 20 | "use strict"; 21 | 22 | return Container.extend({ 23 | Defaults: { 24 | role: 'toolbar', 25 | layout: 'flow' 26 | }, 27 | 28 | /** 29 | * Constructs a instance with the specified settings. 30 | * 31 | * @constructor 32 | * @param {Object} settings Name/value object with settings. 33 | */ 34 | init: function(settings) { 35 | var self = this; 36 | 37 | self._super(settings); 38 | self.classes.add('toolbar'); 39 | }, 40 | 41 | /** 42 | * Called after the control has been rendered. 43 | * 44 | * @method postRender 45 | */ 46 | postRender: function() { 47 | var self = this; 48 | 49 | self.items().each(function(ctrl) { 50 | ctrl.classes.add('toolbar-item'); 51 | }); 52 | 53 | return self._super(); 54 | } 55 | }); 56 | }); -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/test/js/browser/file/ConversionsTest.js: -------------------------------------------------------------------------------- 1 | asynctest('atomic/core/ConvertTest', [ 2 | 'ephox/tinymce', 3 | 'tinymce/inlite/file/Conversions', 4 | 'ephox.agar.api.Step', 5 | 'ephox.agar.api.Pipeline', 6 | 'ephox.agar.api.Assertions' 7 | ], function (tinymce, Conversions, Step, Pipeline, Assertions) { 8 | var success = arguments[arguments.length - 2]; 9 | var failure = arguments[arguments.length - 1]; 10 | 11 | var base64ToBlob = function (base64, type) { 12 | var buff = atob(base64); 13 | var bytes = new Uint8Array(buff.length); 14 | 15 | for (var i = 0; i < bytes.length; i++) { 16 | bytes[i] = buff.charCodeAt(i); 17 | } 18 | 19 | return new Blob([bytes], {type: type}); 20 | }; 21 | 22 | var sBlobToBase64 = function () { 23 | return Step.async(function (next) { 24 | var base64 = 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; 25 | var blob = base64ToBlob(base64, 'image/gif'); 26 | 27 | Conversions.blobToBase64(blob).then(function (convertedBase64) { 28 | Assertions.assertEq('Not the correct base64', base64, convertedBase64); 29 | next(); 30 | }); 31 | }); 32 | }; 33 | 34 | Pipeline.async({}, [ 35 | sBlobToBase64() 36 | ], function () { 37 | success(); 38 | }, function () { 39 | failure(); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/test/js/atomic/core/UrlTypeTest.js: -------------------------------------------------------------------------------- 1 | test('atomic/core/UrlTypeTest', [ 2 | 'tinymce/inlite/core/UrlType' 3 | ], function (UrlType) { 4 | var testIsDomainLike = function () { 5 | var mostUsedTopLevelDomains = [ 6 | 'com', 'org', 'edu', 'gov', 'uk', 'net', 'ca', 'de', 'jp', 7 | 'fr', 'au', 'us', 'ru', 'ch', 'it', 'nl', 'se', 'no', 'es', 'mil' 8 | ]; 9 | 10 | assert.eq(UrlType.isDomainLike('www.site.com'), true); 11 | assert.eq(UrlType.isDomainLike('www.site.xyz'), true); 12 | assert.eq(UrlType.isDomainLike(' www.site.xyz'), true); 13 | assert.eq(UrlType.isDomainLike('site.xyz'), false); 14 | 15 | mostUsedTopLevelDomains.forEach(function (tld) { 16 | assert.eq(UrlType.isDomainLike('site.' + tld), true); 17 | assert.eq(UrlType.isDomainLike(' site.' + tld), true); 18 | assert.eq(UrlType.isDomainLike('site.' + tld + ' '), true); 19 | }); 20 | 21 | assert.eq(UrlType.isDomainLike('/a/b'), false); 22 | }; 23 | 24 | var testIsAbsoluteUrl = function () { 25 | assert.eq(UrlType.isAbsolute('http://www.site.com'), true); 26 | assert.eq(UrlType.isAbsolute('https://www.site.com'), true); 27 | assert.eq(UrlType.isAbsolute('www.site.com'), false); 28 | assert.eq(UrlType.isAbsolute('file.gif'), false); 29 | }; 30 | 31 | testIsDomainLike(); 32 | testIsAbsoluteUrl(); 33 | }); 34 | -------------------------------------------------------------------------------- /tests/tinymce/util/Color.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | module("tinymce.util.Color"); 3 | 4 | var Color = tinymce.util.Color; 5 | 6 | test("Constructor", function() { 7 | equal(new Color().toHex(), '#000000'); 8 | equal(new Color('#faebcd').toHex(), '#faebcd'); 9 | }); 10 | 11 | test("parse method", function() { 12 | var color = new Color(); 13 | 14 | equal(color.parse('#faebcd').toHex(), '#faebcd'); 15 | equal(color.parse('#ccc').toHex(), '#cccccc'); 16 | equal(color.parse(' #faebcd ').toHex(), '#faebcd'); 17 | equal(color.parse('rgb(255,254,253)').toHex(), '#fffefd'); 18 | equal(color.parse(' rgb ( 255 , 254 , 253 ) ').toHex(), '#fffefd'); 19 | equal(color.parse({r: 255, g: 254, b: 253}).toHex(), '#fffefd'); 20 | equal(color.parse({h: 359, s: 50, v: 50}).toHex(), '#804041'); 21 | equal(color.parse({r: 700, g: 700, b: 700}).toHex(), '#ffffff'); 22 | equal(color.parse({r: -1, g: -10, b: -20}).toHex(), '#000000'); 23 | }); 24 | 25 | test("toRgb method", function() { 26 | deepEqual(new Color('#faebcd').toRgb(), {r: 250, g: 235, b: 205}); 27 | }); 28 | 29 | test("toHsv method", function() { 30 | deepEqual(new Color('#804041').toHsv(), {h: 359, s: 50, v: 50}); 31 | }); 32 | 33 | test("toHex method", function() { 34 | equal(new Color({r: 255, g: 254, b: 253}).toHex(), '#fffefd'); 35 | }); 36 | })(); 37 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/Checkbox.less: -------------------------------------------------------------------------------- 1 | // Checkbox 2 | 3 | .@{prefix}-checkbox { 4 | cursor: pointer; 5 | } 6 | 7 | i.@{prefix}-i-checkbox { 8 | margin: 0 3px 0 0; 9 | border: 1px solid @checkbox-border; 10 | .border-radius(3px); 11 | .box-shadow(@checkbox-box-shadow); 12 | .vertical-gradient(@checkbox-bg, @checkbox-bg-hlight); 13 | text-indent: -10em; 14 | *font-size: 0; 15 | *line-height: 0; 16 | *text-indent: 0; 17 | overflow: hidden; 18 | } 19 | 20 | .@{prefix}-checked i.@{prefix}-i-checkbox { 21 | color: @btn-text; 22 | font-size: 16px; 23 | line-height: 16px; 24 | text-indent: 0; 25 | } 26 | 27 | .@{prefix}-checkbox:focus i.@{prefix}-i-checkbox, .@{prefix}-checkbox.@{prefix}-focus i.@{prefix}-i-checkbox { 28 | border: 1px solid @checkbox-border-focus; 29 | .box-shadow(inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px fadeout(@checkbox-border-focus, 15%)); 30 | } 31 | 32 | .@{prefix}-checkbox.@{prefix}-disabled .@{prefix}-label, .@{prefix}-checkbox.@{prefix}-disabled i.@{prefix}-i-checkbox { 33 | color: mix(@text, @panel-bg, 40%); 34 | } 35 | 36 | .@{prefix}-checkbox .@{prefix}-label { 37 | vertical-align: middle; 38 | } 39 | 40 | // RTL 41 | 42 | .@{prefix}-rtl .@{prefix}-checkbox { 43 | direction: rtl; 44 | text-align: right; 45 | } 46 | 47 | .@{prefix}-rtl i.@{prefix}-i-checkbox { 48 | margin: 0 0 0 3px; 49 | } 50 | -------------------------------------------------------------------------------- /tests/tinymce/file/UploadStatus.js: -------------------------------------------------------------------------------- 1 | ModuleLoader.require([ 2 | "tinymce/file/UploadStatus" 3 | ], function(UploadStatus) { 4 | module("tinymce.file.UploadStatus"); 5 | 6 | QUnit.test("hasBlobUri/markPending", function() { 7 | var status = new UploadStatus(); 8 | 9 | strictEqual(status.hasBlobUri("nonexisting_uri"), false); 10 | status.markPending("existing_uri"); 11 | strictEqual(status.isPending("existing_uri"), true); 12 | strictEqual(status.isUploaded("existing_uri"), false); 13 | strictEqual(status.hasBlobUri("existing_uri"), true); 14 | 15 | status.markUploaded("existing_uri", "uri"); 16 | strictEqual(status.isPending("existing_uri"), false); 17 | strictEqual(status.isUploaded("existing_uri"), true); 18 | strictEqual(status.hasBlobUri("existing_uri"), true); 19 | strictEqual(status.getResultUri("existing_uri"), "uri"); 20 | 21 | status.markUploaded("existing_uri2", "uri2"); 22 | strictEqual(status.isPending("existing_uri"), false); 23 | strictEqual(status.isUploaded("existing_uri"), true); 24 | strictEqual(status.hasBlobUri("existing_uri2"), true); 25 | strictEqual(status.getResultUri("existing_uri2"), "uri2"); 26 | 27 | status.markPending("existing_uri"); 28 | strictEqual(status.hasBlobUri("existing_uri"), true); 29 | status.removeFailed("existing_uri"); 30 | strictEqual(status.hasBlobUri("existing_uri"), false); 31 | }); 32 | }); -------------------------------------------------------------------------------- /tests/tinymce/util/JSONRequest.js: -------------------------------------------------------------------------------- 1 | if (location.protocol != "file:") { 2 | module("tinymce.util.JSONRequest"); 3 | 4 | asyncTest("Successful request - send method", function() { 5 | expect(1); 6 | 7 | new tinymce.util.JSONRequest({}).send({ 8 | type : 'GET', 9 | url : 'tinymce/util/json_rpc_ok.js', 10 | success: function(data) { 11 | equal(data, 'Hello JSON-RPC'); 12 | start(); 13 | } 14 | }); 15 | }); 16 | 17 | asyncTest("Successful request - sendRPC static method", function() { 18 | expect(1); 19 | 20 | tinymce.util.JSONRequest.sendRPC({ 21 | type : 'GET', 22 | url : 'tinymce/util/json_rpc_ok.js', 23 | success: function(data) { 24 | equal(data, 'Hello JSON-RPC'); 25 | start(); 26 | } 27 | }); 28 | }); 29 | 30 | asyncTest("Error request - send method", function() { 31 | expect(1); 32 | 33 | new tinymce.util.JSONRequest({}).send({ 34 | type : 'GET', 35 | url : 'tinymce/util/json_rpc_error.js', 36 | error: function(error) { 37 | equal(error.code, 42); 38 | start(); 39 | } 40 | }); 41 | }); 42 | 43 | asyncTest("Error request - sendRPC static method", function() { 44 | expect(1); 45 | 46 | tinymce.util.JSONRequest.sendRPC({ 47 | type : 'GET', 48 | url : 'tinymce/util/json_rpc_error.js', 49 | error: function(error) { 50 | equal(error.code, 42); 51 | start(); 52 | } 53 | }); 54 | }); 55 | } 56 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/CropRect.less: -------------------------------------------------------------------------------- 1 | // CropRect 2 | 3 | .@{prefix}-croprect-container { 4 | position: absolute; 5 | top: 0; 6 | left: 0; 7 | } 8 | 9 | .@{prefix}-croprect-handle { 10 | position: absolute; 11 | top: 0; left: 0; 12 | width: 20px; height: 20px; 13 | border: 2px solid white; 14 | } 15 | 16 | .@{prefix}-croprect-handle-nw { 17 | border-width: 2px 0 0 2px; 18 | margin: -2px 0 0 -2px; 19 | cursor: nw-resize; 20 | top: 100px; left: 100px; 21 | } 22 | 23 | .@{prefix}-croprect-handle-ne { 24 | border-width: 2px 2px 0 0; 25 | margin: -2px 0 0 -20px; 26 | cursor: ne-resize; 27 | top: 100px; left: 200px; 28 | } 29 | 30 | .@{prefix}-croprect-handle-sw { 31 | border-width: 0 0 2px 2px; 32 | margin: -20px 2px 0 -2px; 33 | cursor: sw-resize; 34 | top: 200px; left: 100px; 35 | } 36 | 37 | .@{prefix}-croprect-handle-se { 38 | border-width: 0 2px 2px 0; 39 | margin: -20px 0 0 -20px; 40 | cursor: se-resize; 41 | top: 200px; left: 200px; 42 | } 43 | 44 | .@{prefix}-croprect-handle-move { 45 | position: absolute; 46 | cursor: move; 47 | border: 0; 48 | } 49 | 50 | .@{prefix}-croprect-block { 51 | .opacity(@window-modalblock-opacity); 52 | position: absolute; 53 | background: black; 54 | } 55 | 56 | .@{prefix}-croprect-handle:focus { 57 | border-color: @textbox-border-focus; 58 | } 59 | 60 | .@{prefix}-croprect-handle-move:focus { 61 | outline: 1px solid @textbox-border-focus; 62 | } 63 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/InfoBox.less: -------------------------------------------------------------------------------- 1 | // InfoBox 2 | 3 | .@{prefix}-infobox { 4 | .inline-block(); 5 | text-shadow: @text-shadow; 6 | overflow: hidden; 7 | border: 1px solid red; 8 | 9 | div { 10 | display: block; 11 | margin: 5px; 12 | 13 | button { 14 | position: absolute; 15 | top: 50%; right: 4px; 16 | cursor: pointer; 17 | margin-top: -8px; 18 | display: none; 19 | } 20 | 21 | button:focus { 22 | outline: 2px solid @btn-border-hover; 23 | } 24 | } 25 | } 26 | 27 | .@{prefix}-infobox.@{prefix}-has-help { 28 | div { 29 | margin-right: 25px; 30 | } 31 | 32 | button { 33 | display: block; 34 | } 35 | } 36 | 37 | .@{prefix}-infobox.@{prefix}-success { 38 | background: @infobox-success-bg; 39 | border-color: @infobox-success-border; 40 | 41 | div { 42 | color: @infobox-success-text; 43 | } 44 | } 45 | 46 | .@{prefix}-infobox.@{prefix}-warning { 47 | background: @infobox-warning-bg; 48 | border-color: @infobox-warning-border; 49 | 50 | div { 51 | color: @infobox-warning-text; 52 | } 53 | } 54 | 55 | .@{prefix}-infobox.@{prefix}-error { 56 | background: @infobox-error-bg; 57 | border-color: @infobox-error-border; 58 | 59 | div { 60 | color: @infobox-error-text; 61 | } 62 | } 63 | 64 | // RTL 65 | 66 | .@{prefix}-rtl .@{prefix}-infobox { 67 | div { 68 | text-align: right; 69 | direction: rtl; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /js/tinymce/plugins/nonbreaking/plugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * plugin.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /*global tinymce:true */ 12 | 13 | tinymce.PluginManager.add('nonbreaking', function(editor) { 14 | var setting = editor.getParam('nonbreaking_force_tab'); 15 | 16 | editor.addCommand('mceNonBreaking', function() { 17 | editor.insertContent( 18 | (editor.plugins.visualchars && editor.plugins.visualchars.state) ? 19 | ' ' : ' ' 20 | ); 21 | 22 | editor.dom.setAttrib(editor.dom.select('span.mce-nbsp'), 'data-mce-bogus', '1'); 23 | }); 24 | 25 | editor.addButton('nonbreaking', { 26 | title: 'Nonbreaking space', 27 | cmd: 'mceNonBreaking' 28 | }); 29 | 30 | editor.addMenuItem('nonbreaking', { 31 | text: 'Nonbreaking space', 32 | cmd: 'mceNonBreaking', 33 | context: 'insert' 34 | }); 35 | 36 | if (setting) { 37 | var spaces = +setting > 1 ? +setting : 3; // defaults to 3 spaces if setting is true (or 1) 38 | 39 | editor.on('keydown', function(e) { 40 | if (e.keyCode == 9) { 41 | 42 | if (e.shiftKey) { 43 | return; 44 | } 45 | 46 | e.preventDefault(); 47 | for (var i = 0; i < spaces; i++) { 48 | editor.execCommand('mceNonBreaking'); 49 | } 50 | } 51 | }); 52 | } 53 | }); 54 | -------------------------------------------------------------------------------- /js/tinymce/classes/ui/FitLayout.js: -------------------------------------------------------------------------------- 1 | /** 2 | * FitLayout.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * This layout manager will resize the control to be the size of it's parent container. 13 | * In other words width: 100% and height: 100%. 14 | * 15 | * @-x-less FitLayout.less 16 | * @class tinymce.ui.FitLayout 17 | * @extends tinymce.ui.AbsoluteLayout 18 | */ 19 | define("tinymce/ui/FitLayout", [ 20 | "tinymce/ui/AbsoluteLayout" 21 | ], function(AbsoluteLayout) { 22 | "use strict"; 23 | 24 | return AbsoluteLayout.extend({ 25 | /** 26 | * Recalculates the positions of the controls in the specified container. 27 | * 28 | * @method recalc 29 | * @param {tinymce.ui.Container} container Container instance to recalc. 30 | */ 31 | recalc: function(container) { 32 | var contLayoutRect = container.layoutRect(), paddingBox = container.paddingBox; 33 | 34 | container.items().filter(':visible').each(function(ctrl) { 35 | ctrl.layoutRect({ 36 | x: paddingBox.left, 37 | y: paddingBox.top, 38 | w: contLayoutRect.innerW - paddingBox.right - paddingBox.left, 39 | h: contLayoutRect.innerH - paddingBox.top - paddingBox.bottom 40 | }); 41 | 42 | if (ctrl.recalc) { 43 | ctrl.recalc(); 44 | } 45 | }); 46 | } 47 | }); 48 | }); -------------------------------------------------------------------------------- /tools/docs/tinymce.ContentEvent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This class is the event object send when the content events occurs such as GetContent/SetContent. 3 | * 4 | * @class tinymce.ContentEvent 5 | * @extends tinymce.Event 6 | * @example 7 | * tinymce.activeEditor.on('GetContent', function(e) { 8 | * console.log(e.content); 9 | * }); 10 | */ 11 | 12 | /** 13 | * Optional state gets added for the load event then it's set to true. 14 | * 15 | * @property {Boolean} load 16 | */ 17 | 18 | /** 19 | * Optional state gets added for the save event then it's set to true. 20 | * 21 | * @property {Boolean} save 22 | */ 23 | 24 | /** 25 | * Optional state gets added for the getContent event then it's set to true. 26 | * 27 | * @property {Boolean} set 28 | */ 29 | 30 | /** 31 | * Optional state gets added for the setContent event then it's set to true. 32 | * 33 | * @property {Boolean} get 34 | */ 35 | 36 | /** 37 | * Optional element that the load/save event is for. This element is the textarea/div element that the 38 | * contents gets parsed from or serialized to. 39 | * 40 | * @property {DOMElement} element 41 | */ 42 | 43 | /** 44 | * Editor contents to be set or the content that was returned from the editor. 45 | * 46 | * @property {String} content HTML contents from the editor or to be put into the editor. 47 | */ 48 | 49 | /** 50 | * Format of the contents normally "html". 51 | * 52 | * @property {String} format Format of the contents normally "html". 53 | */ 54 | -------------------------------------------------------------------------------- /tests/tinymce/data/ObservableObject.js: -------------------------------------------------------------------------------- 1 | ModuleLoader.require(["tinymce/data/ObservableObject"], function(ObservableObject) { 2 | module("tinymce.data.ObservableObject"); 3 | 4 | test("Constructor", function(assert) { 5 | var obj; 6 | 7 | obj = new ObservableObject(); 8 | assert.ok(!obj.has('a')); 9 | 10 | obj = new ObservableObject({a: 1, b: 2}); 11 | assert.strictEqual(obj.get('a'), 1); 12 | assert.strictEqual(obj.get('b'), 2); 13 | }); 14 | 15 | test("set/get and observe all", function(assert) { 16 | var obj = new ObservableObject(), events = []; 17 | 18 | obj.on('change', function(e) { 19 | events.push(e); 20 | }); 21 | 22 | obj.set('a', 'a'); 23 | obj.set('a', 'a2'); 24 | obj.set('a', 'a3'); 25 | obj.set('b', 'b'); 26 | assert.strictEqual(obj.get('a'), 'a3'); 27 | 28 | equal(events[0].type, 'change'); 29 | equal(events[0].value, 'a'); 30 | equal(events[1].type, 'change'); 31 | equal(events[1].value, 'a2'); 32 | equal(events[2].type, 'change'); 33 | equal(events[2].value, 'a3'); 34 | equal(events[3].type, 'change'); 35 | equal(events[3].value, 'b'); 36 | }); 37 | 38 | test("set/get and observe specific", function(assert) { 39 | var obj = new ObservableObject(), events = []; 40 | 41 | obj.on('change:a', function(e) { 42 | events.push(e); 43 | }); 44 | 45 | obj.set('a', 'a'); 46 | obj.set('b', 'b'); 47 | equal(events[0].type, 'change'); 48 | equal(events[0].value, 'a'); 49 | equal(events.length, 1); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/main/js/tinymce/inlite/core/ElementMatcher.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ElementMatcher.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2016 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | define('tinymce/inlite/core/ElementMatcher', [ 12 | 'tinymce/inlite/core/Matcher', 13 | 'tinymce/inlite/core/Measure' 14 | ], function (Matcher, Measure) { 15 | // element :: Element, [PredicateId] -> (Editor -> Matcher.result | Null) 16 | var element = function (element, predicateIds) { 17 | return function (editor) { 18 | for (var i = 0; i < predicateIds.length; i++) { 19 | if (predicateIds[i].predicate(element)) { 20 | return Matcher.result(predicateIds[i].id, Measure.getElementRect(editor, element)); 21 | } 22 | } 23 | 24 | return null; 25 | }; 26 | }; 27 | 28 | // parent :: [Elements], [PredicateId] -> (Editor -> Matcher.result | Null) 29 | var parent = function (elements, predicateIds) { 30 | return function (editor) { 31 | for (var i = 0; i < elements.length; i++) { 32 | for (var x = 0; x < predicateIds.length; x++) { 33 | if (predicateIds[x].predicate(elements[i])) { 34 | return Matcher.result(predicateIds[x].id, Measure.getElementRect(editor, elements[i])); 35 | } 36 | } 37 | } 38 | 39 | return null; 40 | }; 41 | }; 42 | 43 | return { 44 | element: element, 45 | parent: parent 46 | }; 47 | }); 48 | -------------------------------------------------------------------------------- /js/tinymce/plugins/anchor/plugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * plugin.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /*global tinymce:true */ 12 | 13 | tinymce.PluginManager.add('anchor', function(editor) { 14 | function showDialog() { 15 | var selectedNode = editor.selection.getNode(), name = ''; 16 | var isAnchor = selectedNode.tagName == 'A' && editor.dom.getAttrib(selectedNode, 'href') === ''; 17 | 18 | if (isAnchor) { 19 | name = selectedNode.name || selectedNode.id || ''; 20 | } 21 | 22 | editor.windowManager.open({ 23 | title: 'Anchor', 24 | body: {type: 'textbox', name: 'name', size: 40, label: 'Name', value: name}, 25 | onsubmit: function(e) { 26 | var id = e.data.name; 27 | 28 | if (isAnchor) { 29 | selectedNode.id = id; 30 | } else { 31 | editor.selection.collapse(true); 32 | editor.execCommand('mceInsertContent', false, editor.dom.createHTML('a', { 33 | id: id 34 | })); 35 | } 36 | } 37 | }); 38 | } 39 | 40 | editor.addCommand('mceAnchor', showDialog); 41 | 42 | editor.addButton('anchor', { 43 | icon: 'anchor', 44 | tooltip: 'Anchor', 45 | onclick: showDialog, 46 | stateSelector: 'a:not([href])' 47 | }); 48 | 49 | editor.addMenuItem('anchor', { 50 | icon: 'anchor', 51 | text: 'Anchor', 52 | context: 'insert', 53 | onclick: showDialog 54 | }); 55 | }); -------------------------------------------------------------------------------- /tests/tinymce/ui/FitLayout.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var panel; 3 | 4 | module("tinymce.ui.FitLayout", { 5 | setup: function() { 6 | document.getElementById('view').innerHTML = ''; 7 | }, 8 | 9 | teardown: function() { 10 | tinymce.dom.Event.clean(document.getElementById('view')); 11 | } 12 | }); 13 | 14 | function createFitPanel(settings) { 15 | return tinymce.ui.Factory.create(tinymce.extend({ 16 | type: 'panel', 17 | layout: 'fit', 18 | width: 200, 19 | height: 200, 20 | border: 1 21 | }, settings)).renderTo(document.getElementById('view')).reflow(); 22 | } 23 | 24 | test("fit with spacer inside", function() { 25 | panel = createFitPanel({ 26 | items: [ 27 | {type: 'spacer', classes: 'red'} 28 | ] 29 | }); 30 | 31 | deepEqual(Utils.rect(panel), [0, 0, 200, 200]); 32 | deepEqual(Utils.rect(panel.find('spacer')[0]), [1, 1, 198, 198]); 33 | }); 34 | 35 | test("fit with padding and spacer inside", function() { 36 | panel = createFitPanel({ 37 | padding: 3, 38 | items: [ 39 | {type: 'spacer', classes: 'red'} 40 | ] 41 | }); 42 | 43 | deepEqual(Utils.rect(panel), [0, 0, 200, 200]); 44 | deepEqual(Utils.rect(panel.find('spacer')[0]), [4, 4, 192, 192]); 45 | }); 46 | 47 | test("fit with panel inside", function() { 48 | panel = createFitPanel({ 49 | items: [ 50 | {type: 'panel', border: 1} 51 | ] 52 | }); 53 | 54 | deepEqual(Utils.rect(panel), [0, 0, 200, 200]); 55 | deepEqual(Utils.rect(panel.find('panel')[0]), [1, 1, 198, 198]); 56 | }); 57 | })(); -------------------------------------------------------------------------------- /js/tinymce/plugins/table/classes/Utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Utils.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * Various utility functions. 13 | * 14 | * @class tinymce.tableplugin.Utils 15 | * @private 16 | */ 17 | define("tinymce/tableplugin/Utils", [ 18 | "tinymce/Env" 19 | ], function(Env) { 20 | var setSpanVal = function (name) { 21 | return function (td, val) { 22 | if (td) { 23 | val = parseInt(val, 10); 24 | 25 | if (val === 1 || val === 0) { 26 | td.removeAttribute(name, 1); 27 | } else { 28 | td.setAttribute(name, val, 1); 29 | } 30 | } 31 | }; 32 | }; 33 | 34 | var getSpanVal = function (name) { 35 | return function (td) { 36 | return parseInt(td.getAttribute(name) || 1, 10); 37 | }; 38 | }; 39 | 40 | function paddCell(cell) { 41 | if (!Env.ie || Env.ie > 9) { 42 | if (!cell.hasChildNodes()) { 43 | cell.innerHTML = '
'; 44 | } 45 | } 46 | } 47 | 48 | return { 49 | setColSpan: setSpanVal('colSpan'), 50 | setRowSpan: setSpanVal('rowspan'), 51 | getColSpan: getSpanVal('colSpan'), 52 | getRowSpan: getSpanVal('rowSpan'), 53 | setSpanVal: function (td, name, value) { 54 | setSpanVal(name)(td, value); 55 | }, 56 | getSpanVal: function (td, name) { 57 | return getSpanVal(name)(td); 58 | }, 59 | paddCell: paddCell 60 | }; 61 | }); 62 | -------------------------------------------------------------------------------- /tests/tinymce/util/Fun.js: -------------------------------------------------------------------------------- 1 | ModuleLoader.require([ 2 | "tinymce/util/Fun" 3 | ], function(Fun) { 4 | module("tinymce.util.Fun"); 5 | 6 | function isTrue(value) { 7 | return value === true; 8 | } 9 | 10 | function isFalse(value) { 11 | return value === true; 12 | } 13 | 14 | function isAbove(target, value) { 15 | return value() > target(); 16 | } 17 | 18 | test('constant', function() { 19 | strictEqual(Fun.constant(1)(), 1); 20 | strictEqual(Fun.constant("1")(), "1"); 21 | strictEqual(Fun.constant(null)(), null); 22 | }); 23 | 24 | test('negate', function() { 25 | strictEqual(Fun.negate(isTrue)(false), true); 26 | strictEqual(Fun.negate(isFalse)(true), false); 27 | }); 28 | 29 | test('and', function() { 30 | var isAbove5 = Fun.curry(isAbove, Fun.constant(5)); 31 | var isAbove10 = Fun.curry(isAbove, Fun.constant(10)); 32 | 33 | strictEqual(Fun.and(isAbove10, isAbove5)(Fun.constant(10)), false); 34 | strictEqual(Fun.and(isAbove10, isAbove5)(Fun.constant(30)), true); 35 | }); 36 | 37 | test('or', function() { 38 | var isAbove5 = Fun.curry(isAbove, Fun.constant(5)); 39 | var isAbove10 = Fun.curry(isAbove, Fun.constant(10)); 40 | 41 | strictEqual(Fun.or(isAbove10, isAbove5)(Fun.constant(5)), false); 42 | strictEqual(Fun.or(isAbove10, isAbove5)(Fun.constant(15)), true); 43 | strictEqual(Fun.or(isAbove5, isAbove10)(Fun.constant(15)), true); 44 | }); 45 | 46 | test('compose', function() { 47 | strictEqual(Fun.compose(Fun.curry(isAbove, Fun.constant(5)), Fun.constant)(10), true); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /tools/docs/tinymce.Event.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This is the base class for all TinyMCE events. 3 | * 4 | * @class tinymce.Event 5 | */ 6 | 7 | /** 8 | * Prevents the default action of an event to be executed. 9 | * 10 | * @method preventDefault 11 | */ 12 | 13 | /** 14 | * Stops the event from propagating up to listeners on parent objects. 15 | * 16 | * @method stopPropagation 17 | */ 18 | 19 | /** 20 | * Prevents the event from propagating to listeners on the same object. 21 | * 22 | * @method stopImmediatePropagation 23 | */ 24 | 25 | /** 26 | * Returns true/false if the default action is to be prevented or not. 27 | * 28 | * @method isDefaultPrevented 29 | * @return {Boolean} True/false if the event is to be execured or not. 30 | */ 31 | 32 | /** 33 | * Returns true/false if the event propagation is stopped or not. 34 | * 35 | * @method isPropagationStopped 36 | * @return {Boolean} True/false if the event propagation is stopped or not. 37 | */ 38 | 39 | /** 40 | * Returns true/false if the event immediate propagation is stopped or not. 41 | * 42 | * @method isImmediatePropagationStopped 43 | * @return {Boolean} True/false if the event immediate propagation is stopped or not. 44 | */ 45 | 46 | /** 47 | * The event type name for example "click". 48 | * 49 | * @property {String} type 50 | */ 51 | 52 | /** 53 | * @include tinymce.ContentEvent.js 54 | * @include tinymce.CommandEvent.js 55 | * @include tinymce.ProgressStateEvent.js 56 | * @include tinymce.FocusEvent.js 57 | * @include tinymce.ResizeEvent.js 58 | */ 59 | -------------------------------------------------------------------------------- /tests/plugins/noneditable.js: -------------------------------------------------------------------------------- 1 | module("tinymce.plugins.Noneditable", { 2 | setupModule: function() { 3 | QUnit.stop(); 4 | 5 | tinymce.init({ 6 | selector: "textarea", 7 | add_unload_trigger: false, 8 | skin: false, 9 | indent: false, 10 | noneditable_regexp: [/\{[^\}]+\}/g], 11 | plugins: 'noneditable', 12 | convert_fonts_to_spans: false, 13 | entities: 'raw', 14 | valid_styles: { 15 | '*': 'color,font-size,font-family,background-color,font-weight,font-style,text-decoration,float,margin,margin-top,margin-right,margin-bottom,margin-left,display' 16 | }, 17 | init_instance_callback: function(ed) { 18 | window.editor = ed; 19 | QUnit.start(); 20 | } 21 | }); 22 | } 23 | }); 24 | 25 | // Ignore on IE 7, 8 this is a known bug not worth fixing 26 | if (tinymce.Env.ceFalse) { 27 | test('noneditable class', function() { 28 | editor.setContent('

abc

'); 29 | equal(editor.dom.select('span')[0].contentEditable, "false"); 30 | }); 31 | 32 | test('editable class', function() { 33 | editor.setContent('

abc

'); 34 | equal(editor.dom.select('span')[0].contentEditable, "true"); 35 | }); 36 | 37 | test('noneditable regexp', function() { 38 | editor.setContent('

{test1}{test2}

'); 39 | 40 | equal(editor.dom.select('span').length, 2); 41 | equal(editor.dom.select('span')[0].contentEditable, "false"); 42 | equal(editor.dom.select('span')[1].contentEditable, "false"); 43 | equal(editor.getContent(), '

{test1}{test2}

'); 44 | }); 45 | } -------------------------------------------------------------------------------- /tests/tinymce/InsertList.js: -------------------------------------------------------------------------------- 1 | ModuleLoader.require([ 2 | "tinymce/InsertList", 3 | "tinymce/html/Node", 4 | "tinymce/html/DomParser", 5 | "tinymce/dom/DOMUtils" 6 | ], function(InsertList, Node, DomParser, DOMUtils) { 7 | module("tinymce.InsertList", {}); 8 | 9 | var createFragment = function(html) { 10 | var parser = new DomParser({validate: false}); 11 | var fragment = parser.parse(html); 12 | 13 | return fragment; 14 | }; 15 | 16 | var createDomFragment = function(html) { 17 | return DOMUtils.DOM.createFragment(html); 18 | }; 19 | 20 | test('isListFragment', function() { 21 | equal(InsertList.isListFragment(createFragment('')), true); 22 | equal(InsertList.isListFragment(createFragment('
  1. x
')), true); 23 | equal(InsertList.isListFragment(createFragment('')), true); 24 | equal(InsertList.isListFragment(createFragment('')), true); 25 | equal(InsertList.isListFragment(createFragment('
')), false); 26 | }); 27 | 28 | test('listItems', function() { 29 | var list = createDomFragment('').firstChild; 30 | 31 | equal(InsertList.listItems(list).length, 3); 32 | equal(InsertList.listItems(list)[0].nodeName, 'LI'); 33 | }); 34 | 35 | test('trimListItems', function() { 36 | var list = createDomFragment('').firstChild; 37 | 38 | equal(InsertList.listItems(list).length, 3); 39 | equal(InsertList.trimListItems(InsertList.listItems(list)).length, 2); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /tests/tinymce/html/Serializer.js: -------------------------------------------------------------------------------- 1 | module("tinymce.html.Serializer"); 2 | 3 | test('Basic serialization', function() { 4 | var serializer = new tinymce.html.Serializer(); 5 | 6 | expect(6); 7 | 8 | equal(serializer.serialize(new tinymce.html.DomParser().parse('texttext')), 'text'); 10 | equal(serializer.serialize(new tinymce.html.DomParser().parse('')), ''); 11 | equal(serializer.serialize(new tinymce.html.DomParser().parse('')), ''); 12 | equal(serializer.serialize(new tinymce.html.DomParser().parse('')), ''); 13 | equal(serializer.serialize(new tinymce.html.DomParser().parse('')), ''); 14 | }); 15 | 16 | test('Sorting of attributes', function() { 17 | var serializer = new tinymce.html.Serializer(); 18 | 19 | expect(1); 20 | 21 | equal(serializer.serialize(new tinymce.html.DomParser().parse('x')), 'x'); 22 | }); 23 | 24 | test('Serialize with validate: true, when parsing with validate:false bug', function() { 25 | var schema = new tinymce.html.Schema({valid_elements: 'b'}); 26 | var serializer = new tinymce.html.Serializer({}, schema); 27 | 28 | equal( 29 | serializer.serialize(new tinymce.html.DomParser({validate: false}, schema).parse('ab')), 30 | 'ab' 31 | ); 32 | }); 33 | -------------------------------------------------------------------------------- /tests/tinymce/AddOnManager.js: -------------------------------------------------------------------------------- 1 | module("tinymce.AddOnManager", { 2 | teardown: function() { 3 | Utils.unpatch(tinymce.dom.ScriptLoader.ScriptLoader); 4 | tinymce.AddOnManager.languageLoad = true; 5 | tinymce.AddOnManager.language = 'en'; 6 | } 7 | }); 8 | 9 | test('requireLangPack', function() { 10 | var languagePackUrl; 11 | 12 | Utils.patch(tinymce.dom.ScriptLoader.ScriptLoader, 'add', function(origFunc, url) { 13 | languagePackUrl = url; 14 | }); 15 | 16 | function getLanguagePackUrl(language, languages) { 17 | languagePackUrl = null; 18 | tinymce.AddOnManager.language = language; 19 | tinymce.AddOnManager.PluginManager.requireLangPack('plugin', languages); 20 | return languagePackUrl; 21 | } 22 | 23 | tinymce.AddOnManager.PluginManager.urls.plugin = '/root'; 24 | 25 | equal(getLanguagePackUrl('sv_SE'), '/root/langs/sv_SE.js'); 26 | equal(getLanguagePackUrl('sv_SE', 'sv,en,us'), '/root/langs/sv.js'); 27 | equal(getLanguagePackUrl('sv_SE', 'sv_SE,en_US'), '/root/langs/sv_SE.js'); 28 | equal(getLanguagePackUrl('sv'), '/root/langs/sv.js'); 29 | equal(getLanguagePackUrl('sv', 'sv'), '/root/langs/sv.js'); 30 | equal(getLanguagePackUrl('sv', 'sv,en,us'), '/root/langs/sv.js'); 31 | equal(getLanguagePackUrl('sv', 'en,sv,us'), '/root/langs/sv.js'); 32 | equal(getLanguagePackUrl('sv', 'en,us,sv'), '/root/langs/sv.js'); 33 | strictEqual(getLanguagePackUrl('sv', 'en,us'), null); 34 | strictEqual(getLanguagePackUrl(null, 'en,us'), null); 35 | strictEqual(getLanguagePackUrl(null), null); 36 | 37 | tinymce.AddOnManager.languageLoad = false; 38 | strictEqual(getLanguagePackUrl('sv', 'sv'), null); 39 | }); 40 | -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/test/js/browser/file/SelectionMatcher.js: -------------------------------------------------------------------------------- 1 | /** 2 | * SelectionMatcher.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2016 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | define('tinymce/inlite/core/SelectionMatcher', [ 12 | 'tinymce/inlite/core/Matcher', 13 | 'tinymce/inlite/core/Measure' 14 | ], function (Matcher, Measure) { 15 | // textSelection :: String -> (Editor -> Matcher.result | Null) 16 | var textSelection = function (id) { 17 | return function (editor) { 18 | if (!editor.selection.isCollapsed()) { 19 | return Matcher.result(id, Measure.getSelectionRect(editor)); 20 | } 21 | 22 | return null; 23 | }; 24 | }; 25 | 26 | // emptyTextBlock :: [Elements], String -> (Editor -> Matcher.result | Null) 27 | var emptyTextBlock = function (elements, id) { 28 | return function (editor) { 29 | var i, textBlockElementsMap = editor.schema.getTextBlockElements(); 30 | 31 | for (i = 0; i < elements.length; i++) { 32 | if (elements[i].nodeName === 'TABLE') { 33 | return null; 34 | } 35 | } 36 | 37 | for (i = 0; i < elements.length; i++) { 38 | if (elements[i].nodeName in textBlockElementsMap) { 39 | if (editor.dom.isEmpty(elements[i])) { 40 | return Matcher.result(id, Measure.getSelectionRect(editor)); 41 | } 42 | 43 | return null; 44 | } 45 | } 46 | 47 | return null; 48 | }; 49 | }; 50 | 51 | return { 52 | textSelection: textSelection, 53 | emptyTextBlock: emptyTextBlock 54 | }; 55 | }); 56 | -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/main/js/tinymce/inlite/core/SelectionMatcher.js: -------------------------------------------------------------------------------- 1 | /** 2 | * SelectionMatcher.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2016 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | define('tinymce/inlite/core/SelectionMatcher', [ 12 | 'tinymce/inlite/core/Matcher', 13 | 'tinymce/inlite/core/Measure' 14 | ], function (Matcher, Measure) { 15 | // textSelection :: String -> (Editor -> Matcher.result | Null) 16 | var textSelection = function (id) { 17 | return function (editor) { 18 | if (!editor.selection.isCollapsed()) { 19 | return Matcher.result(id, Measure.getSelectionRect(editor)); 20 | } 21 | 22 | return null; 23 | }; 24 | }; 25 | 26 | // emptyTextBlock :: [Elements], String -> (Editor -> Matcher.result | Null) 27 | var emptyTextBlock = function (elements, id) { 28 | return function (editor) { 29 | var i, textBlockElementsMap = editor.schema.getTextBlockElements(); 30 | 31 | for (i = 0; i < elements.length; i++) { 32 | if (elements[i].nodeName === 'TABLE') { 33 | return null; 34 | } 35 | } 36 | 37 | for (i = 0; i < elements.length; i++) { 38 | if (elements[i].nodeName in textBlockElementsMap) { 39 | if (editor.dom.isEmpty(elements[i])) { 40 | return Matcher.result(id, Measure.getSelectionRect(editor)); 41 | } 42 | 43 | return null; 44 | } 45 | } 46 | 47 | return null; 48 | }; 49 | }; 50 | 51 | return { 52 | textSelection: textSelection, 53 | emptyTextBlock: emptyTextBlock 54 | }; 55 | }); 56 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "amd": true 5 | }, 6 | 7 | "globals": { 8 | "escape": true, 9 | "unescape": true, 10 | "Uint8Array": true 11 | }, 12 | 13 | "rules": { 14 | "camelcase": 0, 15 | "strict": 0, 16 | "eqeqeq": 0, 17 | "no-underscore-dangle": 0, 18 | "consistent-return": 0, 19 | "no-shadow": 0, 20 | "no-use-before-define": 0, 21 | "brace-style": [2, "1tbs"], 22 | "guard-for-in": 0, 23 | "no-floating-decimal": 2, 24 | "no-nested-ternary": 2, 25 | "radix": 2, 26 | "wrap-iife": [2, "inside"], 27 | "consistent-this": [2, "self"], 28 | "no-bitwise": 2, 29 | "max-params": [2, 50], 30 | "max-depth": [1, 8], 31 | "max-statements": [2, 150], 32 | "max-len": [1, 140, 4], 33 | "eol-last": 0, 34 | "quotes": 0, 35 | "no-trailing-spaces": 2, 36 | "comma-spacing": [2, {"before": false, "after": true}], 37 | "space-in-parens": [2, "never"], 38 | "space-infix-ops": [2, {"int32Hint": false}], 39 | "keyword-spacing": 2, 40 | "space-unary-ops": [1, { "words": true, "nonwords": false }], 41 | "space-before-blocks": [2, "always"], 42 | "no-multiple-empty-lines": [1, {max: 2}], 43 | "object-curly-spacing": [2, "never"], 44 | "operator-linebreak": [2, "after"], 45 | "semi": [2, "always"], 46 | "indent": 0, 47 | "curly": [2, "all"], 48 | "dot-notation": [2, {"allowKeywords": false}], 49 | "no-else-return": 2, 50 | "no-eval": 2, 51 | "no-implied-eval": 2, 52 | "no-loop-func": 2, 53 | "no-multi-str": 2, 54 | "no-multi-spaces": 2, 55 | "no-sequences": 2, 56 | "no-new": 2, 57 | "no-caller": 2 58 | }, 59 | 60 | "extends": "eslint:recommended" 61 | } 62 | -------------------------------------------------------------------------------- /js/tinymce/classes/ui/FormItem.js: -------------------------------------------------------------------------------- 1 | /** 2 | * FormItem.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * This class is a container created by the form element with 13 | * a label and control item. 14 | * 15 | * @class tinymce.ui.FormItem 16 | * @extends tinymce.ui.Container 17 | * @setting {String} label Label to display for the form item. 18 | */ 19 | define("tinymce/ui/FormItem", [ 20 | "tinymce/ui/Container" 21 | ], function(Container) { 22 | "use strict"; 23 | 24 | return Container.extend({ 25 | Defaults: { 26 | layout: 'flex', 27 | align: 'center', 28 | defaults: { 29 | flex: 1 30 | } 31 | }, 32 | 33 | /** 34 | * Renders the control as a HTML string. 35 | * 36 | * @method renderHtml 37 | * @return {String} HTML representing the control. 38 | */ 39 | renderHtml: function() { 40 | var self = this, layout = self._layout, prefix = self.classPrefix; 41 | 42 | self.classes.add('formitem'); 43 | layout.preRender(self); 44 | 45 | return ( 46 | '
' + 47 | (self.settings.title ? ('
' + 48 | self.settings.title + '
') : '') + 49 | '
' + 50 | (self.settings.html || '') + layout.renderHtml(self) + 51 | '
' + 52 | '
' 53 | ); 54 | } 55 | }); 56 | }); -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/ColorButton.less: -------------------------------------------------------------------------------- 1 | // ColorButton 2 | 3 | .@{prefix}-colorbutton .@{prefix}-ico { 4 | position: relative; 5 | } 6 | 7 | .@{prefix}-colorbutton-grid { 8 | margin: 4px; 9 | } 10 | 11 | .@{prefix}-colorbutton button { 12 | padding-right: 6px; 13 | padding-left: 6px; 14 | } 15 | 16 | .@{prefix}-colorbutton .@{prefix}-preview { 17 | padding-right: 3px; 18 | display: block; 19 | position: absolute; 20 | left: 50%; 21 | top: 50%; 22 | margin-left: -17px; 23 | margin-top: 7px; 24 | background: gray; 25 | width: 13px; 26 | height: 2px; 27 | overflow: hidden; 28 | } 29 | 30 | .@{prefix}-colorbutton.@{prefix}-btn-small .@{prefix}-preview { 31 | margin-left: -16px; 32 | padding-right: 0; 33 | width: 16px; 34 | } 35 | 36 | .@{prefix}-colorbutton .@{prefix}-open { 37 | padding-left: 4px; 38 | padding-right: 4px; 39 | border-left: 1px solid transparent; 40 | } 41 | 42 | .@{prefix}-colorbutton:hover .@{prefix}-open { 43 | border-color: darken(@btn-bg, 20%); 44 | } 45 | 46 | .@{prefix}-colorbutton.@{prefix}-btn-small .@{prefix}-open { 47 | padding: 0 3px 0 3px; 48 | } 49 | 50 | // RTL 51 | 52 | .@{prefix}-rtl .@{prefix}-colorbutton { 53 | direction: rtl; 54 | } 55 | 56 | .@{prefix}-rtl .@{prefix}-colorbutton .@{prefix}-preview { 57 | margin-left: 0; 58 | padding-right: 0; 59 | padding-left: 3px; 60 | } 61 | 62 | .@{prefix}-rtl .@{prefix}-colorbutton.@{prefix}-btn-small .@{prefix}-preview { 63 | margin-left: 0; 64 | padding-right: 0; 65 | padding-left: 2px; 66 | } 67 | 68 | .@{prefix}-rtl .@{prefix}-colorbutton .@{prefix}-open { 69 | padding-left: 4px; 70 | padding-right: 4px; 71 | border-left: 0; 72 | } 73 | -------------------------------------------------------------------------------- /js/tinymce/classes/ui/FieldSet.js: -------------------------------------------------------------------------------- 1 | /** 2 | * FieldSet.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * This class creates fieldset containers. 13 | * 14 | * @-x-less FieldSet.less 15 | * @class tinymce.ui.FieldSet 16 | * @extends tinymce.ui.Form 17 | */ 18 | define("tinymce/ui/FieldSet", [ 19 | "tinymce/ui/Form" 20 | ], function(Form) { 21 | "use strict"; 22 | 23 | return Form.extend({ 24 | Defaults: { 25 | containerCls: 'fieldset', 26 | layout: 'flex', 27 | direction: 'column', 28 | align: 'stretch', 29 | flex: 1, 30 | padding: "25 15 5 15", 31 | labelGap: 30, 32 | spacing: 10, 33 | border: 1 34 | }, 35 | 36 | /** 37 | * Renders the control as a HTML string. 38 | * 39 | * @method renderHtml 40 | * @return {String} HTML representing the control. 41 | */ 42 | renderHtml: function() { 43 | var self = this, layout = self._layout, prefix = self.classPrefix; 44 | 45 | self.preRender(); 46 | layout.preRender(self); 47 | 48 | return ( 49 | '
' + 50 | (self.settings.title ? ('' + 51 | self.settings.title + '') : '') + 52 | '
' + 53 | (self.settings.html || '') + layout.renderHtml(self) + 54 | '
' + 55 | '
' 56 | ); 57 | } 58 | }); 59 | }); -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/test/js/browser/alien/UnlinkTest.js: -------------------------------------------------------------------------------- 1 | asynctest('browser/alien/UnlinkTest', [ 2 | 'ephox.mcagar.api.TinyLoader', 3 | 'ephox.mcagar.api.TinyApis', 4 | 'tinymce/inlite/alien/Unlink', 5 | 'ephox.agar.api.Pipeline', 6 | 'ephox.agar.api.Step', 7 | 'ephox.agar.api.GeneralSteps' 8 | ], function (TinyLoader, TinyApis, Unlink, Pipeline, Step, GeneralSteps) { 9 | var success = arguments[arguments.length - 2]; 10 | var failure = arguments[arguments.length - 1]; 11 | 12 | var sUnlinkSelection = function (editor) { 13 | return Step.sync(function () { 14 | Unlink.unlinkSelection(editor); 15 | }); 16 | }; 17 | 18 | TinyLoader.setup(function (editor, onSuccess, onFailure) { 19 | var tinyApis = TinyApis(editor); 20 | 21 | var sAssertUnlink = function (inputHtml, startPath, startOffset, finishPath, finishOffset, expectedHtml) { 22 | return GeneralSteps.sequence([ 23 | tinyApis.sSetContent(inputHtml), 24 | tinyApis.sSetSelection(startPath, startOffset, finishPath, finishOffset), 25 | sUnlinkSelection(editor), 26 | tinyApis.sAssertContent(expectedHtml, 'Should match expected anchor less html') 27 | ]); 28 | }; 29 | 30 | Pipeline.async({}, [ 31 | sAssertUnlink('

a

', [0, 0, 0], 0, [0, 0, 0], 1, '

a

'), 32 | sAssertUnlink('

ab

', [0, 0, 0], 0, [0, 1], 1, '

ab

'), 33 | sAssertUnlink('

a

b', [0, 0, 0], 0, [0, 0, 0], 1, '

a

\n

b

'), 34 | sAssertUnlink('

a

b', [0, 0, 0], 0, [1, 0, 0], 1, '

a

\n

b

') 35 | ], onSuccess, onFailure); 36 | }, { 37 | }, success, failure); 38 | }); 39 | -------------------------------------------------------------------------------- /js/tinymce/classes/ui/Panel.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Panel.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * Creates a new panel. 13 | * 14 | * @-x-less Panel.less 15 | * @class tinymce.ui.Panel 16 | * @extends tinymce.ui.Container 17 | * @mixes tinymce.ui.Scrollable 18 | */ 19 | define("tinymce/ui/Panel", [ 20 | "tinymce/ui/Container", 21 | "tinymce/ui/Scrollable" 22 | ], function(Container, Scrollable) { 23 | "use strict"; 24 | 25 | return Container.extend({ 26 | Defaults: { 27 | layout: 'fit', 28 | containerCls: 'panel' 29 | }, 30 | 31 | Mixins: [Scrollable], 32 | 33 | /** 34 | * Renders the control as a HTML string. 35 | * 36 | * @method renderHtml 37 | * @return {String} HTML representing the control. 38 | */ 39 | renderHtml: function() { 40 | var self = this, layout = self._layout, innerHtml = self.settings.html; 41 | 42 | self.preRender(); 43 | layout.preRender(self); 44 | 45 | if (typeof innerHtml == "undefined") { 46 | innerHtml = ( 47 | '
' + 48 | layout.renderHtml(self) + 49 | '
' 50 | ); 51 | } else { 52 | if (typeof innerHtml == 'function') { 53 | innerHtml = innerHtml.call(self); 54 | } 55 | 56 | self._hasBody = false; 57 | } 58 | 59 | return ( 60 | '
' + 61 | (self._preBodyHtml || '') + 62 | innerHtml + 63 | '
' 64 | ); 65 | } 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /js/tinymce/classes/ui/ButtonGroup.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ButtonGroup.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * This control enables you to put multiple buttons into a group. This is 13 | * useful when you want to combine similar toolbar buttons into a group. 14 | * 15 | * @example 16 | * // Create and render a buttongroup with two buttons to the body element 17 | * tinymce.ui.Factory.create({ 18 | * type: 'buttongroup', 19 | * items: [ 20 | * {text: 'Button A'}, 21 | * {text: 'Button B'} 22 | * ] 23 | * }).renderTo(document.body); 24 | * 25 | * @-x-less ButtonGroup.less 26 | * @class tinymce.ui.ButtonGroup 27 | * @extends tinymce.ui.Container 28 | */ 29 | define("tinymce/ui/ButtonGroup", [ 30 | "tinymce/ui/Container" 31 | ], function(Container) { 32 | "use strict"; 33 | 34 | return Container.extend({ 35 | Defaults: { 36 | defaultType: 'button', 37 | role: 'group' 38 | }, 39 | 40 | /** 41 | * Renders the control as a HTML string. 42 | * 43 | * @method renderHtml 44 | * @return {String} HTML representing the control. 45 | */ 46 | renderHtml: function() { 47 | var self = this, layout = self._layout; 48 | 49 | self.classes.add('btn-group'); 50 | self.preRender(); 51 | layout.preRender(self); 52 | 53 | return ( 54 | '
' + 55 | '
' + 56 | (self.settings.html || '') + layout.renderHtml(self) + 57 | '
' + 58 | '
' 59 | ); 60 | } 61 | }); 62 | }); -------------------------------------------------------------------------------- /js/tinymce/classes/fmt/Hooks.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Hooks.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2016 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * Internal class for overriding formatting. 13 | * 14 | * @private 15 | * @class tinymce.fmt.Hooks 16 | */ 17 | define("tinymce/fmt/Hooks", [ 18 | "tinymce/util/Arr", 19 | "tinymce/dom/NodeType", 20 | "tinymce/dom/DomQuery" 21 | ], function(Arr, NodeType, $) { 22 | var postProcessHooks = [], filter = Arr.filter, each = Arr.each; 23 | 24 | function addPostProcessHook(name, hook) { 25 | var hooks = postProcessHooks[name]; 26 | 27 | if (!hooks) { 28 | postProcessHooks[name] = hooks = []; 29 | } 30 | 31 | postProcessHooks[name].push(hook); 32 | } 33 | 34 | function postProcess(name, editor) { 35 | each(postProcessHooks[name], function(hook) { 36 | hook(editor); 37 | }); 38 | } 39 | 40 | addPostProcessHook("pre", function(editor) { 41 | var rng = editor.selection.getRng(), isPre, blocks; 42 | 43 | function hasPreSibling(pre) { 44 | return isPre(pre.previousSibling) && Arr.indexOf(blocks, pre.previousSibling) != -1; 45 | } 46 | 47 | function joinPre(pre1, pre2) { 48 | $(pre2).remove(); 49 | $(pre1).append('

').append(pre2.childNodes); 50 | } 51 | 52 | isPre = NodeType.matchNodeNames('pre'); 53 | 54 | if (!rng.collapsed) { 55 | blocks = editor.selection.getSelectedBlocks(); 56 | 57 | each(filter(filter(blocks, isPre), hasPreSibling), function(pre) { 58 | joinPre(pre.previousSibling, pre); 59 | }); 60 | } 61 | }); 62 | 63 | return { 64 | postProcess: postProcess 65 | }; 66 | }); 67 | -------------------------------------------------------------------------------- /tests/manual/dirty.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dirty state 5 | 6 | 7 | 8 | 9 | 10 | 11 | 37 | 38 | 39 |
40 |
41 |
42 | 43 | 44 | 45 | 46 | isDirty: false 47 |
48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /js/tinymce/plugins/directionality/plugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * plugin.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /*global tinymce:true */ 12 | 13 | tinymce.PluginManager.add('directionality', function(editor) { 14 | function setDir(dir) { 15 | var dom = editor.dom, curDir, blocks = editor.selection.getSelectedBlocks(); 16 | 17 | if (blocks.length) { 18 | curDir = dom.getAttrib(blocks[0], "dir"); 19 | 20 | tinymce.each(blocks, function(block) { 21 | // Add dir to block if the parent block doesn't already have that dir 22 | if (!dom.getParent(block.parentNode, "*[dir='" + dir + "']", dom.getRoot())) { 23 | if (curDir != dir) { 24 | dom.setAttrib(block, "dir", dir); 25 | } else { 26 | dom.setAttrib(block, "dir", null); 27 | } 28 | } 29 | }); 30 | 31 | editor.nodeChanged(); 32 | } 33 | } 34 | 35 | function generateSelector(dir) { 36 | var selector = []; 37 | 38 | tinymce.each('h1 h2 h3 h4 h5 h6 div p'.split(' '), function(name) { 39 | selector.push(name + '[dir=' + dir + ']'); 40 | }); 41 | 42 | return selector.join(','); 43 | } 44 | 45 | editor.addCommand('mceDirectionLTR', function() { 46 | setDir("ltr"); 47 | }); 48 | 49 | editor.addCommand('mceDirectionRTL', function() { 50 | setDir("rtl"); 51 | }); 52 | 53 | editor.addButton('ltr', { 54 | title: 'Left to right', 55 | cmd: 'mceDirectionLTR', 56 | stateSelector: generateSelector('ltr') 57 | }); 58 | 59 | editor.addButton('rtl', { 60 | title: 'Right to left', 61 | cmd: 'mceDirectionRTL', 62 | stateSelector: generateSelector('rtl') 63 | }); 64 | }); -------------------------------------------------------------------------------- /js/tinymce/classes/util/Fun.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Fun.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * Functional utility class. 13 | * 14 | * @private 15 | * @class tinymce.util.Fun 16 | */ 17 | define("tinymce/util/Fun", [], function() { 18 | var slice = [].slice; 19 | 20 | function constant(value) { 21 | return function() { 22 | return value; 23 | }; 24 | } 25 | 26 | function negate(predicate) { 27 | return function(x) { 28 | return !predicate(x); 29 | }; 30 | } 31 | 32 | function compose(f, g) { 33 | return function(x) { 34 | return f(g(x)); 35 | }; 36 | } 37 | 38 | function or() { 39 | var args = slice.call(arguments); 40 | 41 | return function(x) { 42 | for (var i = 0; i < args.length; i++) { 43 | if (args[i](x)) { 44 | return true; 45 | } 46 | } 47 | 48 | return false; 49 | }; 50 | } 51 | 52 | function and() { 53 | var args = slice.call(arguments); 54 | 55 | return function(x) { 56 | for (var i = 0; i < args.length; i++) { 57 | if (!args[i](x)) { 58 | return false; 59 | } 60 | } 61 | 62 | return true; 63 | }; 64 | } 65 | 66 | function curry(fn) { 67 | var args = slice.call(arguments); 68 | 69 | if (args.length - 1 >= fn.length) { 70 | return fn.apply(this, args.slice(1)); 71 | } 72 | 73 | return function() { 74 | var tempArgs = args.concat([].slice.call(arguments)); 75 | return curry.apply(this, tempArgs); 76 | }; 77 | } 78 | 79 | return { 80 | constant: constant, 81 | negate: negate, 82 | and: and, 83 | or: or, 84 | curry: curry, 85 | compose: compose 86 | }; 87 | }); -------------------------------------------------------------------------------- /js/tinymce/classes/dom/Dimensions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Dimensions.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * This module measures nodes and returns client rects. The client rects has an 13 | * extra node property. 14 | * 15 | * @private 16 | * @class tinymce.dom.Dimensions 17 | */ 18 | define("tinymce/dom/Dimensions", [ 19 | "tinymce/util/Arr", 20 | "tinymce/dom/NodeType", 21 | "tinymce/geom/ClientRect" 22 | ], function(Arr, NodeType, ClientRect) { 23 | 24 | function getClientRects(node) { 25 | function toArrayWithNode(clientRects) { 26 | return Arr.map(clientRects, function(clientRect) { 27 | clientRect = ClientRect.clone(clientRect); 28 | clientRect.node = node; 29 | 30 | return clientRect; 31 | }); 32 | } 33 | 34 | if (Arr.isArray(node)) { 35 | return Arr.reduce(node, function(result, node) { 36 | return result.concat(getClientRects(node)); 37 | }, []); 38 | } 39 | 40 | if (NodeType.isElement(node)) { 41 | return toArrayWithNode(node.getClientRects()); 42 | } 43 | 44 | if (NodeType.isText(node)) { 45 | var rng = node.ownerDocument.createRange(); 46 | 47 | rng.setStart(node, 0); 48 | rng.setEnd(node, node.data.length); 49 | 50 | return toArrayWithNode(rng.getClientRects()); 51 | } 52 | } 53 | 54 | return { 55 | /** 56 | * Returns the client rects for a specific node. 57 | * 58 | * @method getClientRects 59 | * @param {Array/DOMNode} node Node or array of nodes to get client rects on. 60 | * @param {Array} Array of client rects with a extra node property. 61 | */ 62 | getClientRects: getClientRects 63 | }; 64 | }); -------------------------------------------------------------------------------- /js/tinymce/themes/inlite/src/main/js/tinymce/inlite/core/Measure.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Measure.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2016 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | define('tinymce/inlite/core/Measure', [ 12 | 'global!tinymce.DOM', 13 | 'global!tinymce.geom.Rect', 14 | 'tinymce/inlite/core/Convert' 15 | ], function (DOM, Rect, Convert) { 16 | var toAbsolute = function (rect) { 17 | var vp = DOM.getViewPort(); 18 | 19 | return { 20 | x: rect.x + vp.x, 21 | y: rect.y + vp.y, 22 | w: rect.w, 23 | h: rect.h 24 | }; 25 | }; 26 | 27 | var measureElement = function (elm) { 28 | var clientRect = elm.getBoundingClientRect(); 29 | 30 | return toAbsolute({ 31 | x: clientRect.left, 32 | y: clientRect.top, 33 | w: Math.max(elm.clientWidth, elm.offsetWidth), 34 | h: Math.max(elm.clientHeight, elm.offsetHeight) 35 | }); 36 | }; 37 | 38 | var getElementRect = function (editor, elm) { 39 | return measureElement(elm); 40 | }; 41 | 42 | var getPageAreaRect = function (editor) { 43 | return measureElement(editor.getElement().ownerDocument.body); 44 | }; 45 | 46 | var getContentAreaRect = function (editor) { 47 | return measureElement(editor.getContentAreaContainer() || editor.getBody()); 48 | }; 49 | 50 | var getSelectionRect = function (editor) { 51 | var clientRect = editor.selection.getBoundingClientRect(); 52 | return clientRect ? toAbsolute(Convert.fromClientRect(clientRect)) : null; 53 | }; 54 | 55 | return { 56 | getElementRect: getElementRect, 57 | getPageAreaRect: getPageAreaRect, 58 | getContentAreaRect: getContentAreaRect, 59 | getSelectionRect: getSelectionRect 60 | }; 61 | }); 62 | -------------------------------------------------------------------------------- /js/tinymce/classes/ui/ColorBox.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ColorBox.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * This widget lets you enter colors and browse for colors by pressing the color button. It also displays 13 | * a preview of the current color. 14 | * 15 | * @-x-less ColorBox.less 16 | * @class tinymce.ui.ColorBox 17 | * @extends tinymce.ui.ComboBox 18 | */ 19 | define("tinymce/ui/ColorBox", [ 20 | "tinymce/ui/ComboBox" 21 | ], function(ComboBox) { 22 | "use strict"; 23 | 24 | return ComboBox.extend({ 25 | /** 26 | * Constructs a new control instance with the specified settings. 27 | * 28 | * @constructor 29 | * @param {Object} settings Name/value object with settings. 30 | */ 31 | init: function(settings) { 32 | var self = this; 33 | 34 | settings.spellcheck = false; 35 | 36 | if (settings.onaction) { 37 | settings.icon = 'none'; 38 | } 39 | 40 | self._super(settings); 41 | 42 | self.classes.add('colorbox'); 43 | self.on('change keyup postrender', function() { 44 | self.repaintColor(self.value()); 45 | }); 46 | }, 47 | 48 | repaintColor: function(value) { 49 | var elm = this.getEl().getElementsByTagName('i')[0]; 50 | 51 | if (elm) { 52 | try { 53 | elm.style.background = value; 54 | } catch (ex) { 55 | // Ignore 56 | } 57 | } 58 | }, 59 | 60 | bindStates: function() { 61 | var self = this; 62 | 63 | self.state.on('change:value', function(e) { 64 | if (self.state.get('rendered')) { 65 | self.repaintColor(e.value); 66 | } 67 | }); 68 | 69 | return self._super(); 70 | } 71 | }); 72 | }); -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/FloatPanel.less: -------------------------------------------------------------------------------- 1 | // FloatPanel 2 | 3 | .@{prefix}-floatpanel { 4 | position: absolute; 5 | .box-shadow(@floatpanel-box-shadow); 6 | } 7 | 8 | .@{prefix}-floatpanel.@{prefix}-fixed { 9 | position: fixed; 10 | } 11 | 12 | // Popover panel 13 | 14 | .@{prefix}-floatpanel .@{prefix}-arrow, 15 | .@{prefix}-floatpanel .@{prefix}-arrow:after { 16 | position: absolute; 17 | display: block; 18 | width: 0; 19 | height: 0; 20 | border-color: transparent; 21 | border-style: solid; 22 | } 23 | 24 | .@{prefix}-floatpanel .@{prefix}-arrow { 25 | border-width: @popover-arrow-outer-width; 26 | } 27 | 28 | .@{prefix}-floatpanel .@{prefix}-arrow:after { 29 | border-width: @popover-arrow-width; 30 | content: ""; 31 | } 32 | 33 | .@{prefix}-floatpanel.@{prefix}-popover { 34 | .reset-gradient(); 35 | .border-radius(6px); 36 | .box-shadow(@floatpanel-box-shadow); 37 | top: 0; 38 | left: 0; 39 | background: @popover-bg; 40 | border: 1px solid @panel-border; 41 | border: 1px solid @popover-arrow-outer; 42 | 43 | &.@{prefix}-bottom { 44 | margin-top: @popover-arrow-width; 45 | *margin-top: 0; 46 | 47 | & > .@{prefix}-arrow { 48 | left: 50%; 49 | margin-left: -@popover-arrow-outer-width; 50 | border-top-width: 0; 51 | border-bottom-color: @panel-border; 52 | border-bottom-color: @popover-arrow-outer; 53 | top: -@popover-arrow-outer-width; 54 | 55 | &:after { 56 | top: 1px; 57 | margin-left: -@popover-arrow-width; 58 | border-top-width: 0; 59 | border-bottom-color: @popover-arrow; 60 | } 61 | } 62 | 63 | &.@{prefix}-start { margin-left: -22px; } 64 | &.@{prefix}-start > .@{prefix}-arrow { left: 20px; } 65 | 66 | &.@{prefix}-end { margin-left: 22px; } 67 | &.@{prefix}-end > .@{prefix}-arrow { right: 10px; left: auto; } 68 | } 69 | } -------------------------------------------------------------------------------- /js/tinymce/classes/ui/AbsoluteLayout.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AbsoluteLayout.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * LayoutManager for absolute positioning. This layout manager is more of 13 | * a base class for other layouts but can be created and used directly. 14 | * 15 | * @-x-less AbsoluteLayout.less 16 | * @class tinymce.ui.AbsoluteLayout 17 | * @extends tinymce.ui.Layout 18 | */ 19 | define("tinymce/ui/AbsoluteLayout", [ 20 | "tinymce/ui/Layout" 21 | ], function(Layout) { 22 | "use strict"; 23 | 24 | return Layout.extend({ 25 | Defaults: { 26 | containerClass: 'abs-layout', 27 | controlClass: 'abs-layout-item' 28 | }, 29 | 30 | /** 31 | * Recalculates the positions of the controls in the specified container. 32 | * 33 | * @method recalc 34 | * @param {tinymce.ui.Container} container Container instance to recalc. 35 | */ 36 | recalc: function(container) { 37 | container.items().filter(':visible').each(function(ctrl) { 38 | var settings = ctrl.settings; 39 | 40 | ctrl.layoutRect({ 41 | x: settings.x, 42 | y: settings.y, 43 | w: settings.w, 44 | h: settings.h 45 | }); 46 | 47 | if (ctrl.recalc) { 48 | ctrl.recalc(); 49 | } 50 | }); 51 | }, 52 | 53 | /** 54 | * Renders the specified container and any layout specific HTML. 55 | * 56 | * @method renderHtml 57 | * @param {tinymce.ui.Container} container Container to render HTML for. 58 | */ 59 | renderHtml: function(container) { 60 | return '
' + this._super(container); 61 | } 62 | }); 63 | }); -------------------------------------------------------------------------------- /js/tinymce/plugins/code/plugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * plugin.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /*global tinymce:true */ 12 | 13 | tinymce.PluginManager.add('code', function(editor) { 14 | function showDialog() { 15 | var win = editor.windowManager.open({ 16 | title: "Source code", 17 | body: { 18 | type: 'textbox', 19 | name: 'code', 20 | multiline: true, 21 | minWidth: editor.getParam("code_dialog_width", 600), 22 | minHeight: editor.getParam("code_dialog_height", Math.min(tinymce.DOM.getViewPort().h - 200, 500)), 23 | spellcheck: false, 24 | style: 'direction: ltr; text-align: left' 25 | }, 26 | onSubmit: function(e) { 27 | // We get a lovely "Wrong document" error in IE 11 if we 28 | // don't move the focus to the editor before creating an undo 29 | // transation since it tries to make a bookmark for the current selection 30 | editor.focus(); 31 | 32 | editor.undoManager.transact(function() { 33 | editor.setContent(e.data.code); 34 | }); 35 | 36 | editor.selection.setCursorLocation(); 37 | editor.nodeChanged(); 38 | } 39 | }); 40 | 41 | // Gecko has a major performance issue with textarea 42 | // contents so we need to set it when all reflows are done 43 | win.find('#code').value(editor.getContent({source_view: true})); 44 | } 45 | 46 | editor.addCommand("mceCodeEditor", showDialog); 47 | 48 | editor.addButton('code', { 49 | icon: 'code', 50 | tooltip: 'Source code', 51 | onclick: showDialog 52 | }); 53 | 54 | editor.addMenuItem('code', { 55 | icon: 'code', 56 | text: 'Source code', 57 | context: 'tools', 58 | onclick: showDialog 59 | }); 60 | }); -------------------------------------------------------------------------------- /js/tinymce/classes/ui/Resizable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Resizable.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * Resizable mixin. Enables controls to be resized. 13 | * 14 | * @mixin tinymce.ui.Resizable 15 | */ 16 | define("tinymce/ui/Resizable", [ 17 | "tinymce/ui/DomUtils" 18 | ], function(DomUtils) { 19 | "use strict"; 20 | 21 | return { 22 | /** 23 | * Resizes the control to contents. 24 | * 25 | * @method resizeToContent 26 | */ 27 | resizeToContent: function() { 28 | this._layoutRect.autoResize = true; 29 | this._lastRect = null; 30 | this.reflow(); 31 | }, 32 | 33 | /** 34 | * Resizes the control to a specific width/height. 35 | * 36 | * @method resizeTo 37 | * @param {Number} w Control width. 38 | * @param {Number} h Control height. 39 | * @return {tinymce.ui.Control} Current control instance. 40 | */ 41 | resizeTo: function(w, h) { 42 | // TODO: Fix hack 43 | if (w <= 1 || h <= 1) { 44 | var rect = DomUtils.getWindowSize(); 45 | 46 | w = w <= 1 ? w * rect.w : w; 47 | h = h <= 1 ? h * rect.h : h; 48 | } 49 | 50 | this._layoutRect.autoResize = false; 51 | return this.layoutRect({minW: w, minH: h, w: w, h: h}).reflow(); 52 | }, 53 | 54 | /** 55 | * Resizes the control to a specific relative width/height. 56 | * 57 | * @method resizeBy 58 | * @param {Number} dw Relative control width. 59 | * @param {Number} dh Relative control height. 60 | * @return {tinymce.ui.Control} Current control instance. 61 | */ 62 | resizeBy: function(dw, dh) { 63 | var self = this, rect = self.layoutRect(); 64 | 65 | return self.resizeTo(rect.w + dw, rect.h + dh); 66 | } 67 | }; 68 | }); -------------------------------------------------------------------------------- /js/tinymce/plugins/imagetools/src/main/js/ImageSize.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ImageSize.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2016 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | define("tinymce/imagetoolsplugin/ImageSize", [ 12 | ], function() { 13 | function getImageSize(img) { 14 | var width, height; 15 | 16 | function isPxValue(value) { 17 | return /^[0-9\.]+px$/.test(value); 18 | } 19 | 20 | width = img.style.width; 21 | height = img.style.height; 22 | if (width || height) { 23 | if (isPxValue(width) && isPxValue(height)) { 24 | return { 25 | w: parseInt(width, 10), 26 | h: parseInt(height, 10) 27 | }; 28 | } 29 | 30 | return null; 31 | } 32 | 33 | width = img.width; 34 | height = img.height; 35 | 36 | if (width && height) { 37 | return { 38 | w: parseInt(width, 10), 39 | h: parseInt(height, 10) 40 | }; 41 | } 42 | 43 | return null; 44 | } 45 | 46 | function setImageSize(img, size) { 47 | var width, height; 48 | 49 | if (size) { 50 | width = img.style.width; 51 | height = img.style.height; 52 | 53 | if (width || height) { 54 | img.style.width = size.w + 'px'; 55 | img.style.height = size.h + 'px'; 56 | img.removeAttribute('data-mce-style'); 57 | } 58 | 59 | width = img.width; 60 | height = img.height; 61 | 62 | if (width || height) { 63 | img.setAttribute('width', size.w); 64 | img.setAttribute('height', size.h); 65 | } 66 | } 67 | } 68 | 69 | function getNaturalImageSize(img) { 70 | return { 71 | w: img.naturalWidth, 72 | h: img.naturalHeight 73 | }; 74 | } 75 | 76 | return { 77 | getImageSize: getImageSize, 78 | setImageSize: setImageSize, 79 | getNaturalImageSize: getNaturalImageSize 80 | }; 81 | }); 82 | -------------------------------------------------------------------------------- /tests/manual/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Manual test files 5 | 6 | 7 | 8 |

Manual tests

9 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /js/tinymce/plugins/example/plugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * plugin.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /*jshint unused:false */ 12 | /*global tinymce:true */ 13 | 14 | /** 15 | * Example plugin that adds a toolbar button and menu item. 16 | */ 17 | tinymce.PluginManager.add('example', function(editor, url) { 18 | // Add a button that opens a window 19 | editor.addButton('example', { 20 | text: 'My button', 21 | icon: false, 22 | onclick: function() { 23 | // Open window 24 | editor.windowManager.open({ 25 | title: 'Example plugin', 26 | body: [ 27 | {type: 'textbox', name: 'title', label: 'Title'} 28 | ], 29 | onsubmit: function(e) { 30 | // Insert content when the window form is submitted 31 | editor.insertContent('Title: ' + e.data.title); 32 | } 33 | }); 34 | } 35 | }); 36 | 37 | // Adds a menu item to the tools menu 38 | editor.addMenuItem('example', { 39 | text: 'Example plugin', 40 | context: 'tools', 41 | onclick: function() { 42 | // Open window with a specific url 43 | editor.windowManager.open({ 44 | title: 'TinyMCE site', 45 | url: url + '/dialog.html', 46 | width: 600, 47 | height: 400, 48 | buttons: [ 49 | { 50 | text: 'Insert', 51 | onclick: function() { 52 | // Top most window object 53 | var win = editor.windowManager.getWindows()[0]; 54 | 55 | // Insert the contents of the dialog.html textarea into the editor 56 | editor.insertContent(win.getContentWindow().document.getElementById('content').value); 57 | 58 | // Close the window 59 | win.close(); 60 | } 61 | }, 62 | 63 | {text: 'Close', onclick: 'close'} 64 | ] 65 | }); 66 | } 67 | }); 68 | }); -------------------------------------------------------------------------------- /tests/tinymce/file/ImageScanner.js: -------------------------------------------------------------------------------- 1 | ModuleLoader.require([ 2 | "tinymce/file/ImageScanner", 3 | "tinymce/file/UploadStatus", 4 | "tinymce/file/BlobCache", 5 | "tinymce/Env" 6 | ], function(ImageScanner, UploadStatus, BlobCache, Env) { 7 | if (!tinymce.Env.fileApi) { 8 | return; 9 | } 10 | 11 | module("tinymce.file.ImageScanner"); 12 | 13 | var base64Src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw=='; 14 | 15 | QUnit.asyncTest("findAll", function() { 16 | var imageScanner = new ImageScanner(new UploadStatus(), new BlobCache()); 17 | 18 | document.getElementById('view').innerHTML = ( 19 | '' + 20 | '' + 21 | '' + 22 | '' 23 | ); 24 | 25 | imageScanner.findAll(document.getElementById('view')).then(function(result) { 26 | QUnit.start(); 27 | equal(result.length, 1); 28 | equal('data:image/gif;base64,' + result[0].blobInfo.base64(), base64Src); 29 | strictEqual(result[0].image, document.getElementById('view').firstChild); 30 | }); 31 | }); 32 | 33 | QUnit.asyncTest("findAll (filtered)", function() { 34 | var imageScanner = new ImageScanner(new UploadStatus(), new BlobCache()); 35 | 36 | function predicate(img) { 37 | return !img.hasAttribute('data-skip'); 38 | } 39 | 40 | document.getElementById('view').innerHTML = ( 41 | '' + 42 | '' 43 | ); 44 | 45 | imageScanner.findAll(document.getElementById('view'), predicate).then(function(result) { 46 | QUnit.start(); 47 | equal(result.length, 1); 48 | equal('data:image/gif;base64,' + result[0].blobInfo.base64(), base64Src); 49 | strictEqual(result[0].image, document.getElementById('view').firstChild); 50 | }); 51 | }); 52 | }); -------------------------------------------------------------------------------- /js/tinymce/classes/ui/Tooltip.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Tooltip.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * Creates a tooltip instance. 13 | * 14 | * @-x-less ToolTip.less 15 | * @class tinymce.ui.ToolTip 16 | * @extends tinymce.ui.Control 17 | * @mixes tinymce.ui.Movable 18 | */ 19 | define("tinymce/ui/Tooltip", [ 20 | "tinymce/ui/Control", 21 | "tinymce/ui/Movable" 22 | ], function(Control, Movable) { 23 | return Control.extend({ 24 | Mixins: [Movable], 25 | 26 | Defaults: { 27 | classes: 'widget tooltip tooltip-n' 28 | }, 29 | 30 | /** 31 | * Renders the control as a HTML string. 32 | * 33 | * @method renderHtml 34 | * @return {String} HTML representing the control. 35 | */ 36 | renderHtml: function() { 37 | var self = this, prefix = self.classPrefix; 38 | 39 | return ( 40 | '' 44 | ); 45 | }, 46 | 47 | bindStates: function() { 48 | var self = this; 49 | 50 | self.state.on('change:text', function(e) { 51 | self.getEl().lastChild.innerHTML = self.encode(e.value); 52 | }); 53 | 54 | return self._super(); 55 | }, 56 | 57 | /** 58 | * Repaints the control after a layout operation. 59 | * 60 | * @method repaint 61 | */ 62 | repaint: function() { 63 | var self = this, style, rect; 64 | 65 | style = self.getEl().style; 66 | rect = self._layoutRect; 67 | 68 | style.left = rect.x + 'px'; 69 | style.top = rect.y + 'px'; 70 | style.zIndex = 0xFFFF + 0xFFFF; 71 | } 72 | }); 73 | }); -------------------------------------------------------------------------------- /js/tinymce/plugins/emoticons/plugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * plugin.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /*global tinymce:true */ 12 | 13 | tinymce.PluginManager.add('emoticons', function(editor, url) { 14 | var emoticons = [ 15 | ["cool", "cry", "embarassed", "foot-in-mouth"], 16 | ["frown", "innocent", "kiss", "laughing"], 17 | ["money-mouth", "sealed", "smile", "surprised"], 18 | ["tongue-out", "undecided", "wink", "yell"] 19 | ]; 20 | 21 | function getHtml() { 22 | var emoticonsHtml; 23 | 24 | emoticonsHtml = ''; 25 | 26 | tinymce.each(emoticons, function(row) { 27 | emoticonsHtml += ''; 28 | 29 | tinymce.each(row, function(icon) { 30 | var emoticonUrl = url + '/img/smiley-' + icon + '.gif'; 31 | 32 | emoticonsHtml += ''; 35 | }); 36 | 37 | emoticonsHtml += ''; 38 | }); 39 | 40 | emoticonsHtml += '
'; 41 | 42 | return emoticonsHtml; 43 | } 44 | 45 | editor.addButton('emoticons', { 46 | type: 'panelbutton', 47 | panel: { 48 | role: 'application', 49 | autohide: true, 50 | html: getHtml, 51 | onclick: function(e) { 52 | var linkElm = editor.dom.getParent(e.target, 'a'); 53 | 54 | if (linkElm) { 55 | editor.insertContent( 56 | '' + linkElm.getAttribute('data-mce-alt') + '' 57 | ); 58 | 59 | this.hide(); 60 | } 61 | } 62 | }, 63 | tooltip: 'Emoticons' 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /tools/tasks/bundle.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"); 2 | var path = require("path"); 3 | 4 | module.exports = function(grunt) { 5 | grunt.registerMultiTask("bundle", "Bundles code, themes and bundles to a single file.", function() { 6 | var options, contents, themes, plugins; 7 | 8 | function appendFile(src) { 9 | src = src.replace(/\\/g, '/'); 10 | 11 | if (fs.existsSync(src)) { 12 | grunt.log.writeln("Appending file:", src); 13 | contents += grunt.file.read(src); 14 | } else { 15 | grunt.fail.fatal("Could not find file: " + src); 16 | } 17 | } 18 | 19 | function append(dirPath, fileName, value) { 20 | if (value) { 21 | value.split(/,/).forEach(function(src) { 22 | appendFile(path.join(dirPath, src, fileName)); 23 | }); 24 | } 25 | } 26 | 27 | options = grunt.config([this.name, this.target]).options; 28 | options.themesDir = options.themesDir || "plugins"; 29 | options.themeFileName = options.themeFileName || "theme.min.js"; 30 | options.pluginsDir = options.pluginsDir || "plugins"; 31 | options.pluginFileName = options.pluginFileName || "plugin.min.js"; 32 | options.outputPath = options.outputPath || "full.min.js"; 33 | 34 | themes = grunt.option("themes"); 35 | plugins = grunt.option("plugins"); 36 | 37 | if (!themes && !plugins) { 38 | grunt.log.writeln("Use: grunt bundle --themes --plugins "); 39 | process.exit(-1); 40 | return; 41 | } 42 | 43 | contents = ""; 44 | this.files.forEach(function(filePair) { 45 | filePair.src.forEach(function(src) { 46 | appendFile(src); 47 | }); 48 | }); 49 | 50 | append(options.themesDir, options.themeFileName, themes); 51 | append(options.pluginsDir, options.pluginFileName, plugins); 52 | 53 | if (contents.length > 0) { 54 | grunt.file.write(options.outputPath, contents); 55 | grunt.log.ok("Created bundle js:", options.outputPath); 56 | } 57 | }); 58 | }; 59 | -------------------------------------------------------------------------------- /js/tinymce/classes/ui/Progress.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Progress.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * Progress control. 13 | * 14 | * @-x-less Progress.less 15 | * @class tinymce.ui.Progress 16 | * @extends tinymce.ui.Control 17 | */ 18 | define("tinymce/ui/Progress", [ 19 | "tinymce/ui/Widget" 20 | ], function(Widget) { 21 | "use strict"; 22 | 23 | return Widget.extend({ 24 | Defaults: { 25 | value: 0 26 | }, 27 | 28 | init: function(settings) { 29 | var self = this; 30 | 31 | self._super(settings); 32 | self.classes.add('progress'); 33 | 34 | if (!self.settings.filter) { 35 | self.settings.filter = function(value) { 36 | return Math.round(value); 37 | }; 38 | } 39 | }, 40 | 41 | renderHtml: function() { 42 | var self = this, id = self._id, prefix = this.classPrefix; 43 | 44 | return ( 45 | '
' + 46 | '
' + 47 | '
' + 48 | '
' + 49 | '
0%
' + 50 | '
' 51 | ); 52 | }, 53 | 54 | postRender: function() { 55 | var self = this; 56 | 57 | self._super(); 58 | self.value(self.settings.value); 59 | 60 | return self; 61 | }, 62 | 63 | bindStates: function() { 64 | var self = this; 65 | 66 | function setValue(value) { 67 | value = self.settings.filter(value); 68 | self.getEl().lastChild.innerHTML = value + '%'; 69 | self.getEl().firstChild.firstChild.style.width = value + '%'; 70 | } 71 | 72 | self.state.on('change:value', function(e) { 73 | setValue(e.value); 74 | }); 75 | 76 | setValue(self.state.get('value')); 77 | 78 | return self._super(); 79 | } 80 | }); 81 | }); -------------------------------------------------------------------------------- /tests/tinymce/util/I18n.js: -------------------------------------------------------------------------------- 1 | module("tinymce.util.I18n", { 2 | teardown: function() { 3 | tinymce.util.I18n.rtl = false; 4 | } 5 | }); 6 | 7 | test("Translate strings", function() { 8 | tinymce.util.I18n.add("code", { 9 | "text": "text translation", 10 | "value:{0}{1}": "value translation:{0}{1}", 11 | "text{context:something}": "text translation with context", 12 | "value:{0}{1}{context:something}": "value translation:{0}{1} with context" 13 | }); 14 | 15 | equal(tinymce.util.I18n.translate("text"), "text translation"); 16 | equal(tinymce.util.I18n.translate("untranslated text"), "untranslated text"); 17 | equal(tinymce.util.I18n.translate(["untranslated value:{0}{1}", "a", "b"]), "untranslated value:ab"); 18 | equal(tinymce.util.I18n.translate(["value:{0}{1}", "a", "b"]), "value translation:ab"); 19 | equal(tinymce.util.I18n.translate("untranslated text{context:context}"), "untranslated text"); 20 | equal(tinymce.util.I18n.translate(["untranslated value:{0}{1}{context:something}", "a", "b"]), "untranslated value:ab"); 21 | equal(tinymce.util.I18n.translate(["value:{0}{1}{context:something}", "a", "b"]), "value translation:ab with context"); 22 | }); 23 | 24 | test("Switch language", function() { 25 | for (var key in tinymce.util.I18n.data) { 26 | delete tinymce.util.I18n.data[key]; 27 | } 28 | 29 | tinymce.util.I18n.add("code1", { 30 | "text": "translation1" 31 | }); 32 | 33 | equal(tinymce.util.I18n.getCode(), "code1"); 34 | strictEqual(tinymce.util.I18n.rtl, false); 35 | deepEqual(tinymce.util.I18n.data, { 36 | "code1": { 37 | "text": "translation1" 38 | } 39 | }); 40 | 41 | tinymce.util.I18n.add("code2", { 42 | "_dir": "rtl", 43 | "text": "translation2" 44 | }); 45 | 46 | equal(tinymce.util.I18n.getCode(), "code2"); 47 | strictEqual(tinymce.util.I18n.rtl, true); 48 | deepEqual(tinymce.util.I18n.data, { 49 | "code1": { 50 | "text": "translation1" 51 | }, 52 | 53 | "code2": { 54 | "_dir": "rtl", 55 | "text": "translation2" 56 | } 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /js/tinymce/classes/file/UploadStatus.js: -------------------------------------------------------------------------------- 1 | /** 2 | * UploadStatus.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2016 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * Holds the current status of a blob uri, if it's pending or uploaded and what the result urls was. 13 | * 14 | * @private 15 | * @class tinymce.file.UploadStatus 16 | */ 17 | define("tinymce/file/UploadStatus", [ 18 | ], function() { 19 | return function() { 20 | var PENDING = 1, UPLOADED = 2; 21 | var blobUriStatuses = {}; 22 | 23 | function createStatus(status, resultUri) { 24 | return { 25 | status: status, 26 | resultUri: resultUri 27 | }; 28 | } 29 | 30 | function hasBlobUri(blobUri) { 31 | return blobUri in blobUriStatuses; 32 | } 33 | 34 | function getResultUri(blobUri) { 35 | var result = blobUriStatuses[blobUri]; 36 | 37 | return result ? result.resultUri : null; 38 | } 39 | 40 | function isPending(blobUri) { 41 | return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === PENDING : false; 42 | } 43 | 44 | function isUploaded(blobUri) { 45 | return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === UPLOADED : false; 46 | } 47 | 48 | function markPending(blobUri) { 49 | blobUriStatuses[blobUri] = createStatus(PENDING, null); 50 | } 51 | 52 | function markUploaded(blobUri, resultUri) { 53 | blobUriStatuses[blobUri] = createStatus(UPLOADED, resultUri); 54 | } 55 | 56 | function removeFailed(blobUri) { 57 | delete blobUriStatuses[blobUri]; 58 | } 59 | 60 | function destroy() { 61 | blobUriStatuses = {}; 62 | } 63 | 64 | return { 65 | hasBlobUri: hasBlobUri, 66 | getResultUri: getResultUri, 67 | isPending: isPending, 68 | isUploaded: isUploaded, 69 | markPending: markPending, 70 | markUploaded: markUploaded, 71 | removeFailed: removeFailed, 72 | destroy: destroy 73 | }; 74 | }; 75 | }); -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/ButtonGroup.less: -------------------------------------------------------------------------------- 1 | // ButtonGroup 2 | 3 | .btn-group-border-left(@border-color) when (@has-button-borders = true) { 4 | border-left: 1px solid @border-color; 5 | } 6 | 7 | .btn-group-border-right(@border-color) when (@has-button-borders = true) { 8 | border-right: 1px solid @border-color; 9 | } 10 | 11 | 12 | .@{prefix}-btn-group .@{prefix}-btn { 13 | border-width: @btn-group-border-width; 14 | margin: 0; 15 | .border-radius(0); 16 | margin-left: @flow-layout-spacing; 17 | } 18 | 19 | .@{prefix}-btn-group .@{prefix}-btn when (@has-button-borders = true) { 20 | border-left-width: 0; 21 | border-right-width: 0; 22 | margin-left: 0; 23 | } 24 | 25 | .@{prefix}-btn-group:not(:first-child) when (@has-button-borders = true) { 26 | padding-left: 1px; 27 | margin-left: 1px; 28 | } 29 | 30 | .@{prefix}-btn-group:not(:first-child) when (@has-button-borders = false) { 31 | border-left: 1px solid darken(@btn-bg, 15%); 32 | padding-left: @flow-layout-spacing + 1px; 33 | margin-left: @flow-layout-spacing + 1px; 34 | } 35 | 36 | .@{prefix}-btn-group .@{prefix}-first { 37 | .border-radius(3px 0 0 3px); 38 | .btn-group-border-left(@btn-border-left); 39 | margin-left: 0; 40 | } 41 | 42 | .@{prefix}-btn-group .@{prefix}-last { 43 | .border-radius(0 3px 3px 0); 44 | .btn-group-border-right(@btn-border-right); 45 | } 46 | 47 | .@{prefix}-btn-group .@{prefix}-first.@{prefix}-last { 48 | .border-radius(3px); 49 | } 50 | 51 | .@{prefix}-btn-group .@{prefix}-btn.@{prefix}-flow-layout-item { 52 | margin: 0; 53 | } 54 | 55 | // RTL 56 | 57 | .@{prefix}-rtl .@{prefix}-btn-group .@{prefix}-btn { 58 | margin-left: 0; 59 | margin-right: @flow-layout-spacing; 60 | } 61 | 62 | .@{prefix}-rtl .@{prefix}-btn-group .@{prefix}-first { 63 | margin-right: 0; 64 | } 65 | 66 | .@{prefix}-rtl .@{prefix}-btn-group:not(:first-child) { 67 | border-left: none; 68 | border-right:1px solid darken(@btn-bg, 15%); 69 | padding-right: @flow-layout-spacing + 2px; 70 | margin-right: @flow-layout-spacing + 2px; 71 | } 72 | -------------------------------------------------------------------------------- /js/tinymce/plugins/imagetools/src/main/js/Utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Utils.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2016 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | define("tinymce/imagetoolsplugin/Utils", [ 12 | "global!tinymce.util.Promise", 13 | "global!tinymce.util.Tools" 14 | ], function(Promise, Tools) { 15 | var isValue = function (obj) { 16 | return obj !== null && obj !== undefined; 17 | }; 18 | 19 | var traverse = function (json, path) { 20 | var value; 21 | 22 | value = path.reduce(function(result, key) { 23 | return isValue(result) ? result[key] : undefined; 24 | }, json); 25 | 26 | return isValue(value) ? value : null; 27 | }; 28 | 29 | var requestUrlAsBlob = function (url, headers) { 30 | return new Promise(function(resolve) { 31 | var xhr; 32 | 33 | xhr = new XMLHttpRequest(); 34 | 35 | xhr.onreadystatechange = function () { 36 | if (xhr.readyState === 4) { 37 | resolve({ 38 | status: xhr.status, 39 | blob: this.response 40 | }); 41 | } 42 | }; 43 | 44 | xhr.open('GET', url, true); 45 | 46 | Tools.each(headers, function (value, key) { 47 | xhr.setRequestHeader(key, value); 48 | }); 49 | 50 | xhr.responseType = 'blob'; 51 | xhr.send(); 52 | }); 53 | }; 54 | 55 | var readBlob = function (blob) { 56 | return new Promise(function(resolve) { 57 | var fr = new FileReader(); 58 | 59 | fr.onload = function (e) { 60 | var data = e.target; 61 | resolve(data.result); 62 | }; 63 | 64 | fr.readAsText(blob); 65 | }); 66 | }; 67 | 68 | var parseJson = function (text) { 69 | var json; 70 | 71 | try { 72 | json = JSON.parse(text); 73 | } catch (ex) { 74 | // Ignore 75 | } 76 | 77 | return json; 78 | }; 79 | 80 | return { 81 | traverse: traverse, 82 | readBlob: readBlob, 83 | requestUrlAsBlob: requestUrlAsBlob, 84 | parseJson: parseJson 85 | }; 86 | }); 87 | -------------------------------------------------------------------------------- /js/tinymce/skins/lightgray/Mixins.less: -------------------------------------------------------------------------------- 1 | // Mixins 2 | 3 | .opacity(@opacity) { 4 | opacity: @opacity; 5 | @opacityie: @opacity * 100; 6 | filter: ~"alpha(opacity=@{opacityie})"; 7 | zoom: 1; 8 | } 9 | 10 | .vertical-gradient(@startColor, @endColor) when (@has-gradients = true) { 11 | background-color: mix(@startColor, @endColor, 60%); 12 | background-image: -moz-linear-gradient(top, @startColor, @endColor); // FF 3.6+ 13 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@startColor), to(@endColor)); // Safari 4+, Chrome 2+ 14 | background-image: -webkit-linear-gradient(top, @startColor, @endColor); // Safari 5.1+, Chrome 10+ 15 | background-image: -o-linear-gradient(top, @startColor, @endColor); // Opera 11.10 16 | background-image: linear-gradient(to bottom, @startColor, @endColor); // Standard, IE10 17 | background-repeat: repeat-x; 18 | filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)", argb(@startColor), argb(@endColor))); 19 | zoom: 1; 20 | } 21 | 22 | .vertical-gradient(@startColor, @endColor) when (@has-gradients = false) { 23 | background-color: mix(@startColor, @endColor, 60%); 24 | } 25 | 26 | .border-radius(@radius) when (@has-radius = true) { 27 | -webkit-border-radius: @radius; 28 | -moz-border-radius: @radius; 29 | border-radius: @radius; 30 | } 31 | 32 | .box-shadow(@shadowA, @shadowB:X, ...) when (@has-boxshadow = true) { 33 | // Multiple shadow solution from http://toekneestuck.com/blog/2012/05/15/less-css-arguments-variable/ 34 | @props: ~`"@{arguments}".replace(/[\[\]]|\,\sX/g, '')`; 35 | -webkit-box-shadow: @props; 36 | -moz-box-shadow: @props; 37 | box-shadow: @props; 38 | } 39 | 40 | .transition(@transition) { 41 | -webkit-transition: @transition; 42 | transition: @transition; 43 | } 44 | 45 | .inline-block() { 46 | display: inline-block; 47 | *display: inline; 48 | *zoom: 1; 49 | } 50 | 51 | .reset-gradient() { 52 | filter: e(%("progid:DXImageTransform.Microsoft.gradient(enabled = false)")); 53 | background: transparent; 54 | } 55 | -------------------------------------------------------------------------------- /js/tinymce/classes/file/BlobCache.js: -------------------------------------------------------------------------------- 1 | /** 2 | * BlobCache.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * Hold blob info objects where a blob has extra internal information. 13 | * 14 | * @private 15 | * @class tinymce.file.BlobCache 16 | */ 17 | define("tinymce/file/BlobCache", [ 18 | "tinymce/util/Arr", 19 | "tinymce/util/Fun" 20 | ], function(Arr, Fun) { 21 | return function() { 22 | var cache = [], constant = Fun.constant; 23 | 24 | function create(id, blob, base64) { 25 | return { 26 | id: constant(id), 27 | blob: constant(blob), 28 | base64: constant(base64), 29 | blobUri: constant(URL.createObjectURL(blob)) 30 | }; 31 | } 32 | 33 | function add(blobInfo) { 34 | if (!get(blobInfo.id())) { 35 | cache.push(blobInfo); 36 | } 37 | } 38 | 39 | function get(id) { 40 | return findFirst(function(cachedBlobInfo) { 41 | return cachedBlobInfo.id() === id; 42 | }); 43 | } 44 | 45 | function findFirst(predicate) { 46 | return Arr.filter(cache, predicate)[0]; 47 | } 48 | 49 | function getByUri(blobUri) { 50 | return findFirst(function(blobInfo) { 51 | return blobInfo.blobUri() == blobUri; 52 | }); 53 | } 54 | 55 | function removeByUri(blobUri) { 56 | cache = Arr.filter(cache, function(blobInfo) { 57 | if (blobInfo.blobUri() === blobUri) { 58 | URL.revokeObjectURL(blobInfo.blobUri()); 59 | return false; 60 | } 61 | 62 | return true; 63 | }); 64 | } 65 | 66 | function destroy() { 67 | Arr.each(cache, function(cachedBlobInfo) { 68 | URL.revokeObjectURL(cachedBlobInfo.blobUri()); 69 | }); 70 | 71 | cache = []; 72 | } 73 | 74 | return { 75 | create: create, 76 | add: add, 77 | get: get, 78 | getByUri: getByUri, 79 | findFirst: findFirst, 80 | removeByUri: removeByUri, 81 | destroy: destroy 82 | }; 83 | }; 84 | }); -------------------------------------------------------------------------------- /tests/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": { 3 | "module": true, 4 | "asyncTest": false, 5 | "deepEqual": false, 6 | "equal": false, 7 | "expect": false, 8 | "module": false, 9 | "notDeepEqual": false, 10 | "notEqual": false, 11 | "notStrictEqual ": false, 12 | "ok": false, 13 | "QUnit": false, 14 | "raises": false, 15 | "start": false, 16 | "stop": false, 17 | "strictEqual": false, 18 | "test": false, 19 | "throws": false, 20 | "$": false, 21 | "tinymce": false, 22 | "editor": false, 23 | "inlineEditor": false, 24 | "Utils": false, 25 | "google": false, 26 | "ModuleLoader": false 27 | }, 28 | "passfail": false, 29 | "maxerr": 50, 30 | "maxparams": 50, 31 | "maxdepth": 8, 32 | "maxstatements": 150, 33 | //"maxcomplexity": 10, 34 | "camelcase":false, 35 | "browser": true, 36 | "node": false, 37 | "rhino": false, 38 | "couch": false, 39 | "wsh": false, 40 | "jquery": false, 41 | "prototypejs": false, 42 | "mootools": false, 43 | "dojo": false, 44 | "debug": false, 45 | "devel": false, 46 | "es5": false, 47 | "strict": false, 48 | "globalstrict": true, 49 | "asi": false, 50 | "laxbreak": false, 51 | "bitwise": true, 52 | "quotmark": false, 53 | "boss": false, 54 | "curly": true, 55 | "eqeqeq": false, 56 | "eqnull": false, 57 | "evil": true, 58 | "expr": false, 59 | "forin": false, 60 | "immed": true, 61 | "latedef": true, 62 | "loopfunc": false, 63 | "noarg": true, 64 | "regexp": false, 65 | "regexdash": false, 66 | "scripturl": true, 67 | "shadow": false, 68 | "supernew": false, 69 | "undef": true, 70 | "unused": true, 71 | "validthis": false, 72 | "smarttabs": false, 73 | "proto": false, 74 | "onecase": true, 75 | "nonstandard": true, 76 | "multistr": false, 77 | "laxcomma": false, 78 | "lastsemic": false, 79 | "iterator": false, 80 | "funcscope": false, 81 | "esnext": false, 82 | "newcap": false, 83 | "noempty": true, 84 | "nonew": true, 85 | "nomen": false, 86 | "onevar": false, 87 | "plusplus": false, 88 | "sub": false, 89 | "trailing": true, 90 | "white": false 91 | } 92 | -------------------------------------------------------------------------------- /tests/tinymce/fmt/Hooks.js: -------------------------------------------------------------------------------- 1 | ModuleLoader.require(["tinymce/fmt/Hooks"], function(Hooks) { 2 | module("tinymce.fmt.Hooks", { 3 | setupModule: function() { 4 | QUnit.stop(); 5 | 6 | tinymce.init({ 7 | selector: "textarea", 8 | add_unload_trigger: false, 9 | disable_nodechange: true, 10 | skin: false, 11 | entities: 'raw', 12 | indent: false, 13 | init_instance_callback: function(ed) { 14 | editor = ed; 15 | QUnit.start(); 16 | } 17 | }); 18 | } 19 | }); 20 | 21 | test('pre - postProcessHook', function() { 22 | function assertPreHook(setupHtml, setupSelection, expected) { 23 | editor.getBody().innerHTML = setupHtml; 24 | Utils.setSelection.apply(Utils, setupSelection); 25 | Hooks.postProcess('pre', editor); 26 | equal(editor.getContent(), expected); 27 | } 28 | 29 | assertPreHook( 30 | '
a
b
', 31 | ['pre:nth-child(1)', 0, 'pre:nth-child(2)', 1], 32 | '
a

b
' 33 | ); 34 | 35 | assertPreHook( 36 | '
a
b
', 37 | ['pre:nth-child(2)', 0, 'pre:nth-child(2)', 1], 38 | '
a
b
' 39 | ); 40 | 41 | assertPreHook( 42 | '
a
b
', 43 | ['pre:nth-child(2)', 1, 'pre:nth-child(2)', 1], 44 | '
a
b
' 45 | ); 46 | 47 | assertPreHook( 48 | '
a
b
c
', 49 | ['pre:nth-child(1)', 0, 'pre:nth-child(3)', 1], 50 | '
a

b

c
' 51 | ); 52 | 53 | assertPreHook( 54 | '
a
b
', 55 | ['pre:nth-child(1)', 0, 'pre:nth-child(1)', 1], 56 | '
a
b
' 57 | ); 58 | 59 | assertPreHook( 60 | '
a

b

c
', 61 | ['pre:nth-child(1)', 0, 'pre:nth-child(3)', 1], 62 | '
a

b

c
' 63 | ); 64 | 65 | assertPreHook( 66 | '
a
b

c

d
e
', 67 | ['pre:nth-child(1)', 0, 'pre:nth-child(5)', 1], 68 | '
a

b

c

d

e
' 69 | ); 70 | }); 71 | }); 72 | -------------------------------------------------------------------------------- /js/tinymce/classes/ui/ResizeHandle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ResizeHandle.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * Renders a resize handle that fires ResizeStart, Resize and ResizeEnd events. 13 | * 14 | * @-x-less ResizeHandle.less 15 | * @class tinymce.ui.ResizeHandle 16 | * @extends tinymce.ui.Widget 17 | */ 18 | define("tinymce/ui/ResizeHandle", [ 19 | "tinymce/ui/Widget", 20 | "tinymce/ui/DragHelper" 21 | ], function(Widget, DragHelper) { 22 | "use strict"; 23 | 24 | return Widget.extend({ 25 | /** 26 | * Renders the control as a HTML string. 27 | * 28 | * @method renderHtml 29 | * @return {String} HTML representing the control. 30 | */ 31 | renderHtml: function() { 32 | var self = this, prefix = self.classPrefix; 33 | 34 | self.classes.add('resizehandle'); 35 | 36 | if (self.settings.direction == "both") { 37 | self.classes.add('resizehandle-both'); 38 | } 39 | 40 | self.canFocus = false; 41 | 42 | return ( 43 | '
' + 44 | '' + 45 | '
' 46 | ); 47 | }, 48 | 49 | /** 50 | * Called after the control has been rendered. 51 | * 52 | * @method postRender 53 | */ 54 | postRender: function() { 55 | var self = this; 56 | 57 | self._super(); 58 | 59 | self.resizeDragHelper = new DragHelper(this._id, { 60 | start: function() { 61 | self.fire('ResizeStart'); 62 | }, 63 | 64 | drag: function(e) { 65 | if (self.settings.direction != "both") { 66 | e.deltaX = 0; 67 | } 68 | 69 | self.fire('Resize', e); 70 | }, 71 | 72 | stop: function() { 73 | self.fire('ResizeEnd'); 74 | } 75 | }); 76 | }, 77 | 78 | remove: function() { 79 | if (this.resizeDragHelper) { 80 | this.resizeDragHelper.destroy(); 81 | } 82 | 83 | return this._super(); 84 | } 85 | }); 86 | }); 87 | -------------------------------------------------------------------------------- /tests/plugins/charmap.js: -------------------------------------------------------------------------------- 1 | ModuleLoader.require([ 2 | ], function() { 3 | module("tinymce.plugins.CharMap", { 4 | setupModule: function() { 5 | QUnit.stop(); 6 | 7 | tinymce.init({ 8 | selector: "textarea", 9 | plugins: "charmap", 10 | add_unload_trigger: false, 11 | init_instance_callback: function(ed) { 12 | window.editor = ed; 13 | QUnit.start(); 14 | } 15 | }); 16 | } 17 | }); 18 | 19 | test('Replace characters by array', function() { 20 | editor.settings.charmap = [ 21 | [65, 'Latin A'], 22 | [66, 'Latin B'] 23 | ]; 24 | 25 | deepEqual(editor.plugins.charmap.getCharMap(), [ 26 | [65, 'Latin A'], 27 | [66, 'Latin B'] 28 | ]); 29 | }); 30 | 31 | test('Replace characters by function', function() { 32 | editor.settings.charmap = function() { 33 | return [ 34 | [65, 'Latin A fun'], 35 | [66, 'Latin B fun'] 36 | ]; 37 | }; 38 | 39 | deepEqual(editor.plugins.charmap.getCharMap(), [ 40 | [65, 'Latin A fun'], 41 | [66, 'Latin B fun'] 42 | ]); 43 | }); 44 | 45 | test('Append characters by array', function() { 46 | editor.settings.charmap = [ 47 | [67, 'Latin C'] 48 | ]; 49 | 50 | editor.settings.charmap_append = [ 51 | [65, 'Latin A'], 52 | [66, 'Latin B'] 53 | ]; 54 | 55 | deepEqual(editor.plugins.charmap.getCharMap(), [ 56 | [67, 'Latin C'], 57 | [65, 'Latin A'], 58 | [66, 'Latin B'] 59 | ]); 60 | }); 61 | 62 | test('Append characters by function', function() { 63 | editor.settings.charmap = [ 64 | [67, 'Latin C'] 65 | ]; 66 | 67 | editor.settings.charmap_append = function() { 68 | return [ 69 | [65, 'Latin A fun'], 70 | [66, 'Latin B fun'] 71 | ]; 72 | }; 73 | 74 | deepEqual(editor.plugins.charmap.getCharMap(), [ 75 | [67, 'Latin C'], 76 | [65, 'Latin A fun'], 77 | [66, 'Latin B fun'] 78 | ]); 79 | }); 80 | 81 | test('Insert character', function() { 82 | var lastEvt; 83 | 84 | editor.on('insertCustomChar', function(e) { 85 | lastEvt = e; 86 | }); 87 | 88 | editor.plugins.charmap.insertChar('A'); 89 | equal(lastEvt.chr, 'A'); 90 | }); 91 | }); 92 | -------------------------------------------------------------------------------- /js/tinymce/classes/data/Binding.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Binding.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * This class gets dynamically extended to provide a binding between two models. This makes it possible to 13 | * sync the state of two properties in two models by a layer of abstraction. 14 | * 15 | * @private 16 | * @class tinymce.data.Binding 17 | */ 18 | define("tinymce/data/Binding", [], function() { 19 | /** 20 | * Constructs a new bidning. 21 | * 22 | * @constructor 23 | * @method Binding 24 | * @param {Object} settings Settings to the binding. 25 | */ 26 | function Binding(settings) { 27 | this.create = settings.create; 28 | } 29 | 30 | /** 31 | * Creates a binding for a property on a model. 32 | * 33 | * @method create 34 | * @param {tinymce.data.ObservableObject} model Model to create binding to. 35 | * @param {String} name Name of property to bind. 36 | * @return {tinymce.data.Binding} Binding instance. 37 | */ 38 | Binding.create = function(model, name) { 39 | return new Binding({ 40 | create: function(otherModel, otherName) { 41 | var bindings; 42 | 43 | function fromSelfToOther(e) { 44 | otherModel.set(otherName, e.value); 45 | } 46 | 47 | function fromOtherToSelf(e) { 48 | model.set(name, e.value); 49 | } 50 | 51 | otherModel.on('change:' + otherName, fromOtherToSelf); 52 | model.on('change:' + name, fromSelfToOther); 53 | 54 | // Keep track of the bindings 55 | bindings = otherModel._bindings; 56 | 57 | if (!bindings) { 58 | bindings = otherModel._bindings = []; 59 | 60 | otherModel.on('destroy', function() { 61 | var i = bindings.length; 62 | 63 | while (i--) { 64 | bindings[i](); 65 | } 66 | }); 67 | } 68 | 69 | bindings.push(function() { 70 | model.off('change:' + name, fromSelfToOther); 71 | }); 72 | 73 | return model.get(name); 74 | } 75 | }); 76 | }; 77 | 78 | return Binding; 79 | }); -------------------------------------------------------------------------------- /js/tinymce/classes/ui/ElementPath.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ElementPath.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * This control creates an path for the current selections parent elements in TinyMCE. 13 | * 14 | * @class tinymce.ui.ElementPath 15 | * @extends tinymce.ui.Path 16 | */ 17 | define("tinymce/ui/ElementPath", [ 18 | "tinymce/ui/Path" 19 | ], function(Path) { 20 | return Path.extend({ 21 | /** 22 | * Post render method. Called after the control has been rendered to the target. 23 | * 24 | * @method postRender 25 | * @return {tinymce.ui.ElementPath} Current combobox instance. 26 | */ 27 | postRender: function() { 28 | var self = this, editor = self.settings.editor; 29 | 30 | function isHidden(elm) { 31 | if (elm.nodeType === 1) { 32 | if (elm.nodeName == "BR" || !!elm.getAttribute('data-mce-bogus')) { 33 | return true; 34 | } 35 | 36 | if (elm.getAttribute('data-mce-type') === 'bookmark') { 37 | return true; 38 | } 39 | } 40 | 41 | return false; 42 | } 43 | 44 | if (editor.settings.elementpath !== false) { 45 | self.on('select', function(e) { 46 | editor.focus(); 47 | editor.selection.select(this.row()[e.index].element); 48 | editor.nodeChanged(); 49 | }); 50 | 51 | editor.on('nodeChange', function(e) { 52 | var outParents = [], parents = e.parents, i = parents.length; 53 | 54 | while (i--) { 55 | if (parents[i].nodeType == 1 && !isHidden(parents[i])) { 56 | var args = editor.fire('ResolveName', { 57 | name: parents[i].nodeName.toLowerCase(), 58 | target: parents[i] 59 | }); 60 | 61 | if (!args.isDefaultPrevented()) { 62 | outParents.push({name: args.name, element: parents[i]}); 63 | } 64 | 65 | if (args.isPropagationStopped()) { 66 | break; 67 | } 68 | } 69 | } 70 | 71 | self.row(outParents); 72 | }); 73 | } 74 | 75 | return self._super(); 76 | } 77 | }); 78 | }); -------------------------------------------------------------------------------- /js/tinymce/plugins/wordcount/plugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * plugin.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /*global tinymce:true */ 12 | 13 | tinymce.PluginManager.add('wordcount', function(editor) { 14 | var self = this, countre, cleanre; 15 | 16 | // Included most unicode blocks see: http://en.wikipedia.org/wiki/Unicode_block 17 | // Latin-1_Supplement letters, a-z, u2019 == ’ 18 | countre = editor.getParam('wordcount_countregex', /[\w\u2019\x27\-\u00C0-\u1FFF]+/g); 19 | cleanre = editor.getParam('wordcount_cleanregex', /[0-9.(),;:!?%#$?\x27\x22_+=\\\/\-]*/g); 20 | 21 | function update() { 22 | editor.theme.panel.find('#wordcount').text(['Words: {0}', self.getCount()]); 23 | } 24 | 25 | editor.on('init', function() { 26 | var statusbar = editor.theme.panel && editor.theme.panel.find('#statusbar')[0]; 27 | 28 | if (statusbar) { 29 | tinymce.util.Delay.setEditorTimeout(editor, function() { 30 | statusbar.insert({ 31 | type: 'label', 32 | name: 'wordcount', 33 | text: ['Words: {0}', self.getCount()], 34 | classes: 'wordcount', 35 | disabled: editor.settings.readonly 36 | }, 0); 37 | 38 | editor.on('setcontent beforeaddundo', update); 39 | 40 | editor.on('keyup', function(e) { 41 | if (e.keyCode == 32) { 42 | update(); 43 | } 44 | }); 45 | }, 0); 46 | } 47 | }); 48 | 49 | self.getCount = function() { 50 | var tx = editor.getContent({format: 'raw'}); 51 | var tc = 0; 52 | 53 | if (tx) { 54 | tx = tx.replace(/\.\.\./g, ' '); // convert ellipses to spaces 55 | tx = tx.replace(/<.[^<>]*?>/g, ' ').replace(/ | /gi, ' '); // remove html tags and space chars 56 | 57 | // deal with html entities 58 | tx = tx.replace(/(\w+)(&#?[a-z0-9]+;)+(\w+)/i, "$1$3").replace(/&.+?;/g, ' '); 59 | tx = tx.replace(cleanre, ''); // remove numbers and punctuation 60 | 61 | var wordArray = tx.match(countre); 62 | if (wordArray) { 63 | tc = wordArray.length; 64 | } 65 | } 66 | 67 | return tc; 68 | }; 69 | }); -------------------------------------------------------------------------------- /js/tinymce/classes/LegacyInput.js: -------------------------------------------------------------------------------- 1 | /** 2 | * LegacyInput.js 3 | * 4 | * Released under LGPL License. 5 | * Copyright (c) 1999-2015 Ephox Corp. All rights reserved 6 | * 7 | * License: http://www.tinymce.com/license 8 | * Contributing: http://www.tinymce.com/contributing 9 | */ 10 | 11 | /** 12 | * Converts legacy input to modern HTML. 13 | * 14 | * @class tinymce.LegacyInput 15 | * @private 16 | */ 17 | define("tinymce/LegacyInput", [ 18 | "tinymce/EditorManager", 19 | "tinymce/util/Tools" 20 | ], function(EditorManager, Tools) { 21 | var each = Tools.each, explode = Tools.explode; 22 | 23 | EditorManager.on('AddEditor', function(e) { 24 | var editor = e.editor; 25 | 26 | editor.on('preInit', function() { 27 | var filters, fontSizes, dom, settings = editor.settings; 28 | 29 | function replaceWithSpan(node, styles) { 30 | each(styles, function(value, name) { 31 | if (value) { 32 | dom.setStyle(node, name, value); 33 | } 34 | }); 35 | 36 | dom.rename(node, 'span'); 37 | } 38 | 39 | function convert(e) { 40 | dom = editor.dom; 41 | 42 | if (settings.convert_fonts_to_spans) { 43 | each(dom.select('font,u,strike', e.node), function(node) { 44 | filters[node.nodeName.toLowerCase()](dom, node); 45 | }); 46 | } 47 | } 48 | 49 | if (settings.inline_styles) { 50 | fontSizes = explode(settings.font_size_legacy_values); 51 | 52 | filters = { 53 | font: function(dom, node) { 54 | replaceWithSpan(node, { 55 | backgroundColor: node.style.backgroundColor, 56 | color: node.color, 57 | fontFamily: node.face, 58 | fontSize: fontSizes[parseInt(node.size, 10) - 1] 59 | }); 60 | }, 61 | 62 | u: function(dom, node) { 63 | // HTML5 allows U element 64 | if (editor.settings.schema === "html4") { 65 | replaceWithSpan(node, { 66 | textDecoration: 'underline' 67 | }); 68 | } 69 | }, 70 | 71 | strike: function(dom, node) { 72 | replaceWithSpan(node, { 73 | textDecoration: 'line-through' 74 | }); 75 | } 76 | }; 77 | 78 | editor.on('PreProcess SetContent', convert); 79 | } 80 | }); 81 | }); 82 | }); --------------------------------------------------------------------------------