trying to make it work with the precompilation of assets (issue with Aloha and TinyMCE)
3
Gemfile
@ -12,7 +12,7 @@ gem 'cancan', '~> 1.6.7'
|
|||||||
gem 'mongo', '~> 1.5.2'
|
gem 'mongo', '~> 1.5.2'
|
||||||
gem 'bson_ext', '~> 1.5.2'
|
gem 'bson_ext', '~> 1.5.2'
|
||||||
gem 'mongoid', '~> 2.4.0'
|
gem 'mongoid', '~> 2.4.0'
|
||||||
gem 'locomotive_mongoid_acts_as_tree', :git => 'git@github.com:locomotivecms/mongoid_acts_as_tree.git'
|
gem 'locomotive_mongoid_acts_as_tree', '~> 0.1.5.8'
|
||||||
gem 'custom_fields', :path => '../gems/custom_fields' # DEV
|
gem 'custom_fields', :path => '../gems/custom_fields' # DEV
|
||||||
# gem 'custom_fields', :git => 'git://github.com/locomotivecms/custom_fields.git', :branch => 'experimental'
|
# gem 'custom_fields', :git => 'git://github.com/locomotivecms/custom_fields.git', :branch => 'experimental'
|
||||||
gem 'kaminari'
|
gem 'kaminari'
|
||||||
@ -26,6 +26,7 @@ gem 'jquery-rails', '~> 1.0.16'
|
|||||||
gem 'rails-backbone', '0.5.4'
|
gem 'rails-backbone', '0.5.4'
|
||||||
gem 'codemirror-rails'
|
gem 'codemirror-rails'
|
||||||
gem 'tinymce-rails'
|
gem 'tinymce-rails'
|
||||||
|
gem 'locomotive-aloha-rails', :path => '../gems/aloha-rails'
|
||||||
gem 'flash_cookie_session', '~> 1.1.1'
|
gem 'flash_cookie_session', '~> 1.1.1'
|
||||||
|
|
||||||
gem 'locomotive_liquid', '2.2.2', :require => 'liquid'
|
gem 'locomotive_liquid', '2.2.2', :require => 'liquid'
|
||||||
|
12
Gemfile.lock
@ -1,8 +1,8 @@
|
|||||||
GIT
|
PATH
|
||||||
remote: git@github.com:locomotivecms/mongoid_acts_as_tree.git
|
remote: ../gems/aloha-rails
|
||||||
revision: ca494d22c3d7946385aba1153c017d9c30e9f9d3
|
|
||||||
specs:
|
specs:
|
||||||
locomotive_mongoid_acts_as_tree (0.1.5.7)
|
locomotive-aloha-rails (0.20.1)
|
||||||
|
railties (>= 3.1)
|
||||||
|
|
||||||
PATH
|
PATH
|
||||||
remote: ../gems/custom_fields
|
remote: ../gems/custom_fields
|
||||||
@ -163,6 +163,7 @@ GEM
|
|||||||
launchy (2.0.5)
|
launchy (2.0.5)
|
||||||
addressable (~> 2.2.6)
|
addressable (~> 2.2.6)
|
||||||
locomotive_liquid (2.2.2)
|
locomotive_liquid (2.2.2)
|
||||||
|
locomotive_mongoid_acts_as_tree (0.1.5.8)
|
||||||
mail (2.3.0)
|
mail (2.3.0)
|
||||||
i18n (>= 0.4.0)
|
i18n (>= 0.4.0)
|
||||||
mime-types (~> 1.16)
|
mime-types (~> 1.16)
|
||||||
@ -314,8 +315,9 @@ DEPENDENCIES
|
|||||||
jquery-rails (~> 1.0.16)
|
jquery-rails (~> 1.0.16)
|
||||||
kaminari
|
kaminari
|
||||||
launchy
|
launchy
|
||||||
|
locomotive-aloha-rails!
|
||||||
locomotive_liquid (= 2.2.2)
|
locomotive_liquid (= 2.2.2)
|
||||||
locomotive_mongoid_acts_as_tree!
|
locomotive_mongoid_acts_as_tree (~> 0.1.5.8)
|
||||||
mimetype-fu (~> 0.1.2)
|
mimetype-fu (~> 0.1.2)
|
||||||
mocha (= 0.9.12)
|
mocha (= 0.9.12)
|
||||||
mongo (~> 1.5.2)
|
mongo (~> 1.5.2)
|
||||||
|
2
app/assets/javascripts/locomotive/aloha.js.coffee
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#= require ./utils/aloha_settings
|
||||||
|
#= require aloha
|
@ -0,0 +1 @@
|
|||||||
|
#= require jquery
|
@ -1,10 +1,16 @@
|
|||||||
unless window.Aloha?
|
# unless window.Aloha?
|
||||||
window.Aloha = {}
|
# window.Aloha = {}
|
||||||
|
|
||||||
|
Aloha = window.Aloha ?= {}
|
||||||
|
|
||||||
|
Aloha.settings =
|
||||||
|
|
||||||
window.Aloha.settings =
|
|
||||||
logLevels: { 'error': true, 'warn': true, 'info': false, 'debug': false }
|
logLevels: { 'error': true, 'warn': true, 'info': false, 'debug': false }
|
||||||
|
|
||||||
errorhandling: true
|
errorhandling: true
|
||||||
|
|
||||||
plugins:
|
plugins:
|
||||||
|
|
||||||
format:
|
format:
|
||||||
config: [ 'b', 'i', 'u','del','sub','sup', 'p', 'title', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'pre', 'removeFormat']
|
config: [ 'b', 'i', 'u','del','sub','sup', 'p', 'title', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'pre', 'removeFormat']
|
||||||
editables:
|
editables:
|
||||||
@ -25,3 +31,5 @@ window.Aloha.settings =
|
|||||||
|
|
||||||
sidebar:
|
sidebar:
|
||||||
disabled: true
|
disabled: true
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
@import "compass/css3";
|
|
||||||
@import "compass/css3/border-radius";
|
|
||||||
@import "compass/css3/images";
|
|
||||||
@import "compass/css3/text-shadow";
|
|
||||||
@import "locomotive/shared/helpers";
|
|
||||||
|
|
||||||
#panel {
|
|
||||||
.inner {
|
|
||||||
|
|
||||||
padding: 5px 20px 20px 20px;
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #1F82BC;
|
|
||||||
@include hover-link;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.explanations {
|
|
||||||
margin-top: 10px;
|
|
||||||
|
|
||||||
color: #222;
|
|
||||||
font-size: 14px;
|
|
||||||
text-align: justify;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.done {
|
|
||||||
margin: 20px 0px 15px;
|
|
||||||
|
|
||||||
color: #222;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset {
|
|
||||||
ol {
|
|
||||||
li.question {
|
|
||||||
label {
|
|
||||||
display: inline;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=checkbox] {
|
|
||||||
display: inline;
|
|
||||||
width: auto;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
} // li.question
|
|
||||||
|
|
||||||
li {
|
|
||||||
input {
|
|
||||||
&[type=text] { width: 302px; }
|
|
||||||
|
|
||||||
&[type=password] { width: 180px; }
|
|
||||||
}
|
|
||||||
|
|
||||||
} // li
|
|
||||||
} // ol
|
|
||||||
} // fieldset
|
|
||||||
} // inner
|
|
||||||
} // panel
|
|
@ -3,5 +3,5 @@
|
|||||||
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
|
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
|
||||||
* the top of the compiled file, but it's generally better to create a new file per style scope.
|
* the top of the compiled file, but it's generally better to create a new file per style scope.
|
||||||
*= require locomotive/blueprint/screen.css
|
*= require locomotive/blueprint/screen.css
|
||||||
*= require ./simple.css
|
*= require_tree ./not_logged_in
|
||||||
*/
|
*/
|
@ -0,0 +1,60 @@
|
|||||||
|
@import "compass/css3";
|
||||||
|
@import "compass/css3/border-radius";
|
||||||
|
@import "compass/css3/images";
|
||||||
|
@import "compass/css3/text-shadow";
|
||||||
|
@import "locomotive/shared/helpers";
|
||||||
|
|
||||||
|
body.installation {
|
||||||
|
#panel {
|
||||||
|
.inner {
|
||||||
|
|
||||||
|
padding: 5px 20px 20px 20px;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #1F82BC;
|
||||||
|
@include hover-link;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.explanations {
|
||||||
|
margin-top: 10px;
|
||||||
|
|
||||||
|
color: #222;
|
||||||
|
font-size: 14px;
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.done {
|
||||||
|
margin: 20px 0px 15px;
|
||||||
|
|
||||||
|
color: #222;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
ol {
|
||||||
|
li.question {
|
||||||
|
label {
|
||||||
|
display: inline;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=checkbox] {
|
||||||
|
display: inline;
|
||||||
|
width: auto;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
} // li.question
|
||||||
|
|
||||||
|
li {
|
||||||
|
input {
|
||||||
|
&[type=text] { width: 302px; }
|
||||||
|
|
||||||
|
&[type=password] { width: 180px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
} // li
|
||||||
|
} // ol
|
||||||
|
} // fieldset
|
||||||
|
} // inner
|
||||||
|
} // panel
|
||||||
|
}
|
@ -2,7 +2,7 @@
|
|||||||
@import "compass/css3/border-radius";
|
@import "compass/css3/border-radius";
|
||||||
@import "compass/css3/images";
|
@import "compass/css3/images";
|
||||||
@import "compass/css3/text-shadow";
|
@import "compass/css3/text-shadow";
|
||||||
@import "buttons";
|
@import "../backoffice/buttons";
|
||||||
|
|
||||||
body { background: #000 image-url("locomotive/background/body.png") repeat 0 0; }
|
body { background: #000 image-url("locomotive/background/body.png") repeat 0 0; }
|
||||||
|
|
@ -1,117 +0,0 @@
|
|||||||
@mixin clearfix {
|
|
||||||
&:after {
|
|
||||||
content: ".";
|
|
||||||
display: block;
|
|
||||||
height: 0;
|
|
||||||
clear: both;
|
|
||||||
visibility: hidden;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ___ rounded ___ */
|
|
||||||
|
|
||||||
@mixin rounded($side, $radius: 10px, $important: false) {
|
|
||||||
@if $important == true {
|
|
||||||
$important: !important; }
|
|
||||||
@else {
|
|
||||||
$important: ""; }
|
|
||||||
|
|
||||||
border-#{$side}-radius: $radius unquote($important);
|
|
||||||
-moz-border-radius-#{$side}: $radius unquote($important);
|
|
||||||
-webkit-border-#{$side}-radius: $radius unquote($important);
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin border-rounded($vert, $horz, $radius, $important: false) {
|
|
||||||
@if $important == true {
|
|
||||||
$important: !important; }
|
|
||||||
@else {
|
|
||||||
$important: ""; }
|
|
||||||
|
|
||||||
border-#{$vert}-#{$horz}-radius: $radius unquote($important);
|
|
||||||
-moz-border-radius-#{$vert}#{$horz}: $radius unquote($important);
|
|
||||||
-webkit-border-#{$vert}-#{$horz}-radius: $radius unquote($important);
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin full-rounded($radius: 10px) {
|
|
||||||
border-radius: $radius;
|
|
||||||
-moz-border-radius: $radius;
|
|
||||||
-webkit-border-radius: $radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ___ box shadow ___ */
|
|
||||||
|
|
||||||
@mixin box-shadow($hoffset, $voffset, $depth, $color) {
|
|
||||||
box-shadow: $hoffset $voffset $depth $color;
|
|
||||||
-moz-box-shadow: $hoffset $voffset $depth $color;
|
|
||||||
-webkit-box-shadow: $hoffset $voffset $depth $color;
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin box-shadow-with-inset($color_top, $color_bottom: $color_top, $important: false) {
|
|
||||||
$color_bottom: $color_top !default;
|
|
||||||
|
|
||||||
@if $important == true {
|
|
||||||
$important: " !important"; }
|
|
||||||
@else {
|
|
||||||
$important: ""; }
|
|
||||||
|
|
||||||
box-shadow: inset 0 1px 0 0 $color_top, 0 1px 0 0 $color_bottom unquote($important);
|
|
||||||
-moz-box-shadow: inset 0 1px 0 0 $color_top, 0 1px 0 0 $color_bottom unquote($important);
|
|
||||||
-webkit-box-shadow: inset 0 1px 0 0 $color_top, 0 1px 0 0 $color_bottom unquote($important);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin no-box-shadow($important: false) {
|
|
||||||
@if $important == true {
|
|
||||||
$important: " !important"; }
|
|
||||||
@else {
|
|
||||||
$important: ""; }
|
|
||||||
|
|
||||||
box-shadow: none $important;
|
|
||||||
-moz-box-shadow: none $important;
|
|
||||||
-webkit-box-shadow: none $important;
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin popup-box {
|
|
||||||
@include full-rounded(4px);
|
|
||||||
box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.17), 3px 3px 5px 0 rgba(0, 0, 0, 0.41);
|
|
||||||
-moz-box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.17), 3px 3px 5px 0 rgba(0, 0, 0, 0.41);
|
|
||||||
-webkit-box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.17), 3px 3px 5px 0 rgba(0, 0, 0, 0.41);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ___ others ___ */
|
|
||||||
|
|
||||||
@mixin reset {
|
|
||||||
padding: 0px;
|
|
||||||
margin: 0px;
|
|
||||||
list-style: none;
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin absolute-position($vside, $vvalue, $hside, $hvalue, $display: block) {
|
|
||||||
display: $display;
|
|
||||||
position: absolute;
|
|
||||||
#{$vside}: $vvalue;
|
|
||||||
#{$hside}: $hvalue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin linear-background-gradient($from, $to) {
|
|
||||||
background: mix($from, $to);
|
|
||||||
background: -moz-linear-gradient(0% 100% 90deg, $to, $from);
|
|
||||||
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from($from), to($to));
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin icon($where, $width, $height, $enabled: false, $top: 0, $left: 0) {
|
|
||||||
position: relative;
|
|
||||||
width: $width;
|
|
||||||
height: $height;
|
|
||||||
line-height: $height + 1;
|
|
||||||
@if $enabled == true {
|
|
||||||
background-position: -#{$width} $where; }
|
|
||||||
@else {
|
|
||||||
background-position: 0 $where; }
|
|
||||||
top: $top;
|
|
||||||
left: $left;
|
|
||||||
}
|
|
@ -1,126 +0,0 @@
|
|||||||
/* ___ AUTOMATICALLY GENERATED: see admin/button.scss for the source file */
|
|
||||||
|
|
||||||
@import "helpers";
|
|
||||||
|
|
||||||
.button {
|
|
||||||
display: inline-block;
|
|
||||||
background: transparent url(/assets/locomotive//buttons/dark-gray-left.png) no-repeat 0 0;
|
|
||||||
padding: 0px 0px 0px 2px;
|
|
||||||
font-size: 0.9em;
|
|
||||||
color: white;
|
|
||||||
cursor: pointer;
|
|
||||||
border: none;
|
|
||||||
height: 31px;
|
|
||||||
outline: none;
|
|
||||||
|
|
||||||
span {
|
|
||||||
display: inline-block;
|
|
||||||
background: transparent url(/assets/locomotive//buttons/dark-gray-right.png) no-repeat right top;
|
|
||||||
position: relative;
|
|
||||||
top: -1px;
|
|
||||||
padding: 3px 9px 9px 4px;
|
|
||||||
line-height: 21px;
|
|
||||||
text-shadow: 1px 1px 1px #000;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.light {
|
|
||||||
background-image: url(/assets/locomotive//buttons/light-gray-left.png);
|
|
||||||
color: #787a89;
|
|
||||||
|
|
||||||
span {
|
|
||||||
background-image: url(/assets/locomotive//buttons/light-gray-right.png);
|
|
||||||
text-shadow: 1px 1px 1px #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.small {
|
|
||||||
background: #ebedf4;
|
|
||||||
outline: none;
|
|
||||||
-moz-border-radius : 10px;
|
|
||||||
-webkit-border-radius: 10px;
|
|
||||||
height: 20px;
|
|
||||||
font-size: 0.7em;
|
|
||||||
padding: 0px 12px 0px 12px;
|
|
||||||
color: #8B8D9A !important;
|
|
||||||
text-decoration: none;
|
|
||||||
text-shadow: 1px 1px 1px #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.mini.add {
|
|
||||||
background: transparent;
|
|
||||||
height: 20px;
|
|
||||||
@include linear-background-gradient(#ebedf4, #d7dbe7);
|
|
||||||
@include full-rounded(4px);
|
|
||||||
@include box-shadow(1px, 1px, 1px, rgba(0, 0, 0, 0.4));
|
|
||||||
|
|
||||||
span {
|
|
||||||
background: none;
|
|
||||||
line-height: 10px;
|
|
||||||
padding: 0px 5px 0 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.remove {
|
|
||||||
color: #ff092c !important;
|
|
||||||
font-size: 1.1em;
|
|
||||||
|
|
||||||
&:hover { text-decoration: underline; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// .button {
|
|
||||||
// display: inline-block;
|
|
||||||
// background: transparent url(/assets/locomotive//buttons/dark-gray-left.png) no-repeat 0 0;
|
|
||||||
// padding: 0px 0px 0px 2px;
|
|
||||||
// font-size: 0.9em;
|
|
||||||
// color: white;
|
|
||||||
// cursor: pointer;
|
|
||||||
// border: none;
|
|
||||||
// height: 31px;
|
|
||||||
// outline: none;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// .button span {
|
|
||||||
// display: inline-block;
|
|
||||||
// background: transparent url(/assets/locomotive//buttons/dark-gray-right.png) no-repeat right top;
|
|
||||||
// position: relative;
|
|
||||||
// top: -1px;
|
|
||||||
// padding: 3px 9px 9px 4px;
|
|
||||||
// line-height: 21px;
|
|
||||||
// text-shadow: 1px 1px 1px #000;
|
|
||||||
// outline: none;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// .button.light {
|
|
||||||
// background-image: url(/assets/locomotive//buttons/light-gray-left.png);
|
|
||||||
// color: #787a89;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// .button.light span {
|
|
||||||
// background-image: url(/assets/locomotive//buttons/light-gray-right.png);
|
|
||||||
// text-shadow: 1px 1px 1px #fff;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// .button.small {
|
|
||||||
// background: #ebedf4;
|
|
||||||
// outline: none;
|
|
||||||
// -moz-border-radius : 10px;
|
|
||||||
// -webkit-border-radius: 10px;
|
|
||||||
// height: 20px;
|
|
||||||
// font-size: 0.7em;
|
|
||||||
// padding: 0px 12px 0px 12px;
|
|
||||||
// color: #8B8D9A !important;
|
|
||||||
// text-decoration: none;
|
|
||||||
// text-shadow: 1px 1px 1px #fff;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// .button.small.add {
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// .button.remove {
|
|
||||||
// color: #ff092c !important;
|
|
||||||
// font-size: 1.1em;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// .button.remove:hover { text-decoration: underline; }
|
|
@ -1,461 +0,0 @@
|
|||||||
/* ___ AUTOMATICALLY GENERATED: see admin/menu.scss for the source file */
|
|
||||||
|
|
||||||
@import "helpers";
|
|
||||||
|
|
||||||
/* ___ submenu: bg ___*/
|
|
||||||
|
|
||||||
#submenu {
|
|
||||||
clear: both;
|
|
||||||
position: relative;
|
|
||||||
top: -1px;
|
|
||||||
z-index: 998;
|
|
||||||
height: 60px;
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0 8px;
|
|
||||||
background: transparent image-url("locomotive/menu/shadow.png") repeat-y 0 0;
|
|
||||||
|
|
||||||
/* ___ submenu items ___ */
|
|
||||||
|
|
||||||
& > ul {
|
|
||||||
@include reset;
|
|
||||||
border-top: 1px solid rgba(255, 255, 255, 0.4);
|
|
||||||
background: transparent image-url("locomotive/menu/submenu/shadow.png") repeat-x 0 0;
|
|
||||||
@include rounded(top-right, 3px);
|
|
||||||
|
|
||||||
height: 60px;
|
|
||||||
|
|
||||||
& > li {
|
|
||||||
margin: 15px 7px 0 8px;
|
|
||||||
float: left;
|
|
||||||
|
|
||||||
&.hoverable > a span {
|
|
||||||
em {
|
|
||||||
display: inline-block;
|
|
||||||
background: transparent image-url("locomotive/menu/icons.png") no-repeat 0 -16px;
|
|
||||||
width: 12px;
|
|
||||||
height: 7px;
|
|
||||||
position: relative;
|
|
||||||
top: 0px;
|
|
||||||
left: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > a {
|
|
||||||
display: inline-block;
|
|
||||||
|
|
||||||
@include full-rounded(16px);
|
|
||||||
@include box-shadow-with-inset(rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.1));
|
|
||||||
|
|
||||||
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.4);
|
|
||||||
border-top: 1px solid rgba(0, 0, 0, 0.3);
|
|
||||||
padding: 0px 16px 0px 16px;
|
|
||||||
height: 26px;
|
|
||||||
line-height: 22px;
|
|
||||||
outline: none;
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: #fff;
|
|
||||||
font-size: 0.8em;
|
|
||||||
font-weight: normal;
|
|
||||||
text-shadow: 1px 1px 1px #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.9);
|
|
||||||
border-top: 1px solid rgba(0, 0, 0, 0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.on, &:active {
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
|
||||||
border-top: 1px solid rgba(0, 0, 0, 0.4);
|
|
||||||
border-bottom: 1px solid transparent !important;
|
|
||||||
@include box-shadow-with-inset(rgba(0, 0, 0, 0), rgba(255, 255, 255, 0.2), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.hover {
|
|
||||||
background: #fff !important;
|
|
||||||
border-color: transparent !important;
|
|
||||||
border-color-bottom: #fff;
|
|
||||||
padding-bottom: 0px;
|
|
||||||
@include border-rounded(bottom, left, 0px, true);
|
|
||||||
@include border-rounded(bottom, right, 0px, true);
|
|
||||||
position: relative;
|
|
||||||
z-index: 998;
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: #8b8d9a;
|
|
||||||
text-shadow: none;
|
|
||||||
@include no-box-shadow(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
span em {
|
|
||||||
background-position: -12px -16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > em {
|
|
||||||
@include absolute-position(bottom, 0px, right, -11px);
|
|
||||||
width: 13px;
|
|
||||||
height: 13px;
|
|
||||||
background: transparent url(/assets/locomotive//menu/popup/bottom-right-corner.png) no-repeat 0 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ___ submenu: actions ___ */
|
|
||||||
|
|
||||||
& > .action {
|
|
||||||
@include absolute-position(top, 0px, right, 22px);
|
|
||||||
height: 60px;
|
|
||||||
padding-left: 20px;
|
|
||||||
z-index: 1;
|
|
||||||
background: transparent url(/assets/locomotive//menu/submenu/action-border.png) repeat-y left 0;
|
|
||||||
|
|
||||||
a {
|
|
||||||
margin-top: 18px;
|
|
||||||
display: inline-block;
|
|
||||||
background: rgba(0, 0, 0, 0.4);
|
|
||||||
@include full-rounded(16px);
|
|
||||||
padding: 0px 10px 0 15px;
|
|
||||||
height: 22px;
|
|
||||||
line-height: 20px;
|
|
||||||
text-decoration: none;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
outline: none;
|
|
||||||
|
|
||||||
em {
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
background: transparent url(/assets/locomotive//menu/icons.png) no-repeat 0 0px;
|
|
||||||
height: 11px;
|
|
||||||
width: 11px;
|
|
||||||
top: 1px;
|
|
||||||
left: -5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
position: relative;
|
|
||||||
top: -2px;
|
|
||||||
color: #fff;
|
|
||||||
font-size: 0.7em;
|
|
||||||
text-shadow: 1px 1px 1px #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border-color: rgba(0, 0, 0, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ___ submenu: popup ___ */
|
|
||||||
|
|
||||||
.popup {
|
|
||||||
position: absolute;
|
|
||||||
top: 42px;
|
|
||||||
min-width: 250px;
|
|
||||||
background: #fff;
|
|
||||||
@include box-shadow(0px, 0px, 10px, rgba(0, 0, 0, 0.5));
|
|
||||||
@include full-rounded(16px);
|
|
||||||
@include border-rounded(top, left, 0px);
|
|
||||||
z-index: 997;
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #1f82bc;
|
|
||||||
text-decoration: none;
|
|
||||||
&:hover { text-decoration: underline; }
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
border-bottom: 1px dotted #bbbbbd;
|
|
||||||
padding-bottom: 6px;
|
|
||||||
margin: 0px 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inner { padding: 8px 16px; }
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 0.7em;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #1e1f26;
|
|
||||||
margin-bottom: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 0px;
|
|
||||||
padding: 10px 0 0 0px;
|
|
||||||
|
|
||||||
a {
|
|
||||||
font-size: 0.8em;
|
|
||||||
background: transparent url(/assets/locomotive//menu/popup/add.png) no-repeat left 4px;
|
|
||||||
padding-left: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.edit {
|
|
||||||
padding-top: 0px;
|
|
||||||
|
|
||||||
a {
|
|
||||||
background: transparent url(/assets/locomotive//menu/popup/bullet.png) no-repeat left 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
list-style-image: url(/assets/locomotive//menu/popup/bullet.png);
|
|
||||||
margin: 0px 0px 0 15px;
|
|
||||||
|
|
||||||
li {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
a { font-size: 0.7em; }
|
|
||||||
|
|
||||||
span {
|
|
||||||
@include absolute-position(top, 6px, right, 15px, inline);
|
|
||||||
color: #8b8d9a;
|
|
||||||
font-size: 0.7em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.big-links {
|
|
||||||
list-style: none;
|
|
||||||
margin: 0px;
|
|
||||||
|
|
||||||
li {
|
|
||||||
margin: 10px 0;
|
|
||||||
|
|
||||||
a {
|
|
||||||
@include full-rounded(16px);
|
|
||||||
padding: 3px 10px;
|
|
||||||
background: #ebedf4;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 0.8em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
background: #ebedf4;
|
|
||||||
padding: 8px 16px;
|
|
||||||
@include rounded("bottom-left", 16px);
|
|
||||||
@include rounded("bottom-right", 16px);
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #8b8d9a;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin black-submenu {
|
|
||||||
& > ul {
|
|
||||||
background: #23242b url(/assets/locomotive//menu/submenu/black-bg.png) repeat-x 0 0;
|
|
||||||
border-color: rgba(255, 255, 255, 0.2);
|
|
||||||
& > li > a {
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
|
||||||
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
|
||||||
border-bottom: 1px solid rgba(0, 0, 0, 0.6);
|
|
||||||
@include box-shadow-with-inset(rgba(255, 255, 255, 0.1));
|
|
||||||
@include linear-background-gradient(#303138, #1e1e24);
|
|
||||||
|
|
||||||
&.on, &:active {
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.4);
|
|
||||||
border-top: 1px solid rgba(0, 0, 0, 0.6);
|
|
||||||
@include linear-background-gradient(#1e1e24, #212229);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > .action {
|
|
||||||
background-image: url(/assets/locomotive//menu/submenu/black-action-border.png) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin green-submenu {
|
|
||||||
& > ul {
|
|
||||||
background-color: #2e9a7d;
|
|
||||||
& > li > a {
|
|
||||||
@include linear-background-gradient(#258c70, #13604b);
|
|
||||||
|
|
||||||
&.on, &:active {
|
|
||||||
@include linear-background-gradient(#195e4b, #166d55);
|
|
||||||
@include box-shadow-with-inset(rgba(0, 0, 0, 0), rgba(255, 255, 255, 0.2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin blue-submenu {
|
|
||||||
& > ul {
|
|
||||||
background-color: #2579ae;
|
|
||||||
& > li > a {
|
|
||||||
@include linear-background-gradient(#1f6ea1, #135179);
|
|
||||||
|
|
||||||
&.on, &:active {
|
|
||||||
@include linear-background-gradient(#13496c, #175b88);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin orange-submenu {
|
|
||||||
& > ul {
|
|
||||||
background-color: #ed8102;
|
|
||||||
& > li > a {
|
|
||||||
@include linear-background-gradient(#e07a02, #a25804);
|
|
||||||
|
|
||||||
&.on, &:active {
|
|
||||||
@include linear-background-gradient(#965201, #9d5603);
|
|
||||||
@include box-shadow-with-inset(rgba(0, 0, 0, 0), rgba(255, 255, 255, 0.2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin red-submenu {
|
|
||||||
& > ul {
|
|
||||||
background-color: #d23c45;
|
|
||||||
& > li > a {
|
|
||||||
@include linear-background-gradient(#b63e45, #89272d);
|
|
||||||
|
|
||||||
&.on, &:active {
|
|
||||||
@include linear-background-gradient(#7b292e, #972e35);
|
|
||||||
@include box-shadow-with-inset(rgba(0, 0, 0, 0), rgba(255, 255, 255, 0.2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin submenu-color($color) {
|
|
||||||
@if $color == black { @include black-submenu; }
|
|
||||||
@if $color == green { @include green-submenu; }
|
|
||||||
@if $color == blue { @include blue-submenu; }
|
|
||||||
@if $color == orange { @include orange-submenu; }
|
|
||||||
@if $color == red { @include red-submenu; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ___ menu ___ */
|
|
||||||
|
|
||||||
#menu {
|
|
||||||
@include reset;
|
|
||||||
margin: 20px 0 0 0px;
|
|
||||||
|
|
||||||
li.item {
|
|
||||||
float: left;
|
|
||||||
position: relative;
|
|
||||||
z-index: 994;
|
|
||||||
|
|
||||||
& > span, a {
|
|
||||||
float: left;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > span {
|
|
||||||
background: transparent url(/assets/locomotive//menu/left.png) no-repeat 0 0;
|
|
||||||
width: 40px;
|
|
||||||
height: 39px;
|
|
||||||
background-position: 0 -39px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.first > span {
|
|
||||||
width: 18px;
|
|
||||||
background-position: 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
background: transparent url(/assets/locomotive//menu/right.png) no-repeat right 0px;
|
|
||||||
padding: 0px 52px 0 2px;
|
|
||||||
height: 39px;
|
|
||||||
line-height: 26px;
|
|
||||||
outline: none;
|
|
||||||
|
|
||||||
em, span { display: inline-block; position: relative; }
|
|
||||||
|
|
||||||
em {
|
|
||||||
background: transparent url(/assets/locomotive//menu/icons.png) no-repeat 0px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
top: 9px;
|
|
||||||
left: 6px;
|
|
||||||
color: #787A89;
|
|
||||||
text-shadow: #C5CFD1 1px 1px 1px;
|
|
||||||
font-size: 0.8em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@for $i from 2 through 5 {
|
|
||||||
&.item-#{$i} { left: -35px * ($i - 1); z-index: 993 - $i; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin menu-color($color) {
|
|
||||||
$color-index: 1;
|
|
||||||
@if $color == green { $color-index: 1; }
|
|
||||||
@if $color == black { $color-index: 2; }
|
|
||||||
@if $color == blue { $color-index: 3; }
|
|
||||||
@if $color == orange { $color-index: 4; }
|
|
||||||
@if $color == red { $color-index: 5; }
|
|
||||||
|
|
||||||
z-index: 999;
|
|
||||||
|
|
||||||
a {
|
|
||||||
background-position: right -39px * $color-index;
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: #fff;
|
|
||||||
text-shadow: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > span { background-position: -40px * $color-index -39px; }
|
|
||||||
|
|
||||||
&.first > span { background-position: -18px * $color-index 0px; }
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin menu-contents-icon($enabled: false) {
|
|
||||||
@include icon(-64px, 16px, 12px, $enabled, 10px);
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin menu-assets-icon($enabled: false) {
|
|
||||||
@include icon(-48px, 20px, 16px, $enabled, 11px);
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin menu-settings-icon($enabled: false) {
|
|
||||||
@include icon(-32px, 14px, 13px, $enabled, 11px);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ___ section/color/icon associations ___ */
|
|
||||||
|
|
||||||
#menu li.contents a em { @include menu-contents-icon; }
|
|
||||||
body.contents {
|
|
||||||
$color: black;
|
|
||||||
#menu li.contents {
|
|
||||||
@include menu-color($color);
|
|
||||||
em { @include menu-contents-icon(true); }
|
|
||||||
}
|
|
||||||
#submenu { @include submenu-color($color); }
|
|
||||||
}
|
|
||||||
|
|
||||||
#menu li.assets a em { @include menu-assets-icon; }
|
|
||||||
body.assets {
|
|
||||||
$color: green;
|
|
||||||
#menu li.assets {
|
|
||||||
@include menu-color($color);
|
|
||||||
em { @include menu-assets-icon(true); }
|
|
||||||
}
|
|
||||||
#submenu { @include submenu-color($color); }
|
|
||||||
}
|
|
||||||
|
|
||||||
#menu li.settings a em { @include menu-settings-icon; }
|
|
||||||
body.settings {
|
|
||||||
$color: blue;
|
|
||||||
#menu li.settings {
|
|
||||||
@include menu-color($color);
|
|
||||||
em { @include menu-settings-icon(true); }
|
|
||||||
}
|
|
||||||
#submenu { @include submenu-color($color); }
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
/* ___ AUTOMATICALLY GENERATED: see admin/sites_picker.scss for the source file */
|
|
||||||
|
|
||||||
@import "helpers";
|
|
||||||
|
|
||||||
#sites-picker {
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
top: 97px;
|
|
||||||
|
|
||||||
padding: 0px 0 0 0;
|
|
||||||
|
|
||||||
@include popup-box;
|
|
||||||
|
|
||||||
border: 1px solid #000;
|
|
||||||
|
|
||||||
background: rgba(50, 51, 59, 1);
|
|
||||||
|
|
||||||
min-width: 160px;
|
|
||||||
|
|
||||||
z-index: 999;
|
|
||||||
|
|
||||||
font-size: 12px;
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin-bottom: 0px;
|
|
||||||
|
|
||||||
padding: 0 8px;
|
|
||||||
|
|
||||||
&, a {
|
|
||||||
color: #fff;
|
|
||||||
text-shadow: #000 0px 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
&:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.action {
|
|
||||||
margin-top: 0px;
|
|
||||||
padding: 2px 8px 4px 8px;
|
|
||||||
text-align: right;
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
@include reset;
|
|
||||||
|
|
||||||
margin: 1px 0 0 0;
|
|
||||||
|
|
||||||
li {
|
|
||||||
color: #aaa;
|
|
||||||
text-shadow: #000 0px 1px;
|
|
||||||
background: transparent url(/assets/locomotive//plugins/sites_picker_entry_bg.png) repeat-x 0 bottom;
|
|
||||||
padding: 2px 8px 6px 8px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: #aaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
&, a { color: #fff; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
content: " ";
|
|
||||||
display: block;
|
|
||||||
width: 21px;
|
|
||||||
height: 13px;
|
|
||||||
position: absolute;
|
|
||||||
top: -11px;
|
|
||||||
right: 20px;
|
|
||||||
background: transparent url(/assets/locomotive//plugins/sites_picker_top_arrow.png) no-repeat 0 0;
|
|
||||||
}
|
|
||||||
}
|
|
@ -24,7 +24,7 @@ class Locomotive::GlobalActionsCell < ::Locomotive::MenuCell
|
|||||||
end
|
end
|
||||||
|
|
||||||
add :help, :url => '#', :class => 'tutorial', :id => 'help'
|
add :help, :url => '#', :class => 'tutorial', :id => 'help'
|
||||||
add :logout, :url => destroy_locomotive_account_session_url, :confirm => t('locomotive.messages.confirm')
|
add :logout, :url => destroy_locomotive_account_session_url, :confirm => t('locomotive.messages.confirm'), :method => :delete
|
||||||
end
|
end
|
||||||
|
|
||||||
def localize_label(label, options = {})
|
def localize_label(label, options = {})
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
- content_for :head_title do
|
- content_for :head_title do
|
||||||
= t('locomotive.installation.common.title')
|
= t('locomotive.installation.common.title')
|
||||||
|
|
||||||
- content_for :head do
|
|
||||||
= stylesheet_link_tag 'locomotive/installation', :media => 'screen'
|
|
||||||
|
|
||||||
- title t('.title')
|
- title t('.title')
|
||||||
|
|
||||||
- if @step_done.blank?
|
- if @step_done.blank?
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
- content_for :head_title do
|
- content_for :head_title do
|
||||||
= t('locomotive.installation.common.title')
|
= t('locomotive.installation.common.title')
|
||||||
|
|
||||||
- content_for :head do
|
|
||||||
= stylesheet_link_tag 'locomotive/installation', :media => 'screen'
|
|
||||||
|
|
||||||
- title t('.title')
|
- title t('.title')
|
||||||
|
|
||||||
= semantic_form_for(@site, :url => installation_step_url(2), :html => { :multipart => true }) do |f|
|
= semantic_form_for(@site, :url => installation_step_url(2), :html => { :multipart => true }) do |f|
|
||||||
|
@ -4,14 +4,11 @@
|
|||||||
%head
|
%head
|
||||||
%title= title || escape_once("#{Locomotive.config.name} — #{current_site.name}")
|
%title= title || escape_once("#{Locomotive.config.name} — #{current_site.name}")
|
||||||
|
|
||||||
= javascript_include_tag 'jquery.js'
|
= javascript_include_tag 'locomotive/not_logged_in'
|
||||||
= stylesheet_link_tag 'locomotive/not_logged_in', :media => 'screen'
|
= stylesheet_link_tag 'locomotive/not_logged_in', :media => 'screen'
|
||||||
|
|
||||||
= yield :head
|
= yield :head
|
||||||
|
|
||||||
/ [if IE]
|
|
||||||
= stylesheet_link_tag 'locomotive/ie', :media => 'screen'
|
|
||||||
|
|
||||||
%body{ :class => controller.controller_name }
|
%body{ :class => controller.controller_name }
|
||||||
#wrapper
|
#wrapper
|
||||||
#light.container
|
#light.container
|
||||||
|
6
doc/TODO
@ -83,13 +83,19 @@ x edit my site
|
|||||||
x remove sidebar
|
x remove sidebar
|
||||||
- i18n
|
- i18n
|
||||||
- insert image
|
- insert image
|
||||||
|
- deployment
|
||||||
|
- fix integration problems
|
||||||
|
- pre-compile assets
|
||||||
|
|
||||||
- bugs:
|
- bugs:
|
||||||
x unable to toggle the "required" check_boxes for content types
|
x unable to toggle the "required" check_boxes for content types
|
||||||
|
- unable to sign out
|
||||||
|
- https://github.com/locomotivecms/engine/pull/281/files
|
||||||
|
|
||||||
- disallow to click twice on the submit form button (spinner ?)
|
- disallow to click twice on the submit form button (spinner ?)
|
||||||
- message to notify people if their browser is too old
|
- message to notify people if their browser is too old
|
||||||
- install a site by default at the first installation (without asking)
|
- install a site by default at the first installation (without asking)
|
||||||
|
- where to put Locomotive::InlineEditorMiddleware ?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,3 +19,17 @@
|
|||||||
|
|
||||||
collection, selector = Locomotive::ContentType.collection, Locomotive::ContentType.criteria.selector
|
collection, selector = Locomotive::ContentType.collection, Locomotive::ContentType.criteria.selector
|
||||||
collection.update selector, { '$rename' => { 'contents_custom_fields' => 'entries_custom_fields' } }
|
collection.update selector, { '$rename' => { 'contents_custom_fields' => 'entries_custom_fields' } }
|
||||||
|
|
||||||
|
|
||||||
|
Installation:
|
||||||
|
|
||||||
|
1/ open Gemfile
|
||||||
|
|
||||||
|
gem 'locomotive_cms', :path => '../../Desktop/NoCoffee/LocomotiveCMS/engine/', :require => 'locomotive/engine'
|
||||||
|
gem 'unicorn'
|
||||||
|
|
||||||
|
2/ bundle exec rails g mongoid:config
|
||||||
|
|
||||||
|
3/ bundle exec rails g locomotive:install
|
||||||
|
|
||||||
|
4/ bundle exec rake assets:precompile
|
@ -3,15 +3,6 @@ module Locomotive
|
|||||||
|
|
||||||
source_root File.expand_path('../../../../../', __FILE__)
|
source_root File.expand_path('../../../../../', __FILE__)
|
||||||
|
|
||||||
def copy_mongoid_config
|
|
||||||
copy_file 'config/mongoid.yml', 'config/mongoid.yml'
|
|
||||||
end
|
|
||||||
|
|
||||||
def copy_assets
|
|
||||||
directory 'public', 'public', :recursive => true
|
|
||||||
copy_file 'config/assets.yml', 'config/assets.yml'
|
|
||||||
end
|
|
||||||
|
|
||||||
def copy_initializers
|
def copy_initializers
|
||||||
@source_paths = nil # reset it for the find_in_source_paths method
|
@source_paths = nil # reset it for the find_in_source_paths method
|
||||||
|
|
||||||
@ -24,6 +15,12 @@ module Locomotive
|
|||||||
template 'dragonfly.rb', 'config/initializers/dragonfly.rb'
|
template 'dragonfly.rb', 'config/initializers/dragonfly.rb'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def insert_engine_routes
|
||||||
|
route %(
|
||||||
|
mount Locomotive::Engine => '/locomotive', :as => 'locomotive' # you can change the value of the path, by default set to "/locomotive"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
def remove_index_html
|
def remove_index_html
|
||||||
remove_file 'public/index.html'
|
remove_file 'public/index.html'
|
||||||
end
|
end
|
||||||
|
@ -8,10 +8,12 @@ The Locomotive Engine has been correctly installed in your Rails application.
|
|||||||
- config/initializers/carrierwave.rb
|
- config/initializers/carrierwave.rb
|
||||||
- config/initializers/dragonfly.rb
|
- config/initializers/dragonfly.rb
|
||||||
- config/mongoid.yml
|
- config/mongoid.yml
|
||||||
|
- config/devise.yml
|
||||||
|
- config/routes.rb
|
||||||
|
|
||||||
2. Launch the server
|
2. Launch the server
|
||||||
|
|
||||||
> unicorn_rails
|
> bundle exec unicorn_rails
|
||||||
|
|
||||||
3. Open your browser
|
3. Open your browser
|
||||||
|
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
require 'locomotive/engine'
|
puts "\t...loading core"
|
||||||
|
|
||||||
require 'locomotive/dependencies'
|
|
||||||
|
|
||||||
require 'locomotive/version'
|
require 'locomotive/version'
|
||||||
require 'locomotive/core_ext'
|
require 'locomotive/core_ext'
|
||||||
@ -91,6 +89,8 @@ module Locomotive
|
|||||||
|
|
||||||
self.app_middleware.insert_before Rack::Lock, '::Locomotive::Middlewares::Fonts', :path => %r{^/fonts}
|
self.app_middleware.insert_before Rack::Lock, '::Locomotive::Middlewares::Fonts', :path => %r{^/fonts}
|
||||||
self.app_middleware.use '::Locomotive::Middlewares::SeoTrailingSlash'
|
self.app_middleware.use '::Locomotive::Middlewares::SeoTrailingSlash'
|
||||||
|
|
||||||
|
self.app_middleware.use '::Locomotive::InlineEditorMiddleware' # TODO
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.configure_multi_sites
|
def self.configure_multi_sites
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
require 'devise'
|
puts "\t...loading dependencies"
|
||||||
|
|
||||||
require 'mongoid'
|
require 'mongoid'
|
||||||
require 'mongoid/railtie'
|
require 'mongoid/railtie'
|
||||||
require 'mongoid_acts_as_tree'
|
require 'mongoid_acts_as_tree'
|
||||||
|
require 'devise'
|
||||||
|
require 'devise/orm/mongoid'
|
||||||
require 'kaminari'
|
require 'kaminari'
|
||||||
require 'haml'
|
require 'haml'
|
||||||
require 'liquid'
|
require 'liquid'
|
||||||
@ -20,3 +23,12 @@ require 'cancan'
|
|||||||
require 'RMagick'
|
require 'RMagick'
|
||||||
require 'cells'
|
require 'cells'
|
||||||
require 'sanitize'
|
require 'sanitize'
|
||||||
|
|
||||||
|
require 'compass'
|
||||||
|
require 'codemirror/rails'
|
||||||
|
require 'jquery/rails'
|
||||||
|
require 'backbone-rails'
|
||||||
|
require 'tinymce/version'
|
||||||
|
require 'tinymce/railtie'
|
||||||
|
require 'aloha/version'
|
||||||
|
require 'aloha/railtie'
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
puts "...loading Locomotive engine"
|
puts "...loading Locomotive engine"
|
||||||
|
|
||||||
|
require 'locomotive/dependencies'
|
||||||
|
require 'locomotive'
|
||||||
|
|
||||||
|
$:.unshift File.dirname(__FILE__) # TODO: not sure about that, looks pretty useless
|
||||||
|
|
||||||
module Locomotive
|
module Locomotive
|
||||||
class Engine < Rails::Engine
|
class Engine < Rails::Engine
|
||||||
|
|
||||||
@ -7,18 +12,6 @@ module Locomotive
|
|||||||
|
|
||||||
# config.autoload_once_paths += %W( #{config.root}/app/controllers #{config.root}/app/models #{config.root}/app/helpers #{config.root}/app/uploaders)
|
# config.autoload_once_paths += %W( #{config.root}/app/controllers #{config.root}/app/models #{config.root}/app/helpers #{config.root}/app/uploaders)
|
||||||
|
|
||||||
# initializer 'locomotive.load_controllers_and_models' do |app|
|
|
||||||
# puts "[locomotive/initializer] locomotive.load_controllers_and_models"
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# config.before_initialize do |app|
|
|
||||||
# puts "[locomotive/before_initialize] NOTHING IS INITIALIZED !!!!!"
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# config.before_configuration do |app|
|
|
||||||
# puts "[locomotive/before_configuration] NOTHING IS INITIALIZED !!!!!"
|
|
||||||
# end
|
|
||||||
|
|
||||||
initializer 'locomotive.cells' do |app|
|
initializer 'locomotive.cells' do |app|
|
||||||
Cell::Base.prepend_view_path("#{config.root}/app/cells")
|
Cell::Base.prepend_view_path("#{config.root}/app/cells")
|
||||||
end
|
end
|
||||||
@ -27,5 +20,38 @@ module Locomotive
|
|||||||
::ActionController::Base.wrap_parameters :format => [:json]
|
::ActionController::Base.wrap_parameters :format => [:json]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
initializer "Locomotive precompile hook" do |app|
|
||||||
|
# app.config.assets.precompile += %w(locomotive.js locomotive.css locomotive/inline_editor.js locomotive/inline_editor.css
|
||||||
|
# locomotive/not_logged_in.js locomotive/not_logged_in.css
|
||||||
|
# locomotive/aloha.js)
|
||||||
|
|
||||||
|
app.config.assets.precompile += %w(locomotive.js locomotive.css locomotive/inline_editor.js locomotive/inline_editor.css
|
||||||
|
locomotive/not_logged_in.js locomotive/not_logged_in.css
|
||||||
|
locomotive/aloha.js)
|
||||||
|
|
||||||
|
def compile_asset?(path)
|
||||||
|
# ignores any filename that begins with '_' (e.g. sass partials)
|
||||||
|
# all other css/js/sass/image files are processed
|
||||||
|
if File.basename(path) =~ /^[^_].*\.\w+$/
|
||||||
|
puts "Compiling: #{path}"
|
||||||
|
true
|
||||||
|
else
|
||||||
|
puts "Ignoring: #{path}"
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
app.config.assets.precompile = [ method(:compile_asset?).to_proc ]
|
||||||
|
|
||||||
|
# app.config.assets.precompile += lambda { |f| puts f.inspect; true }
|
||||||
|
|
||||||
|
# locomotive/aloha.js locomotive/aloha.css
|
||||||
|
# locomotive/aloha/img/*)
|
||||||
|
# # locomotive/utils/aloha_settings.js
|
||||||
|
# # locomotive/aloha/*.js
|
||||||
|
# # locomotive/aloha.css
|
||||||
|
# # locomotive/aloha/plugins/*.css)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -5,17 +5,23 @@ module Liquid
|
|||||||
|
|
||||||
def render(context)
|
def render(context)
|
||||||
if context.registers[:current_locomotive_account] && context.registers[:inline_editor]
|
if context.registers[:current_locomotive_account] && context.registers[:inline_editor]
|
||||||
|
|
||||||
|
plugins = 'common/format,common/table,common/list,common/link,common/highlighteditables,common/block,common/undo,common/contenthandler,common/paste,common/commands,common/abbr,common/horizontalruler'
|
||||||
|
|
||||||
%{
|
%{
|
||||||
<meta content="true" name="inline-editor" />
|
<meta content="true" name="inline-editor" />
|
||||||
<link href="/assets/locomotive/aloha/css/aloha.css" media="screen" rel="stylesheet" type="text/css" />
|
|
||||||
<script type="text/javascript" src="/assets/locomotive/utils/aloha_settings.js"></script>
|
#{ActionController::Base.helpers.stylesheet_link_tag 'aloha'}
|
||||||
<script type="text/javascript" src="/assets/locomotive/aloha/lib/aloha.js" data-aloha-plugins="common/format,common/highlighteditables,common/list,common/link,common/undo,common/paste"></script>
|
|
||||||
|
#{ActionController::Base.helpers.javascript_include_tag 'locomotive/aloha', :'data-aloha-plugins' => plugins}
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
Aloha.ready(function() \{
|
Aloha.ready(function() \{
|
||||||
window.parent.application_view.set_page(#{context.registers[:page].to_presenter.as_json_for_html_view.to_json});
|
window.parent.application_view.set_page(#{context.registers[:page].to_presenter.as_json_for_html_view.to_json});
|
||||||
\});
|
\});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
''
|
''
|
||||||
@ -27,3 +33,17 @@ module Liquid
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# = javascript_include_tag 'locomotive/not_logged_in'
|
||||||
|
# = stylesheet_link_tag 'locomotive/not_logged_in', :media => 'screen'
|
||||||
|
|
||||||
|
# <link href="/assets/locomotive/aloha/css/aloha.css" media="screen" rel="stylesheet" type="text/css" />
|
||||||
|
# <script type="text/javascript" src="/assets/locomotive/utils/aloha_settings.js"></script>
|
||||||
|
# <script type="text/javascript" src="/assets/locomotive/aloha/lib/aloha.js" data-aloha-plugins="common/format,common/highlighteditables,common/list,common/link,common/undo,common/paste"></script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#{ActionController::Base.helpers.javascript_include_tag 'locomotive/aloha', :'data-aloha-plugins' => 'common/format,common/highlighteditables,common/list,common/link,common/undo,common/paste'}
|
||||||
|
|
||||||
|
# <script type="text/javascript" src="/assets/aloha/lib/aloha.js" data-aloha-plugins="common/format,common/highlighteditables,common/list,common/link,common/undo,common/paste"></script>
|
@ -1,3 +1,3 @@
|
|||||||
module Locomotive #:nodoc
|
module Locomotive #:nodoc
|
||||||
VERSION = "1.0.0.rc1"
|
VERSION = "2.0.0.rc1"
|
||||||
end
|
end
|
||||||
|
@ -10,59 +10,104 @@ Gem::Specification.new do |s|
|
|||||||
s.platform = Gem::Platform::RUBY
|
s.platform = Gem::Platform::RUBY
|
||||||
s.authors = ['Didier Lafforgue']
|
s.authors = ['Didier Lafforgue']
|
||||||
s.email = ['didier@nocoffee.fr']
|
s.email = ['didier@nocoffee.fr']
|
||||||
s.homepage = 'http://locomotiveapp.org'
|
s.homepage = 'http://locomotivecms.com'
|
||||||
s.summary = 'A Next Generation Sexy CMS for Rails3'
|
s.summary = 'A Next Generation Sexy CMS for Rails3'
|
||||||
s.description = 'Locomotive is a next generation CMS system with sexy admin tools, liquid templating, and inline editing powered by mongodb and rails3'
|
s.description = 'Locomotive is a next generation CMS system with sexy admin tools, liquid templating, and inline editing powered by mongodb and rails 3.1'
|
||||||
|
|
||||||
s.required_rubygems_version = '>= 1.3.6'
|
s.required_rubygems_version = '>= 1.3.6'
|
||||||
s.rubyforge_project = 'nowarning'
|
s.rubyforge_project = 'nowarning'
|
||||||
|
|
||||||
s.add_dependency 'rails', '~> 3.1.3'
|
s.add_dependency 'rails', '~> 3.1.3'
|
||||||
s.add_dependency 'warden'
|
|
||||||
s.add_dependency 'devise', '1.3.4'
|
|
||||||
s.add_dependency 'devise_bushido_authenticatable', '1.0.0.alpha10'
|
|
||||||
|
|
||||||
s.add_dependency 'mongo', '~> 1.3.1'
|
s.add_dependency 'devise', '~> 1.5.3'
|
||||||
s.add_dependency 'bson', '~> 1.3.1'
|
s.add_dependency 'cancan', '~> 1.6.7'
|
||||||
s.add_dependency 'bson_ext', '~> 1.3.1'
|
|
||||||
s.add_dependency 'mongoid', '~> 2.0.2'
|
s.add_dependency 'mongo', '~> 1.5.2'
|
||||||
|
s.add_dependency 'bson_ext', '~> 1.5.2'
|
||||||
|
s.add_dependency 'mongoid', '~> 2.4.0'
|
||||||
|
s.add_dependency 'locomotive_mongoid_acts_as_tree', '0.1.5.8'
|
||||||
|
|
||||||
|
s.add_dependency 'custom_fields', '~> 2.0.0.rc1'
|
||||||
|
|
||||||
s.add_dependency 'locomotive_mongoid_acts_as_tree', '0.1.5.7'
|
|
||||||
s.add_dependency 'kaminari'
|
s.add_dependency 'kaminari'
|
||||||
|
|
||||||
s.add_dependency 'haml', '3.1.2'
|
s.add_dependency 'haml', '~> 3.1.3'
|
||||||
s.add_dependency 'sass', '3.1.2'
|
s.add_dependency 'sass-rails', '~> 3.1.4'
|
||||||
s.add_dependency 'locomotive_liquid', '2.2.2'
|
s.add_dependency 'coffee-script', '~> 2.2.0'
|
||||||
s.add_dependency 'formtastic', '~> 1.2.3'
|
s.add_dependency 'uglifier', '~> 1.2.2'
|
||||||
s.add_dependency 'cells', '~> 3.7.0'
|
s.add_dependency 'compass', '~> 0.12.alpha.4'
|
||||||
s.add_dependency 'highline'
|
s.add_dependency 'jquery-rails', '~> 1.0.16'
|
||||||
s.add_dependency 'sanitize'
|
s.add_dependency 'rails-backbone', '0.5.4'
|
||||||
|
s.add_dependency 'codemirror-rails'
|
||||||
|
s.add_dependency 'tinymce-rails'
|
||||||
|
s.add_dependency 'locomotive-aloha-rails'
|
||||||
|
s.add_dependency 'flash_cookie_session', '~> 1.1.1'
|
||||||
|
|
||||||
s.add_dependency 'json_pure', '1.5.1'
|
s.add_dependency 'locomotive_liquid', '2.2.2'
|
||||||
s.add_dependency 'bushido'
|
s.add_dependency 'formtastic', '~> 2.0.2'
|
||||||
s.add_dependency 'heroku', '1.19.1'
|
s.add_dependency 'responders', '~> 0.6.4'
|
||||||
|
s.add_dependency 'cells', '~> 3.7.1'
|
||||||
|
s.add_dependency 'RedCloth', '~> 4.2.8'
|
||||||
|
s.add_dependency 'sanitize', '~> 2.0.3'
|
||||||
|
s.add_dependency 'highline', '~> 1.6.2'
|
||||||
|
|
||||||
s.add_dependency 'rmagick', '2.12.2'
|
s.add_dependency 'rmagick', '2.12.2'
|
||||||
s.add_dependency 'carrierwave', '0.5.6'
|
s.add_dependency 'carrierwave-mongoid', '~> 0.1.3'
|
||||||
s.add_dependency 'dragonfly', '~> 0.9.1'
|
s.add_dependency 'fog', '~> 1.0.0'
|
||||||
s.add_dependency 'rack-cache'
|
s.add_dependency 'dragonfly', '~> 0.9.8'
|
||||||
|
s.add_dependency 'rack-cache', '~> 1.1'
|
||||||
s.add_dependency 'custom_fields', '1.0.0.beta.25'
|
s.add_dependency 'mimetype-fu', '~> 0.1.2'
|
||||||
s.add_dependency 'cancan', '~> 1.6.0'
|
|
||||||
s.add_dependency 'fog', '0.8.2'
|
|
||||||
s.add_dependency 'mimetype-fu'
|
|
||||||
s.add_dependency 'actionmailer-with-request'
|
|
||||||
s.add_dependency 'httparty', '0.7.8'
|
|
||||||
s.add_dependency 'RedCloth', '4.2.9'
|
|
||||||
s.add_dependency 'delayed_job_mongoid', '1.0.8'
|
|
||||||
s.add_dependency 'rubyzip'
|
s.add_dependency 'rubyzip'
|
||||||
s.add_dependency 'locomotive_jammit-s3'
|
|
||||||
|
s.add_dependency 'actionmailer-with-request', '~> 0.3.0'
|
||||||
|
s.add_dependency 'httparty', '~> 0.8.1'
|
||||||
|
s.add_dependency 'delayed_job_mongoid', '~> 1.0.8'
|
||||||
|
|
||||||
|
# s.add_dependency 'SystemTimer', :platforms => :ruby_18
|
||||||
|
|
||||||
|
# s.add_dependency 'rails', '~> 3.1.3'
|
||||||
|
# # s.add_dependency 'warden'
|
||||||
|
# s.add_dependency 'devise', '~> 1.5.3'
|
||||||
|
#
|
||||||
|
# s.add_dependency 'mongo', '~> 1.5.2'
|
||||||
|
# s.add_dependency 'bson_ext', '~> 1.5.2'
|
||||||
|
# s.add_dependency 'mongoid', '~> 2.4.0'
|
||||||
|
#
|
||||||
|
# s.add_dependency 'locomotive_mongoid_acts_as_tree', '0.1.5.7'
|
||||||
|
# s.add_dependency 'kaminari'
|
||||||
|
#
|
||||||
|
# s.add_dependency 'sass', '3.1.2'
|
||||||
|
# s.add_dependency 'locomotive_liquid', '2.2.2'
|
||||||
|
# s.add_dependency 'formtastic', '~> 1.2.3'
|
||||||
|
# s.add_dependency 'cells', '~> 3.7.0'
|
||||||
|
# s.add_dependency 'highline'
|
||||||
|
# s.add_dependency 'sanitize'
|
||||||
|
#
|
||||||
|
# s.add_dependency 'json_pure', '1.5.1'
|
||||||
|
# s.add_dependency 'bushido'
|
||||||
|
# s.add_dependency 'heroku', '1.19.1'
|
||||||
|
#
|
||||||
|
# s.add_dependency 'rmagick', '2.12.2'
|
||||||
|
# s.add_dependency 'carrierwave', '0.5.6'
|
||||||
|
# s.add_dependency 'dragonfly', '~> 0.9.1'
|
||||||
|
# s.add_dependency 'rack-cache'
|
||||||
|
#
|
||||||
|
# s.add_dependency 'custom_fields', '2.0.0.rc1'
|
||||||
|
# s.add_dependency 'cancan', '~> 1.6.0'
|
||||||
|
# s.add_dependency 'fog', '0.8.2'
|
||||||
|
# s.add_dependency 'mimetype-fu'
|
||||||
|
# s.add_dependency 'actionmailer-with-request'
|
||||||
|
# s.add_dependency 'httparty', '0.7.8'
|
||||||
|
# s.add_dependency 'RedCloth', '4.2.9'
|
||||||
|
# s.add_dependency 'delayed_job_mongoid', '1.0.8'
|
||||||
|
# s.add_dependency 'rubyzip'
|
||||||
|
# s.add_dependency 'locomotive_jammit-s3'
|
||||||
|
|
||||||
s.files = Dir[ 'Gemfile',
|
s.files = Dir[ 'Gemfile',
|
||||||
'{app}/**/*',
|
'{app}/**/*',
|
||||||
'{config}/**/*',
|
'{config}/**/*',
|
||||||
'{lib}/**/*',
|
'{lib}/**/*',
|
||||||
'{public}/stylesheets/admin/**/*', '{public}/javascripts/admin/**/*', '{public}/images/admin/**/*',
|
'{public}/**/*',
|
||||||
'{vendor}/**/*']
|
'{vendor}/**/*']
|
||||||
|
|
||||||
s.require_path = 'lib'
|
s.require_path = 'lib'
|
||||||
|
@ -1,209 +0,0 @@
|
|||||||
var InlineEditorToolbar = {
|
|
||||||
|
|
||||||
element: null, // reference to the toolbar element
|
|
||||||
|
|
||||||
form: null, // reference to the form used to post changes
|
|
||||||
|
|
||||||
editingMode: false, // true means that Aloha should be enabled
|
|
||||||
|
|
||||||
drawerButton: null,
|
|
||||||
|
|
||||||
locale: 'en', // default locale
|
|
||||||
|
|
||||||
initialize: function() {
|
|
||||||
this.editingMode = window.location.href.match(/\/edit$/) != null;
|
|
||||||
this.locale = $('meta[name=locale]').attr('content');
|
|
||||||
|
|
||||||
this._buildHTML();
|
|
||||||
|
|
||||||
this.element = $('#page-toolbar');
|
|
||||||
this.form = this.element.find('form');
|
|
||||||
this.drawerButton = this.element.find('.drawer a');
|
|
||||||
|
|
||||||
this._bindEvents();
|
|
||||||
|
|
||||||
if ($.cookie('ie_toolbar_off') == '1') this.hide(0, false);
|
|
||||||
},
|
|
||||||
|
|
||||||
toggle: function(animate) {
|
|
||||||
var duration = (typeof animate == 'undefined') || animate == true ? 300 : 0;
|
|
||||||
|
|
||||||
if (this.drawerButton.hasClass('off')) this.show(duration); else this.hide(duration);
|
|
||||||
},
|
|
||||||
|
|
||||||
show: function(duration, withCookie) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
this.element.animate({ 'right': 0 }, duration, function() {
|
|
||||||
self.drawerButton.removeClass('off');
|
|
||||||
if ((typeof withCookie == 'undefined') || withCookie == true)
|
|
||||||
$.cookie('ie_toolbar_off', '0');
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
hide: function(duration, withCookie) {
|
|
||||||
var self = this;
|
|
||||||
var max = this.element.width() - 17;
|
|
||||||
|
|
||||||
this.element.animate({ 'right': -max }, duration, function() {
|
|
||||||
self.drawerButton.addClass('off');
|
|
||||||
if ((typeof withCookie == 'undefined') || withCookie == true)
|
|
||||||
$.cookie('ie_toolbar_off', '1');
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
updateForm: function(jEvent, aEvent) {
|
|
||||||
InlineEditorToolbar.element.find('li.save, li.cancel, li.sep:eq(1)').show();
|
|
||||||
|
|
||||||
var content = aEvent.editable.getContents().replace(/^\s*/, "").replace(/\s*$/, "");
|
|
||||||
var editableObj = $(aEvent.editable.obj[0]);
|
|
||||||
var dataId = editableObj.attr('data-element-id');
|
|
||||||
var idInput = InlineEditorToolbar.form.find('#editable-id');
|
|
||||||
var contentInput = InlineEditorToolbar.form.find('#editable-content');
|
|
||||||
|
|
||||||
idInput.attr('name', 'page[editable_elements_attributes][0][id]').val(dataId);
|
|
||||||
contentInput.attr('name', 'page[editable_elements_attributes][0][content]').val(content);
|
|
||||||
|
|
||||||
InlineEditorToolbar.show(true, false);
|
|
||||||
},
|
|
||||||
|
|
||||||
displaySpinner: function() {
|
|
||||||
this.element.find('li.save, li.cancel, li.sep:eq(1)').hide();
|
|
||||||
this.element.find('.spinner').show();
|
|
||||||
},
|
|
||||||
|
|
||||||
resetForm: function() {
|
|
||||||
this.form.find('input.auto').each(function() {
|
|
||||||
$(this).attr('name', $(this).attr('name').replace('content', '_index'));
|
|
||||||
$(this).val('');
|
|
||||||
});
|
|
||||||
|
|
||||||
this.element.find('li.save, li.cancel, li.sep:eq(1), li.spinner').hide();
|
|
||||||
},
|
|
||||||
|
|
||||||
/* ___ internal methods ___ */
|
|
||||||
|
|
||||||
_buildHTML: function() {
|
|
||||||
var csrf_token = $('meta[name=csrf-token]').attr('content'),
|
|
||||||
csrf_param = $('meta[name=csrf-param]').attr('content');
|
|
||||||
|
|
||||||
var labels = this._translations[this.locale];
|
|
||||||
|
|
||||||
var showPageUrl = $('meta[name=page-url]').attr('content');
|
|
||||||
var editPageUrl = $('meta[name=edit-page-url]').attr('content');
|
|
||||||
var nbElements = parseInt($('meta[name=page-elements-count]').attr('content'));
|
|
||||||
|
|
||||||
var formContentHTML = "<input type='hidden' name='_method' value='put' />\
|
|
||||||
<input class='auto' id='editable-id' type='hidden' name='_id' value='' />\
|
|
||||||
<input class='auto' id='editable-content' type='hidden' name='_content' value='' />";
|
|
||||||
|
|
||||||
if (csrf_param != null && csrf_token != null) {
|
|
||||||
formContentHTML += '<input name="' + csrf_param + '" value="' + csrf_token + '" type="hidden" />';
|
|
||||||
}
|
|
||||||
|
|
||||||
$('body').prepend("<div id='page-toolbar'>\
|
|
||||||
<ul>\
|
|
||||||
<li class='drawer'><a href='#'><span> </span></a></li>\
|
|
||||||
<li class='link home'><a href='" + editPageUrl + "'><span>" + labels['home'] + "</span></a></li>\
|
|
||||||
<li class='sep'><span> </span></li>\
|
|
||||||
<li class='link edit' style='" + (this.editingMode ? 'display: none' : '') + "'><a href='#'><span>" + labels['edit'] + "</span></a></li>\
|
|
||||||
<li class='link save' style='display: none'><a href='#'><span>" + labels['save'] + "</span></a></li>\
|
|
||||||
<li class='link cancel' style='display: none'><a href='#'><span>" + labels['cancel'] + "</span></a></li>\
|
|
||||||
<li class='link spinner' style='display: none'><a href='#'><span><img src='/images/admin/form/spinner.gif' /><em>" + labels['saving'] + "</em></span></a></li>\
|
|
||||||
<li class='sep' style='display: none'><span> </span></li>\
|
|
||||||
<li class='link back' style='" + (this.editingMode ? '' : 'display: none') + "'><a href='#'><span>" + labels['back'] + "</span></a></li>\
|
|
||||||
</ul>\
|
|
||||||
<form action='" + showPageUrl + "' accept-charset='UTF-8' method='post'>\
|
|
||||||
" + formContentHTML + "\
|
|
||||||
</form>\
|
|
||||||
</div>");
|
|
||||||
},
|
|
||||||
|
|
||||||
_bindEvents: function() {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
this.form.live('submit', function (e) { $(this).callRemote(); e.stopPropagation(); e.preventDefault();
|
|
||||||
}).bind('ajax:complete', function() { self.resetForm();
|
|
||||||
}).bind('ajax:loading', function() { self.displaySpinner();
|
|
||||||
}).bind('ajax:failure', function() { self.resetForm();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.element.find('ul li a').click(function(e) {
|
|
||||||
var classArray = $(this).parent().attr('class').split(' ');
|
|
||||||
switch(classArray[1] || classArray[0]) {
|
|
||||||
case 'home':
|
|
||||||
window.location.href = $(this).attr('href'); break;
|
|
||||||
|
|
||||||
case 'edit': // passing in editing mode
|
|
||||||
var url = window.location.href.replace(/\/$/, '/index').replace('#', '');
|
|
||||||
window.location.href = url + '/edit'; break;
|
|
||||||
|
|
||||||
case 'save': // saving changes
|
|
||||||
self.form.submit(); break;
|
|
||||||
|
|
||||||
case 'cancel': // reload the page
|
|
||||||
window.location.href = window.location.href; break;
|
|
||||||
|
|
||||||
case 'back': // back to the non edition mode
|
|
||||||
var url = window.location.href.replace(/\/edit$/, '');
|
|
||||||
window.location.href = url; break;
|
|
||||||
|
|
||||||
case 'drawer': // expand / shrink toolbar
|
|
||||||
self.toggle(); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
e.preventDefault(); e.stopPropagation();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_translations: {
|
|
||||||
'en': {
|
|
||||||
'home': 'admin',
|
|
||||||
'edit': 'edit',
|
|
||||||
'save': 'save',
|
|
||||||
'cancel': 'cancel',
|
|
||||||
'back': 'edition done',
|
|
||||||
'saving': 'saving'
|
|
||||||
},
|
|
||||||
'de': {
|
|
||||||
'home': 'admin',
|
|
||||||
'edit': 'bearbeiten',
|
|
||||||
'save': 'speichern',
|
|
||||||
'cancel': 'schließen',
|
|
||||||
'back': 'bearbeiten abschließen',
|
|
||||||
'saving': 'am Speichern'
|
|
||||||
},
|
|
||||||
'fr': {
|
|
||||||
'home': 'admin',
|
|
||||||
'edit': 'editer',
|
|
||||||
'save': 'sauver',
|
|
||||||
'cancel': 'annuler',
|
|
||||||
'back': 'fin mode edition',
|
|
||||||
'saving': 'sauvegarde en cours'
|
|
||||||
},
|
|
||||||
'pt-BR': {
|
|
||||||
'home': 'admin',
|
|
||||||
'edit': 'editar',
|
|
||||||
'save': 'salvar',
|
|
||||||
'cancel': 'cancelar',
|
|
||||||
'back': 'terminar edição',
|
|
||||||
'saving': 'salvando'
|
|
||||||
},
|
|
||||||
'it': {
|
|
||||||
'home': 'admin',
|
|
||||||
'edit': 'modifica',
|
|
||||||
'save': 'salva',
|
|
||||||
'cancel': 'annulla',
|
|
||||||
'back': 'fine modifica',
|
|
||||||
'saving': 'sto salvando'
|
|
||||||
},
|
|
||||||
'ru': {
|
|
||||||
'home': 'панель управления',
|
|
||||||
'edit': 'редактирование',
|
|
||||||
'save': 'сохранение',
|
|
||||||
'cancel': 'отмена',
|
|
||||||
'back': 'закончить редактирование',
|
|
||||||
'saving': 'сохранение'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
@ -1 +0,0 @@
|
|||||||
tinyMCE.addI18n('ru.advhr_dlg',{size:"\u0412\u044b\u0441\u043e\u0442\u0430",noshade:"\u0411\u0435\u0437 \u0442\u0435\u043d\u0438",width:"\u0428\u0438\u0440\u0438\u043d\u0430",normal:"\u041e\u0431\u044b\u0447\u043d\u0430\u044f",widthunits:"\u0415\u0434\u0438\u043d\u0438\u0446\u044b \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f"});
|
|
@ -1 +0,0 @@
|
|||||||
tinyMCE.addI18n('ru.advimage_dlg',{"image_list":"\u0421\u043f\u0438\u0441\u043e\u043a \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a","align_right":"\u041f\u043e \u043f\u0440\u0430\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e","align_left":"\u041f\u043e \u043b\u0435\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e","align_textbottom":"\u041f\u043e \u043d\u0438\u0436\u043d\u0435\u043c\u0443 \u043a\u0440\u0430\u044e \u0442\u0435\u043a\u0441\u0442\u0430","align_texttop":"\u041f\u043e \u0432\u0435\u0440\u0445\u043d\u0435\u043c\u0443 \u043a\u0440\u0430\u044e \u0442\u0435\u043a\u0441\u0442\u0430","align_bottom":"\u041f\u043e \u043d\u0438\u0436\u043d\u0435\u043c\u0443 \u043a\u0440\u0430\u044e","align_middle":"\u041f\u043e \u0446\u0435\u043d\u0442\u0440\u0443","align_top":"\u041f\u043e \u0432\u0435\u0440\u0445\u043d\u0435\u043c\u0443 \u043a\u0440\u0430\u044e","align_baseline":"\u041f\u043e \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u043b\u0438\u043d\u0438\u0438",align:"\u0412\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u0435",hspace:"\u0413\u043e\u0440\u0438\u0437. \u043e\u0442\u0441\u0442\u0443\u043f",vspace:"\u0412\u0435\u0440\u0442. \u043e\u0442\u0441\u0442\u0443\u043f",dimensions:"\u0420\u0430\u0437\u043c\u0435\u0440",border:"\u0413\u0440\u0430\u043d\u0438\u0446\u0430",list:"\u0421\u043f\u0438\u0441\u043e\u043a",alt:"\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435",src:"\u0410\u0434\u0440\u0435\u0441","dialog_title":"\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f","missing_alt":"\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c \u0431\u0435\u0437 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f? \u0411\u0435\u0437 \u044d\u0442\u043e\u0433\u043e \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c.","example_img":"\u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f",misc:"\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b",mouseout:"\u0412 \u043f\u043e\u043a\u043e\u0435",mouseover:"\u041f\u0440\u0438 \u043d\u0430\u0432\u0435\u0434\u0435\u043d\u0438\u0438","alt_image":"\u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435","swap_image":"\u0414\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435",map:"\u041a\u0430\u0440\u0442\u0430 \u0441\u0441\u044b\u043b\u043e\u043a",id:"\u0418\u043c\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430",rtl:"\u0421\u043f\u0440\u0430\u0432\u0430 \u043d\u0430\u043b\u0435\u0432\u043e",ltr:"\u0421\u043b\u0435\u0432\u0430 \u043d\u0430\u043f\u0440\u0430\u0432\u043e",classes:"\u041a\u043b\u0430\u0441\u0441\u044b",style:"\u0421\u0442\u0438\u043b\u044c","long_desc":"\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043f\u043e\u043b\u043d\u043e\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435",langcode:"\u041a\u043e\u0434 \u044f\u0437\u044b\u043a\u0430",langdir:"\u041d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u0435\u043a\u0441\u0442\u0430","constrain_proportions":"\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043f\u0440\u043e\u043f\u043e\u0440\u0446\u0438\u0438",preview:"\u041f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440",title:"\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a",general:"\u041e\u0431\u0449\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b","tab_advanced":"\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e","tab_appearance":"\u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435","tab_general":"\u041e\u0431\u0449\u0435\u0435",width:"\u0428\u0438\u0440\u0438\u043d\u0430",height:"\u0412\u044b\u0441\u043e\u0442\u0430"});
|
|
@ -1 +0,0 @@
|
|||||||
tinyMCE.addI18n('ru.emotions_dlg',{cry:"\u041f\u043b\u0430\u0447\u0443",cool:"\u041a\u0440\u0443\u0442\u043e\u0439",desc:"\u0421\u043c\u0430\u0439\u043b\u044b",title:"\u0412\u044b\u0431\u043e\u0440 \u0441\u043c\u0430\u0439\u043b\u0430",yell:"\u041a\u0440\u0438\u0447\u0443",wink:"\u041f\u043e\u0434\u043c\u0438\u0433\u0438\u0432\u0430\u044e",undecided:"\u0412 \u043d\u0435\u0440\u0435\u0448\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438","tongue_out":"\u0414\u0440\u0430\u0437\u043d\u044e\u0441\u044c",surprised:"\u0423\u0434\u0438\u0432\u043b\u044f\u044e\u0441\u044c",smile:"\u0423\u043b\u044b\u0431\u0430\u044e\u0441\u044c",sealed:"\u041d\u0435\u043c \u043a\u0430\u043a \u0440\u044b\u0431\u0430","money_mouth":"\u0414\u0435\u043d\u044c\u0433\u0438",laughing:"\u0421\u043c\u0435\u044e\u0441\u044c",kiss:"\u041f\u043e\u0446\u0435\u043b\u0443\u0439",innocent:"\u0410\u043d\u0433\u0435\u043b",frown:"\u0425\u043c\u0443\u0440\u044e\u0441\u044c","foot_in_mouth":"\u0412 \u0440\u043e\u0442 \u043c\u043d\u0435 \u043d\u043e\u0433\u0438",embarassed:"\u041a\u0440\u0430\u0441\u043d\u0435\u044e",usage:"\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u043a\u043b\u0430\u0432\u0438\u0448\u0438 \"\u0412\u043b\u0435\u0432\u043e\" \u0438 \"\u0412\u043f\u0440\u0430\u0432\u043e\" \u0434\u043b\u044f \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438."});
|
|
@ -1,9 +0,0 @@
|
|||||||
tinyMCE.addI18n('ru.locomedia_dlg',{
|
|
||||||
dialog_title: 'Вставить изображение', // Insert media
|
|
||||||
upload: 'Загрузить изображение', // Upload media
|
|
||||||
loading: 'Идет загрузка...', // Loading...
|
|
||||||
uploading: 'Идет загрузка...', // Uploading...
|
|
||||||
destroying: 'Идет удаление...', // Destroying...
|
|
||||||
confirm: 'Вы уверены?', // Are you sure ?
|
|
||||||
no_items: 'Список изображений пуск.' // There are no media for now.
|
|
||||||
});
|
|
@ -1 +0,0 @@
|
|||||||
tinyMCE.addI18n('ru.paste_dlg',{"word_title":"\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 CTRL+V \u0434\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u0442\u0435\u043a\u0441\u0442\u0430 \u0432 \u043e\u043a\u043d\u043e.","text_linebreaks":"\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u044b \u0441\u0442\u0440\u043e\u043a","text_title":"\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 CTRL+V \u0434\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u0442\u0435\u043a\u0441\u0442\u0430 \u0432 \u043e\u043a\u043d\u043e."});
|
|
@ -1 +0,0 @@
|
|||||||
tinyMCE.addI18n('ru.searchreplace_dlg',{findwhat:"\u041f\u043e\u0438\u0441\u043a",replacewith:"\u0417\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0430",direction:"\u041d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435",up:"\u0412\u0432\u0435\u0440\u0445 ",down:"\u0412\u043d\u0438\u0437",mcase:"\u0423\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u0440\u0435\u0433\u0438\u0441\u0442\u0440",findnext:"\u041d\u0430\u0439\u0442\u0438 \u0434\u0430\u043b\u0435\u0435",allreplaced:"\u0412\u0441\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0431\u044b\u043b\u0438 \u0437\u0430\u043c\u0435\u043d\u0435\u043d\u044b.","searchnext_desc":"\u041d\u0430\u0439\u0442\u0438 \u0435\u0449\u0435",notfound:"\u041f\u043e\u0438\u0441\u043a \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d. \u0421\u043e\u043e\u0442\u0432\u0435\u0441\u0442\u0432\u0438\u0439 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e.","search_title":"\u041f\u043e\u0438\u0441\u043a","replace_title":"\u041f\u043e\u0438\u0441\u043a \u0438 \u0437\u0430\u043c\u0435\u043d\u0430",replaceall:"\u0417\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u0441\u0435",replace:"\u0417\u0430\u043c\u0435\u043d\u0430"});
|
|
@ -1 +0,0 @@
|
|||||||
tinyMCE.addI18n('ru.style_dlg',{"text_lineheight":"\u0412\u044b\u0441\u043e\u0442\u0430 \u0441\u0442\u0440\u043e\u043a\u0438","text_variant":"\u0412\u0430\u0440\u0438\u0430\u043d\u0442","text_style":"\u0421\u0442\u0438\u043b\u044c","text_weight":"\u0422\u043e\u043b\u0449\u0438\u043d\u0430","text_size":"\u0420\u0430\u0437\u043c\u0435\u0440","text_font":"\u0428\u0440\u0438\u0444\u0442","text_props":"\u0422\u0435\u043a\u0441\u0442","positioning_tab":"\u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435","list_tab":"\u0421\u043f\u0438\u0441\u043e\u043a","border_tab":"\u0413\u0440\u0430\u043d\u0438\u0446\u0430","box_tab":"\u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440","block_tab":"\u0411\u043b\u043e\u043a","background_tab":"\u0424\u043e\u043d","text_tab":"\u0422\u0435\u043a\u0441\u0442",apply:"\u041f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c",title:"\u0420\u0435\u0434\u0430\u043a\u0442\u043e\u0440 CSS \u0441\u0442\u0438\u043b\u044f",clip:"\u041e\u0442\u0441\u0435\u0447\u0435\u043d\u0438\u0435",placement:"\u0420\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0438\u0435",overflow:"\u041f\u0435\u0440\u0435\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435",zindex:"Z-\u0438\u043d\u0434\u0435\u043a\u0441",visibility:"\u0412\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c","positioning_type":"\u0422\u0438\u043f",position:"\u041f\u043e\u0437\u0438\u0446\u0438\u044f","bullet_image":"\u041c\u0430\u0440\u043a\u0435\u0440","list_type":"\u0422\u0438\u043f",color:"\u0426\u0432\u0435\u0442",height:"\u0412\u044b\u0441\u043e\u0442\u0430",width:"\u0428\u0438\u0440\u0438\u043d\u0430",style:"\u0421\u0442\u0438\u043b\u044c",margin:"\u041e\u0442\u0441\u0442\u0443\u043f",left:"\u0421\u043b\u0435\u0432\u0430",bottom:"\u0421\u043d\u0438\u0437\u0443",right:"\u0421\u043f\u0440\u0430\u0432\u0430",top:"\u0412\u0432\u0435\u0440\u0445",same:"\u041e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e \u0434\u043b\u044f \u0432\u0441\u0435\u0445",padding:"\u041f\u043e\u043b\u044f","box_clear":"\u042f\u0432\u043d\u044b\u0439","box_float":"\u041f\u043b\u0430\u0432\u0430\u044e\u0449\u0438\u0439","box_height":"\u0412\u044b\u0441\u043e\u0442\u0430","box_width":"\u0428\u0438\u0440\u0438\u043d\u0430","block_display":"\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435","block_whitespace":"\u041f\u0440\u043e\u0431\u0435\u043b","block_text_indent":"\u041e\u0442\u0441\u0442\u0443\u043f \u0442\u0435\u043a\u0441\u0442\u0430","block_text_align":"\u0412\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u0435 \u0442\u0435\u043a\u0441\u0442\u0430","block_vertical_alignment":"\u0412\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u0435","block_letterspacing":"\u041e\u0442\u0441\u0442\u0443\u043f\u044b \u043c\u0435\u0436\u0434\u0443 \u0431\u0443\u043a\u0432\u0430\u043c\u0438","block_wordspacing":"\u041e\u0442\u0441\u0442\u0443\u043f\u044b \u043c\u0435\u0436\u0434\u0443 \u0441\u043b\u043e\u0432\u0430\u043c\u0438","background_vpos":"\u0412\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0437\u0438\u0446\u0438\u044f","background_hpos":"\u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0437\u0438\u0446\u0438\u044f","background_attachment":"\u041f\u0440\u0438\u0432\u044f\u0437\u043a\u0430","background_repeat":"\u041f\u043e\u0432\u0442\u043e\u0440","background_image":"\u0424\u043e\u043d\u043e\u0432\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435","background_color":"\u0426\u0432\u0435\u0442 \u0444\u043e\u043d\u0430","text_none":"\u0411\u0435\u0437 \u0432\u0441\u0435\u0433\u043e","text_blink":"\u041c\u0435\u0440\u0446\u0430\u044e\u0449\u0438\u0439","text_case":"\u0420\u0435\u0433\u0438\u0441\u0442\u0440","text_striketrough":"\u0417\u0430\u0447\u0435\u0440\u043a\u043d\u0443\u0442\u044b\u0439","text_underline":"\u041f\u043e\u0434\u0447\u0435\u0440\u043a\u043d\u0443\u0442\u044b\u0439","text_overline":"\u0421 \u0432\u0435\u0440\u0445\u043d\u0435\u0439 \u0447\u0435\u0440\u0442\u043e\u0439","text_decoration":"\u041e\u0444\u043e\u0440\u043c\u043b\u0435\u043d\u0438\u0435","text_color":"\u0426\u0432\u0435\u0442",text:"\u0422\u0435\u043a\u0441\u0442",background:"\u0424\u043e\u043d",block:"\u0411\u043b\u043e\u043a",box:"\u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440",border:"\u0413\u0440\u0430\u043d\u0438\u0446\u0430",list:"\u0421\u043f\u0438\u0441\u043e\u043a"});
|
|
@ -1 +0,0 @@
|
|||||||
tinyMCE.addI18n('ru.template_dlg',{title:"\u0428\u0430\u0431\u043b\u043e\u043d\u044b",label:"\u0428\u0430\u0431\u043b\u043e\u043d","desc_label":"\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435",desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d",select:"\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0448\u0430\u0431\u043b\u043e\u043d",preview:"\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440",warning:"\u0412\u043d\u0438\u043c\u0430\u043d\u0438\u0435: \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u043f\u043e\u0442\u0435\u0440\u044f\u043c \u0434\u0430\u043d\u043d\u044b\u0445/","mdate_format":"%Y.%m.%d %H:%M:%S","cdate_format":"%Y.%m.%d %H:%M:%S","months_long":"\u044f\u043d\u0432\u0430\u0440\u044c,\u0444\u0435\u0432\u0440\u0430\u043b\u044c,\u043c\u0430\u0440\u0442,\u0430\u043f\u0440\u0435\u043b\u044c,\u043c\u0430\u0439,\u0438\u044e\u043d\u044c,\u0438\u044e\u043b\u044c,\u0430\u0432\u0433\u0443\u0441\u0442,\u0441\u0435\u043d\u0442\u044f\u0431\u0440\u044c,\u043e\u043a\u0442\u044f\u0431\u0440\u044c,\u043d\u043e\u044f\u0431\u0440\u044c,\u0434\u0435\u043a\u0430\u0431\u0440\u044c","months_short":"\u044f\u043d\u0432,\u0444\u0435\u0432,\u043c\u0430\u0440\u0442,\u0430\u043f\u0440,\u043c\u0430\u0439,\u0438\u044e\u043d\u044c,\u0438\u044e\u043b\u044c,\u0430\u0432\u0433,\u0441\u0435\u043d,\u043e\u043a\u0442,\u043d\u043e\u044f,\u0434\u0435\u043a","day_long":"\u0432\u043e\u0441\u043a\u0440\u0435\u0441\u0435\u043d\u044c\u0435,\u043f\u043e\u043d\u0435\u0434\u0435\u043b\u044c\u043d\u0438\u043a,\u0432\u0442\u043e\u0440\u043d\u0438\u043a,\u0441\u0440\u0435\u0434\u0430,\u0447\u0435\u0442\u0432\u0435\u0440\u0433,\u043f\u044f\u0442\u043d\u0438\u0446\u0443,\u0441\u0443\u0431\u0431\u043e\u0442\u0430,\u0432\u043e\u0441\u043a\u0440\u0435\u0441\u0435\u043d\u044c\u0435","day_short":"\u0432\u0441,\u043f\u043d,\u0432\u0442,\u0441\u0440,\u0447\u0442,\u043f\u0442,\u0441\u0431,\u0432\u0441"});
|
|
@ -1 +0,0 @@
|
|||||||
tinyMCE.addI18n('ru.xhtmlxtras_dlg',{"attribs_title":"\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430","option_rtl":"\u0421\u043f\u0440\u0430\u0432\u0430 \u043d\u0430\u043b\u0435\u0432\u043e","option_ltr":"\u0421\u043b\u0435\u0432\u0430 \u043d\u0430\u043f\u0440\u0430\u0432\u043e","insert_date":"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0434\u0430\u0442\u0443/\u0432\u0440\u0435\u043c\u044f",remove:"\u0423\u0434\u0430\u043b\u0438\u0442\u044c","title_cite_element":"\u0426\u0438\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435","title_abbr_element":"\u0421\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u0435","title_acronym_element":"\u0410\u0431\u0431\u0440\u0435\u0432\u0438\u0430\u0446\u0438\u044f","title_del_element":"\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435","title_ins_element":"\u0417\u0430\u043c\u0435\u043d\u0430","fieldset_events_tab":"\u0421\u043e\u0431\u044b\u0442\u0438\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430","fieldset_attrib_tab":"\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430","fieldset_general_tab":"\u041e\u0431\u0449\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b","events_tab":"\u0421\u043e\u0431\u044b\u0442\u0438\u044f","attrib_tab":"\u0410\u0442\u0440\u0438\u0431\u0443\u0442\u044b","general_tab":"\u041e\u0431\u0449\u0435\u0435","attribute_attrib_tab":"\u0410\u0442\u0440\u0438\u0431\u0443\u0442\u044b","attribute_events_tab":"\u0421\u043e\u0431\u044b\u0442\u0438\u044f","attribute_label_accesskey":"\u041a\u043b\u044e\u0447 \u0434\u043e\u0441\u0442\u0443\u043f\u0430","attribute_label_tabindex":"\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a","attribute_label_langcode":"\u042f\u0437\u044b\u043a","attribute_option_rtl":"\u0421\u043f\u0440\u0430\u0432\u0430 \u043d\u0430\u043b\u0435\u0432\u043e","attribute_option_ltr":"\u0421\u043b\u0435\u0432\u0430 \u043d\u0430\u043f\u0440\u0430\u0432\u043e","attribute_label_langdir":"\u041d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u0435\u043a\u0441\u0442\u0430","attribute_label_datetime":"\u0414\u0430\u0442\u0430/\u0412\u0440\u0435\u043c\u044f","attribute_label_cite":"\u0426\u0438\u0442\u0430\u0442\u0430","attribute_label_style":"\u0421\u0442\u0438\u043b\u044c","attribute_label_class":"\u041a\u043b\u0430\u0441\u0441","attribute_label_id":"\u0418\u043c\u044f","attribute_label_title":"\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a"});
|
|
@ -1 +0,0 @@
|
|||||||
tinyMCE.addI18n('ru.simple',{"cleanup_desc":"\u041e\u0447\u0438\u0441\u0442\u0438\u0442\u044c \u043b\u0438\u0448\u043d\u0438\u0439 \u043a\u043e\u0434","redo_desc":"\u0412\u0435\u0440\u043d\u0443\u0442\u044c (Ctrl+Y)","undo_desc":"\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c (Ctrl+Z)","numlist_desc":"\u041d\u0443\u043c\u0435\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a","bullist_desc":"\u041c\u0430\u0440\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a","striketrough_desc":"\u0417\u0430\u0447\u0435\u0440\u043a\u043d\u0443\u0442\u044b\u0439","underline_desc":"\u041f\u043e\u0434\u0447\u0435\u0440\u043a\u043d\u0443\u0442\u044b\u0439 (Ctrl+U)","italic_desc":"\u041a\u0443\u0440\u0441\u0438\u0432 (Ctrl+I)","bold_desc":"\u041f\u043e\u043b\u0443\u0436\u0438\u0440\u043d\u044b\u0439 (Ctrl+B)"});
|
|
@ -6,7 +6,7 @@ require 'active_resource/railtie'
|
|||||||
require 'sprockets/railtie'
|
require 'sprockets/railtie'
|
||||||
|
|
||||||
Bundler.require
|
Bundler.require
|
||||||
require 'locomotive'
|
require 'locomotive/engine'
|
||||||
|
|
||||||
module Dummy
|
module Dummy
|
||||||
class Application < Rails::Application
|
class Application < Rails::Application
|
||||||
@ -43,8 +43,6 @@ module Dummy
|
|||||||
|
|
||||||
# Version of your assets, change this if you want to expire all your assets
|
# Version of your assets, change this if you want to expire all your assets
|
||||||
config.assets.version = '1.0'
|
config.assets.version = '1.0'
|
||||||
|
|
||||||
config.middleware.use 'Locomotive::InlineEditorMiddleware'
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
.aloha-editable {
|
|
||||||
min-height: 1.2em;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
.aloha-editable ::selection,
|
|
||||||
.aloha-editable ::-moz-selection {
|
|
||||||
background: #80B5F2;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.aloha-editable-zerowidthfix {
|
|
||||||
padding: 0px 5px 0px 5px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.aloha-logo {
|
|
||||||
width:37px !important;
|
|
||||||
height:25px !important;
|
|
||||||
background-image: url('../img/gentics-logo.png') !important;
|
|
||||||
}
|
|
||||||
.aloha-maximize {
|
|
||||||
background-image: url('../img/gentics-logo.png') !important;
|
|
||||||
}
|
|
||||||
.aloha-fade-out {
|
|
||||||
background-image: url('../img/fade-out.png') !important;
|
|
||||||
width:20px !important;
|
|
||||||
height:20px !important;
|
|
||||||
}
|
|
||||||
.aloha-fade-in {
|
|
||||||
background-image: url('../img/fade-in.png') !important;
|
|
||||||
width:20px !important;
|
|
||||||
height:20px !important;
|
|
||||||
}
|
|
||||||
.aloha-maximize {
|
|
||||||
width:20px !important;
|
|
||||||
height:20px !important;
|
|
||||||
background-image: url('../img/maximize.png') !important;
|
|
||||||
}
|
|
||||||
.aloha-textarea {
|
|
||||||
overflow: hidden;
|
|
||||||
border:1px solid #ccc;
|
|
||||||
padding:6px;
|
|
||||||
overflow:auto;
|
|
||||||
}
|
|
@ -1,284 +0,0 @@
|
|||||||
.aloha-sidebar-bar {
|
|
||||||
z-index: 999999999;
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
text-align: left;
|
|
||||||
font-family: Arial, sans-serif;
|
|
||||||
font-size: 12px;
|
|
||||||
border-right: 1px solid #888;
|
|
||||||
-moz-box-shadow: 0px 0px 10px rgba(0, 0, 0, .5);
|
|
||||||
-webkit-box-shadow: 0px 0px 10px rgba(0, 0, 0, .5);
|
|
||||||
box-shadow: 0px 0px 10px rgba(0, 0, 0, .5);
|
|
||||||
|
|
||||||
}
|
|
||||||
.aloha-sidebar-bar.aloha-sidebar-right {
|
|
||||||
left: auto;
|
|
||||||
right: 0;
|
|
||||||
border-right-width: 0;
|
|
||||||
border-left: 1px solid #888;
|
|
||||||
}
|
|
||||||
.aloha-sidebar-inner {
|
|
||||||
position: relative;
|
|
||||||
background-color: #ccc;
|
|
||||||
background-image: -webkit-radial-gradient(
|
|
||||||
rgba(0, 0, 0, 0.0) 20%,
|
|
||||||
rgba(0, 0, 0, 0.2) 80%,
|
|
||||||
rgba(0, 0, 0, 0.3) 100%
|
|
||||||
);
|
|
||||||
background-image: -moz-radial-gradient(
|
|
||||||
rgba(0, 0, 0, 0.0) 20%,
|
|
||||||
rgba(0, 0, 0, 0.2) 80%,
|
|
||||||
rgba(0, 0, 0, 0.3) 100%
|
|
||||||
);
|
|
||||||
}
|
|
||||||
.aloha-sidebar-panels {
|
|
||||||
margin: 0;
|
|
||||||
padding: 15px 0;
|
|
||||||
}
|
|
||||||
.aloha-sidebar-panels li {
|
|
||||||
overflow: hidden;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0 15px;
|
|
||||||
}
|
|
||||||
.aloha-sidebar-panel-top {
|
|
||||||
-webkit-border-top-left-radius: 5px;
|
|
||||||
-webkit-border-top-right-radius: 5px;
|
|
||||||
-moz-border-radius-topleft: 5px;
|
|
||||||
-moz-border-radius-topright: 5px;
|
|
||||||
}
|
|
||||||
.aloha-sidebar-panel-content.aloha-sidebar-panel-bottom {
|
|
||||||
padding-bottom: 0;
|
|
||||||
-webkit-border-bottom-left-radius: 5px;
|
|
||||||
-webkit-border-bottom-right-radius: 5px;
|
|
||||||
-moz-border-radius-bottomleft: 5px;
|
|
||||||
-moz-border-radius-bottomright: 5px;
|
|
||||||
border-bottom-width: 1px;
|
|
||||||
}
|
|
||||||
.aloha-sidebar-panel-title {
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 8px 0 0 8px;
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
|
||||||
border-bottom-width: 0;
|
|
||||||
background-color: #303539;
|
|
||||||
background-image: -webkit-gradient(
|
|
||||||
linear,
|
|
||||||
center top,
|
|
||||||
center bottom,
|
|
||||||
color-stop(0.00, #6c6f74),
|
|
||||||
color-stop(0.05, #4c4f54),
|
|
||||||
color-stop(0.10, #3f4448),
|
|
||||||
color-stop(0.45, #383d41),
|
|
||||||
color-stop(0.50, #303539),
|
|
||||||
color-stop(0.95, #33363b)
|
|
||||||
);
|
|
||||||
background-image: -moz-linear-gradient(
|
|
||||||
center top,
|
|
||||||
#6c6f74 0%,
|
|
||||||
#4c4f54 5%,
|
|
||||||
#3f4448 10%,
|
|
||||||
#383d41 45%,
|
|
||||||
#303539 50%,
|
|
||||||
#33363b 95%
|
|
||||||
);
|
|
||||||
|
|
||||||
color: #ccc;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: bold;
|
|
||||||
line-height: 1.5em;
|
|
||||||
text-shadow: 0 0 6px #23262b;
|
|
||||||
}
|
|
||||||
.aloha-sidebar-panel-title:hover {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
.aloha-sidebar-panel-title-arrow {
|
|
||||||
position: absolute;
|
|
||||||
top: 8px;
|
|
||||||
left: 8px;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
background: url(../img/arrow.png) no-repeat center center;
|
|
||||||
opacity: 0.3;
|
|
||||||
|
|
||||||
}
|
|
||||||
.aloha-sidebar-panel-title:hover .aloha-sidebar-panel-title-arrow {
|
|
||||||
opacity: 0.9;
|
|
||||||
|
|
||||||
}
|
|
||||||
.aloha-sidebar-panel-title .aloha-sidebar-panel-title-arrow.aloha-sidebar-panel-title-arrow-down {
|
|
||||||
background-image: url(../img/arrow-down.png);
|
|
||||||
}
|
|
||||||
.aloha-sidebar-panel-title-text {
|
|
||||||
margin-left: 24px;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.aloha-sidebar-panel-content {
|
|
||||||
overflow: hidden;
|
|
||||||
height: 5px;
|
|
||||||
background: #303539;
|
|
||||||
}
|
|
||||||
.aloha-sidebar-panel-content-inner {
|
|
||||||
margin: 5px 0 0;
|
|
||||||
padding: 0;
|
|
||||||
color: #888;
|
|
||||||
background: #fff;
|
|
||||||
background-image: -webkit-radial-gradient(
|
|
||||||
rgba(0, 0, 0, 0.0) 50%,
|
|
||||||
rgba(0, 0, 0, 0.1) 90%,
|
|
||||||
rgba(0, 0, 0, 0.2) 100%
|
|
||||||
);
|
|
||||||
background-image: -moz-radial-gradient(
|
|
||||||
rgba(0, 0, 0, 0.0) 50%,
|
|
||||||
rgba(0, 0, 0, 0.1) 90%,
|
|
||||||
rgba(0, 0, 0, 0.2) 100%
|
|
||||||
);
|
|
||||||
}
|
|
||||||
.aloha-sidebar-panel-content input {
|
|
||||||
margin: 5px;
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
.aloha-sidebar-handle {
|
|
||||||
position: absolute;
|
|
||||||
top: 30px;
|
|
||||||
right: -30px;
|
|
||||||
width: 40px;
|
|
||||||
height: 30px;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
background-color: #303539;
|
|
||||||
background-image: -webkit-gradient(
|
|
||||||
linear,
|
|
||||||
center top,
|
|
||||||
center bottom,
|
|
||||||
color-stop(0.00, #6c6f74),
|
|
||||||
color-stop(0.05, #4c4f54),
|
|
||||||
color-stop(0.10, #3f4448),
|
|
||||||
color-stop(0.45, #383d41),
|
|
||||||
color-stop(0.50, #303539),
|
|
||||||
color-stop(0.95, #33363b)
|
|
||||||
);
|
|
||||||
background-image: -moz-linear-gradient(
|
|
||||||
center top,
|
|
||||||
#6c6f74 0%,
|
|
||||||
#4c4f54 5%,
|
|
||||||
#3f4448 10%,
|
|
||||||
#383d41 45%,
|
|
||||||
#303539 50%,
|
|
||||||
#33363b 95%
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
-moz-box-shadow: 0px 0px 10px rgba(0, 0, 0, .5);
|
|
||||||
-webkit-box-shadow: 0px 0px 10px rgba(0, 0, 0, .5);
|
|
||||||
box-shadow: 0px 0px 10px rgba(0, 0, 0, .5);
|
|
||||||
|
|
||||||
border-top-right-radius: 5px;
|
|
||||||
border-bottom-right-radius: 5px;
|
|
||||||
-moz-border-radius-topright: 5px;
|
|
||||||
-moz-border-radius-bottomright: 5px;
|
|
||||||
-webkit-border-top-right-radius: 5px;
|
|
||||||
-webkit-border-bottom-right-radius: 5px;
|
|
||||||
}
|
|
||||||
.aloha-sidebar-right .aloha-sidebar-handle {
|
|
||||||
left: -30px;
|
|
||||||
border-top-right-radius: 0px;
|
|
||||||
border-bottom-right-radius: 0px;
|
|
||||||
-moz-border-radius-topright: 0px;
|
|
||||||
-moz-border-radius-bottomright: 0px;
|
|
||||||
-webkit-border-top-right-radius: 0px;
|
|
||||||
-webkit-border-bottom-right-radius: 0px;
|
|
||||||
|
|
||||||
border-top-left-radius: 5px;
|
|
||||||
border-bottom-left-radius: 5px;
|
|
||||||
-moz-border-radius-topleft: 5px;
|
|
||||||
-moz-border-radius-bottomleft: 5px;
|
|
||||||
-webkit-border-top-left-radius: 5px;
|
|
||||||
-webkit-border-bottom-left-radius: 5px;
|
|
||||||
}
|
|
||||||
.aloha-sidebar-handle-icon {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top: 5px;
|
|
||||||
right: 5px;
|
|
||||||
background: url(../img/arrow.png) no-repeat center center;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
opacity: 0.5;
|
|
||||||
|
|
||||||
}
|
|
||||||
.aloha-sidebar-right .aloha-sidebar-handle-icon {
|
|
||||||
left: 5px;
|
|
||||||
right: auto;
|
|
||||||
}
|
|
||||||
.aloha-sidebar-handle-icon.aloha-sidebar-handle-icon-left {
|
|
||||||
background-image: url(../img/arrow-left.png);
|
|
||||||
}
|
|
||||||
.aloha-sidebar-panel-parent-path {
|
|
||||||
background-color: #303539;
|
|
||||||
background-image: -webkit-gradient(
|
|
||||||
linear,
|
|
||||||
center top,
|
|
||||||
center bottom,
|
|
||||||
color-stop(0.00, #6c6f74),
|
|
||||||
color-stop(0.05, #4c4f54),
|
|
||||||
color-stop(0.10, #3f4448),
|
|
||||||
color-stop(0.45, #383d41),
|
|
||||||
color-stop(0.50, #303539),
|
|
||||||
color-stop(0.95, #33363b)
|
|
||||||
);
|
|
||||||
background-image: -moz-linear-gradient(
|
|
||||||
center top,
|
|
||||||
#6c6f74 0%,
|
|
||||||
#4c4f54 5%,
|
|
||||||
#3f4448 10%,
|
|
||||||
#383d41 45%,
|
|
||||||
#303539 50%,
|
|
||||||
#33363b 95%
|
|
||||||
);
|
|
||||||
|
|
||||||
color: #fff;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 12px;
|
|
||||||
text-shadow: 0 0 6px #23262b;
|
|
||||||
white-space: nowrap;
|
|
||||||
line-height: 1em;
|
|
||||||
}
|
|
||||||
.aloha-sidebar-panel-parent-path:hover {
|
|
||||||
opacity: 0.9;
|
|
||||||
|
|
||||||
}
|
|
||||||
.aloha-sidebar-panel-parent-path span {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 0 10px 0 5px;
|
|
||||||
background: url(../img/breadcrumb-divider.png) no-repeat right center;
|
|
||||||
opacity: 0.25;
|
|
||||||
|
|
||||||
line-height: 1.6em;
|
|
||||||
}
|
|
||||||
.aloha-sidebar-panel-parent-path span:first-child {
|
|
||||||
font-weight: bold;
|
|
||||||
opacity: 0.8;
|
|
||||||
|
|
||||||
}
|
|
||||||
.aloha-sidebar-panel-parent-path span:last-child {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
.aloha-sidebar-panel-parent-content {
|
|
||||||
padding: 4px;
|
|
||||||
background-image: -webkit-gradient(
|
|
||||||
linear,
|
|
||||||
center top,
|
|
||||||
center bottom,
|
|
||||||
color-stop(0.0, rgba(0, 0, 0, 0.25)),
|
|
||||||
color-stop(0.05, rgba(0, 0, 0, 0.0))
|
|
||||||
);
|
|
||||||
background-image: -moz-linear-gradient(
|
|
||||||
center top,
|
|
||||||
rgba(0, 0, 0, 0.25) 0%,
|
|
||||||
rgba(0, 0, 0, 0.0) 5%
|
|
||||||
);
|
|
||||||
}
|
|
7774
vendor/assets/javascripts/locomotive/aloha/css/aloha.css
vendored
@ -1,33 +0,0 @@
|
|||||||
.aloha-floatingmenu table, .aloha-floatingmenu tr, .aloha-floatingmenu td,
|
|
||||||
.ext-root table, .ext-root tr, .ext-root td,
|
|
||||||
table.x-layer, .x-layer tr, .x-layer td,
|
|
||||||
table.x-window, .x-window tr, .x-window td,
|
|
||||||
table.x-toolbar-ct, .x-toolbar-ct tr, .x-toolbar-ct td,
|
|
||||||
table.x-toolbar-left, .x-toolbar-left tr, .x-toolbar-left td,
|
|
||||||
table.x-table-layout, .x-table-layout tr, .x-table-layout td,
|
|
||||||
table.x-toolbar-ct table, .x-toolbar-cell td, .x-table-layout-cell td {
|
|
||||||
width: 0 !important;
|
|
||||||
height: 0 !important;
|
|
||||||
border: 0 !important;
|
|
||||||
padding: 0 !important;
|
|
||||||
margin: 0 !important;
|
|
||||||
background-color: transparent !important;
|
|
||||||
}
|
|
||||||
/* reset for floatingmenu */
|
|
||||||
div.aloha-floatingmenu, div.aloha-shadow {
|
|
||||||
min-width: 0px;
|
|
||||||
}
|
|
||||||
/* more specific for browsers that support nth-child. */
|
|
||||||
.ext-root tr:nth-child(2n), .ext-root tr:nth-child(3n), .ext-root tr:nth-child(4n), .ext-root tr:nth-child(5n) {
|
|
||||||
width: 0 !important;
|
|
||||||
height: 0 !important;
|
|
||||||
border: 0 !important;
|
|
||||||
padding: 0 !important;
|
|
||||||
margin: 0 !important;
|
|
||||||
background-color: transparent !important;
|
|
||||||
}
|
|
||||||
.ext-root ol, .ext-root ul, .x-menu ul, .x-menu ol {
|
|
||||||
list-style:none;
|
|
||||||
margin:0;
|
|
||||||
padding:0;
|
|
||||||
}
|
|
@ -1,357 +0,0 @@
|
|||||||
.aloha-floatingmenu {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
.aloha-floatingmenu.fixed {
|
|
||||||
position: fixed !important;
|
|
||||||
}
|
|
||||||
.aloha-floatingmenu .x-tab-panel-header {
|
|
||||||
border-width: 0px 0px 1px 0px !important;
|
|
||||||
background: none !important;
|
|
||||||
}
|
|
||||||
.aloha-floatingmenu .x-tab-panel-header .x-tab-strip-wrap, .aloha-floatingmenu ul.x-tab-strip-top {
|
|
||||||
background: none !important;
|
|
||||||
}
|
|
||||||
.x-tab-strip-wrap ul li a:hover {
|
|
||||||
border: none;
|
|
||||||
text-decoration:none;
|
|
||||||
}
|
|
||||||
.aloha-floatingmenu .x-tab-panel-header {
|
|
||||||
padding-bottom: 0px !important;
|
|
||||||
}
|
|
||||||
.aloha-floatingmenu:hover {
|
|
||||||
background-color: #E0E0E0;
|
|
||||||
-moz-border-radius-topleft: 3px;
|
|
||||||
-moz-border-radius-topright: 3px;
|
|
||||||
-webkit-border-top-left-radius: 3px;
|
|
||||||
-webkit-border-top-right-radius: 3px;
|
|
||||||
border-top-left-radius: 3px;
|
|
||||||
border-top-right-radius: 3px;
|
|
||||||
background: url(../img/grabhandle.png) no-repeat scroll center 5px rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
.aloha-floatingmenu:hover .aloha-floatingmenu-pin {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.aloha-floatingmenu-pin {
|
|
||||||
background: url("../img/pin.png") no-repeat scroll 0 6px transparent;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-left: 5px !important;
|
|
||||||
width: 16px;
|
|
||||||
position: absolute !important;
|
|
||||||
right: 10px;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.aloha-floatingmenu-pinned {
|
|
||||||
background-position: -16px 6px;
|
|
||||||
}
|
|
||||||
#aloha-floatingmenu-shadow {
|
|
||||||
position: absolute;
|
|
||||||
top: -1000;
|
|
||||||
left: -1000;
|
|
||||||
display: none;
|
|
||||||
z-index: 8800;
|
|
||||||
}
|
|
||||||
#aloha-floatingmenu-shadow.fixed {
|
|
||||||
position: fixed !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.x-tree-root-ct {
|
|
||||||
padding: 0px;
|
|
||||||
}
|
|
||||||
.x-tree-node {
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
.x-tree-node-ct {
|
|
||||||
padding: 0px;
|
|
||||||
}
|
|
||||||
.aloha-button a:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
button.aloha-button {
|
|
||||||
background: url('../img/base.png') no-repeat !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-big {
|
|
||||||
background: url('../img/base-big.png') no-repeat !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-b {
|
|
||||||
background-position: 0px 0px;
|
|
||||||
}
|
|
||||||
button.aloha-button-i {
|
|
||||||
background-position: -16px 0px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-u {
|
|
||||||
background-position: -32px 0px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-del {
|
|
||||||
background-position: -48px 0px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-sub {
|
|
||||||
background-position: -64px 0px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-sup {
|
|
||||||
background-position: -80px 0px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-ul {
|
|
||||||
background-position: -256px 0px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-ol {
|
|
||||||
background-position: -272px 0px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-indent-list {
|
|
||||||
background-image: url(../img/text_indent.png) !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-outdent-list {
|
|
||||||
background-image: url(../img/text_indent_remove.png) !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-a {
|
|
||||||
background-position: -288px 0px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-a-remove {
|
|
||||||
background-position: -304px 0px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-p {
|
|
||||||
background-position: 0px 0 !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-p-de {
|
|
||||||
background-position: 0px -42px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-h1 {
|
|
||||||
background-position: -52px 0 !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-h1-de {
|
|
||||||
background-position: -52px -42px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-h2 {
|
|
||||||
background-position: -104px 0 !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-h2-de {
|
|
||||||
background-position: -104px -42px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-h3 {
|
|
||||||
background-position: -156px 0 !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-h3-de {
|
|
||||||
background-position: -156px -42px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-h4 {
|
|
||||||
background-position: -208px 0 !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-h4-de {
|
|
||||||
background-position: -208px -42px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-h5 {
|
|
||||||
background-position: -260px 0 !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-h5-de {
|
|
||||||
background-position: -260px -42px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-h6 {
|
|
||||||
background-position: -312px 0 !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-h6-de {
|
|
||||||
background-position: -312px -42px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-pre {
|
|
||||||
background-position: -364px 0 !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-pre-de {
|
|
||||||
background-position: -364px -42px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-title {
|
|
||||||
background-position: -416px 0 !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-title-de {
|
|
||||||
background-position: -416px -42px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-table {
|
|
||||||
background-position: -96px 0 !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-addColumnLeft {
|
|
||||||
background-position: -112px 0 !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-addColumnRight {
|
|
||||||
background-position: -128px 0 !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-addRowBefore {
|
|
||||||
background-position: -144px 0 !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-addRowAfter {
|
|
||||||
background-position: -160px 0 !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-deleteRows {
|
|
||||||
background-position: -176px 0 !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-deleteColumns {
|
|
||||||
background-position: -192px 0 !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-addPerson {
|
|
||||||
background-position: -224px 0 !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-addEvent {
|
|
||||||
background-position: -208px 0 !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-abbr {
|
|
||||||
background-position: -336px 0px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-row-header {
|
|
||||||
background-position: -352px 0px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-col-header {
|
|
||||||
background-position: -368px 0px !important;
|
|
||||||
}
|
|
||||||
button.aloha-button-tree {
|
|
||||||
background-position: -0 0 !important;
|
|
||||||
}
|
|
||||||
div.aloha-button a:hover {
|
|
||||||
border: 1px solid #b2cbff;
|
|
||||||
}
|
|
||||||
.aloha-floatingmenu {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.aloha-floatingmenu .pressed a {
|
|
||||||
border:1px solid #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
html body #aloha-ribbon {
|
|
||||||
z-index:90000;
|
|
||||||
position:fixed;
|
|
||||||
top:0;
|
|
||||||
left:0;
|
|
||||||
width:100%;
|
|
||||||
padding-left:0;
|
|
||||||
padding-right:0;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.x-menu-list-item {
|
|
||||||
text-align:left;
|
|
||||||
}
|
|
||||||
.aloha-shadow {
|
|
||||||
-moz-box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3);
|
|
||||||
-webkit-box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3);
|
|
||||||
box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
ul.aloha-multisplit button.aloha-button {
|
|
||||||
background-image: url(../img/base-multi.png) !important;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: 0 0;
|
|
||||||
|
|
||||||
width: 54px !important;
|
|
||||||
height: 44px !important;
|
|
||||||
-moz-border-radius: 3px;
|
|
||||||
-webkit-border-radius: 3px;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
.aloha-multisplit {
|
|
||||||
float: left;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
ul.aloha-multisplit, div.aloha-multisplit-wrapper {
|
|
||||||
width: 232px;
|
|
||||||
height: 46px;
|
|
||||||
overflow: hidden;
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
}
|
|
||||||
div.aloha-multisplit-wrapper {
|
|
||||||
width: 248px;
|
|
||||||
}
|
|
||||||
ul.aloha-multisplit li {
|
|
||||||
float: left;
|
|
||||||
padding: 0px 1px;
|
|
||||||
margin: 0px;
|
|
||||||
}
|
|
||||||
ul.aloha-multisplit button.aloha-multisplit-wide {
|
|
||||||
font: 11px tahoma,arial,helvetica;
|
|
||||||
height: 18px !important;
|
|
||||||
width: 234px !important;
|
|
||||||
border: 0;
|
|
||||||
border-top: 1px solid #cccccc;
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: white;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: 6px 1px !important;
|
|
||||||
text-align: left;
|
|
||||||
margin-left: -2px;
|
|
||||||
padding-left: 26px;
|
|
||||||
}
|
|
||||||
button.aloha-multisplit-toggle {
|
|
||||||
float: right;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
width: 15px;
|
|
||||||
height: 12px;
|
|
||||||
margin-top: 32px;
|
|
||||||
cursor: pointer;
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
button.aloha-multisplit-toggle-open {
|
|
||||||
background-image: url(../img/multisplit-open.gif);
|
|
||||||
}
|
|
||||||
button.aloha-multisplit-toggle-close {
|
|
||||||
background-image: url(../img/multisplit-close.gif);
|
|
||||||
}
|
|
||||||
ul.aloha-multisplit button {
|
|
||||||
border: 1px solid #cccccc;
|
|
||||||
margin: 1px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
ul.aloha-multisplit button:hover {
|
|
||||||
border: 1px solid #666666;
|
|
||||||
}
|
|
||||||
ul.aloha-multisplit button.aloha-multisplit-wide:hover {
|
|
||||||
border: 0;
|
|
||||||
border-top: 1px solid #cccccc;
|
|
||||||
}
|
|
||||||
ul.aloha-multisplit .aloha-multisplit-activeitem button {
|
|
||||||
border: 2px solid #3B73D7;
|
|
||||||
}
|
|
||||||
ul.aloha-multisplit-expanded {
|
|
||||||
position: absolute;
|
|
||||||
top: 0px;
|
|
||||||
left: 0px;
|
|
||||||
z-index: 20000;
|
|
||||||
background-color: white;
|
|
||||||
border: 1px solid #afafaf;
|
|
||||||
-moz-border-radius: 3px;
|
|
||||||
-webkit-border-radius: 3px;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
ul.aloha-multisplit button.aloha-button-removeFormat {
|
|
||||||
background-image: url(../img/removeformat.png) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* combo-list box
|
|
||||||
*/
|
|
||||||
.x-combo-list {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
.x-combo-list-inner {
|
|
||||||
padding: 3px;
|
|
||||||
}
|
|
||||||
.x-combo-list-inner .loading-indicator {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
.x-combo-selected {
|
|
||||||
color: #fff !important;
|
|
||||||
background-color: #3B73D7 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ui-attribute field
|
|
||||||
*/
|
|
||||||
.x-form-field.x-form-text {
|
|
||||||
color: #333 !important;
|
|
||||||
padding: 3px;
|
|
||||||
}
|
|
||||||
.x-form-field.x-form-text::selection {
|
|
||||||
color: #fff;
|
|
||||||
background: #3B73D7;
|
|
||||||
}
|
|
||||||
.x-form-field.x-form-text::-moz-selection {
|
|
||||||
color: #fff;
|
|
||||||
background: #3B73D7;
|
|
||||||
}
|
|
||||||
.x-form-field.x-form-text::-webkit-selection {
|
|
||||||
color: #fff;
|
|
||||||
background: #3B73D7;
|
|
||||||
}
|
|
Before Width: | Height: | Size: 770 B |
Before Width: | Height: | Size: 790 B |
Before Width: | Height: | Size: 719 B |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 509 KiB |
Before Width: | Height: | Size: 330 B |
Before Width: | Height: | Size: 278 B |
Before Width: | Height: | Size: 292 B |
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 112 B |
Before Width: | Height: | Size: 123 B |
Before Width: | Height: | Size: 929 B |
Before Width: | Height: | Size: 211 B |
Before Width: | Height: | Size: 211 B |
Before Width: | Height: | Size: 564 B |
Before Width: | Height: | Size: 193 B |
Before Width: | Height: | Size: 353 B |
Before Width: | Height: | Size: 351 B |
88671
vendor/assets/javascripts/locomotive/aloha/lib/aloha.js
vendored
@ -1,246 +0,0 @@
|
|||||||
/*!
|
|
||||||
* CommandManager file is part of Aloha Editor Project http://aloha-editor.org
|
|
||||||
* Copyright (c) 2010-2011 Gentics Software GmbH, aloha@gentics.com
|
|
||||||
* Contributors http://aloha-editor.org/contribution.php
|
|
||||||
* Licensed unter the terms of http://www.aloha-editor.org/license.html
|
|
||||||
*//*
|
|
||||||
* Aloha Editor is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.*
|
|
||||||
*
|
|
||||||
* Aloha Editor is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with CommandManager program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
define( [ 'aloha/core', 'aloha/registry', 'aloha/engine', 'util/dom', 'aloha/contenthandlermanager' ],
|
|
||||||
function( Aloha, Registry, Engine, Dom, ContentHandlerManager ) {
|
|
||||||
|
|
||||||
// Action: What the command does when executed via execCommand(). Every command defined
|
|
||||||
// in CommandManager specification has an action defined for it in the relevant section. For example,
|
|
||||||
// the bold command's action generally makes the current selection bold, or removes bold if
|
|
||||||
// the selection is already bold. An editing toolbar might provide buttons that execute the
|
|
||||||
// action for a command if clicked, or a script might run an action without user interaction
|
|
||||||
// to achieve some particular effect.
|
|
||||||
//
|
|
||||||
// Indeterminate: A boolean value returned by queryCommandIndeterm(), depending on the
|
|
||||||
// current state of the document. Generally, a command that has a state defined will be
|
|
||||||
// indeterminate if the state is true for part but not all of the current selection, and a
|
|
||||||
// command that has a value defined will be indeterminate if different parts of the
|
|
||||||
// selection have different values. An editing toolbar might display a button or control
|
|
||||||
// in a special way if the command is indeterminate, like showing a "bold" button as
|
|
||||||
// partially depressed, or leaving a font size selector blank instead of showing the font
|
|
||||||
// size of the current selection. As a rule, a command can only be indeterminate if its
|
|
||||||
// state is false, supposing it has a state.
|
|
||||||
//
|
|
||||||
// State: A boolean value returned by queryCommandState(), depending on the current state
|
|
||||||
// of the document. The state of a command is true if it is already in effect, in some
|
|
||||||
// sense specific to the command. Most commands that have a state defined will take opposite
|
|
||||||
// actions depending on whether the state is true or false, such as making the selection
|
|
||||||
// bold if the state is false and removing bold if the state is true. Others will just
|
|
||||||
// have no effect if the state is true, like the justifyCenter command. Still others will
|
|
||||||
// have the same effect regardless, like the styleWithCss command. An editing toolbar might
|
|
||||||
// display a button or control differently depending on the state and indeterminacy of the
|
|
||||||
// command.
|
|
||||||
//
|
|
||||||
// Value: A string returned by queryCommandValue(), depending on the current state of the
|
|
||||||
// document. A command usually has a value instead of a state if the property it modifies
|
|
||||||
// can take more than two different values, like the foreColor command. If the command is
|
|
||||||
// indeterminate, its value is generally based on the start of the selection. Otherwise,
|
|
||||||
// in most cases the value holds true for the entire selection, but see the justifyCenter
|
|
||||||
// command and its three companions for an exception. An editing toolbar might display the
|
|
||||||
// value of a command as selected in a drop-down or filled in in a text box, if the command
|
|
||||||
// isn't indeterminate.
|
|
||||||
//
|
|
||||||
// Relevant CSS property: CommandManager is defined for certain inline formatting commands, and
|
|
||||||
// is used in algorithms specific to those commands. It is an implementation detail, and
|
|
||||||
// is not exposed to authors. If a command does not have a relevant CSS property
|
|
||||||
// specified, it defaults to null.
|
|
||||||
|
|
||||||
var CommandManager = {
|
|
||||||
|
|
||||||
execCommand: function( commandId, showUi, value, range ) {
|
|
||||||
|
|
||||||
// Read current selection if not passed
|
|
||||||
if ( !range ) {
|
|
||||||
if ( !Aloha.getSelection().getRangeCount() ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
range = Aloha.getSelection().getRangeAt( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
// For the insertHTML command we provide contenthandler API
|
|
||||||
if ( commandId == 'insertHTML' ) {
|
|
||||||
//if (typeof Aloha.settings.contentHandler.insertHtml === 'undefined') {
|
|
||||||
// use all registered content handler; used for copy & paste atm (or write log message)
|
|
||||||
// Aloha.settings.contentHandler.insertHtml = Aloha.defaults.contentHandler.insertHtml;
|
|
||||||
//}
|
|
||||||
value = ContentHandlerManager.handleContent( value, {
|
|
||||||
contenthandler: Aloha.settings.contentHandler.insertHtml
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Engine.execCommand( commandId, showUi, value, range );
|
|
||||||
|
|
||||||
// Read range after engine modification
|
|
||||||
range = Aloha.getSelection().getRangeAt( 0 );
|
|
||||||
|
|
||||||
// FIX: doCleanup should work with W3C range
|
|
||||||
var startnode = range.commonAncestorContainer.parentNode;
|
|
||||||
var rangeObject = new window.GENTICS.Utils.RangeObject();
|
|
||||||
rangeObject.startContainer = range.startContainer;
|
|
||||||
rangeObject.startOffset = range.startOffset;
|
|
||||||
rangeObject.endContainer = range.endContainer;
|
|
||||||
rangeObject.endOffset = range.endOffset;
|
|
||||||
Dom.doCleanup({merge:true, removeempty: false}, rangeObject, startnode);
|
|
||||||
rangeObject.select();
|
|
||||||
Aloha.trigger('aloha-command-executed', commandId);
|
|
||||||
},
|
|
||||||
|
|
||||||
// If command is available and not disabled or the active range is not null
|
|
||||||
// the command is enabled
|
|
||||||
queryCommandEnabled: function( commandId, range ) {
|
|
||||||
|
|
||||||
// Take current selection if not passed
|
|
||||||
if ( !range ) {
|
|
||||||
if ( !Aloha.getSelection().getRangeCount() ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
range = Aloha.getSelection().getRangeAt(0);
|
|
||||||
}
|
|
||||||
return Engine.queryCommandEnabled( commandId, range );
|
|
||||||
},
|
|
||||||
|
|
||||||
// "Return true if command is indeterminate, otherwise false."
|
|
||||||
queryCommandIndeterm: function( commandId, range ) {
|
|
||||||
|
|
||||||
// Take current selection if not passed
|
|
||||||
if ( !range ) {
|
|
||||||
if ( !Aloha.getSelection().getRangeCount() ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
range = Aloha.getSelection().getRangeAt(0);
|
|
||||||
}
|
|
||||||
return Engine.queryCommandIndeterm( commandId, range );
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
queryCommandState: function( commandId, range ) {
|
|
||||||
|
|
||||||
// Take current selection if not passed
|
|
||||||
if ( !range ) {
|
|
||||||
if ( !Aloha.getSelection().getRangeCount() ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
range = Aloha.getSelection().getRangeAt(0);
|
|
||||||
}
|
|
||||||
return Engine.queryCommandState( commandId, range );
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
// "When the queryCommandSupported(command) method on the HTMLDocument
|
|
||||||
// interface is invoked, the user agent must return true if command is
|
|
||||||
// supported, and false otherwise."
|
|
||||||
queryCommandSupported: function( commandId ) {
|
|
||||||
|
|
||||||
return Engine.queryCommandSupported( commandId );
|
|
||||||
},
|
|
||||||
|
|
||||||
queryCommandValue: function( commandId, range ) {
|
|
||||||
|
|
||||||
// Take current selection if not passed
|
|
||||||
if ( !range ) {
|
|
||||||
if ( !Aloha.getSelection().getRangeCount() ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
range = Aloha.getSelection().getRangeAt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// "Return command's value."
|
|
||||||
return Engine.queryCommandValue( commandId, range );
|
|
||||||
},
|
|
||||||
querySupportedCommands: function() {
|
|
||||||
|
|
||||||
var
|
|
||||||
commands = [],
|
|
||||||
command;
|
|
||||||
|
|
||||||
for ( command in Engine.commands ) {
|
|
||||||
commands.push( command );
|
|
||||||
}
|
|
||||||
return commands;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// create an instance
|
|
||||||
CommandManager = new ( Registry.extend( CommandManager ) )();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes a registered command.
|
|
||||||
* http://aryeh.name/spec/editing/editing.html#methods-of-the-htmldocument-interface
|
|
||||||
* @method
|
|
||||||
* @param command name of the command
|
|
||||||
* @param showUI has no effect for Aloha Editor and is only here because in spec...
|
|
||||||
* @param value depends on the used command and it impementation
|
|
||||||
* @range optional a range on which the command will be executed if not specified
|
|
||||||
* the current selection will be used as range
|
|
||||||
*/
|
|
||||||
Aloha.execCommand = CommandManager.execCommand;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check wheater the command in enabled.
|
|
||||||
* If command is not supported, raise a NOT_SUPPORTED_ERR exception.
|
|
||||||
* @param command name of the command
|
|
||||||
* @return true if command is enabled, false otherwise.
|
|
||||||
*/
|
|
||||||
Aloha.queryCommandEnabled = CommandManager.queryCommandEnabled;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the command has an indetermed state.
|
|
||||||
* If command is not supported, a NOT_SUPPORTED_ERR exception is thrown
|
|
||||||
* If command has no indeterminacy, INVALID_ACCESS_ERR exception is thrown
|
|
||||||
* If command is not enabled, return false.
|
|
||||||
* @param command name of the command
|
|
||||||
* @range optional a range on which the command will be executed if not specified
|
|
||||||
* the current selection will be used as range
|
|
||||||
* @return true if command is indeterminate, otherwise false.
|
|
||||||
*/
|
|
||||||
Aloha.queryCommandIndeterm = CommandManager.queryCommandIndeterm;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the state of a given command
|
|
||||||
* If command is not supported, a NOT_SUPPORTED_ERR exception is thrown
|
|
||||||
* If command has no state, an INVALID_ACCESS_ERR exception is thrown
|
|
||||||
* If command is not enabled, return false
|
|
||||||
* If the state override for command is set, it returns the state
|
|
||||||
* @param command name of the command
|
|
||||||
* @return state override or true if command's state is true, otherwise false.
|
|
||||||
*/
|
|
||||||
Aloha.queryCommandState = CommandManager.queryCommandState;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a given command is supported
|
|
||||||
* @return true if command is supported, and false otherwise.
|
|
||||||
*/
|
|
||||||
Aloha.queryCommandSupported = CommandManager.queryCommandSupported;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Value of a given Command
|
|
||||||
* If command is not supported, a NOT_SUPPORTED_ERR exception is thrown
|
|
||||||
* If command is not enabled, returns an empty string
|
|
||||||
* If command is "fontSize" and its value override is set, an integer
|
|
||||||
* number of pixels is returned as font size for the result.
|
|
||||||
* If the value override for command is set, it returns that.
|
|
||||||
* @return command's value.
|
|
||||||
*/
|
|
||||||
Aloha.queryCommandValue = CommandManager.queryCommandValue;
|
|
||||||
|
|
||||||
Aloha.querySupportedCommands = CommandManager.querySupportedCommands;
|
|
||||||
|
|
||||||
return CommandManager;
|
|
||||||
});
|
|
@ -1,330 +0,0 @@
|
|||||||
/*!
|
|
||||||
* This file is part of Aloha Editor Project http://aloha-editor.org
|
|
||||||
* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com
|
|
||||||
* Contributors http://aloha-editor.org/contribution.php
|
|
||||||
* Licensed unter the terms of http://www.aloha-editor.org/license.html
|
|
||||||
*//*
|
|
||||||
* Aloha Editor is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.*
|
|
||||||
*
|
|
||||||
* Aloha Editor is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
define(
|
|
||||||
['aloha/core', 'util/class', 'aloha/jquery'],
|
|
||||||
function(Aloha, Class, jQuery ) {
|
|
||||||
|
|
||||||
|
|
||||||
var
|
|
||||||
// $ = jQuery,
|
|
||||||
// Aloha = window.Aloha,
|
|
||||||
console = window.console;
|
|
||||||
// Class = window.Class
|
|
||||||
// GENTICS = window.GENTICS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the aloha Log
|
|
||||||
* @namespace Aloha
|
|
||||||
* @class Log
|
|
||||||
* @singleton
|
|
||||||
*/
|
|
||||||
var alohaConsole = Class.extend({
|
|
||||||
/**
|
|
||||||
* Initialize the logging
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
init: function() {
|
|
||||||
|
|
||||||
// initialize the logging settings (if not present)
|
|
||||||
if (typeof Aloha.settings.logLevels === 'undefined' || !Aloha.settings.logLevels) {
|
|
||||||
Aloha.settings.logLevels = {'error' : true, 'warn' : true};
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize the logHistory settings (if not present)
|
|
||||||
if (typeof Aloha.settings.logHistory === 'undefined' || !Aloha.settings.logHistory) {
|
|
||||||
Aloha.settings.logHistory = {};
|
|
||||||
}
|
|
||||||
// set the default values for the loghistory
|
|
||||||
if (!Aloha.settings.logHistory.maxEntries) {
|
|
||||||
Aloha.settings.logHistory.maxEntries = 100;
|
|
||||||
}
|
|
||||||
if (!Aloha.settings.logHistory.highWaterMark) {
|
|
||||||
Aloha.settings.logHistory.highWaterMark = 90;
|
|
||||||
}
|
|
||||||
if (!Aloha.settings.logHistory.levels) {
|
|
||||||
Aloha.settings.logHistory.levels = {'error' : true, 'warn' : true};
|
|
||||||
}
|
|
||||||
this.flushLogHistory();
|
|
||||||
|
|
||||||
Aloha.trigger('aloha-logger-ready');
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log History as array of Message Objects. Every object has the properties
|
|
||||||
* 'level', 'component' and 'message'
|
|
||||||
* @property
|
|
||||||
* @type Array
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
logHistory: [],
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flag, which is set as soon as the highWaterMark for the log history is reached.
|
|
||||||
* This flag is reset on every call of flushLogHistory()
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
highWaterMarkReached: false,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs a message to the console
|
|
||||||
* @method
|
|
||||||
* @param {String} level Level of the log ('error', 'warn' or 'info', 'debug')
|
|
||||||
* @param {String} component Component that calls the log
|
|
||||||
* @param {String} message log message
|
|
||||||
*/
|
|
||||||
log: function(level, component, message) {
|
|
||||||
|
|
||||||
|
|
||||||
// log ('Logging message');
|
|
||||||
if ( typeof component === 'undefined' ) {
|
|
||||||
message = level;
|
|
||||||
}
|
|
||||||
if ( typeof component !== 'string' && component && component.toString ) {
|
|
||||||
component = component.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// log ('warn', 'Warning message');
|
|
||||||
if ( typeof message === 'undefined' ) {
|
|
||||||
message = component;
|
|
||||||
component = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof level === 'undefined' || !level) {
|
|
||||||
level = 'log';
|
|
||||||
}
|
|
||||||
|
|
||||||
level = level.toLowerCase();
|
|
||||||
|
|
||||||
if ( typeof Aloha.settings.logLevels === "undefined" ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// now check whether the log level is activated
|
|
||||||
if ( !Aloha.settings.logLevels[ level ] ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
component = component || "Unkown Aloha Component";
|
|
||||||
|
|
||||||
this.addToLogHistory({'level' : level, 'component' : component, 'message' : message, 'date' : new Date()});
|
|
||||||
|
|
||||||
switch (level) {
|
|
||||||
case 'error':
|
|
||||||
if (window.console && console.error) {
|
|
||||||
// FIXME:
|
|
||||||
// Using console.error rather than throwing an error is very
|
|
||||||
// problematic because we get not stack.
|
|
||||||
// We ought to consider doing the following:
|
|
||||||
// throw component + ': ' + message;
|
|
||||||
if(!component && !message) {
|
|
||||||
console.error("Error occured without message and component");
|
|
||||||
} else {
|
|
||||||
console.error(component + ': ' + message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'warn':
|
|
||||||
if (window.console && console.warn) {
|
|
||||||
console.warn(component + ': ' + message);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'info':
|
|
||||||
if (window.console && console.info) {
|
|
||||||
console.info(component + ': ' + message);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'debug':
|
|
||||||
if (window.console && console.log) {
|
|
||||||
console.log(component + ' [' + level + ']: ' + message);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (window.console && console.log) {
|
|
||||||
console.log(component + ' [' + level + ']: ' + message);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log a message of log level 'error'
|
|
||||||
* @method
|
|
||||||
* @param {String} component Component that calls the log
|
|
||||||
* @param {String} message log message
|
|
||||||
*/
|
|
||||||
error: function(component, message) {
|
|
||||||
this.log('error', component, message);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log a message of log level 'warn'
|
|
||||||
* @method
|
|
||||||
* @param {String} component Component that calls the log
|
|
||||||
* @param {String} message log message
|
|
||||||
*/
|
|
||||||
warn: function(component, message) {
|
|
||||||
this.log('warn', component, message);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log a message of log level 'info'
|
|
||||||
* @method
|
|
||||||
* @param {String} component Component that calls the log
|
|
||||||
* @param {String} message log message
|
|
||||||
*/
|
|
||||||
info: function(component, message) {
|
|
||||||
this.log('info', component, message);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log a message of log level 'debug'
|
|
||||||
* @param {String} component Component that calls the log
|
|
||||||
* @param {String} message log message
|
|
||||||
*/
|
|
||||||
debug: function(component, message) {
|
|
||||||
this.log('debug', component, message);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Methods to mark function as deprecated for developers.
|
|
||||||
* @param {String} component String that calls the log
|
|
||||||
* @param {String} message log message
|
|
||||||
*/
|
|
||||||
deprecated: function(component, message) {
|
|
||||||
this.log( 'warn', component, message );
|
|
||||||
// help the developer to locate the call.
|
|
||||||
if ( Aloha.settings.logLevels[ 'deprecated' ] ) {
|
|
||||||
throw new Error ( message );
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether the given log level is currently enabled
|
|
||||||
* @param {String} level
|
|
||||||
* @return true when log level is enabled, false if not
|
|
||||||
*/
|
|
||||||
isLogLevelEnabled: function(level) {
|
|
||||||
return Aloha.settings && Aloha.settings.logLevels && Aloha.settings.logLevels[level];
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether error logging is enabled
|
|
||||||
* @return true if error logging is enabled, false if not
|
|
||||||
*/
|
|
||||||
isErrorEnabled: function() {
|
|
||||||
return this.isLogLevelEnabled('error');
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether warn logging is enabled
|
|
||||||
* @return true if warn logging is enabled, false if not
|
|
||||||
*/
|
|
||||||
isWarnEnabled: function() {
|
|
||||||
return this.isLogLevelEnabled('warn');
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether info logging is enabled
|
|
||||||
* @return true if info logging is enabled, false if not
|
|
||||||
*/
|
|
||||||
isInfoEnabled: function() {
|
|
||||||
return this.isLogLevelEnabled('info');
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether debug logging is enabled
|
|
||||||
* @return true if debug logging is enabled, false if not
|
|
||||||
*/
|
|
||||||
isDebugEnabled: function() {
|
|
||||||
return this.isLogLevelEnabled('debug');
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the given entry to the log history. Check whether the highWaterMark has been reached, and fire an event if yes.
|
|
||||||
* @param {Object} entry entry to be added to the log history
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
addToLogHistory: function(entry) {
|
|
||||||
|
|
||||||
if ( !Aloha.settings.logHistory ) {
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
// when maxEntries is set to something illegal, we do nothing (log history is disabled)
|
|
||||||
// check whether the level is one we like to have logged
|
|
||||||
if ( Aloha.settings.logHistory.maxEntries <= 0
|
|
||||||
|| !Aloha.settings.logHistory.levels[ entry.level ]
|
|
||||||
) {
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// first add the entry as last element to the history array
|
|
||||||
this.logHistory.push( entry );
|
|
||||||
|
|
||||||
// check whether the highWaterMark was reached, if so, fire an event
|
|
||||||
if ( !this.highWaterMarkReached ) {
|
|
||||||
|
|
||||||
if ( this.logHistory.length >= Aloha.settings.logHistory.maxEntries * Aloha.settings.logHistory.highWaterMark / 100 ) {
|
|
||||||
|
|
||||||
// fire the event
|
|
||||||
Aloha.trigger('aloha-log-full');
|
|
||||||
// set the flag (so we will not fire the event again until the logHistory is flushed)
|
|
||||||
this.highWaterMarkReached = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check whether the log is full and eventually remove the oldest entries
|
|
||||||
while ( this.logHistory.length > Aloha.settings.logHistory.maxEntries ) {
|
|
||||||
this.logHistory.shift();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the log history
|
|
||||||
* @return log history as array of objects
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
getLogHistory: function() {
|
|
||||||
return this.logHistory;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flush the log history. Remove all log entries and reset the flag for the highWaterMark
|
|
||||||
* @return void
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
flushLogHistory: function() {
|
|
||||||
this.logHistory = [];
|
|
||||||
this.highWaterMarkReached = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the Log object
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
alohaConsole = new alohaConsole();
|
|
||||||
|
|
||||||
// add to log namespace for compatiblility.
|
|
||||||
return Aloha.Log = Aloha.Console = alohaConsole;
|
|
||||||
|
|
||||||
});
|
|
@ -1,65 +0,0 @@
|
|||||||
/*!
|
|
||||||
* Aloha Editor
|
|
||||||
* Author & Copyright (c) 2010 Gentics Software GmbH
|
|
||||||
* aloha-sales@gentics.com
|
|
||||||
* Licensed unter the terms of http://www.aloha-editor.com/license.html
|
|
||||||
*/
|
|
||||||
define(
|
|
||||||
['aloha/jquery', 'aloha/registry'],
|
|
||||||
function( jQuery, Registry ) {
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an contentHandler from the given definition. Acts as a factory method
|
|
||||||
* for contentHandler.
|
|
||||||
*
|
|
||||||
* @param {Object} definition
|
|
||||||
*/
|
|
||||||
return new ( Registry.extend({
|
|
||||||
|
|
||||||
createHandler: function( definition ) {
|
|
||||||
|
|
||||||
if ( typeof definition.handleContent != 'function' ) {
|
|
||||||
throw 'ContentHandler has no function handleContent().';
|
|
||||||
}
|
|
||||||
|
|
||||||
var AbstractContentHandler = Class.extend({
|
|
||||||
handleContent: function( content ) {
|
|
||||||
// Implement in subclass!
|
|
||||||
}
|
|
||||||
}, definition);
|
|
||||||
|
|
||||||
return new AbstractContentHandler();
|
|
||||||
},
|
|
||||||
|
|
||||||
handleContent: function ( content, options ) {
|
|
||||||
var handler,
|
|
||||||
handlers = this.getEntries();
|
|
||||||
|
|
||||||
if ( typeof options.contenthandler === 'undefined') {
|
|
||||||
options.contenthandler = [];
|
|
||||||
for ( handler in handlers ) {
|
|
||||||
if ( handlers.hasOwnProperty(handler) ) {
|
|
||||||
options.contenthandler.push(handler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( handler in handlers ) {
|
|
||||||
if ( handlers.hasOwnProperty(handler) ) {
|
|
||||||
if (jQuery.inArray( handler, options.contenthandler ) < 0 ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( typeof handlers[handler].handleContent === 'function') {
|
|
||||||
content = handlers[handler].handleContent( content, options );
|
|
||||||
} else {
|
|
||||||
console.error( 'A valid content handler needs the method handleContent.' );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
}))();
|
|
||||||
});
|
|
@ -1,560 +0,0 @@
|
|||||||
/*!
|
|
||||||
* This file is part of Aloha Editor Project http://aloha-editor.org
|
|
||||||
* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com
|
|
||||||
* Contributors http://aloha-editor.org/contribution.php
|
|
||||||
* Licensed unter the terms of http://www.aloha-editor.org/license.html
|
|
||||||
*//*
|
|
||||||
* Aloha Editor is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.*
|
|
||||||
*
|
|
||||||
* Aloha Editor is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
define(
|
|
||||||
|
|
||||||
[
|
|
||||||
'aloha/jquery',
|
|
||||||
'aloha/pluginmanager'
|
|
||||||
],
|
|
||||||
|
|
||||||
function ( jQuery, PluginManager ) {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------
|
|
||||||
// Private variables
|
|
||||||
//----------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hash table that will be populated through the loadPlugins method.
|
|
||||||
* Maps the names of plugins with their urls for easy assess in the getPluginsUrl method
|
|
||||||
*/
|
|
||||||
var pluginPaths = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base Aloha Object
|
|
||||||
* @namespace Aloha
|
|
||||||
* @class Aloha The Aloha base object, which contains all the core functionality
|
|
||||||
* @singleton
|
|
||||||
*/
|
|
||||||
jQuery.extend(true, Aloha, {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Aloha Editor Version we are using
|
|
||||||
* It should be set by us and updated for the particular branch
|
|
||||||
* @property
|
|
||||||
*/
|
|
||||||
version: '0.10.0',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Array of editables that are managed by Aloha
|
|
||||||
* @property
|
|
||||||
* @type Array
|
|
||||||
*/
|
|
||||||
editables: [],
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The currently active editable is referenced here
|
|
||||||
* @property
|
|
||||||
* @type Aloha.Editable
|
|
||||||
*/
|
|
||||||
activeEditable: null,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* settings object, which will contain all Aloha settings
|
|
||||||
* @cfg {Object} object Aloha's settings
|
|
||||||
*/
|
|
||||||
settings: {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* defaults object, which will contain all Aloha defaults
|
|
||||||
* @cfg {Object} object Aloha's settings
|
|
||||||
*/
|
|
||||||
defaults: {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Namespace for ui components
|
|
||||||
*/
|
|
||||||
ui: {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This represents the name of the users OS. Could be:
|
|
||||||
* 'Mac', 'Linux', 'Win', 'Unix', 'Unknown'
|
|
||||||
* @property
|
|
||||||
* @type string
|
|
||||||
*/
|
|
||||||
OSName: 'Unknown',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Which stage is the aloha init process at?
|
|
||||||
* @property
|
|
||||||
* @type string
|
|
||||||
*/
|
|
||||||
stage: 'loadingAloha',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of loaded plugin names. Available after the
|
|
||||||
* "loadPlugins" stage.
|
|
||||||
*
|
|
||||||
* @property
|
|
||||||
* @type array
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
loadedPlugins: [],
|
|
||||||
|
|
||||||
requirePaths: [],
|
|
||||||
/**
|
|
||||||
* Initialize the initialization process
|
|
||||||
*/
|
|
||||||
init: function () {
|
|
||||||
|
|
||||||
// merge defaults and settings and provide all in settings
|
|
||||||
Aloha.settings = jQuery.extendObjects( true, {}, Aloha.defaults, Aloha.settings );
|
|
||||||
|
|
||||||
// initialize rangy. This is probably necessary here,
|
|
||||||
// because due to the current loading mechanism, rangy
|
|
||||||
// doesn't initialize itself in all browsers
|
|
||||||
if (window.rangy) {
|
|
||||||
window.rangy.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load & Initialise
|
|
||||||
Aloha.stage = 'loadPlugins';
|
|
||||||
Aloha.loadPlugins(function(){
|
|
||||||
Aloha.stage = 'initAloha';
|
|
||||||
Aloha.initAloha(function(){
|
|
||||||
Aloha.stage = 'initPlugins';
|
|
||||||
Aloha.initPlugins(function(){
|
|
||||||
Aloha.stage = 'initGui';
|
|
||||||
Aloha.initGui(function(){
|
|
||||||
Aloha.stage = 'alohaReady';
|
|
||||||
Aloha.trigger('aloha-ready');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load Plugins
|
|
||||||
*/
|
|
||||||
loadPlugins: function (next) {
|
|
||||||
// contains an array like [common/format, common/block]
|
|
||||||
var configuredPluginsWithBundle = this.getPluginsToBeLoaded();
|
|
||||||
|
|
||||||
if (configuredPluginsWithBundle.length) {
|
|
||||||
var paths = {},
|
|
||||||
pluginNames = [],
|
|
||||||
requiredInitializers = [],
|
|
||||||
pathsToPlugins = {};
|
|
||||||
|
|
||||||
// Background: We do not use CommonJS packages for our Plugins
|
|
||||||
// as this breaks the loading order when these modules have
|
|
||||||
// other dependencies.
|
|
||||||
// We "emulate" the commonjs modules with the path mapping.
|
|
||||||
/* require(
|
|
||||||
* { paths: {
|
|
||||||
* 'format': 'plugins/common/format/lib',
|
|
||||||
* 'format/nls': 'plugins/common/format/nls',
|
|
||||||
* ... for every plugin ...
|
|
||||||
* }
|
|
||||||
* },
|
|
||||||
* ['format/format-plugin', ... for every plugin ...],
|
|
||||||
* next <-- when everything is loaded, we continue
|
|
||||||
*/
|
|
||||||
jQuery.each(configuredPluginsWithBundle, function (i, configuredPluginWithBundle) {
|
|
||||||
var tmp, bundleName, pluginName, bundlePath = '';
|
|
||||||
|
|
||||||
tmp = configuredPluginWithBundle.split('/');
|
|
||||||
bundleName = tmp[0];
|
|
||||||
pluginName = tmp[1];
|
|
||||||
|
|
||||||
// TODO assertion if pluginName or bundleName NULL _-> ERROR!!
|
|
||||||
|
|
||||||
if (Aloha.settings.basePath) {
|
|
||||||
bundlePath = Aloha.settings.basePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Aloha.settings.bundles && Aloha.settings.bundles[bundleName]) {
|
|
||||||
bundlePath += Aloha.settings.bundles[bundleName];
|
|
||||||
} else {
|
|
||||||
bundlePath += '../plugins/' + bundleName;
|
|
||||||
}
|
|
||||||
|
|
||||||
pluginNames.push(pluginName);
|
|
||||||
paths[pluginName] = bundlePath + '/' + pluginName + '/lib';
|
|
||||||
|
|
||||||
pathsToPlugins[pluginName] = bundlePath + '/' + pluginName;
|
|
||||||
|
|
||||||
// As the "nls" path lies NOT inside /lib/, but is a sibling to /lib/, we need
|
|
||||||
// to register it explicitely. The same goes for the "css" folder.
|
|
||||||
jQuery.each(['nls', 'css', 'vendor', 'res'], function() {
|
|
||||||
paths[pluginName + '/' + this] = bundlePath + '/' + pluginName + '/' + this;
|
|
||||||
});
|
|
||||||
|
|
||||||
requiredInitializers.push(pluginName + '/' + pluginName + '-plugin');
|
|
||||||
});
|
|
||||||
|
|
||||||
this.loadedPlugins = pluginNames;
|
|
||||||
this.requirePaths = paths;
|
|
||||||
|
|
||||||
// Main Require.js loading call, which fetches all the plugins.
|
|
||||||
require(
|
|
||||||
{
|
|
||||||
context: 'aloha',
|
|
||||||
paths: paths,
|
|
||||||
locale: this.settings.locale || this.defaults.locale || 'en'
|
|
||||||
},
|
|
||||||
requiredInitializers,
|
|
||||||
next
|
|
||||||
);
|
|
||||||
|
|
||||||
pluginPaths = pathsToPlugins;
|
|
||||||
} else {
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches plugins the user wants to have loaded. Returns all plugins the user
|
|
||||||
* has specified with the data-plugins property as array, with the bundle
|
|
||||||
* name in front.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
getPluginsToBeLoaded: function() {
|
|
||||||
// look for data-aloha-plugins attributes and load values
|
|
||||||
var
|
|
||||||
plugins = jQuery('[data-aloha-plugins]').data('aloha-plugins');
|
|
||||||
|
|
||||||
// Determine Plugins
|
|
||||||
if ( typeof plugins === 'string' && plugins !== "") {
|
|
||||||
return plugins.replace(/\s+/g, '').split(',');
|
|
||||||
}
|
|
||||||
// Return
|
|
||||||
return [];
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns list of loaded plugins (without Bundle name)
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
getLoadedPlugins: function() {
|
|
||||||
return this.loadedPlugins;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if a certain plugin is loaded, false otherwise.
|
|
||||||
*/
|
|
||||||
isPluginLoaded: function(pluginName) {
|
|
||||||
var found = false;
|
|
||||||
jQuery.each(this.loadedPlugins, function() {
|
|
||||||
if (pluginName.toString() === this.toString()) {
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return found;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialise Aloha
|
|
||||||
*/
|
|
||||||
initAloha: function(next){
|
|
||||||
// check browser version on init
|
|
||||||
// this has to be revamped, as
|
|
||||||
if (jQuery.browser.webkit && parseFloat(jQuery.browser.version) < 532.5 || // Chrome/Safari 4
|
|
||||||
jQuery.browser.mozilla && parseFloat(jQuery.browser.version) < 1.9 || // FF 3.5
|
|
||||||
jQuery.browser.msie && jQuery.browser.version < 7 || // IE 7
|
|
||||||
jQuery.browser.opera && jQuery.browser.version < 11 ) { // right now, Opera needs some work
|
|
||||||
if (window.console && window.console.log) {
|
|
||||||
window.console.log( 'Your browser is not supported.' );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// register the body click event to blur editables
|
|
||||||
jQuery('html').mousedown(function(e) {
|
|
||||||
// if an Ext JS modal is visible, we don't want to loose the focus on
|
|
||||||
// the editable as we assume that the user must have clicked somewhere
|
|
||||||
// in the modal... where else could he click?
|
|
||||||
// loosing the editable focus in this case hinders correct table
|
|
||||||
// column/row deletion, as the table module will clean it's selection
|
|
||||||
// as soon as the editable is deactivated. Fusubscriberthermore you'd have to
|
|
||||||
// refocus the editable again, which is just strange UX
|
|
||||||
if (Aloha.activeEditable && !Aloha.isMessageVisible() && !Aloha.eventHandled) {
|
|
||||||
Aloha.activeEditable.blur();
|
|
||||||
Aloha.activeEditable = null;
|
|
||||||
}
|
|
||||||
}).mouseup(function(e) {
|
|
||||||
Aloha.eventHandled = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Initialise the base path to the aloha files
|
|
||||||
Aloha.settings.base = Aloha.getAlohaUrl();
|
|
||||||
|
|
||||||
// initialize the Log
|
|
||||||
Aloha.Log.init();
|
|
||||||
|
|
||||||
// initialize the error handler for general javascript errors
|
|
||||||
if ( Aloha.settings.errorhandling ) {
|
|
||||||
window.onerror = function (msg, url, linenumber) {
|
|
||||||
Aloha.Log.error(Aloha, 'Error message: ' + msg + '\nURL: ' + url + '\nLine Number: ' + linenumber);
|
|
||||||
// TODO eventually add a message to the message line?
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// OS detection
|
|
||||||
if (navigator.appVersion.indexOf('Win') != -1) {
|
|
||||||
Aloha.OSName = 'Win';
|
|
||||||
}
|
|
||||||
if (navigator.appVersion.indexOf('Mac') != -1) {
|
|
||||||
Aloha.OSName = 'Mac';
|
|
||||||
}
|
|
||||||
if (navigator.appVersion.indexOf('X11') != -1) {
|
|
||||||
Aloha.OSName = 'Unix';
|
|
||||||
}
|
|
||||||
if (navigator.appVersion.indexOf('Linux') != -1) {
|
|
||||||
Aloha.OSName = 'Linux';
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// this will disable browsers image resizing facilities
|
|
||||||
// disable resize handles
|
|
||||||
var supported;
|
|
||||||
try {
|
|
||||||
supported = document.queryCommandSupported( 'enableObjectResizing' );
|
|
||||||
} catch ( e ) {
|
|
||||||
supported = false;
|
|
||||||
Aloha.Log.log( 'enableObjectResizing is not supported.' );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( supported ) {
|
|
||||||
document.execCommand( 'enableObjectResizing', false, false);
|
|
||||||
Aloha.Log.log( 'enableObjectResizing disabled.' );
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
Aloha.Log.error( e, 'Could not disable enableObjectResizing' );
|
|
||||||
// this is just for others, who will not support disabling enableObjectResizing
|
|
||||||
}
|
|
||||||
// Forward
|
|
||||||
next();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads plugins Aloha
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
initPlugins: function (next) {
|
|
||||||
PluginManager.init(function(){
|
|
||||||
next();
|
|
||||||
}, this.getLoadedPlugins() );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads GUI components
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
initGui: function (next) {
|
|
||||||
|
|
||||||
Aloha.RepositoryManager.init();
|
|
||||||
|
|
||||||
// activate registered editables
|
|
||||||
for (var i = 0, editablesLength = Aloha.editables.length; i < editablesLength; i++) {
|
|
||||||
if ( !Aloha.editables[i].ready ) {
|
|
||||||
Aloha.editables[i].init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward
|
|
||||||
next();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Activates editable and deactivates all other Editables
|
|
||||||
* @param {Editable} editable the Editable to be activated
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
activateEditable: function (editable) {
|
|
||||||
|
|
||||||
// blur all editables, which are currently active
|
|
||||||
for (var i = 0, editablesLength = Aloha.editables.length; i < editablesLength; i++) {
|
|
||||||
if (Aloha.editables[i] != editable && Aloha.editables[i].isActive) {
|
|
||||||
Aloha.editables[i].blur();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Aloha.activeEditable = editable;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current Editable
|
|
||||||
* @return {Editable} returns the active Editable
|
|
||||||
*/
|
|
||||||
getActiveEditable: function() {
|
|
||||||
return Aloha.activeEditable;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* deactivated the current Editable
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
deactivateEditable: function () {
|
|
||||||
|
|
||||||
if ( typeof Aloha.activeEditable === 'undefined' || Aloha.activeEditable === null ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// blur the editable
|
|
||||||
Aloha.activeEditable.blur();
|
|
||||||
Aloha.activeEditable = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an editable by an ID or null if no Editable with that ID registered.
|
|
||||||
* @param {string} id the element id to look for.
|
|
||||||
* @return {Aloha.Editable} editable
|
|
||||||
*/
|
|
||||||
getEditableById: function (id) {
|
|
||||||
|
|
||||||
// if the element is a textarea than route to the editable div
|
|
||||||
if (jQuery('#'+id).get(0).nodeName.toLowerCase() === 'textarea' ) {
|
|
||||||
id = id + '-aloha';
|
|
||||||
}
|
|
||||||
|
|
||||||
// serach all editables for id
|
|
||||||
for (var i = 0, editablesLength = Aloha.editables.length; i < editablesLength; i++) {
|
|
||||||
if (Aloha.editables[i].getId() == id) {
|
|
||||||
return Aloha.editables[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks wheater an object is a registered Aloha Editable.
|
|
||||||
* @param {jQuery} obj the jQuery object to be checked.
|
|
||||||
* @return {boolean}
|
|
||||||
*/
|
|
||||||
isEditable: function (obj) {
|
|
||||||
for (var i=0, editablesLength = Aloha.editables.length; i < editablesLength; i++) {
|
|
||||||
if ( Aloha.editables[i].originalObj.get(0) === obj ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs a message to the console
|
|
||||||
* @param level Level of the log ("error", "warn" or "info", "debug")
|
|
||||||
* @param component Component that calls the log
|
|
||||||
* @param message log message
|
|
||||||
* @return void
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
log: function(level, component, message) {
|
|
||||||
if (typeof Aloha.Log !== "undefined")
|
|
||||||
Aloha.Log.log(level, component, message);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register the given editable
|
|
||||||
* @param editable editable to register
|
|
||||||
* @return void
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
registerEditable: function (editable) {
|
|
||||||
Aloha.editables.push(editable);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unregister the given editable. It will be deactivated and removed from editables.
|
|
||||||
* @param editable editable to unregister
|
|
||||||
* @return void
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
unregisterEditable: function (editable) {
|
|
||||||
|
|
||||||
// Find the index
|
|
||||||
var id = Aloha.editables.indexOf( editable );
|
|
||||||
// Remove it if really found!
|
|
||||||
if (id != -1) {
|
|
||||||
Aloha.editables.splice(id, 1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* String representation
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
toString: function () {
|
|
||||||
return 'Aloha';
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether at least one editable was modified
|
|
||||||
* @method
|
|
||||||
* @return {boolean} true when at least one editable was modified, false if not
|
|
||||||
*/
|
|
||||||
isModified: function () {
|
|
||||||
// check if something needs top be saved
|
|
||||||
for (var i = 0; i < Aloha.editables.length; i++) {
|
|
||||||
if (Aloha.editables[i].isModified && Aloha.editables[i].isModified()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines the Aloha Url
|
|
||||||
* @method
|
|
||||||
* @return {String} alohaUrl
|
|
||||||
*/
|
|
||||||
getAlohaUrl: function( suffix ) {
|
|
||||||
// aloha base path is defined by a script tag with 2 data attributes
|
|
||||||
var requireJs = jQuery('[data-aloha-plugins]'),
|
|
||||||
baseUrl = ( requireJs.length ) ? requireJs[0].src.replace( /\/?aloha.js$/ , '' ) : '';
|
|
||||||
|
|
||||||
return baseUrl;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the Plugin Url
|
|
||||||
* @method
|
|
||||||
* @param {String} name
|
|
||||||
* @return {String} url
|
|
||||||
*/
|
|
||||||
getPluginUrl: function (name) {
|
|
||||||
var url;
|
|
||||||
|
|
||||||
if (name) {
|
|
||||||
url = pluginPaths[name];
|
|
||||||
if(url) {
|
|
||||||
//Check if url is absolute and attach base url if it is not
|
|
||||||
if(!url.match("^(\/|http[s]?:).*")) {
|
|
||||||
url = Aloha.getAlohaUrl() + '/' + url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
return Aloha;
|
|
||||||
});
|
|
@ -1,194 +0,0 @@
|
|||||||
//Add ECMA262-5 method binding if not supported natively
|
|
||||||
//
|
|
||||||
if (!('bind' in Function.prototype)) {
|
|
||||||
Function.prototype.bind= function(owner) {
|
|
||||||
var that= this;
|
|
||||||
if (arguments.length<=1) {
|
|
||||||
return function() {
|
|
||||||
return that.apply(owner, arguments);
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
var args= Array.prototype.slice.call(arguments, 1);
|
|
||||||
return function() {
|
|
||||||
return that.apply(owner, arguments.length===0? args : args.concat(Array.prototype.slice.call(arguments)));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add ECMA262-5 string trim if not supported natively
|
|
||||||
//
|
|
||||||
if (!('trim' in String.prototype)) {
|
|
||||||
String.prototype.trim= function() {
|
|
||||||
return this.replace(/^\s+/, '').replace(/\s+$/, '');
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add ECMA262-5 Array methods if not supported natively
|
|
||||||
//
|
|
||||||
if (!('indexOf' in Array.prototype)) {
|
|
||||||
Array.prototype.indexOf= function(find, i /*opt*/) {
|
|
||||||
if (i===undefined) i= 0;
|
|
||||||
if (i<0) i+= this.length;
|
|
||||||
if (i<0) i= 0;
|
|
||||||
for (var n= this.length; i<n; i++)
|
|
||||||
if (i in this && this[i]===find)
|
|
||||||
return i;
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (!('lastIndexOf' in Array.prototype)) {
|
|
||||||
Array.prototype.lastIndexOf= function(find, i /*opt*/) {
|
|
||||||
if (i===undefined) i= this.length-1;
|
|
||||||
if (i<0) i+= this.length;
|
|
||||||
if (i>this.length-1) i= this.length-1;
|
|
||||||
for (i++; i-->0;) /* i++ because from-argument is sadly inclusive */
|
|
||||||
if (i in this && this[i]===find)
|
|
||||||
return i;
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (!('forEach' in Array.prototype)) {
|
|
||||||
Array.prototype.forEach= function(action, that /*opt*/) {
|
|
||||||
for (var i= 0, n= this.length; i<n; i++)
|
|
||||||
if (i in this)
|
|
||||||
action.call(that, this[i], i, this);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (!('map' in Array.prototype)) {
|
|
||||||
Array.prototype.map= function(mapper, that /*opt*/) {
|
|
||||||
var other= new Array(this.length);
|
|
||||||
for (var i= 0, n= this.length; i<n; i++)
|
|
||||||
if (i in this)
|
|
||||||
other[i]= mapper.call(that, this[i], i, this);
|
|
||||||
return other;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (!('filter' in Array.prototype)) {
|
|
||||||
Array.prototype.filter= function(filter, that /*opt*/) {
|
|
||||||
var other= [], v;
|
|
||||||
for (var i=0, n= this.length; i<n; i++)
|
|
||||||
if (i in this && filter.call(that, v= this[i], i, this))
|
|
||||||
other.push(v);
|
|
||||||
return other;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (!('every' in Array.prototype)) {
|
|
||||||
Array.prototype.every= function(tester, that /*opt*/) {
|
|
||||||
for (var i= 0, n= this.length; i<n; i++)
|
|
||||||
if (i in this && !tester.call(that, this[i], i, this))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (!('some' in Array.prototype)) {
|
|
||||||
Array.prototype.some= function(tester, that /*opt*/) {
|
|
||||||
for (var i= 0, n= this.length; i<n; i++)
|
|
||||||
if (i in this && tester.call(that, this[i], i, this))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (!Node) {
|
|
||||||
// http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1841493061
|
|
||||||
var Node = {
|
|
||||||
'ELEMENT_NODE' : 1,
|
|
||||||
'ATTRIBUTE_NODE': 2,
|
|
||||||
'TEXT_NODE': 3,
|
|
||||||
'CDATA_SECTION_NODE': 4,
|
|
||||||
'ENTITY_REFERENCE_NODE': 5,
|
|
||||||
'ENTITY_NODE': 6,
|
|
||||||
'PROCESSING_INSTRUCTION_NODE': 7,
|
|
||||||
'COMMENT_NODE': 8,
|
|
||||||
'DOCUMENT_NODE': 9,
|
|
||||||
'DOCUMENT_TYPE_NODE': 10,
|
|
||||||
'DOCUMENT_FRAGMENT_NODE': 11,
|
|
||||||
'NOTATION_NODE': 12,
|
|
||||||
//The two nodes are disconnected. Order between disconnected nodes is always implementation-specific.
|
|
||||||
'DOCUMENT_POSITION_DISCONNECTED': 0x01,
|
|
||||||
//The second node precedes the reference node.
|
|
||||||
'DOCUMENT_POSITION_PRECEDING': 0x02,
|
|
||||||
//The node follows the reference node.
|
|
||||||
'DOCUMENT_POSITION_FOLLOWING': 0x04,
|
|
||||||
//The node contains the reference node. A node which contains is always preceding, too.
|
|
||||||
'DOCUMENT_POSITION_CONTAINS': 0x08,
|
|
||||||
//The node is contained by the reference node. A node which is contained is always following, too.
|
|
||||||
'DOCUMENT_POSITION_CONTAINED_BY': 0x10,
|
|
||||||
//The determination of preceding versus following is implementation-specific.
|
|
||||||
'DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC': 0x20
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-compareDocumentPosition
|
|
||||||
// FIXME: Check if the DOMNode prototype can be set.
|
|
||||||
window.compareDocumentPosition = function(node1, node2) {
|
|
||||||
|
|
||||||
if ('compareDocumentPosition' in document.documentElement ) {
|
|
||||||
return node1.compareDocumentPosition(node2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!("contains" in document.documentElement)) {
|
|
||||||
throw 'compareDocumentPosition nor contains is not supported by this browser.';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node1 == node2) return 0;
|
|
||||||
|
|
||||||
//if they don't have the same parent, there's a disconnect
|
|
||||||
if (getRootParent(node1) != getRootParent(node2)) return 1;
|
|
||||||
|
|
||||||
//use this if both nodes have a sourceIndex (text nodes don't)
|
|
||||||
if ("sourceIndex" in node1 && "sourceIndex" in node2) {
|
|
||||||
return comparePosition(node1, node2);
|
|
||||||
}
|
|
||||||
|
|
||||||
//document will definitely contain the other node
|
|
||||||
if (node1 == document) return 20;
|
|
||||||
else if (node2 == document) return 10;
|
|
||||||
|
|
||||||
//get sourceIndexes to use for both nodes
|
|
||||||
var useNode1 = getUseNode(node1), useNode2 = getUseNode(node2);
|
|
||||||
|
|
||||||
//call this function again to get the result
|
|
||||||
var result = comparePosition(useNode1, useNode2);
|
|
||||||
|
|
||||||
//clean up if needed
|
|
||||||
if (node1 != useNode1) useNode1.parentNode.removeChild(useNode1);
|
|
||||||
if (node2 != useNode2) useNode2.parentNode.removeChild(useNode2);
|
|
||||||
return result;
|
|
||||||
|
|
||||||
|
|
||||||
//node.ownerDocument gives the document object, which isn't the right info for a disconnect
|
|
||||||
function getRootParent(node) {
|
|
||||||
do { var parent = node; }
|
|
||||||
while (node = node.parentNode);
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Compare Position - MIT Licensed, John Resig; http://ejohn.org/blog/comparing-document-position/
|
|
||||||
//Already checked for equality and disconnect
|
|
||||||
function comparePosition(node1, node2) {
|
|
||||||
return (node1.contains(node2) && 16) +
|
|
||||||
(node2.contains(node1) && 8) +
|
|
||||||
(node1.sourceIndex >= 0 && node2.sourceIndex >= 0 ?
|
|
||||||
(node1.sourceIndex < node2.sourceIndex && 4) +
|
|
||||||
(node1.sourceIndex > node2.sourceIndex && 2) :
|
|
||||||
1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//get a node with a sourceIndex to use
|
|
||||||
function getUseNode(node) {
|
|
||||||
//if the node already has a sourceIndex, use that node
|
|
||||||
if ("sourceIndex" in node) return node;
|
|
||||||
//otherwise, insert a comment (which has a sourceIndex but minimal DOM impact) before the node and use that
|
|
||||||
return node.parentNode.insertBefore(document.createComment(""), node);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!('getComputedStyle' in window)) {
|
|
||||||
window.getComputedStyle = function (node, style) {
|
|
||||||
if( node.currentStyle ) {
|
|
||||||
return node.currentStyle;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,280 +0,0 @@
|
|||||||
|
|
||||||
define([],
|
|
||||||
function(){
|
|
||||||
|
|
||||||
var shims = {
|
|
||||||
// Function bind
|
|
||||||
bind: function(owner){
|
|
||||||
var obj = this.obj || this;
|
|
||||||
var native_method = Function.prototype.bind;
|
|
||||||
var args= Array.prototype.slice.call(arguments, 1);
|
|
||||||
|
|
||||||
if(native_method){
|
|
||||||
return native_method.apply(obj, arguments);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
return function() {
|
|
||||||
return obj.apply(owner, arguments.length===0? args : args.concat(Array.prototype.slice.call(arguments)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// String trim
|
|
||||||
trim: function(){
|
|
||||||
var obj = this.obj || this;
|
|
||||||
var native_method = String.prototype.trim;
|
|
||||||
|
|
||||||
if(native_method){
|
|
||||||
return native_method.call(obj);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return obj.replace(/^\s+/, '').replace(/\s+$/, '');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Array methods
|
|
||||||
indexOf: function(find, i /*opt*/){
|
|
||||||
var obj = this.obj || this;
|
|
||||||
var native_method = Array.prototype.indexOf;
|
|
||||||
|
|
||||||
if(native_method){
|
|
||||||
return native_method.call(obj, find, i);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (i===undefined) i= 0;
|
|
||||||
if (i<0) i+= obj.length;
|
|
||||||
if (i<0) i= 0;
|
|
||||||
for (var n = obj.length; i<n; i++)
|
|
||||||
if (i in obj && obj[i]===find)
|
|
||||||
return i;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
forEach: function(action, that /*opt*/){
|
|
||||||
var obj = this.obj || this;
|
|
||||||
var native_method = Array.prototype.forEach;
|
|
||||||
|
|
||||||
if(native_method){
|
|
||||||
return native_method.call(obj, action, that);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (var i= 0, n = obj.length; i<n; i++)
|
|
||||||
if (i in obj)
|
|
||||||
action.call(that, obj[i], i, obj);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
map: function(mapper, that /*opt*/, chain /*opt */){
|
|
||||||
var obj = this.obj || this;
|
|
||||||
var native_method = Array.prototype.map;
|
|
||||||
var returnWrapper = (typeof arguments[arguments.length - 1] == "boolean") ? Array.prototype.pop.call(arguments) : false;
|
|
||||||
var result = [];
|
|
||||||
|
|
||||||
if(native_method){
|
|
||||||
result = native_method.call(obj, mapper, that);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var other= new Array(obj.length);
|
|
||||||
for (var i= 0, n= obj.length; i<n; i++)
|
|
||||||
if (i in obj)
|
|
||||||
other[i]= mapper.call(that, obj[i], i, obj);
|
|
||||||
result = other;
|
|
||||||
}
|
|
||||||
|
|
||||||
return returnWrapper ? $_(result) : result;
|
|
||||||
},
|
|
||||||
|
|
||||||
filter: function(filterFunc, that /*opt*/, chain /*opt */){
|
|
||||||
var obj = this.obj || this;
|
|
||||||
var native_method = Array.prototype.filter;
|
|
||||||
var returnWrapper = (typeof arguments[arguments.length - 1] == "boolean") ? Array.prototype.pop.call(arguments) : false;
|
|
||||||
var result = [];
|
|
||||||
|
|
||||||
if(native_method){
|
|
||||||
result = native_method.call(obj, filterFunc, that);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var other= [], v;
|
|
||||||
for (var i=0, n= obj.length; i<n; i++)
|
|
||||||
if (i in obj && filterFunc.call(that, v= obj[i], i, obj))
|
|
||||||
other.push(v);
|
|
||||||
result = other;
|
|
||||||
}
|
|
||||||
|
|
||||||
return returnWrapper ? $_(result) : result;
|
|
||||||
},
|
|
||||||
|
|
||||||
every: function(tester, that /*opt*/) {
|
|
||||||
var obj = this.obj || this;
|
|
||||||
var native_method = Array.prototype.every;
|
|
||||||
|
|
||||||
if(native_method){
|
|
||||||
return native_method.call(obj, tester, that);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (var i= 0, n= obj.length; i<n; i++)
|
|
||||||
if (i in obj && !tester.call(that, obj[i], i, obj))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
some: function(tester, that /*opt*/){
|
|
||||||
var obj = this.obj || this;
|
|
||||||
var native_method = Array.prototype.some;
|
|
||||||
|
|
||||||
if(native_method){
|
|
||||||
return native_method.call(obj, tester, that);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (var i= 0, n= obj.length; i<n; i++)
|
|
||||||
if (i in obj && tester.call(that, obj[i], i, obj))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Since IE7 doesn't support 'hasAttribute' method on nodes
|
|
||||||
// TODO: raise an exception if the object is not an node
|
|
||||||
hasAttribute: function(attr){
|
|
||||||
var obj = this.obj || this;
|
|
||||||
var native_method = obj.hasAttribute;
|
|
||||||
|
|
||||||
if(native_method){
|
|
||||||
return obj.hasAttribute(attr);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return (typeof obj.attributes[attr] != "undefined")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
var $_ = function(obj) {
|
|
||||||
var wrapper = function() {};
|
|
||||||
wrapper.prototype = shims;
|
|
||||||
|
|
||||||
var wrapper_instance = new wrapper();
|
|
||||||
wrapper_instance.obj = obj;
|
|
||||||
return wrapper_instance;
|
|
||||||
};
|
|
||||||
|
|
||||||
for (var shim in shims) {
|
|
||||||
$_[shim] = shims[shim];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Node constants
|
|
||||||
// http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1841493061
|
|
||||||
if(typeof Node != 'undefined'){
|
|
||||||
$_.Node = Node;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$_.Node = {
|
|
||||||
'ELEMENT_NODE' : 1,
|
|
||||||
'ATTRIBUTE_NODE': 2,
|
|
||||||
'TEXT_NODE': 3,
|
|
||||||
'CDATA_SECTION_NODE': 4,
|
|
||||||
'ENTITY_REFERENCE_NODE': 5,
|
|
||||||
'ENTITY_NODE': 6,
|
|
||||||
'PROCESSING_INSTRUCTION_NODE': 7,
|
|
||||||
'COMMENT_NODE': 8,
|
|
||||||
'DOCUMENT_NODE': 9,
|
|
||||||
'DOCUMENT_TYPE_NODE': 10,
|
|
||||||
'DOCUMENT_FRAGMENT_NODE': 11,
|
|
||||||
'NOTATION_NODE': 12,
|
|
||||||
//The two nodes are disconnected. Order between disconnected nodes is always implementation-specific.
|
|
||||||
'DOCUMENT_POSITION_DISCONNECTED': 0x01,
|
|
||||||
//The second node precedes the reference node.
|
|
||||||
'DOCUMENT_POSITION_PRECEDING': 0x02,
|
|
||||||
//The node follows the reference node.
|
|
||||||
'DOCUMENT_POSITION_FOLLOWING': 0x04,
|
|
||||||
//The node contains the reference node. A node which contains is always preceding, too.
|
|
||||||
'DOCUMENT_POSITION_CONTAINS': 0x08,
|
|
||||||
//The node is contained by the reference node. A node which is contained is always following, too.
|
|
||||||
'DOCUMENT_POSITION_CONTAINED_BY': 0x10,
|
|
||||||
//The determination of preceding versus following is implementation-specific.
|
|
||||||
'DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC': 0x20
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-compareDocumentPosition
|
|
||||||
// FIXME: Check if the DOMNode prototype can be set.
|
|
||||||
$_.compareDocumentPosition = function(node1, node2) {
|
|
||||||
|
|
||||||
if ('compareDocumentPosition' in document.documentElement ) {
|
|
||||||
return node1.compareDocumentPosition(node2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!("contains" in document.documentElement)) {
|
|
||||||
throw 'compareDocumentPosition nor contains is not supported by this browser.';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node1 == node2) return 0;
|
|
||||||
|
|
||||||
//if they don't have the same parent, there's a disconnect
|
|
||||||
if (getRootParent(node1) != getRootParent(node2)) return 1;
|
|
||||||
|
|
||||||
//use this if both nodes have a sourceIndex (text nodes don't)
|
|
||||||
if ("sourceIndex" in node1 && "sourceIndex" in node2) {
|
|
||||||
return comparePosition(node1, node2);
|
|
||||||
}
|
|
||||||
|
|
||||||
//document will definitely contain the other node
|
|
||||||
if (node1 == document) return 20;
|
|
||||||
else if (node2 == document) return 10;
|
|
||||||
|
|
||||||
//get sourceIndexes to use for both nodes
|
|
||||||
var useNode1 = getUseNode(node1), useNode2 = getUseNode(node2);
|
|
||||||
|
|
||||||
//call this function again to get the result
|
|
||||||
var result = comparePosition(useNode1, useNode2);
|
|
||||||
|
|
||||||
//clean up if needed
|
|
||||||
if (node1 != useNode1) useNode1.parentNode.removeChild(useNode1);
|
|
||||||
if (node2 != useNode2) useNode2.parentNode.removeChild(useNode2);
|
|
||||||
return result;
|
|
||||||
|
|
||||||
|
|
||||||
//node.ownerDocument gives the document object, which isn't the right info for a disconnect
|
|
||||||
function getRootParent(node) {
|
|
||||||
do { var parent = node; }
|
|
||||||
while (node = node.parentNode);
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Compare Position - MIT Licensed, John Resig; http://ejohn.org/blog/comparing-document-position/
|
|
||||||
//Already checked for equality and disconnect
|
|
||||||
function comparePosition(node1, node2) {
|
|
||||||
return (node1.contains(node2) && 16) +
|
|
||||||
(node2.contains(node1) && 8) +
|
|
||||||
(node1.sourceIndex >= 0 && node2.sourceIndex >= 0 ?
|
|
||||||
(node1.sourceIndex < node2.sourceIndex && 4) +
|
|
||||||
(node1.sourceIndex > node2.sourceIndex && 2) :
|
|
||||||
1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//get a node with a sourceIndex to use
|
|
||||||
function getUseNode(node) {
|
|
||||||
//if the node already has a sourceIndex, use that node
|
|
||||||
if ("sourceIndex" in node) return node;
|
|
||||||
//otherwise, insert a comment (which has a sourceIndex but minimal DOM impact) before the node and use that
|
|
||||||
return node.parentNode.insertBefore(document.createComment(""), node);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$_.getComputedStyle = function(node, style){
|
|
||||||
if('getComputedStyle' in window) {
|
|
||||||
return window.getComputedStyle(node, style);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if( node.currentStyle ) {
|
|
||||||
return node.currentStyle;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return $_;
|
|
||||||
});
|
|
@ -1,878 +0,0 @@
|
|||||||
/*!
|
|
||||||
* This file is part of Aloha Editor Project http://aloha-editor.org
|
|
||||||
* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com
|
|
||||||
* Contributors http://aloha-editor.org/contribution.php
|
|
||||||
* Licensed unter the terms of http://www.aloha-editor.org/license.html
|
|
||||||
*
|
|
||||||
* Aloha Editor is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* ( at your option ) any later version.*
|
|
||||||
*
|
|
||||||
* Aloha Editor is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
define( [
|
|
||||||
'aloha/core',
|
|
||||||
'util/class',
|
|
||||||
'aloha/jquery',
|
|
||||||
'aloha/pluginmanager',
|
|
||||||
'aloha/floatingmenu',
|
|
||||||
'aloha/selection',
|
|
||||||
'aloha/markup',
|
|
||||||
'aloha/contenthandlermanager',
|
|
||||||
'aloha/console'
|
|
||||||
], function( Aloha, Class, jQuery, PluginManager, FloatingMenu, Selection,
|
|
||||||
Markup, ContentHandlerManager, console ) {
|
|
||||||
|
|
||||||
|
|
||||||
var unescape = window.unescape,
|
|
||||||
GENTICS = window.GENTICS,
|
|
||||||
|
|
||||||
// True, if the next editable activate event should not be handled
|
|
||||||
ignoreNextActivateEvent = false;
|
|
||||||
|
|
||||||
// default supported and custom content handler settings
|
|
||||||
// @TODO move to new config when implemented in Aloha
|
|
||||||
Aloha.defaults.contentHandler = {};
|
|
||||||
Aloha.defaults.contentHandler.initEditable = [ 'sanitize' ];
|
|
||||||
Aloha.defaults.contentHandler.getContents = [ 'sanitize' ];
|
|
||||||
|
|
||||||
// The insertHtml contenthandler ( paste ) will, by default, use all
|
|
||||||
// registered content handlers.
|
|
||||||
//Aloha.defaults.contentHandler.insertHtml = void 0;
|
|
||||||
|
|
||||||
if ( typeof Aloha.settings.contentHandler === 'undefined' ) {
|
|
||||||
Aloha.settings.contentHandler = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
var defaultContentSerializer = function(editableElement){
|
|
||||||
return jQuery(editableElement).html();
|
|
||||||
};
|
|
||||||
|
|
||||||
var contentSerializer = defaultContentSerializer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Editable object
|
|
||||||
* @namespace Aloha
|
|
||||||
* @class Editable
|
|
||||||
* @method
|
|
||||||
* @constructor
|
|
||||||
* @param {Object} obj jQuery object reference to the object
|
|
||||||
*/
|
|
||||||
Aloha.Editable = Class.extend( {
|
|
||||||
|
|
||||||
_constructor: function( obj ) {
|
|
||||||
// check wheter the object has an ID otherwise generate and set
|
|
||||||
// globally unique ID
|
|
||||||
if ( !obj.attr( 'id' ) ) {
|
|
||||||
obj.attr( 'id', GENTICS.Utils.guid() );
|
|
||||||
}
|
|
||||||
|
|
||||||
// store object reference
|
|
||||||
this.obj = obj;
|
|
||||||
this.originalObj = obj;
|
|
||||||
this.ready = false;
|
|
||||||
|
|
||||||
// delimiters, timer and idle for smartContentChange
|
|
||||||
// smartContentChange triggers -- tab: '\u0009' - space: '\u0020' - enter: 'Enter'
|
|
||||||
this.sccDelimiters = [ ':', ';', '.', '!', '?', ',',
|
|
||||||
unescape( '%u0009' ), unescape( '%u0020' ), 'Enter' ];
|
|
||||||
this.sccIdle = 5000;
|
|
||||||
this.sccDelay = 500;
|
|
||||||
this.sccTimerIdle = false;
|
|
||||||
this.sccTimerDelay = false;
|
|
||||||
|
|
||||||
// see keyset http://www.w3.org/TR/2007/WD-DOM-Level-3-Events-20071221/keyset.html
|
|
||||||
this.keyCodeMap = {
|
|
||||||
93 : "Apps", // The Application key
|
|
||||||
18 : "Alt", // The Alt ( Menu ) key.
|
|
||||||
20 : "CapsLock", // The Caps Lock ( Capital ) key.
|
|
||||||
17 : "Control", // The Control ( Ctrl ) key.
|
|
||||||
40 : "Down", // The Down Arrow key.
|
|
||||||
35 : "End", // The End key.
|
|
||||||
13 : "Enter", // The Enter key.
|
|
||||||
112 : "F1", // The F1 key.
|
|
||||||
113 : "F2", // The F2 key.
|
|
||||||
114 : "F3", // The F3 key.
|
|
||||||
115 : "F4", // The F4 key.
|
|
||||||
116 : "F5", // The F5 key.
|
|
||||||
117 : "F6", // The F6 key.
|
|
||||||
118 : "F7", // The F7 key.
|
|
||||||
119 : "F8", // The F8 key.
|
|
||||||
120 : "F9", // The F9 key.
|
|
||||||
121 : "F10", // The F10 key.
|
|
||||||
122 : "F11", // The F11 key.
|
|
||||||
123 : "F12", // The F12 key.
|
|
||||||
|
|
||||||
// Anybody knows the keycode for F13-F24?
|
|
||||||
36 : "Home", // The Home key.
|
|
||||||
45 : "Insert", // The Insert ( Ins ) key.
|
|
||||||
37 : "Left", // The Left Arrow key.
|
|
||||||
224 : "Meta", // The Meta key.
|
|
||||||
34 : "PageDown", // The Page Down ( Next ) key.
|
|
||||||
33 : "PageUp", // The Page Up key.
|
|
||||||
19 : "Pause", // The Pause key.
|
|
||||||
44 : "PrintScreen", // The Print Screen ( PrintScrn, SnapShot ) key.
|
|
||||||
39 : "Right", // The Right Arrow key.
|
|
||||||
145 : "Scroll", // The scroll lock key
|
|
||||||
16 : "Shift", // The Shift key.
|
|
||||||
38 : "Up", // The Up Arrow key.
|
|
||||||
91 : "Win", // The left Windows Logo key.
|
|
||||||
92 : "Win" // The right Windows Logo key.
|
|
||||||
};
|
|
||||||
|
|
||||||
this.placeholderClass = 'aloha-placeholder';
|
|
||||||
|
|
||||||
Aloha.registerEditable( this );
|
|
||||||
|
|
||||||
this.init();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the editable
|
|
||||||
* @return void
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
init: function() {
|
|
||||||
var me = this;
|
|
||||||
|
|
||||||
// TODO make editables their own settings.
|
|
||||||
this.settings = Aloha.settings;
|
|
||||||
|
|
||||||
// smartContentChange settings
|
|
||||||
// @TODO move to new config when implemented in Aloha
|
|
||||||
if ( Aloha.settings && Aloha.settings.smartContentChange ) {
|
|
||||||
if ( Aloha.settings.smartContentChange.delimiters ) {
|
|
||||||
this.sccDelimiters = Aloha.settings.smartContentChange.delimiters;
|
|
||||||
} /* else {
|
|
||||||
this.sccDelimiters = this.sccDelimiters;
|
|
||||||
} */
|
|
||||||
|
|
||||||
if ( Aloha.settings.smartContentChange.idle ) {
|
|
||||||
this.sccIdle = Aloha.settings.smartContentChange.idle;
|
|
||||||
} /* else {
|
|
||||||
this.sccIdle = this.sccIdle;
|
|
||||||
} */
|
|
||||||
|
|
||||||
if ( Aloha.settings.smartContentChange.delay ) {
|
|
||||||
this.sccDelay = Aloha.settings.smartContentChange.delay;
|
|
||||||
} /* else {
|
|
||||||
this.sccDelay = this.sccDelay;
|
|
||||||
} */
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if Aloha can handle the obj as Editable
|
|
||||||
if ( !this.check( this.obj ) ) {
|
|
||||||
//Aloha.log( 'warn', this, 'Aloha cannot handle {' + this.obj[0].nodeName + '}' );
|
|
||||||
this.destroy();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply content handler to clean up content
|
|
||||||
var content = me.obj.html();
|
|
||||||
if ( typeof Aloha.settings.contentHandler.initEditable === 'undefined' ) {
|
|
||||||
Aloha.settings.contentHandler.initEditable = Aloha.defaults.contentHandler.initEditable;
|
|
||||||
}
|
|
||||||
content = ContentHandlerManager.handleContent( content, {
|
|
||||||
contenthandler: Aloha.settings.contentHandler.initEditable
|
|
||||||
} );
|
|
||||||
me.obj.html( content );
|
|
||||||
|
|
||||||
// only initialize the editable when Aloha is fully ready ( including plugins )
|
|
||||||
Aloha.bind( 'aloha-ready', function() {
|
|
||||||
// initialize the object
|
|
||||||
me.obj.addClass( 'aloha-editable' ).contentEditable( true );
|
|
||||||
|
|
||||||
// add focus event to the object to activate
|
|
||||||
me.obj.mousedown( function( e ) {
|
|
||||||
// check whether the mousedown was already handled
|
|
||||||
if ( !Aloha.eventHandled ) {
|
|
||||||
Aloha.eventHandled = true;
|
|
||||||
return me.activate( e );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
me.obj.mouseup( function( e ) {
|
|
||||||
Aloha.eventHandled = false;
|
|
||||||
} );
|
|
||||||
|
|
||||||
me.obj.focus( function( e ) {
|
|
||||||
return me.activate( e );
|
|
||||||
} );
|
|
||||||
|
|
||||||
// by catching the keydown we can prevent the browser from doing its own thing
|
|
||||||
// if it does not handle the keyStroke it returns true and therefore all other
|
|
||||||
// events ( incl. browser's ) continue
|
|
||||||
me.obj.keydown( function( event ) {
|
|
||||||
me.keyCode = event.which;
|
|
||||||
return Markup.preProcessKeyStrokes( event );
|
|
||||||
} );
|
|
||||||
|
|
||||||
// handle keypress
|
|
||||||
me.obj.keypress( function( event ) {
|
|
||||||
// triggers a smartContentChange to get the right charcode
|
|
||||||
// To test try http://www.w3.org/2002/09/tests/keys.html
|
|
||||||
Aloha.activeEditable.smartContentChange( event );
|
|
||||||
} );
|
|
||||||
|
|
||||||
// handle shortcut keys
|
|
||||||
me.obj.keyup( function( event ) {
|
|
||||||
if ( event.keyCode === 27 ) {
|
|
||||||
Aloha.deactivateEditable();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
// register the onSelectionChange Event with the Editable field
|
|
||||||
me.obj.contentEditableSelectionChange( function( event ) {
|
|
||||||
Selection.onChange( me.obj, event );
|
|
||||||
return me.obj;
|
|
||||||
} );
|
|
||||||
|
|
||||||
// mark the editable as unmodified
|
|
||||||
me.setUnmodified();
|
|
||||||
|
|
||||||
// we don't do the sanitizing on aloha ready, since some plugins add elements into the content and bind events to it.
|
|
||||||
// if we sanitize by replacing the html, all events would get lost. TODO: think about a better solution for the sanitizing, without
|
|
||||||
// destroying the events
|
|
||||||
// // apply content handler to clean up content
|
|
||||||
// var content = me.obj.html();
|
|
||||||
// if ( typeof Aloha.settings.contentHandler.initEditable === 'undefined' ) {
|
|
||||||
// Aloha.settings.contentHandler.initEditable = Aloha.defaults.contentHandler.initEditable;
|
|
||||||
// }
|
|
||||||
// content = ContentHandlerManager.handleContent( content, {
|
|
||||||
// contenthandler: Aloha.settings.contentHandler.initEditable
|
|
||||||
// } );
|
|
||||||
// me.obj.html( content );
|
|
||||||
|
|
||||||
me.snapshotContent = me.getContents();
|
|
||||||
|
|
||||||
// FF bug: check for empty editable contents ( no <br>; no whitespace )
|
|
||||||
if ( jQuery.browser.mozilla ) {
|
|
||||||
me.initEmptyEditable();
|
|
||||||
}
|
|
||||||
|
|
||||||
me.initPlaceholder();
|
|
||||||
|
|
||||||
me.ready = true;
|
|
||||||
|
|
||||||
// throw a new event when the editable has been created
|
|
||||||
/**
|
|
||||||
* @event editableCreated fires after a new editable has been created, eg. via $( '#editme' ).aloha()
|
|
||||||
* The event is triggered in Aloha's global scope Aloha
|
|
||||||
* @param {Event} e the event object
|
|
||||||
* @param {Array} a an array which contains a reference to the currently created editable on its first position
|
|
||||||
*/
|
|
||||||
Aloha.trigger( 'aloha-editable-created', [ me ] );
|
|
||||||
} );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* True, if this editable is active for editing
|
|
||||||
* @property
|
|
||||||
* @type boolean
|
|
||||||
*/
|
|
||||||
isActive: false,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* stores the original content to determine if it has been modified
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
originalContent: null,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* every time a selection is made in the current editable the selection has to
|
|
||||||
* be saved for further use
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
range: undefined,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if object can be edited by Aloha Editor
|
|
||||||
* @return {boolean } editable true if Aloha Editor can handle else false
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
check: function() {
|
|
||||||
/* TODO check those elements
|
|
||||||
'map', 'meter', 'object', 'output', 'progress', 'samp',
|
|
||||||
'time', 'area', 'datalist', 'figure', 'kbd', 'keygen',
|
|
||||||
'mark', 'math', 'wbr', 'area',
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Extract El
|
|
||||||
var me = this,
|
|
||||||
obj = this.obj,
|
|
||||||
el = obj.get( 0 ),
|
|
||||||
nodeName = el.nodeName.toLowerCase(),
|
|
||||||
|
|
||||||
// supported elements
|
|
||||||
textElements = [ 'a', 'abbr', 'address', 'article', 'aside',
|
|
||||||
'b', 'bdo', 'blockquote', 'cite', 'code', 'command',
|
|
||||||
'del', 'details', 'dfn', 'div', 'dl', 'em', 'footer',
|
|
||||||
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'i',
|
|
||||||
'ins', 'menu', 'nav', 'p', 'pre', 'q', 'ruby',
|
|
||||||
'section', 'small', 'span', 'strong', 'sub', 'sup',
|
|
||||||
'var' ],
|
|
||||||
i, div;
|
|
||||||
|
|
||||||
for ( i = 0; i < textElements.length; i++ ) {
|
|
||||||
if ( nodeName === textElements[ i ] ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// special handled elements
|
|
||||||
switch ( nodeName ) {
|
|
||||||
case 'label':
|
|
||||||
case 'button':
|
|
||||||
// TODO need some special handling.
|
|
||||||
break;
|
|
||||||
case 'textarea':
|
|
||||||
// Create a div alongside the textarea
|
|
||||||
div = jQuery( '<div id="' + this.getId() +
|
|
||||||
'-aloha" class="aloha-textarea" />' )
|
|
||||||
.insertAfter( obj );
|
|
||||||
|
|
||||||
// Resize the div to the textarea and
|
|
||||||
// Populate the div with the value of the textarea
|
|
||||||
// Then, hide the textarea
|
|
||||||
div.height( obj.height() )
|
|
||||||
.width( obj.width() )
|
|
||||||
.html( obj.val() );
|
|
||||||
|
|
||||||
obj.hide();
|
|
||||||
|
|
||||||
// Attach a onsubmit to the form to place the HTML of the
|
|
||||||
// div back into the textarea
|
|
||||||
obj.parents( 'form:first' ).submit( function() {
|
|
||||||
obj.val( me.getContents() );
|
|
||||||
} );
|
|
||||||
|
|
||||||
// Swap textarea reference with the new div
|
|
||||||
this.obj = div;
|
|
||||||
|
|
||||||
// Supported
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the following elements are not supported
|
|
||||||
/*
|
|
||||||
'canvas', 'audio', 'br', 'embed', 'fieldset', 'hgroup', 'hr',
|
|
||||||
'iframe', 'img', 'input', 'map', 'script', 'select', 'style',
|
|
||||||
'svg', 'table', 'ul', 'video', 'ol', 'form', 'noscript',
|
|
||||||
*/
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Init Placeholder
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
initPlaceholder: function() {
|
|
||||||
if ( Aloha.settings.placeholder && this.isEmpty() ) {
|
|
||||||
this.addPlaceholder();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the conteneditable is empty.
|
|
||||||
*
|
|
||||||
* @return {Boolean}
|
|
||||||
*/
|
|
||||||
isEmpty: function() {
|
|
||||||
var editableTrimedContent = jQuery.trim( this.getContents() ),
|
|
||||||
onlyBrTag = ( editableTrimedContent === '<br>' ) ? true : false;
|
|
||||||
return ( editableTrimedContent.length === 0 || onlyBrTag );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the editable div is not empty. Fixes a FF browser bug
|
|
||||||
* see issue: https://github.com/alohaeditor/Aloha-Editor/issues/269
|
|
||||||
*
|
|
||||||
* @return {undefined}
|
|
||||||
*/
|
|
||||||
initEmptyEditable: function( ) {
|
|
||||||
var obj = this.obj;
|
|
||||||
if ( this.empty( this.getContents() ) ) {
|
|
||||||
jQuery( obj ).prepend( '<br class="aloha-cleanme" />' );
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add placeholder in editable
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
addPlaceholder: function() {
|
|
||||||
var div = jQuery( '<div>' ),
|
|
||||||
span = jQuery( '<span>' ),
|
|
||||||
el,
|
|
||||||
obj = this.obj;
|
|
||||||
|
|
||||||
if ( GENTICS.Utils.Dom.allowsNesting( obj[0], div[0] ) ) {
|
|
||||||
el = div;
|
|
||||||
} else {
|
|
||||||
el = span;
|
|
||||||
}
|
|
||||||
|
|
||||||
jQuery( obj ).append( el.addClass( this.placeholderClass ) );
|
|
||||||
jQuery.each(
|
|
||||||
Aloha.settings.placeholder,
|
|
||||||
function( selector, selectorConfig ) {
|
|
||||||
if ( obj.is( selector ) ) {
|
|
||||||
el.html( selectorConfig );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// remove browser br
|
|
||||||
jQuery( 'br', obj ).remove();
|
|
||||||
|
|
||||||
// delete div, span, el;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* remove placeholder from contenteditable. If setCursor is true,
|
|
||||||
* will also set the cursor to the start of the selection. However,
|
|
||||||
* this will be ASYNCHRONOUS, so if you rely on the fact that
|
|
||||||
* the placeholder is removed after calling this method, setCursor
|
|
||||||
* should be false ( or not set )
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
removePlaceholder: function( obj, setCursor ) {
|
|
||||||
var placeholderClass = this.placeholderClass,
|
|
||||||
range;
|
|
||||||
|
|
||||||
// // remove browser br
|
|
||||||
// jQuery( 'br', obj ).remove();
|
|
||||||
|
|
||||||
// set the cursor // remove placeholder
|
|
||||||
if ( setCursor === true ) {
|
|
||||||
range = Selection.getRangeObject();
|
|
||||||
if ( !range.select ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
range.startContainer = range.endContainer = obj.get( 0 );
|
|
||||||
range.startOffset = range.endOffset = 0;
|
|
||||||
range.select();
|
|
||||||
|
|
||||||
window.setTimeout( function() {
|
|
||||||
jQuery( '.' + placeholderClass, obj ).remove();
|
|
||||||
}, 20 );
|
|
||||||
|
|
||||||
} else {
|
|
||||||
jQuery( '.' + placeholderClass, obj ).remove();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* destroy the editable
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
destroy: function() {
|
|
||||||
// leave the element just to get sure
|
|
||||||
if ( this === Aloha.getActiveEditable() ) {
|
|
||||||
this.blur();
|
|
||||||
|
|
||||||
// also hide the floating menu if the current editable was active
|
|
||||||
FloatingMenu.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
// special handled elements
|
|
||||||
switch ( this.originalObj.get( 0 ).nodeName.toLowerCase() ) {
|
|
||||||
case 'label':
|
|
||||||
case 'button':
|
|
||||||
// TODO need some special handling.
|
|
||||||
break;
|
|
||||||
case 'textarea':
|
|
||||||
// restore content to original textarea
|
|
||||||
this.originalObj.val( this.getContents() );
|
|
||||||
this.obj.remove();
|
|
||||||
this.originalObj.show();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// now the editable is not ready any more
|
|
||||||
this.ready = false;
|
|
||||||
|
|
||||||
// remove the placeholder if needed.
|
|
||||||
this.removePlaceholder( this.obj );
|
|
||||||
|
|
||||||
// initialize the object and disable contentEditable
|
|
||||||
// unbind all events
|
|
||||||
// TODO should only unbind the specific handlers.
|
|
||||||
this.obj.removeClass( 'aloha-editable' )
|
|
||||||
.contentEditable( false )
|
|
||||||
.unbind( 'mousedown click dblclick focus keydown keypress keyup' );
|
|
||||||
|
|
||||||
/* TODO remove this event, it should implemented as bind and unbind
|
|
||||||
// register the onSelectionChange Event with the Editable field
|
|
||||||
this.obj.contentEditableSelectionChange( function( event ) {
|
|
||||||
Aloha.Selection.onChange( me.obj, event );
|
|
||||||
return me.obj;
|
|
||||||
} );
|
|
||||||
*/
|
|
||||||
|
|
||||||
// throw a new event when the editable has been created
|
|
||||||
/**
|
|
||||||
* @event editableCreated fires after a new editable has been destroyes, eg. via $( '#editme' ).mahalo()
|
|
||||||
* The event is triggered in Aloha's global scope Aloha
|
|
||||||
* @param {Event} e the event object
|
|
||||||
* @param {Array} a an array which contains a reference to the currently created editable on its first position
|
|
||||||
*/
|
|
||||||
Aloha.trigger( 'aloha-editable-destroyed', [ this ] );
|
|
||||||
|
|
||||||
// finally register the editable with Aloha
|
|
||||||
Aloha.unregisterEditable( this );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* marks the editables current state as unmodified. Use this method to inform the editable
|
|
||||||
* that it's contents have been saved
|
|
||||||
* @method
|
|
||||||
*/
|
|
||||||
setUnmodified: function() {
|
|
||||||
this.originalContent = this.getContents();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* check if the editable has been modified during the edit process#
|
|
||||||
* @method
|
|
||||||
* @return boolean true if the editable has been modified, false otherwise
|
|
||||||
*/
|
|
||||||
isModified: function() {
|
|
||||||
return this.originalContent !== this.getContents();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* String representation of the object
|
|
||||||
* @method
|
|
||||||
* @return Aloha.Editable
|
|
||||||
*/
|
|
||||||
toString: function() {
|
|
||||||
return 'Aloha.Editable';
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* check whether the editable has been disabled
|
|
||||||
*/
|
|
||||||
isDisabled: function() {
|
|
||||||
return !this.obj.contentEditable()
|
|
||||||
|| this.obj.contentEditable() === 'false';
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* disable this editable
|
|
||||||
* a disabled editable cannot be written on by keyboard
|
|
||||||
*/
|
|
||||||
disable: function() {
|
|
||||||
return this.isDisabled() || this.obj.contentEditable( false );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* enable this editable
|
|
||||||
* reenables a disabled editable to be writteable again
|
|
||||||
*/
|
|
||||||
enable: function() {
|
|
||||||
return this.isDisabled() && this.obj.contentEditable( true );
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* activates an Editable for editing
|
|
||||||
* disables all other active items
|
|
||||||
* @method
|
|
||||||
*/
|
|
||||||
activate: function( e ) {
|
|
||||||
// get active Editable before setting the new one.
|
|
||||||
var oldActive = Aloha.getActiveEditable();
|
|
||||||
|
|
||||||
// We need to ommit this call when this flag is set to true.
|
|
||||||
// This flag will only be set to true before the removePlaceholder method
|
|
||||||
// is called since that method invokes a focus event which will again trigger
|
|
||||||
// this method. We want to avoid double invokation of this method.
|
|
||||||
if ( ignoreNextActivateEvent ) {
|
|
||||||
ignoreNextActivateEvent = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle special case in which a nested editable is focused by a click
|
|
||||||
// in this case the "focus" event would be triggered on the parent element
|
|
||||||
// which actually shifts the focus away to it's parent. this if is here to
|
|
||||||
// prevent this situation
|
|
||||||
if ( e && e.type === 'focus' && oldActive !== null
|
|
||||||
&& oldActive.obj.parent().get( 0 ) === e.currentTarget ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// leave immediately if this is already the active editable
|
|
||||||
if ( this.isActive || this.isDisabled() ) {
|
|
||||||
// we don't want parent editables to be triggered as well, so return false
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.obj.addClass( 'aloha-editable-active' );
|
|
||||||
|
|
||||||
Aloha.activateEditable( this );
|
|
||||||
|
|
||||||
ignoreNextActivateEvent = true;
|
|
||||||
this.removePlaceholder ( this.obj, true );
|
|
||||||
ignoreNextActivateEvent = false;
|
|
||||||
|
|
||||||
this.isActive = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @event editableActivated fires after the editable has been activated by clicking on it.
|
|
||||||
* This event is triggered in Aloha's global scope Aloha
|
|
||||||
* @param {Event} e the event object
|
|
||||||
* @param {Array} a an array which contains a reference to last active editable on its first position, as well
|
|
||||||
* as the currently active editable on it's second position
|
|
||||||
*/
|
|
||||||
// trigger a 'general' editableActivated event
|
|
||||||
Aloha.trigger( 'aloha-editable-activated', {
|
|
||||||
'oldActive' : oldActive,
|
|
||||||
'editable' : this
|
|
||||||
} );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* handle the blur event
|
|
||||||
* this must not be attached to the blur event, which will trigger far too often
|
|
||||||
* eg. when a table within an editable is selected
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
blur: function() {
|
|
||||||
this.obj.blur();
|
|
||||||
this.isActive = false;
|
|
||||||
this.initPlaceholder();
|
|
||||||
this.obj.removeClass( 'aloha-editable-active' );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @event editableDeactivated fires after the editable has been activated by clicking on it.
|
|
||||||
* This event is triggered in Aloha's global scope Aloha
|
|
||||||
* @param {Event} e the event object
|
|
||||||
* @param {Array} a an array which contains a reference to this editable
|
|
||||||
*/
|
|
||||||
Aloha.trigger( 'aloha-editable-deactivated', { editable : this } );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @event smartContentChanged
|
|
||||||
*/
|
|
||||||
Aloha.activeEditable.smartContentChange( { type : 'blur' }, null );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* check if the string is empty
|
|
||||||
* used for zerowidth check
|
|
||||||
* @return true if empty or string is null, false otherwise
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
empty: function( str ) {
|
|
||||||
// br is needed for chrome
|
|
||||||
return ( null === str )
|
|
||||||
|| ( jQuery.trim( str ) === '' || str === '<br/>' );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the contents of this editable as a HTML string
|
|
||||||
* @method
|
|
||||||
* @return contents of the editable
|
|
||||||
*/
|
|
||||||
getContents: function( asObject ) {
|
|
||||||
var clonedObj = this.obj.clone( false );
|
|
||||||
|
|
||||||
// do core cleanup
|
|
||||||
clonedObj.find( '.aloha-cleanme' ).remove();
|
|
||||||
this.removePlaceholder( clonedObj );
|
|
||||||
PluginManager.makeClean( clonedObj );
|
|
||||||
|
|
||||||
return asObject ? clonedObj.contents() : contentSerializer(clonedObj[0]);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the id of this editable
|
|
||||||
* @method
|
|
||||||
* @return id of this editable
|
|
||||||
*/
|
|
||||||
getId: function() {
|
|
||||||
return this.obj.attr( 'id' );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates and signals a smartContentChange event.
|
|
||||||
*
|
|
||||||
* A smart content change occurs when a special editing action, or a
|
|
||||||
* combination of interactions are performed by the user during the
|
|
||||||
* course of editing within an editable.
|
|
||||||
* The smart content change event would therefore signal to any
|
|
||||||
* component that is listening to this event, that content has been
|
|
||||||
* inserted into the editable that may need to be prococessed in a
|
|
||||||
* special way
|
|
||||||
* This is used for smart actions within the content/while editing.
|
|
||||||
* @param {Event} event
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
smartContentChange: function( event ) {
|
|
||||||
var me = this,
|
|
||||||
uniChar = null,
|
|
||||||
re,
|
|
||||||
match;
|
|
||||||
|
|
||||||
// ignore meta keys like crtl+v or crtl+l and so on
|
|
||||||
if ( event && ( event.metaKey || event.crtlKey || event.altKey ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( event && event.originalEvent ) {
|
|
||||||
// regex to strip unicode
|
|
||||||
re = new RegExp( "U\\+(\\w{4})" );
|
|
||||||
match = re.exec( event.originalEvent.keyIdentifier );
|
|
||||||
|
|
||||||
// Use keyIdentifier if available
|
|
||||||
if ( event.originalEvent.keyIdentifier && 1 === 2 ) {
|
|
||||||
// @fixme: Because of "&& 1 === 2" above, all the below is
|
|
||||||
// unreachable code
|
|
||||||
if ( match !== null ) {
|
|
||||||
uniChar = unescape( '%u' + match[1] );
|
|
||||||
}
|
|
||||||
if ( uniChar === null ) {
|
|
||||||
uniChar = event.originalEvent.keyIdentifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FF & Opera don't support keyIdentifier
|
|
||||||
} else {
|
|
||||||
// Use among browsers reliable which http://api.jquery.com/keypress
|
|
||||||
uniChar = ( this.keyCodeMap[ this.keyCode ] ||
|
|
||||||
String.fromCharCode( event.which ) || 'unknown' );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle "Enter" -- it's not "U+1234" -- when returned via "event.originalEvent.keyIdentifier"
|
|
||||||
// reference: http://www.w3.org/TR/2007/WD-DOM-Level-3-Events-20071221/keyset.html
|
|
||||||
if ( jQuery.inArray( uniChar, this.sccDelimiters ) >= 0 ) {
|
|
||||||
clearTimeout( this.sccTimerIdle );
|
|
||||||
clearTimeout( this.sccTimerDelay );
|
|
||||||
|
|
||||||
this.sccTimerDelay = setTimeout( function() {
|
|
||||||
Aloha.trigger( 'aloha-smart-content-changed', {
|
|
||||||
'editable' : me,
|
|
||||||
'keyIdentifier' : event.originalEvent.keyIdentifier,
|
|
||||||
'keyCode' : event.keyCode,
|
|
||||||
'char' : uniChar,
|
|
||||||
'triggerType' : 'keypress', // keypress, timer, blur, paste
|
|
||||||
'snapshotContent' : me.getSnapshotContent()
|
|
||||||
} );
|
|
||||||
|
|
||||||
console.debug( 'Aloha.Editable',
|
|
||||||
'smartContentChanged: event type keypress triggered' );
|
|
||||||
/*
|
|
||||||
var r = Aloha.Selection.rangeObject;
|
|
||||||
if ( r.isCollapsed()
|
|
||||||
&& r.startContainer.nodeType == 3 ) {
|
|
||||||
|
|
||||||
var posDummy = jQuery( '<span id="GENTICS-Aloha-PosDummy" />' );
|
|
||||||
|
|
||||||
GENTICS.Utils.Dom.insertIntoDOM(
|
|
||||||
posDummy,
|
|
||||||
r,
|
|
||||||
this.obj,
|
|
||||||
null,
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log( posDummy.offset().top, posDummy.offset().left );
|
|
||||||
|
|
||||||
GENTICS.Utils.Dom.removeFromDOM(
|
|
||||||
posDummy,
|
|
||||||
r,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
r.select();
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}, this.sccDelay );
|
|
||||||
|
|
||||||
} else if ( event && event.type === 'paste' ) {
|
|
||||||
Aloha.trigger( 'aloha-smart-content-changed', {
|
|
||||||
'editable' : me,
|
|
||||||
'keyIdentifier' : null,
|
|
||||||
'keyCode' : null,
|
|
||||||
'char' : null,
|
|
||||||
'triggerType' : 'paste',
|
|
||||||
'snapshotContent' : me.getSnapshotContent()
|
|
||||||
} );
|
|
||||||
|
|
||||||
} else if ( event && event.type === 'blur' ) {
|
|
||||||
Aloha.trigger( 'aloha-smart-content-changed', {
|
|
||||||
'editable' : me,
|
|
||||||
'keyIdentifier' : null,
|
|
||||||
'keyCode' : null,
|
|
||||||
'char' : null,
|
|
||||||
'triggerType' : 'blur',
|
|
||||||
'snapshotContent' : me.getSnapshotContent()
|
|
||||||
} );
|
|
||||||
|
|
||||||
} else if ( uniChar !== null ) {
|
|
||||||
// in the rare case idle time is lower then delay time
|
|
||||||
clearTimeout( this.sccTimerDelay );
|
|
||||||
clearTimeout( this.sccTimerIdle );
|
|
||||||
this.sccTimerIdle = setTimeout( function() {
|
|
||||||
Aloha.trigger( 'aloha-smart-content-changed', {
|
|
||||||
'editable' : me,
|
|
||||||
'keyIdentifier' : null,
|
|
||||||
'keyCode' : null,
|
|
||||||
'char' : null,
|
|
||||||
'triggerType' : 'idle',
|
|
||||||
'snapshotContent' : me.getSnapshotContent()
|
|
||||||
} );
|
|
||||||
}, this.sccIdle );
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a snapshot of the active editable as a HTML string
|
|
||||||
* @hide
|
|
||||||
* @return snapshot of the editable
|
|
||||||
*/
|
|
||||||
getSnapshotContent: function() {
|
|
||||||
var ret = this.snapshotContent;
|
|
||||||
this.snapshotContent = this.getContents();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the serializer function to be used for the contents of all editables.
|
|
||||||
*
|
|
||||||
* The default content serializer will just call the jQuery.html()
|
|
||||||
* function on the editable element (which gets the innerHTML property).
|
|
||||||
*
|
|
||||||
* This method is a static class method and will affect the result
|
|
||||||
* of editable.getContents() for all editables that have been or
|
|
||||||
* will be constructed.
|
|
||||||
*
|
|
||||||
* @param serializerFunction
|
|
||||||
* A function that accepts a DOM element and returns the serialized
|
|
||||||
* XHTML of the element contents (excluding the start and end tag of
|
|
||||||
* the passed element).
|
|
||||||
*/
|
|
||||||
Aloha.Editable.setContentSerializer = function( serializerFunction ) {
|
|
||||||
contentSerializer = serializerFunction;
|
|
||||||
};
|
|
||||||
} );
|
|
@ -1,86 +0,0 @@
|
|||||||
/*!
|
|
||||||
* This file is part of Aloha Editor Project http://aloha-editor.org
|
|
||||||
* Copyright <EFBFBD> 2010-2011 Gentics Software GmbH, aloha@gentics.com
|
|
||||||
* Contributors http://aloha-editor.org/contribution.php
|
|
||||||
* Licensed unter the terms of http://www.aloha-editor.org/license.html
|
|
||||||
*//*
|
|
||||||
* Aloha Editor is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.*
|
|
||||||
*
|
|
||||||
* Aloha Editor is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
define( [
|
|
||||||
'aloha/jquery',
|
|
||||||
'aloha/ext',
|
|
||||||
'aloha/repositorymanager',
|
|
||||||
'aloha/console',
|
|
||||||
'i18n!aloha/nls/i18n'
|
|
||||||
], function ( jQuery, Ext, RepositoryManager, console ) {
|
|
||||||
|
|
||||||
|
|
||||||
Ext.data.AlohaProxy = function () {
|
|
||||||
// Must define a dummy api with "read" action to satisfy
|
|
||||||
// Ext.data.Api#prepare *before* calling super
|
|
||||||
var api = {};
|
|
||||||
api[ Ext.data.Api.actions.read ] = true;
|
|
||||||
Ext.data.AlohaProxy.superclass.constructor.call( this, { api: api } );
|
|
||||||
|
|
||||||
this.params = {
|
|
||||||
queryString : null,
|
|
||||||
objectTypeFilter : null,
|
|
||||||
filter : null,
|
|
||||||
inFolderId : null,
|
|
||||||
orderBy : null,
|
|
||||||
maxItems : null,
|
|
||||||
skipCount : null,
|
|
||||||
renditionFilter : null,
|
|
||||||
repositoryId : null
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
var i18n = Aloha.require( 'i18n!aloha/nls/i18n' );
|
|
||||||
|
|
||||||
Ext.extend( Ext.data.AlohaProxy, Ext.data.DataProxy, {
|
|
||||||
|
|
||||||
doRequest: function ( action, rs, params, reader, cb, scope, arg ) {
|
|
||||||
jQuery.extend( this.params, params );
|
|
||||||
|
|
||||||
try {
|
|
||||||
RepositoryManager.query( this.params, function ( items ) {
|
|
||||||
cb.call( scope, reader.readRecords( items ), arg, true );
|
|
||||||
} );
|
|
||||||
} catch ( ex ) {
|
|
||||||
console.error( 'Ext.data.AlohaProxy',
|
|
||||||
'An error occured while querying repositories.' );
|
|
||||||
|
|
||||||
this.fireEvent( 'loadexception', this, null, arg, ex );
|
|
||||||
this.fireEvent( 'exception', this, 'response', action, arg, null, ex );
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setObjectTypeFilter: function ( otFilter ) {
|
|
||||||
this.params.objectTypeFilter = otFilter;
|
|
||||||
},
|
|
||||||
|
|
||||||
getObjectTypeFilter: function () {
|
|
||||||
return this.params.objectTypeFilter;
|
|
||||||
},
|
|
||||||
|
|
||||||
setParams: function ( p ) {
|
|
||||||
jQuery.extend( this.params, p );
|
|
||||||
}
|
|
||||||
|
|
||||||
} );
|
|
||||||
|
|
||||||
} );
|
|
@ -1,50 +0,0 @@
|
|||||||
/*!
|
|
||||||
* This file is part of Aloha Editor Project http://aloha-editor.org
|
|
||||||
* Copyright <EFBFBD> 2010-2011 Gentics Software GmbH, aloha@gentics.com
|
|
||||||
* Contributors http://aloha-editor.org/contribution.php
|
|
||||||
* Licensed unter the terms of http://www.aloha-editor.org/license.html
|
|
||||||
*//*
|
|
||||||
* Aloha Editor is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.*
|
|
||||||
*
|
|
||||||
* Aloha Editor is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
define(
|
|
||||||
['aloha/ext'],
|
|
||||||
function(Ext) {
|
|
||||||
|
|
||||||
|
|
||||||
Ext.data.AlohaObjectReader = function(meta, recordType) {
|
|
||||||
meta = {};
|
|
||||||
Ext.applyIf(meta, {
|
|
||||||
idProperty: 'id',
|
|
||||||
root: 'items',
|
|
||||||
totalProperty: 'results',
|
|
||||||
// TODO implement all defined optional attributes
|
|
||||||
fields: [
|
|
||||||
'id',
|
|
||||||
'url',
|
|
||||||
'name',
|
|
||||||
'type',
|
|
||||||
'weight',
|
|
||||||
'path',
|
|
||||||
'repositoryId'
|
|
||||||
]
|
|
||||||
});
|
|
||||||
Ext.data.JsonReader.superclass.constructor.call(this, meta, meta.fields);
|
|
||||||
};
|
|
||||||
|
|
||||||
Ext.extend(Ext.data.AlohaObjectReader, Ext.data.JsonReader, {
|
|
||||||
// extend of necessary
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
@ -1,77 +0,0 @@
|
|||||||
/*!
|
|
||||||
* This file is part of Aloha Editor Project http://aloha-editor.org
|
|
||||||
* Copyright (c) 2010-2011 Gentics Software GmbH, aloha@gentics.com
|
|
||||||
* Contributors http://aloha-editor.org/contribution.php
|
|
||||||
* Licensed unter the terms of http://www.aloha-editor.org/license.html
|
|
||||||
*//*
|
|
||||||
* Aloha Editor is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.*
|
|
||||||
*
|
|
||||||
* Aloha Editor is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
define(
|
|
||||||
['aloha/ext', 'aloha/repositorymanager'],
|
|
||||||
function(Ext, RepositoryManager) {
|
|
||||||
|
|
||||||
|
|
||||||
Ext.tree.AlohaTreeLoader = function(config) {
|
|
||||||
Ext.apply(this, config);
|
|
||||||
Ext.tree.AlohaTreeLoader.superclass.constructor.call(this);
|
|
||||||
};
|
|
||||||
|
|
||||||
Ext.extend( Ext.tree.AlohaTreeLoader, Ext.tree.TreeLoader, {
|
|
||||||
paramOrder: ['node', 'id'],
|
|
||||||
nodeParameter: 'id',
|
|
||||||
directFn : function(node, id, callback) {
|
|
||||||
var
|
|
||||||
params = {
|
|
||||||
inFolderId: node.id,
|
|
||||||
objectTypeFilter: this.objectTypeFilter,
|
|
||||||
repositoryId: node.repositoryId
|
|
||||||
};
|
|
||||||
|
|
||||||
RepositoryManager.getChildren ( params, function( items ) {
|
|
||||||
var response = {};
|
|
||||||
|
|
||||||
response = {
|
|
||||||
status: true,
|
|
||||||
scope: this,
|
|
||||||
argument: {callback: callback, node: node}
|
|
||||||
};
|
|
||||||
|
|
||||||
if(typeof callback === 'function'){
|
|
||||||
callback(items, response);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
createNode: function(node) {
|
|
||||||
if ( node.name ) {
|
|
||||||
node.text = node.name;
|
|
||||||
}
|
|
||||||
if ( node.hasMoreItems ) {
|
|
||||||
node.leaf = !node.hasMoreItems;
|
|
||||||
}
|
|
||||||
if ( node.objectType ) {
|
|
||||||
node.cls = node.objectType;
|
|
||||||
}
|
|
||||||
return Ext.tree.TreeLoader.prototype.createNode.call(this, node);
|
|
||||||
},
|
|
||||||
objectTypeFilter : null,
|
|
||||||
setObjectTypeFilter : function (otFilter) {
|
|
||||||
this.objectTypeFilter = otFilter;
|
|
||||||
},
|
|
||||||
getObjectTypeFilter : function () {
|
|
||||||
return this.objectTypeFilter;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
@ -1,32 +0,0 @@
|
|||||||
/*!
|
|
||||||
* This file is part of Aloha Editor Project http://aloha-editor.org
|
|
||||||
* Copyright (c) 2010-2011 Gentics Software GmbH, aloha@gentics.com
|
|
||||||
* Contributors http://aloha-editor.org/contribution.php
|
|
||||||
* Licensed unter the terms of http://www.aloha-editor.org/license.html
|
|
||||||
*//*
|
|
||||||
* Aloha Editor is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.*
|
|
||||||
*
|
|
||||||
* Aloha Editor is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
define('aloha/ext',[], function() {
|
|
||||||
|
|
||||||
// Ext seems to have an onClick handler that uses
|
|
||||||
// QuickTips, but the handler doesn't initialize
|
|
||||||
// QuickTips and therefore causes an error.
|
|
||||||
// The bug occurred with the Gentics Content Node
|
|
||||||
// integration, but if it's really a bug in Ext, then
|
|
||||||
// it's a good idea to always initialize QuickTips here.
|
|
||||||
Ext.QuickTips.init();
|
|
||||||
|
|
||||||
return Ext;
|
|
||||||
});
|
|
@ -1,546 +0,0 @@
|
|||||||
/*!
|
|
||||||
* This file is part of Aloha Editor
|
|
||||||
* Author & Copyright (c) 2010 Gentics Software GmbH, aloha@gentics.com
|
|
||||||
* Licensed unter the terms of http://www.aloha-editor.com/license.html
|
|
||||||
*/
|
|
||||||
(function(window, undefined) {
|
|
||||||
|
|
||||||
var
|
|
||||||
jQuery = window.alohaQuery || window.jQuery, $ = jQuery,
|
|
||||||
// GENTICS = window.GENTICS,
|
|
||||||
// Aloha = window.Aloha,
|
|
||||||
DOMUtils, TextRangeUtils, selection, DOMRange, RangeIterator, DOMSelection;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Only execute the following code if we are in IE (check for
|
|
||||||
* document.attachEvent, this is a microsoft event and therefore only available
|
|
||||||
* in IE).
|
|
||||||
*/
|
|
||||||
|
|
||||||
if(document.attachEvent && document.selection) {
|
|
||||||
/*!
|
|
||||||
* DOM Ranges for Internet Explorer (m2)
|
|
||||||
*
|
|
||||||
* Copyright (c) 2009 Tim Cameron Ryan
|
|
||||||
* Released under the MIT/X License
|
|
||||||
* available at http://code.google.com/p/ierange/
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Range reference:
|
|
||||||
http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html
|
|
||||||
http://mxr.mozilla.org/mozilla-central/source/content/base/src/nsRange.cpp
|
|
||||||
https://developer.mozilla.org/En/DOM:Range
|
|
||||||
Selection reference:
|
|
||||||
http://trac.webkit.org/browser/trunk/WebCore/page/DOMSelection.cpp
|
|
||||||
TextRange reference:
|
|
||||||
http://msdn.microsoft.com/en-us/library/ms535872.aspx
|
|
||||||
Other links:
|
|
||||||
http://jorgenhorstink.nl/test/javascript/range/range.js
|
|
||||||
http://jorgenhorstink.nl/2006/07/05/dom-range-implementation-in-ecmascript-completed/
|
|
||||||
http://dylanschiemann.com/articles/dom2Range/dom2RangeExamples.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
//[TODO] better exception support
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
DOM functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
DOMUtils = {
|
|
||||||
findChildPosition: function (node) {
|
|
||||||
for (var i = 0; node = node.previousSibling; i++)
|
|
||||||
continue;
|
|
||||||
return i;
|
|
||||||
},
|
|
||||||
isDataNode: function (node) {
|
|
||||||
return node && node.nodeValue !== null && node.data !== null;
|
|
||||||
},
|
|
||||||
isAncestorOf: function (parent, node) {
|
|
||||||
return !DOMUtils.isDataNode(parent) &&
|
|
||||||
(parent.contains(DOMUtils.isDataNode(node) ? node.parentNode : node) ||
|
|
||||||
node.parentNode == parent);
|
|
||||||
},
|
|
||||||
isAncestorOrSelf: function (root, node) {
|
|
||||||
return DOMUtils.isAncestorOf(root, node) || root == node;
|
|
||||||
},
|
|
||||||
findClosestAncestor: function (root, node) {
|
|
||||||
if (DOMUtils.isAncestorOf(root, node))
|
|
||||||
while (node && node.parentNode != root)
|
|
||||||
node = node.parentNode;
|
|
||||||
return node;
|
|
||||||
},
|
|
||||||
getNodeLength: function (node) {
|
|
||||||
return DOMUtils.isDataNode(node) ? node.length : node.childNodes.length;
|
|
||||||
},
|
|
||||||
splitDataNode: function (node, offset) {
|
|
||||||
if (!DOMUtils.isDataNode(node))
|
|
||||||
return false;
|
|
||||||
var newNode = node.cloneNode(false);
|
|
||||||
node.deleteData(offset, node.length);
|
|
||||||
newNode.deleteData(0, offset);
|
|
||||||
node.parentNode.insertBefore(newNode, node.nextSibling);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Text Range utilities
|
|
||||||
functions to simplify text range manipulation in ie
|
|
||||||
*/
|
|
||||||
|
|
||||||
TextRangeUtils = {
|
|
||||||
convertToDOMRange: function (textRange, document) {
|
|
||||||
var domRange,adoptBoundary;
|
|
||||||
|
|
||||||
adoptBoundary = function(domRange, textRange, bStart) {
|
|
||||||
// iterate backwards through parent element to find anchor location
|
|
||||||
var cursorNode = document.createElement('a'),
|
|
||||||
cursor = textRange.duplicate(),
|
|
||||||
parent;
|
|
||||||
|
|
||||||
cursor.collapse(bStart);
|
|
||||||
parent = cursor.parentElement();
|
|
||||||
do {
|
|
||||||
parent.insertBefore(cursorNode, cursorNode.previousSibling);
|
|
||||||
cursor.moveToElementText(cursorNode);
|
|
||||||
} while (cursor.compareEndPoints(bStart ? 'StartToStart' : 'StartToEnd', textRange) > 0 && cursorNode.previousSibling);
|
|
||||||
|
|
||||||
// when we exceed or meet the cursor, we've found the node
|
|
||||||
if (cursor.compareEndPoints(bStart ? 'StartToStart' : 'StartToEnd', textRange) == -1 && cursorNode.nextSibling) {
|
|
||||||
// data node
|
|
||||||
cursor.setEndPoint(bStart ? 'EndToStart' : 'EndToEnd', textRange);
|
|
||||||
domRange[bStart ? 'setStart' : 'setEnd'](cursorNode.nextSibling, cursor.text.length);
|
|
||||||
} else {
|
|
||||||
// element
|
|
||||||
domRange[bStart ? 'setStartBefore' : 'setEndBefore'](cursorNode);
|
|
||||||
}
|
|
||||||
cursorNode.parentNode.removeChild(cursorNode);
|
|
||||||
};
|
|
||||||
|
|
||||||
// return a DOM range
|
|
||||||
domRange = new DOMRange(document);
|
|
||||||
adoptBoundary(domRange, textRange, true);
|
|
||||||
adoptBoundary(domRange, textRange, false);
|
|
||||||
return domRange;
|
|
||||||
},
|
|
||||||
|
|
||||||
convertFromDOMRange: function (domRange) {
|
|
||||||
function adoptEndPoint(textRange, domRange, bStart) {
|
|
||||||
// find anchor node and offset
|
|
||||||
var container = domRange[bStart ? 'startContainer' : 'endContainer'],
|
|
||||||
offset = domRange[bStart ? 'startOffset' : 'endOffset'], textOffset = 0,
|
|
||||||
anchorNode = DOMUtils.isDataNode(container) ? container : container.childNodes[offset],
|
|
||||||
anchorParent = DOMUtils.isDataNode(container) ? container.parentNode : container,
|
|
||||||
cursorNode, cursor;
|
|
||||||
|
|
||||||
// visible data nodes need a text offset
|
|
||||||
if (container.nodeType == 3 || container.nodeType == 4) {
|
|
||||||
textOffset = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a cursor element node to position range (since we can't select text nodes)
|
|
||||||
cursorNode = domRange._document.createElement('a');
|
|
||||||
anchorParent.insertBefore(cursorNode, anchorNode);
|
|
||||||
cursor = domRange._document.body.createTextRange();
|
|
||||||
cursor.moveToElementText(cursorNode);
|
|
||||||
cursorNode.parentNode.removeChild(cursorNode);
|
|
||||||
// move range
|
|
||||||
textRange.setEndPoint(bStart ? 'StartToStart' : 'EndToStart', cursor);
|
|
||||||
textRange[bStart ? 'moveStart' : 'moveEnd']('character', textOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
// return an IE text range
|
|
||||||
var textRange = domRange._document.body.createTextRange();
|
|
||||||
adoptEndPoint(textRange, domRange, true);
|
|
||||||
adoptEndPoint(textRange, domRange, false);
|
|
||||||
return textRange;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
DOM Range
|
|
||||||
*/
|
|
||||||
DOMRange = function(document) {
|
|
||||||
// save document parameter
|
|
||||||
this._document = document;
|
|
||||||
|
|
||||||
// initialize range
|
|
||||||
//[TODO] this should be located at document[0], document[0]
|
|
||||||
this.startContainer = this.endContainer = document.body;
|
|
||||||
this.endOffset = DOMUtils.getNodeLength(document.body);
|
|
||||||
};
|
|
||||||
|
|
||||||
DOMRange.START_TO_START = 0;
|
|
||||||
DOMRange.START_TO_END = 1;
|
|
||||||
DOMRange.END_TO_END = 2;
|
|
||||||
DOMRange.END_TO_START = 3;
|
|
||||||
|
|
||||||
DOMRange.prototype = {
|
|
||||||
// public properties
|
|
||||||
startContainer: null,
|
|
||||||
startOffset: 0,
|
|
||||||
endContainer: null,
|
|
||||||
endOffset: 0,
|
|
||||||
commonAncestorContainer: null,
|
|
||||||
collapsed: false,
|
|
||||||
// private properties
|
|
||||||
_document: null,
|
|
||||||
|
|
||||||
// private methods
|
|
||||||
_refreshProperties: function () {
|
|
||||||
// collapsed attribute
|
|
||||||
this.collapsed = (this.startContainer == this.endContainer && this.startOffset == this.endOffset);
|
|
||||||
// find common ancestor
|
|
||||||
var node = this.startContainer;
|
|
||||||
while (node && node != this.endContainer && !DOMUtils.isAncestorOf(node, this.endContainer))
|
|
||||||
node = node.parentNode;
|
|
||||||
this.commonAncestorContainer = node;
|
|
||||||
},
|
|
||||||
|
|
||||||
// range methods
|
|
||||||
//[TODO] collapse if start is after end, end is before start
|
|
||||||
setStart: function(container, offset) {
|
|
||||||
this.startContainer = container;
|
|
||||||
this.startOffset = offset;
|
|
||||||
this._refreshProperties();
|
|
||||||
},
|
|
||||||
setEnd: function(container, offset) {
|
|
||||||
this.endContainer = container;
|
|
||||||
this.endOffset = offset;
|
|
||||||
this._refreshProperties();
|
|
||||||
},
|
|
||||||
setStartBefore: function (refNode) {
|
|
||||||
// set start to beore this node
|
|
||||||
this.setStart(refNode.parentNode, DOMUtils.findChildPosition(refNode));
|
|
||||||
},
|
|
||||||
setStartAfter: function (refNode) {
|
|
||||||
// select next sibling
|
|
||||||
this.setStart(refNode.parentNode, DOMUtils.findChildPosition(refNode) + 1);
|
|
||||||
},
|
|
||||||
setEndBefore: function (refNode) {
|
|
||||||
// set end to beore this node
|
|
||||||
this.setEnd(refNode.parentNode, DOMUtils.findChildPosition(refNode));
|
|
||||||
},
|
|
||||||
setEndAfter: function (refNode) {
|
|
||||||
// select next sibling
|
|
||||||
this.setEnd(refNode.parentNode, DOMUtils.findChildPosition(refNode) + 1);
|
|
||||||
},
|
|
||||||
selectNode: function (refNode) {
|
|
||||||
this.setStartBefore(refNode);
|
|
||||||
this.setEndAfter(refNode);
|
|
||||||
},
|
|
||||||
selectNodeContents: function (refNode) {
|
|
||||||
this.setStart(refNode, 0);
|
|
||||||
this.setEnd(refNode, DOMUtils.getNodeLength(refNode));
|
|
||||||
},
|
|
||||||
collapse: function (toStart) {
|
|
||||||
if (toStart)
|
|
||||||
this.setEnd(this.startContainer, this.startOffset);
|
|
||||||
else
|
|
||||||
this.setStart(this.endContainer, this.endOffset);
|
|
||||||
},
|
|
||||||
|
|
||||||
// editing methods
|
|
||||||
cloneContents: function () {
|
|
||||||
// clone subtree
|
|
||||||
return (function cloneSubtree(iterator) {
|
|
||||||
for (var node, frag = document.createDocumentFragment(); node = iterator.next(); ) {
|
|
||||||
node = node.cloneNode(!iterator.hasPartialSubtree());
|
|
||||||
if (iterator.hasPartialSubtree())
|
|
||||||
node.appendChild(cloneSubtree(iterator.getSubtreeIterator()));
|
|
||||||
frag.appendChild(node);
|
|
||||||
}
|
|
||||||
return frag;
|
|
||||||
})(new RangeIterator(this));
|
|
||||||
},
|
|
||||||
extractContents: function () {
|
|
||||||
// cache range and move anchor points
|
|
||||||
var range = this.cloneRange();
|
|
||||||
if (this.startContainer != this.commonAncestorContainer)
|
|
||||||
this.setStartAfter(DOMUtils.findClosestAncestor(this.commonAncestorContainer, this.startContainer));
|
|
||||||
this.collapse(true);
|
|
||||||
// extract range
|
|
||||||
return (function extractSubtree(iterator) {
|
|
||||||
for (var node, frag = document.createDocumentFragment(); node = iterator.next(); ) {
|
|
||||||
if ( iterator.hasPartialSubtree() ) {
|
|
||||||
node = node.cloneNode(false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
iterator.remove();
|
|
||||||
}
|
|
||||||
if (iterator.hasPartialSubtree())
|
|
||||||
node.appendChild(extractSubtree(iterator.getSubtreeIterator()));
|
|
||||||
frag.appendChild(node);
|
|
||||||
}
|
|
||||||
return frag;
|
|
||||||
})(new RangeIterator(range));
|
|
||||||
},
|
|
||||||
deleteContents: function () {
|
|
||||||
// cache range and move anchor points
|
|
||||||
var range = this.cloneRange();
|
|
||||||
if (this.startContainer != this.commonAncestorContainer)
|
|
||||||
this.setStartAfter(DOMUtils.findClosestAncestor(this.commonAncestorContainer, this.startContainer));
|
|
||||||
this.collapse(true);
|
|
||||||
// delete range
|
|
||||||
(function deleteSubtree(iterator) {
|
|
||||||
while (iterator.next()) {
|
|
||||||
if ( iterator.hasPartialSubtree() ) {
|
|
||||||
deleteSubtree(iterator.getSubtreeIterator());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
iterator.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})(new RangeIterator(range));
|
|
||||||
},
|
|
||||||
insertNode: function (newNode) {
|
|
||||||
// set original anchor and insert node
|
|
||||||
if (DOMUtils.isDataNode(this.startContainer)) {
|
|
||||||
DOMUtils.splitDataNode(this.startContainer, this.startOffset);
|
|
||||||
this.startContainer.parentNode.insertBefore(newNode, this.startContainer.nextSibling);
|
|
||||||
} else {
|
|
||||||
this.startContainer.insertBefore(newNode, this.startContainer.childNodes[this.startOffset]);
|
|
||||||
}
|
|
||||||
// resync start anchor
|
|
||||||
this.setStart(this.startContainer, this.startOffset);
|
|
||||||
},
|
|
||||||
surroundContents: function (newNode) {
|
|
||||||
// extract and surround contents
|
|
||||||
var content = this.extractContents();
|
|
||||||
this.insertNode(newNode);
|
|
||||||
newNode.appendChild(content);
|
|
||||||
this.selectNode(newNode);
|
|
||||||
},
|
|
||||||
|
|
||||||
// other methods
|
|
||||||
compareBoundaryPoints: function (how, sourceRange) {
|
|
||||||
// get anchors
|
|
||||||
var containerA, offsetA, containerB, offsetB;
|
|
||||||
switch (how) {
|
|
||||||
case DOMRange.START_TO_START:
|
|
||||||
case DOMRange.START_TO_END:
|
|
||||||
containerA = this.startContainer;
|
|
||||||
offsetA = this.startOffset;
|
|
||||||
break;
|
|
||||||
case DOMRange.END_TO_END:
|
|
||||||
case DOMRange.END_TO_START:
|
|
||||||
containerA = this.endContainer;
|
|
||||||
offsetA = this.endOffset;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
switch (how) {
|
|
||||||
case DOMRange.START_TO_START:
|
|
||||||
case DOMRange.END_TO_START:
|
|
||||||
containerB = sourceRange.startContainer;
|
|
||||||
offsetB = sourceRange.startOffset;
|
|
||||||
break;
|
|
||||||
case DOMRange.START_TO_END:
|
|
||||||
case DOMRange.END_TO_END:
|
|
||||||
containerB = sourceRange.endContainer;
|
|
||||||
offsetB = sourceRange.endOffset;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// compare
|
|
||||||
return containerA.sourceIndex < containerB.sourceIndex ? -1 :
|
|
||||||
containerA.sourceIndex == containerB.sourceIndex ?
|
|
||||||
offsetA < offsetB ? -1 : offsetA == offsetB ? 0 : 1
|
|
||||||
: 1;
|
|
||||||
},
|
|
||||||
cloneRange: function () {
|
|
||||||
// return cloned range
|
|
||||||
var range = new DOMRange(this._document);
|
|
||||||
range.setStart(this.startContainer, this.startOffset);
|
|
||||||
range.setEnd(this.endContainer, this.endOffset);
|
|
||||||
return range;
|
|
||||||
},
|
|
||||||
detach: function () {
|
|
||||||
//[TODO] Releases Range from use to improve performance.
|
|
||||||
},
|
|
||||||
toString: function () {
|
|
||||||
return TextRangeUtils.convertFromDOMRange(this).text;
|
|
||||||
},
|
|
||||||
createContextualFragment: function (tagString) {
|
|
||||||
// parse the tag string in a context node
|
|
||||||
var
|
|
||||||
content = (DOMUtils.isDataNode(this.startContainer) ? this.startContainer.parentNode : this.startContainer).cloneNode(false),
|
|
||||||
fragment;
|
|
||||||
|
|
||||||
content.innerHTML = tagString;
|
|
||||||
// return a document fragment from the created node
|
|
||||||
for (fragment = this._document.createDocumentFragment(); content.firstChild; )
|
|
||||||
fragment.appendChild(content.firstChild);
|
|
||||||
return fragment;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Range iterator
|
|
||||||
*/
|
|
||||||
RangeIterator = function(range) {
|
|
||||||
this.range = range;
|
|
||||||
if (range.collapsed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//[TODO] ensure this works
|
|
||||||
// get anchors
|
|
||||||
var root = range.commonAncestorContainer;
|
|
||||||
this._next = range.startContainer == root && !DOMUtils.isDataNode(range.startContainer) ?
|
|
||||||
range.startContainer.childNodes[range.startOffset] :
|
|
||||||
DOMUtils.findClosestAncestor(root, range.startContainer);
|
|
||||||
this._end = range.endContainer == root && !DOMUtils.isDataNode(range.endContainer) ?
|
|
||||||
range.endContainer.childNodes[range.endOffset] :
|
|
||||||
DOMUtils.findClosestAncestor(root, range.endContainer).nextSibling;
|
|
||||||
};
|
|
||||||
|
|
||||||
RangeIterator.prototype = {
|
|
||||||
// public properties
|
|
||||||
range: null,
|
|
||||||
// private properties
|
|
||||||
_current: null,
|
|
||||||
_next: null,
|
|
||||||
_end: null,
|
|
||||||
|
|
||||||
// public methods
|
|
||||||
hasNext: function () {
|
|
||||||
return !!this._next;
|
|
||||||
},
|
|
||||||
next: function () {
|
|
||||||
// move to next node
|
|
||||||
var current = this._current = this._next;
|
|
||||||
this._next = this._current && this._current.nextSibling != this._end ?
|
|
||||||
this._current.nextSibling : null;
|
|
||||||
|
|
||||||
// check for partial text nodes
|
|
||||||
if (DOMUtils.isDataNode(this._current)) {
|
|
||||||
if (this.range.endContainer == this._current)
|
|
||||||
(current = current.cloneNode(true)).deleteData(this.range.endOffset, current.length - this.range.endOffset);
|
|
||||||
if (this.range.startContainer == this._current)
|
|
||||||
(current = current.cloneNode(true)).deleteData(0, this.range.startOffset);
|
|
||||||
}
|
|
||||||
return current;
|
|
||||||
},
|
|
||||||
remove: function () {
|
|
||||||
var end, start;
|
|
||||||
// check for partial text nodes
|
|
||||||
if (DOMUtils.isDataNode(this._current) &&
|
|
||||||
(this.range.startContainer == this._current || this.range.endContainer == this._current)) {
|
|
||||||
start = this.range.startContainer == this._current ? this.range.startOffset : 0;
|
|
||||||
end = this.range.endContainer == this._current ? this.range.endOffset : this._current.length;
|
|
||||||
this._current.deleteData(start, end - start);
|
|
||||||
} else
|
|
||||||
this._current.parentNode.removeChild(this._current);
|
|
||||||
},
|
|
||||||
hasPartialSubtree: function () {
|
|
||||||
// check if this node be partially selected
|
|
||||||
return !DOMUtils.isDataNode(this._current) &&
|
|
||||||
(DOMUtils.isAncestorOrSelf(this._current, this.range.startContainer) ||
|
|
||||||
DOMUtils.isAncestorOrSelf(this._current, this.range.endContainer));
|
|
||||||
},
|
|
||||||
getSubtreeIterator: function () {
|
|
||||||
// create a new range
|
|
||||||
var subRange = new DOMRange(this.range._document);
|
|
||||||
subRange.selectNodeContents(this._current);
|
|
||||||
// handle anchor points
|
|
||||||
if (DOMUtils.isAncestorOrSelf(this._current, this.range.startContainer))
|
|
||||||
subRange.setStart(this.range.startContainer, this.range.startOffset);
|
|
||||||
if (DOMUtils.isAncestorOrSelf(this._current, this.range.endContainer))
|
|
||||||
subRange.setEnd(this.range.endContainer, this.range.endOffset);
|
|
||||||
// return iterator
|
|
||||||
return new RangeIterator(subRange);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
DOM Selection
|
|
||||||
*/
|
|
||||||
|
|
||||||
//[NOTE] This is a very shallow implementation of the Selection object, based on Webkit's
|
|
||||||
// implementation and without redundant features. Complete selection manipulation is still
|
|
||||||
// possible with just removeAllRanges/addRange/getRangeAt.
|
|
||||||
|
|
||||||
DOMSelection = function (document) {
|
|
||||||
// save document parameter
|
|
||||||
this._document = document;
|
|
||||||
|
|
||||||
// add DOM selection handler
|
|
||||||
var selection = this;
|
|
||||||
document.attachEvent('onselectionchange', function () { selection._selectionChangeHandler(); });
|
|
||||||
};
|
|
||||||
|
|
||||||
DOMSelection.prototype = {
|
|
||||||
// public properties
|
|
||||||
rangeCount: 0,
|
|
||||||
// private properties
|
|
||||||
_document: null,
|
|
||||||
|
|
||||||
// private methods
|
|
||||||
_selectionChangeHandler: function () {
|
|
||||||
// check if there exists a range
|
|
||||||
this.rangeCount = this._selectionExists(this._document.selection.createRange()) ? 1 : 0;
|
|
||||||
},
|
|
||||||
_selectionExists: function (textRange) {
|
|
||||||
// checks if a created text range exists or is an editable cursor
|
|
||||||
return textRange.compareEndPoints('StartToEnd', textRange) !== 0 ||
|
|
||||||
textRange.parentElement().isContentEditable;
|
|
||||||
},
|
|
||||||
|
|
||||||
// public methods
|
|
||||||
addRange: function (range) {
|
|
||||||
// add range or combine with existing range
|
|
||||||
var selection = this._document.selection.createRange(), textRange = TextRangeUtils.convertFromDOMRange(range);
|
|
||||||
if (!this._selectionExists(selection))
|
|
||||||
{
|
|
||||||
// select range
|
|
||||||
textRange.select();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// only modify range if it intersects with current range
|
|
||||||
if (textRange.compareEndPoints('StartToStart', selection) == -1)
|
|
||||||
if (textRange.compareEndPoints('StartToEnd', selection) > -1 &&
|
|
||||||
textRange.compareEndPoints('EndToEnd', selection) == -1)
|
|
||||||
selection.setEndPoint('StartToStart', textRange);
|
|
||||||
else
|
|
||||||
if (textRange.compareEndPoints('EndToStart', selection) < 1 &&
|
|
||||||
textRange.compareEndPoints('EndToEnd', selection) > -1)
|
|
||||||
selection.setEndPoint('EndToEnd', textRange);
|
|
||||||
selection.select();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
removeAllRanges: function () {
|
|
||||||
// remove all ranges
|
|
||||||
this._document.selection.empty();
|
|
||||||
},
|
|
||||||
getRangeAt: function (index) {
|
|
||||||
// return any existing selection, or a cursor position in content editable mode
|
|
||||||
var textRange = this._document.selection.createRange();
|
|
||||||
if (this._selectionExists(textRange))
|
|
||||||
return TextRangeUtils.convertToDOMRange(textRange, this._document);
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
toString: function () {
|
|
||||||
// get selection text
|
|
||||||
return this._document.selection.createRange().text;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
scripting hooks
|
|
||||||
*/
|
|
||||||
|
|
||||||
document.createRange = function () {
|
|
||||||
return new DOMRange(document);
|
|
||||||
};
|
|
||||||
|
|
||||||
selection = new DOMSelection(document);
|
|
||||||
window.getSelection = function () {
|
|
||||||
return selection;
|
|
||||||
};
|
|
||||||
|
|
||||||
//[TODO] expose DOMRange/DOMSelection to window.?
|
|
||||||
}
|
|
||||||
|
|
||||||
})(window);
|
|
@ -1,324 +0,0 @@
|
|||||||
/*!
|
|
||||||
* This file is part of Aloha Editor Project http://aloha-editor.org
|
|
||||||
* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com
|
|
||||||
* Contributors http://aloha-editor.org/contribution.php
|
|
||||||
* Licensed unter the terms of http://www.aloha-editor.org/license.html
|
|
||||||
*//*
|
|
||||||
* Aloha Editor is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.*
|
|
||||||
*
|
|
||||||
* Aloha Editor is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
define(
|
|
||||||
[ 'aloha/core', 'aloha/selection', 'aloha/jquery', 'aloha/console' ],
|
|
||||||
function( Aloha, Selection, jQuery, console ) {
|
|
||||||
|
|
||||||
|
|
||||||
var
|
|
||||||
// $ = jQuery,
|
|
||||||
// Aloha = window.Aloha,
|
|
||||||
// console = window.console,
|
|
||||||
XMLSerializer = window.XMLSerializer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* jQuery between Extension
|
|
||||||
*
|
|
||||||
* insert either html code, a dom object OR a jQuery object inside of an existing text node.
|
|
||||||
* if the chained jQuery object is not a text node, nothing will happen.
|
|
||||||
*
|
|
||||||
* @param content HTML Code, DOM object or jQuery object to be inserted
|
|
||||||
* @param offset character offset from the start where the content should be inserted
|
|
||||||
*/
|
|
||||||
jQuery.fn.between = function(content, offset) {
|
|
||||||
var
|
|
||||||
offSize,
|
|
||||||
fullText;
|
|
||||||
|
|
||||||
if (this[0].nodeType !== 3) {
|
|
||||||
// we are not in a text node, just insert the element at the corresponding position
|
|
||||||
offSize = this.children().size();
|
|
||||||
if (offset > offSize) {
|
|
||||||
offset = offSize;
|
|
||||||
}
|
|
||||||
if (offset <= 0) {
|
|
||||||
this.prepend(content);
|
|
||||||
} else {
|
|
||||||
this.children().eq(offset -1).after(content);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// we are in a text node so we have to split it at the correct position
|
|
||||||
if (offset <= 0) {
|
|
||||||
this.before(content);
|
|
||||||
} else if (offset >= this[0].length) {
|
|
||||||
this.after(content);
|
|
||||||
} else {
|
|
||||||
fullText = this[0].data;
|
|
||||||
this[0].data = fullText.substring(0, offset);
|
|
||||||
this.after(fullText.substring(offset, fullText.length));
|
|
||||||
this.after(content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make the object contenteditable. Care about browser version (name of contenteditable attribute depends on it)
|
|
||||||
*/
|
|
||||||
jQuery.fn.contentEditable = function( b ) {
|
|
||||||
// ie does not understand contenteditable but contentEditable
|
|
||||||
// contentEditable is not xhtml compatible.
|
|
||||||
var $el = jQuery(this);
|
|
||||||
var ce = 'contenteditable';
|
|
||||||
|
|
||||||
// Check
|
|
||||||
if (jQuery.browser.msie && parseInt(jQuery.browser.version,10) == 7 ) {
|
|
||||||
ce = 'contentEditable';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof b === 'undefined' ) {
|
|
||||||
|
|
||||||
// For chrome use this specific attribute. The old ce will only
|
|
||||||
// return 'inherit' for nested elements of a contenteditable.
|
|
||||||
// The isContentEditable is a w3c standard compliant property which works in IE7,8,FF36+, Chrome 12+
|
|
||||||
if (typeof $el[0] === 'undefined' ) {
|
|
||||||
console.error('The jquery object did not contain any valid elements.');
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
if (typeof $el[0].isContentEditable === 'undefined') {
|
|
||||||
console.warn('Could not determine whether the is editable or not. I assume it is.');
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return $el[0].isContentEditable;
|
|
||||||
}
|
|
||||||
} else if (b === '') {
|
|
||||||
$el.removeAttr(ce);
|
|
||||||
} else {
|
|
||||||
if (b && b !== 'false') {
|
|
||||||
b = 'true';
|
|
||||||
} else {
|
|
||||||
b = 'false';
|
|
||||||
}
|
|
||||||
$el.attr(ce, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $el;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* jQuery Aloha Plugin
|
|
||||||
*
|
|
||||||
* turn all dom elements to continous text
|
|
||||||
* @return jQuery object for the matched elements
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
jQuery.fn.aloha = function() {
|
|
||||||
var $this = jQuery( this );
|
|
||||||
|
|
||||||
Aloha.bind( 'aloha-ready', function() {
|
|
||||||
$this.each( function() {
|
|
||||||
// create a new aloha editable object for each passed object
|
|
||||||
if ( !Aloha.isEditable( this ) ) {
|
|
||||||
new Aloha.Editable( jQuery( this ) );
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Chain
|
|
||||||
return $this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* jQuery destroy elements as editable
|
|
||||||
*
|
|
||||||
* destroy all mached elements editable capabilities
|
|
||||||
* @return jQuery object for the matched elements
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
jQuery.fn.mahalo = function() {
|
|
||||||
return this.each(function() {
|
|
||||||
if (Aloha.isEditable(this)) {
|
|
||||||
Aloha.getEditableById(jQuery(this).attr('id')).destroy();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* jQuery Extension
|
|
||||||
* new Event which is triggered whenever a selection (length >= 0) is made in
|
|
||||||
* an Aloha Editable element
|
|
||||||
*/
|
|
||||||
jQuery.fn.contentEditableSelectionChange = function(callback) {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
// update selection when keys are pressed
|
|
||||||
this.keyup(function(event){
|
|
||||||
var rangeObject = Selection.getRangeObject();
|
|
||||||
callback(event);
|
|
||||||
});
|
|
||||||
|
|
||||||
// update selection on doubleclick (especially important for the first automatic selection, when the Editable is not active yet, but is at the same time activated as the selection occurs
|
|
||||||
this.dblclick(function(event) {
|
|
||||||
callback(event);
|
|
||||||
});
|
|
||||||
|
|
||||||
// update selection when text is selected
|
|
||||||
this.mousedown(function(event){
|
|
||||||
// remember that a selection was started
|
|
||||||
that.selectionStarted = true;
|
|
||||||
});
|
|
||||||
jQuery(document).mouseup(function(event) {
|
|
||||||
Selection.eventOriginalTarget = that;
|
|
||||||
if (that.selectionStarted) {
|
|
||||||
callback(event);
|
|
||||||
}
|
|
||||||
Selection.eventOriginalTarget = false;
|
|
||||||
that.selectionStarted = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch the outerHTML of an Element
|
|
||||||
* @version 1.0.0
|
|
||||||
* @date February 01, 2011
|
|
||||||
* @package jquery-sparkle {@link http://www.balupton/projects/jquery-sparkle}
|
|
||||||
* @author Benjamin Arthur Lupton {@link http://balupton.com}
|
|
||||||
* @copyright 2011 Benjamin Arthur Lupton {@link http://balupton.com}
|
|
||||||
* @license MIT License {@link http://creativecommons.org/licenses/MIT/}
|
|
||||||
* @return {String} outerHtml
|
|
||||||
*/
|
|
||||||
jQuery.fn.outerHtml = jQuery.fn.outerHtml || function(){
|
|
||||||
var
|
|
||||||
$el = jQuery(this),
|
|
||||||
el = $el.get(0);
|
|
||||||
if (typeof el.outerHTML != 'undefined') {
|
|
||||||
return el.outerHTML;
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
// Gecko-based browsers, Safari, Opera.
|
|
||||||
return (new XMLSerializer()).serializeToString(el);
|
|
||||||
} catch (e) {
|
|
||||||
try {
|
|
||||||
// Internet Explorer.
|
|
||||||
return el.xml;
|
|
||||||
} catch (e) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
jQuery.fn.zap = function () {
|
|
||||||
return this.each(function(){ jQuery(this.childNodes).insertBefore(this); }).remove();
|
|
||||||
};
|
|
||||||
|
|
||||||
jQuery.fn.textNodes = function(excludeBreaks, includeEmptyTextNodes) {
|
|
||||||
var
|
|
||||||
ret = [],
|
|
||||||
doSomething = function(el){
|
|
||||||
if (
|
|
||||||
(el.nodeType === 3 && jQuery.trim(el.data) && !includeEmptyTextNodes) ||
|
|
||||||
(el.nodeType === 3 && includeEmptyTextNodes) ||
|
|
||||||
(el.nodeName =="BR" && !excludeBreaks)) {
|
|
||||||
ret.push(el);
|
|
||||||
} else {
|
|
||||||
for (var i=0, childLength = el.childNodes.length; i < childLength; ++i) {
|
|
||||||
doSomething(el.childNodes[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
doSomething(this[0]);
|
|
||||||
|
|
||||||
return jQuery(ret);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* extendObjects is like jQuery.extend, but it does not extend arrays
|
|
||||||
*/
|
|
||||||
jQuery.extendObjects = jQuery.fn.extendObjects = function() {
|
|
||||||
var options, name, src, copy, copyIsArray, clone,
|
|
||||||
target = arguments[0] || {},
|
|
||||||
i = 1,
|
|
||||||
length = arguments.length,
|
|
||||||
deep = false;
|
|
||||||
|
|
||||||
// Handle a deep copy situation
|
|
||||||
if ( typeof target === "boolean" ) {
|
|
||||||
deep = target;
|
|
||||||
target = arguments[1] || {};
|
|
||||||
// skip the boolean and the target
|
|
||||||
i = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle case when target is a string or something (possible in deep copy)
|
|
||||||
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
|
|
||||||
target = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// extend jQuery itself if only one argument is passed
|
|
||||||
if ( length === i ) {
|
|
||||||
target = this;
|
|
||||||
--i;
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( ; i < length; i++ ) {
|
|
||||||
// Only deal with non-null/undefined values
|
|
||||||
if ( (options = arguments[ i ]) != null ) {
|
|
||||||
// Extend the base object
|
|
||||||
for ( name in options ) {
|
|
||||||
src = target[ name ];
|
|
||||||
copy = options[ name ];
|
|
||||||
|
|
||||||
// Prevent never-ending loop
|
|
||||||
if ( target === copy ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recurse if we're merging plain objects or arrays
|
|
||||||
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
|
|
||||||
if ( copyIsArray ) {
|
|
||||||
copyIsArray = false;
|
|
||||||
clone = src && jQuery.isArray(src) ? src : [];
|
|
||||||
|
|
||||||
} else {
|
|
||||||
clone = src && jQuery.isPlainObject(src) ? src : {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Never move original objects, clone them
|
|
||||||
if (jQuery.isArray(copy)) {
|
|
||||||
// don't extend arrays
|
|
||||||
target[ name ] = copy;
|
|
||||||
} else {
|
|
||||||
target[ name ] = jQuery.extendObjects( deep, clone, copy );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't bring in undefined values
|
|
||||||
} else if ( copy !== undefined ) {
|
|
||||||
target[ name ] = copy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the modified object
|
|
||||||
return target;
|
|
||||||
};
|
|
||||||
|
|
||||||
jQuery.isBoolean = function(b) {
|
|
||||||
return b === true || b === false;
|
|
||||||
},
|
|
||||||
|
|
||||||
jQuery.isNumeric = function(o) {
|
|
||||||
return ! isNaN (o-0);
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,24 +0,0 @@
|
|||||||
/*!
|
|
||||||
* This file is part of Aloha Editor Project http://aloha-editor.org
|
|
||||||
* Copyright (c) 2010-2011 Gentics Software GmbH, aloha@gentics.com
|
|
||||||
* Contributors http://aloha-editor.org/contribution.php
|
|
||||||
* Licensed unter the terms of http://www.aloha-editor.org/license.html
|
|
||||||
*
|
|
||||||
* Aloha Editor is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.*
|
|
||||||
*
|
|
||||||
* Aloha Editor is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// define jquery and ext modules. They need to be available in global namespace
|
|
||||||
define('aloha/jquery',[], function() {
|
|
||||||
return Aloha.jQuery;
|
|
||||||
});
|
|
@ -1,115 +0,0 @@
|
|||||||
/*!
|
|
||||||
* This file is part of Aloha Editor Project http://aloha-editor.org
|
|
||||||
* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com
|
|
||||||
* Contributors http://aloha-editor.org/contribution.php
|
|
||||||
* Licensed unter the terms of http://www.aloha-editor.org/license.html
|
|
||||||
*//*
|
|
||||||
* Aloha Editor is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.*
|
|
||||||
*
|
|
||||||
* Aloha Editor is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// use specified jQuery or load jQuery
|
|
||||||
|
|
||||||
define(
|
|
||||||
[ 'aloha/jquery' ],
|
|
||||||
function( jQuery ) {
|
|
||||||
|
|
||||||
//PATCH FOR A JQUERY BUG IN 1.6.1 & 1.6.2
|
|
||||||
//An additional sanity check was introduced to prevent IE from crashing when cache[id] does not exist
|
|
||||||
jQuery.data = ( function( jQuery ) {
|
|
||||||
return function( elem, name, data, pvt /* Internal Use Only */ ) {
|
|
||||||
if ( !jQuery.acceptData( elem ) ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache,
|
|
||||||
|
|
||||||
// We have to handle DOM nodes and JS objects differently because IE6-7
|
|
||||||
// can't GC object references properly across the DOM-JS boundary
|
|
||||||
isNode = elem.nodeType,
|
|
||||||
|
|
||||||
// Only DOM nodes need the global jQuery cache; JS object data is
|
|
||||||
// attached directly to the object so GC can occur automatically
|
|
||||||
cache = isNode ? jQuery.cache : elem,
|
|
||||||
|
|
||||||
// Only defining an ID for JS objects if its cache already exists allows
|
|
||||||
// the code to shortcut on the same path as a DOM node with no cache
|
|
||||||
id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando;
|
|
||||||
|
|
||||||
// Avoid doing any more work than we need to when trying to get data on an
|
|
||||||
// object that has no data at all
|
|
||||||
//if ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) {
|
|
||||||
if ( (!id || (pvt && id && (!cache[id] || !cache[ id ][ internalKey ]))) && getByName && data === undefined ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !id ) {
|
|
||||||
// Only DOM nodes need a new unique ID for each element since their data
|
|
||||||
// ends up in the global cache
|
|
||||||
if ( isNode ) {
|
|
||||||
elem[ jQuery.expando ] = id = ++jQuery.uuid;
|
|
||||||
} else {
|
|
||||||
id = jQuery.expando;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !cache[ id ] ) {
|
|
||||||
cache[ id ] = {};
|
|
||||||
|
|
||||||
// TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
|
|
||||||
// metadata on plain JS objects when the object is serialized using
|
|
||||||
// JSON.stringify
|
|
||||||
if ( !isNode ) {
|
|
||||||
cache[ id ].toJSON = jQuery.noop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// An object can be passed to jQuery.data instead of a key/value pair; this gets
|
|
||||||
// shallow copied over onto the existing cache
|
|
||||||
if ( typeof name === "object" || typeof name === "function" ) {
|
|
||||||
if ( pvt ) {
|
|
||||||
cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name);
|
|
||||||
} else {
|
|
||||||
cache[ id ] = jQuery.extend(cache[ id ], name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
thisCache = cache[ id ];
|
|
||||||
|
|
||||||
// Internal jQuery data is stored in a separate object inside the object's data
|
|
||||||
// cache in order to avoid key collisions between internal data and user-defined
|
|
||||||
// data
|
|
||||||
if ( pvt ) {
|
|
||||||
if ( !thisCache[ internalKey ] ) {
|
|
||||||
thisCache[ internalKey ] = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
thisCache = thisCache[ internalKey ];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( data !== undefined ) {
|
|
||||||
thisCache[ jQuery.camelCase( name ) ] = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should
|
|
||||||
// not attempt to inspect the internal events object using jQuery.data, as this
|
|
||||||
// internal data object is undocumented and subject to change.
|
|
||||||
if ( name === "events" && !thisCache[name] ) {
|
|
||||||
return thisCache[ internalKey ] && thisCache[ internalKey ].events;
|
|
||||||
}
|
|
||||||
|
|
||||||
return getByName ? thisCache[ jQuery.camelCase( name ) ] : thisCache;
|
|
||||||
};
|
|
||||||
})( jQuery );
|
|
||||||
|
|
||||||
});
|
|
@ -1,898 +0,0 @@
|
|||||||
/*!
|
|
||||||
* This file is part of Aloha Editor Project http://aloha-editor.org
|
|
||||||
* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com
|
|
||||||
* Contributors http://aloha-editor.org/contribution.php
|
|
||||||
* Licensed unter the terms of http://www.aloha-editor.org/license.html
|
|
||||||
*//*
|
|
||||||
* Aloha Editor is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.*
|
|
||||||
*
|
|
||||||
* Aloha Editor is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
define(
|
|
||||||
[ 'aloha/core', 'util/class', 'aloha/jquery' ],
|
|
||||||
function( Aloha, Class, jQuery ) {
|
|
||||||
|
|
||||||
|
|
||||||
var
|
|
||||||
// Aloha = window.Aloha,
|
|
||||||
// Class = window.Class,
|
|
||||||
GENTICS = window.GENTICS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Markup object
|
|
||||||
*/
|
|
||||||
Aloha.Markup = Class.extend({
|
|
||||||
/**
|
|
||||||
* Key handlers for special key codes
|
|
||||||
*/
|
|
||||||
keyHandlers: {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a key handler for the given key code
|
|
||||||
* @param keyCode key code
|
|
||||||
* @param handler handler function
|
|
||||||
*/
|
|
||||||
addKeyHandler: function (keyCode, handler) {
|
|
||||||
if (!this.keyHandlers[keyCode]) {
|
|
||||||
this.keyHandlers[keyCode] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.keyHandlers[keyCode].push(handler);
|
|
||||||
},
|
|
||||||
|
|
||||||
insertBreak: function () {
|
|
||||||
var range = Aloha.Selection.rangeObject,nonWSIndex,nextTextNode,newBreak;
|
|
||||||
if (!range.isCollapsed()) {
|
|
||||||
this.removeSelectedMarkup();
|
|
||||||
}
|
|
||||||
|
|
||||||
newBreak = jQuery('<br/>');
|
|
||||||
GENTICS.Utils.Dom.insertIntoDOM(newBreak, range, Aloha.activeEditable.obj);
|
|
||||||
|
|
||||||
nextTextNode = GENTICS.Utils.Dom.searchAdjacentTextNode(newBreak.parent().get(0), GENTICS.Utils.Dom.getIndexInParent(newBreak.get(0)) + 1, false);
|
|
||||||
if (nextTextNode) {
|
|
||||||
// trim leading whitespace
|
|
||||||
nonWSIndex = nextTextNode.data.search(/\S/);
|
|
||||||
if (nonWSIndex > 0) {
|
|
||||||
nextTextNode.data = nextTextNode.data.substring(nonWSIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
range.startContainer = range.endContainer = newBreak.get(0).parentNode;
|
|
||||||
range.startOffset = range.endOffset = GENTICS.Utils.Dom.getIndexInParent(newBreak.get(0)) + 1;
|
|
||||||
range.correctRange();
|
|
||||||
range.clearCaches();
|
|
||||||
range.select();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* first method to handle key strokes
|
|
||||||
* @param event DOM event
|
|
||||||
* @param rangeObject as provided by Aloha.Selection.getRangeObject();
|
|
||||||
* @return "Aloha.Selection"
|
|
||||||
*/
|
|
||||||
preProcessKeyStrokes: function(event) {
|
|
||||||
if (event.type != 'keydown') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var rangeObject = Aloha.Selection.rangeObject,
|
|
||||||
handlers,
|
|
||||||
i;
|
|
||||||
|
|
||||||
if (this.keyHandlers[event.keyCode]) {
|
|
||||||
handlers = this.keyHandlers[event.keyCode];
|
|
||||||
for ( i = 0; i < handlers.length; ++i) {
|
|
||||||
if (!handlers[i](event)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle left (37) and right (39) keys for block detection
|
|
||||||
if (event.keyCode === 37 || event.keyCode === 39) {
|
|
||||||
return this.processCursor(rangeObject, event.keyCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
// BACKSPACE
|
|
||||||
if (event.keyCode === 8) {
|
|
||||||
event.preventDefault(); // prevent history.back() even on exception
|
|
||||||
Aloha.execCommand( 'delete', false );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// DELETE
|
|
||||||
if (event.keyCode === 46) {
|
|
||||||
Aloha.execCommand( 'forwarddelete', false );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ENTER
|
|
||||||
if (event.keyCode === 13 ) {
|
|
||||||
if (event.shiftKey) {
|
|
||||||
Aloha.execCommand( 'insertlinebreak', false );
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
Aloha.execCommand( 'insertparagraph', false );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processing of cursor keys
|
|
||||||
* will currently detect blocks (elements with contenteditable=false)
|
|
||||||
* and selects them (normally the cursor would jump right past them)
|
|
||||||
*
|
|
||||||
* For each block an 'aloha-block-selected' event will be triggered.
|
|
||||||
*
|
|
||||||
* @param range the current range object
|
|
||||||
* @param keyCode keyCode of current keypress
|
|
||||||
* @return false if a block was found to prevent further events, true otherwise
|
|
||||||
*/
|
|
||||||
processCursor: function(range, keyCode) {
|
|
||||||
var rt = range.getRangeTree(), // RangeTree reference
|
|
||||||
i = 0,
|
|
||||||
cursorLeft = keyCode === 37,
|
|
||||||
cursorRight = keyCode === 39,
|
|
||||||
nextSiblingIsBlock = false, // check whether the next sibling is a block (contenteditable = false)
|
|
||||||
cursorIsWithinBlock = false, // check whether the cursor is positioned within a block (contenteditable = false)
|
|
||||||
cursorAtLastPos = false, // check if the cursor is within the last position of the currently active dom element
|
|
||||||
obj; // will contain references to dom objects
|
|
||||||
|
|
||||||
if ( !range.isCollapsed() ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;i < rt.length; i++) {
|
|
||||||
if ( typeof rt[i].domobj !== 'undefined' ) {
|
|
||||||
cursorAtLastPos = range.startOffset === rt[i].domobj.length;
|
|
||||||
if (cursorAtLastPos) {
|
|
||||||
nextSiblingIsBlock = jQuery( rt[i].domobj.nextSibling ).attr('contenteditable') === 'false';
|
|
||||||
cursorIsWithinBlock = jQuery( rt[i].domobj ).parents('[contenteditable=false]').length > 0;
|
|
||||||
|
|
||||||
if ( cursorRight && nextSiblingIsBlock ) {
|
|
||||||
obj = rt[i].domobj.nextSibling;
|
|
||||||
GENTICS.Utils.Dom.selectDomNode( obj );
|
|
||||||
Aloha.trigger( 'aloha-block-selected', obj );
|
|
||||||
Aloha.Selection.preventSelectionChanged();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( cursorLeft && cursorIsWithinBlock ) {
|
|
||||||
obj = jQuery( rt[i].domobj ).parents('[contenteditable=false]').get(0);
|
|
||||||
GENTICS.Utils.Dom.selectDomNode( obj );
|
|
||||||
Aloha.trigger( 'aloha-block-selected', obj );
|
|
||||||
Aloha.Selection.preventSelectionChanged();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* method handling shiftEnter
|
|
||||||
* @param Aloha.Selection.SelectionRange of the current selection
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
processShiftEnter: function(rangeObject) {
|
|
||||||
this.insertHTMLBreak(rangeObject.getSelectionTree(), rangeObject);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* method handling Enter
|
|
||||||
* @param Aloha.Selection.SelectionRange of the current selection
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
processEnter: function(rangeObject) {
|
|
||||||
if (rangeObject.splitObject) {
|
|
||||||
// now comes a very evil hack for ie, when the enter is pressed in a text node in an li element, we just append an empty text node
|
|
||||||
// if (jQuery.browser.msie
|
|
||||||
// && GENTICS.Utils.Dom
|
|
||||||
// .isListElement(rangeObject.splitObject)) {
|
|
||||||
// jQuery(rangeObject.splitObject).append(
|
|
||||||
// jQuery(document.createTextNode('')));
|
|
||||||
// }
|
|
||||||
|
|
||||||
this.splitRangeObject(rangeObject);
|
|
||||||
} else { // if there is no split object, the Editable is the paragraph type itself (e.g. a p or h2)
|
|
||||||
this.insertHTMLBreak(rangeObject.getSelectionTree(), rangeObject);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert the given html markup at the current selection
|
|
||||||
* @param html html markup to be inserted
|
|
||||||
*/
|
|
||||||
insertHTMLCode: function (html) {
|
|
||||||
var rangeObject = Aloha.Selection.rangeObject;
|
|
||||||
|
|
||||||
this.insertHTMLBreak(rangeObject.getSelectionTree(), rangeObject, jQuery(html));
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* insert an HTML Break <br /> into current selection
|
|
||||||
* @param Aloha.Selection.SelectionRange of the current selection
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
insertHTMLBreak: function(selectionTree, rangeObject, inBetweenMarkup) {
|
|
||||||
var i, treeLength, el, jqEl, jqElBefore, jqElAfter, tmpObject, offset, checkObj;
|
|
||||||
|
|
||||||
inBetweenMarkup = inBetweenMarkup ? inBetweenMarkup: jQuery('<br/>');
|
|
||||||
for ( i = 0, treeLength = selectionTree.length; i < treeLength; i++) {
|
|
||||||
el = selectionTree[i];
|
|
||||||
jqEl = el.domobj ? jQuery(el.domobj) : undefined;
|
|
||||||
if (el.selection !== 'none') { // before cursor, leave this part inside the splitObject
|
|
||||||
if (el.selection == 'collapsed') {
|
|
||||||
// collapsed selection found (between nodes)
|
|
||||||
if (i > 0) {
|
|
||||||
// not at the start, so get the element to the left
|
|
||||||
jqElBefore = jQuery(selectionTree[i-1].domobj);
|
|
||||||
// and insert the break after it
|
|
||||||
jqElBefore.after(inBetweenMarkup);
|
|
||||||
} else {
|
|
||||||
// at the start, so get the element to the right
|
|
||||||
jqElAfter = jQuery(selectionTree[1].domobj);
|
|
||||||
// and insert the break before it
|
|
||||||
jqElAfter.before(inBetweenMarkup);
|
|
||||||
}
|
|
||||||
|
|
||||||
// now set the range
|
|
||||||
rangeObject.startContainer = rangeObject.endContainer = inBetweenMarkup[0].parentNode;
|
|
||||||
rangeObject.startOffset = rangeObject.endOffset = GENTICS.Utils.Dom.getIndexInParent(inBetweenMarkup[0]) + 1;
|
|
||||||
rangeObject.correctRange();
|
|
||||||
} else if (el.domobj && el.domobj.nodeType === 3) { // textNode
|
|
||||||
// when the textnode is immediately followed by a blocklevel element (like p, h1, ...) we need to add an additional br in between
|
|
||||||
if (el.domobj.nextSibling
|
|
||||||
&& el.domobj.nextSibling.nodeType == 1
|
|
||||||
&& Aloha.Selection.replacingElements[el.domobj.nextSibling.nodeName
|
|
||||||
.toLowerCase()]) {
|
|
||||||
// TODO check whether this depends on the browser
|
|
||||||
jqEl.after('<br/>');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.needEndingBreak()) {
|
|
||||||
// when the textnode is the last inside a blocklevel element
|
|
||||||
// (like p, h1, ...) we need to add an additional br as very
|
|
||||||
// last object in the blocklevel element
|
|
||||||
checkObj = el.domobj;
|
|
||||||
while (checkObj) {
|
|
||||||
if (checkObj.nextSibling) {
|
|
||||||
checkObj = false;
|
|
||||||
} else {
|
|
||||||
// go to the parent
|
|
||||||
checkObj = checkObj.parentNode;
|
|
||||||
// found a blocklevel or list element, we are done
|
|
||||||
if (GENTICS.Utils.Dom.isBlockLevelElement(checkObj) || GENTICS.Utils.Dom.isListElement(checkObj)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// reached the limit object, we are done
|
|
||||||
if (checkObj === rangeObject.limitObject) {
|
|
||||||
checkObj = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// when we found a blocklevel element, insert a break at the
|
|
||||||
// end. Mark the break so that it is cleaned when the
|
|
||||||
// content is fetched.
|
|
||||||
if (checkObj) {
|
|
||||||
jQuery(checkObj).append('<br class="aloha-cleanme"/>');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert the break
|
|
||||||
jqEl.between(inBetweenMarkup, el.startOffset);
|
|
||||||
|
|
||||||
// correct the range
|
|
||||||
// count the number of previous siblings
|
|
||||||
offset = 0;
|
|
||||||
tmpObject = inBetweenMarkup[0];
|
|
||||||
while (tmpObject) {
|
|
||||||
tmpObject = tmpObject.previousSibling;
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
|
|
||||||
rangeObject.startContainer = inBetweenMarkup[0].parentNode;
|
|
||||||
rangeObject.endContainer = inBetweenMarkup[0].parentNode;
|
|
||||||
rangeObject.startOffset = offset;
|
|
||||||
rangeObject.endOffset = offset;
|
|
||||||
rangeObject.correctRange();
|
|
||||||
} else if (el.domobj && el.domobj.nodeType === 1) { // other node, normally a break
|
|
||||||
if (jqEl.parent().find('br.aloha-ephemera').length === 0) {
|
|
||||||
// but before putting it, remove all:
|
|
||||||
jQuery(rangeObject.limitObject).find('br.aloha-ephemera').remove();
|
|
||||||
// now put it:
|
|
||||||
jQuery(rangeObject.commonAncestorContainer).append(this.getFillUpElement(rangeObject.splitObject));
|
|
||||||
}
|
|
||||||
jqEl.after(inBetweenMarkup);
|
|
||||||
|
|
||||||
// now set the selection. Since we just added one break do the currect el
|
|
||||||
// the new position must be el's position + 1. el's position is the index
|
|
||||||
// of the el in the selection tree, which is i. then we must add
|
|
||||||
// another +1 because we want to be AFTER the object, not before. therefor +2
|
|
||||||
rangeObject.startContainer = rangeObject.commonAncestorContainer;
|
|
||||||
rangeObject.endContainer = rangeObject.startContainer;
|
|
||||||
rangeObject.startOffset = i+2;
|
|
||||||
rangeObject.endOffset = i+2;
|
|
||||||
rangeObject.update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rangeObject.select();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether blocklevel elements need breaks at the end to visibly render a newline
|
|
||||||
* @return true if an ending break is necessary, false if not
|
|
||||||
*/
|
|
||||||
needEndingBreak: function () {
|
|
||||||
// currently, all browser except IE need ending breaks
|
|
||||||
return !jQuery.browser.msie;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the currently selected text or false if nothing is selected (or the selection is collapsed)
|
|
||||||
* @return selected text
|
|
||||||
*/
|
|
||||||
getSelectedText: function () {
|
|
||||||
var rangeObject = Aloha.Selection.rangeObject;
|
|
||||||
|
|
||||||
if (rangeObject.isCollapsed()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.getFromSelectionTree(rangeObject.getSelectionTree(), true);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recursive function to get the selected text from the selection tree starting at the given level
|
|
||||||
* @param selectionTree array of selectiontree elements
|
|
||||||
* @param astext true when the contents shall be fetched as text, false for getting as html markup
|
|
||||||
* @return selected text from that level (incluiding all sublevels)
|
|
||||||
*/
|
|
||||||
getFromSelectionTree: function (selectionTree, astext) {
|
|
||||||
var text = '', i, treeLength, el, clone;
|
|
||||||
for ( i = 0, treeLength = selectionTree.length; i < treeLength; i++) {
|
|
||||||
el = selectionTree[i];
|
|
||||||
if (el.selection == 'partial') {
|
|
||||||
if (el.domobj.nodeType === 3) {
|
|
||||||
// partial text node selected, get the selected part
|
|
||||||
text += el.domobj.data.substring(el.startOffset, el.endOffset);
|
|
||||||
} else if (el.domobj.nodeType === 1 && el.children) {
|
|
||||||
// partial element node selected, do the recursion into the children
|
|
||||||
if (astext) {
|
|
||||||
text += this.getFromSelectionTree(el.children, astext);
|
|
||||||
} else {
|
|
||||||
// when the html shall be fetched, we create a clone of the element and remove all the children
|
|
||||||
clone = jQuery(el.domobj).clone(false).empty();
|
|
||||||
// then we do the recursion and add the selection into the clone
|
|
||||||
clone.html(this.getFromSelectionTree(el.children, astext));
|
|
||||||
// finally we get the html of the clone
|
|
||||||
text += clone.outerHTML();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (el.selection == 'full') {
|
|
||||||
if (el.domobj.nodeType === 3) {
|
|
||||||
// full text node selected, get the text
|
|
||||||
text += jQuery(el.domobj).text();
|
|
||||||
} else if (el.domobj.nodeType === 1 && el.children) {
|
|
||||||
// full element node selected, get the html of the node and all children
|
|
||||||
text += astext ? jQuery(el.domobj).text() : jQuery(el.domobj).outerHTML();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return text;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the currently selected markup or false if nothing is selected (or the selection is collapsed)
|
|
||||||
* @return selected markup
|
|
||||||
*/
|
|
||||||
getSelectedMarkup: function () {
|
|
||||||
var rangeObject = Aloha.Selection.rangeObject;
|
|
||||||
|
|
||||||
if (rangeObject.isCollapsed()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.getFromSelectionTree(rangeObject.getSelectionTree(), false);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the currently selected markup
|
|
||||||
|
|
||||||
*/
|
|
||||||
removeSelectedMarkup: function () {
|
|
||||||
var rangeObject = Aloha.Selection.rangeObject, newRange;
|
|
||||||
|
|
||||||
if (rangeObject.isCollapsed()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
newRange = new Aloha.Selection.SelectionRange();
|
|
||||||
// remove the selection
|
|
||||||
this.removeFromSelectionTree(rangeObject.getSelectionTree(), newRange);
|
|
||||||
|
|
||||||
// do a cleanup now (starting with the commonancestorcontainer)
|
|
||||||
newRange.update();
|
|
||||||
GENTICS.Utils.Dom.doCleanup({'merge' : true, 'removeempty' : true}, Aloha.Selection.rangeObject);
|
|
||||||
Aloha.Selection.rangeObject = newRange;
|
|
||||||
|
|
||||||
// need to set the collapsed selection now
|
|
||||||
newRange.correctRange();
|
|
||||||
newRange.update();
|
|
||||||
newRange.select();
|
|
||||||
Aloha.Selection.updateSelection();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recursively remove the selected items, starting with the given level in the selectiontree
|
|
||||||
* @param selectionTree current level of the selectiontree
|
|
||||||
* @param newRange new collapsed range to be set after the removal
|
|
||||||
*/
|
|
||||||
removeFromSelectionTree: function (selectionTree, newRange) {
|
|
||||||
// remember the first found partially selected element node (in case we need
|
|
||||||
// to merge it with the last found partially selected element node)
|
|
||||||
var firstPartialElement, newdata, i, el, adjacentTextNode, treeLength;
|
|
||||||
|
|
||||||
// iterate through the selection tree
|
|
||||||
for (i = 0, treeLength = selectionTree.length; i < treeLength; i++) {
|
|
||||||
el = selectionTree[i];
|
|
||||||
// check the type of selection
|
|
||||||
if (el.selection == 'partial') {
|
|
||||||
if (el.domobj.nodeType === 3) {
|
|
||||||
// partial text node selected, so remove the selected portion
|
|
||||||
newdata = '';
|
|
||||||
if (el.startOffset > 0) {
|
|
||||||
newdata += el.domobj.data.substring(0, el.startOffset);
|
|
||||||
}
|
|
||||||
if (el.endOffset < el.domobj.data.length) {
|
|
||||||
newdata += el.domobj.data.substring(el.endOffset, el.domobj.data.length);
|
|
||||||
}
|
|
||||||
el.domobj.data = newdata;
|
|
||||||
|
|
||||||
// eventually set the new range (if not done before)
|
|
||||||
if (!newRange.startContainer) {
|
|
||||||
newRange.startContainer = newRange.endContainer = el.domobj;
|
|
||||||
newRange.startOffset = newRange.endOffset = el.startOffset;
|
|
||||||
}
|
|
||||||
} else if (el.domobj.nodeType === 1 && el.children) {
|
|
||||||
// partial element node selected, so do the recursion into the children
|
|
||||||
this.removeFromSelectionTree(el.children, newRange);
|
|
||||||
if (firstPartialElement) {
|
|
||||||
// when the first parially selected element is the same type
|
|
||||||
// of element, we need to merge them
|
|
||||||
if (firstPartialElement.nodeName == el.domobj.nodeName) {
|
|
||||||
// merge the nodes
|
|
||||||
jQuery(firstPartialElement).append(jQuery(el.domobj).contents());
|
|
||||||
// and remove the latter one
|
|
||||||
jQuery(el.domobj).remove();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// remember this element as first partially selected element
|
|
||||||
firstPartialElement = el.domobj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (el.selection == 'full') {
|
|
||||||
// eventually set the new range (if not done before)
|
|
||||||
if (!newRange.startContainer) {
|
|
||||||
adjacentTextNode = GENTICS.Utils.Dom.searchAdjacentTextNode(el.domobj.parentNode, GENTICS.Utils.Dom.getIndexInParent(el.domobj) + 1, false, {'blocklevel' : false});
|
|
||||||
if (adjacentTextNode) {
|
|
||||||
newRange.startContainer = newRange.endContainer = adjacentTextNode;
|
|
||||||
newRange.startOffset = newRange.endOffset = 0;
|
|
||||||
} else {
|
|
||||||
newRange.startContainer = newRange.endContainer = el.domobj.parentNode;
|
|
||||||
newRange.startOffset = newRange.endOffset = GENTICS.Utils.Dom.getIndexInParent(el.domobj) + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// full node selected, so just remove it (will also remove all children)
|
|
||||||
jQuery(el.domobj).remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* split passed rangeObject without or with optional markup
|
|
||||||
* @param Aloha.Selection.SelectionRange of the current selection
|
|
||||||
* @param markup object (jQuery) to insert in between the split elements
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
splitRangeObject: function(rangeObject, markup) {
|
|
||||||
// UAAAA: first check where the markup can be inserted... *grrrrr*, then decide where to split
|
|
||||||
// object which is split up
|
|
||||||
var
|
|
||||||
splitObject = jQuery(rangeObject.splitObject),
|
|
||||||
selectionTree, insertAfterObject, followUpContainer;
|
|
||||||
|
|
||||||
// update the commonAncestor with the splitObject (so that the selectionTree is correct)
|
|
||||||
rangeObject.update(rangeObject.splitObject); // set the splitObject as new commonAncestorContainer and update the selectionTree
|
|
||||||
|
|
||||||
// calculate the selection tree. NOTE: it is necessary to do this before
|
|
||||||
// getting the followupcontainer, since getting the selection tree might
|
|
||||||
// possibly merge text nodes, which would lead to differences in the followupcontainer
|
|
||||||
selectionTree = rangeObject.getSelectionTree();
|
|
||||||
|
|
||||||
// object to be inserted after the splitObject
|
|
||||||
followUpContainer = this.getSplitFollowUpContainer(rangeObject);
|
|
||||||
|
|
||||||
// now split up the splitObject into itself AND the followUpContainer
|
|
||||||
this.splitRangeObjectHelper(selectionTree, rangeObject, followUpContainer); // split the current object into itself and the followUpContainer
|
|
||||||
|
|
||||||
// check whether the followupcontainer is still marked for removal
|
|
||||||
if (followUpContainer.hasClass('preparedForRemoval')) {
|
|
||||||
// TODO shall we just remove the class or shall we not use the followupcontainer?
|
|
||||||
followUpContainer.removeClass('preparedForRemoval');
|
|
||||||
}
|
|
||||||
|
|
||||||
// now let's find the place, where the followUp is inserted afterwards. normally that's the splitObject itself, but in
|
|
||||||
// some cases it might be their parent (e.g. inside a list, a <p> followUp must be inserted outside the list)
|
|
||||||
insertAfterObject = this.getInsertAfterObject(rangeObject, followUpContainer);
|
|
||||||
|
|
||||||
// now insert the followUpContainer
|
|
||||||
jQuery(followUpContainer).insertAfter(insertAfterObject); // attach the followUpContainer right after the insertAfterObject
|
|
||||||
|
|
||||||
// in some cases, we want to remove the "empty" splitObject (e.g. LIs, if enter was hit twice)
|
|
||||||
if (rangeObject.splitObject.nodeName.toLowerCase() === 'li' && !Aloha.Selection.standardTextLevelSemanticsComparator(rangeObject.splitObject, followUpContainer)) {
|
|
||||||
jQuery(rangeObject.splitObject).remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
rangeObject.startContainer = null;
|
|
||||||
// first check whether the followUpContainer starts with a <br/>
|
|
||||||
// if so, place the cursor right before the <br/>
|
|
||||||
var followContents = followUpContainer.contents();
|
|
||||||
if (followContents.length > 0
|
|
||||||
&& followContents.get(0).nodeType == 1
|
|
||||||
&& followContents.get(0).nodeName.toLowerCase() === 'br') {
|
|
||||||
rangeObject.startContainer = followUpContainer.get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rangeObject.startContainer) {
|
|
||||||
// find a possible text node in the followUpContainer and set the selection to it
|
|
||||||
// if no textnode is available, set the selection to the followup container itself
|
|
||||||
rangeObject.startContainer = followUpContainer.textNodes(true, true).first().get(0);
|
|
||||||
}
|
|
||||||
if (!rangeObject.startContainer) { // if no text node was found, select the parent object of <br class="aloha-ephemera" />
|
|
||||||
rangeObject.startContainer = followUpContainer.textNodes(false).first().parent().get(0);
|
|
||||||
}
|
|
||||||
if (rangeObject.startContainer) {
|
|
||||||
// the cursor is always at the beginning of the followUp
|
|
||||||
rangeObject.endContainer = rangeObject.startContainer;
|
|
||||||
rangeObject.startOffset = 0;
|
|
||||||
rangeObject.endOffset = 0;
|
|
||||||
} else {
|
|
||||||
rangeObject.startContainer = rangeObject.endContainer = followUpContainer.parent().get(0);
|
|
||||||
rangeObject.startOffset = rangeObject.endOffset = GENTICS.Utils.Dom.getIndexInParent(followUpContainer.get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
// finally update the range object again
|
|
||||||
rangeObject.update();
|
|
||||||
|
|
||||||
// now set the selection
|
|
||||||
rangeObject.select();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* method to get the object after which the followUpContainer can be inserted during splitup
|
|
||||||
* this is a helper method, not needed anywhere else
|
|
||||||
* @param rangeObject Aloha.Selection.SelectionRange of the current selection
|
|
||||||
* @param followUpContainer optional jQuery object; if provided the rangeObject will be split and the second part will be insert inside of this object
|
|
||||||
* @return object after which the followUpContainer can be inserted
|
|
||||||
*/
|
|
||||||
getInsertAfterObject: function(rangeObject, followUpContainer) {
|
|
||||||
var passedSplitObject,i,el;
|
|
||||||
|
|
||||||
for (i = 0; i < rangeObject.markupEffectiveAtStart.length; i++) {
|
|
||||||
el = rangeObject.markupEffectiveAtStart[ i ];
|
|
||||||
// check if we have already passed the splitObject (some other markup might come before)
|
|
||||||
if (el === rangeObject.splitObject){
|
|
||||||
passedSplitObject = true;
|
|
||||||
}
|
|
||||||
// if not passed splitObject, skip this markup
|
|
||||||
if (!passedSplitObject) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// once we are passed, check if the followUpContainer is allowed to be inserted into the currents el's parent
|
|
||||||
if (Aloha.Selection.canTag1WrapTag2(jQuery(el).parent()[0].nodeName, followUpContainer[0].nodeName)) {
|
|
||||||
return el;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* method to get the html code for a fillUpElement. this is needed for empty paragraphs etc., so that they take up their expected height
|
|
||||||
* @param splitObject split object (dom object)
|
|
||||||
* @return fillUpElement HTML Code
|
|
||||||
*/
|
|
||||||
getFillUpElement: function(splitObject) {
|
|
||||||
if (jQuery.browser.msie) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return jQuery('<br class="aloha-cleanme"/>');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* removes textNodes from passed array, which only contain contentWhiteSpace (e.g. a \n between two tags)
|
|
||||||
* @param domArray array of domObjects
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
removeElementContentWhitespaceObj: function(domArray) {
|
|
||||||
var correction = 0,
|
|
||||||
removeLater = [],
|
|
||||||
i,
|
|
||||||
el, removeIndex;
|
|
||||||
|
|
||||||
for (i = 0; i < domArray.length; i++) {
|
|
||||||
el = domArray[i];
|
|
||||||
if (el.isElementContentWhitespace) {
|
|
||||||
removeLater[removeLater.length] = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < removeLater.length; i++) {
|
|
||||||
removeIndex = removeLater[i];
|
|
||||||
domArray.splice(removeIndex - correction, 1);
|
|
||||||
correction++;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* recursive method to parallelly walk through two dom subtrees, leave elements before startContainer in first subtree and move rest to other
|
|
||||||
* @param selectionTree tree to iterate over as contained in rangeObject. must be passed separately to allow recursion in the selection tree, but not in the rangeObject
|
|
||||||
* @param rangeObject Aloha.Selection.SelectionRange of the current selection
|
|
||||||
* @param followUpContainer optional jQuery object; if provided the rangeObject will be split and the second part will be insert inside of this object
|
|
||||||
* @param inBetweenMarkup jQuery object to be inserted between the two split parts. will be either a <br> (if no followUpContainer is passed) OR e.g. a table, which must be inserted between the splitobject AND the follow up
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
splitRangeObjectHelper: function(selectionTree, rangeObject, followUpContainer, inBetweenMarkup) {
|
|
||||||
if (!followUpContainer) {
|
|
||||||
Aloha.Log.warn(this, 'no followUpContainer, no inBetweenMarkup, nothing to do...');
|
|
||||||
}
|
|
||||||
|
|
||||||
var fillUpElement = this.getFillUpElement(rangeObject.splitObject),
|
|
||||||
splitObject = jQuery(rangeObject.splitObject),
|
|
||||||
startMoving = false,
|
|
||||||
el, i, completeText, jqObj, mirrorLevel, parent, treeLength;
|
|
||||||
|
|
||||||
if (selectionTree.length > 0) {
|
|
||||||
mirrorLevel = followUpContainer.contents();
|
|
||||||
|
|
||||||
// if length of mirrorLevel and selectionTree are not equal, the mirrorLevel must be corrected. this happens, when the mirrorLevel contains whitespace textNodes
|
|
||||||
if (mirrorLevel.length !== selectionTree.length) {
|
|
||||||
this.removeElementContentWhitespaceObj(mirrorLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0, treeLength = selectionTree.length; i < treeLength; i++) {
|
|
||||||
el = selectionTree[i];
|
|
||||||
// remove all objects in the mirrorLevel, which are BEFORE the cursor
|
|
||||||
// OR if the cursor is at the last position of the last Textnode (causing an empty followUpContainer to be appended)
|
|
||||||
if (
|
|
||||||
(el.selection === 'none' && startMoving === false) ||
|
|
||||||
(el.domobj && el.domobj.nodeType === 3 && el === selectionTree[ (selectionTree.length-1) ] && el.startOffset === el.domobj.data.length)
|
|
||||||
) {
|
|
||||||
// iteration is before cursor, leave this part inside the splitObject, remove from followUpContainer
|
|
||||||
// however if the object to remove is the last existing textNode within the followUpContainer, insert a BR instead
|
|
||||||
// otherwise the followUpContainer is invalid and takes up no vertical space
|
|
||||||
|
|
||||||
if (followUpContainer.textNodes().length > 1 || (el.domobj.nodeType === 1 && el.children.length === 0)) {
|
|
||||||
// note: the second part of the if (el.domobj.nodeType === 1 && el.children.length === 0) covers a very special condition,
|
|
||||||
// where an empty tag is located right before the cursor when pressing enter. In this case the empty tag would not be
|
|
||||||
// removed correctly otherwise
|
|
||||||
mirrorLevel.eq(i).remove();
|
|
||||||
} else if (GENTICS.Utils.Dom.isSplitObject(followUpContainer[0])) {
|
|
||||||
if (fillUpElement) {
|
|
||||||
followUpContainer.html(fillUpElement); // for your zoological german knowhow: ephemera = Eintagsfliege
|
|
||||||
} else {
|
|
||||||
followUpContainer.empty();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
followUpContainer.empty();
|
|
||||||
followUpContainer.addClass('preparedForRemoval');
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
// split objects, which are AT the cursor Position or directly above
|
|
||||||
if (el.selection !== 'none') { // before cursor, leave this part inside the splitObject
|
|
||||||
// TODO better check for selection == 'partial' here?
|
|
||||||
if (el.domobj && el.domobj.nodeType === 3 && el.startOffset !== undefined) {
|
|
||||||
completeText = el.domobj.data;
|
|
||||||
if (el.startOffset > 0) {// first check, if there will be some text left in the splitObject
|
|
||||||
el.domobj.data = completeText.substr(0, el.startOffset);
|
|
||||||
} else if (selectionTree.length > 1) { // if not, check if the splitObject contains more than one node, because then it can be removed. this happens, when ENTER is pressed inside of a textnode, but not at the borders
|
|
||||||
jQuery(el.domobj).remove();
|
|
||||||
} else { // if the "empty" textnode is the last node left in the splitObject, replace it with a ephemera break
|
|
||||||
// if the parent is a blocklevel element, we insert the fillup element
|
|
||||||
parent = jQuery(el.domobj).parent();
|
|
||||||
if (GENTICS.Utils.Dom.isSplitObject(parent[0])) {
|
|
||||||
if (fillUpElement) {
|
|
||||||
parent.html(fillUpElement);
|
|
||||||
} else {
|
|
||||||
parent.empty();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// if the parent is no blocklevel element and would be empty now, we completely remove it
|
|
||||||
parent.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (completeText.length - el.startOffset > 0) {
|
|
||||||
// first check if there is text left to put in the followUpContainer's textnode. this happens, when ENTER is pressed inside of a textnode, but not at the borders
|
|
||||||
mirrorLevel[i].data = completeText.substr(el.startOffset, completeText.length);
|
|
||||||
} else if (mirrorLevel.length > 1) {
|
|
||||||
// if not, check if the followUpContainer contains more than one node, because if yes, the "empty" textnode can be removed
|
|
||||||
mirrorLevel.eq( (i) ).remove();
|
|
||||||
} else if (GENTICS.Utils.Dom.isBlockLevelElement(followUpContainer[0])) {
|
|
||||||
// if the "empty" textnode is the last node left in the followUpContainer (which is a blocklevel element), replace it with a ephemera break
|
|
||||||
if (fillUpElement) {
|
|
||||||
followUpContainer.html(fillUpElement);
|
|
||||||
} else {
|
|
||||||
followUpContainer.empty();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// if the "empty" textnode is the last node left in a non-blocklevel element, mark it for removal
|
|
||||||
followUpContainer.empty();
|
|
||||||
followUpContainer.addClass('preparedForRemoval');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
startMoving = true;
|
|
||||||
if (el.children.length > 0) {
|
|
||||||
this.splitRangeObjectHelper(el.children, rangeObject, mirrorLevel.eq(i), inBetweenMarkup);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// remove all objects in the origin, which are AFTER the cursor
|
|
||||||
if (el.selection === 'none' && startMoving === true) {
|
|
||||||
// iteration is after cursor, remove from splitObject and leave this part inside the followUpContainer
|
|
||||||
jqObj = jQuery(el.domobj).remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Aloha.Log.error(this, 'can not split splitObject due to an empty selection tree');
|
|
||||||
}
|
|
||||||
|
|
||||||
// and finally cleanup: remove all fillUps > 1
|
|
||||||
splitObject.find('br.aloha-ephemera:gt(0)').remove(); // remove all elements greater than (gt) 0, that also means: leave one
|
|
||||||
followUpContainer.find('br.aloha-ephemera:gt(0)').remove(); // remove all elements greater than (gt) 0, that also means: leave one
|
|
||||||
|
|
||||||
// remove objects prepared for removal
|
|
||||||
splitObject.find('.preparedForRemoval').remove();
|
|
||||||
followUpContainer.find('.preparedForRemoval').remove();
|
|
||||||
|
|
||||||
// if splitObject / followUp are empty, place a fillUp inside
|
|
||||||
if (splitObject.contents().length === 0 && GENTICS.Utils.Dom.isSplitObject(splitObject[0]) && fillUpElement) {
|
|
||||||
splitObject.html(fillUpElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (followUpContainer.contents().length === 0 && GENTICS.Utils.Dom.isSplitObject(followUpContainer[0]) && fillUpElement) {
|
|
||||||
followUpContainer.html(fillUpElement);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* returns a jQuery object fitting the passed splitObject as follow up object
|
|
||||||
* examples,
|
|
||||||
* - when passed a p it will return an empty p (clone of the passed p)
|
|
||||||
* - when passed an h1, it will return either an h1 (clone of the passed one) or a new p (if the collapsed selection was at the end)
|
|
||||||
* @param rangeObject Aloha.RangeObject
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
getSplitFollowUpContainer: function(rangeObject) {
|
|
||||||
var
|
|
||||||
tagName = rangeObject.splitObject.nodeName.toLowerCase(),
|
|
||||||
returnObj, inside, lastObj;
|
|
||||||
|
|
||||||
switch(tagName) {
|
|
||||||
case 'h1':
|
|
||||||
case 'h2':
|
|
||||||
case 'h3':
|
|
||||||
case 'h4':
|
|
||||||
case 'h5':
|
|
||||||
case 'h6':
|
|
||||||
// get the last textnode in the splitobject, but don't consider aloha-cleanme elements
|
|
||||||
lastObj = jQuery(rangeObject.splitObject).textNodes(':not(.aloha-cleanme)').last()[0];
|
|
||||||
// special case: when enter is hit at the end of a heading, the followUp should be a <p>
|
|
||||||
if (lastObj && rangeObject.startContainer === lastObj && rangeObject.startOffset === lastObj.length) {
|
|
||||||
returnObj = jQuery('<p></p>');
|
|
||||||
inside = jQuery(rangeObject.splitObject).clone().contents();
|
|
||||||
returnObj.append(inside);
|
|
||||||
return returnObj;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'li':
|
|
||||||
// TODO check whether the li is the last one
|
|
||||||
// special case: if enter is hit twice inside a list, the next item should be a <p> (and inserted outside the list)
|
|
||||||
if (rangeObject.startContainer.nodeName.toLowerCase() === 'br' && jQuery(rangeObject.startContainer).hasClass('aloha-ephemera')) {
|
|
||||||
returnObj = jQuery('<p></p>');
|
|
||||||
inside = jQuery(rangeObject.splitObject).clone().contents();
|
|
||||||
returnObj.append(inside);
|
|
||||||
return returnObj;
|
|
||||||
}
|
|
||||||
// when the li is the last one and empty, we also just return a <p>
|
|
||||||
if (!rangeObject.splitObject.nextSibling && jQuery.trim(jQuery(rangeObject.splitObject).text()).length === 0) {
|
|
||||||
returnObj = jQuery('<p></p>');
|
|
||||||
return returnObj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return jQuery(rangeObject.splitObject).clone();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transform the given domobj into an object with the given new nodeName.
|
|
||||||
* Preserves the content and all attributes. If a range object is given, also the range will be preserved
|
|
||||||
* @param domobj dom object to transform
|
|
||||||
* @param nodeName new node name
|
|
||||||
* @param range range object
|
|
||||||
* @api
|
|
||||||
* @return new object as jQuery object
|
|
||||||
*/
|
|
||||||
transformDomObject: function (domobj, nodeName, range) {
|
|
||||||
// first create the new element
|
|
||||||
var
|
|
||||||
jqOldObj = jQuery(domobj),
|
|
||||||
jqNewObj = jQuery('<' + nodeName + '></' + nodeName + '>'),
|
|
||||||
i;
|
|
||||||
|
|
||||||
// TODO what about events? css properties?
|
|
||||||
|
|
||||||
// copy attributes
|
|
||||||
if (jqOldObj[0].attributes) {
|
|
||||||
for (i = 0; i < jqOldObj[0].attributes.length; i++) {
|
|
||||||
jqNewObj.attr(jqOldObj[0].attributes[i].nodeName, jqOldObj[0].attributes[i].nodeValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy inline CSS
|
|
||||||
if (jqOldObj[0].style && jqOldObj[0].style.cssText) {
|
|
||||||
jqNewObj[0].style.cssText = jqOldObj[0].style.cssText;
|
|
||||||
}
|
|
||||||
|
|
||||||
// now move the contents of the old dom object into the new dom object
|
|
||||||
jqOldObj.contents().appendTo(jqNewObj);
|
|
||||||
|
|
||||||
// finally replace the old object with the new one
|
|
||||||
jqOldObj.replaceWith(jqNewObj);
|
|
||||||
|
|
||||||
// preserve the range
|
|
||||||
if (range) {
|
|
||||||
if (range.startContainer == domobj) {
|
|
||||||
range.startContainer = jqNewObj.get(0);
|
|
||||||
}
|
|
||||||
if (range.endContainer == domobj) {
|
|
||||||
range.endContainer = jqNewObj.get(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return jqNewObj;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* String representation
|
|
||||||
* @return "Aloha.Selection"
|
|
||||||
*/
|
|
||||||
toString: function() {
|
|
||||||
return 'Aloha.Markup';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Aloha.Markup = new Aloha.Markup();
|
|
||||||
|
|
||||||
return Aloha.Markup;
|
|
||||||
|
|
||||||
});
|
|
@ -1,115 +0,0 @@
|
|||||||
/*!
|
|
||||||
* This file is part of Aloha Editor Project http://aloha-editor.org
|
|
||||||
* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com
|
|
||||||
* Contributors http://aloha-editor.org/contribution.php
|
|
||||||
* Licensed unter the terms of http://www.aloha-editor.org/license.html
|
|
||||||
*//*
|
|
||||||
* Aloha Editor is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.*
|
|
||||||
*
|
|
||||||
* Aloha Editor is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
define(
|
|
||||||
['aloha/core', 'util/class', 'aloha/jquery'],
|
|
||||||
function( Aloha, Class, jQuery ) {
|
|
||||||
|
|
||||||
|
|
||||||
var
|
|
||||||
// Aloha = window.Aloha,
|
|
||||||
// Class = window.Class,
|
|
||||||
GENTICS = window.GENTICS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Message Object
|
|
||||||
* @namespace Aloha
|
|
||||||
* @class Message
|
|
||||||
* @constructor
|
|
||||||
* @param {Object} data object which contains the parts of the message
|
|
||||||
* title: the title
|
|
||||||
* text: the message text to be displayed
|
|
||||||
* type: one of Aloha.Message.Type
|
|
||||||
* callback: callback function, which will be triggered after the message was confirmed, closed or accepted
|
|
||||||
*/
|
|
||||||
Aloha.Message = Class.extend({
|
|
||||||
_constructor: function (data) {
|
|
||||||
this.title = data.title;
|
|
||||||
this.text = data.text;
|
|
||||||
this.type = data.type;
|
|
||||||
this.callback = data.callback;
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a textual representation of the message
|
|
||||||
* @return textual representation of the message
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
toString: function () {
|
|
||||||
return this.type + ': ' + this.message;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Message types enum. Contains all allowed types of messages
|
|
||||||
* @property
|
|
||||||
*/
|
|
||||||
Aloha.Message.Type = {
|
|
||||||
// reserved for messages
|
|
||||||
// SUCCESS : 'success',
|
|
||||||
// INFO : 'info',
|
|
||||||
// WARN : 'warn',
|
|
||||||
// CRITICAL : 'critical',
|
|
||||||
CONFIRM : 'confirm', // confirm dialog, like js confirm()
|
|
||||||
ALERT : 'alert', // alert dialog like js alert()
|
|
||||||
WAIT : 'wait' // wait dialog with loading bar. has to be hidden via Aloha.hideMessage()
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the message line
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
Aloha.MessageLine = Class.extend({
|
|
||||||
messages: [],
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a new message to the message line
|
|
||||||
* @param message message to add
|
|
||||||
* @return void
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
add: function(message) {
|
|
||||||
var messageline = '',
|
|
||||||
messagesLength = this.messages.length,
|
|
||||||
i;
|
|
||||||
|
|
||||||
// dummy implementation to add a message
|
|
||||||
this.messages[messagesLength] = message;
|
|
||||||
while(messagesLength > 4) {
|
|
||||||
this.messages.shift();
|
|
||||||
--messagesLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( i = 0; i < messagesLength; i++) {
|
|
||||||
messageline += this.messages[i].toString() + '<br/>';
|
|
||||||
}
|
|
||||||
jQuery('#gtx_aloha_messageline').html(messageline);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Message Line Object
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
Aloha.MessageLine = new Aloha.MessageLine();
|
|
||||||
|
|
||||||
});
|
|
@ -1,10 +0,0 @@
|
|||||||
define( {
|
|
||||||
'floatingmenu.tab.format': 'Formatieren',
|
|
||||||
'floatingmenu.tab.insert': 'Einf\u00fcgen',
|
|
||||||
'yes': 'Ja',
|
|
||||||
'no': 'Nein',
|
|
||||||
'cancel': 'Abbrechen',
|
|
||||||
'repository.no_item_found': 'Keinen Eintrag gefunden.',
|
|
||||||
'repository.loading': 'Es wird geladen',
|
|
||||||
'repository.no_items_found_yet': 'Noch keine Eintr\u00e4ge gefunden...'
|
|
||||||
} );
|
|
@ -1,10 +0,0 @@
|
|||||||
define( {
|
|
||||||
'floatingmenu.tab.format': 'Mise en page',
|
|
||||||
'floatingmenu.tab.insert': 'Insertion',
|
|
||||||
'yes': 'Oui',
|
|
||||||
'no': 'Non',
|
|
||||||
'cancel': 'Annuel',
|
|
||||||
'repository.no_item_found': 'Aucun élément trouvé.',
|
|
||||||
'repository.loading': 'Chargement',
|
|
||||||
'repository.no_items_found_yet': 'Aucun élément trouvé...'
|
|
||||||
} );
|
|
@ -1,21 +0,0 @@
|
|||||||
define( {
|
|
||||||
'root': {
|
|
||||||
'plugin.abbr.floatingmenu.tab.abbr': 'Abbreviation',
|
|
||||||
'floatingmenu.tab.format': 'Format',
|
|
||||||
'floatingmenu.tab.insert': 'Insert',
|
|
||||||
'yes': 'Yes',
|
|
||||||
'no': 'No',
|
|
||||||
'cancel': 'Cancel',
|
|
||||||
'repository.no_item_found': 'No item found.',
|
|
||||||
'repository.loading': 'Loading',
|
|
||||||
'repository.no_items_found_yet': 'No items found yet...'
|
|
||||||
},
|
|
||||||
'de': true,
|
|
||||||
'fr': true
|
|
||||||
/* 'eo': true,
|
|
||||||
'fi': true,
|
|
||||||
|
|
||||||
'it': true,
|
|
||||||
'pl': true,
|
|
||||||
'ru': true*/
|
|
||||||
} );
|
|
@ -1,106 +0,0 @@
|
|||||||
/*!
|
|
||||||
* This file is part of Aloha Editor Project http://aloha-editor.org
|
|
||||||
* Copyright <EFBFBD> 2010-2011 Gentics Software GmbH, aloha@gentics.com
|
|
||||||
* Contributors http://aloha-editor.org/contribution.php
|
|
||||||
* Licensed unter the terms of http://www.aloha-editor.org/license.html
|
|
||||||
*//*
|
|
||||||
* Aloha Editor is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.*
|
|
||||||
*
|
|
||||||
* Aloha Editor is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
define(
|
|
||||||
['aloha/jquery'],
|
|
||||||
function(jQuery, undefined) {
|
|
||||||
|
|
||||||
|
|
||||||
var
|
|
||||||
$ = jQuery;
|
|
||||||
|
|
||||||
return {
|
|
||||||
_eventHandlers: null,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attach a handler to an event
|
|
||||||
*
|
|
||||||
* @param {String} eventType A string containing the event name to bind to
|
|
||||||
* @param {Function} handler A function to execute each time the event is triggered
|
|
||||||
* @param {Object} scope Optional. Set the scope in which handler is executed
|
|
||||||
*/
|
|
||||||
bind: function(eventType, handler, scope) {
|
|
||||||
this._eventHandlers = this._eventHandlers || {};
|
|
||||||
if (!this._eventHandlers[eventType]) {
|
|
||||||
this._eventHandlers[eventType] = [];
|
|
||||||
}
|
|
||||||
this._eventHandlers[eventType].push({
|
|
||||||
handler: handler,
|
|
||||||
scope: (scope ? scope : window)
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a previously-attached event handler
|
|
||||||
*
|
|
||||||
* @param {String} eventType A string containing the event name to unbind
|
|
||||||
* @param {Function} handler The function that is to be no longer executed. Optional. If not given, unregisters all functions for the given event.
|
|
||||||
*/
|
|
||||||
unbind: function(eventType, handler) {
|
|
||||||
this._eventHandlers = this._eventHandlers || {};
|
|
||||||
if (!this._eventHandlers[eventType]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!handler) {
|
|
||||||
// No handler function given, unbind all event handlers for the eventType
|
|
||||||
this._eventHandlers[eventType] = [];
|
|
||||||
} else {
|
|
||||||
this._eventHandlers[eventType] = $.grep(this._eventHandlers[eventType], function(element) {
|
|
||||||
if (element.handler === handler) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute all handlers attached to the given event type.
|
|
||||||
* All arguments except the eventType are directly passed to the callback function.
|
|
||||||
*
|
|
||||||
* @param (String} eventType A string containing the event name for which the event handlers should be invoked.
|
|
||||||
*/
|
|
||||||
trigger: function(eventType) {
|
|
||||||
this._eventHandlers = this._eventHandlers || {};
|
|
||||||
if (!this._eventHandlers[eventType]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// preparedArguments contains all arguments except the first one.
|
|
||||||
var preparedArguments = [];
|
|
||||||
$.each(arguments, function(i, argument) {
|
|
||||||
if (i>0) {
|
|
||||||
preparedArguments.push(argument);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$.each(this._eventHandlers[eventType], function(index, element) {
|
|
||||||
element.handler.apply(element.scope, preparedArguments);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears all event handlers. Call this method when cleaning up.
|
|
||||||
*/
|
|
||||||
unbindAll: function() {
|
|
||||||
this._eventHandlers = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
@ -1,276 +0,0 @@
|
|||||||
/*!
|
|
||||||
* This file is part of Aloha Editor Project http://aloha-editor.org
|
|
||||||
* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com
|
|
||||||
* Contributors http://aloha-editor.org/contribution.php
|
|
||||||
* Licensed unter the terms of http://www.aloha-editor.org/license.html
|
|
||||||
*//*
|
|
||||||
* Aloha Editor is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.*
|
|
||||||
*
|
|
||||||
* Aloha Editor is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
define(
|
|
||||||
['aloha/core', 'aloha/jquery', 'util/class', 'aloha/pluginmanager', 'aloha/console'],
|
|
||||||
function(Aloha, jQuery, Class, PluginManager, console ) {
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract Plugin Object
|
|
||||||
* @namespace Aloha
|
|
||||||
* @class Plugin
|
|
||||||
* @constructor
|
|
||||||
* @param {String} pluginPrefix unique plugin prefix
|
|
||||||
*/
|
|
||||||
var Plugin = Class.extend({
|
|
||||||
|
|
||||||
name: null,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* contains the plugin's default settings object
|
|
||||||
* @cfg {Object} default settings for the plugin
|
|
||||||
*/
|
|
||||||
defaults: {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* contains the plugin's settings object
|
|
||||||
* @cfg {Object} settings the plugins settings stored in an object
|
|
||||||
*/
|
|
||||||
settings: {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Names of other plugins which must be loaded in order for this plugin to
|
|
||||||
* function.
|
|
||||||
* @cfg {Array}
|
|
||||||
*/
|
|
||||||
dependencies: [],
|
|
||||||
|
|
||||||
_constructor: function( name ) {
|
|
||||||
/**
|
|
||||||
* Settings of the plugin
|
|
||||||
*/
|
|
||||||
if (typeof name !== "string") {
|
|
||||||
console.error('Cannot initialise unnamed plugin, skipping');
|
|
||||||
} else {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if dependencies satisfied, false otherwise
|
|
||||||
*/
|
|
||||||
checkDependencies: function() {
|
|
||||||
var
|
|
||||||
dependenciesSatisfied = true,
|
|
||||||
that = this;
|
|
||||||
|
|
||||||
jQuery.each(this.dependencies, function() {
|
|
||||||
|
|
||||||
if (!Aloha.isPluginLoaded(this)) {
|
|
||||||
dependenciesSatisfied = false;
|
|
||||||
console.error('plugin.' + that.name, 'Required plugin "' + this + '" not found.');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return dependenciesSatisfied;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Init method of the plugin. Called from Aloha Core to initialize this plugin
|
|
||||||
* @return void
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
init: function() {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the configuration settings for an editable obj.
|
|
||||||
* Handles both conf arrays or conf objects
|
|
||||||
* <ul>
|
|
||||||
* <li>Array configuration parameters are:
|
|
||||||
* <pre>
|
|
||||||
* "list": {
|
|
||||||
* config : [ 'b', 'h1' ],
|
|
||||||
* editables : {
|
|
||||||
* '#title' : [ ],
|
|
||||||
* 'div' : [ 'b', 'i' ],
|
|
||||||
* '.article' : [ 'h1' ]
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* The hash keys of the editables are css selectors. For a
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* <div class="article">content</div>
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* the selectors 'div' and '.article' match and the returned configuration is
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* [ 'b', 'i', 'h1']
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* The '#title' object would return an empty configuration.
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* [ ]
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* All other objects would get the 'config' configuration. If config is not set
|
|
||||||
* the plugin default configuration is returned.
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* [ 'b', 'h1']
|
|
||||||
* </pre></li>
|
|
||||||
* <li>Object configuration parameters are :
|
|
||||||
* <pre>
|
|
||||||
* "image": {
|
|
||||||
* config : { 'img': { 'max_width': '50px',
|
|
||||||
* 'max_height': '50px' }},
|
|
||||||
* editables : {
|
|
||||||
* '#title': {},
|
|
||||||
* 'div': {'img': {}},
|
|
||||||
* '.article': {'img': { 'max_width': '150px',
|
|
||||||
* 'max_height': '150px' }}
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
* The '#title' object would return an empty configuration.<br/>
|
|
||||||
* The 'div' object would return the default configuration.<br/>
|
|
||||||
* the '.article' would return :
|
|
||||||
* <pre>
|
|
||||||
* {'img': { 'max_width': '150px',
|
|
||||||
* 'max_height': '150px' }}
|
|
||||||
* </pre>
|
|
||||||
* </li>
|
|
||||||
*
|
|
||||||
* @param {jQuery} obj jQuery object of an Editable Object
|
|
||||||
* @return {Array} config A Array with configuration entries
|
|
||||||
*/
|
|
||||||
getEditableConfig: function (obj) {
|
|
||||||
var configObj = null,
|
|
||||||
configSpecified = false,
|
|
||||||
that = this;
|
|
||||||
|
|
||||||
if ( this.settings.editables ) {
|
|
||||||
// check if the editable's selector matches and if so add its configuration to object configuration
|
|
||||||
jQuery.each( this.settings.editables, function (selector, selectorConfig) {
|
|
||||||
if ( obj.is(selector) ) {
|
|
||||||
configSpecified = true;
|
|
||||||
if (selectorConfig instanceof Array) {
|
|
||||||
configObj = [];
|
|
||||||
configObj = jQuery.merge(configObj, selectorConfig);
|
|
||||||
} else if (typeof selectorConfig === "object") {
|
|
||||||
configObj = {};
|
|
||||||
for (var k in selectorConfig) {
|
|
||||||
if ( selectorConfig.hasOwnProperty(k) ) {
|
|
||||||
if (selectorConfig[k] instanceof Array) {
|
|
||||||
|
|
||||||
} else if (typeof selectorConfig[k] === "object") {
|
|
||||||
configObj[k] = {};
|
|
||||||
configObj[k] = jQuery.extend(true, configObj[k], that.config[k], selectorConfig[k]);
|
|
||||||
} else {
|
|
||||||
configObj[k] = selectorConfig[k];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
configObj = selectorConfig;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// fall back to default configuration
|
|
||||||
if ( !configSpecified ) {
|
|
||||||
if ( typeof this.settings.config === 'undefined' || !this.settings.config ) {
|
|
||||||
configObj = this.config;
|
|
||||||
} else {
|
|
||||||
configObj = this.settings.config;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return configObj;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make the given jQuery object (representing an editable) clean for saving
|
|
||||||
* @param obj jQuery object to make clean
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
makeClean: function ( obj ) {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make a system-wide unique id out of a plugin-wide unique id by prefixing it with the plugin prefix
|
|
||||||
* @param id plugin-wide unique id
|
|
||||||
* @return system-wide unique id
|
|
||||||
* @hide
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
getUID: function(id) {
|
|
||||||
console.deprecated ('plugin', 'getUID() is deprecated. Use plugin.name instead.');
|
|
||||||
return this.name;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Localize the given key for the plugin.
|
|
||||||
* @param key key to be localized
|
|
||||||
* @param replacements array of replacement strings
|
|
||||||
* @return localized string
|
|
||||||
* @hide
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
i18n: function(key, replacements) {
|
|
||||||
console.deprecated ('plugin', 'i18n() is deprecated. Use plugin.t() instead.');
|
|
||||||
return Aloha.i18n(this, key, replacements);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return string representation of the plugin, which is the prefix
|
|
||||||
* @return name
|
|
||||||
* @hide
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
toString: function() {
|
|
||||||
return this.name;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log a plugin message to the logger
|
|
||||||
* @param level log level
|
|
||||||
* @param message log message
|
|
||||||
* @return void
|
|
||||||
* @hide
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
log: function (level, message) {
|
|
||||||
console.deprecated ('plugin', 'log() is deprecated. Use Aloha.console instead.');
|
|
||||||
console.log(level, this, message);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Static method used as factory to create plugins.
|
|
||||||
*
|
|
||||||
* @param {String} pluginName name of the plugin
|
|
||||||
* @param {Object} definition definition of the plugin, should have at least an "init" and "destroy" method.
|
|
||||||
*/
|
|
||||||
Plugin.create = function(pluginName, definition) {
|
|
||||||
|
|
||||||
var pluginInstance = new ( Plugin.extend( definition ) )( pluginName );
|
|
||||||
pluginInstance.settings = jQuery.extendObjects( true, pluginInstance.defaults, Aloha.settings[pluginName] );
|
|
||||||
PluginManager.register( pluginInstance );
|
|
||||||
|
|
||||||
return pluginInstance;
|
|
||||||
};
|
|
||||||
|
|
||||||
return Plugin;
|
|
||||||
});
|
|
@ -1,146 +0,0 @@
|
|||||||
/*!
|
|
||||||
* This file is part of Aloha Editor Project http://aloha-editor.org
|
|
||||||
* Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com
|
|
||||||
* Contributors http://aloha-editor.org/contribution.php
|
|
||||||
* Licensed unter the terms of http://www.aloha-editor.org/license.html
|
|
||||||
*//*
|
|
||||||
* Aloha Editor is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.*
|
|
||||||
*
|
|
||||||
* Aloha Editor is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Do not add dependencies that require depend on aloha/core
|
|
||||||
define(
|
|
||||||
[ 'aloha/jquery', 'util/class' ],
|
|
||||||
function( jQuery, Class ) {
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Plugin Manager controls the lifecycle of all Aloha Plugins.
|
|
||||||
*
|
|
||||||
* @namespace Aloha
|
|
||||||
* @class PluginManager
|
|
||||||
* @singleton
|
|
||||||
*/
|
|
||||||
return new (Class.extend({
|
|
||||||
plugins: {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize all registered plugins
|
|
||||||
* @return void
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
init: function(next, userPlugins) {
|
|
||||||
|
|
||||||
var
|
|
||||||
me = this,
|
|
||||||
globalSettings = ( Aloha && Aloha.settings ) ? Aloha.settings.plugins||{}: {},
|
|
||||||
i,
|
|
||||||
plugin,
|
|
||||||
pluginName;
|
|
||||||
|
|
||||||
// Global to local settings
|
|
||||||
for ( pluginName in globalSettings ) {
|
|
||||||
|
|
||||||
if ( globalSettings.hasOwnProperty( pluginName ) ) {
|
|
||||||
|
|
||||||
plugin = this.plugins[pluginName] || false;
|
|
||||||
|
|
||||||
if ( plugin ) {
|
|
||||||
plugin.settings = globalSettings[ pluginName ] || {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default: All loaded plugins are enabled
|
|
||||||
if ( !userPlugins.length ) {
|
|
||||||
|
|
||||||
for ( pluginName in this.plugins ) {
|
|
||||||
|
|
||||||
if ( this.plugins.hasOwnProperty( pluginName ) ) {
|
|
||||||
userPlugins.push( pluginName );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable Plugins specified by User
|
|
||||||
for ( i=0; i < userPlugins.length; ++i ) {
|
|
||||||
|
|
||||||
pluginName = userPlugins[ i ];
|
|
||||||
plugin = this.plugins[ pluginName ]||false;
|
|
||||||
|
|
||||||
if ( plugin ) {
|
|
||||||
|
|
||||||
plugin.settings = plugin.settings || {};
|
|
||||||
|
|
||||||
if ( typeof plugin.settings.enabled === 'undefined' ) {
|
|
||||||
plugin.settings.enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( plugin.settings.enabled ) {
|
|
||||||
if ( plugin.checkDependencies() ) {
|
|
||||||
plugin.init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a plugin
|
|
||||||
* @param {Plugin} plugin plugin to register
|
|
||||||
*/
|
|
||||||
register: function( plugin ) {
|
|
||||||
|
|
||||||
if ( !plugin.name ) {
|
|
||||||
throw new Error( 'Plugin does not have an name.' );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( this.plugins[ plugin.name ]) {
|
|
||||||
throw new Error( 'Already registered the plugin "' + plugin.name + '"!' );
|
|
||||||
}
|
|
||||||
|
|
||||||
this.plugins[ plugin.name ] = plugin;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pass the given jQuery object, which represents an editable to all plugins, so that they can make the content clean (prepare for saving)
|
|
||||||
* @param obj jQuery object representing an editable
|
|
||||||
* @return void
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
makeClean: function(obj) {
|
|
||||||
var i, plugin;
|
|
||||||
// iterate through all registered plugins
|
|
||||||
for ( plugin in this.plugins ) {
|
|
||||||
if ( this.plugins.hasOwnProperty( plugin ) ) {
|
|
||||||
if (Aloha.Log.isDebugEnabled()) {
|
|
||||||
Aloha.Log.debug(this, 'Passing contents of HTML Element with id { ' + obj.attr('id') +
|
|
||||||
' } for cleaning to plugin { ' + plugin + ' }');
|
|
||||||
}
|
|
||||||
this.plugins[plugin].makeClean(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expose a nice name for the Plugin Manager
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
toString: function() {
|
|
||||||
return 'pluginmanager';
|
|
||||||
}
|
|
||||||
|
|
||||||
}))();
|
|
||||||
});
|
|
@ -1,59 +0,0 @@
|
|||||||
/*!
|
|
||||||
* This file is part of Aloha Editor
|
|
||||||
* Author & Copyright (c) 2010 Gentics Software GmbH, aloha@gentics.com
|
|
||||||
* Licensed unter the terms of http://www.aloha-editor.com/license.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registry base class.
|
|
||||||
* TODO: document that it also contains Observable.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
define(
|
|
||||||
['aloha/jquery', 'aloha/observable'],
|
|
||||||
function(jQuery, Observable) {
|
|
||||||
|
|
||||||
|
|
||||||
return Class.extend(Observable, {
|
|
||||||
|
|
||||||
_entries: null,
|
|
||||||
|
|
||||||
_constructor: function() {
|
|
||||||
this._entries = {};
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @event register
|
|
||||||
* @param entry
|
|
||||||
* @param id
|
|
||||||
*/
|
|
||||||
register: function(id, entry) {
|
|
||||||
this._entries[id] = entry;
|
|
||||||
this.trigger('register', entry, id);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @event unregister
|
|
||||||
* @param odEntry
|
|
||||||
* @param id
|
|
||||||
*/
|
|
||||||
unregister: function(id) {
|
|
||||||
var oldEntry = this._entries[id];
|
|
||||||
delete this._entries[id];
|
|
||||||
this.trigger('unregister', oldEntry, id);
|
|
||||||
},
|
|
||||||
|
|
||||||
get: function(id) {
|
|
||||||
return this._entries[id];
|
|
||||||
},
|
|
||||||
|
|
||||||
has: function(id) {
|
|
||||||
return (this._entries[id] ? true : false);
|
|
||||||
},
|
|
||||||
|
|
||||||
getEntries: function() {
|
|
||||||
// clone the entries so the user does not accidentally modify our _entries object.
|
|
||||||
return jQuery.extend({}, this._entries);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|