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 'bson_ext', '~> 1.5.2'
|
||||
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', :git => 'git://github.com/locomotivecms/custom_fields.git', :branch => 'experimental'
|
||||
gem 'kaminari'
|
||||
@ -26,6 +26,7 @@ gem 'jquery-rails', '~> 1.0.16'
|
||||
gem 'rails-backbone', '0.5.4'
|
||||
gem 'codemirror-rails'
|
||||
gem 'tinymce-rails'
|
||||
gem 'locomotive-aloha-rails', :path => '../gems/aloha-rails'
|
||||
gem 'flash_cookie_session', '~> 1.1.1'
|
||||
|
||||
gem 'locomotive_liquid', '2.2.2', :require => 'liquid'
|
||||
|
12
Gemfile.lock
@ -1,8 +1,8 @@
|
||||
GIT
|
||||
remote: git@github.com:locomotivecms/mongoid_acts_as_tree.git
|
||||
revision: ca494d22c3d7946385aba1153c017d9c30e9f9d3
|
||||
PATH
|
||||
remote: ../gems/aloha-rails
|
||||
specs:
|
||||
locomotive_mongoid_acts_as_tree (0.1.5.7)
|
||||
locomotive-aloha-rails (0.20.1)
|
||||
railties (>= 3.1)
|
||||
|
||||
PATH
|
||||
remote: ../gems/custom_fields
|
||||
@ -163,6 +163,7 @@ GEM
|
||||
launchy (2.0.5)
|
||||
addressable (~> 2.2.6)
|
||||
locomotive_liquid (2.2.2)
|
||||
locomotive_mongoid_acts_as_tree (0.1.5.8)
|
||||
mail (2.3.0)
|
||||
i18n (>= 0.4.0)
|
||||
mime-types (~> 1.16)
|
||||
@ -314,8 +315,9 @@ DEPENDENCIES
|
||||
jquery-rails (~> 1.0.16)
|
||||
kaminari
|
||||
launchy
|
||||
locomotive-aloha-rails!
|
||||
locomotive_liquid (= 2.2.2)
|
||||
locomotive_mongoid_acts_as_tree!
|
||||
locomotive_mongoid_acts_as_tree (~> 0.1.5.8)
|
||||
mimetype-fu (~> 0.1.2)
|
||||
mocha (= 0.9.12)
|
||||
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?
|
||||
window.Aloha = {}
|
||||
# unless window.Aloha?
|
||||
# window.Aloha = {}
|
||||
|
||||
Aloha = window.Aloha ?= {}
|
||||
|
||||
Aloha.settings =
|
||||
|
||||
window.Aloha.settings =
|
||||
logLevels: { 'error': true, 'warn': true, 'info': false, 'debug': false }
|
||||
|
||||
errorhandling: true
|
||||
|
||||
plugins:
|
||||
|
||||
format:
|
||||
config: [ 'b', 'i', 'u','del','sub','sup', 'p', 'title', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'pre', 'removeFormat']
|
||||
editables:
|
||||
@ -24,4 +30,6 @@ window.Aloha.settings =
|
||||
available: ['en', 'fr', 'pt-BR', 'es', 'de', 'no', 'ru', 'nl']
|
||||
|
||||
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
|
||||
* 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 ./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/images";
|
||||
@import "compass/css3/text-shadow";
|
||||
@import "buttons";
|
||||
@import "../backoffice/buttons";
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
def localize_label(label, options = {})
|
||||
|
@ -1,9 +1,6 @@
|
||||
- content_for :head_title do
|
||||
= t('locomotive.installation.common.title')
|
||||
|
||||
- content_for :head do
|
||||
= stylesheet_link_tag 'locomotive/installation', :media => 'screen'
|
||||
|
||||
- title t('.title')
|
||||
|
||||
- if @step_done.blank?
|
||||
|
@ -1,9 +1,6 @@
|
||||
- content_for :head_title do
|
||||
= t('locomotive.installation.common.title')
|
||||
|
||||
- content_for :head do
|
||||
= stylesheet_link_tag 'locomotive/installation', :media => 'screen'
|
||||
|
||||
- title t('.title')
|
||||
|
||||
= semantic_form_for(@site, :url => installation_step_url(2), :html => { :multipart => true }) do |f|
|
||||
|
@ -4,14 +4,11 @@
|
||||
%head
|
||||
%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'
|
||||
|
||||
= yield :head
|
||||
|
||||
/ [if IE]
|
||||
= stylesheet_link_tag 'locomotive/ie', :media => 'screen'
|
||||
|
||||
%body{ :class => controller.controller_name }
|
||||
#wrapper
|
||||
#light.container
|
||||
|
6
doc/TODO
@ -83,13 +83,19 @@ x edit my site
|
||||
x remove sidebar
|
||||
- i18n
|
||||
- insert image
|
||||
- deployment
|
||||
- fix integration problems
|
||||
- pre-compile assets
|
||||
|
||||
- bugs:
|
||||
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 ?)
|
||||
- message to notify people if their browser is too old
|
||||
- install a site by default at the first installation (without asking)
|
||||
- where to put Locomotive::InlineEditorMiddleware ?
|
||||
|
||||
|
||||
|
||||
|
@ -18,4 +18,18 @@
|
||||
|
||||
|
||||
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__)
|
||||
|
||||
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
|
||||
@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'
|
||||
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
|
||||
remove_file 'public/index.html'
|
||||
end
|
||||
|
@ -8,10 +8,12 @@ The Locomotive Engine has been correctly installed in your Rails application.
|
||||
- config/initializers/carrierwave.rb
|
||||
- config/initializers/dragonfly.rb
|
||||
- config/mongoid.yml
|
||||
- config/devise.yml
|
||||
- config/routes.rb
|
||||
|
||||
2. Launch the server
|
||||
|
||||
> unicorn_rails
|
||||
> bundle exec unicorn_rails
|
||||
|
||||
3. Open your browser
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
require 'locomotive/engine'
|
||||
|
||||
require 'locomotive/dependencies'
|
||||
puts "\t...loading core"
|
||||
|
||||
require 'locomotive/version'
|
||||
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.use '::Locomotive::Middlewares::SeoTrailingSlash'
|
||||
|
||||
self.app_middleware.use '::Locomotive::InlineEditorMiddleware' # TODO
|
||||
end
|
||||
|
||||
def self.configure_multi_sites
|
||||
|
@ -1,7 +1,10 @@
|
||||
require 'devise'
|
||||
puts "\t...loading dependencies"
|
||||
|
||||
require 'mongoid'
|
||||
require 'mongoid/railtie'
|
||||
require 'mongoid_acts_as_tree'
|
||||
require 'devise'
|
||||
require 'devise/orm/mongoid'
|
||||
require 'kaminari'
|
||||
require 'haml'
|
||||
require 'liquid'
|
||||
@ -20,3 +23,12 @@ require 'cancan'
|
||||
require 'RMagick'
|
||||
require 'cells'
|
||||
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"
|
||||
|
||||
require 'locomotive/dependencies'
|
||||
require 'locomotive'
|
||||
|
||||
$:.unshift File.dirname(__FILE__) # TODO: not sure about that, looks pretty useless
|
||||
|
||||
module Locomotive
|
||||
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)
|
||||
|
||||
# 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|
|
||||
Cell::Base.prepend_view_path("#{config.root}/app/cells")
|
||||
end
|
||||
@ -27,5 +20,38 @@ module Locomotive
|
||||
::ActionController::Base.wrap_parameters :format => [:json]
|
||||
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
|
||||
|
@ -5,17 +5,23 @@ module Liquid
|
||||
|
||||
def render(context)
|
||||
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" />
|
||||
<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.stylesheet_link_tag 'aloha'}
|
||||
|
||||
#{ActionController::Base.helpers.javascript_include_tag 'locomotive/aloha', :'data-aloha-plugins' => plugins}
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
Aloha.ready(function() \{
|
||||
window.parent.application_view.set_page(#{context.registers[:page].to_presenter.as_json_for_html_view.to_json});
|
||||
\});
|
||||
</script>
|
||||
|
||||
}
|
||||
else
|
||||
''
|
||||
@ -27,3 +33,17 @@ module Liquid
|
||||
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
|
||||
VERSION = "1.0.0.rc1"
|
||||
VERSION = "2.0.0.rc1"
|
||||
end
|
||||
|
@ -10,59 +10,104 @@ Gem::Specification.new do |s|
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.authors = ['Didier Lafforgue']
|
||||
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.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.rubyforge_project = 'nowarning'
|
||||
|
||||
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 'rails', '~> 3.1.3'
|
||||
|
||||
s.add_dependency 'mongo', '~> 1.3.1'
|
||||
s.add_dependency 'bson', '~> 1.3.1'
|
||||
s.add_dependency 'bson_ext', '~> 1.3.1'
|
||||
s.add_dependency 'mongoid', '~> 2.0.2'
|
||||
s.add_dependency 'devise', '~> 1.5.3'
|
||||
s.add_dependency 'cancan', '~> 1.6.7'
|
||||
|
||||
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 'haml', '3.1.2'
|
||||
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 'haml', '~> 3.1.3'
|
||||
s.add_dependency 'sass-rails', '~> 3.1.4'
|
||||
s.add_dependency 'coffee-script', '~> 2.2.0'
|
||||
s.add_dependency 'uglifier', '~> 1.2.2'
|
||||
s.add_dependency 'compass', '~> 0.12.alpha.4'
|
||||
s.add_dependency 'jquery-rails', '~> 1.0.16'
|
||||
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 'bushido'
|
||||
s.add_dependency 'heroku', '1.19.1'
|
||||
s.add_dependency 'locomotive_liquid', '2.2.2'
|
||||
s.add_dependency 'formtastic', '~> 2.0.2'
|
||||
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 'carrierwave', '0.5.6'
|
||||
s.add_dependency 'dragonfly', '~> 0.9.1'
|
||||
s.add_dependency 'rack-cache'
|
||||
|
||||
s.add_dependency 'custom_fields', '1.0.0.beta.25'
|
||||
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 'rmagick', '2.12.2'
|
||||
s.add_dependency 'carrierwave-mongoid', '~> 0.1.3'
|
||||
s.add_dependency 'fog', '~> 1.0.0'
|
||||
s.add_dependency 'dragonfly', '~> 0.9.8'
|
||||
s.add_dependency 'rack-cache', '~> 1.1'
|
||||
s.add_dependency 'mimetype-fu', '~> 0.1.2'
|
||||
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',
|
||||
'{app}/**/*',
|
||||
'{config}/**/*',
|
||||
'{lib}/**/*',
|
||||
'{public}/stylesheets/admin/**/*', '{public}/javascripts/admin/**/*', '{public}/images/admin/**/*',
|
||||
'{public}/**/*',
|
||||
'{vendor}/**/*']
|
||||
|
||||
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'
|
||||
|
||||
Bundler.require
|
||||
require 'locomotive'
|
||||
require 'locomotive/engine'
|
||||
|
||||
module Dummy
|
||||
class Application < Rails::Application
|
||||
@ -43,8 +43,6 @@ module Dummy
|
||||
|
||||
# Version of your assets, change this if you want to expire all your assets
|
||||
config.assets.version = '1.0'
|
||||
|
||||
config.middleware.use 'Locomotive::InlineEditorMiddleware'
|
||||
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);
|
||||
}
|
||||
});
|
||||
});
|